À droite, je travaille sur l'implémentation de DirectSound dans notre application voip Delphi (l'application permet aux radios d'être utilisées par plusieurs utilisateurs via une connexion réseau) Les données arrivent via les diffusions UDP. Comme c'est le cas maintenant, nous descendons sur un niveau de données brutes et faisons le mixage audio de plusieurs sources nous-mêmes et avons un composant centralisé qui est utilisé pour jouer tout ce retour. L'application elle-même est une application Delphi 5 et je suis chargé de la porter vers Delphi 2010. Une fois que j'ai eu cette partie de lecture audio, nous avons conclu qu'il est préférable de se débarrasser de cet ancien code et de remplacer avec directsound. Donc, l'idée est d'avoir un SecondaryBuffer par radio (nous avons un 'panneau' par connexion radio, basé sur un ensemble de composants que nous créons pour chaque radio spécifique) et nous laissons simplement ces données ajouter leurs données respectives SecondaryBuffers chaque fois qu'ils obtiennent des données, s'arrêtant seulement pour remplir une demi-seconde de données audio dans le tampon s'il manque de données. Maintenant, je suis bloqué sur la partie où j'ajoute des données aux tampons dans mon application de test où j'essaye simplement de faire fonctionner correctement ceci avant que je commence à écrire un composant pour l'utiliser comme je le souhaite. nous voulons.Directsound avec le tampon de diffusion - Le verrouillage ne s'enroule pas! Utilisation des en-têtes DirectX portés pour Delphi
J'utilise les en-têtes DirectX portés pour Delphi (http://www.clootie.ru/delphi/download_dx92.html)
Le point de ces en-têtes est au port sur l'interface DirectSound régulière à Delphes, alors je espère que les programmeurs non Delphi avec DirectSound peuvent savoir ce que la cause de mon problème est aussi bien.
Mon SecondaryBuffer (IDirectSoundBuffer) a été créé comme suit:
var
BufferDesc: DSBUFFERDESC;
wfx: tWAVEFORMATEX;
wfx.wFormatTag := WAVE_FORMAT_PCM;
wfx.nChannels := 1;
wfx.nSamplesPerSec := 8000;
wfx.wBitsPerSample := 16;
wfx.nBlockAlign := 2; // Channels * (BitsPerSample/2)
wfx.nAvgBytesPerSec := 8000 * 2; // SamplesPerSec * BlockAlign
BufferDesc.dwSize := SizeOf(DSBUFFERDESC);
BufferDesc.dwFlags := (DSBCAPS_GLOBALFOCUS or DSBCAPS_GETCURRENTPOSITION2 or DSBCAPS_CTRLPOSITIONNOTIFY);
BufferDesc.dwBufferBytes := wfx.nAvgBytesPerSec * 4; //Which should land at 64000
BufferDesc.lpwfxFormat := @wfx;
case DSInterface.CreateSoundBuffer(BufferDesc, DSCurrentBuffer, nil) of
DS_OK: ;
DSERR_BADFORMAT: ShowMessage('DSERR_BADFORMAT');
DSERR_INVALIDPARAM: ShowMessage('DSERR_INVALIDPARAM');
end;
je suis parti sur les parties où je définissais mon PrimaryBuffer (il est mis à jouer avec le drapeau en boucle et a été créé exactement comme MSDN dit qu'il devrait être) et la DSInterface, mais c'est comme vous pouvez l'imaginer une IDirectSoundInterface.
Maintenant, chaque fois que je reçois un message audio (détecté, décodé et converti au format audio appropriée par d'autres composants que nous avons fait qui ont été confirmés au travail depuis plus de sept ans), je fais ce qui suit:
AudioData contient les données dans mon message.DSCurrentBuffer.Lock(0, 512, @FirstPart, @FirstLength, @SecondPart, @SecondLength, DSBLOCK_FROMWRITECURSOR);
Move(AudioData, FirstPart^, FirstLength);
if SecondLength > 0 then
Move(AudioData[FirstLength], SecondPart^, SecondLength);
DSCurrentBuffer.GetStatus(Status);
DSCurrentBuffer.GetCurrentPosition(@PlayCursorPosition, @WriteCursorPosition);
if (FirstPart <> nil) or (SecondPart <> nil) then
begin
Memo1.Lines.Add('FirstLength = ' + IntToStr(FirstLength));
Memo1.Lines.Add('PlayCursorPosition = ' + IntToStr(PlayCursorPosition));
Memo1.Lines.Add('WriteCursorPosition = ' + IntToStr(WriteCursorPosition));
end;
DSCurrentBuffer.Unlock(@FirstPart, FirstLength, @SecondPart, SecondLength);
Messages contient toujours 512 octets de données audio. J'ai ajouté les lignes Memo1.Lines.Add pour être en mesure d'obtenir une sortie de débogage (puisque l'utilisation de breakpoints ne fonctionne pas tout à fait, car DirectSounds continue de lire le contenu du buffer primaire indépendamment)
Maintenant, quand je suis Jouer mon DSCurrentBuffer en utilisant l'indicateur de bouclage (qui, selon le MSDN docs est suffisant pour en faire un Streaming Buffer) et avoir ce code qui fonctionne comme il veut, mon texte de sortie dans le mémo montre que je suis autorisé à écrire jusqu'à la fin du tampon ... Mais ça ne s'enroule pas.
SecondPart est toujours nul. Il ne tourne jamais au début de la mémoire tampon, ce qui signifie que je reçois les mêmes quelques secondes de données audio à jouer encore et encore.
Et oui, j'ai récuré le net pour les composants qui peuvent faire ce genre de choses pour nous et avons conclu que le seul moyen fiable est de le faire nous-mêmes comme ça.
Et oui, les données audio que cette application joue est saccadée.Je m'attends à écrire le code tampon d'une demi-seconde jusqu'à ce que je puisse obtenir le code write-to-buffer comme il se doit:/
J'ai lu que les gens suggèrent de garder une trace de leur propre écriture curseur, mais à partir de ce que je lis Lock and Unlock devrait m'aider à contourner ce besoin. Je préférerais aussi éviter d'avoir deux tampons que j'alterne d'avant en arrière (ou un split-buffer, ce qui serait essentiellement la même chose, seulement un peu plus complexe en écriture)
Toute aide grandement appréciée !
Avez-vous regardé les composants lakeofsoft? Je les ai déjà utilisés pour une application audio sur Internet, et cela vient avec la source. Je les aimais. OTOH pour nous c'était juste un travail de côté (audio sur webapp) –
Ouais, je l'ai fait. Nous n'avons pas besoin d'aide pour diffuser les données - nous le faisons déjà. Nous avons besoin des fonctionnalités de mixage automatisé de DirectSound. La commodité de chaque thread séparé étant capable de jouer comme il le souhaite sans avoir à prêter attention à toute autre partie de l'application. DirectSound semble avoir une certaine forme d'annulation d'écho quelque part dans ce qui serait un très bon bonus. –
Avez-vous déjà essayé l'audio BASS? http://www.un4seen.com/bass.html Il est à faible latence, très rapide et il y a des wrappers Delphi corrects disponibles. J'ai fait quelques bonnes choses avec BASS dans .NET ... –