首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >理解音频焦点 (第 3/3 部分):三个步骤实现音频聚焦

理解音频焦点 (第 3/3 部分):三个步骤实现音频聚焦

作者头像
Android 开发者
发布于 2024-01-27 04:24:43
发布于 2024-01-27 04:24:43
62100
代码可运行
举报
文章被收录于专栏:Android 开发者Android 开发者
运行总次数:0
代码可运行

本系列文章旨在让您深入理解音频焦点的含义,使用方法和其对用户体验的重要性。本篇文章是该系列的第一部分,该系列三篇文章包含了:

  1. 最常见的音频焦点用例和成为一个优秀的媒体事业人员的重要性
  2. 其它一些能体现音频焦点对应用体验的重要性的用例
  3. 在您的应用中实现音频焦点的三个步骤 (此篇文章)

如果您不妥善处理好音频聚焦,您的用户可能受到下图所示的困扰。

现在您已经知道音频聚焦的重要性,让我们通过一些步骤来让您的应用程序正确处理音频焦点。

开始代码示例之前,先看看下图,它展示了实现步骤:

步骤一 :请求音频焦点

获取音频焦点的第一个步骤是先向系统发出申请焦点的消息。注意这只是发出请求,并非直接获取。为了申请到音频聚焦,您必须向系统描述好您的意图。介绍四个常见音频焦点类型:

  • AUDIOFOCUS_GAIN的使用场景:应用需要聚焦音频的时长会根据用户的使用时长改变,属于不确定期限。例如:多媒体播放或者播客等应用。
  • AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK的使用场景:应用只需短暂的音频聚焦,来播放一些提示类语音消息,或录制一段语音。例如:闹铃,导航等应用。
  • AUDIOFOCUS_GAIN_TRANSIENT的使用场景:应用只需短暂的音频聚焦,但包含了不同响应情况,例如:电话、QQ、微信等通话应用。
  • AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE 的使用场景:同样您的应用只是需要短暂的音频聚焦。未知时长,但不允许被其它应用截取音频焦点。例如:录音软件。

在 Android O 或者更新的版本上您必须使用 builder 来实例化一个 AudioFocusRequest 类。(在 builder 中必须指明请求的音频焦点类型)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
AudioAttributes mAudioAttributes =
       new AudioAttributes.Builder()
               .setUsage(AudioAttributes.USAGE_MEDIA)
               .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
               .build();
AudioFocusRequest mAudioFocusRequest =
       new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
               .setAudioAttributes(mAudioAttributes)
               .setAcceptsDelayedFocusGain(true)
               .setOnAudioFocusChangeListener(...) // Need to implement listener
               .build();
int focusRequest = mAudioManager.requestAudioFocus(mAudioFocusRequest);
switch (focusRequest) {
   case AudioManager.AUDIOFOCUS_REQUEST_FAILED:
       // 不允许播放
   case AudioManager.AUDIOFOCUS_REQUEST_GRANTED:
       // 开始播放
}

音频焦点类型要点:

  1. AudioManager.AUDIOFOCUS_GAIN:请求长时间音频聚焦。如果只是临时需要音频焦点可以选用这几个:AUDIOFOCUS_GAIN_TRANSIENTAUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
  2. 您必须通过 setOnAudioFocusChangeListener() 方法来实现 AudioManager.OnAudioFocusChangeListener 接口。用来响应音频焦点状态的变化,如被其它应用截取了音频焦点,或者其它应用释放焦点,都会在这里回调。
  3. 调用 AudioManager 的 requestAudioFocus(…) 方法,需要用到实例化好的 AudioFocusRequest。 请求结果以一个 int 变量返回:AUDIOFOCUS_REQUEST_GRANTED 表示获得授权, AUDIOFOCUS_REQUEST_FAILED 表示被系统拒绝。

在 Android N 及其更早的版本中,不需要用到 AudioFocusRequest,只需实现 AudioManager.OnAudioFocusChangeListener 接口。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int focusRequest = mAudioManager.requestAudioFocus(
..., // Need to implement listener
       AudioManager.STREAM_MUSIC,
       AudioManager.AUDIOFOCUS_GAIN);
switch (focusRequest) {
   case AudioManager.AUDIOFOCUS_REQUEST_FAILED:
       // don't start playback
   case AudioManager.AUDIOFOCUS_REQUEST_GRANTED:
       // actually start playback
}

上述皆为音频焦点的申请,接下来我们将介绍 AudioManager.OnAudioFocusChangeListener 如何实现,以此来响应音频焦点的状态。

步骤二 :响应音频焦点的状态改变

