1. 程式人生 > >使用 RK3399 搭載 Android 系統7.1.2,出現 AudioTrack 有時無法播放 PCM 音訊

使用 RK3399 搭載 Android 系統7.1.2,出現 AudioTrack 有時無法播放 PCM 音訊

RK3399 在 Android 系統 7.1.2,出現 AudioTrack 有時無法播放 PCM 音訊的問題

問題背景:
切換 rk3399 後,搭載系統為 Android 7.1.2,如果單獨使用 audiotrack 播放 PCM 音訊是沒有問題,但是應用在智慧家居上,一般都需要和語音識別打交道,在開啟錄音後,很大的機率出現播放 PCM 音訊不出聲,檢視log日誌發現在錄音短暫關閉後能恢復聲音播放,此時重啟錄音功能,能做到語音識別和 PCM 音訊播放。在 4.4.4 系統沒出現這個現象。
目前,RK 廠家還沒有給出解決方案,不確定是否為系統驅動問題,現在只能從應用層去繞開。

問題重現

  1. 語音喚醒後(多輪互動,單輪互動會在識別後關閉錄音,不在考慮範圍),能識別語音,並播放PCM音訊
  2. 語音喚醒後,能識別語音,但不能播放語音合成的 PCM 音訊,幾次互動後,還是不能播放
  3. 語音喚醒後,能識別語音,但不能播放語音合成的 PCM 音訊,幾次互動後,能恢復播放音訊
  4. 在後臺開啟音樂播放(另一個APP如網易雲播放歌曲),在喚醒互動,能準確播放出語音合成 PCM

問題分析

  1. 我這邊測試的語音識別用的訊飛 AIUI 平臺,檢視原始碼喚醒後的錄音執行緒等級設定為10,有可能執行緒爭奪導致 audio 程序降級,但可能性不大。
  2. 系統問題,在啟用錄音後,播放器被短暫關閉。目前這個可能性最大,在語音喚起互動 PCM 無法播放出聲音,此時用第三方音樂播放器同樣不出聲(進度條顯示播放正常),多次暫停播放操作才有可能重新出聲。

解決方法

很明顯,在錄音啟動後,再通過語音合成來播放音訊,失敗機率太大而且不可知,你無法在應用層得知喇叭有沒有出聲,不出聲是一個物理現象,無法監控,所以只能從問題重現的第4點來解決,在開啟錄音之前,先啟動一個播放操作來搶佔焦點,然後再開啟錄音,經測試能有效解決這個不出聲的問題。當然最好的解決方法是系統層面來解決這個問題。
下面是部分程式碼:

  • AudioTrack 初始化部分
	//目前語音合成都有提供合成並播放的呼叫,但不適用這場景
	//只能合成 PCM 音訊後,自己使用 audioTrack 來播放 

	private AudioTrack audioTrack;
//初始化 private void init() { if (audioTrack == null) { int bufferSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { AudioFormat audioFormat = new AudioFormat.Builder().setChannelMask(AudioFormat.CHANNEL_IN_STEREO).setSampleRate(8000).build(); audioTrack = new AudioTrack(new AudioAttributes.Builder().build(), audioFormat, bufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE); } } } //語音喚醒時先啟用播放 protected void wake() { if (audioTrack != null) { audioTrack.play(); } } //在呼叫停止播放呼叫,清空未播放快取 protected void sleep() { if (audioTrack != null) { audioTrack.pause();//暫停 audioTrack.flush();//清空未播放資料 } }
  • 呼叫虛擬碼

	//語音喚醒後回撥
	public void wakeupCallback(){

		...
		wake();//啟動音訊播放搶佔
		startListener();//開啟拾音 
		//aiui 要傳送 startRecord
		//非 aiui 要啟用startListener(xxx)
		
	}

	//語音合成
	public void speak(String text){

		//百度
		mSpeechSynthesizer.synthesize(text)
		//百度在 SpeechSynthesizerListener 裡做audiotrack 寫入操作

		//aiui
		String p = "xiaoyan,speed=50,pitch=50,volume=50";
        AIUIMessage startTts = new AIUIMessage(AIUIConstant.CMD_TTS, AIUIConstant.START, 0, p, ttsData);
		aiuiAgent.sendMessage(startTts);
		//aiui 在 onEvent 型別為 tts 做資料寫入

	}


希望能夠解決啟動錄音後不播放合成音問題,有問題可以在評論區一起交流。

注:這個文僅做記錄,解決一個猜想,在測試方面並不非常充分,所以若專案使用,請考慮存在風險再使用。