Android AudioManager

2024-02-02 23:12
文章标签 android audiomanager

本文主要是介绍Android AudioManager,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android AudioManager

API

AudioManager(audio翻译过来就是声音、音频):

AudioManager,音频管理类,它主要提供了丰富的API让开发者对应用的音量和铃声模式进行控制以及访问。主要内容涉及到音频流、声音、蓝牙、扩音器、耳机等等。AudioManager类位于android.Media 包中。

A:获取实例

​ 由于音频管理涉及到多媒体,因此这个AudioManager获取实例的方式是这样的:

AudioManager audio = (AudioManager)Context.getSystemService(Context.AUDIO_SERVICE);

B:丰富的API

音频管理类提供了大量的API,这些API是我们经常看到或者用到的,比如,调节音量,我相信对于很多人来说,调节音量这个姿势是很常见的,比如你打开某视频APP、某音乐APP其中肯定有调节音量大小的手势,那么调节音量内部的逻辑可以使用 adjustStreamVolume(int streamType, int direction, int flags)

参数预览:

streamType :要调整的音频流类型。类型有以下几种:

STREAM_VOICE_CALL(电话的音频流),

STREAM_SYSTEM(系统声音的音频流),

STREAM_RING(电话铃声的音频流),

STREAM_MUSIC(用于音乐播放的音频流)

STREAM_ALARM(警报的音频流)

STREAM_ACCESSIBILITY(无障碍的音频流)

STREAM_NOTIFICATION(通知的音频流)

区分流类型的目的是让用户能够单独地控制不同的种类的音频。但上述音频种类中,大多数都是被系统限制。除非应用需要做替换闹钟的铃声的操作,不然的话你只能通过STREAM_MUSIC来播放你的音频。也就是说我们最常见操作的就是STREAM_MUSIC这个类型。

direction :调整音量的方向。其中: ADJUST_LOWER(减少铃声音量),ADJUST_RAISE(增加铃声音量)或 ADJUST_SAME(保持之前的铃声音量)

flags :一个或多个标志。可能这里的标志不是很好理解,是这样,AudioManager提供了一些常量,我们可以将这些系统已经准备好的常量设置为这里的flags,比如:

FLAG_ALLOW_RINGER_MODES(更改音量时是否包括振铃模式作为可能的选项),

FLAG_PLAY_SOUND(是否在改变音量时播放声音),

FLAG_REMOVE_SOUND_AND_VIBRATE(删除可能在队列中或正在播放的任何声音/振动(与更改音量有关)),

FLAG_SHOW_UI(显示包含当前音量的吐司),

FLAG_VIBRATE(是否进入振动振铃模式时是否振动)

比如我现在想要增加音量,就可以这样写:

AudioManager . adjustStreamVolume (AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);

这句代码的意思是指:指定调节类型为 音乐的音频,增大音量,显示音量图形示意。举一反三下面就是降低音量的代码:

AudioManager . adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND);

比如,我想要获取手机的音量,可以调取getStreamVolume(int streamType); 这里的streamType指获得手机的当前流类型的音量,最大值为15(不同手机可能不同)最小值为0。

setStreamVolume(int streamType, int index,int flags)这个API顾名思义就是根据音频流类型去设置音量大小的。主要这里的index不能超过最大索引,也就是15。

getMode()

返回当前音频模式,如 NORMAL(普通), RINGTONE(铃声), orIN_CALL(通话)

setMode()

设置声音模式,可取值NORMAL(普通), RINGTONE(铃声), or IN_CALL(通话)

getRingerMode()

返回当前的铃声模式。如RINGER_MODE_NORMAL(普通)、RINGER_MODE_SILENT(静音)、RINGER_MODE_VIBRATE(震动)

setRingerMode(int ringerMode)

改变铃声模式

getStreamVolume(int streamType)

取得当前手机的音量,最大值为15,最小值为0,当为0时,手机自动将模式调整为“震动模式”。

