热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于微信、QQ语音消息,语音电话的时候控制应用音频播放以及暂停

最近项目中有这样的需求,要求在用户使用QQ或微信在录制或播放语音消息的时候可以自动暂停后台的音频播放,完毕后可以恢复播放。Android是多任务系统,Audio系统是竞争资源,Andr

最近项目中有这样的需求,要求在用户使用QQ或微信在录制或播放语音消息的时候可以自动暂停后台的音频播放,完毕后可以恢复播放。

Android是多任务系统,Audio系统是竞争资源,Android2.2之前,没有内建的机制来解决多个程序竞争Audio的问题,2.2引入了称作AudioFocus的机制来管理对Audio资源的竞争的管理与协调。
未解决以上问题,可以使用AudioFocus的机制,即是在使用AudioStream之前,需要申请AudioFocus,在获得AudioFocus之后才可以使用相应的AudioStream;如果有别的程序竞争你正在使用的AudioStream,你的程序需要在收到通知之后做停止播放或者降低声音的处理。

在项目中播放音频一般都是在service中处理播放的逻辑,直接在onCreate中请求AudioFocus,监听播放状态

@Override
public void onCreate() {
audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
mListener = new MyOnAudioFocusChangeListener();
// 请求AudioFocus,注册监听
int result = audioManager.requestAudioFocus(mListener,
AudioManager.STREAM_MUSIC,
AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
//能打印出这句话标识已监听成功
Log.e("MyOnAudioFocus", "requestAudioFocus successfully.");
} else {
Log.e("MyOnAudioFocus", "requestAudioFocus failed.");
}
...此处省略其他代码
}
@Override
public void onDestory(){
...此处省略其他代码
//不再监听
audioManager.abandonAudioFocus(mListener);
}

具体的对监听的结果进行相应的处理,只需要实现相应的类即可,监听的状态有如下四种

  • AUDIOFOCUS_GAIN:当前应用获得了Audio Focus;
  • AUDIOFOCUS_LOSS:当前应用失去了Audio Focus,并将会持续很长的时间。这里因为可能会停掉很长时间,所以不仅仅要停止Audio的播放,最好直接释放掉Media资源。而因为停止播放Audio的时间会很长,如果程序因为这个原因而失去AudioFocus,最好不要让它再次自动获得AudioFocus而继续播放,不然突然冒出来的声音会让用户感觉莫名其妙,感受很不好。这里直接放弃AudioFocus,当然也不用再侦听远程播放控制【如下面代码的处理】。要再次播放,除非用户再在界面上点击开始播放,才重新初始化Media,进行播放。
  • AUDIOFOCUS_LOSS_TRANSIENT:当前应用暂时失去Audio Focus,并会很快再次获得。必须停止Audio的播放,但是因为可能会很快再次获得AudioFocus,这里可以不释放Media资源;
  • AUDIO重点内容FOCUS_LOSS_TRANSIENT_CAN_DUCK:当前应用暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。

在项目中我对 AUDIOFOCUS_LOSS_TRANSIENT AUDIOFOCUS_LOSS_TRANSIENT这两种情况作了相同的处理,都是进行了播放的暂停。isUserPauseAudio这是一个我自己定义的标志位,用来记录是否是用户手动的暂停音乐的播放,如果是用户手动的暂停音乐的播放,那么即使获取到了AudioFocus也不会进行相应的操作,这一点很重要。

private class MyOnAudioFocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
@Override
public void onAudioFocusChange(int focusChange) {
//监听系统播放状态的改变
//Log.e("MyOnAudioFocus", "focusChange=" + focusChange);
//暂时失去AudioFocus,可以很快再次获取AudioFocus,可以不释放播放资源
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT ||
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
if (AudioPlayerService.status == Status.PLAY || AudioPlayerService.status == Status.LOADING) {
//暂时失去AudioFocus,可以很快再次获取AudioFocus,可以不释放播放资源,只需暂停播放
PlayerController.pausePlay();
}
} else if (focusChange == AUDIOFOCUS_GAIN) {
//获取了AudioFocus,如果当前处于播放暂停状态,并且这个暂停状态不是用户手动点击的暂停,才会继续播放
if (AudioPlayerService.status == Status.PAUSE && !Constant.isUserPauseAudio) {
PlayerController.continuePlay();
}
} else if (focusChange == AUDIOFOCUS_LOSS) {
// 会长时间的失去AudioFoucs,就不在监听远程播放
if (AudioPlayerService.this!=null){
PlayerController.stopService(AudioPlayerService.this);
audioManager.abandonAudioFocus(mListener);//不再监听播放焦点的变化
}
}
}
}

最后分析一下QQ微信语音消息以及拨打语音电话的时候AudioFocus的变化情况,以及相应的处理方式。

操作 状态 处理方式
录制语音消息/播放语音消息 AUDIOFOCUS_LOSS_TRANSIENT 暂停播放,录制/播放结束后,会重新获取AudioFocus,继续播放
被动接收QQ/微信电话 AUDIOFOCUS_LOSS_TRANSIENT 同上
主动拨打QQ/微信电话 & 使用第三方的播放器听歌(酷狗、QQ音乐等) AUDIOFOCUS_LOSS 停止播放,拨打电话后,不能再获取到焦点,不再继续播放

好了,就此解决了这个问题,分享给大家。
第一次用MarkDown写文章,还有点不适应啊。。。。


推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • publicvoidchooseVideo(Viewview){IntentintentnewIntent();*开启Pictur ... [详细]
  • WPF之Binding初探
      初学wpf,经常被Binding搞晕,以下记录写Binding的基础。首先,盗用张图。这图形象的说明了Binding的机理。对于Binding,意思是数据绑定,基本用法是:1、 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了10分钟了解Android的事件分发相关的知识,希望对你有一定的参考价值。什么是事件分发?大家 ... [详细]
  • Thisissuewasoriginallyopenedbyashashicorp/terraform#5664.Itwasmigratedhe ... [详细]
  • 移动–镜像y轴的视频文件剪辑原文:https://www. ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
author-avatar
gunnerliang_851
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有