up vote9down voteaccepted

+50

"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.

Tweak basically hooks just one function - AudioConverterConvertComplexBuffer from AudioToolbox.framework. Tweak is loaded in mediaserverd daemon at startup.

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.

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.

Helper class to keep track of AudioConverterRef - ExtAudioFileRef pairs

@interface ConverterFile : NSObject

@property (nonatomic, assign) AudioConverterRef converter;
@property (nonatomic, assign) ExtAudioFileRef file;
@property (nonatomic, assign) BOOL failedToOpenFile; @end @implementation ConverterFile
@end

ConverterFile objects container

NSMutableArray* callConvertersFiles = [[NSMutableArray alloc] init];

AudioConverterConvertComplexBuffer original implementation

OSStatus(*AudioConverterConvertComplexBuffer_orig)(AudioConverterRef, UInt32, const AudioBufferList*, AudioBufferList*);

AudioConverterConvertComplexBuffer hook declaration

OSStatus AudioConverterConvertComplexBuffer_hook(AudioConverterRef inAudioConverter, UInt32 inNumberPCMFrames, const AudioBufferList *inInputData, AudioBufferList *outOutputData);

Hooking

MSHookFunction(AudioConverterConvertComplexBuffer, AudioConverterConvertComplexBuffer_hook, &AudioConverterConvertComplexBuffer_orig);

AudioConverterConvertComplexBuffer hook definition

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);
}

This is roughly how it's done in the tweak. But why it's done like that? When phone call is in progress AudioConverterConvertComplexBuffer_hook will be called continuously. But inAudioConverter argument will be different. I've found that there can be more than nine different inAudioConverter objects passed to our hook during one phone call. They will have different audio formats so we can't write everything in one file. This is why we building array of AudioConverterRef-ExtAudioFileRef pairs - to keep track of what is being saved to where. This code will create as many file as there is AudioConverterRef objects. All files will containt different audio - one or two will be the speaker sound. Others - microphone. I've tested this code on iPhone 4S with iOS 6.1 and it works. Unfortunately, call recording on 4S can be done only when speaker is turned on. There is no such limitation on iPhone 5. This is mentioned in tweak's description.

Only thing left is to find out how we can find just two specific inAudioConverter objects - one for speaker audio and one for microphone. Everything else is not a problem.

And one last thing - mediaserverd process is sandboxed so as our tweak. We can't save files anywhere we want. This is why I chose that file path - it can be written even from the inside of the sandbox.

PS Even though I've posted this code credit has to go to Elias Limneos. He's done it.

iOS 后台录音Tweak实现参考--stackoverflow的更多相关文章

  1. iOS 直播-实现后台录音并推流

    iOS 直播-实现后台录音并推流 从一个月前开始开始接收公司的直播类app.到今天为止测试都已接近尾声,但是产品哥哥加了一个要求,就是在app进入后台后也实时保证录音并且推流. 刚听到这个的时候我也是 ...

  2. iOS后台运行

    http://www.cocoachina.com/bbs/read.php?tid=149564 文一 我从苹果文档中得知,一般的应用在进入后台的时候可以获取一定时间来运行相关任务,也就是说可以在后 ...

  3. iOS 后台处理

    iOS 后台处理的常见用途 1.进入后台时候删除资源:应用处于挂起状态的时候所占用的资源越少,该应用被iOS终止的风险就越低.通过从内存中清理那些易于重新创建的资源,可以增加应用驻留内存的机会,因此可 ...

  4. iOS后台定位实现

    iOS后台定位实现 (2013-01-24 16:43:12)     工作中碰到一个定位的应用场景:app需要在后台运行,实时上传用户地理位置.   苹果对iOS的规范性在提升了app的品质的同时也 ...

  5. iOS 后台运行 类型

    iOS后台运行,需要有特定的类型才可以进行.这些内容并不是一直不变的,苹果也在逐步的更新这些内容. 本文内容是2015年11月03日时苹果支持的后台运行类型. 这是官方连接地址 其中较为重要的是下面这 ...

  6. iOS AVAudioRecorder 录音频率、声道、位数配置 wav格式

    iOS AVAudioRecorder 录音频率.声道.位数配置 #pragma mark 录音设置 - (void)setUP_VOICE_RECOARDER { NSError *error = ...

  7. IOS 后台执行

    在IOS后台执行是本文要介绍的内容,大多数应用程序进入后台状态不久后转入暂停状态.在这种状态下,应用程序不执行任何代码,并有可能在任意时候从内存中删除.应用程序提供特定的服务,用户可以请求后台执行时间 ...

  8. iOS 后台运行实现 --备用

    文一 我从苹果文档中得知,一般的应用在进入后台的时候可以获取一定时间来运行相关任务,也就是说可以在后台运行一小段时间. 还有三种类型的可以运行在后以,1.音乐2.location 3.voip 文二 ...

  9. iOS 后台定位被拒注意事项

    iOS 后台定位被拒的原因很简单就是没有达到苹果对后台定位的要求. 本地要求: 1.在plist文件中添加字段 "Privacy - Location Always Usage Descri ...

  10. iOS 后台持续定位详解(支持ISO9.0以上)

    iOS 后台持续定位详解(支持ISO9.0以上) #import <CoreLocation/CoreLocation.h>并实现CLLocationManagerDelegate 代理, ...

