ios - Audio Queue is playing too fast when the buffer size is small -


i able stream , play m4a files using audio file services + audio queue services. bitrate information of file not available audio queue because of file type.

after downloading of audio packets feed them player.

when choose buffer size around 32768 or 16384 since callbacks called less , and each buffer size big, seems playing @ regular speed. problem have play small files when choose small buffer size -512 or 1024 or 2048 8192- audio plays fast , occasional glitches.

i know calling objective-c function in c callback not great idea readability , easiness that. regardless think not problem.

// allocate buffers , prime queue data before starting audioqueuebufferref buffers[xmnumberplaybackbuffers];  int i; (i = 0; < 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 fill buffers data     myaqoutputcallback((__bridge void *)(self), queue, buffers[i]);  } 

i audio packets mutablearray of dictionaries...

#define xmnumberplaybackbuffers 4  #define xmaqdefaultbufsize 8192  #pragma mark playback callback function static void myaqoutputcallback(void *inuserdata, audioqueueref inaq, audioqueuebufferref incompleteaqbuffer) {     // called audio queue when has finished decoding our data.     // buffer free 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 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 enqued             if (sharedcache.audiocache) {                  nsmutabledictionary *mydict= [[nsmutabledictionary alloc] init];                 mydict=[sharedcache.audiocache objectatindex:currentlyreadingbufferindex];                  //why cant use 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];                    (int = 0; < 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 space remaining in buffer not enough packet, enqueue 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 kind of issue enqueuebuffer , didn't                         // make space new audio data out                         //                         if (bytesfilled + packetsize > packetbuffersize)                         {                             return;                         }                          // copy data audio queue buffer                         //error -66686 refers                         //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 last free packet description, enqueue 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 last free packet description, enqueue buffer\n");                                 //go next item on keepbuffer array                                 isbufferfilled=yes;                                  [self incrementbufferusedcount];                                 return;                             }                             else                             {                                 //if loop yes return first packet pointer , fill rest of buffer before enqueing                                 //set reading 0                                 //check space in buffer                                 //if space avaialbele create while loop till filled                                 //then enqueu buffer                                 currentlyreadingbufferindex=0;                             }                          }                     }                  }              }          }   } } 
#######################################

edit:
visiting in future, turns out exact problem audiostreampacketdescription packetdescs[xmaqmaxpacketdescs]; xmaqmaxpacketdescs here 512 when choose bigger buffer sizes enqueueing closer numbers 512 packets each buffer playing @ normal speed

however small buffer sizes 1024 2-3 packets total rest of 508 packets 0, , player trying play packetdescriptions 512 of them that's why fast.

i solved problem counting number of total number of packets put buffers created dynamic audiostreampacketdescription description 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];                                 } 

however accepted , rewarded 100 points dave answer's below, realized problem different.....

when allocate queue variable bit rate, instead of using xmaqdefaultbufsize, variable bit rate, need calculate packet size. pulled method this tutorial this book shows how it's done.

void derivebuffersize (audioqueueref audioqueue, audiostreambasicdescription asbdescription, float64 seconds, uint32 *outbuffersize) {     static const int maxbuffersize = 0x50000; // punting 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); } 

you use this.

float64 bufferdurseconds = 0.54321;   audiostreambasicdescription myasbd = self.format; // or  uint32 bufferbytesize;    derivebuffersize(recordstate.queue, myasbd, bufferdurseconds, &bufferbytesize);  audioqueueallocatebuffer(queue, bufferbytesize, &buffers[i]); 

using kaudioconverterpropertymaximumoutputpacketsize, calculate smallest buffer size can safely use unpredictable variable bit rate file. if file small, need identify samples padding codec.


Comments

Popular posts from this blog

Java 3D LWJGL collision -

spring - SubProtocolWebSocketHandler - No handlers -

methods - python can't use function in submodule -