Войти
ПрограммированиеФорумЗвук

[FMOD] [Win32] голосовой чат. проблема с вопроизведением звука

#0
15:58, 12 фев. 2009

приветствую всех.
в общем, такая проблема: записываю голос с микрофона, передаю по сети, на приеме ловлю звук и закидываю данные в circular буффер вопроизведения.
И все бы как-бы ничего, но вот звук прерывается и иногда повторяется (что-то вроде эхо).
на форуме FMOD сказали, что, возможно проблема с тем, что разная скорость воспроизведения и записи. типа звук после передачи по сети принимает другой битрейт(?) или что-то в этом роде.

Может кто сталкивался с такой проблемой?

исходный код приемника и "воспроизводителя"

...
FMOD::Sound* _playbackSound;//звук, в который пишем входящие данные
unsigned int _lastPlayPos; //индекс буфера проигрывания
...

void SoundMgr::PlayVoipSpeech(unsigned char* data, unsigned int soundlen) //принятый звук и его длина
{  
  void* ptr1, *ptr2;
  unsigned int len1, len2;


  unsigned int maxSoundSize = SOUND_FRAMES_PER_BUFFER*SOUND_SAMPLE_SIZE*SOUND_FRAMES_IN_SOUND;
        //SOUND_FRAMES_PER_BUFFER*SOUND_SAMPLE_SIZE*SOUND_FRAMES_IN_SOUND = (2048 / (32000 / 8000)) * 2 * 4 = 512*8 = 4096

  if (_lastPlayPos >= maxSoundSize) //более ранний звук "ушел" за пределы circular buffer
    _lastPlayPos = _lastPlayPos - maxSoundSize; //возвращаем в рамки буффера

  FMOD_RESULT res =_playbackSound->lock(_lastPlayPos,
    soundlen, 
    &ptr1, &ptr2, &len1,  &len2);
  if (res != FMOD_OK)
    return;

  memcpy(ptr1, data, soundlen);
  res = _playbackSound->unlock(ptr1, ptr2, soundlen, len2);
  if (res != FMOD_OK)
    return;

  _lastPlayPos += soundlen; //переводим индекс на позицию вперед, сколько байт получили в "порции"

теоретически, если смотреть по loopback'y, т.е. не обращая внимания на latency, то сколько мы записали, столько и скормили. все байтики доходят корректно (сравнивал по CRC). таймеры на отправку и прием - 10мс (пробовал с разными вариантами, от 1 - 100мс).
если записывать звук в файл wav (предварительно записав все хэдеры) - то звучит оно хорошо, четко. но проблема именно с воспроизведением. видно, что-то не так с буффером делаю.

подскажите, в какой области копать, хотя бы.
заранее сенкс


#1
18:08, 12 фев. 2009

1. Микрофон может отдавать данных меньше, чем размер буфера.
2. Размер буфера записи/проигрывания. У нас буфера выровнены на 40мс, используем буфера на 120мс.
3. Сетевые задержки. Задержка на каждый пакет может быть разной, соответственно получаешь "дырки" при проигрывании. Бороться можно двумя методами:

а) Простой. Перед каждым пакетом начинающим проигрывание (после "блока" данных с тишиной) вставляется небольшой буфер с тишиной, обычно хватает 320мс.

б) Сложный. На каждый пакет вешается timestamp, на проигрывающей стороне данные выбираются с учетом timestamp'а, т.е. вставляются блоки с тишиной (если данных вдруг нет), дропаются блоки которые "уже проиграны" (вместо них проигрывали тишину, а они пришли с задержкой). Плюс задержка проигрывания после "молчания" как в методе а). Ну и после каждого пакета с тишиной нужно timestamp сбрасывать для синхронизации.

#2
11:54, 10 июня 2009

Всем привет!

У меня возникла подобная проблема. С помощью DirectSound беру звук с микрофона, отсылаю фрагменты по сети и там их собираю с DirectSound в циркулярный буфер. Иногда после начала передачи появляется хрип, прерывание звука и что-то вроде эха. Обычно через некоторое время это проходит само. На принимающей стороне приходящий звук сохраняется в wav, и при проигрывании в нём нет никаких шумов.

Есть ещё одна проблема. Если на передающем компе установлена интегрированная звуковая карта, то звук приходит сильно прерывающийся, будто из него "вырвали" небольшие фрагменты. Особенно это заметно при небольших частотах: 8000, 11025. При частоте 48000 прерываний почти не заметно. При воспроизведении wav-файла на принимающей стороне, прерывания также слышны. Если на передающий комп поставить внешнюю звуковуху, звук приходит нормальный.

Кто-то сталкивался с подобными проблемами и удалось ли побороть?

Проверил то, что описал Alex.
Смотрел данные, приходящие с микрофона. Они всегда соответствуют размеру notify.
Насчёт выравнивания не совсем понятно, где оно должно происходить. Размер передающего и принимающего буфера - 1/4 с. Размер передаваемого фрагмента - 1/64 сек. Частота передаваемого и принимаемого звука одинакова - 8 кГц.
С сетевыми задержками пробовал бороться простым методом. Получилось не очень хорошо, т.к. хрип усилился. Возможно это из-за того, что размер записываемых данных увеличился, а проигрывающий буфер блокируется на момент записи в него и стало быть не проигрывается.

ПрограммированиеФорумЗвук

Тема в архиве.