使用 RK3399 搭载 Android 系统7.1.2,出现 AudioTrack 有时无法播放 PCM 音频

RK3399 在 Android 系统 7.1.2,出现 AudioTrack 有时无法播放 PCM 音频的问题

更新 2018-12-28 09:24:07:

瑞芯微提供了解决方案,注释部分代码即可修复这个 bug,修改如下:
文件位置:rk3399_android7.1\hardware\rockchip\audio\tinyalsa_hal\codec_config
文件名:rt5651_config.h
修改部分:

/*
	//省略前部分
	//将这一块注释掉
	{
        .ctl_name = "RT5651 ASRC Switch",
        .str_val = "Disable",
    },*/
    //这里注释结束
	{
        .ctl_name = "DAC MIXL INF1 Switch",
        .int_val = {on},
    },
//省略后部分

截图:
修改前
使用 RK3399 搭载 Android 系统7.1.2,出现 AudioTrack 有时无法播放 PCM 音频_第1张图片

修改后截图:
使用 RK3399 搭载 Android 系统7.1.2,出现 AudioTrack 有时无法播放 PCM 音频_第2张图片

注:使用AudioTrack 在一定几率下也会出现不出声,但比用自带的播放出现问题概率低,能改源码是最好的!!!


问题背景:

切换 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 做数据写入

	}


希望能够解决启动录音后不播放合成音问题,有问题可以在评论区一起交流。

注:这个文仅做记录,解决一个猜想,在测试方面并不非常充分,所以若项目使用,请考虑存在风险再使用。

你可能感兴趣的:(Android开发)