Android藍芽音訊兩個問題
阿新 • • 發佈:2019-01-09
1.qq通話,微信通話,打電話,鈴聲想起時,為何鈴聲只在手機端響起?而藍芽耳機裡只有嘟嘟聲?
(1)來電鈴聲播放
streamType = 2(AUDIO_STREAM_RING)
APM::AudioPolicyManager: startOutput() output 18, stream 2, session 24
(2)Engine::getStrategyForStream()函式可得stream 2對應
strategy 2 (STRATEGY_SONIFICATION)
(3)選裝置
APM::AudioPolicyEngine: getDeviceForStrategy() strategy 2 , device 82
結果為AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_SPEAKER
這地方就奇怪了,明明選擇的裝置是藍芽裝置和揚聲器,為什麼只有揚聲器有鈴聲?
log中可以發現
bt_a2dp_hw: out_set_parameters: state 5
5 對應 AUDIO_A2DP_STATE_STANDBY
經過一番費力的查詢,可以發現
鈴聲響起時執行
adb shell dumpsys media.audio_flinger結果中
藍芽裝置對應的:
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)
小提示
多輸出裝置的時候,每個裝置對應一個Mixthread,然後對應著一個總的DuplicatingThread。
藍芽裝置對應的Output thread在鈴聲播放的時候處於Standby狀態。而這個狀態賦值的地方很好找到(Threads.cpp):
if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) ||
isSuspended()) {
// put audio hardware into standby after short delay
if (shouldStandby_l()) {
threadLoop_standby();
mStandby = true;
}
經過一番尋找,真相了:
AudioPolicyManager setPhoneState會呼叫checkA2dpSuspend()函式,最終導致藍芽Thread standBy.然後整個藍芽輸出相關的MixThread都暫停工作了,此時肯定不會去呼叫out_write函式往下寫鈴聲資料,也就不會發出任何聲音了。
看官且看checkA2dpSuspend函式中註釋:
// 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)
//
以在下區區四級的英文水平觀之,大意為:打電話或者is ringing(setPhonestate 0之後)的時候(sco要連線成功)要用sco,掛起a2dp.
百度搜搜sco和a2dp的區別:
2. 通話過程中,如果開啟擴音,聲音不再從藍芽裝置中輸出,而從手機端輸出,這是為什麼?
我們且看看
電話接通之後,電話應用正常會呼叫
setBluetoothScoOn()切換藍芽裝置為Sco模式
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);
}
,點選“揚聲器”之後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的呼叫就略過不提了。
所以。。。就。。。不多說了