Android10.0(Q) 实现通话中播放音乐/通话背景音(答录机/魔音功能)

前言

这个功能大体意思类似机器人交互的效果,一般多应用到客服接听场景中,电话接通自动播放一段录音给

对方听,根据选项操作录音解析等完成一整个流程。这里面电话接通播放声音给对方听普通应用是做不到的,

因为这关系到音频焦点分配的问题。Android 电话拨入音频焦点(Audio Focus)

谷歌默认的策略,当电话响铃或接通后,电话的音频焦点使用优先级是最高的,其它应用是无法抢占的。

但我们有源码啊,可以跳过这个地方,但是尝试后你会发现依旧不行。因为这还关系到 audio 驱动部分的上下行。

修改方案

frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java
vendor/mediatek/proprietary/hardware/audio/common/speech_driver/SpeechPcmMixerBGSPlayer.cpp
vendor/mediatek/proprietary/hardware/audio/common/speech_driver/SpeechPcmMixerTelephonyTx.cpp
vendor/mediatek/proprietary/hardware/audio/mt6735/include/AudioALSAVolumeController.h
vendor/mediatek/proprietary/hardware/audio/mt6735/include/AudioMTKGainController.h

frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java

canReassignAudioFocus 直接放回 true,其实最终发现改不改这里无所谓,主要是 audio 的上下行

     private boolean canReassignAudioFocus() {
         // focus requests are rejected during a phone call or when the phone is ringing
         // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
        /*if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
             return false;
         }*/
        return true;
     }

audio driver 部分需要修改 mPcmMixerDlGain 和 mPcmMixerUlGain 默认初始值

其中 mPcmMixerDlGain 表示下行 gain 值,影响的是本端听到的声音大小

mPcmMixerUlGain 表示上行 gain 值,影响的是对方听到的声音大小,默认值是 0x00,

所以对方听不到,只要将 mPcmMixerUlGain 改为非 0 值即可,最大值 0xFF

vendor/mediatek/proprietary/hardware/audio/common/speech_driver/SpeechPcmMixerBGSPlayer.cpp

 uint8_t SpeechPcmMixerBGSPlayer::mPcmMixerDlGain = 0xFF;
-uint8_t SpeechPcmMixerBGSPlayer::mPcmMixerUlGain = 0x0;
+uint8_t SpeechPcmMixerBGSPlayer::mPcmMixerUlGain = 0xFF;



