2013-10-27 4 views
3

저는 CoreAudio 기반 FLAC 플레이어를 제작 중이며 AudioQueues와 관련된 문제가 있습니다. 나는이 같은 내 물건을 초기화하고 있습니다 (밑줄로 시작하는 변수 인스턴스 변수) :CoreAudio AudioQueue 중지 문제

_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 비트 44.1 kHz의에서 스테레오 PCM, 꽤 기본 설정. 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); 

을 애플의 문서에서 예상대로 다음 재생이 즉시/동 기적으로 중지 , ). false를 전달하면 함수는 즉각적으로 을 반환하지만 지연 대기열 버퍼가 으로 재생되거나 (즉, 비동기 적으로 중지 될 때까지) 오디오 대기열이 중지되지 않습니다. 오디오 대기열 콜백은 실제로 대기열이 멈출 때까지 필요에 따라 호출됩니다.

내 질문은 : - 내가 잘못하고 있니? - 끝까지 오디오를 재생하고 큐를 적절히 종료 할 수 있습니까? 물론

답변

0

가, 시간이 물건과 사투를 벌인 후, 나는이 질문을 게시 한 후 솔루션을 분을 발견했습니다 ... 문제는 AudioQueue은 (버퍼 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

이 - 당신이 ... AudioQueue가 큐에 버퍼에 대해 상관하지 않는다 " 말을 의미 않았다 ** AFTER * * AudioQueueStop 호출 .... ". 대기열이 멈추기 전에 대기열에있는 모든 버퍼가 재생됩니다. – helioz

+0

당신은 맞습니다! Mea culpa –