Skip to content

Commit

Permalink
add AudioRecorder
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy committed Jun 17, 2017
1 parent f167588 commit 28f2c70
Show file tree
Hide file tree
Showing 5 changed files with 659 additions and 0 deletions.
24 changes: 24 additions & 0 deletions RecordKit/RKAudioRecorder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// RKAudioRecorder.h
// Pods
//
// Created by goccy on 2017/06/16.
//
//

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>

@interface RKAudioRecorder : NSObject

@property(nonatomic, readonly) BOOL isRecording;
@property(nonatomic, readonly) ExtAudioFileRef audioFile;

+ (instancetype)sharedInstance;

- (BOOL)startRecording;

- (void)stopRecording;

@end
118 changes: 118 additions & 0 deletions RecordKit/RKAudioRecorder.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// RKAudioRecorder.m
// Pods
//
// Created by goccy on 2017/06/16.
//
//

#import "RKAudioRecorder.h"
#import "RKAudioUnitProxy.h"
#import "RKRecordFile.h"

@interface RKAudioRecorder()

@property(nonatomic, readwrite) BOOL isRecording;

@property(nonatomic, readwrite) ExtAudioFileRef audioFile;

@end

@implementation RKAudioRecorder

static RKAudioRecorder *g_sharedInstance = nil;

+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
g_sharedInstance = [RKAudioRecorder new];
});
return g_sharedInstance;
}

- (NSURL *)defaultRecordFileURL
{
return [RKRecordFile fileURL:@"audio.aiff"];
}

- (BOOL)startRecording
{
AudioStreamBasicDescription asbd;
asbd.mSampleRate = 44100.0;
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
asbd.mBitsPerChannel = 32;
asbd.mChannelsPerFrame = 2;
asbd.mFramesPerPacket = 1;
asbd.mBytesPerFrame = 4;
asbd.mBytesPerPacket = 4;
asbd.mReserved = 0;

AudioStreamBasicDescription createASBD;
memcpy(&createASBD, &asbd, sizeof(AudioStreamBasicDescription));
createASBD.mFormatFlags = kLinearPCMFormatFlagIsBigEndian|kLinearPCMFormatFlagIsSignedInteger|kLinearPCMFormatFlagIsPacked;
createASBD.mBitsPerChannel = 16;

if (ExtAudioFileCreateWithURL((__bridge CFURLRef)[self defaultRecordFileURL],
kAudioFileAIFFType,
&createASBD,
NULL,
kAudioFileFlags_EraseFile,
&_audioFile) != noErr) {
return NO;
}
// Set up the converter
if (ExtAudioFileSetProperty(self.audioFile,
kExtAudioFileProperty_ClientDataFormat,
sizeof(AudioStreamBasicDescription),
&asbd) != noErr) {
return NO;
}
self.isRecording = YES;
return YES;
}

- (void)stopRecording
{
self.isRecording = NO;
ExtAudioFileDispose(self.audioFile);
NSLog(@"write file %@", [self defaultRecordFileURL].path);
}

+ (void)injectAudioUnitProxy
{
// (1) Fetch all `AudioComponent` by `AudioComponentFindNext`
// (2) `AudioComponentRegister` can register customized AudioUnit defined lifecycle.
// (3) Define newer version of predefined AudioUnit
// (4) After this section, `AudioComponentFindNext(NULL, desc)` returns `newer` version for AudioUnit ( our customized AudioUnit )
AudioComponentDescription allDesc = {0};
AudioComponent component = NULL;
while ((component = AudioComponentFindNext(component, &allDesc)) != NULL) {
AudioComponentDescription outDesc;
AudioComponentGetDescription(component, &outDesc);
CFStringRef name;
AudioComponentCopyName(component, &name);
UInt32 version;
AudioComponentGetVersion(component, &version);

// ignore not supported componentSubType
if (outDesc.componentSubType == kAudioUnitSubType_AUiPodTime) continue;
if (outDesc.componentSubType == kAudioUnitSubType_AUiPodEQ) continue;

AudioComponentInstance instance;
assert(AudioComponentInstanceNew(component, &instance) == noErr);
if (AudioUnitInitialize(instance) == noErr) {
AudioComponentRegister(&outDesc, name, version + 1, &RKAudioUnitProxyPlugin::factory);
}
AudioUnitUninitialize(instance);
AudioComponentInstanceDispose(instance);
}
}

