Android bluetooth audio two problems

1. QQ calls, WeChat calls, phone calls, when the ringtone is remembered, why does the ringtone only ring on the mobile phone? And the bluetooth headset only beeps?

(1) Call ringtone playback

streamType = 2(AUDIO_STREAM_RING)
APM::AudioPolicyManager: startOutput() output 18, stream 2, session 24

(2) Engine::getStrategyForStream() function can get stream 2 corresponding to
strategy 2 (STRATEGY_SONIFICATION)
(3) Select device

APM::AudioPolicyEngine: getDeviceForStrategy() strategy 2, device 82
结果为AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_SPEAKER

This place is strange, the selected devices are bluetooth devices and speakers, why only the speakers have ringtones?

It can be found in the log that
bt_a2dp_hw: out_set_parameters: state 5
5 corresponds to AUDIO_A2DP_STATE_STANDBY
After a lot of searching, it can be found that
it runs when the bell rings

adb shell dumpsys media.audio_flinger results

For Bluetooth devices:

Output thread 0xecec0000 type 0 (MIXER):
  Thread name: AudioOut_441
  I/O handle: 1089
  TID: 2033
  Standby: yes
  Sample rate: 44100 Hz
  HAL frame count: 2560
  HAL format: 0x1 (pcm16)
  HAL buffer size: 10240 bytes
  Channel count: 2
  Channel mask: 0x00000003 (front-left, front-right)
  Format: 0x1 (pcm16)
  Frame size: 4 bytes
  Pending config events: none
  Output device: 0x80 (BLUETOOTH_A2DP)

Tips
When there are multiple output devices, each device corresponds to a Mixthread, and then corresponds to a total DuplicatingThread.

The Output thread corresponding to the Bluetooth device is in the Standby state when the ringtone is playing. And this state assignment is easy to find (Threads.cpp):

if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) ||
                                   isSuspended()) {
                // put audio hardware into standby after short delay
                if (shouldStandby_l()) {

                    threadLoop_standby();

                    mStandby = true;
                }

After some searching, the truth came out:

AudioPolicyManager setPhoneState will call the checkA2dpSuspend() function, which eventually leads to Bluetooth Thread standBy. Then the entire Bluetooth output-related MixThread is suspended. At this time, the out_write function will definitely not be called to write down the ringtone data, and no sound will be emitted. .

Look at the official and see the comment in the checkA2dpSuspend function:

// suspend A2DP output if:
    //      (NOT already suspended) &&
    //      ((SCO device is connected &&
    //       (forced usage for communication || for record is SCO))) ||
    //      (phone state is ringing || in call)//响铃的时候要把a2dp挂起,注意是a2dp
    //
    // restore A2DP output if:
    //      (Already suspended) &&
    //      ((SCO device is NOT connected ||
    //       (forced usage NOT for communication && NOT for record is SCO))) &&
    //      (phone state is NOT ringing && NOT in call)
    //

Based on the English level of the lower level 4, the general idea is: when making a call or is ringing (after setPhonestate 0) (sco must be connected successfully), use sco and suspend a2dp.

The difference between Baidu Soso sco and a2dp:

Bluetooth generally has two voice-related modes: A2DP and SCO. The former is for high-quality music playback (commonly known as: only in and out), and the latter is for voice calls (commonly known as: in and out).

Excerpted from: http://blog.csdn.net/kangear/article/details/38780185 (If there is any offense, please forgive me)

2. During a call, if the handsfree is turned on, the sound is no longer output from the Bluetooth device, but from the mobile phone. Why?

Let's take a look.
After the call is connected, the phone application will normally call
setBluetoothScoOn() to switch the Bluetooth device to Sco mode.

public void setBluetoothScoOnInt(boolean on) {
        if (on) {
        //通话时强制使用BT_SCO
            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
            mForcedUseForComm = AudioSystem.FORCE_NONE;
        }
        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
    }

, after clicking "Speaker" setSpeakerphoneOn()

public void setSpeakerphoneOn(boolean on){
        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
            return;
        }

        if (on) {
            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
            //如果之前设置了通话强制使用BT_SCO
            //先取消强制使用(FORCE_NONE)
                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
            }
            //设置强制使用SPEAKER
            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
            mForcedUseForComm = AudioSystem.FORCE_NONE;
        }

        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
    }
case MSG_SET_FORCE_USE:
                case MSG_SET_FORCE_BT_A2DP_USE:
                    setForceUse(msg.arg1, msg.arg2);
                    break;
//往下,AudioPolicyManager setForceUse的调用就略过不提了。

so. . . At once. . . not much to say

Guess you like

Origin blog.csdn.net/bberdong/article/details/53036569