项目里面要做语音交流的部分,把其中遇到的问题记录下来。单拿android和iOS录音来说都没什么问题,android和iOS都有各自支持的语音格式,但是要做语音交互的时候就遇到各种蛋碎的事情了。
网上查找说有三种方案供选择
第一种方案对于服务器负荷较大,不论是安卓端亦或是IOS端都将音频传输到服务器,通过服务器进行转换再进行转发。这种做法可以不受系统限制,但是信息量较大时对服务器负荷较大,对服务器端的要求很高。据传闻,微信就是采用这种方式进行的语音IM交互
第二种方案是不论IOS端还是安卓端都统一使用相同的第三方音频库进行编解码处理,然后再进行网络传输,优点是可供选择的音频库非常多,可以根据自己不同的需求选择各种各样的音频格式,但是因为不论是IOS端还是安卓端都需要对其进行i编码解码处理,而项目初期并没有设计这方面的需求所以如果双端都进行修改修改量实在太大。同样据传闻,同为语音IM的成熟案例微米就是依靠Speex的三方开源库来完成的,这种格式体积小,能降噪,是目前比较受推崇的方式。
第三种方案就是amr格式的音频文件是安卓系统中默认的录音文件,IOS系统曾经是支持这种格式的文件,自4.3以后才取消了对amr的支持,那我们只需要在IOS端转换出安卓端可以使用的amr文件就可以语音交互了,最后只需考虑在iOS端录的wav格式与amr格式的互转即可。
其实最开始我们项目也没考虑这种转语音格式,在网上查找得知也是有两种语音格式是android/iOS都支持的,aac以及pcm格式。
AAC:压缩,数据量小
PCM:接近无损,音频数据量大
最后我们选择aac格式。
lua中
function audioRecordUtils(value)
if value == true then
if device.platform == "android" then
local args = { 2,3}
local sigs = "(II)I"
local luaj = require "cocos.cocos2d.luaj"
local className = "com/cocos2dx/sample/LuaJavaBridge"
local ok,ret = luaj.callStaticMethod(className,"sendLuaToJavaAudioRecordStart",args,sigs)--开始录音
if not ok then
print("luaj error:",ret)
else
print("The ret is:",ret)
end
elseif device.platform == "ios" then
local i = iosStartAudioRecord( 1 )
end
else
if device.platform == "android" then
local args = { 1,"sendLuaToJavaAudioRecordStop",sigs) --停止录音
if not ok then
print("luaj error:",ret)
end
elseif device.platform == "ios" then
local i = iosStopAudioRecord( 1 )
end
end
end
android中
//在LuaJavaBridge.java中,导入需要的包等。。。
public class LuaJavaBridge {
//...
//开始录音
public static int sendLuaToJaveAudioRecordStart(final int type,final int num){
AudioRecording.getInstance().startRecord();
return 1;
}
//停止录音
public static int sendLuaToJaveAudioRecordStop(final int type,final int num){
AudioRecording.getInstance().stopRecord();
return 1;
}
//...
}
录音主要的部分(音源/封装格式/编码格式 )
mRecorder = new MediaRecorder();
//设置音源为Micphone
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置封装格式
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
//设置编码格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mRecorder.setAudioEncodingBitRate(8);//设置音频编码录音比特率
mRecorder.setAudioChannels(1);//设置录制的音频通道数
mRecorder.setAudioSamplingRate(8000); //设置音频采样率记录
mRecorder.setOutputFile(recondPath);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.e(TAG,"prepare() Failed");
}
//录音
mRecorder.start();
iOS中
// lua 调用 c 开始录音
int AppDelegate::iosStartAudioRecord(lua_State *L)
{
if(CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
{
AudioPicker::getInstance()->startAudioRecord();
}
return 1;
}
在AudioPicker.mm中
void AudioPicker::startAudioRecord()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
[imagePickerViewController startAudioRecording];
#endif
}
录音开始,主要部分还是设置音源/封装格式/编码格式
-(void)startAudioRecording
{
if(!isRecording)
{
[self init];
isRecording = YES;
NSLog(@"正在录音");
NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
//设置录音格式
[dicM setObject:@(kAudioFormatMPEG4AAC) forKey:AVFormatIDKey];
//设置录音采样率,8000是电话采样率,对于一般录音已经够了
[dicM setObject:@(1600) forKey:AVSampleRateKey];
//设置通道,这里采用单声道
[dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
//每个采样点位数,分为8、16、24、32
[dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
//录音的质量
[dicM setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];
//是否使用浮点数采样
[dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
recorder = [[AVAudioRecorder alloc] initWithURL:recordedFile settings:dicM error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[self setSoundSession];
[recorder peakPowerForChannel:0];
[recorder prepareToRecord];
[recorder record];
}
}
本来这样应该就是可以的了,但是发现有些手机对这种格式支持还不是很完美。到目前为止除了小米手机外没有发现其他手机有什么问题,android和iOS手机自己录的音其他android和iOS也能播,但是发现小米手机自己录的这种aac格式自己都不能播。。。,不得已那只能用第三方库将录音格式互转了。
参考:
http://www.jb51.cc/article/p-mcdpwusb-bpt.html
http://blog.csdn.net/adalu1986/article/details/50502387
http://www.jianshu.com/p/7dc01b48f8fc