[RK3288][Android6.0] 按键(MediaButton)控制音乐播放功能
2017-08-23 17:52
573 查看
Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
在看music后台自动播放的问题时因为对这块不了解,以为开机默认打印的这条log会有关系
事实上,这是和MediaButton有关系。
通俗一点讲,就是在你插了耳机,如果有些上面有按键,当你按下之后,系统就会调用music来播放音乐,此功能正是通过MediaButtonIntentReceiver来接收然后处理播放/暂停/下一曲等功能的。
packages/apps/Music/AndroidManifest.xml
接收”android.intent.action.MEDIA_BUTTON” 和 “android.media.AUDIO_BECOMING_NOISY”两种Action.
前者处理按键事件, 后者处理比如耳机插拔等事件(比如收到事件后停止播放)。具体说明如下:
Intent.java
AudioManager.java
老版本的处理:
系统的处理行为是: 哪个应用注册得晚,就使用哪个应用来播放。
原理是: 系统通过一个堆栈来保存当前所有注册的MediaButttonReceiver, 按照先进后出的原则,最后一个注册的Receviver将会被放在栈顶,
如果已经注册过了,那么先删除,再放在栈顶。
上面这部分功能是在AudioService中实现的。
新版本处理:
用MediaSession进行保存,当有按键事件发生时,通过判断当前应用是否正在播放以及优先级来决定发送给哪个应用程序。
注册过程:
registerMediaButtonEventReceiver -> registerMediaButtonIntent -> helper.addMediaButtonListener ->
MediaButtonListener -> holder.mSession.setMediaButtonReceiver
系统收到事件后的处理:
sendMediaButtonEvent -> mSessionManager.dispatchMediaKeyEvent -> dispatchMediaKeyEvent(MediaSessionManager.java)
audio系列之MediaButton–基于Android7.0
Android中MediaButtonReceiver广播监听器的机制分析
Add Headset button support to your Android application
Android耳机Hook键功能
OS: Android 6.0
Kernel: 3.10.92
在看music后台自动播放的问题时因为对这块不了解,以为开机默认打印的这条log会有关系
ActivityManager: Start proc 978:com.android.music/u0a29 for broadcast com.android.music/.MediaButtonIntentReceiver
事实上,这是和MediaButton有关系。
通俗一点讲,就是在你插了耳机,如果有些上面有按键,当你按下之后,系统就会调用music来播放音乐,此功能正是通过MediaButtonIntentReceiver来接收然后处理播放/暂停/下一曲等功能的。
定义:
本质上它也是一个Broadcast Receiver,在xml有静态定义:packages/apps/Music/AndroidManifest.xml
<receiver android:name="com.android.music.MediaButtonIntentReceiver"> <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.media.AUDIO_BECOMING_NOISY" /> </intent-filter> </receiver>
接收”android.intent.action.MEDIA_BUTTON” 和 “android.media.AUDIO_BECOMING_NOISY”两种Action.
前者处理按键事件, 后者处理比如耳机插拔等事件(比如收到事件后停止播放)。具体说明如下:
Intent.java
/** * Broadcast Action: The "Media Button" was pressed. Includes a single * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that * caused the broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
AudioManager.java
/** * Broadcast intent, a hint for applications that audio is about to become * 'noisy' due to a change in audio outputs. For example, this intent may * be sent when a wired headset is unplugged, or when an A2DP audio * sink is disconnected, and the audio system is about to automatically * switch audio route to the speaker. Applications that are controlling * audio streams may consider pausing, reducing volume or some other action * on receipt of this intent so as not to surprise the user with audio * from the speaker. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
注册:
packages/apps/Music/src/com/android/music/MediaPlaybackService.javapublic void onCreate() { //MediaButton类的注册都要通过AudioManager实现和管理 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); ComponentName rec = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName()); //注册接口 mAudioManager.registerMediaButtonEventReceiver(rec); }
事件处理:
packages/apps/Music/src/com/android/music/MediaButtonIntentReceiver.javapublic class MediaButtonIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); //插拔等处理 if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) { Intent i = new Intent(context, MediaPlaybackService.class); i.setAction(MediaPlaybackService.SERVICECMD); i.putExtra(MediaPlaybackService.CMDNAME, MediaPlaybackService.CMDPAUSE); context.startService(i); //按键处理 } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { ...... if (command != null) { //按下处理 if (action == KeyEvent.ACTION_DOWN) { if (mDown) { if ((MediaPlaybackService.CMDTOGGLEPAUSE.equals(command) || MediaPlaybackService.CMDPLAY.equals(command)) && mLastClickTime != 0 && eventtime - mLastClickTime > LONG_PRESS_DELAY) { mHandler.sendMessage( mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context)); } } else if (event.getRepeatCount() == 0) { ...... } if (isOrderedBroadcast()) { abortBroadcast(); } } } } }
优先处理原则:
每个应用程序都可以注册MediaButton这种Receiver,比如当前有酷狗和系统自带音乐播放器,当按键按下的时候应该调用哪个来播放呢?老版本的处理:
系统的处理行为是: 哪个应用注册得晚,就使用哪个应用来播放。
原理是: 系统通过一个堆栈来保存当前所有注册的MediaButttonReceiver, 按照先进后出的原则,最后一个注册的Receviver将会被放在栈顶,
如果已经注册过了,那么先删除,再放在栈顶。
上面这部分功能是在AudioService中实现的。
新版本处理:
用MediaSession进行保存,当有按键事件发生时,通过判断当前应用是否正在播放以及优先级来决定发送给哪个应用程序。
注册过程:
registerMediaButtonEventReceiver -> registerMediaButtonIntent -> helper.addMediaButtonListener ->
MediaButtonListener -> holder.mSession.setMediaButtonReceiver
系统收到事件后的处理:
sendMediaButtonEvent -> mSessionManager.dispatchMediaKeyEvent -> dispatchMediaKeyEvent(MediaSessionManager.java)
参考:
Android中通过耳机按键控制音乐播放的实现audio系列之MediaButton–基于Android7.0
Android中MediaButtonReceiver广播监听器的机制分析
Add Headset button support to your Android application
Android耳机Hook键功能
相关文章推荐
- [RK3288][Android6.0] 调试笔记 --- 查看音乐播放对应的进程名
- [RK3288][Android6.0] 调试笔记 --- 关闭音频播放停止后进入Standby功能
- [RK3288][Android6.0] 调试笔记 --- 命令行播放音乐方法
- [RK3288][Android6.0] 调试笔记 --- 开机动画支持播放mp4视频功能
- [RK3288][Android6.0] 开机播放音乐流程小结
- [RK3288][Android6.0] GPU DVFS控制策略小结
- [RK3288][Android6.0] 调试笔记 --- RT5640播放时的Codec寄存器列表
- [RK3288][Android6.0] 调试笔记 --- 播放搜狐视频会Crash问题
- [RK3288][Android6.0] WiFi之Passpoint功能了解
- [RK3288][Android6.0] WiFi之PNO功能了解
- [RK3288][Android6.0] 开发者选项中的Strict mode功能
- [RK3288][Android6.0] Audio播放时的pcm数据dump思路
- [RK3288][Android6.0] 调试笔记 --- CPU温度降频控制
- Android中通过耳机按键控制音乐播放的实现
- [RK3288][Android6.0] 调试笔记 --- 关闭按键音后无法录音问题
- [RK3288][Android6.0] 调试笔记 --- 开机视频无法播放
- 简单的Android音乐播放,解决incall类型不能通过音量按键控制声音大小的问题
- [RK3288][Android6.0] DDR Frequency控制流程小结
- [RK3288][Android6.0] 调试笔记 --- 通用GPIO驱动控制LED
- [RK3288][Android6.0] 调试笔记 --- 移除锁屏功能