"Audio Recorder" is indeed a very simple tweak. The author tried to obfuscate important parts of his tweak (which function is being hooked), but here is what I found.ide
Tweak basically hooks just one function - AudioConverterConvertComplexBuffer
from AudioToolbox.framework
. Tweak is loaded in mediaserverd
daemon at startup.post
First, we need to find out when we should start recording because AudioConverterConvertComplexBuffer
is called even when you just playing regular audio files. To achieve that tweak is listening to kCTCallStatusChangeNotification
notification from CTTelephonyCenter
.ui
Second, AudioConverterConvertComplexBuffer
implementation. I didn't finished it yet so I will post what I have so far. Here is somewhat working example that will get you started.this
Helper class to keep track of AudioConverterRef - ExtAudioFileRef pairsatom
@interface ConverterFile : NSObject @property (nonatomic, assign) AudioConverterRef converter; @property (nonatomic, assign) ExtAudioFileRef file; @property (nonatomic, assign) BOOL failedToOpenFile; @end @implementation ConverterFile @end
ConverterFile objects containerurl
NSMutableArray* callConvertersFiles = [[NSMutableArray alloc] init];
AudioConverterConvertComplexBuffer original implementationspa
OSStatus(*AudioConverterConvertComplexBuffer_orig)(AudioConverterRef, UInt32, const AudioBufferList*, AudioBufferList*);
AudioConverterConvertComplexBuffer hook declarationcode
OSStatus AudioConverterConvertComplexBuffer_hook(AudioConverterRef inAudioConverter, UInt32 inNumberPCMFrames, const AudioBufferList *inInputData, AudioBufferList *outOutputData);
Hookingorm
MSHookFunction(AudioConverterConvertComplexBuffer, AudioConverterConvertComplexBuffer_hook, &AudioConverterConvertComplexBuffer_orig);
AudioConverterConvertComplexBuffer hook definitionserver
OSStatus AudioConverterConvertComplexBuffer_hook(AudioConverterRef inAudioConverter, UInt32 inNumberPCMFrames, const AudioBufferList *inInputData, AudioBufferList *outOutputData) { //Searching for existing AudioConverterRef-ExtAudioFileRef pair __block ConverterFile* cf = nil; [callConvertersFiles enumerateObjectsUsingBlock:^(ConverterFile* obj, NSUInteger idx, BOOL *stop){ if (obj.converter == inAudioConverter) { cf = obj; *stop = YES; } }]; //Inserting new AudioConverterRef if (!cf) { cf = [[[ConverterFile alloc] init] autorelease]; cf.converter = inAudioConverter; [callConvertersFiles addObject:cf]; } //Opening new audio file if (!cf.file && !cf.failedToOpenFile) { //Obtaining input audio format AudioStreamBasicDescription desc; UInt32 descSize = sizeof(desc); AudioConverterGetProperty(cf.converter, kAudioConverterCurrentInputStreamDescription, &descSize, &desc); //Opening audio file CFURLRef url = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)[NSString stringWithFormat:@"/var/mobile/Media/DCIM/Call%u.caf", [callConvertersFiles indexOfObject:cf]], kCFURLPOSIXPathStyle, false); ExtAudioFileRef audioFile = NULL; OSStatus result = ExtAudioFileCreateWithURL(url, kAudioFileCAFType, &desc, NULL, kAudioFileFlags_EraseFile, &audioFile); if (result != 0) { cf.failedToOpenFile = YES; cf.file