Почему мой AudioQueueOutputCallback не может быть вызван? - PullRequest
4 голосов
/ 28 сентября 2011

Я использую API служб Audio Queue Services для воспроизведения потокового звука с сервера через соединение через сокет TCP на iPhone. Я могу воспроизвести буферы, которые были заполнены из сокетного соединения, я просто не могу заставить свой AudioQueue вызывать мою функцию AudioQueueOutputCallback, и у меня нет идей.

Дизайн высокого уровня

  1. Данные передаются на плеер от сокета и записываются сразу в кольцевые буферы в памяти.
  2. Когда становятся доступны 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 ]

7 голосов
/ 28 сентября 2011

Это выполняется в основном потоке или в фоновом потоке? вероятно, не очень хорошо, если CFRunLoopGetCurrent() возвращает цикл выполнения потока, который может исчезнуть (пул потоков и т. д.) или является циклом выполнения, который не заботится о kCFRunLoopCommonModes.

Попробуйте изменить CFRunLoopGetCurrent() на CFRunLoopGetMain() или убедитесь, что AudioQueueNewOutput() и CFRunLoopGetCurrent() выполняются в главном потоке или потоке, которым вы управляете, и который имеет правильный цикл выполнения.

0 голосов
/ 28 сентября 2011

Попробуйте изменить self на (void*)self.Как это:

status = AudioQueueNewOutput(&_streamDescription, AQBufferCallback, (void*)self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_audioQueue);

...