+ (void)load
{
[[self class] injectAudioUnitProxy];
}

@end
115 changes: 115 additions & 0 deletions RecordKit/RKAudioUnitProxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// RKAudioUnitProxy.h
// Pods
//
// Created by goccy on 2017/06/16.
//
//

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>

class RKAudioUnitProxy {
public:
AudioUnit __nonnull audioUnit;
AudioUnit __nonnull originalAudioUnit;
AudioComponentDescription audioComponentDescription;

RKAudioUnitProxy(AudioComponentInstance __nonnull instance);
~RKAudioUnitProxy(void);
void setAudioComponentDescription(AudioComponentDescription from);
};

class RKAudioUnitProxyPlugin {
public:
RKAudioUnitProxyPlugin(void);
~RKAudioUnitProxyPlugin(void);
static AudioComponentPlugInInterface *__nonnull factory(const AudioComponentDescription *__nonnull inDesc);

private:
RKAudioUnitProxy *__nonnull audioUnitProxy;

static OSStatus open(AudioComponentPlugInInterface *__nonnull plugin, AudioComponentInstance __nonnull instance);
static OSStatus close(AudioComponentPlugInInterface *__nonnull plugin);
static AudioComponentMethod __nonnull lookup(SInt16 selector);

static OSStatus unInitialize(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus initialize(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus getPropertyInfo(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 *__nullable outDataSize,
Boolean *__nullable outWritable);
static OSStatus getProperty(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void *__nonnull outData,
UInt32 *__nonnull ioDataSize);
static OSStatus setProperty(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * __nullable inData,
UInt32 inDataSize);
static OSStatus addPropertyListener(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitPropertyID inID,
AudioUnitPropertyListenerProc __nonnull inProc,
void * __nullable inProcUserData);
static OSStatus removePropertyListenerWithUserData(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitPropertyID inID,
AudioUnitPropertyListenerProc __nonnull inProc,
void * __nullable inProcUserData);
static OSStatus addRenderNotify(AudioComponentPlugInInterface *__nonnull plugin,
AURenderCallback __nonnull inProc,
void *__nullable inProcUserData);
static OSStatus removeRenderNotify(AudioComponentPlugInInterface *__nonnull plugin,
AURenderCallback __nonnull inProc,
void *__nullable inProcUserData);
static OSStatus getParameter(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
AudioUnitParameterValue *__nonnull outValue);
static OSStatus setParameter(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
AudioUnitParameterValue inValue,
UInt32 inBufferOffsetInFrames);
static OSStatus scheduleParameters(AudioComponentPlugInInterface *__nonnull plugin,
const AudioUnitParameterEvent *__nonnull inParameterEvent,
UInt32 inNumParamEvents);
static OSStatus reset(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitScope inScope,
AudioUnitElement inElement);
static OSStatus process(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitRenderActionFlags *__nullable ioActionFlags,
const AudioTimeStamp *__nonnull inTimeStamp,
UInt32 inNumberFrames,
AudioBufferList *__nonnull ioData);
static OSStatus processMultiple(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitRenderActionFlags *__nullable ioActionFlags,
const AudioTimeStamp *__nonnull inTimeStamp,
UInt32 inNumberFrames,
UInt32 inNumberInputBufferLists,
const AudioBufferList * __nonnull * __nonnull inInputBufferLists,
UInt32 inNumberOutputBufferLists,
AudioBufferList * __nonnull * __nonnull ioOutputBufferLists);
static OSStatus render(AudioComponentPlugInInterface *__nonnull plugin,
AudioUnitRenderActionFlags *__nonnull ioActionFlags,
const AudioTimeStamp *__nonnull inTimeStamp,
UInt32 inOutputBusNumber,
UInt32 inNumberFrames,
AudioBufferList *__nonnull ioData);
static OSStatus start(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus stop(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus callback0x101(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus callback0x102(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus callback0x105(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus callback0x106(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus callback0x008(AudioComponentPlugInInterface *__nonnull plugin);
static OSStatus callback0x00c(AudioComponentPlugInInterface *__nonnull plugin);
};
Loading

0 comments on commit 28f2c70

Please sign in to comment.