gpt4 book ai didi

delphi - 带流缓冲区的 Directsound - 锁不会换行!使用 Delphi 移植的 DirectX header

转载 作者:行者123 更新时间:2023-12-03 15:55:36 25 4
gpt4 key购买 nike

对了,我正在努力在我们的 Delphi voip 应用程序中实现 DirectSound(该应用程序允许多个用户通过网络连接使用 radio )数据通过 UDP 广播传入。就像现在一样,我们在原始数据级别上进行,并自己从多个源进行音频混合,并有一个用于播放所有这些的集中组件。

该应用程序本身是一个 Delphi 5 应用程序,我的任务是将其移植到 Delphi 2010。一旦我到达这个音频播放部分,我们得出的结论是,最好能够摆脱这个旧代码并替换它带有直接声音。

因此,我们的想法是每个 radio 都有一个SecondaryBuffer(我们每个 radio 连接都有一个“面板”,基于我们为每个特定 radio 创建的一组组件),然后让这些将数据添加到各自的SecondaryBuffers每当他们获取数据时,只有在数据耗尽时才会暂停以填充缓冲区中半秒的音频数据。

现在,我陷入了向测试应用程序中的缓冲区添加数据的部分,在开始编写组件以按照我们的方式使用它之前,我只是想让它正常工作想要。

我正在使用 Delphi 的移植 DirectX header ( http://www.clootie.ru/delphi/download_dx92.html )

这些 header 的目的是将常规 DirectSound 接口(interface)移植到 Delphi,因此希望使用 DirectSound 的非 Delphi 程序员也能知道我的问题的原因是什么。

我的SecondaryBuffer(IDirectSoundBuffer)创建如下:

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);

AudioData 包含我的消息中的数据。消息始终包含 512 字节的音频数据。我添加了 Memo1.Lines.Add 行,以便能够获得一些调试输出(因为使用断点不太有效,因为 directsound 无论如何都会继续播放主缓冲区的内容)

现在,当我使用循环标志(根据 Hte MSDN 文档足以使其成为流缓冲区)播放 DSCurrentBuffer 并让此代码按需要运行时,备忘录中的输出文本显示:我被允许一直写到缓冲区末尾...但它不会换行。

SecondPart 始终为零。它永远不会绕到缓冲区的开头,这意味着我会一遍又一遍地播放相同的几秒钟音频数据。

是的,我在网上搜索了可以为我们做这些事情的组件,并得出结论,唯一可靠的方法就是我们自己这样做。

是的,这个应用程序播放的音频数据不稳定。我推迟编写半秒缓冲代码,直到我能让写入缓冲区代码按其应有的方式换行:/

我一直在读到人们建议跟踪你自己的写入光标,但从我读到的“锁定和解锁”应该可以帮助我绕过这个需求。我还宁愿避免必须有两个来回交替的缓冲区(或分割缓冲区,本质上是相同的东西,只是编写起来更复杂一点)

非常感谢任何帮助!

最佳答案

所以我找到了问题所在^^;

也很简单。

DSCurrentBuffer.Unlock(@FirstPart, FirstLength, @SecondPart, SecondLength);

我认为我应该将与 Lock() 所需的指针相同的指针传递给指针。

更改为

DSCurrentBuffer.Unlock(FirstPart, FirstLength, SecondPart, SecondLength);

解决了问题,缓冲区现在可以正确换行。

抱歉浪费了您的时间,不过还是谢谢您^^;

关于delphi - 带流缓冲区的 Directsound - 锁不会换行!使用 Delphi 移植的 DirectX header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2116459/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com