我正在使用DirectSound的DirectSoundBuffer播放我通过网络传输的语音数据。语音/语音的本质是它不一定经常流(它开始和停止),它也可能有不同的数据包大小(这使得很难预测缓冲区应该停止的位置)。我保留了一个StoppingPoint
变量,用于跟踪我写入缓冲区的位置(它还考虑了此缓冲区的循环特性)。如果达到StoppingPoint
,我想停止播放我的缓冲区。此外,我StoppingPoint
也意味着我也想开始写作。
My buffer
|==============================|--------------------------|
^ ^ ^
| | |
Voice Data Stopping point Old/Garbage
data
另外,我无法使用通知,因为为了使用通知,必须停止缓冲区。但就我而言,当缓冲区正在播放时,很可能会有更多数据进入,从而推迟我的'StoppingPoint`值。
我现在拥有的是每帧调用的函数。除其他外,此功能是检查Play游标的位置。如果播放光标通过StoppingPoint
位置,它将停止缓冲区,并将播放光标移回StoppingPoint
位置。到目前为止,这似乎工作正常,但正如您所期望的那样,Play游标经常超过StoppingPoint
。这意味着每次到达流数据结束时都会播放一些旧/垃圾数据。
我只是想知道是否有办法停止在特定偏移处播放DirectSoundBuffer?我想要的是将数据写入缓冲区,然后播放,然后将其精确地停在我的StoppingPoint
变量描述的位置,而不会超出它。
注意:我没有包含任何代码,因为这更像是我需要的高级解决方案。我的实施是非常直接的,典型的,并且大多数情况下它的工作。我只需要朝正确的方向轻推即可消除StoppingPoint
的过冲。也许有一个我可以使用的功能?还是通常用于实现此目的的其他一些算法?
答案 0 :(得分:0)
我提出了一个解决方案,但我仍然对任何反馈或替代解决方案感兴趣。我不确定我做的方式是否正常,但它似乎产生了预期的结果。虽然,我的解决方案感觉有点过于复杂......
1)每当我写数据时,我现在写入缓冲区的Write Cursor
或StoppingPoint
- 以较晚者为准。这是为了避免停止,然后写入播放光标和写光标之间的“不可触摸”空间,其数据已经专用于播放。
DWORD writeCursorOffset = 0;
buffer->GetCurrentPosition(NULL, &writeCursorOffset);
//if write cursor has passed stopping point, then we need to write from there.
//So update m_StoppingPoint to reflect the new writing position.
m_StoppingPoint = m_StoppingPoint > writeCursorOffset ? m_StoppingPoint : writeCursorOffset;
2)我在每次写入后都添加了一些静音,但是我将StoppingPoint
指向实际语音数据的末尾。例如
|==============================|*********|---------------------|
^ ^ ^ ^
| | | |
Voice data Stopping Silence Old/Garbage
Point Data
3)如果缓冲区的Play Cursor
通过StoppingPoint
,我将停止播放缓冲区。即使播放光标在这里超调,它所播放的只是静音。
//error checking removed for demonstration purposes
buffer->Stop();
4)停止后我会立即将StoppingPoint
更新为等于沉默的结束。这将确保当更多语音数据进入时,缓冲区将不会首先播放任何静音。
//don't forget that modulo at the end - circular buffer!
m_StoppingPoint = (m_StoppingPoint + SILENCE_BUFFER_SIZE) % BufferSize;
|==============================|*********|-------------------|
^
|
Move Stopping
Point here
同样,如果我在这里做了任何明显的恶事,请告诉我!