随机推荐

  1. 局部区块多个报表 TAB 页切换及局部区块的参数查询

    在企业的业务系统中,如何从纷繁复杂的数据中抽丝剥茧看到关键数据信息呢?一个重要的途径就是将企业和各部门运营中关键的 KPI 集中在一起显示,同时尽量省去在企业的各个业务系统中分别查找数据. 下面是我近 ...

  2. 抓包整理————tcp 传输数据的基础概念[十一]

    前言 简单介绍一下tcp 数据传输. 正文 tcp 数据传输是怎么样子的呢? 比如我们在代码中写好了,connection 去连接. 然后我们用 write 去读取数据,这个时候呢,到底我们的操作系统 ...

  3. signalr 应用于微信小程序(二)

    前言 本节基于一,为2017年写的脚本库. 正文 我们连接的是websocket那么我们需要看的是ws: 这里看到需要的参数其实只要connecttoken我们是没有的,那么如果得到的呢? 是网络请求 ...

  4. 一个简单的开源消息中间件 FolkMQ v1.4.2 发布

    功能简表 角色 功能 生产者(客户端) 发布消息.定时消息(或叫延时).顺序消息.可过期消息.事务消息.支持 Qos0.Qos1 消费者(客户端) 订阅.取消订阅.消费-ACK(自动.手动) 服务端 ...

  5. Kotlin 使用协程编写高效的并发程序

    概念: 轻量级的线程 协程允许我们在单线程模式下模拟多线程编程的效果,代码执行时的挂起与恢复完 全是由编程语言来控制的,和操作系统无关.这种特性使得高并发程序的运行效率得到了极大的提升. 依赖库: d ...

  6. 使用WebApi+Vue3从0到1搭建《权限管理系统》:二、搭建JWT系统鉴权

    视频地址:[WebApi+Vue3从0到1搭建<权限管理系统>系列视频:搭建JWT系统鉴权-哔哩哔哩] https://b23.tv/R6cOcDO qq群:801913255 一.在ap ...

  7. 剑指offer03(Java)-数组中重复的数字(简单)

    题目: 找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中任 ...

  8. Flink 1.13,面向流批一体的运行时与 DataStream API 优化

    简介: 在 1.13 中,针对流批一体的目标,Flink 优化了大规模作业调度以及批执行模式下网络 Shuffle 的性能,以及在 DataStream API 方面完善有限流作业的退出语义. 本文由 ...

  9. Git 工具下载慢问题 & 图像化界面工具

    Git 命令行淘宝镜像:git-for-windows Mirror (taobao.org) Git 图形客户端:Download – TortoiseGit – Windows Shell Int ...

  10. [Caddy2] URL访问路径的重定向和重写规则 (redir/rewrite 指令)

    当我们在规划网站路径时,为了保留搜索引擎收录 避免404的同时做到升级,常用到重定向跳转和URL重写. 重定向(redirect) 在 Caddy 中为 redir 指令. https://caddy ...