文档章节

Android文档学习09_多媒体2

larryee
 larryee
发布于 2015/01/14 21:35
字数 1337
阅读 3
收藏 0

在开始播放音频之前,App必须先获取需要处理的音频流的音频焦点,通过requestAudioFocus()方法,成功则返回AUDIOFOCUS_REQUEST_GRANTED常量,失败则返回AUDIOFOCUS_REQUEST_FAILED常量


短暂的音频焦点用于处理播放短时间的音频(例如汽车导航仪的提示)。如果您想长时间播放音频(例如播放音乐),那么就需要请求长期的音频焦点。


获得音频焦点的请求应该在马上就要播放音频前发出,比如在用户按下播放键或下一关游戏的背景音乐就要开始时发出焦点请求,接着再播放音乐。

下面是获得长期焦点的相关代码:

AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
 
//请求播放的音频焦点
int result = am.requestAudioFocus(afChangeListener,
                                 // 指定所使用的音频流
                                 AudioManager.STREAM_MUSIC,
                                 // 请求长时间的音频焦点
                                 AudioManager.AUDIOFOCUS_GAIN);
 
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
    // 开始播放
}
 

当完成音频播放后,请一定记得调用abandonAudioFocus()方法,这会通知系统您的App不再需要音频焦点,并移除相关OnAudioFocusChangeListener的注册。如果释放的是短暂音调焦点,那么被打断的音频会被继续播放。


// 当播放结束,您需要释放音频焦点    
am.abandonAudioFocus(afChangeListener);


当请求短暂音频焦点时,您可以添加有一额外的选择——是否使用“浮动声音(英文为“ducking”,这里是指降低原音频流播放的音量,并使获得短暂音频焦点的音频流音量较大,而不去停止原来音频流的播放)”方式。

通常来说,一个好的音频播放App会在失去音频焦点时立即停止播放。但如果在请求短暂音频焦点时使用“浮动声音”方式,可以允许先前的App以较低的音量继续播放,在重新获得音频焦点后再以原来的音量播放。


// 请求播放的音频焦点
int result = am.requestAudioFocus(afChangeListener,
                             // 指定所使用的音频流
                             AudioManager.STREAM_MUSIC,
                             // 请求短暂焦点
 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
 
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // 开始播放
}

浮动音频非常适合间断播放音频的App,例如导航仪的提示


注册的监听器可以判断是否获得到了长期或短暂(可以选择浮动音频方式)的音频焦点。


App请求并得到音频焦点后,当其他App请求得到焦点时,先前的App就会失去焦点


onAudioFocusChange(int)回调函数


失去音频焦点的事件类型与请求焦点的类型相对应——失去长期焦点(AUDIOFOCUS_LOSS)、短暂焦点(AUDIOFOCUS_LOSS_TRANSIENT)和浮动音频方式的短暂焦点(AUDIOFOCUS_LOSS_TRANSIENT)。


一般情况下,

App在失去短暂音频焦点时,应该停止播放并记录下播放状态。但仍然需要监听音频焦点的变化,当重新获得音频焦点时,需要在从先前暂停的地方继续播放。

如果失去的是长期音频焦点,那就是说其他App需要使用当前音频流,而您的App需要尽快结束。实际上,意味着您的App需要停止播放,移除媒体键监听器并释放音频焦点——这将允许新的音频播放器独占地持有音频焦点等

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
            // 暂停播放
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // 恢复播放
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
            am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
            am.abandonAudioFocus(afChangeListener);
            // 停止播放
        }
    }
};

如果失去的是短暂且允许使用浮动播放(duck)的音频焦点,相比暂停播放,更好的做法应该是使用“浮动播放”的方式。


浮动播放(Duck)

浮动播放会将您正使用的音频流输出音量降低,这会使其他App的短暂音频更容易听到,如此一来您的App就不用被完全打断了。

下面的代码会使App在暂时失去焦点时降低媒体播放器的音量,并在重新获得音频焦点时恢复到原来的音量大小。


OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
            // 降低音量
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // 恢复至正常音量
        }
    }
};


大多数设备有一个内置扬声器,有线耳机的耳机插孔,不少还配备了蓝牙连接,支持A2DP的音频。


