4

요즘은 iPhone에서 AudioQueue 서비스를 사용하여 네트워크 오디오 스트림 (MP3 패킷 형식)을 재생하는 방법을 찾기 위해 고심하고 있습니다.AudioQueue 서비스를 사용한 재생 MP3 데이터 버퍼 : 프라임 실패 (-50)

이 목표를 연속적으로 달성하려면 먼저 AudioQueue를 사용하여 재생할 공통 로컬 MP3 파일을 얻었고 작동합니다. 그리고 나서 AudioFileReadPackets를 stdio 함수 fread로 바꿨고 매번 AudioFileReadPackets와 같은 양의 mp3 패킷을 네트워크에서 오는 오디오 스트림을 시뮬 레이팅하기 위해 바꿨습니다. 그러나 이번에는 오류가 발생했습니다 :

2011-09-28 14:21:28.245 SunFlower[1554:207] Prime: Exiting because mConverterError is -50 (0x11940 req, 0x0 primed) 
2011-09-28 14:21:28.253 SunFlower[1554:207] Prime failed (-50); will stop (72000/0 frames) 

"Prime failed (-50)"오류의 원인을 아는 사람이 있습니까? 도움말 zzzzzzz

******************************************* *************************************************** *************************************************** *********************. 전에

  1. "를 교체 한 후" "교체하기 전에"과 : 나는 교체 작업에 무슨 짓을했는지, 내가 두 부분이 있습니다 당신에게 코드의 주요 변경 부분을 보여주고 싶습니다

    설명하려면 (로컬 MP3 파일 playbak) 교체 :

1)의 오디오 큐 runloop 콜백

static void HandleOutputBuffer(void    *aqData, 
           AudioQueueRef  inAQ, 
           AudioQueueBufferRef inBuffer) 
{ 
    AQPlayerState *pAqData = (AQPlayerState *) aqData; 
    UInt32 numBytesReadFromFile; 
    UInt32 numPackets = pAqData->mNumPacketsToRead; 
    UInt32 i = 0; 

    printf("HandleOutputBuffer::Start!\n"); 
    //If the audio queue is stopped, returns immediately 
    if(pAqData->mIsRunning == 0) 
    { 
     printf("HandleOutputBuffer::Error Return!\n"); 
     return; 
    } 

    //Read a packet of audio data from file stream 
    AudioFileReadPackets(pAqData->mAudioFile, 
         false, 
         &numBytesReadFromFile, 
         pAqData->mPacketDescs, 
         pAqData->mCurrentPacket, 
         &numPackets, 
         inBuffer->mAudioData); 

    //Enqueue the audio packet into the audio queue 
    if(numPackets > 0) 
    { 
     printf("HandleOutputBuffer::Step 1!\n"); 
     inBuffer->mAudioDataByteSize = numBytesReadFromFile; 
     AudioQueueEnqueueBuffer(pAqData->mQueue, 
           inBuffer, 
           (pAqData->mPacketDescs ? numPackets : 0), 
           pAqData->mPacketDescs); 

     pAqData->mCurrentPacket += numPackets; 
    } 
    else 
    { 
     printf("HandleOutputBuffer::Step 2!\n"); 
     AudioQueueStop(pAqData->mQueue, 
         false); 
     pAqData->mIsRunning = false; 
    } 
} 

2) 오디오 파일 열기 0,123,516

OSStatus AqOpenAudioFile(char *filePath, AQPlayerState *pAqData) 
{ 
    CFURLRef audioFileURL; 
    OSStatus result; 
    UInt32 maxPacketSize; 
    UInt32 propertySize = sizeof (maxPacketSize); 

    audioFileURL = 
     CFURLCreateFromFileSystemRepresentation(NULL, 
               (const UInt8 *) filePath, 
               strlen (filePath), 
               false); 

    result = AudioFileOpenURL(audioFileURL, 
           kAudioFileReadPermission, 
           0, 
           &(pAqData->mAudioFile)); 
    CFRelease(audioFileURL); 

    AudioFileGetProperty(pAqData->mAudioFile, 
         kAudioFilePropertyPacketSizeUpperBound, 
         &propertySize, 
         &maxPacketSize); 

    DeriveBufferSize(pAqData->mDataFormat, 
        maxPacketSize, 
        0.5, 
        &(pAqData->bufferByteSize), 
        &(pAqData->mNumPacketsToRead)); 

    return result; 
} 

3) (playbak의 MP3 데이터 버퍼가 FREAD에 의해 얻을) 교체 한 후 오디오 큐

OSStatus AqCreateAudioQueue(AQPlayerState *pAqData) 
{ 
    UInt32 dataFormatSize = sizeof (AudioStreamBasicDescription); 
    OSStatus result; 
    bool isFormatVBR; 
    UInt32 cookieSize = sizeof (UInt32); 
    bool couldNotGetProperty; 

    AudioFileGetProperty(pAqData->mAudioFile, 
         kAudioFilePropertyDataFormat, 
         &dataFormatSize, 
         &(pAqData->mDataFormat)); 

    result = AudioQueueNewOutput(&(pAqData->mDataFormat), 
           HandleOutputBuffer, 
           pAqData, 
           CFRunLoopGetCurrent(), 
           kCFRunLoopCommonModes, 
           0, 
           &(pAqData->mQueue)); 

    //Configurate the VBR property if any 
    isFormatVBR = (pAqData->mDataFormat.mBytesPerPacket == 0 || 
        pAqData->mDataFormat.mFramesPerPacket == 0); 

    if(isFormatVBR) 
    { 
     pAqData->mPacketDescs = 
      (AudioStreamPacketDescription*)malloc(pAqData->mNumPacketsToRead * sizeof(AudioStreamPacketDescription)); 
    } 
    else 
    { 
     pAqData->mPacketDescs = NULL; 
    } 

    //Set Metadata for Audio Queue 
    couldNotGetProperty = 
     AudioFileGetPropertyInfo(pAqData->mAudioFile, 
           kAudioFilePropertyMagicCookieData, 
           &cookieSize, 
           NULL); 

    if (!couldNotGetProperty && cookieSize) 
    { 
     char* magicCookie = (char *)malloc(cookieSize); 
     AudioFileGetProperty(pAqData->mAudioFile, 
          kAudioFilePropertyMagicCookieData, 
          &cookieSize, 
          magicCookie); 

     AudioQueueSetProperty(pAqData->mQueue, 
           kAudioQueueProperty_MagicCookie, 
           magicCookie, 
           cookieSize); 
     free(magicCookie); 
    } 

    //Set the playback gain 
    AudioQueueSetParameter(pAqData->mQueue, 
          kAudioQueueParam_Volume, 
          AQ_PLAYBACK_GAIN);  
} 

2. 만들기 : 원활하게 포팅 코드를 만들기 위해

를, 나는 실행 - 복사 pAqData-> bufferByteSize, pAqData-> mNumPacketsToRead, pAqData-> mDataFormat ... 등과 같은 중요한 변수의 시간 값. 그리고 대체 된 코드에서 복사 된 값을 사용하여 이러한 변수를 직접 초기화하십시오. 이 동작의 목적은 AudioToolbox 프레임 워크의 인터페이스를 버리는 것입니다 : AudioFileOpenURL, AudioFileGetProperty, AudioFileReadPackets ... 그리고 stdio 함수 fread를 사용하여 mp3 패킷을 직접 가져올 수 있습니다. 변경된 코드는 다음과 같다 :

1)의 오디오 큐 runloop 콜백 (이전 코드에서 AudioFileReadPackets 338 개 패킷 전부 129,792 바이트를 읽어 I 직접

static void HandleOutputBuffer(void    *aqData, 
           AudioQueueRef  inAQ, 
           AudioQueueBufferRef inBuffer) 
{ 
    AQPlayerState *pAqData = (AQPlayerState *) aqData; 
    UInt32 numBytesReadFromFile; 
    UInt32 numPackets = pAqData->mNumPacketsToRead; 
    UInt32 i = 0; 

    printf("HandleOutputBuffer::Start!\n"); 
    //If the audio queue is stopped, returns immediately 
    if(pAqData->mIsRunning == 0) 
    { 
     printf("HandleOutputBuffer::Error Return!\n"); 
     return; 
    } 

    //Read a packet of audio data using fread 
    memset(audio_buffer, 0, 327680); 
    memset(inBuffer->mAudioData, 0, 327680); 
    pAqData->mPacketDescs->mStartOffset = 0; 
    pAqData->mPacketDescs->mVariableFramesInPacket = 0; 
    pAqData->mPacketDescs->mDataByteSize = 384; 

    numBytesReadFromFile = fread(audio_buffer, sizeof(uint8_t), 129792, source_file); 
    numPackets = 338; 
    memcpy(inBuffer->mAudioData, audio_buffer, 327680); 

    //Enqueue the audio packet into the audio queue 
    if(numPackets > 0) 
    { 
     printf("HandleOutputBuffer::Step 1!\n"); 
     inBuffer->mAudioDataByteSize = numBytesReadFromFile; 
     AudioQueueEnqueueBuffer(pAqData->mQueue, 
           inBuffer, 
           (pAqData->mPacketDescs ? numPackets : 0), 
           pAqData->mPacketDescs); 

     pAqData->mCurrentPacket += numPackets; 
    } 
    else 
    { 
     printf("HandleOutputBuffer::Step 2!\n"); 
     AudioQueueStop(pAqData->mQueue, 
         false); 
     pAqData->mIsRunning = false; 
    } 
} 
) 대체 코드로이 값을 복사 pAqData-> 지역 MP3 재생 모드에 할당 된 값 mDataFormat을) 직접 (오디오 큐 만들기))

