В примере SpeakHere воспроизведение выполняется с использованием AudioQueue
.
В настройке AudioQueue
указана функция, которая будет вызываться, когда очереди требуется больше данных.
Вы можете видеть, что в этом методе:
void AQPlayer::SetupNewQueue()
Вот строка, которая определяет функцию обратного вызова:
XThrowIfError(AudioQueueNewOutput(&mDataFormat, AQPlayer::AQBufferCallback, this,
CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue), "AudioQueueNew failed");
Если вы посмотрите на AQPlayer::AQBufferCallback
, вы увидите, откуда он получает данные.В этом примере данные были записаны в файл на диске.Это хорошее решение, если вы хотите сэкономить память или если есть вероятность, что аудиофайл может быть довольно большим.
В любом случае, глядя на AQPlayer::AQBufferCallback
, вы увидите вызов функции AudioFileReadPackets
,Вот что читает аудиопакеты из файла на диске.Он считывает их прямо в буфер, который будет использовать AudioQueue
:
OSStatus result = AudioFileReadPackets(THIS->GetAudioFileID(), false, &numBytes, inCompleteAQBuffer->mPacketDescriptions, THIS->GetCurrentPacket(), &nPackets,
inCompleteAQBuffer->mAudioData);
Этот буфер равен inCompleteAQBuffer->mAudioData
.
Наконец, функция обратного вызова должна поставить в буфер буфер следующим образом:
if (nPackets > 0) {
inCompleteAQBuffer->mAudioDataByteSize = numBytes;
inCompleteAQBuffer->mPacketDescriptionCount = nPackets;
AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, 0, NULL);
THIS->mCurrentPacket = (THIS->GetCurrentPacket() + nPackets);
}
Сначала обратите внимание, что он должен проверить, что у нас есть несколько пакетов для воспроизведения.Также необходимо указать, сколько байтов находится в буфере.
Затем эта строка здесь:
THIS->mCurrentPacket = (THIS->GetCurrentPacket() + nPackets);
Это отслеживает, где мы находимся в целом внаш аудио буфер.Другими словами, по мере того, как из файла копируется больше данных, нам нужно поместить mCurrentPacket
вперед, чтобы следующая копия поместила данные в правильное место.