$ find -name "*.cpp" | xargs grep "setPcmMixerDlMute"
./common/speech_driver/SpeechPcmMixerBGSPlayer.cpp:uint8_t SpeechPcmMixerBGSPlayer::mPcmMixerDlGain = 0xFF;
./common/speech_driver/SpeechPcmMixerBGSPlayer.cpp:    pSpeechDriver->BGSoundConfig(mPcmMixerUlGain, mPcmMixerDlGain);
./common/speech_driver/SpeechPcmMixerBGSPlayer.cpp:        mPcmMixerDlGain = 0x0;
./common/speech_driver/SpeechPcmMixerBGSPlayer.cpp:        mPcmMixerDlGain = 0xFF;
./common/speech_driver/SpeechPcmMixerTelephonyTx.cpp:uint8_t SpeechPcmMixerTelephonyTx::mPcmMixerDlGain = 0x0;
./common/speech_driver/SpeechPcmMixerTelephonyTx.cpp:    pSpeechDriver->TelephonyTxConfig(mPcmMixerUlGain, mPcmMixerDlGain);
./common/speech_driver/SpeechPcmMixerTelephonyTx.cpp:        mPcmMixerDlGain = 0x0;
./common/speech_driver/SpeechPcmMixerTelephonyTx.cpp:        mPcmMixerDlGain = 0xFF;
$ find -name "*.cpp" | xargs grep "setPcmMixerDlMute("
./common/speech_driver/SpeechPcmMixerBGSPlayer.cpp:void SpeechPcmMixerBGSPlayer::setPcmMixerDlMute(const bool mute_on) {
./common/speech_driver/SpeechPcmMixerTelephonyTx.cpp:void SpeechPcmMixerTelephonyTx::setPcmMixerDlMute(const bool mute_on) {
./common/V3/aud_drv/AudioALSAHardware.cpp:        SpeechPcmMixerBGSPlayer::setPcmMixerDlMute((bool)value);

AndroidO 版本修改方法

frameworks/base/media/java/android/media/AudioAttributes.java
frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java
vendor/mediatek/proprietary/hardware/audio/common/V3/aud_drv/AudioALSAStreamManager.cpp
vendor/mediatek/proprietary/hardware/audio/mt6735/include/AudioALSAVolumeController.h
vendor/mediatek/proprietary/hardware/audio/mt6735/include/AudioMTKGainController.h

frameworks/base/media/java/android/media/AudioAttributes.java

         public Builder setCapturePreset(int preset) {
             switch (preset) {
+            	case MediaRecorder.AudioSource.VOICE_UPLINK:
+            	case MediaRecorder.AudioSource.VOICE_DOWNLINK:
+            	case MediaRecorder.AudioSource.VOICE_CALL:
+            	case MediaRecorder.AudioSource.REMOTE_SUBMIX:
                 case MediaRecorder.AudioSource.DEFAULT:
                 case MediaRecorder.AudioSource.MIC:

frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java

     private boolean canReassignAudioFocus() {
         // focus requests are rejected during a phone call or when the phone is ringing
         // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
        /*if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
             return false;
         }*/
-        return true;
     }

vendor/mediatek/proprietary/hardware/audio/common/V3/aud_drv/AudioALSAStreamManager.cpp

AudioALSAStreamManager::AudioALSAStreamManager() :
     mForceDisableVoiceWakeUpForSetMode(false),
     mBypassPostProcessDL(false),
     mBGSDlGain(0xFF),
-    mBGSUlGain(0),
+    //mBGSUlGain(0),
+    mBGSUlGain(0xFF),
     mBypassDualMICProcessUL(false),

vendor/mediatek/proprietary/hardware/audio/mt6735/include/AudioALSAVolumeController.h

 #define HW_DIGITAL_GAIN_MAX (252)
 #define HW_DIGITAL_GAIN_STEP (4)   // 2==> 0.5 dB ,4==>1dB
 
-#define AUDIO_SYSTEM_UL_GAIN_MAX            (45)
+#define AUDIO_SYSTEM_UL_GAIN_MAX            (160)
 #define MIN_PGA_GAIN                                         (0)
 #define MAX_PGA_GAIN_RANGE                          (30)
 #define AUDIO_UL_PGA_STEP

vendor/mediatek/proprietary/hardware/audio/mt6735/include/AudioMTKGainController.h

 #define HW_DIGITAL_GAIN_MAX (252)
 #define HW_DIGITAL_GAIN_STEP (4)   // 2==> 0.5 dB ,4==>1dB
 
-#define AUDIO_SYSTEM_UL_GAIN_MAX            (45)
+#define AUDIO_SYSTEM_UL_GAIN_MAX            (160)
 #define MIN_PGA_GAIN                                         (2)
 #define MAX_PGA_GAIN_RANGE                          (30)
 #define AUDIO_UL_PGA_STEP  

其它问题收录

1、使用答录机的时候会听到连续的啪的声音

主要原因在于 AFE 不断去重新设置 uplink 的 AGC 那个寄存器。修正方法是当 mic volume

不变的时候不再重复设置 AGC 的那个寄存器。

Patch id: MAUI_02602310

2、答录机中进入远程访问之后,直接开始播放所有未读留言,此时用户输入 DTMF 无效

主要原因是函数 mmi_autoam_key_detection_callback 中没有把 MMI_AUTOAM_STATE_REMOTE_PRE_PLAY_UNREAD

这种 case 考虑进去,导致无法相对应的 DTMF 输入,修改方法是将这种 case 加进去

Patch id: MAUI_02029196

3、实现第三方的魔音功能的时候要修改 wav.c

添加第三方的魔音功能的时候,常常会要求开发 wav.c,因为要改到这里面的某些函数。出于策略,从 09A0924 之后,wav.c 等相关文件都被封装到 lib 中了,这部分将不会再重新开放出来。事实上,要实现魔音功能,其实不开放
wav.c 也是可以完成的,基本上只需要修改函数 wavADPCMPutData 和 wavDviADPCMPutDataMono,可以在 code
中对 ihdl->wav.Wav_PutData 进行赋值的地方进行相应的修改,赋值成自行修改之后的函数
wavADPCMPutData_modified 和 wavDviADPCMPutDataMono_modified 即可。

4、在通话中,播放背景音时,如何屏蔽掉按键音

如果是本地产生的按键音,可以利用 BGSND 的接口,把整个 speech 关闭。

修改 aud_snd_play_req 和 aud_snd_set_volume_req_hdlr:

SND_ConfigULMixer(snd_handle, KAL_TRUE, volume);

改为

SND_ConfigULMixer(snd_handle, KAL_FALSE, volume);

如果是因为按键产生 DTMF 发送到对方触发对方手机产生的声音,只能通过屏蔽本地产生 DTMF 处理。

方法是在通话时进入 option 选择其中的 DTMF 菜单并设成 off 或者直接在代码里设置

g_ucm_p->call_miss.is_dtmf=false 来实现。

5、来电时播放一段声音对对方听,自己这边不放出声来,同时本地的声音对方也听不见。然后在播放结束之后进入正常通话状态

修改文件 Am.c 中的函数 AM_SpeechOn()

在改函数内部加上判断条件,如果处于播放背景音的应用则不调用

AFE_TurnOnSpeaker(L1SP_SPEECH);

AFE_TurnOnMicrophone(L1SP_SPEECH);

在播放背景音的 callback 中调用函数

AFE_TurnOnSpeaker(L1SP_SPEECH);

AFE_TurnOnMicrophone(L1SP_SPEECH); 即可进入正常通话状态

参考

Android10.0AudioFocus之源码分析(二)

Android 电话拨入音频焦点(Audio Focus)

Android ALSA音频系统架构分析(1)----从Loopback了解Audio

Android 如何在通话中播放音乐/通话背景音

mt6735 Audio Common 通话时如何播放声音给对方听

上一篇:李宏毅DLHLP.26.Audio BERT.2/2


下一篇:WEBRTC系列之基于IOS平台编译WEBRTC(一)