Android使用AudioTrack时AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK不生效问题
问题根因
- AudioAttributes配置不符合导航播报的场景规范,当前使用的
USAGE_MEDIA、CONTENT_TYPE_MUSIC属于普通媒体内容,部分应用不会针对普通媒体的AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK请求做降音量处理 - 未设置
OnAudioFocusChangeListener,Android 8.0及以上版本的AudioFocusRequest要求必须绑定焦点变化监听器,否则部分系统版本会判定该焦点请求无效,不会通知其他应用响应焦点变化 - 焦点释放时机错误,当前代码在写入音频数据后立刻调用
abandonAudioFocusRequest释放焦点,焦点持有时间极短,其他应用还没来得及执行降音量逻辑就已经收到焦点恢复通知,自然看不到效果
修复方案
1. 修正AudioAttributes配置
将AudioTrack和焦点请求共用的AudioAttributes改为导航场景专属配置,系统会对这类用途的音频焦点请求做优先处理,第三方应用也普遍适配了这类场景的duck逻辑:
AudioAttributes playbackAttributes = new AudioAttributes.Builder() // 设置为导航引导用途,系统优先级更高 .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) // 设置为语音内容,匹配导航播报场景 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .build();
2. 补全焦点变化监听器
哪怕暂时没有复杂逻辑也要给焦点请求绑定监听器,保证高版本系统的焦点请求正常生效:
// 先实现基础监听器,后续再补充焦点丢失、恢复等场景的处理逻辑 AudioManager.OnAudioFocusChangeListener afChangeListener = focusChange -> { // 后续逻辑补充位置 }; AudioFocusRequest focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) .setAudioAttributes(playbackAttributes) .setAcceptsDelayedFocusGain(true) // 必须绑定监听器 .setOnAudioFocusChangeListener(afChangeListener) .build();
3. 调整焦点释放时机
不要在写入音频数据后立刻释放焦点,要等音频完全播放完成后再执行释放操作:
// 给AudioTrack设置播放完成监听 audioTrack.setPlaybackPositionUpdateListener(new AudioTrack.PlaybackPositionUpdateListener() { @Override public void onMarkerReached(AudioTrack track) { // 音频播放完成后再释放焦点 audioManager.abandonAudioFocusRequest(focusRequest); // 后续可补充AudioTrack资源释放逻辑 } @Override public void onPeriodicNotification(AudioTrack track) {} }); // 设置播放完成标记为写入的音频数据长度 audioTrack.setNotificationMarkerPosition(myAudioData.length); // 原逻辑:申请到焦点后写入音频 if (afresult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { Log.d(TAG, "Audio Focus is granted "); audioTrack.setVolume(maxVolume*0.4f); audioTrack.write(myAudioData, 0, myAudioData.length); }
额外校验点
优先使用网易云音乐、QQ音乐等主流音频APP测试,部分小众音频应用未适配音频焦点规范,本身就不会响应AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK请求,不属于代码问题。
内容的提问来源于stack exchange,提问作者user12628549
相关产品推荐
相关产品推荐

