Android蓝牙音频两个问题

24 篇文章 32 订阅

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的调用就略过不提了。

所以。。。就。。。不多说了

如果您想使用Android的AudioRecorder录制音频,并在蓝牙音箱上播放,请按照以下步骤操作: 1. 配置和准备录音器 创建`AudioRecorder`对象,设置音频源、采样率、声道数、编码格式等参数,并调用`prepare()`方法准备录音器。 2. 启动录音 调用`start()`方法开始录音。录音期间,将蓝牙音箱连接到Android设备,并将其设置为音频输出源。 3. 播放录制的音频 录音完成后,您可以使用`MediaPlayer`对象加载和播放录制的音频文件。在播放期间,音频将通过蓝牙音箱进行输出。 下面是一个简单的示例代码: ``` private AudioRecorder audioRecorder; private MediaPlayer mediaPlayer; private void startRecordingAndPlayback() { audioRecorder = new AudioRecorder(); audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); audioRecorder.setAudioSamplingRate(44100); audioRecorder.setAudioChannels(2); audioRecorder.setOutputFile(getFilePath()); // 设置音频文件保存路径 try { audioRecorder.prepare(); audioRecorder.start(); } catch (Exception e) { e.printStackTrace(); } mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(getFilePath()); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepare(); mediaPlayer.start(); } private void stopRecordingAndPlayback() { if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } if (audioRecorder != null) { audioRecorder.stop(); audioRecorder.release(); audioRecorder = null; } } ``` 请注意,这只是一个基本示例。您可能需要根据自己的需求进行更改和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值