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的区别:
蓝牙一般有两种语音相关的模式是A2DP和SCO,前者是高质量音乐播放(俗称:只进不出),后者是语音通话(俗称:有进有出)。
摘自:http://blog.csdn.net/kangear/article/details/38780185(如有冒犯,请作者原谅)
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的调用就略过不提了。
所以。。。就。。。不多说了