蓝牙音乐和导航语音播放混音卡顿问题

最近发现公司自研的智能车载设备上存在一个问题:手机通过蓝牙连接车机,在手机上播放音乐车机上发声然后跟车机上的导航语音播报一起混音播出的时候会出现卡顿的现象;但是在车机上播放音乐和导航混音就正常。另外需要说明的是播放音乐使用的是Music流,导航使用的是Alarm流

通过 adb shell dumpsys media.audio_flinger 工具对比查看两种场景下实时的音频流信息(截取其中一个回放线程中的音频流信息如下):

Output thread 0xe6c833c0 type 0 (MIXER):
  Thread name: AudioOut_1D
  I/O handle: 29
  TID: 935
  Standby: yes
  Sample rate: 48000 Hz
  HAL frame count: 1920
  HAL format: 0x1 (pcm16)
  HAL buffer size: 7680 bytes
  Channel count: 2
  Channel mask: 0x00000003 (front-left, front-right)
  Processing format: 0x1 (pcm16)
  Processing frame size: 4 bytes
  Pending config events: none
  Output device: 0x20000 (LINE)
  Input device: 0 (NONE)
  Audio source: 0 (default)
  Normal frame count: 1920
  Last write occurred (msecs): 1087537
  Total writes: 4905
  Delayed writes: 0
  Blocked in write: no
  Suspend count: 0
  Sink buffer : 0xe73da000
  Mixer buffer: 0xe83d8000
  Effect buffer: 0xe73dc000
  Fast track availMask=0xfe
  Standby delay ns=3000000000
  AudioStreamOut: 0xe83c82a0 flags 0x8 (DEEP_BUFFER)
  Frames written: 9417600
  Suspended frames: 0
  Hal stream dump:
  Thread throttle time (msecs): 106
  AudioMixer tracks: 0x00000003
  Master mono: off
  FastMixer not initialized
  Stream volumes in dB: 0:-11, 1:-10, 2:-10, 3:0, 4:-10, 5:-10, 6:0, 7:-10, 8:-10, 9:-96, 10:0, 11:0, 12:0
  Normal mixer raw underrun counters: partial=0 empty=0
  2 Tracks of which 0 are active
    Name Active Client Type      Fmt Chn mask Session fCount S F SRate  L dB  R dB    Server Main buf  Aux Buf Flags UndFrmCnt
       1     no   3190    3 00000001 00000003      97   7088 I 0 22050     0     0  00000000 0xe73da000 0x0 0x000         0 
       0     no   3190    3 00000001 00000003      89   7072 P 3 44100     0     0  004FF80C 0xe73da000 0x0 0x600      1768 
  0 Effect Chains

进一步简化对比可以看到:

车机上播音乐和导航    不卡顿    
    导航语音是     AudioStreamOut: 0xea0c8150 flags 0x6 (PRIMARY|FAST)
    后台音乐是     AudioStreamOut: 0xea0c82a0 flags 0x8 (DEEP_BUFFER)
手机上播音乐和车机上播导航     卡顿
    导航语音和后台音乐都是   AudioStreamOut: 0xea0c8150 flags 0x6 (PRIMARY|FAST)

蓝牙连接上手机后Music流走的输出流通道和导航的Alarm流走的输出流通道是同一个;车机上的Music流和导航的Alarm流走的是不同的输出流通道,也即是虽然两种场景下音乐的流都是Music流但是属性是不一样的,导致了最终系统选择的输出流通道不一致。

分析蓝牙底层的服务,看看蓝牙播放音乐时构建的AudioTrack对象跟平时播放音乐的有什么不同之处

void *BtifAvrcpAudioTrackCreate(int trackFreq, int channelType)
{
    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d  channel %d ",
                     __func__, trackFreq, channelType);
    sp<android::AudioTrack> track =
        new android::AudioTrack(AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT,
                                channelType, (size_t) 0 /*frameCount*/,
                                (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST,
                                NULL /*callback_t*/, NULL /*void* user*/, 0 /*notificationFrames*/,
                                AUDIO_SESSION_ALLOCATE, android::AudioTrack::TRANSFER_SYNC);//!!!注意AUDIO_OUTPUT_FLAG_FAST属性
    assert(track != NULL);

    BtifAvrcpAudioTrack *trackHolder = new BtifAvrcpAudioTrack;
    assert(trackHolder != NULL);
    trackHolder->track = track;

    if (trackHolder->track->initCheck() != 0)
    {
        return nullptr;
    }

#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
    outputPcmSampleFile = fopen(outputFilename, "ab");
#endif
    trackHolder->track->setVolume(1, 1);
    return (void *)trackHolder;
}

调试的经验表明车机端音乐类应用在底层给出的属性一般是 AUDIO_OUTPUT_FLAG_DEEP_BUFFER ,这里给定的是 AUDIO_OUTPUT_FLAG_FAST,所以导致了这里的Music流走了跟Alarm流同一个输出流通道,当导航的Alarm音频流过来以后,音频路由发生了改变,先关闭了当前的输出流通道然后再开启才导致的卡顿问题,最后解决方案也很简单,将蓝牙这里的AUDIO_OUTPUT_FLAG_FAST属性修改为AUDIO_OUTPUT_FLAG_DEEP_BUFFER 属性即可,卡顿现象也随即消失。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现 Android 多人语音通话中混音播放 PCM 的一种方法是使用 AudioTrack 类。首先,你需要将每个人的 PCM 数据进行混音,然后将混音后的 PCM 数据传递给 AudioTrack 对象进行播放。 以下是一些实现步骤: 1. 创建一个 AudioTrack 对象,并设置相关参数。 ``` int sampleRateInHz = 44100; int channelConfig = AudioFormat.CHANNEL_OUT_MONO; int audioFormat = AudioFormat.ENCODING_PCM_16BIT; int bufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM); ``` 2. 将每个人的 PCM 数据进行混音。可以通过将每个人的 PCM 数据的每个采样点相加并除以参与混音的人数来实现混音。这里假设有两个人的 PCM 数据。 ``` byte[] pcmData1 = ...; // 第一个人的 PCM 数据 byte[] pcmData2 = ...; // 第二个人的 PCM 数据 byte[] mixPcmData = new byte[pcmData1.length]; for (int i = 0; i < pcmData1.length; i += 2) { // 将每个采样点相加并除以 2 short sample1 = (short) ((pcmData1[i + 1] << 8) | pcmData1[i]); short sample2 = (short) ((pcmData2[i + 1] << 8) | pcmData2[i]); short mixSample = (short) ((sample1 + sample2) / 2); mixPcmData[i] = (byte) (mixSample & 0xff); mixPcmData[i + 1] = (byte) ((mixSample >> 8) & 0xff); } ``` 3. 将混音后的 PCM 数据传递给 AudioTrack 对象进行播放。 ``` audioTrack.play(); audioTrack.write(mixPcmData, 0, mixPcmData.length); ``` 需要注意的是,在多人语音通话中,每个人的 PCM 数据的采样率、声道数、采样位数等参数可能不同,需要进行处理以确保混音后的 PCM 数据的参数一致。同时,由于混音后的 PCM 数据可能会比单个人的 PCM 数据更大,需要确保 AudioTrack 对象的缓冲区足够大以避免播放时出现丢失数据的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值