C++ - DirectSoundBuffer перестает воспроизводиться в определенном месте - нет уведомлений

Я использую DirectSoundBuffer DirectSound для воспроизведения голосовых данных, которые я передаю в потоковом режиме по сети. Природа голоса/речи заключается в том, что они не обязательно постоянно передаются (они начинаются и останавливаются), а также могут поступать в пакетах разного размера (что затрудняет прогнозирование того, где должен остановиться буфер). Я держу переменную StoppingPoint, которая отслеживает, где в моем буфере я выполнил запись (она также принимает во внимание циклическую природу этого буфера). Если достигнуто StoppingPoint, я хотел бы остановить воспроизведение своего буфера. Кроме того, я StoppingPoint также обозначал бы точку, с которой я также хотел бы начать писать.

My buffer
|==============================|--------------------------|
      ^                        ^             ^
      |                        |             |
  Voice Data            Stopping point   Old/Garbage
                                            data

Кроме того, я не могу использовать уведомления, потому что для использования уведомления буфер должен быть остановлен. Но в моем случае очень вероятно, что во время воспроизведения буфера будет поступать больше данных, что отодвигает мое значение «StoppingPoint».

Сейчас у меня есть функция, которая вызывается каждый кадр. Эта функция, среди прочего, проверяет, где находится курсор воспроизведения. Если курсор воспроизведения проходит через позицию StoppingPoint, он останавливает буфер и перемещает курсор воспроизведения обратно в позицию StoppingPoint. Кажется, пока это работает нормально, но, как и следовало ожидать, курсор воспроизведения довольно часто выходит за пределы StoppingPoint. Это означает, что немного старых/мусорных данных воспроизводится каждый раз, когда достигается конец потоковых данных.

Мне просто любопытно, есть ли способ остановить воспроизведение DirectSoundBuffer по определенному смещению? Что я хотел бы, так это записать данные в буфер, затем воспроизвести, а затем остановить их точно в месте, описанном моей переменной StoppingPoint, не выходя за ее пределы.

Примечание. Я не добавлял никакого кода, потому что мне нужно более высокоуровневое решение. Моя реализация невероятно прямолинейна, типична и по большей части ДЕЙСТВИТЕЛЬНО работает. Мне просто нужно подтолкнуть в правильном направлении, чтобы убрать превышение моего StoppingPoint. Возможно, есть функция, которую я могу использовать? Или какой-то другой алгоритм, который обычно используется для достижения этой цели?


person Jace    schedule 10.05.2013    source источник


Ответы (1)


Я придумал решение, но меня по-прежнему интересуют любые отзывы или альтернативные решения. Я не уверен, что способ, которым я это сделал, в порядке, но, похоже, он дает желаемые результаты. Хотя мое решение кажется слишком запутанным...

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

Опять же, если я сделал что-то вопиющее зло здесь, пожалуйста, дайте мне знать!

person Jace    schedule 10.05.2013