一旦获得音频聚焦,您的应用要马上做出响应,因为它的状态可能在任何时间发生改变(丢失或重新获取),您可以实现 OnAudioFocusChangeListener 的来响应状态改变。

以下代码展示了 OnAudioFocusChangeListener 接口的实现,它处理了与 Google Assistant 应用协同工作的时候,音频焦点的各种状态的变化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private final class AudioFocusHelper
        implements AudioManager.OnAudioFocusChangeListener {
private void abandonAudioFocus() {
        mAudioManager.abandonAudioFocus(this);
    }
@Override
    public void onAudioFocusChange(int focusChange) {
        switch (focusChange) {
            case AudioManager.AUDIOFOCUS_GAIN:
                if (mPlayOnAudioFocus && !isPlaying()) {
                    play();
                } else if (isPlaying()) {
                    setVolume(MEDIA_VOLUME_DEFAULT);
                }
                mPlayOnAudioFocus = false;
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                setVolume(MEDIA_VOLUME_DUCK);
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                if (isPlaying()) {
                    mPlayOnAudioFocus = true;
                    pause();
                }
                break;
            case AudioManager.AUDIOFOCUS_LOSS:
                mAudioManager.abandonAudioFocus(this);
                mPlayOnAudioFocus = false;
                stop();
                break;
        }
    }
}

关于暂停播放,应用程序的行为应该是不同的。如果用户主动暂停播放时,您的应用应释放音频焦点。如果是为了响应音频焦点的暂时丢失而暂停播放,则不应释放音频焦点。 这里有一些用例来说明这一点。

分析上面接口mPlayOnAudioFocus 的场景,您的音频应用正在后台播放音乐:

  1. 用户点击播放,您的应用向系统申请音频聚焦,假如系统授权了。
  2. 现在用户长按 HOME 键启动 Google Assistant。Google Assistant 会向系统申请一个短暂的音频聚焦。
  3. 一旦系统授权给 Google Assistant,您的 OnAudioFocusChangeListener 接口会收到 AUDIOFOCUS_LOSS_TRANSIENT 事件回调。您在这个回调里处理暂停音乐播放。
  4. 当 Google Assistant 使用结束,您的 OnAudioFocusChangeListener 会收到 AUDIOFOCUS_GAIN 事件回调。 在这里您可以处理是否让音乐恢复播放。

以下代码展示如何释放音频焦点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final void pause() {
   if (!mPlayOnAudioFocus) {
       mAudioFocusHelper.abandonAudioFocus();
   }
  onPause();
}

您可以看到释放焦点是在用户暂停播放的时候,而非其它应用请求焦点 AUDIOFOCUS_GAIN_TRANSIENT 导致他们释放焦点。

应对焦点丢失

选择在 OnAudioFocusChangeListener 中暂停还是降低音量,取决于您应用的交互方式。在 Android O上,会自动的帮您降低音量,所以您可以忽略 OnAudioFocusChangeListener 接口的 AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 事件。

在 Android O 以下的版本,您需要自己用代码实现,具体实现方式如上面代码所示。

延迟聚焦

Android O 介绍了延迟聚焦这个概念,您可以在申请音频聚焦的时候来响应 AUDIOFOCUS_REQUEST_DELAYED 这个结果,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void requestPlayback() {
    int audioFocus = mAudioManager.requestAudioFocus(mAudioFocusRequest);
    switch (audioFocus) {
        case AudioManager.AUDIOFOCUS_REQUEST_FAILED:
            ...
        case AudioManager.AUDIOFOCUS_REQUEST_GRANTED:
            ...
        case AudioManager.AUDIOFOCUS_REQUEST_DELAYED:
            mAudioFocusPlaybackDelayed = true;
    }
}

在您 OnAudioFocusChangeListener 的实现,您需要检查 mAudioFocusPlaybackDelayed 这个变量,当您响应 AUDIOFOCUS_GAIN 音频聚焦的时候, 如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void onAudioFocusChange(int focusChange) {
   switch (focusChange) {
       case AudioManager.AUDIOFOCUS_GAIN:
           logToUI("Audio Focus: Gained");
           if (mAudioFocusPlaybackDelayed || mAudioFocusResumeOnFocusGained) {
               mAudioFocusPlaybackDelayed = false;
               mAudioFocusResumeOnFocusGained = false;
               start();
           }
           break;
       case AudioManager.AUDIOFOCUS_LOSS:
           mAudioFocusResumeOnFocusGained = false;
           mAudioFocusPlaybackDelayed = false;
           stop();
           break;
       case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
           mAudioFocusResumeOnFocusGained = true;
           mAudioFocusPlaybackDelayed = false;
           pause();
           break;
       case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
           pause();
           break;
   }
}

步骤三 :释放音频焦点

播放完音频,记得使用 AudioManager.abandonAudioFocus(…) 来释放掉音频焦点。在前面的步骤中,我们遇到了一个应用暂停播放应该释放音频焦点的情况,但是这个应用依旧保留了音频焦点。

代码示例

几个您可以在您应用使用的案例

GitHub gist 上有三个类关于音频焦点的使用,这可能对您的代码有帮助。

  • AudioFocusRequestCompat:使用这个类来描述您的音频焦点类型
  • AudioFocusHelper:这个类帮助您处理音频焦点,您可以把它加入您的代码,但是必须确保在您的播放 service 中使用 AudioFocusAwarePlayer 这个接口。
  • AudioFocusAwarePlayer:这个接口应该在 service 中实现,来管理您的播放组件(MediaPlayer或者ExoPlayer),它可以确保 AudioFocusHelper 正常工作。

完整的代码示例

android-MediaBrowserService 完整展示了音频焦点的处理,使用 MediaPlayer 来播放音乐,同时使用了 MediaSession

PlayerAdapter展示了音频聚焦的最佳实践,请注意 pause()onAudioFocusChange(int) 方法的实现。

测试您的代码

一旦您在应用中实现了音频焦点的处理,您可以使用安卓媒体控制工具来测试您的应用对音频聚焦的真实反映,具体使用方法请查阅 GitHub/Android Media Controller.

Android多媒体开发资源


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
实测Android音频的焦点获取和归还
最近老板想在产品中的短视频后者直播播放的时候对于手机中的音乐播放器进行暂停播放,并且退出视频播放后手机的音乐播放器还能继续播放之前的音乐。
静默加载
2022/02/09
3.9K0
实测Android音频的焦点获取和归还
android学习笔记----关于音频焦点Audio Focus
为了便于理解,我们以android的8.0以前的版本为例,8.0以后有一定改动,但是基本思路一样。
砖业洋__
2023/05/06
2K0
笔记59 | Android管理音频焦点的学习
管理音频焦点 由于可能会有多个应用可以播放音频,所以我们应当考虑一下他们应该如何交互。为了防止多个音乐播放应用同时播放音频,Android使用音频焦点(Audio Focus)来控制音频的播放——即只有获取到音频焦点的应用才能够播放音频。 在我们的应用开始播放音频之前,它需要先请求音频焦点,然后再获取到音频焦点。另外,它还需要知道如何监听失去音频焦点的事件并对此做出合适的响应。 请求获取音频焦点(Request the Audio Focus) 在我们的应用开始播放音频之前,它需要获取将要使用的音频流的音频
项勇
2018/06/19
2.2K0
什么是音频焦点管理?音频焦点的行为准则是什么?
两个或两个以上的 Android 应用可同时向同一输出流播放音频。系统会将所有音频流混合在一起。虽然这是一项出色的技术,但却会给用户带来很大的困扰。为了避免所有音乐应用同时播放,Android 引入了“音频焦点”的概念。 一次只能有一个应用获得音频焦点。
用户9253515
2022/01/17
2.4K0
音视频基础能力之 Android 音频篇 (四):音频路由
涉及硬件的音视频能力,比如采集、渲染、硬件编码、硬件解码,通常是与客户端操作系统强相关的,就算是跨平台的多媒体框架也必须使用平台原生语言的模块来支持这些功能。本系列文章将详细讲述移动端音视频的采集、渲染、硬件编码、硬件解码这些涉及硬件的能力该如何实现。
声知视界
2024/12/23
6200
音视频基础能力之 Android 音频篇 (四):音频路由
Android使用WebView加载H5页面播放视频音频,退出后还在播放问题解决
Android中经常会使用到WebView来加载H5的页面,如果H5页面中有音频或者视频的播放时,还没播放完就退出界面,这个时候会发现音频或者视频还在后台播放,这就有点一脸懵逼了,下面是解决方案:
SoullessCoder
2019/08/07
2.4K0
Android 音频开发入门指南
Android 平台提供了一套丰富的音频 API,使得开发者可以轻松地为应用添加音频播放、录制、处理等功能。这些 API 包括:
陆业聪
2024/07/23
5570
Android 音频开发入门指南
理解音频焦点 (第1/3部分):常见的音频焦点用例
原文地址:Understanding Audio Focus (Part 1 / 3): Common Audio Focus use cases 原文作者:Nazmul Idris (Naz) 译文
Android 开发者
2018/05/31
2.4K0
音频开发ijkplayer小结 android
最近接触到一些音频开发的操作和一个音频开发的三方库: github:https://github.com/Bilibili/ijkplayer。 有人会问为什么使用三方库:最直接原因当然是因为系统的MediaPlayer支持格式不多或者是版本限制。具体只支持格式: http://developer.android.com/intl/zh-cn/guide/appendix/media-formats.html http://blog.csdn.net/ddna/article/details/517
用户1127566
2018/06/01
1.8K0
音视频开发之旅(45)-ExoPlayer 音频播放器实践(一)
通过上一篇的学习实践,我们了解了ExoPlayer的优缺点以及基本用法,今天我们进入ExoPlayer的音频播放实践,我们来一起实现一个简单的音频播放器。
音视频开发之旅
2021/05/29
5.7K1
音视频开发之旅(45)-ExoPlayer 音频播放器实践(一)
Android-MediaPlayer
突然觉得这个音乐播放有点意思,我们来做一下吧。 首先我们来一个名为MediaPlayerDemo的项目。 然后再main.xml文件里面创建三个按钮,分别是播放、暂停、停止,代码如下:
晨曦_LLW
2020/09/25
7800
从 0 到 1 掌握鸿蒙 AudioRenderer 音频渲染:我的自学笔记与踩坑实录(API 14)
​最近我在研究 HarmonyOS 音频开发。在音视频领域,鸿蒙的 AudioKit 框架提供了 AVPlayer 和 AudioRenderer 两种方案。AVPlayer 适合快速实现播放功能,而 AudioRenderer 允许更底层的音频处理,适合定制化需求。本文将以一个开发者的自学视角,详细记录使用 AudioRenderer 开发音频播放功能的完整过程,包含代码实现、状态管理、最佳实践及踩坑总结。
李游Leo
2025/03/18
960
从 0 到 1 掌握鸿蒙 AudioRenderer 音频渲染:我的自学笔记与踩坑实录(API 14)
Android多媒体之认识MP3与内置媒体播放(MediaPlayer)
零、前言 作为90后,mp3格式的音乐可谓灵魂之友。 小时候带着耳机,躺在桌子上听歌看月亮心情依稀。 当某个旋律想起,还会不会浮现某个风景,某个人……, 今天全程单曲播放——梁静茹-勇气(献上
张风捷特烈
2019/02/25
2.1K0
Android多媒体之认识MP3与内置媒体播放(MediaPlayer)
Android 8.0 功能和 API(翻译自Google官网)
Android 8.0 为用户和开发者引入多种新功能。本文重点介绍面向开发者的新功能。
蜻蜓队长
2018/08/03
3.2K0
Android 8.0 功能和 API(翻译自Google官网)
Android SoundPool 音效播放库
我们如果想在应用中进行播放一些音效,例如提示音,提示短语等简短的音频文件。可以使用 SoundPool 这个工具进行快捷播放。
zinyan.com
2023/07/14
9460
Android SoundPool 音效播放库
教你使用超简单的视频播放器JiaoZiVideoPlayer
在之前的项目中用到了视频播放的功能,在网上看了看使用了大家用的比较多的一个开源项目JiaoZiVideo让我迅速的实现了视频播放的相关功能。
程思扬
2022/01/11
5.4K0
教你使用超简单的视频播放器JiaoZiVideoPlayer
Android应用的必要功能——音频的播放
Android应用面向的是普通个人用户,这些用户往往会更加关注用户体验,因此为Android应用增加动画、视频、音乐等多媒体功能十分必要。就目前的手机发展趋势来看,手机已经不再是单一的通信工具,已经发展成集照相机、音乐播放器、视频播放器、个人小型终端于一体的智能设备,因此为手机提供音频录制、播放,视频录制、播放的功能十分重要。
博文视点Broadview
2020/06/11
2K0
Android简易“吹一吹实现”以及录音和播放示例
最近在做一些跟传感器相关的东西,有注意到以前腾讯微博以前出过一个吹一吹交互,虽然和传感器无关,但是感觉也比较有兴趣,就写了一个拙劣的demo,因为接触媒体文件操作比较少,顺带写了一个录音和播放的例子,总结了一下一些小坑的地方,一并在此分享给大家。 主要思路和坑的地方 主要的思路是通过MediaRecorder提供的getMaxAmplitude()函数,获取一段时间内输入的音频最大幅值来进行检测,所以除了吹的动作,其他声音也会被录进来。 “吹”这个动作如果想和其他动作进行区分,其实本质在于吹的时候靠近听筒,
NaOH
2018/05/29
1.3K0
NDK--利用OpenSL ES实现播放FFmpeg解码后的音频流
1、创建引擎接口对象 2、创建混音器 3、创建播放器(录音器) 4、设置缓冲队列和回调函数 5、设置播放状态 6、启动回调函数
aruba
2020/07/13
1.2K0
推荐阅读
相关推荐
实测Android音频的焦点获取和归还
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档