2013-10-27 1 views
3

Я создаю проигрыватель FLAC на базе CoreAudio и столкнулся с непослушной проблемой с AudioQueues. Я инициализацией мои вещи, как это (переменные, начинающиеся с символа подчеркивания переменные экземпляра):CoreAudio AudioQueue stop issue

_flacDecoder = FLAC__stream_decoder_new(); 

    AudioStreamBasicDescription asbd = { 
     .mFormatID = kAudioFormatLinearPCM, 
     .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked, 
     .mSampleRate = 44100, 
     .mChannelsPerFrame = 2, 
     .mBitsPerChannel = 16, 
     .mBytesPerPacket = 4, 
     .mFramesPerPacket = 1, 
     .mBytesPerFrame = 4, 
     .mReserved = 0 
    }; 

    AudioQueueNewOutput(&asbd, HandleOutputBuffer, (__bridge void *)(self), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &_audioQueue); 

    for (int i = 0; i < kNumberBuffers; ++i) { 
     AudioQueueAllocateBuffer(_audioQueue, 0x10000, &_audioQueueBuffers[i]); 
    } 

    AudioQueueSetParameter(_audioQueue, kAudioQueueParam_Volume, 1.0); 

16 бит стерео PCM с частотой 44,1 кГц, довольно простой установки. kNumberBuffers равно 3, и каждый буфер равен 0x10000 байт. я заполнить буфера с этими обратными вызовами:

static void HandleOutputBuffer(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer){ 

    FLACPlayer * self = (__bridge FLACPlayer*)inUserData; 

    UInt32 largestBlockSizeInBytes = self->_currentStreamInfo.max_blocksize * self->_currentStreamInfo.channels * self->_currentStreamInfo.bits_per_sample/8; 

    inBuffer->mAudioDataByteSize = 0; 
    self->_buffer = inBuffer; 

    while(inBuffer->mAudioDataByteSize <= inBuffer->mAudioDataBytesCapacity - largestBlockSizeInBytes){ 
     FLAC__bool result = FLAC__stream_decoder_process_single(self->_flacDecoder); 
     assert(result); 

     if(FLAC__stream_decoder_get_state(self->_flacDecoder) == FLAC__STREAM_DECODER_END_OF_STREAM){ 
      AudioQueueStop(self->_audioQueue, false); 
      break; 
     } 
    } 

    AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); 
} 

static FLAC__StreamDecoderWriteStatus flacDecoderWriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data){ 

    FLACPlayer * self = (__bridge FLACPlayer *)client_data; 

    assert(frame->header.bits_per_sample == 16); // TODO 

    int16_t * bufferWritePosition = (int16_t*)((uint8_t*)self->_buffer->mAudioData + self->_buffer->mAudioDataByteSize); 
    for(int i = 0; i < frame->header.blocksize; i++){ 
     for(int j = 0; j < frame->header.channels; j++){ 
      *bufferWritePosition = (int16_t)buffer[j][i]; 
      bufferWritePosition++; 
     } 
    } 

    int totalFramePayloadInBytes = frame->header.channels * frame->header.blocksize * frame->header.bits_per_sample/8; 
    self->_buffer->mAudioDataByteSize += totalFramePayloadInBytes; 

    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; 
} 

static void flacDecoderMetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data){ 

    FLACPlayer * self = (__bridge FLACPlayer*) client_data; 

    if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO){ 
     self->_currentStreamInfo = metadata->data.stream_info; 
    } 
} 

В основном, когда очередь запрашивает новый буфер, я заполнить буфер из FLAC__stream_decoder, то я епдиеий его. Как и все остальные. Когда libFLAC сообщает мне, что я дошел до конца своего файла, я говорю, что AudioQueue останавливается асинхронно, пока он не поглотит все содержимое буферов. Однако, вместо того, чтобы проигрывать до конца, воспроизведение останавливается немного раньше, чем нужно. Если я удалю эту строку:

AudioQueueStop(self->_audioQueue, false); 

все работает нормально; звук воспроизводится от конца до конца, хотя моя очередь продолжает работать до конца времени. Если изменить эту строку на это:

AudioQueueStop(self->_audioQueue, true); 

то воспроизведение немедленно останавливается/синхронно, как и следовало ожидать от документации Apple:

Если вы проходите так, остановка происходит немедленно (т.е. , синхронно). Если вы передадите false, функция немедленно вернется, , но звуковая очередь не остановится до тех пор, пока не будут проиграны их буферы с очередями или записаны (то есть останов происходит асинхронно). Звуковая очередь обратные вызовы вызываются по мере необходимости, пока очередь не остановится.

Мои вопросы: - я делаю что-то неправильно? - как я могу воспроизвести свой звук до конца и правильно закрыть очередь?

ответ

0

Конечно, после борьбы с этим материалом в течение нескольких часов, я нашел протокол решения после публикации этого вопроса ... Проблемы заключалась в том, что не звуковые сообщениях заботятся о буферах помещён после вызывающего AudioQueueStop (..., false). Так что теперь я кормлю очереди, как это, и все работает как шарм:

static void HandleOutputBuffer(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer){ 

    FLACPlayer * self = (__bridge FLACPlayer*)inUserData; 

    UInt32 largestBlockSizeInBytes = self->_currentStreamInfo.max_blocksize * self->_currentStreamInfo.channels * self->_currentStreamInfo.bits_per_sample/8; 

    inBuffer->mAudioDataByteSize = 0; 
    self->_buffer = inBuffer; 

    bool shouldStop = false; 

    while(inBuffer->mAudioDataByteSize <= inBuffer->mAudioDataBytesCapacity - largestBlockSizeInBytes){ 
     FLAC__bool result = FLAC__stream_decoder_process_single(self->_flacDecoder); 
     assert(result); 

     if(FLAC__stream_decoder_get_state(self->_flacDecoder) == FLAC__STREAM_DECODER_END_OF_STREAM){ 
      shouldStop = true; 
      break; 
     } 
    } 

    AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); 
    if(shouldStop){ 
     AudioQueueStop(self->_audioQueue, false); 
    } 
} 
+0

Не осмысление - Вы хотите сказать, »... не звуковые сообщения заботятся о буферах ** ПОСЛЕ установлена ​​в очереди * * вызов AudioQueueStop .... ". Я думаю, что каждый буфер, выделенный перед остановкой очереди, будет воспроизведен. – helioz

+0

Вы правы! Моя вина –

 Смежные вопросы

  • Нет связанных вопросов^_^