Android如何判斷當前手機是否正在播放音樂,並獲取到正在播放的音樂的信息

我想實現如下的場景,判斷當前Android手機上是否正在播放音樂,如果是,通過某個特定的手勢,

或者點擊某個按鍵,將當前我正在聽的音樂共享出去。

第一步,就是判斷當前是否有音樂正在播放。

最開始我想得有點複雜,以爲要深入framework或更下層去做手腳才行,找了一下資料,發現AudioManager對外暴露了接口。

  1. /** Checks whether any music is active. */  
  2. isMusicActive()  

通過這個接口就可以判斷當前系統是否有音樂在播放了。

 

還有一個問題,如果我想在音樂一開始就已經播放的時候,就知道這個事件,以便進行特殊的處理。

再進一步看一下 AudioManager 的源碼,發現其中有如下方法:

  1.     /** 
  2.      *  Request audio focus. 
  3.      *  Send a request to obtain the audio focus 
  4.      *  @param l the listener to be notified of audio focus changes 
  5.      *  @param streamType the main audio stream type affected by the focus request 
  6.      *  @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 
  7.      *      is temporary, and focus will be abandonned shortly. Examples of transient requests are 
  8.      *      for the playback of driving directions, or notifications sounds. 
  9.      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 
  10.      *      the previous focus owner to keep playing if it ducks its audio output. 
  11.      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 
  12.      *      as the playback of a song or a video. 
  13.      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 
  14.      */  
  15.     public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)  

 

從字面意思來看:請求音頻焦點,再看這個函數的返回值:

  1.     /** 
  2.      * A failed focus change request. 
  3.      */  
  4.     public static final int AUDIOFOCUS_REQUEST_FAILED = 0;  
  5.   
  6.   
  7.     /** 
  8.      * A successful focus change request. 
  9.      */  
  10.     public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;  


這個函數可能對我有幫助,進一步查一下Google官方的幫助:http://developer.android.com/training/managing-audio/audio-focus.html

Managing Audio Focus

With multiple apps potentially playing audio it's important to think about how they should interact. To avoid every music app playing at the same time, Android uses audio focus to moderate audio playback—only apps that hold the audio focus should play audio.

Before your app starts playing audio it should request—and receive—the audio focus.  Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that happens.

 

簡單地翻譯一下:

管理音頻焦點

多個應用都在播放音頻的可能性,所以考慮應用間如何交互非常重要。爲避免每個音樂應用同時播放,Android使用音頻焦點來協調音頻的播放----只有獲取到音頻焦點的應用可以播放音頻。

在你的應用開始播放音頻之前,它應該先請求--並接收音頻焦點。同樣,它也應該知道當監聽到失去音頻焦點後如何合理地進行響應。

 

沿着這個路應該是對的,寫了下面的測試代碼進行驗證。這個主要是Service的實現,你還需要實現一個Activity去啓動Service、結束Service:

  1. package com.example.servicetest;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.media.AudioManager;  
  7. import android.media.AudioManager.OnAudioFocusChangeListener;  
  8. import android.media.MediaPlayer;  
  9. import android.os.IBinder;  
  10. import android.util.Log;  
  11. import android.widget.Toast;  
  12.   
  13. public class MainService extends Service  
  14. {  
  15.     private static final String TAG = "MainService";  
  16.       
  17.     private MediaPlayer player;  
  18.       
  19.     private AudioManager mAm;  
  20.       
  21.     private MyOnAudioFocusChangeListener mListener;  
  22.   
  23.       
  24.     @Override  
  25.     public void onCreate()  
  26.     {  
  27.         Log.i(TAG, "onCreate");  
  28.           
  29.         player = MediaPlayer.create(this, R.raw.test);  // 在res目錄下新建raw目錄,複製一個test.mp3文件到此目錄下。  
  30.         player.setLooping(false);  
  31.           
  32.         mAm = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);  
  33.         mListener = new MyOnAudioFocusChangeListener();  
  34.     }  
  35.       
  36.   
  37.     @Override  
  38.     public IBinder onBind(Intent intent)  
  39.     {  
  40.         return null;  
  41.     }  
  42.       
  43.   
  44.     @Override  
  45.     public void onStart(Intent intent, int startid)  
  46.     {  
  47.         Toast.makeText(this"My Service Start", Toast.LENGTH_LONG).show();  
  48.         Log.i(TAG, "onStart");  
  49.           
  50.         // Request audio focus for playback  
  51.         int result = mAm.requestAudioFocus(mListener,  
  52.                 AudioManager.STREAM_MUSIC,  
  53.                 AudioManager.AUDIOFOCUS_GAIN);  
  54.           
  55.         if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)  
  56.         {  
  57.             Log.i(TAG, "requestAudioFocus successfully.");  
  58.               
  59.             // Start playback.  
  60.             player.start();  
  61.         }  
  62.         else  
  63.         {  
  64.             Log.e(TAG, "requestAudioFocus failed.");  
  65.         }  
  66.     }  
  67.       
  68.   
  69.     @Override  
  70.     public void onDestroy()  
  71.     {  
  72.         Toast.makeText(this"My Service Stoped", Toast.LENGTH_LONG).show();  
  73.         Log.i(TAG, "onDestroy");  
  74.         player.stop();  
  75.           
  76.         mAm.abandonAudioFocus(mListener);  
  77.     }  
  78.       
  79.   
  80.     private class MyOnAudioFocusChangeListener implements  
  81.             OnAudioFocusChangeListener  
  82.     {  
  83.         @Override  
  84.         public void onAudioFocusChange(int focusChange)  
  85.         {  
  86.             Log.i(TAG, "focusChange=" + focusChange);  
  87.         }  
  88.     }  
  89. }  

 

和 天天動聽 結合起來測試,先打開天天動聽播放音樂,再啓動這個Service,發現天天動聽自動暫停,再停止這個Service,天天動聽又開始播放了。

反過來,我先啓動這個Service,再播放、暫停天天動聽,“Log.i(TAG, "focusChange=" + focusChange);” 這個確實有輸出日誌。

 

主流的音樂播放器,都遵循此規則的,所以通過使用Android的這個機制,我們就可以監控音樂的播放了。

 

還有一個問題,如何知道當前播放的音樂信息呢?兩個思路:

1、通過在後臺自動截取音頻流的輸出,通過服務器進行聽歌識曲;

2、通過在SystemUI中攔截主流音樂播放器的通知;

 

第1個思路,從原理上是可行的,但是實現起來難度比較大,而且嚴重依賴網絡;

還是先來分析一下第2個思路。

先找主流的Android音樂播放器來做個簡單地測試,比如:天天動聽、QQ音樂、酷狗音樂、酷我音樂、百度音樂等,在播放過程中,都會向狀態欄中發一個Notification消息,其中已經包含歌曲信息。那我只需要做一個特殊的攔截並進行包名匹配,就可以獲取正在播放的音樂了。


具體思路如下:

1、實現一個服務,這個服務在Android手機啓動時,自動運行起來,通過 AudioManager.requestAudioFocus() 獲取音頻焦點,但什麼事都不幹,只爲有其它音樂播放器開始運行時,得到一個通知消息;

2、修改SystemUI,當主流音樂播放器發Notification到狀態欄時,從中獲取到音樂信息;

3、步驟1的Listener就可以集成到SystemUI中,這樣當音樂焦點被其它音樂播放器搶走後,再結合最近收到的Notification通知,這樣更準確一些;


這樣,基本上就可以實現我們想要的場景了。

發佈了3 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章