可以通过以下代码片段来查询AudioManager来确定的音频路由是否被发送到扬声器,有线耳机或连接的蓝牙设备:

if (isBluetoothA2dpOn()) {
    // Adjust output for Bluetooth.
} else if (isSpeakerphoneOn()) {
    // Adjust output for Speakerphone.
} else if (isWiredHeadsetOn()) {
    // Adjust output for headsets
} else { 
    // If audio plays and noone can hear it, is it still playing?
}

当耳机被拔掉,或蓝牙设备断开连接,音频流将会自动重新路由到内置的扬声器。如果你正用很高的音量听歌,那将会是一个嘈杂的“惊喜”。

幸运的是,当这一切发生的时候,系统会广播ACTION_AUDIO_BECOMING_NOISY意图。当你正播放音频时,注册BroadcastReceiver,并监听这个意图是很好的做法。在音乐播放器案例中,用户通常期望要暂停播放,而在游戏中,你可以选择大大地降低音量。


private class NoisyAudioStreamReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
            // Pause the playback
        }
    }
}
 
private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
 
private void startPlayback() {
    registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}
 
private void stopPlayback() {
    unregisterReceiver(myNoisyAudioStreamReceiver);
}






















本文转载自:http://blog.csdn.net/u012992171/article/details/17321197

larryee
粉丝 0
博文 51
码字总数 393
作品 0
浦东
私信 提问
android系统底层到应用层全方位剖析

共12个pdf文档打包分享,大小 4.8M 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android...

无鸯
2011/09/05
11.3K
23
我把简历贴出来,各位大神看看哪里不好的地方,很想开始工作

姓 名 性 别 男 民 族 汉 族 籍 贯 学 历 大专 出生日期 1990 专 业 计算机技术及应用 就读院校 广州铁路职业技术学院 联系电话 13794340872 邮箱 chinamingke@163.com 主修课程: Office、j...

ckc
2013/04/09
6.1K
73
Android特色开发之语音识别

本文节选于机械工业出版社推出的《Android应用开发揭秘》一书,作者为杨丰盛。本书内容全面,详细讲解了Android框架、Android组件、用户界面开发、游戏开发、数据存储、多媒体开发和网络开发...

yarin
2018/06/26
0
0
【猎头招聘】Android技术经理(年薪20-30万)

大型网游公司诚聘 Android技术经理 年薪20-30万 岗位职责: 1、 独立(或带领项目团队)完成基于android手机平台项目的需求的收集分析、设计、框架搭建、开发与实施部署; 2、 能按照项目计划...

madan
2011/11/21
2.1K
16
推荐一本android学习图书《Android应用程序开发与典型案例》完整版PDF下载

《android应用程序开发与典型案例》图书简介: 共23章,内容包含两大部分。第一部分是android程序设计 基础,在介绍android环境搭建以及android系统基本控件和组件后,详细介绍了android系统...

华清远见2014
2014/09/23
1K
8

没有更多内容

加载失败,请刷新页面

加载更多

Netty整合Protobuffer

现在我们都知道,rpc的三要素:IO模型,线程模型,然后就是数据交互模型,即我们说的序列化和反序列化,现在我们来看一下压缩比率最大的二进制序列化方式——Protobuffer,而且该方式是可以跨...

算法之名
29分钟前
16
0
如何用C++实现栈

栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压...

BWH_Steven
48分钟前
5
0
编程作业20190210900169

1编写一个程序,提示用户输入名和姓,然后以“名,姓”的格式打印出来。 #include <stdio.h>#include <stdlib.h> int main(){ char firstName[20]; char lastName[20]; print......

1李嘉焘1
今天
12
0
补码的优点及原理分析

只讨论整数 1.计算机内部为什么没有减法器? 减法运算本身其实就是加法,如x - y即x +(-y),所以只需要将负数成功表示出来并可以参加加法运算,那加法器就可同时实现“+”和“-”的运算。这...

清自以敬
今天
76
0
Docker 可视化管理 portainer

官网安装指南: https://portainer.readthedocs.io/en/latest/deployment.html docker-compose.yml 位置,下载地址:https://downloads.portainer.io/docker-compose.yml...

Moks角木
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部