2015-05-29 10 views
6

Ich kann m4a Dateien mit Audio File Services + Audio Queue Services streamen und abspielen. Bitrate-Informationen der Datei sind aufgrund des Dateityps für die Audio-Warteschlange nicht verfügbar.Audio Queue spielt zu schnell, wenn die Puffergröße klein ist

Nach dem Herunterladen aller Audiopakete füttere ich sie dem Player.

Wenn ich eine Puffergröße um 32768 oder 16384 wähle, da Callbacks seltener aufgerufen werden und jede Puffergröße groß ist, scheint sie fast mit normaler Geschwindigkeit zu spielen. Problem ist manchmal, dass ich auch kleine Dateien abspielen muss, aber wenn ich eine kleine Puffergröße -512 oder 1024 oder 2048 bis zu 8192- wähle, wird Audio sehr schnell und mit gelegentlichen Störungen abgespielt.

Ich weiß Calling Objective-C-Funktion in c Callback ist keine gute Idee, aber für die Lesbarkeit und Leichtigkeit, die ich tun. Egal, ich denke, das ist nicht das Problem.

// allocate the buffers and prime the queue with some data before starting 
AudioQueueBufferRef buffers[XMNumberPlaybackBuffers]; 

int i; 
for (i = 0; i < XMNumberPlaybackBuffers; ++i) 
{ 
    err=AudioQueueAllocateBuffer(queue, XMAQDefaultBufSize, &buffers[i]); 
    if (err) { 
     [self failWithErrorCode:err customError:AP_AUDIO_QUEUE_BUFFER_ALLOCATION_FAILED]; 
    } 
    @synchronized(self) 
    { 
     state=AP_WAITING_FOR_QUEUE_TO_START; 
    } 


    // manually invoke callback to fill buffers with data 
    MyAQOutputCallBack((__bridge void *)(self), queue, buffers[i]); 

} 

ich auch Audio-Pakete von einem MutableArray der Wörterbücher ...

#define XMNumberPlaybackBuffers 4 
#define XMAQDefaultBufSize 8192 
#pragma mark playback callback function 
static void MyAQOutputCallBack(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) 
{ 
    // this is called by the audio queue when it has finished decoding our data. 
    // The buffer is now free to be reused. 
    NSLog(@"MyAQOutputCallBack.."); 

    //printf("MyAQOutputCallBack...\n"); 
    XMAudioPlayer* player = (__bridge XMAudioPlayer *)inUserData; 
    [player handleBufferCompleteForQueue:inAQ buffer:inCompleteAQBuffer]; 
    //printf("##################\n"); 

} 

- (void)handleBufferCompleteForQueue:(AudioQueueRef)inAQ 
           buffer:(AudioQueueBufferRef)inBuffer 
{ 
    //NSLog(@"######################\n"); 
    AudioTimeStamp queueTime; 
    Boolean discontinuity; 
    err = AudioQueueGetCurrentTime(queue, NULL, &queueTime, &discontinuity); 
    printf("queueTime.mSampleTime %.2f\n",queueTime.mSampleTime/dataFormat.mSampleRate); 

    AudioStreamPacketDescription packetDescs[XMAQMaxPacketDescs]; // packet descriptions for enqueuing audio 

    BOOL isBufferFilled=NO; 

    size_t bytesFilled=0;    // how many bytes have been filled 
    size_t packetsFilled=0;   // how many packets have been filled 
    size_t bufSpaceRemaining; 

    while (isBufferFilled==NO && isEOF==NO) { 
     if (currentlyReadingBufferIndex<[sharedCache.audioCache count]) { 

      //loop thru untill buffer is enqued 
      if (sharedCache.audioCache) { 

       NSMutableDictionary *myDict= [[NSMutableDictionary alloc] init]; 
       myDict=[sharedCache.audioCache objectAtIndex:currentlyReadingBufferIndex]; 

       //why I cant use this info? 
       //UInt32 inNumberBytes =[[myDict objectForKey:@"inNumberBytes"] intValue]; 
       UInt32 inNumberPackets =[[myDict objectForKey:@"inNumberPackets"] intValue]; 
       NSData *convert=[myDict objectForKey:@"inInputData"]; 
       const void *inInputData=(const char *)[convert bytes]; 

       //AudioStreamPacketDescription *inPacketDescriptions; 
       AudioStreamPacketDescription *inPacketDescriptions= malloc(sizeof(AudioStreamPacketDescription)); 

       NSNumber *mStartOffset = [myDict objectForKey:@"mStartOffset"]; 
       NSNumber *mDataByteSize = [myDict objectForKey:@"mDataByteSize"]; 
       NSNumber *mVariableFramesInPacket = [myDict objectForKey:@"mVariableFramesInPacket"]; 

       inPacketDescriptions->mVariableFramesInPacket=[mVariableFramesInPacket intValue]; 
       inPacketDescriptions->mStartOffset=[mStartOffset intValue]; 
       inPacketDescriptions->mDataByteSize=[mDataByteSize intValue]; 



       for (int i = 0; i < inNumberPackets; ++i) 
       { 
        SInt64 packetOffset = [mStartOffset intValue]; 
        SInt64 packetSize = [mDataByteSize intValue]; 
        //printf("packetOffset %lli\n",packetOffset); 
        //printf("packetSize %lli\n",packetSize); 

        currentlyReadingBufferIndex++; 

        if (packetSize > packetBufferSize) 
        { 
         //[self failWithErrorCode:AS_AUDIO_BUFFER_TOO_SMALL]; 
        } 

        bufSpaceRemaining = packetBufferSize - bytesFilled; 
        //printf("bufSpaceRemaining %zu\n",bufSpaceRemaining); 

        // if the space remaining in the buffer is not enough for this packet, then enqueue the buffer. 
        if (bufSpaceRemaining < packetSize) 
        { 


         inBuffer->mAudioDataByteSize = (UInt32)bytesFilled; 
         err=AudioQueueEnqueueBuffer(inAQ,inBuffer,(UInt32)packetsFilled,packetDescs); 
         if (err) { 
          [self failWithErrorCode:err customError:AP_AUDIO_QUEUE_ENQUEUE_FAILED]; 
         } 
         isBufferFilled=YES; 
         [self incrementBufferUsedCount]; 
         return; 

        } 
        @synchronized(self) 
        { 

         // 
         // If there was some kind of issue with enqueueBuffer and we didn't 
         // make space for the new audio data then back out 
         // 
         if (bytesFilled + packetSize > packetBufferSize) 
         { 
          return; 
         } 

         // copy data to the audio queue buffer 
         //error -66686 refers to 
         //kAudioQueueErr_BufferEmpty   = -66686 
         //memcpy((char*)inBuffer->mAudioData + bytesFilled, (const char*)inInputData + packetOffset, packetSize); 
         memcpy(inBuffer->mAudioData + bytesFilled, (const char*)inInputData + packetOffset, packetSize); 

         // fill out packet description 
         packetDescs[packetsFilled] = inPacketDescriptions[0]; 
         packetDescs[packetsFilled].mStartOffset = bytesFilled; 
         bytesFilled += packetSize; 
         packetsFilled += 1; 
         free(inPacketDescriptions); 
        } 

        // if that was the last free packet description, then enqueue the buffer. 
//     size_t packetsDescsRemaining = kAQMaxPacketDescs - packetsFilled; 
//     if (packetsDescsRemaining == 0) { 
//       
//     } 

        if (sharedCache.numberOfToTalPackets>0) 
        { 
         if (currentlyReadingBufferIndex==[sharedCache.audioCache count]-1) { 

          if (loop==NO) { 
           inBuffer->mAudioDataByteSize = (UInt32)bytesFilled; 
           lastEnqueudBufferSize=bytesFilled; 
           lastbufferPacketCount=(int)packetsFilled; 
           err=AudioQueueEnqueueBuffer(inAQ,inBuffer,(UInt32)packetsFilled,packetDescs); 
           if (err) { 
            [self failWithErrorCode:err customError:AP_AUDIO_QUEUE_ENQUEUE_FAILED]; 
           } 
           printf("if that was the last free packet description, then enqueue the buffer\n"); 
           //go to the next item on keepbuffer array 
           isBufferFilled=YES; 

           [self incrementBufferUsedCount]; 
           return; 
          } 
          else 
          { 
           //if loop is yes return to first packet pointer and fill the rest of the buffer before enqueing it 
           //set the currently reading to zero 
           //check the space in buffer 
           //if space is avaialbele create a while loop till it is filled 
           //then enqueu the buffer 
           currentlyReadingBufferIndex=0; 
          } 

         } 
        } 

       } 

      } 

     } 
    } 
} 
######################## ###############

EDIT:
Für alle, die dies in der Zukunft besucht, schaltet sie mein genaues Problem war AudioStreamPacketDescription packetDescs[XMAQMaxPacketDescs];, so XMAQMaxPacketDescs hier ist 512, wenn ich größere Puffergrößen wählen Ich habe nähere Zahlen zu 512 Paketen für jeden Puffer eingegeben, so dass es mit normaler Geschwindigkeit abgespielt wurde

Jedoch für kleine Puffergrößen wie 1024 sind das nur 2-3 Pakete insgesamt, also war der Rest der 508 Pakete 0, und der Spieler versuchte alle Paketbeschreibungen 512 davon zu spielen und deshalb war es zu schnell.

gelöst ich das Problem, indem die Anzahl der Gesamtanzahl von Paketen zu zählen, die ich die Puffer setzen dann habe ich eine dynamische AudioStreamPacketDescription Beschreibung array ..

AudioStreamPacketDescription * tempDesc = (AudioStreamPacketDescription *)(malloc(packetsFilledDesc * sizeof(AudioStreamPacketDescription))); 
           memcpy(tempDesc,packetDescs, packetsFilledDesc*sizeof(AudioStreamPacketDescription)); 

           err = AudioQueueEnqueueBuffer(inAQ,inBuffer,packetsFilledDesc,tempDesc); 
           if (err) { 
            [self failWithErrorCode:err customError:AP_AUDIO_QUEUE_ENQUEUE_FAILED]; 
           } 

Jedoch habe ich akzeptiert und belohnt 100 Punkte DAVE Antwort unten ist bald erkannte ich, dass mein Problem anders war.

Antwort

1

Wenn Sie Ihre Warteschlange für variable Bitrate zuweisen, anstatt XMAQDefaultBufSize für variable Bitrate zu verwenden, müssen Sie die Paketgröße berechnen. Ich zog eine Methode aus this Tutorial von this Buch, das zeigt, wie es gemacht wird.

void DeriveBufferSize (AudioQueueRef audioQueue, AudioStreamBasicDescription ASBDescription, Float64 seconds, UInt32 *outBufferSize) 
{ 
    static const int maxBufferSize = 0x50000; // punting with 50k 
    int maxPacketSize = ASBDescription.mBytesPerPacket; 
    if (maxPacketSize == 0) 
    {       
     UInt32 maxVBRPacketSize = sizeof(maxPacketSize); 
     AudioQueueGetProperty(audioQueue, kAudioConverterPropertyMaximumOutputPacketSize, &maxPacketSize, &maxVBRPacketSize); 
    } 

    Float64 numBytesForTime = ASBDescription.mSampleRate * maxPacketSize * seconds; 
    *outBufferSize = (UInt32)((numBytesForTime < maxBufferSize) ? numBytesForTime : maxBufferSize); 
} 

Sie würden es so verwenden.

Float64 bufferDurSeconds = 0.54321; 
AudioStreamBasicDescription myAsbd = self.format; // or something 

UInt32 bufferByteSize; 
DeriveBufferSize(recordState.queue, myAsbd, bufferDurSeconds, &bufferByteSize); 

AudioQueueAllocateBuffer(queue, bufferByteSize, &buffers[i]); 

Mit kAudioConverterPropertyMaximumOutputPacketSize, berechnen Sie die kleinste Puffergröße Sie sicher für die unberechenbare Variable Bitrate-Datei verwenden können. Wenn Ihre Datei zu klein ist, müssen Sie nur identifizieren, welche Beispiele für den Codec aufgefüllt werden.

+0

hmm ist nicht dieses Beispiel aus dem Learning Core Audio Book? Eigentlich habe ich die Audiowarteschlange erstellt, als ich das Buch betrachtete, ich erinnere mich an diesen Ansatz, der für mich nicht funktionierte ... aber lass mich es noch einmal versuchen. Vielleicht habe ich vorher etwas falsch gemacht ... https://github.com/abbood/Learning-Core-Audio-Book-Code-Sample/blob/master/CH05_Player/CH05_Player/main.c –

+0

@Spacedust_ Gleicher Ansatz, anderes Beispiel . Ich habe bereits in meiner Antwort darauf hingewiesen. – dave234

+0

ok Ich erinnerte mich, warum dies nicht für mich funktioniert '// wenn Frames pro Paket ist Null, dann hat der Codec keine vorhersagbare Paket == Zeit \t \t // so können wir nicht das (wir wissen nicht, wie viele Pakete repräsentieren einen Zeitraum \t \t // Wir werden nur eine Standardpuffergröße 'für jedes Audiopaket zurückgeben' NSNumber * mVariableFramesInPacket = [myDict objectForKey: @ "mVariableFramesInPacket"]; 'das ist immer Null –

Verwandte Themen