cocos2dx之 android/ios語音交互(一)

項目裏面要做語音交流的部分,把其中遇到的問題記錄下來。單拿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 , 3}
            local sigs = "(II)I"
            local luaj = require "cocos.cocos2d.luaj"
            local className = "com/cocos2dx/sample/LuaJavaBridge"
            local ok,ret  = luaj.callStaticMethod(className,"sendLuaToJavaAudioRecordStop",args,sigs) --停止錄音
            if not ok then
                print("luaj error:", ret)
            else
                print("The ret is:", 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://blog.csdn.net/qq_36946260/article/details/69224150
http://blog.csdn.net/adalu1986/article/details/50502387
http://www.jianshu.com/p/7dc01b48f8fc

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章