拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Android音频用途管理:AudioAttributes与getUsage详解

1. Android音频用途管理基础在Android音频系统中AudioAttributes是一个核心类它定义了音频流的属性和用途。这个类在API 21(Android 5.0)中被引入用于替代旧的AudioManager中的流类型(STREAM_MUSIC, STREAM_RING等)系统。AudioAttributes.Builder则是用于构建AudioAttributes对象的辅助类。AudioAttributes的主要作用包括定义音频内容的性质如音乐、语音等指定音频的使用场景如媒体播放、闹钟、通知等控制音频的行为如是否可以被其他音频打断影响音频的路由和音量控制提示从Android 8.0开始Google强烈建议开发者使用AudioAttributes而非旧的流类型系统因为前者提供了更精细的控制能力。1.1 AudioAttributes.Builder核心方法AudioAttributes.Builder提供了多个方法来设置音频属性其中最关键的几个方法包括setUsage(int usage)设置音频用途setContentType(int contentType)设置音频内容类型setFlags(int flags)设置音频标志setAllowedCapturePolicy(int capturePolicy)设置音频捕获策略其中setUsage()是最基础也是最重要的方法之一它决定了音频的主要用途和行为特征。2. getUsage()方法详解getUsage()是AudioAttributes.Builder类中的一个方法用于获取当前设置的音频用途值。这个方法返回一个int类型的值对应AudioAttributes类中定义的常量。2.1 音频用途常量定义Android系统预定义了多种音频用途每种用途都有特定的行为表现public static final int USAGE_UNKNOWN 0; public static final int USAGE_MEDIA 1; public static final int USAGE_VOICE_COMMUNICATION 2; public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING 3; public static final int USAGE_ALARM 4; public static final int USAGE_NOTIFICATION 5; public static final int USAGE_NOTIFICATION_RINGTONE 6; public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST 7; public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT 8; public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED 9; public static final int USAGE_NOTIFICATION_EVENT 10; public static final int USAGE_ASSISTANCE_ACCESSIBILITY 11; public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE 12; public static final int USAGE_ASSISTANCE_SONIFICATION 13; public static final int USAGE_GAME 14; public static final int USAGE_ASSISTANT 16;2.2 常见用途场景分析USAGE_MEDIA (1)用于音乐播放、视频播放、游戏音效等媒体内容音量受媒体音量控制示例音乐播放器、视频播放器应用USAGE_VOICE_COMMUNICATION (2)用于语音通话场景系统会优化音频路径以提供清晰的语音质量示例VoIP应用如微信语音通话USAGE_ALARM (4)用于闹钟声音即使设备处于静音模式也会播放示例闹钟应用USAGE_NOTIFICATION (5)用于通知声音音量受通知音量控制示例消息通知提示音注意正确设置音频用途非常重要因为它不仅影响音量控制还会影响音频路由、电源管理和焦点控制等系统行为。3. getUsage()实战应用3.1 基本使用示例下面是一个完整的AudioAttributes构建和使用示例展示getUsage()的典型应用场景// 构建AudioAttributes AudioAttributes.Builder builder new AudioAttributes.Builder(); builder.setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC); AudioAttributes attributes builder.build(); // 获取usage值 int currentUsage builder.getUsage(); // 返回1 (USAGE_MEDIA) // 使用AudioAttributes创建音频播放器 MediaPlayer player new MediaPlayer(); player.setAudioAttributes(attributes);3.2 动态修改音频用途在实际开发中我们可能需要根据场景动态调整音频用途。下面是一个动态切换的例子public void switchToCommunicationMode(MediaPlayer player) { AudioAttributes currentAttributes player.getAudioAttributes(); AudioAttributes.Builder builder new AudioAttributes.Builder(currentAttributes); // 获取当前用途 int oldUsage builder.getUsage(); Log.d(AudioDemo, Current usage: oldUsage); // 修改为语音通信用途 builder.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION); player.setAudioAttributes(builder.build()); // 验证修改 int newUsage builder.getUsage(); Log.d(AudioDemo, New usage: newUsage); }3.3 结合音频焦点使用音频用途经常与音频焦点系统配合使用。下面是一个结合音频焦点管理的示例public void playWithFocus(AudioManager audioManager, MediaPlayer player) { // 构建音频属性 AudioAttributes attrs new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); // 请求音频焦点 int result audioManager.requestAudioFocus( new AudioManager.OnAudioFocusChangeListener() { Override public void onAudioFocusChange(int focusChange) { // 处理焦点变化 } }, attrs, AudioManager.AUDIOFOCUS_GAIN, 0); if (result AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { player.setAudioAttributes(attrs); player.start(); } }4. 高级应用与问题排查4.1 自定义音频路由策略通过getUsage()获取当前音频用途可以实现自定义路由逻辑public void setupAudioRouting(AudioAttributes attributes) { int usage attributes.getUsage(); if (usage AudioAttributes.USAGE_VOICE_COMMUNICATION) { // 语音通话优先使用听筒或蓝牙耳机 audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); audioManager.setSpeakerphoneOn(false); } else if (usage AudioAttributes.USAGE_MEDIA) { // 媒体播放使用扬声器或3.5mm耳机 audioManager.setMode(AudioManager.MODE_NORMAL); } }4.2 常见问题排查音频播放被中断问题检查音频用途是否设置正确不同用途的音频流可能有不同的焦点策略使用getUsage()验证当前设置音量控制不生效问题确保音频用途与预期的音量控制类型匹配USAGE_MEDIA对应媒体音量USAGE_NOTIFICATION对应通知音量低延迟音频实现对于游戏等需要低延迟的场景使用USAGE_GAME结合性能模式标志使用AudioAttributes attrs new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setFlags(AudioAttributes.FLAG_LOW_LATENCY) .build();4.3 兼容性处理不同Android版本对音频用途的支持有所差异需要进行兼容性处理public static AudioAttributes createCompatAudioAttributes() { AudioAttributes.Builder builder new AudioAttributes.Builder(); if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { builder.setUsage(AudioAttributes.USAGE_MEDIA) .setAllowedCapturePolicy(AudioAttributes.ALLOW_CAPTURE_BY_ALL); } else { builder.setUsage(AudioAttributes.USAGE_MEDIA); } return builder.build(); }5. 性能优化与最佳实践5.1 音频用途选择策略精确匹配场景不要总是使用USAGE_MEDIA作为默认值根据实际用途选择最匹配的常量省电考虑后台播放使用USAGE_MEDIA避免在不必要时使用USAGE_ALARM等高优先级用途用户体验优化通知类声音使用USAGE_NOTIFICATION系列常量即时通讯提示使用USAGE_NOTIFICATION_COMMUNICATION_INSTANT5.2 对象重用优化频繁创建AudioAttributes对象会影响性能建议// 应用级别缓存常用配置 public class AudioAttributesCache { private static AudioAttributes mediaAttrs; private static AudioAttributes notificationAttrs; public static AudioAttributes getMediaAttributes() { if (mediaAttrs null) { mediaAttrs new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); } return mediaAttrs; } // 其他预置配置... }5.3 测试验证方法验证音频用途设置是否生效的方法使用getUsage()获取当前值并记录日志测试不同音量键控制的是否是预期音量类型使用Android的音频转储工具检查adb shell dumpsys audio在音频焦点变化时验证行为是否符合预期6. 实际案例分析6.1 音乐播放器实现一个完整的音乐播放器音频属性设置示例public class MusicPlayer { private MediaPlayer mediaPlayer; private AudioManager audioManager; public void initAudio() { // 构建音频属性 AudioAttributes attrs new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED) .build(); // 配置MediaPlayer mediaPlayer new MediaPlayer(); mediaPlayer.setAudioAttributes(attrs); // 设置音频焦点监听 audioManager (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager.requestAudioFocus( focusChange - handleFocusChange(focusChange), attrs, AudioManager.AUDIOFOCUS_GAIN, 0); } private void handleFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: pause(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: pause(); break; case AudioManager.AUDIOFOCUS_GAIN: start(); break; } } }6.2 语音通话应用实现VoIP应用的音频属性特殊设置public class VoipCallManager { public static AudioAttributes getVoipAttributes() { return new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .setFlags(AudioAttributes.FLAG_LOW_LATENCY) .build(); } public void startCall() { AudioManager audioManager (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); AudioAttributes attrs getVoipAttributes(); // 配置音频录制和播放... } }6.3 游戏音效处理游戏音效的特殊处理方式public class GameAudioManager { private SoundPool soundPool; public void init() { AudioAttributes attrs new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setFlags(AudioAttributes.FLAG_LOW_LATENCY) .build(); soundPool new SoundPool.Builder() .setMaxStreams(16) .setAudioAttributes(attrs) .build(); } public void playSound(int soundId) { soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f); } }
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门