getStreamMaxVolume(int streamType)

获得当前手机最大铃声。

setStreamMute(int streamType, boolean state) 静音或不静音音频流 设置指定声音类型(streamType)是否为静音。如果state为true,则设置为静音;否则,不设置为静音。

麦克风相关

setMicrophoneMute(boolean on):设置麦克风静音开启或关闭。( 设置true 关闭麦克风也就是麦克风静音; 设置false,即关闭静音打开麦克风)

setSpeakerphoneOn(boolean on):这个方法主要是判断是否打开扩音器(设置true,即打开免提电话; false将其关闭)

isMicrophoneMute():判断麦克风是否静音或是否打开(如果麦克风静音则为true,否则为false)

isMusicActive():判断是否有音乐处于活跃状态(如果任何音乐曲目有效,则为true)

比如蓝牙相关的API

isBluetoothA2dpOn() :这个方法是检查是否打开或关闭了到蓝牙耳机的A2DP音频路由。

isBluetoothScoOn(): 这个方法主要是检查通信是否使用蓝牙SCO。

startBluetoothSco(): 启动蓝牙SCO音频连接

setBluetoothScoOn(boolean on): 请求使用蓝牙SCO耳机进行通信。(设置true 代表用于通信的蓝牙SCO; 设置false 即不使用蓝牙SCO进行通信)

void stopBluetoothSco(): 停止蓝牙SCO音频连接。

等等,具体的更丰富更全面的API可以参考 AudioManager官方文档

代码

获取AudioManager实例

要使用AudioManager类,首先需要获取一个AudioManager实例。可以通过以下代码来获取:

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

音量控制

通过AudioManager类,我们可以控制设备的各种音量,包括媒体音量、闹钟音量、通话音量等等。下面是一些常用的方法:

获取当前音量

可以使用getStreamVolume()方法来获取当前音量。下面的代码演示了如何获取媒体音量:

int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
设置音量

可以使用setStreamVolume()方法来设置音量。下面的代码演示了如何将媒体音量设置为最大:

int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, 0);
调整音量

如果希望逐步调整音量,可以使用adjustStreamVolume()方法。下面的代码演示了如何将媒体音量调低一个单位:

audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0);

铃声模式控制

除了音量控制外,AudioManager还允许我们管理设备的铃声模式。以下是一些常用的方法:

获取当前铃声模式

使用getRingerMode()方法可以获取当前的铃声模式。返回值可以是以下之一:RINGER_MODE_NORMAL、RINGER_MODE_SILENT、RINGER_MODE_VIBRATE。

int ringerMode = audioManager.getRingerMode();
设置铃声模式

可以使用setRingerMode()方法来设置铃声模式。以下是一些常用的设置:

  1. RINGER_MODE_NORMAL:设置为正常模式,即响铃和震动都开启。
  2. RINGER_MODE_SILENT:设置为静音模式,即不响铃也不震动。
  3. RINGER_MODE_VIBRATE:设置为震动模式,即不响铃但会震动。
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);

监听音频焦点

在开发中,有时候需要监听音频焦点的变化,比如当其他应用开始播放音频时暂停当前应用的音乐。通过AudioManager类,我们可以实现这样的功能。

请求音频焦点

使用requestAudioFocus()方法可以请求音频焦点,并指定焦点类型、音频焦点变化的回调等参数。下面的代码演示了如何请求音频焦点:

AudioManager.OnAudioFocusChangeListener focusChangeListener = new AudioManager.OnAudioFocusChangeListener(){@Overridepublic void onAudioFocusChange(int focusChange) {// 处理音频焦点变化事件}
};int result = audioManager.requestAudioFocus(focusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
释放音频焦点

当不再需要音频焦点时,可以调用abandonAudioFocus()方法来释放焦点。

audioManager.abandonAudioFocus(focusChangeListener);

监听系统音量控制按键

除了我们手动去改之外,用户也可以通过物理按键或是耳机来控制音量,这时,我们理应也要做出相应的改变,所以,还需要对音量按键做监听才行。

这里就用到熟悉的老方法了,重写ActivityonKeyDown方法:

    /*** 监听并接管系统的音量按键,* 注意:最好保持原有逻辑不变*/override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {when (keyCode) {//音量+按键KeyEvent.KEYCODE_VOLUME_UP -> {return true}//音量-按键KeyEvent.KEYCODE_VOLUME_DOWN -> {return true}}return super.onKeyDown(keyCode, event)}

音频焦点

介绍

两个或两个以上的 Android App可同时向同一输出流(比如手机的蓝牙、手机的喇叭)播放音频,系统会将所有音频流(就是音频数据了)混合在一起。这是一项有意思的技术,但却会出现混音。为了避免所有音乐应用同时播放,Android 引入了“音频焦点”的概念。 音频焦点机制是Android系统提供的一种道德约定,它倡导的东西有三点:
1、 只有一个App持有音频焦点;
2 、播放声音前申请音频焦点,不需要播放的时候释放音频焦点;
3 、失去音频焦点应该暂停播放或者降低音量。
音频焦点是Android系统进程管理的一个值,这个值就记录了当前音频焦点属于哪个应用,类型等。

使用中注意的点:

① 为 requestAudioFocus 方法传入的第3个参数:

  • 如果计划在将来一段时间内播放音频,并且希望前一个持有音频焦点的应用停止播放,则应该请求永久性的音频焦点 (AUDIOFOCUS_GAIN)。
  • 如果只希望在短时间内播放音频,并且希望前一个持有音频焦点的应用暂停播放,则应该请求暂时性的焦点 (AUDIOFOCUS_GAIN_TRANSIENT)。
  • 如果只希望在短时间内播放音频,并允许前一个持有焦点的应用在降低音量的情况下继续播放,则应该请求“降低音量”的暂时性焦点(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) 。这两个音频会混合到音频流中同时输出。

② AudioManager.OnAudioFocusChangeListener回调回来的音频焦点类型,如下:

  • AUDIOFOCUS_GAIN:获取得到音频焦点。
  • AUDIOFOCUS_LOSS:永久性失去音频焦点,后续不会再收到 AUDIOFOCUS_GAIN 回调。应用应立即暂停播放,此时其他应用会播放音频。
  • AUDIOFOCUS_LOSS_TRANSIENT:暂时性失去音频焦点,应用应暂停播放。当抢占焦点的应用放弃焦点时、自己的应用可以收到 AUDIOFOCUS_GAIN 回调。
  • AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暂时性失去音频焦点,应用应降低音量。当抢占焦点的应用放弃焦点时、自己的应用可以收到 AUDIOFOCUS_GAIN 回调。

实现音频焦点的步骤

要实现音频焦点,可以遵循以下步骤:

  • 请求音频焦点

  • 维护音频焦点变更:

    1. AUDIOFOCUS_GAIN:应用程序已经拥有了焦点,可以播放音频并且恢复至最近一次播放的状态。
    2. AUDIOFOCUS_LOSS:失去了焦点,需要停止播放并清理音频资源。
    3. AUDIOFOCUS_LOSS_TRANSIENT:失去焦点,但很快就能返回,并且和AUDIOFOCUS_LOSS的关键区别是不需要释放音频资源,因为等待时间很短。
    4. AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:失去焦点,但可以在音量稍稍降低后继续播放音频。
  • 释放音频焦点

代码

public class MediaPlayerDemo extends Activity implementsOnAudioFocusChangeListener {AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);MediaPlayer mediaPlayer;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}private boolean requestAudioFocus() {int result = audioManager.requestAudioFocus(this,AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {return true;}return false;}private void releaseAudioFocus() {audioManager.abandonAudioFocus(this);}@Overridepublic void onAudioFocusChange(int focusChange) {switch (focusChange) {case AudioManager.AUDIOFOCUS_GAIN:// 恢复音频播放if (mediaPlayer == null) {initMediaPlayer();}else if (!mediaPlayer.isPlaying()) {mediaPlayer.start();}mediaPlayer.setVolume(1.0f, 1.0f);break;case AudioManager.AUDIOFOCUS_LOSS:// 失去音频焦点退出程序if (mediaPlayer.isPlaying()) {mediaPlayer.stop();}mediaPlayer.release();mediaPlayer = null;break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:// 暂时失去焦点,暂停播放等待重新获得音频焦点if (mediaPlayer.isPlaying()) {mediaPlayer.pause();}break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:// 暂时失去焦点,音量减小,等待重新获得音频焦点if (mediaPlayer.isPlaying()) {mediaPlayer.setVolume(0.1f, 0.1f);}break;}}
}

其中,requestAudioFocus()方法请求音频焦点,releaseAudioFocus()方法释放音频焦点。onAudioFocusChange()方法响应音频焦点的状态变化。

焦点类型AUDIOFOCUS_GAIN_TRANSIENT表示当一段时间内需要持有音频焦点。例如,一些短暂的提示音效在它们播放期间重新获取音频焦点会更好。相对于AUDIOFOCUS_GAIN,AUDIOFOCUS_GAIN_TRANSIENT可以更快地响应其他应用程序的请求。

焦点类型AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK表示音频源可能在持有焦点播放时更小地响应。例如,当正在播放音乐的应用程序收到来自其他应用程序的通知时,音量将自动减小。

注意

大多数情况下,按照上述流程使用音频焦点是没有问题的。但线上有部分用户反馈无法使用语音唤醒功能(即无法通过语音来和应用交互),经过排查,发现有如下可优化的地方:

  • 问题1:不是所有应用都会将音频焦点释放,有的应用也会不释放,比如手机系统的录音机。这看似违背最上面说的音频焦点管理规则,但录音机是有它特殊性的,不管它位于前台还是后台,都应该拥有录音的功能。这就会导致只要不杀死录音机应用进程,它就会一直占用音频焦点,导致其他应用无法使用音频焦点。或者是其他应用把原本属于本应用的音频焦点抢占了,也会导致本应用无法使用音频焦点,比如某些应用内的语音通话功能就会抢占音频焦点。

    处理策略:当AudioManager.OnAudioFocusChangeListener监听器监听到音频焦点已失去时(AUDIOFOCUS_LOSS、AUDIOFOCUS_LOSS_TRANSIENT),就主动通过弹窗或toast提示用户【关闭其他应用或重启手机】,以期望达到让其他应用释放音频焦点的目的。

  • 问题2:正常来说,当B应用把音频焦点释放后,A应用是可以重新获取到音频焦点的回调(AUDIOFOCUS_GAIN),但某些Android手机可能会有系统bug,即不会主动通知A应用音频焦点已经回来了,A应用无法拿到AUDIOFOCUS_GAIN这个回调,A应用也就无法再恢复播放音频。

    处理策略:增加音频功能的调用时机。比如在切页或者做其他操作的时候,主动尝试使用语音唤醒的音频功能,而不是通过AudioManager.OnAudioFocusChangeListener监听器被动地等待回调。当主动尝试使用语音唤醒成功时,说明音频焦点已经回来了。

26版本之上

请求焦点

mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE).setOnAudioFocusChangeListener(focusChangeListener).setAudioAttributes(new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build()).setFocusGain(AudioManager.AUDIOFOCUS_GAIN).setForceDucking(true).setWillPauseWhenDucked(true)//可以设置其他的参数及listener.build();
mAudioManager.requestAudioFocus(mAudioFocusRequest);

放弃焦点

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
}

参考

android audiomanager

Android音频管理之AudioManager

Android 修改系统音量及监听

音频焦点

音频焦点九问

提高应用交互体验:Android音频焦点如何调整

浅析Android音频焦点

这篇关于Android AudioManager的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/672287

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk