Advertisement
two

Core Audio I/O File Recording

two
Feb 3rd, 2012
3,289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. //  ViewController.m
  3. //  Mic Recording
  4. //
  5. //  Created by Thorsten Wolfer on 03.02.12.
  6. //  Copyright (c) 2012 malivo. All rights reserved.
  7. //
  8.  
  9. #import "ViewController.h"
  10. #import <CoreAudio/CoreAudioTypes.h>
  11.  
  12. #define kOutputBus 0
  13. #define kInputBus 1
  14. #define kSampleRate 44100
  15.  
  16. #import <Foundation/Foundation.h>
  17. #import <AudioToolbox/AudioToolbox.h>
  18. #import <AVFoundation/AVAudioSession.h>
  19. #import "AudioUnit/AudioUnit.h"
  20.  
  21. @interface ViewController () {
  22.    
  23.     AudioComponentInstance      mAudioUnit;
  24.     ExtAudioFileRef             mAudioFileRef;
  25. }
  26.  
  27. -(void) initializeOutputUnit;
  28. static OSStatus recordingCallback       (void *                            inRefCon,
  29.                                          AudioUnitRenderActionFlags *      ioActionFlags,
  30.                                          const AudioTimeStamp *            inTimeStamp,
  31.                                          UInt32                            inBusNumber,
  32.                                          UInt32                            inNumberFrames,
  33.                                          AudioBufferList *                 ioData);
  34. -(void)stopRecording:(NSTimer*)theTimer;
  35.  
  36. @end
  37.  
  38. @implementation ViewController
  39.  
  40. - (void)didReceiveMemoryWarning
  41. {
  42.     [super didReceiveMemoryWarning];
  43.     // Release any cached data, images, etc that aren't in use.
  44. }
  45.  
  46. #pragma mark Core Audio
  47.  
  48. static void CheckError(OSStatus error, const char *operation)
  49. {
  50.     if (error == noErr) return;
  51.    
  52.     char errorString[20];
  53.    
  54.     // See if it appears to be a 4-char-code *(UInt32 *)(errorString + 1) =
  55.     CFSwapInt32HostToBig(error);
  56.     if (isprint(errorString[1]) && isprint(errorString[2]) &&
  57.         isprint(errorString[3]) && isprint(errorString[4])) {
  58.        
  59.         errorString[0] = errorString[5] = '\''; errorString[6] = '\0';
  60.     }
  61.     else {
  62.        
  63.         // No, format it as an integer sprintf(errorString, "%d", (int)error);
  64.         fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
  65.     }
  66. }
  67.  
  68. - (void)stopRecording:(NSTimer*)theTimer
  69. {
  70.     printf("\nstopRecording\n");
  71.     AudioOutputUnitStop(mAudioUnit);
  72.     AudioUnitUninitialize(mAudioUnit);
  73.    
  74.     OSStatus status = ExtAudioFileDispose(mAudioFileRef);
  75.     printf("OSStatus(ExtAudioFileDispose): %ld\n", status);
  76. }
  77.  
  78. - (void) initializeOutputUnit
  79. {
  80.     OSStatus status;
  81.    
  82.     // Describe audio component
  83.     AudioComponentDescription desc;
  84.     desc.componentType = kAudioUnitType_Output;
  85.     desc.componentSubType = kAudioUnitSubType_RemoteIO;
  86.     desc.componentFlags = 0;
  87.     desc.componentFlagsMask = 0;
  88.     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  89.    
  90.     // Get component
  91.     AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);
  92.    
  93.     // Get audio units
  94.     status = AudioComponentInstanceNew(inputComponent, &mAudioUnit);
  95.    
  96.     // Enable IO for recording
  97.     UInt32 flag = 1;
  98.     status = AudioUnitSetProperty(mAudioUnit,
  99.                                   kAudioOutputUnitProperty_EnableIO,
  100.                                   kAudioUnitScope_Input,
  101.                                   kInputBus,
  102.                                   &flag,
  103.                                   sizeof(flag));
  104.    
  105.     // Enable IO for playback
  106.     status = AudioUnitSetProperty(mAudioUnit,
  107.                                   kAudioOutputUnitProperty_EnableIO,
  108.                                   kAudioUnitScope_Output,
  109.                                   kOutputBus,
  110.                                   &flag,
  111.                                   sizeof(flag));
  112.    
  113.     // Describe format
  114.     AudioStreamBasicDescription audioFormat={0};
  115.     audioFormat.mSampleRate         = kSampleRate;
  116.     audioFormat.mFormatID           = kAudioFormatLinearPCM;
  117.     audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
  118.     audioFormat.mFramesPerPacket    = 1;
  119.     audioFormat.mChannelsPerFrame   = 1;
  120.     audioFormat.mBitsPerChannel     = 16;
  121.     audioFormat.mBytesPerPacket     = 2;
  122.     audioFormat.mBytesPerFrame      = 2;
  123.    
  124.     // Apply format
  125.     status = AudioUnitSetProperty(mAudioUnit,
  126.                                   kAudioUnitProperty_StreamFormat,
  127.                                   kAudioUnitScope_Output,
  128.                                   kInputBus,
  129.                                   &audioFormat,
  130.                                   sizeof(audioFormat));
  131.     status = AudioUnitSetProperty(mAudioUnit,
  132.                                   kAudioUnitProperty_StreamFormat,
  133.                                   kAudioUnitScope_Input,
  134.                                   kOutputBus,
  135.                                   &audioFormat,
  136.                                   sizeof(audioFormat));
  137.    
  138.    
  139.     // Set input callback
  140.     AURenderCallbackStruct callbackStruct;
  141.     callbackStruct.inputProc = recordingCallback;
  142.     callbackStruct.inputProcRefCon = (__bridge void *)self;
  143.    
  144.     status = AudioUnitSetProperty(mAudioUnit,
  145.                                   kAudioOutputUnitProperty_SetInputCallback,
  146.                                   kAudioUnitScope_Global,
  147.                                   kInputBus,
  148.                                   &callbackStruct,
  149.                                   sizeof(callbackStruct));
  150.        
  151.     // Disable buffer allocation for the recorder (optional - do this if we want to pass in our own)
  152.     flag = 0;
  153.     status = AudioUnitSetProperty(mAudioUnit,
  154.                                   kAudioUnitProperty_ShouldAllocateBuffer,
  155.                                   kAudioUnitScope_Output,
  156.                                   kInputBus,
  157.                                   &flag,
  158.                                   sizeof(flag));
  159.        
  160.     // On initialise le fichier audio
  161.     NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  162.     NSString *documentsDirectory = [paths objectAtIndex:0];
  163.     NSString *destinationFilePath = [[NSString alloc] initWithFormat: @"%@/output.caf", documentsDirectory];
  164.     NSLog(@">>> %@\n", destinationFilePath);
  165.    
  166.     CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false);
  167.    
  168.     OSStatus setupErr = ExtAudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &audioFormat, NULL, kAudioFileFlags_EraseFile, &mAudioFileRef);  
  169.     CFRelease(destinationURL);
  170.     NSAssert(setupErr == noErr, @"Couldn't create file for writing");
  171.    
  172.     setupErr = ExtAudioFileSetProperty(mAudioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &audioFormat);
  173.     NSAssert(setupErr == noErr, @"Couldn't create file for format");
  174.    
  175.     setupErr =  ExtAudioFileWriteAsync(mAudioFileRef, 0, NULL);
  176.     NSAssert(setupErr == noErr, @"Couldn't initialize write buffers for audio file");
  177.    
  178.     CheckError(AudioUnitInitialize(mAudioUnit), "AudioUnitInitialize");
  179.     CheckError(AudioOutputUnitStart(mAudioUnit), "AudioOutputUnitStart");
  180.    
  181.     [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(stopRecording:) userInfo:nil repeats:NO];
  182. }
  183.  
  184. static void printAudioUnitRenderActionFlags(AudioUnitRenderActionFlags * ioActionFlags)
  185. {
  186.     if (*ioActionFlags == 0) {
  187.        
  188.         printf("AudioUnitRenderActionFlags(%lu) ", *ioActionFlags);
  189.         return;
  190.     }
  191.     printf("AudioUnitRenderActionFlags(%lu): ", *ioActionFlags);
  192.     if (*ioActionFlags & kAudioUnitRenderAction_PreRender)              printf("kAudioUnitRenderAction_PreRender ");
  193.     if (*ioActionFlags & kAudioUnitRenderAction_PostRender)             printf("kAudioUnitRenderAction_PostRender ");
  194.     if (*ioActionFlags & kAudioUnitRenderAction_OutputIsSilence)        printf("kAudioUnitRenderAction_OutputIsSilence ");
  195.     if (*ioActionFlags & kAudioOfflineUnitRenderAction_Preflight)       printf("kAudioOfflineUnitRenderAction_Prefli ght ");
  196.     if (*ioActionFlags & kAudioOfflineUnitRenderAction_Render)          printf("kAudioOfflineUnitRenderAction_Render");
  197.     if (*ioActionFlags & kAudioOfflineUnitRenderAction_Complete)        printf("kAudioOfflineUnitRenderAction_Complete ");
  198.     if (*ioActionFlags & kAudioUnitRenderAction_PostRenderError)        printf("kAudioUnitRenderAction_PostRenderError ");
  199.     if (*ioActionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs)   printf("kAudioUnitRenderAction_DoNotCheckRenderArgs ");
  200. }
  201.  
  202. static OSStatus recordingCallback       (void *                            inRefCon,
  203.                                          AudioUnitRenderActionFlags *      ioActionFlags,
  204.                                          const AudioTimeStamp *            inTimeStamp,
  205.                                          UInt32                            inBusNumber,
  206.                                          UInt32                            inNumberFrames,
  207.                                          AudioBufferList *                 ioData)
  208. {
  209.     double timeInSeconds = inTimeStamp->mSampleTime / kSampleRate;
  210.     printf("\n%fs inBusNumber: %lu inNumberFrames: %lu ", timeInSeconds, inBusNumber, inNumberFrames);
  211.     printAudioUnitRenderActionFlags(ioActionFlags);
  212.  
  213.     AudioBufferList bufferList;
  214.    
  215.     SInt16 samples[inNumberFrames]; // A large enough size to not have to worry about buffer overrun
  216.     memset (&samples, 0, sizeof (samples));
  217.    
  218.     bufferList.mNumberBuffers = 1;
  219.     bufferList.mBuffers[0].mData = samples;
  220.     bufferList.mBuffers[0].mNumberChannels = 1;
  221.     bufferList.mBuffers[0].mDataByteSize = inNumberFrames*sizeof(SInt16);
  222.  
  223.     ViewController* THIS = THIS = (__bridge ViewController *)inRefCon;
  224.    
  225.     OSStatus status;
  226.     status = AudioUnitRender(THIS->mAudioUnit,    
  227.                              ioActionFlags,
  228.                              inTimeStamp,
  229.                              kInputBus,
  230.                              inNumberFrames,
  231.                              &bufferList);
  232.    
  233.     if (noErr != status) {
  234.        
  235.         printf("AudioUnitRender error: %ld", status);
  236.         return noErr;
  237.     }
  238.    
  239.     // Now, we have the samples we just read sitting in buffers in bufferList
  240.     ExtAudioFileWriteAsync(THIS->mAudioFileRef, inNumberFrames, &bufferList);
  241.        
  242.     return noErr;    
  243. }
  244.  
  245. #pragma mark - View lifecycle
  246.  
  247. - (void)viewDidLoad
  248. {
  249.     [super viewDidLoad];
  250.     // Do any additional setup after loading the view, typically from a nib.
  251.    
  252.     [self initializeOutputUnit];
  253. }
  254.  
  255. - (void)viewDidUnload
  256. {
  257.     [super viewDidUnload];
  258.     // Release any retained subviews of the main view.
  259.     // e.g. self.myOutlet = nil;
  260. }
  261.  
  262. - (void)viewWillAppear:(BOOL)animated
  263. {
  264.     [super viewWillAppear:animated];
  265. }
  266.  
  267. - (void)viewDidAppear:(BOOL)animated
  268. {
  269.     [super viewDidAppear:animated];
  270. }
  271.  
  272. - (void)viewWillDisappear:(BOOL)animated
  273. {
  274.     [super viewWillDisappear:animated];
  275. }
  276.  
  277. - (void)viewDidDisappear:(BOOL)animated
  278. {
  279.     [super viewDidDisappear:animated];
  280. }
  281.  
  282. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  283. {
  284.     // Return YES for supported orientations
  285.     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
  286. }
  287.  
  288. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement