# 自定义音频采集和渲染
# 简介
实时音频传输过程中,JC SDK 会启动默认的音频模块进行采集和渲染。当遇到不支持系统标准 API 的音频设备的时候,或者希望使用自己已经拥有的音频模块进行音频采集和渲染的时候,您可以选择在音频被采集前自定义音频采集,也可以选择在音频播放前自定义音频渲染。
# 前提条件
在自定义音频采集和渲染前,确保已经初始化了 JCMediaDevice 模块。
# 自定义音频采集
参照下述步骤,在音频输入前,修改音频输入源和采样率等参数:
- 发起通话前,将 JCMediaDevice 中 audioParam 的 autoStartAudioInputDevice (opens new window) 设置为 false。这种情况下才可以获取音频输入数据。
- 调用 inputCustomAudioData (opens new window) 自定义音频采集。 建议在一对一通话状态为连接中时或者加入频道成功后,在子线程不断的调用此方法传入音频数据。
- 在结束通话的时候,关闭子线程停止音频采集。
// 在开启前将 autoStartAudioOutputDevice 属性设为 false
- (void)onAutoAudioInputDeviceChanged {
_mediaDevice.audioParam.autoStartAudioInputDevice = false;
}
// 声明一个子线程用于输入自定义音频数据
@property (nonatomic) NSThread *customAudioInputThread;
/**
* 0.当收到一对一通话状态更新时且通话状态是否为连接中,或收到成功加入多方通话时,可执行以下方法。
* 1.初始化 customAudioInputThread。
* 2.将音频文件转为 NSData 数据类型。
* 3.获取音频数据长度,并按照一定长度等分成若干音频数据。
* 4.while 循环不断将音频数据通过 inputCustomAudioData 接口传入到媒体层,每次传入后停止一秒。
* 5.子线程开始工作。
*/
- (void)startInputAudio {
if (!_customAudioInputThread) {
_customAudioInputThread = [[NSThread alloc] initWithBlock:^{
NSString *path = [[NSBundle mainBundle] pathForResource:@"customAudio" ofType:@"pcm"];
NSData *data= [NSData dataWithContentsOfFile:path];
int len = (int)(data.length);
int packetLen = 32 * 1024;
int packetNum = len / packetLen;
NSMutableArray *dataList = [NSMutableArray array];
for (int i = 0; i < packetNum; i++) {
NSData *d = [data subdataWithRange:NSMakeRange(i * packetLen, packetLen)];
[dataList addObject:d];
}
int num = 0;
while (([_call getActiveCallItem] && [_call getActiveCallItem].state == JCCallStateConnecting) || _mediaChannel.state == JCMediaChannelStateJoined) {
[_mediaDevice inputCustomAudioData:dataList[num] sampleRateHz:16000 channels:1 playDelayMS:0 recDelayMS:0 clockDrift:0];
++num;
num = num % packetNum;
[NSThread sleepForTimeInterval:1];
}
}];
}
if (!_customAudioInputThread.isExecuting && !_customAudioInputThread.isFinished && !_customAudioInputThread.isCancelled) {
[_customAudioInputThread start];
}
}
# 自定义音频渲染
参照下述步骤,在音频播放前,修改音频输入源和采样率等参数:
- 发起通话前,将 JCMediaDevice 中 audioParam 的 autoStartAudioInputDevice (opens new window) 设置为 false。这种情况下才可以获取音频输出数据。
- 调用 getAudioOutputData (opens new window) 自定义音频渲染。建议在一对一通话状态为连接中时或者加入频道成功后,在子线程不断的调用此方法渲染音频数据。
- 在结束通话的时候,关闭子线程停止音频渲染。
# 示例代码
// 在开启前将 autoStartAudioOutputDevice 属性设为 false
- (void)onAutoAudioOutputDeviceChanged {
_mediaDevice.audioParam.autoStartAudioOutputDevice = false;
}
// 声明一个子线程用于获取音频输出数据
@property (nonatomic) NSThread *outputAudioThread;
/**
* 0.当收到一对一通话状态更新时且通话状态是否为连接中,或收到成功加入多方通话时,可执行以下方法。
* 1.初始化 outputAudioThread。
* 2.while 循环不断通过 getAudioOutputData 接口获取对端音频数据。
* 3.子线程开始工作。
*/
- (void)playOutputAudio {
if (!_outputAudioThread) {
_outputAudioThread = [[NSThread alloc] initWithBlock:^{
while (([_call getActiveCallItem] && [_call getActiveCallItem].state == JCCallStateConnecting) || _mediaChannel.state == JCMediaChannelStateJoined) {
if (!_mediaDevice.audioParam.autoStartAudioOutputDevice) {
NSData *data = [NSData data];
int len = 1024;
unsigned char * buf = malloc(len);
[_mediaDevice getAudioOutputData:buf length:len sampleRateHz:16000 channels:1];
data = [NSData dataWithBytes:buf length:len];
if (data) {
// 此处可播放音频数据 data
}
free(buf);
}
}
}];
}
if (!_outputAudioThread.isFinished && !_outputAudioThread.isExecuting && !_outputAudioThread.isCancelled) {
[_outputAudioThread start];
}
}