使用过Android系统的朋友应该都知道,Android里面声音是区分好几种状况,每种状况下的音频大小是独立的。也就是说你调节了电话铃声大小不会影响多媒体播放的声音大小。这个涉及了AudioStream的使用,今天会详细讲解一下AudioStream相关知识。另外咱们用耳机上按钮控制音乐播放器等音频程序,可使用MediaButton来实现远程控制。另外会详细讲解MediaButton的两种注册方法以及他们的区别。html
(PS:新建的QQ群,有兴趣能够加入一块儿讨论:Android群:322599434)android
一、AudioStream分类ide
首先看看AudioStream的分类,Android为不一样的应用场合定义了不一样的AudioStream: Voice Call, Ring, Music,Alarm, Notification, DTMF。 这些AudioStream是相互独立的,因此也有各自的音量。AudioStream的定义在android.media.AudioManager中。this
二、AudioStream控制spa
但咱们按下调音量大小的按键,缺省状况下,按下音量控制的硬件控制键Vol+/-,调节的是当前被激活的AudioStream的音量,若是你的程序当前没有正在播听任何声音,按下Vol+/-调节的是来电铃声的音量。在某一个程序运行时,但愿按下Vol+/-调节的是当前所使用的AudioStream的音量,Android在Activity中提供了setVolumeControlStream()方法用来指定你的应用程序使用的Audio Stream类型。因此,若是你的程序用到Audio的播放,你首先要知道你的程序所用的AudioStream类型,并在onCreate()中调用setVolumeControlStream()来设定AudioStream的类型。code
例以下面是音乐播放器打开的时候,设置的AudioStream:视频
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
三、MediaButtonxml
这里说的MediaButton实际上是对应系统的ACTION_MEDIA_BUTTON,ACTION_MEDIA_BUTTON的定义为“android.intent.action.MEDIA_BUTTON”,是系统控制远程音乐和其余多媒体的方法。在手机上常见的应用就是耳机上的控制按钮。通常咱们手机或者平板上的音乐、视频播放器都会响应这个广播。例如Android系统自带的Music工程,里面就响应了这个广播。htm
除了在手机平板这些对音视频控制,其实在智能电视或者对于须要高度整合的系统来讲,这个消息都十分有用。例如:智能电视里面,咱们能够利用这个广播实现远程遥控,系统底层接收遥控播放、暂停、下一曲、上一曲等消息,而后经过ACTION_MEDIA_BUTTON广播给上层应用。高度整合的系统,通常都是针对深度定制的系统,用于特定环境的系统。这种系统对于应用之间的配合要求十分高。例如一些工控的机器。这些系统定制比通常的手机系统要求高不少,这些状况下,ACTION_MEDIA_BUTTON就能够发挥很重要的做用。对象
下面咱们看看怎么使用ACTION_MEDIA_BUTTON这个广播。
//Edited by mythou
//http://www.cnblogs.com/mythou/
public class RemoteControlClientReceiver extends BroadcastReceiver { @SuppressWarnings("unused") private static final String TAG = "mythou_ACTION_MEDIA_BUTTON"; /* * It should be safe to use static variables here once registered via the * AudioManager */ private static long mHeadsetDownTime = 0; private static long mHeadsetUpTime = 0; @Override public void onReceive(Context context, Intent intent) {
//获取对应Acton,判断是不是须要的ACTION_MEDIA_BUTTON String action = intent.getAction();if (action.equalsIgnoreCase(Intent.ACTION_MEDIA_BUTTON)) { KeyEvent event = (KeyEvent) intent .getParcelableExtra(Intent.EXTRA_KEY_EVENT); if (event == null) return; if (event.getKeyCode() != KeyEvent.KEYCODE_HEADSETHOOK && event.getKeyCode() != KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE && event.getAction() != KeyEvent.ACTION_DOWN) return; Intent i = null; switch (event.getKeyCode()) { /* * one click => play/pause long click => previous double click => * next */
//这里根据按下的时间和操做,分离出具体的控制 case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: long time = SystemClock.uptimeMillis(); switch (event.getAction()) { case KeyEvent.ACTION_DOWN: if (event.getRepeatCount() > 0) break; mHeadsetDownTime = time; break; case KeyEvent.ACTION_UP: // long click if (time - mHeadsetDownTime >= 1000) { i = new Intent(AudioService.ACTION_REMOTE_BACKWARD); time = 0; // double click } else if (time - mHeadsetUpTime <= 500) { i = new Intent(AudioService.ACTION_REMOTE_FORWARD); } // one click else { if (mLibVLC.isPlaying()) i = new Intent(AudioService.ACTION_REMOTE_PAUSE); else i = new Intent(AudioService.ACTION_REMOTE_PLAY); } mHeadsetUpTime = time; break; } break;
//下面是常规的播放、暂停、中止、上下曲 case KeyEvent.KEYCODE_MEDIA_PLAY: i = new Intent(AudioService.ACTION_REMOTE_PLAY); break; case KeyEvent.KEYCODE_MEDIA_PAUSE: i = new Intent(AudioService.ACTION_REMOTE_PAUSE); break; case KeyEvent.KEYCODE_MEDIA_STOP: i = new Intent(AudioService.ACTION_REMOTE_STOP); break; case KeyEvent.KEYCODE_MEDIA_NEXT: i = new Intent(AudioService.ACTION_REMOTE_FORWARD); break; case KeyEvent.KEYCODE_MEDIA_PREVIOUS: i = new Intent(AudioService.ACTION_REMOTE_BACKWARD); break; } if (isOrderedBroadcast()) abortBroadcast(); if (i != null) context.sendBroadcast(i); } } }
上面是音乐播放器里面的一个ACTION_MEDIA_BUTTON 的接收器。接收ACTION_MEDIA_BUTTON 跟咱们通常的广播差很少,也是须要定义一个BroadcastReceiver,如何定义BroadcastReceiver这里很少说。
从上面的代码能够看到,咱们能够根据接收的ACTION判断是不是ACTION_MEDIA_BUTTON ,而后获取里面的KeyEvent的值来判断是什么操做。里面包含了常规的媒体控制的值。编写完BroadcastReceiver后,咱们只须要在AndroidManifest.xml注册便可。
//Edited by mythou
//http://www.cnblogs.com/mythou/
<receiver android:name="RemoteControlClientReceiver" > <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON" /> </intent-filter> </receiver>
四、独占MEDIA_BUTTON广播
上面说的注册方法是通常状况下使用,可是ACTION_MEDIA_BUTTON 比较特殊,你能够注册一个ACTION_MEDIA_BUTTON 。只有你一个能接收到,其余人都不能接收。由于这个是控制多媒体的,因此存在一个音视频冲突问题。作过一些系统整合的朋友应该都遇到过这个问题。基本上在我工做里面,我最不想处理的就是音视频冲突,特别在多任务系统里面。
下面咱们说说如何注册一个只有你能接收的ACTION_MEDIA_BUTTON :
//Edited by mythou
//http://www.cnblogs.com/mythou/
//获取音频服务 AudioManager audioManager = (AudioManager) this.getSystemService(AUDIO_SERVICE); //注册接收的Receiver ComponentName mRemoteControlClientReceiverComponent; mRemoteControlClientReceiverComponent = new ComponentName( getPackageName(), RemoteControlClientReceiver.class.getName());
//注册MediaButton audioManager.registerMediaButtonEventReceiver(mRemoteControlClientReceiverComponent);
不须要的时候,只要取消注册便可:
//取消注册
audioManager.unregisterMediaButtonEventReceiver(mRemoteControlClientReceiverComponent);
五、两种注册状况对比
下面说说两种注册ACTION_MEDIA_BUTTON不一样的地方,须要说这个就要讲解一下ACTION_MEDIA_BUTTON的发送机制。这个主要是AudioManager作的事情,AudioManager是上层的一个高层封装的音频管理类,真正实现音频的管理的是IAudioService 实现,这里面涉及了Android的底层核心Binder机制,这个是分析Android系统层必须掌握的课程。今天主要是讲解ACTION_MEDIA_BUTTON,因此我这里不作深刻分析Binder机制和下面的IAudioService ,后面有空我会写一些分析Binder机制的文章。
下面简单说一下ACTION_MEDIA_BUTTON消息是如何广播分发的,让你们使用的时候知道什么时候使用哪一种注册方式。
A、AudioManager或者说AudioService服务端对象内部会利用一个栈来管理全部registerMediaButtonEventReceiver()注册的ComponentName对象,最后调用registerMediaButtonEventReceiver()注册的ComponentName就位置这个栈的栈顶。
B、当系统发送MEDIA_BUTTON,系统MediaButtonBroadcastReceiver 监听到系统广播,它会作以下处理:
上面的两条规则,你们必定要记住,这个关系咱们注册的ACTION_MEDIA_BUTTON可否正常工做。固然这个是系统全局广播,须要你们的APP都遵照这个规则才可让系统正常运行。
Edited by mythou
原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3302347.html