android 多媒体播放 MediaSession 框架

概念性简述

MediaSession 框架是 Google 推出专门解决媒体播放时界面和服务通讯问题。这个框架可以让我们不再使用广播来控制播放器,而且也能适配耳机,蓝牙等一些其它设备,实现线控的功能

要理解MediaSession框架,分别看看Media和Session:首先Media是媒体的意思,也就是说这个框架用于音视频媒体;而Session呢,翻译成中文就是会话的意思。一个会话,肯定是涉及两方或以上;在MediaSession框架中,有受控端(一个)和控制端(可以有多个)。接下来为了保证受控端和控制端不串号(想象一个遥控器可以遥控同一型号的多台电视),就有了SessionToken的概念,相当于我们在连接蓝牙设备时的配对码,这样就保证了不串号。在MediaSession框架中,最重要的三个类的概念就这么多,


核心类

  • MediaSessionCompat
  • PlaybackStateCompat
  • MediaMetadataCompat
  • MediaSessionCompat.Callback

初始化配置

    /**
     * 初始化并激活 MediaSession
     */
    private void setupMediaSession() {
//        第二个参数 tag: 这个是用于调试用的,随便填写即可
        mMediaSession = new MediaSessionCompat(context, TAG);
        //指明支持的按键信息类型
        mMediaSession.setFlags(
                MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                        MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
        );
        mMediaSession.setCallback(callback);
        mMediaSession.setActive(true);
    }

指定可以接收的来自锁屏页面的按键信息

    private static final long MEDIA_SESSION_ACTIONS =
            PlaybackStateCompat.ACTION_PLAY
                    | PlaybackStateCompat.ACTION_PAUSE
                    | PlaybackStateCompat.ACTION_PLAY_PAUSE
                    | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
                    | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
                    | PlaybackStateCompat.ACTION_STOP
                    | PlaybackStateCompat.ACTION_SEEK_TO;

5.0之后耳机物理按键的回调监听

   /**
     * API 21 以上 耳机多媒体按钮监听 MediaSessionCompat.Callback
     */
    private MediaSessionCompat.Callback callback = new MediaSessionCompat.Callback() {

//        接收到监听事件,可以有选择的进行重写相关方法

        @Override
        public void onPlay() {
            super.onPlay();
        }

        @Override
        public void onPause() {
            super.onPause();
        }

        @Override
        public void onSkipToNext() {
            super.onSkipToNext();
        }

        @Override
        public void onSkipToPrevious() {
            super.onSkipToPrevious();
        }

        @Override
        public void onStop() {
            super.onStop();
        }

        @Override
        public void onSeekTo(long pos) {
            super.onSeekTo(pos);
        }
    };

配置完成后,播放状态,及音乐信息的更新

    /**
     * 更新播放状态,播放/暂停/拖动进度条时调用
     */
    public void updatePlaybackState() {
        int state = isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED;
        mMediaSession.setPlaybackState(
                new PlaybackStateCompat.Builder()
                        .setActions(MEDIA_SESSION_ACTIONS)
                        .setState(state, getCurrentPosition(), 1)
                        .build());
    }
    /**
     * 更新正在播放的音乐信息,切换歌曲时调用
     */
    public void updateMetaData(String path) {
        if (!StringUtils.isReal(path)) {
            mMediaSession.setMetadata(null);
            return;
        }

        SongInfo info = mediaManager.getSongInfo(context, path);
        MediaMetadataCompat.Builder metaData = new MediaMetadataCompat.Builder()
                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, info.getTitle())
                .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, info.getArtist())
                .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, info.getAlbum())
                .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, info.getArtist())
                .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, info.getDuration())
                .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, getCoverBitmap(info));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            metaData.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getCount());
        }

        mMediaSession.setMetadata(metaData.build());
    }

完整代码

package com.zdd.musicplayer.service;

import android.content.Context;
import android.drm.DrmStore;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.RemoteException;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;

import com.zdd.musicplayer.R;
import com.zdd.musicplayer.aidl.IPlayControl;
import com.zdd.musicplayer.manager.MediaManager;
import com.zdd.musicplayer.modle.SongInfo;
import com.zdd.musicplayer.util.StringUtils;

import java.util.zip.Inflater;

/**
 * Project: MusicPlayer
 * Created by Zdd on 2018/2/2.
 * 

* 耳机线控 *

* Android 5.0中新增了MediaSession类专门解决媒体播放时界面和服务通讯问题,官方说明是 允许与媒体控制器、音量键、媒体按钮和传输控件交互。 * 包含了媒体控制和线控等功能 * 这个框架可以让我们不再使用广播来控制播放器,而且也能适配耳机,蓝牙等一些其它设备,实现线控的功能。 *

* 但是对于低版本上的仍需要自己控制 *

* 参考文章 http://www.jianshu.com/p/bc2f779a5400; */ public class MediaSessionManager { private static final String TAG = "MediaSessionManager"; //指定可以接收的来自锁屏页面的按键信息 private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_SEEK_TO; private final IPlayControl control; private final Context context; private MediaSessionCompat mMediaSession; private final MediaManager mediaManager; public MediaSessionManager(IPlayControl control, Context context) { this.control = control; this.context = context; this.mediaManager = MediaManager.getInstance(); setupMediaSession(); } /** * 初始化并激活 MediaSession */ private void setupMediaSession() { // 第二个参数 tag: 这个是用于调试用的,随便填写即可 mMediaSession = new MediaSessionCompat(context, TAG); //指明支持的按键信息类型 mMediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ); mMediaSession.setCallback(callback); mMediaSession.setActive(true); } /** * 更新播放状态, 播放/暂停/拖动进度条时调用 */ public void updatePlaybackState() { int state = isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED; mMediaSession.setPlaybackState(new PlaybackStateCompat.Builder() .setActions(MEDIA_SESSION_ACTIONS) .setState(state, getCurrentPosition(), 1) .build()); } private long getCurrentPosition() { try { return control.getProgress(); } catch (RemoteException e) { e.printStackTrace(); return 0; } } /** * 是否在播放 * * @return */ protected boolean isPlaying() { try { return control.status() == PlayController.STATUS_PLAYING; } catch (RemoteException e) { e.printStackTrace(); return false; } } /** * 更新正在播放的音乐信息,切换歌曲时调用 */ public void updateMetaData(String path) { if (!StringUtils.isReal(path)) { mMediaSession.setMetadata(null); return; } SongInfo songInfo = mediaManager.getSongInfo(context, path); MediaMetadataCompat.Builder metaDta = new MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, songInfo.getTitle()) .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, songInfo.getArtist()) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, songInfo.getAlbum()) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, songInfo.getArtist()) .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, songInfo.getDuration()) .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, getCoverBitmap(songInfo)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { metaDta.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getCount()); } mMediaSession.setMetadata(metaDta.build()); } private long getCount() { try { return control.getPlayList().size(); } catch (RemoteException e) { e.printStackTrace(); return 0; } } private Bitmap getCoverBitmap(SongInfo info) { if (StringUtils.isReal(info.getAlbum_path())) { return BitmapFactory.decodeFile(info.getAlbum_path()); } else { return BitmapFactory.decodeResource(context.getResources(), R.drawable.default_song); } } /** * 释放MediaSession,退出播放器时调用 */ public void release() { mMediaSession.setCallback(null); mMediaSession.setActive(false); mMediaSession.release(); } /** * API 21 以上 耳机多媒体按钮监听 MediaSessionCompat.Callback */ private MediaSessionCompat.Callback callback = new MediaSessionCompat.Callback() { // 接收到监听事件,可以有选择的进行重写相关方法 @Override public void onPlay() { try { control.resume(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onPause() { try { control.pause(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onSkipToNext() { try { control.next(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onSkipToPrevious() { try { control.pre(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onStop() { try { control.pause(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onSeekTo(long pos) { try { control.seekTo((int) pos); } catch (RemoteException e) { e.printStackTrace(); } } }; }


参考文章

Android开源音乐播放器之播放器基本功能

音乐播放器备忘录

Android 多媒体控制 来电监听-耳机插拔监听-耳机按钮监听-MediaSession-MediaStyle

Android:MediaSession框架介绍

Android系统线控和歌曲信息屏显的那点事

你可能感兴趣的:(android那些事)