title: How to correctly read decoded PCM samples on iOS using AVAssetReader -- currently incorrect decoding
body: <p>I am currently working on an application as part of my Bachelor in Computer Science. The application will correlate data from the iPhone hardware (accelerometer, gps) and music that is being played.</p>
  
  <p>The project is still in its infancy, having worked on it for only 2 months.</p>
  
  <p>The moment that I am right now, and where I need help, is reading PCM samples from songs from the itunes library, and playing them back using and audio unit.
  Currently the implementation I would like working does the following: chooses a random song from iTunes, and reads samples from it when required, and stores in a buffer, lets call it sampleBuffer. Later on in the consumer model the audio unit (which has a mixer and a remoteIO output) has a callback where I simply copy the required number of samples from sampleBuffer into the buffer specified in the callback. What i then hear through the speakers is something not quite what i expect; I can recognize that it is playing the song however it seems that it is incorrectly decoded and it has a lot of noise! I attached an image which shows the first ~half a second (24576 samples @ 44.1kHz), and this does not resemble a normall looking output.
  Before I get into the listing I have checked that the file is not corrupted, similarily I have written test cases for the buffer (so I know the buffer does not alter the samples), and although this might not be the best way to do it (some would argue to go the audio queue route), I want to perform various manipulations on the samples aswell as changing the song before it is finished, rearranging what song is played, etc. Furthermore, maybe there are some incorrect settings in the audio unit, however, the graph that displays the samples (which shows the samples are decoded incorrectly) is taken straight from the buffer, thus I am only looking now to solve why the reading from the disk and decoding does not work correctly. Right now i simply want to get a play through working.
  Cant post images because new to stackoverflow so heres the link to the image: <a href="http://i.stack.imgur.com/RHjlv.jpg" rel="nofollow">http://i.stack.imgur.com/RHjlv.jpg</a></p>
  
  <p>Listing:</p>
  
  <p>This is where I setup the audioReadSettigns which will be used for the AVAssetReaderAudioMixOutput</p>
  
  <pre><code>// Set the read settings
      audioReadSettings = [[NSMutableDictionary alloc] init];
      [audioReadSettings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM]
                           forKey:AVFormatIDKey];
      [audioReadSettings setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
      [audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
      [audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
      [audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsNonInterleaved];
      [audioReadSettings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
  </code></pre>
  
  <p>Now the following code listing is a method that receives an NSString with the persistant_id of the song:</p>
  
  <pre><code>-(BOOL)setNextSongID:(NSString*)persistand_id {
  
  assert(persistand_id != nil);
  
  MPMediaItem *song = [self getMediaItemForPersistantID:persistand_id];
  NSURL *assetUrl = [song valueForProperty:MPMediaItemPropertyAssetURL];
  AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetUrl 
                                              options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] 
                                                                                  forKey:AVURLAssetPreferPreciseDurationAndTimingKey]];
  
  
  NSError *assetError = nil;
  
  assetReader = [[AVAssetReader assetReaderWithAsset:songAsset error:&amp;assetError] retain];
  
  if (assetError) {
      NSLog(@"error: %@", assetError);
      return NO;
  }
  
  CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, songAsset.duration);
  [assetReader setTimeRange:timeRange];
  
  track = [[songAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
  
  assetReaderOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:[NSArray arrayWithObject:track]
                                                                              audioSettings:audioReadSettings];
  
  if (![assetReader canAddOutput:assetReaderOutput]) {
      NSLog(@"cant add reader output... die!");
      return NO;
  }
  
  [assetReader addOutput:assetReaderOutput];
  [assetReader startReading];
  
  // just getting some basic information about the track to print
  NSArray *formatDesc = ((AVAssetTrack*)[[assetReaderOutput audioTracks] objectAtIndex:0]).formatDescriptions;
  for (unsigned int i = 0; i &lt; [formatDesc count]; ++i) {
      CMAudioFormatDescriptionRef item = (CMAudioFormatDescriptionRef)[formatDesc objectAtIndex:i];
      const CAStreamBasicDescription *asDesc = (CAStreamBasicDescription*)CMAudioFormatDescriptionGetStreamBasicDescription(item);
      if (asDesc) {
          // get data
          numChannels = asDesc-&gt;mChannelsPerFrame;
          sampleRate = asDesc-&gt;mSampleRate;
          asDesc-&gt;Print();
      }
  }
  [self copyEnoughSamplesToBufferForLength:24000];
  return YES;
  }
  </code></pre>
  
  <p>The following presents the function -(void)copyEnoughSamplesToBufferForLength:</p>
  
  <pre><code>-(void)copyEnoughSamplesToBufferForLength:(UInt32)samples_count {
  
  [w_lock lock];
  int stillToCopy = 0;
  if (sampleBuffer-&gt;numSamples() &lt; samples_count) {
      stillToCopy = samples_count;
  }
  
  NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
  
  
  CMSampleBufferRef sampleBufferRef;
  SInt16 *dataBuffer = (SInt16*)malloc(8192 * sizeof(SInt16));
  
  int a = 0;
  
  while (stillToCopy &gt; 0) {
  
      sampleBufferRef = [assetReaderOutput copyNextSampleBuffer];
      if (!sampleBufferRef) {
          // end of song or no more samples
          return;
      }
  
      CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBufferRef);
      CMItemCount numSamplesInBuffer = CMSampleBufferGetNumSamples(sampleBufferRef);
      AudioBufferList audioBufferList;
  
      CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBufferRef,
                                                              NULL,
                                                              &amp;audioBufferList,
                                                              sizeof(audioBufferList),
                                                              NULL,
                                                              NULL,
                                                              0,
                                                              &amp;blockBuffer);
  
      int data_length = floorf(numSamplesInBuffer * 1.0f);
  
      int j = 0;
  
      for (int bufferCount=0; bufferCount &lt; audioBufferList.mNumberBuffers; bufferCount++) {
          SInt16* samples = (SInt16 *)audioBufferList.mBuffers[bufferCount].mData;
          for (int i=0; i &lt; numSamplesInBuffer; i++) {
              dataBuffer[j] = samples[i];
              j++;
          }
      }
  
      CFRelease(sampleBufferRef);
      sampleBuffer-&gt;putSamples(dataBuffer, j);
      stillToCopy = stillToCopy - data_length;
  }
  
  free(dataBuffer);
  [w_lock unlock];
  [apool release];
  }
  </code></pre>
  
  <p>Now the sampleBuffer will have incorrectly decoded samples. Can anyone help me why this is so? This happens for different files on my iTunes library (mp3, aac, wav, etc).
  Any help would be greatly appreciated, furthermore, if you need any other listing of my code, or perhaps what the output sounds like, I will attach it per request. I have been sitting on this for the past week trying to debug it and have found no help online -- everyone seems to be doign it in my way, yet it seems that only I have this issue.</p>
  
  <p>Thanks for any help at all!</p>
  
  <p>Peter</p>