Почему мой AudioQueueOutputCallback не может быть вызван?
Я использую API AudioQueue Services для воспроизведения потокового аудио с сервера через соединение через сокет TCP на iPhone. Я могу воспроизвести буферы, которые были заполнены из сокетного соединения, я просто не могу заставить свой AudioQueue вызывать мою функцию AudioQueueOutputCallback, и у меня нет идей.
Дизайн высокого уровня
- Данные передаются на проигрыватель из сокета и сразу записываются в кольцевые буферы в памяти.
- Когда AudioQueueBuffers становятся доступными, данные копируются из циклических буферов в доступный AudioQueueBuffer, который немедленно помещается в очередь. (Или было бы, если бы мой обратный звонок произошел)
Что просходит
Все буферы успешно заполнены и поставлены в очередь, и я четко слышу аудиопоток. Для тестирования я использую большое количество буферов (15), и все они воспроизводятся без проблем, но AudioQueueOutputCallback никогда не вызывается, поэтому я никогда не ставлю в очередь ни один из этих буферов, несмотря на то, что, кажется, все работает отлично. Если я не жду своего обратного вызова, предполагая, что он никогда не будет вызван, и вместо этого управляю постановкой в очередь буферов, основанных на данных, как они записаны, я могу проигрывать аудиопоток бесконечно, повторно используя и повторно ставя в очередь буферы, как будто они был явно возвращен мне обратным вызовом. Это тот факт, что я могу отлично воспроизводить поток, используя при необходимости буферы, что меня больше всего смущает. Почему не вызывается обратный вызов?
Возможно соответствующий код
Формат потока - 16-битный линейный PCM, 8 кГц, моно:
_streamDescription.mSampleRate = 8000.0f;
_streamDescription.mFormatID = kAudioFormatLinearPCM;
_streamDescription.mBytesPerPacket = 2;
_streamDescription.mFramesPerPacket = 1;
_streamDescription.mBytesPerFrame = sizeof(AudioSampleType);
_streamDescription.mChannelsPerFrame = 1;
_streamDescription.mBitsPerChannel = 8 * sizeof(AudioSampleType)
_streamDescription.mReserved = 0;
_streamDescription.mFormatFlags = (kLinearPCMFormatFlagIsBigEndian |
kLinearPCMFormatFlagIsPacked);
Мой прототип и реализация обратного вызова заключаются в следующем. Ничего особенного, и в значительной степени идентичного каждому примеру, который я видел до сих пор:
// Prototype, declared above the class's @implementation
void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer);
// Definition at the bottom of the file.
void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer) {
printf("callback\n");
[(MyAudioPlayer *)inUserData audioQueue:inAudioQueue didAquireBufferForReuse:inAudioQueueBuffer];
}
Я создаю AudioQueue так:
OSStatus status = 0;
status = AudioQueueNewOutput(&_streamDescription,
AQBufferCallback, // <-- Doesn't work...
self,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&_audioQueue);
if (status) {
// This is not called...
NSLog(@"Error creating new audio output queue: %@", [MyAudioPlayer stringForOSStatus:status]);
return;
}
И я ставлю в очередь такие буферы. На данный момент известно, что локальный буфер содержит правильный объем данных для копирования:
memcpy(aqBuffer->mAudioData, localBuffer, kAQBufferSize);
aqBuffer->mAudioDataByteSize = kAQBufferSize;
OSStatus status = AudioQueueEnqueueBuffer(_audioQueue, aqBuffer, 0, NULL);
if (status) {
// This is also not called.
NSLog(@"Error enqueueing buffer %@", [MyAudioPlayer stringForOSStatus:status]);
}
Пожалуйста спаси меня.
2 ответа
Это выполняется в основном потоке или в фоновом потоке? наверное не хорошо если CFRunLoopGetCurrent()
возвращает цикл выполнения потока, который может исчезнуть (пул потоков и т. д.) или цикл выполнения, который не заботится о kCFRunLoopCommonModes
,
Попробуй поменять CFRunLoopGetCurrent()
в CFRunLoopGetMain()
или убедитесь AudioQueueNewOutput()
а также CFRunLoopGetCurrent()
выполняется в главном потоке или потоке, которым вы управляете, и имеет правильный цикл выполнения.
Попробуйте изменить self
за (void*)self
, Как это:
status = AudioQueueNewOutput(&_streamDescription,
AQBufferCallback,
(void*)self,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&_audioQueue);