Directsound带流式缓冲区-锁不换行!在Delphi中使用移植的DirectX头文件
没错,我正在Delphi voip应用程序中实现DirectSound(该应用程序允许多个用户通过网络连接使用无线电) 数据通过UDP广播进入。 就像现在一样,我们在原始数据级别上,自己做来自多个源的音频混合,并有一个用于播放所有这些内容的集中组件 该应用程序本身是Delphi5应用程序,我的任务是将其移植到Delphi2010。当我谈到这个音频播放部分时,我们得出结论,如果我们能摆脱这个旧代码,用directsound取代它,那将是最好的 因此,我们的想法是每个无线电都有一个二级缓冲区(每个无线电连接都有一个“面板”,基于我们为每个特定无线电创建的一组组件),只要让这些设备在获得数据时将数据添加到各自的二级缓冲区,只有当缓冲区中的数据用完时,才会暂停以填充半秒钟的音频数据 现在,我被困在测试应用程序中向缓冲区添加数据的部分,我只是想在开始编写一个组件以我们想要的方式利用它之前,让它正常工作 我正在为Delphi()使用移植的DirectX头文件 这些头文件的目的是通过常规的DirectSound接口向Delphi进行移植,因此希望使用DirectSound的非Delphi程序员也知道我的问题的原因 我的第二个缓冲区(IDirectSoundBuffer)创建如下:Directsound带流式缓冲区-锁不换行!在Delphi中使用移植的DirectX头文件,delphi,directx,directsound,Delphi,Directx,Directsound,没错,我正在Delphi voip应用程序中实现DirectSound(该应用程序允许多个用户通过网络连接使用无线电) 数据通过UDP广播进入。 就像现在一样,我们在原始数据级别上,自己做来自多个源的音频混合,并有一个用于播放所有这些内容的集中组件 该应用程序本身是Delphi5应用程序,我的任务是将其移植到Delphi2010。当我谈到这个音频播放部分时,我们得出结论,如果我们能摆脱这个旧代码,用directsound取代它,那将是最好的 因此,我们的想法是每个无线电都有一个二级缓冲区(每个无
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;
我省略了我定义PrimaryBuffer(它被设置为使用循环标志,并且完全按照MSDN所说的那样创建)和DSInterface的部分,但正如您所想象的IDirectSoundInterface一样
现在,每当我收到一条音频信息(由我们制作的其他组件检测、解码并转换为适当的音频格式,这些组件已被确认工作了七年以上),我都会执行以下操作:
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);
DSCurrentBuffer.Lock(0,512,@FirstPart,@FirstLength,@SecondPart,@SecondLength,DSBLOCK_fromWriteCursors);
移动(音频数据,第一部分^,第一长度);
如果SecondLength>0,则
移动(音频数据[FirstLength],SecondPart^,SecondLength);
DSCurrentBuffer.GetStatus(状态);
GetCurrentPosition(@PlayCursorPosition、@WriteCursorPosition);
如果(第一部分为零)或(第二部分为零),则
开始
Memo1.Lines.Add('FirstLength='+IntToStr(FirstLength));
备注1.Lines.Add('PlayCursorPosition='+IntToStr(PlayCursorPosition));
Memo1.Lines.Add('WriteCursorPosition='+IntToStr(WriteCursorPosition));
结束;
DSCurrentBuffer.Unlock(@FirstPart,FirstLength,@SecondPart,SecondLength);
AudioData包含我的消息中的数据。消息始终包含512字节的音频数据。
我添加了Memo1.Lines.Add行,以便能够获得一些调试输出(因为使用断点并不十分有效,因为directsound始终播放主缓冲区的内容)
现在,当我使用循环标志播放我的DSCurrentBuffer(根据hte MSDN文档,循环标志足以使其成为流式缓冲区)并使此代码按需要运行时,我在备忘录中的输出文本显示,我被允许在缓冲区结束前进行写操作。。。但它没有包装
第二部分总是零。它从来不会绕到缓冲区的开头,这意味着我会一遍又一遍地播放同样的几秒钟音频数据
是的,我已经搜索了网络上可以为我们做这些事情的组件,并得出结论,唯一可靠的方法就是自己这样做
是的,这个应用程序播放的音频数据是不稳定的。我一直在等待半秒缓冲代码的编写,直到我能够将write to buffer代码按应有的方式包装:/
我一直在读人们建议跟踪你自己的写光标,但从我读到的锁和解锁应该可以帮助我绕过这种需要。
我还希望避免使用两个前后交替的缓冲区(或者一个拆分缓冲区,本质上是一样的,只是在编写时稍微复杂一点)
非常感谢您的帮助 一些可能导致这种情况的因素:
DSCurrentBuffer.Lock(0, 512, @FirstPart, @FirstLength, @SecondPart, @SecondLength, DSBLOCK_FROMWRITECURSOR);
try
//...
finally
DSCurrentBuffer.Unlock(@FirstPart, FirstLength, @SecondPart, SecondLength);
end;
--杰伦所以我解决了问题^^ 也很简单
DSCurrentBuffer.Unlock(@FirstPart, FirstLength, @SecondPart, SecondLength);
我想我应该只传递Lock()所需的相同指针
改成
DSCurrentBuffer.Unlock(FirstPart, FirstLength, SecondPart, SecondLength);
解决了该问题,缓冲区现在已正确包装
很抱歉浪费了你的时间,不过还是要谢谢你^^ 你看过lakeofsoft组件了吗?我以前在互联网音频应用程序中使用过它们,它附带了源代码。我喜欢他们。对我们来说,这只是一个副业(网络应用上的音频)是的,我做了。不过,我们不需要数据流的帮助——我们已经这样做了。我们需要的是DirectSound的自动混音功能。每一个独立线程都可以随心所欲地运行,而不必关注应用程序的任何其他部分。DirectSound似乎在它的某个地方也有某种形式的回声消除,这将是一个巨大的好处。你有没有尝试过低音音频?它的延迟很低,速度很快,并且有合适的Delphi包装器可用。我和BASS在.NET中做了一些非常漂亮的事情…谢谢你的建议。不幸的是,考虑到我们需要的