title: Record and play audio with AVAssetWriter
body: <p>I have reduced this question quite a bit and am hoping for some help.  </p>
  
  <p>Basically this class has two methods, one to start recording audio (<code>-recordMode</code>) and the other to play audio (<code>playMode</code>). I currently have this class in a project with a single view controller with two buttons that call the corresponding methods (rec, play). There are no other variables, the class is self-contained.</p>
  
  <p>However it will not play/rec anything and I cannot figure out why. When I try to play the file I get a file size of 0 and an error because you cant init the <code>AVAudioPlayer</code> with a <code>nil</code> reference of course. But I dont understand why the file is empty or why <code>self.outputPath</code> is <code>nil</code>.</p>
  
  <p>.h file</p>
  
  <pre><code>#import &lt;AVFoundation/AVFoundation.h&gt;
  
  @interface MicCommunicator : NSObject&lt;AVCaptureAudioDataOutputSampleBufferDelegate&gt;
  
  @property(nonatomic,retain) NSURL *outputPath;
  @property(nonatomic,retain) AVCaptureSession * captureSession;
  @property(nonatomic,retain) AVCaptureAudioDataOutput * output;
  
  -(void)beginStreaming;
  -(void)playMode;
  -(void)recordMode;
  
  @end
  </code></pre>
  
  <p>.m file:</p>
  
  <pre><code>@implementation MicCommunicator {
      AVAssetWriter *assetWriter;
      AVAssetWriterInput *assetWriterInput;
  }
  
  @synthesize captureSession = _captureSession;
  @synthesize output = _output;
  @synthesize outputPath = _outputPath;
  
  -(id)init {
      if ((self = [super init])) {
          NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
          self.outputPath = [NSURL fileURLWithPath:[[searchPaths objectAtIndex:0] stringByAppendingPathComponent:@"micOutput.output"]];
  
          AudioChannelLayout acl;
          bzero(&amp;acl, sizeof(acl));
          acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono; //kAudioChannelLayoutTag_Stereo;
          NSDictionary *audioOutputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSNumber numberWithInt: kAudioFormatULaw],AVFormatIDKey,        
                                               [NSNumber numberWithFloat:8000.0],AVSampleRateKey,//was 44100.0
                                               [NSData dataWithBytes: &amp;acl length: sizeof( AudioChannelLayout ) ], AVChannelLayoutKey,
                                               [NSNumber numberWithInt:1],AVNumberOfChannelsKey,
                                               [NSNumber numberWithInt:8000.0],AVEncoderBitRateKey,
                                               nil];
  
          assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioOutputSettings];
          [assetWriterInput setExpectsMediaDataInRealTime:YES];
  
          assetWriter = [[AVAssetWriter assetWriterWithURL:_outputPath fileType:AVFileTypeWAVE error:nil] retain];
          [assetWriter addInput:assetWriterInput];
      }
      return self;
  }
  
  -(void)dealloc {
      [assetWriter release];
      [super dealloc];
  }
  
  //conveniance methods
  
  -(void)playMode
  {
      [self stopRecording];
  
      NSError *error;
      AVAudioPlayer * audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.outputPath error:&amp;error];
      audioPlayer.numberOfLoops = -1;
  
      if (audioPlayer == nil){
          NSLog(@"error: %@",[error description]);        
      }else{ 
          NSLog(@"playing");  
          [audioPlayer play];
      }
  }
  
  -(void)recordMode
  {
          [self beginStreaming];    
  }
  
  -(void)stopRecording
  {
      [self.captureSession stopRunning];
      [assetWriterInput markAsFinished];
      [assetWriter  finishWriting];
  
      NSDictionary *outputFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[NSString stringWithFormat:@"%@",self.outputPath] error:nil];
      NSLog (@"done. file size is %llu", [outputFileAttributes fileSize]);
  }
  
  //starts audio recording
  -(void)beginStreaming {
      self.captureSession = [[AVCaptureSession alloc] init];
      AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
      NSError *error = nil;
      AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&amp;error];
      if (audioInput)
          [self.captureSession addInput:audioInput];
      else {
          NSLog(@"No audio input found.");
          return;
      }
  
      AVCaptureAudioDataOutput *output = [[AVCaptureAudioDataOutput alloc] init];
  
      dispatch_queue_t outputQueue = dispatch_queue_create("micOutputDispatchQueue", NULL);
      [output setSampleBufferDelegate:self queue:outputQueue];
      dispatch_release(outputQueue);
  
      [self.captureSession addOutput:output];
      [assetWriter startWriting];
      [self.captureSession startRunning];
  }
  
  //callback
  -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
      AudioBufferList audioBufferList;
      NSMutableData *data= [[NSMutableData alloc] init];
      CMBlockBufferRef blockBuffer;
      CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &amp;audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &amp;blockBuffer);
  
      //for (int y = 0; y &lt; audioBufferList.mNumberBuffers; y++) {
      //  AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
      //  Float32 *frame = (Float32*)audioBuffer.mData;
      //          
      //  [data appendBytes:frame length:audioBuffer.mDataByteSize];
      //}
  
      // append [data bytes] to your NSOutputStream 
  
  
      // These two lines write to disk, you may not need this, just providing an example
      [assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
      [assetWriterInput appendSampleBuffer:sampleBuffer];
  
      CFRelease(blockBuffer);
      blockBuffer=NULL;
      [data release];
  }
  
  @end
  </code></pre>