OSStatus AqOpenAudioFile(char *filePath, AQPlayerState *pAqData) 
{ 
    CFURLRef audioFileURL; 
    OSStatus result; 
    UInt32 maxPacketSize; 
    UInt32 propertySize = sizeof (maxPacketSize); 

    source_file = fopen(filePath, "r"); 

    memset(audio_buffer, 0, 327680); 
    fread(audio_buffer, sizeof(uint8_t), 32, source_file); 

    pAqData->bufferByteSize = 327680; 
    pAqData->mNumPacketsToRead = 338; 

    return result; 
} 

3 AudioFileOpenURL을 대체 초기화

2) 열기 오디오 파일 (사용하면 fopen

OSStatus AqCreateAudioQueue(AQPlayerState *pAqData) 
{ 
    UInt32 dataFormatSize = sizeof (AudioStreamBasicDescription); 
    OSStatus result; 
    bool isFormatVBR; 
    UInt32 cookieSize = sizeof (UInt32); 
    bool couldNotGetProperty; 


    memset(&(pAqData->mDataFormat), 0, sizeof(AudioStreamBasicDescription)); 
    pAqData->mDataFormat.mSampleRate = 48000; 
    pAqData->mDataFormat.mFormatID = 778924083;//mp3 ID 
    pAqData->mDataFormat.mFramesPerPacket = 1152; 
    pAqData->mDataFormat.mChannelsPerFrame = 2; 


    result = AudioQueueNewOutput(&(pAqData->mDataFormat), 
           HandleOutputBuffer, 
           pAqData, 
           CFRunLoopGetCurrent(), 
           kCFRunLoopCommonModes, 
           0, 
           &(pAqData->mQueue)); 

    //Configurate the VBR property if any 
    isFormatVBR = (pAqData->mDataFormat.mBytesPerPacket == 0 || 
        pAqData->mDataFormat.mFramesPerPacket == 0); 

    if(isFormatVBR) 
    { 
     pAqData->mPacketDescs = 
      (AudioStreamPacketDescription*)malloc(pAqData->mNumPacketsToRead * 
               sizeof(AudioStreamPacketDescription)); 
    } 
    else 
    { 
     pAqData->mPacketDescs = NULL; 
    } 

    //Set the playback gain 
    AudioQueueSetParameter(pAqData->mQueue, 
          kAudioQueueParam_Volume, 
          AQ_PLAYBACK_GAIN);  
} 

답변

3

얘들 아 :

나는 근본 원인을 발견!

문제는 HandleOutputBuffer (변경된 것)에서 왔습니다!

매번 mp3 데이터의 338 패킷 (단 하나의 패킷이 아님) [pAqData-> mPacketDescs]은 단일 변수가 아니기 때문에 실제로 338 개의 배열 항목 크기를 갖는 배열입니다. 따라서 우리는 338 개의 모든 배열 항목을 초기화해야합니다.

그래서 우리는 코드를 변경해야합니다

static void HandleOutputBuffer(void    *aqData, 
           AudioQueueRef  inAQ, 
           AudioQueueBufferRef inBuffer) 
{ 
    ... 
    pAqData->mPacketDescs->mStartOffset = 0; 
    pAqData->mPacketDescs->mVariableFramesInPacket = 0; 
    pAqData->mPacketDescs->mDataByteSize = 384; 
    ... 
} 

마지막으로, 문제가 해결

static void HandleOutputBuffer(void    *aqData, 
           AudioQueueRef  inAQ, 
           AudioQueueBufferRef inBuffer) 
{ 
    ... 
    for (i = 0; i < 338; i++) 
    { 
     pAqData->mPacketDescs[i].mStartOffset = PACKET_SIZE * i; 
     pAqData->mPacketDescs[i].mVariableFramesInPacket = 0; 
     pAqData->mPacketDescs[i].mDataByteSize = PACKET_SIZE; 
    } 
    ... 
} 

에!

+0

동일한 문제가 있습니다. 그러나 나는 어디에서 HandleOutputBuffer를 바꾸거나 재정의해야하는지 이해할 수 없다. – Aplextor