Android Audio控制和MediaButton遠程控制(音視頻控制配合)

  使用過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的廣播,手動發送了MEDIA_BUTTON廣播,而且指定了目標對象(棧頂對象)去處理該MEDIA_BUTTON 。

  上面的兩條規則,你們必定要記住,這個關係咱們註冊的ACTION_MEDIA_BUTTON可否正常工做。固然這個是系統全局廣播,須要你們的APP都遵照這個規則纔可讓系統正常運行。

 

 

 

Edited by mythou

原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3302347.html 

相關文章
相關標籤/搜索