ケータイアプリで会話するたびにレコしたい。私のデバイスはジェイルブレイクされているので、appStore の制限については問題ありません。
もちろん、公開フレームワークは何も提供しないと思います。また、私はプライベートフレームワークを見てきましたが、有用なものは何も見ていません.
現在、マイクからの録音はできているのですが、会話が始まるとマイクが排他モードになり、データが受信されなくなります。
ガイダンスはありますか?
「Audio Recorder」は実にシンプルな調整です。作者は自分の微調整の重要な部分 (フックされている関数) を難読化しようとしましたが、ここに私が見つけたものがあります。
Tweak は基本的にAudioConverterConvertComplexBuffer
fromという 1 つの関数だけをフックしAudioToolbox.framework
ます。Tweak はmediaserverd
起動時にデーモンにロードされます。
AudioConverterConvertComplexBuffer
まず、通常のオーディオ ファイルを再生しているときでも が呼び出されるため、いつ録音を開始する必要があるかを調べる必要があります。その微調整を実現するには、 からのkCTCallStatusChangeNotification
通知をリッスンしCTTelephonyCenter
ます。
第二に、AudioConverterConvertComplexBuffer
実装。まだ完成していないので、今あるものを載せておきます。これは、あなたが始めるためのいくらか実用的な例です。
AudioConverterRef と ExtAudioFileRef のペアを追跡するヘルパー クラス
@interface ConverterFile : NSObject
@property (nonatomic, assign) AudioConverterRef converter;
@property (nonatomic, assign) ExtAudioFileRef file;
@property (nonatomic, assign) BOOL failedToOpenFile;
@end
@implementation ConverterFile
@end
ConverterFile オブジェクト コンテナ
NSMutableArray* callConvertersFiles = [[NSMutableArray alloc] init];
AudioConvertConvertComplexBuffer 独自の実装
OSStatus(*AudioConverterConvertComplexBuffer_orig)(AudioConverterRef, UInt32, const AudioBufferList*, AudioBufferList*);
AudioConvertConvertComplexBuffer フック宣言
OSStatus AudioConverterConvertComplexBuffer_hook(AudioConverterRef inAudioConverter, UInt32 inNumberPCMFrames, const AudioBufferList *inInputData, AudioBufferList *outOutputData);
フッキング
MSHookFunction(AudioConverterConvertComplexBuffer, AudioConverterConvertComplexBuffer_hook, &AudioConverterConvertComplexBuffer_orig);
AudioConvertConvertComplexBuffer フックの定義
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 = NULL;
}
else
{
cf.failedToOpenFile = NO;
cf.file = audioFile;
//Writing audio format
ExtAudioFileSetProperty(cf.file, kExtAudioFileProperty_ClientDataFormat, sizeof(desc), &desc);
}
CFRelease(url);
}
//Writing audio buffer
if (cf.file)
{
ExtAudioFileWrite(cf.file, inNumberPCMFrames, inInputData);
}
return AudioConverterConvertComplexBuffer_orig(inAudioConverter, inNumberPCMFrames, inInputData, outOutputData);
}
これは、微調整で行われるおおよその方法です。しかし、なぜそれがそのように行われるのですか?通話中の場合AudioConverterConvertComplexBuffer_hook
連続して呼び出されます。ただし、inAudioConverter 引数は異なります。1 回の通話中に 9 つ以上の異なる inAudioConverter オブジェクトがフックに渡される可能性があることがわかりました。オーディオ形式が異なるため、すべてを 1 つのファイルに書き込むことはできません。これが、AudioConverterRef-ExtAudioFileRef ペアの配列を作成する理由です。何がどこに保存されているかを追跡します。このコードは、AudioConverterRef オブジェクトと同じ数のファイルを作成します。すべてのファイルには異なるオーディオが含まれます。1 つまたは 2 つがスピーカー サウンドになります。その他 - マイク。iOS 6.1 を搭載した iPhone 4S でこのコードをテストしたところ、動作しました。残念ながら、4S での通話録音は、スピーカーがオンになっている場合にのみ実行できます。iPhone 5 ではそのような制限はありません。これは tweak の説明に記載されています。
あとは、スピーカー オーディオ用とマイク用の 2 つの特定の inAudioConverter オブジェクトを見つける方法を見つけるだけです。他のすべては問題ではありません。
最後にもう 1 つ -mediaserverd
プロセスはサンドボックス化されているため、微調整を行っています。必要な場所にファイルを保存できません。これが、そのファイル パスを選択した理由です。サンドボックス内からでも書き込むことができます。
PS このコードを投稿しましたが、クレジットは Elias Limneos に帰属します。彼はそれをやった。