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


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

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

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

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

  isMusicActive()  

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

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

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

  public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)  

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

    /** 
     * A failed focus change request. 
     */  
    public static final int AUDIOFOCUS_REQUEST_FAILED = 0;  
    /** 
     * A successful focus change request. 
     */  
    public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;  

Managing Audio Focus

管理音頻焦點

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

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

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

public class MainService extends Service {
    private static final String TAG = "MainService";

    private MediaPlayer player;

    private AudioManager mAm;

    private MyOnAudioFocusChangeListener mListener;

    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate");

        player = MediaPlayer.create(this, R.raw.test); // 在res目錄下新建raw目錄,復制一個test.mp3文件到此目錄下。
        player.setLooping(false);

        mAm = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
        mListener = new MyOnAudioFocusChangeListener();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onStart(Intent intent, int startid) {
        Toast.makeText(this, "My Service Start", Toast.LENGTH_LONG).show();
        Log.i(TAG, "onStart");

        // Request audio focus for playback
        int result = mAm.requestAudioFocus(mListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            Log.i(TAG, "requestAudioFocus successfully.");

            // Start playback.
            player.start();
        } else {
            Log.e(TAG, "requestAudioFocus failed.");
        }
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "My Service Stoped", Toast.LENGTH_LONG).show();
        Log.i(TAG, "onDestroy");
        player.stop();

        mAm.abandonAudioFocus(mListener);
    }

    private class MyOnAudioFocusChangeListener implements OnAudioFocusChangeListener {
        @Override
        public void onAudioFocusChange(int focusChange) {
            Log.i(TAG, "focusChange=" + focusChange);
        }
    }
}

 

和 天天動聽 結合起來測試,先打開天天動聽播放音樂,再啟動這個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通知,這樣更准確一些;
這樣,基本上就可以實現我們想要的場景了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM