MediaSession分析

很苦恼没有详细的资料介绍MediaSession,也没有多少现成的例子demo可以参考。那就自己研究一下源码。

先看一下先相关的类,MediaSession、MediaController,SessionToken,MediaSessionService。


MediaSession构造函数

    public MediaSession(@NonNull Context context, @NonNull String tag, int userId) {
        if (context == null) {
            throw new IllegalArgumentException("context cannot be null.");
        }
        if (TextUtils.isEmpty(tag)) {
            throw new IllegalArgumentException("tag cannot be null or empty");
        }
        mMaxBitmapSize = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
        mCbStub = new CallbackStub(this); //第一处
        MediaSessionManager manager = (MediaSessionManager) context
                .getSystemService(Context.MEDIA_SESSION_SERVICE);
        try {
            mBinder = manager.createSession(mCbStub, tag, userId); //第二处
            mSessionToken = new Token(mBinder.getController()); //第三处
            mController = new MediaController(context, mSessionToken); //第四处
        } catch (RemoteException e) {
            throw new RuntimeException("Remote error creating session.", e);
        }
    }

先看第一处,CallbackStub,看几行就大概明白意思

    public static class CallbackStub extends ISessionCallback.Stub {
        private WeakReference<MediaSession> mMediaSession;

        public CallbackStub(MediaSession session) {
            mMediaSession = new WeakReference<MediaSession>(session);
        }

        @Override
        public void onCommand(String command, Bundle args, ResultReceiver cb) {
            MediaSession session = mMediaSession.get();
            if (session != null) {
                session.postCommand(command, args, cb);
            }
        }

        @Override
        public void onMediaButton(Intent mediaButtonIntent, int sequenceNumber,
                ResultReceiver cb) {
            MediaSession session = mMediaSession.get();
            try {
                if (session != null) {
                    session.dispatchMediaButton(mediaButtonIntent);
                }
            } finally {
                if (cb != null) {
                    cb.send(sequenceNumber, null);
                }
            }
        }

        @Override
        public void onPrepare() {
            MediaSession session = mMediaSession.get();
            if (session != null) {
                session.dispatchPrepare();
            }
        }
就是将自己封装一下,传给别的类,以便让别的类调用这些功能。也就是说,具体的控制功能是通过这些回调实现的。

这些功能是怎么实现的?MediaSession还有个内部类Callback,需要开发者具体实现它。比如

public void onPrepare() {}
public void onPrepareFromMediaId(String mediaId, Bundle extras) { }
public void onPrepareFromSearch(String query, Bundle extras) { }
具体的调用关系,已prepare为例,

        public void onPrepare() {
            MediaSession session = mMediaSession.get();
            if (session != null) {
                session.dispatchPrepare();
            }
        }

    private void dispatchPrepare() {
        postToCallback(CallbackMessageHandler.MSG_PREPARE);
    }
    case MSG_PREPARE:
         mCallback.onPrepare();
这个mCallback就是MediaSession.Callback类型,即需要实现的。

第二处,

 mBinder = manager.createSession(mCbStub, tag, userId)

最终会调用到MediaSessionService的

    private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
            String callerPackageName, ISessionCallback cb, String tag) {

        final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
                callerPackageName, cb, tag, this, mHandler);
        try {
            cb.asBinder().linkToDeath(session, 0);
        } catch (RemoteException e) {
            throw new RuntimeException("Media Session owner died prematurely.", e);
        }

        mAllSessions.add(session);
        mPriorityStack.addSession(session);

        UserRecord user = getOrCreateUser(userId);
        user.addSessionLocked(session);

        mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);

        if (DEBUG) {
            Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
        }
        return session;
    }
创建了一个MediaSessionRecord对象,并把它放到mAllSessions统一管理。注意,ISessionCallback对象也传过来了。

mAllSessions 对象是ArrayList<MediaSessionRecord>类型。在这个服务中,SessionManagerImpl才是真正的Manager对应的service,因为它实现了ISessionManager.Stub。

所以

mBinder = manager.createSession(mCbStub, tag, userId)

mBinder指向的就是一个ISession对象,通过MediaSessionRecord.getSessionBinder() 获得。


第三处,创建Token。

mSessionToken = new Token(mBinder.getController());

token,即标识,身份的代表吧。每个token与每个session一一对应。

又引入几个对象,SessionStub,SessionCb,ControllerStub。

前面提到,mBinder指向的是ISession对象,具体实现类是SessionStub。

所以mBinder.getController()对应着SessionStub.getController(),为ISessionController对象,具体实现为ControllerStub类。

还有个SessionCb类,就是封装(组合)了MediaSession对象的内部类ISessionCallback。


第四处,创建MediaController

mController = new MediaController(context, mSessionToken);
public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
    this(context, token.getBinder());
}
此类的介绍

Allows an app to interact with an ongoing media session. Media buttons and other commands can be sent to the session. A callback may be registered to receive updates from the session, such as metadata and play state changes.

A MediaController can be created through MediaSessionManager if you hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an enabled notification listener or by getting a MediaSession.Token directly from the session owner.

它的构造函数

    public MediaController(Context context, ISessionController sessionBinder) {
        if (sessionBinder == null) {
            throw new IllegalArgumentException("Session token cannot be null");
        }
        if (context == null) {
            throw new IllegalArgumentException("Context cannot be null");
        }
        mSessionBinder = sessionBinder;
        mTransportControls = new TransportControls();
        mToken = new MediaSession.Token(sessionBinder);
        mContext = context;
    }

mSessionBinder对象,对应的就是Token类的mBinder,也就是MediaSessionRecord类的ControllerStub。

随便浏览MediaController的几个函数,基本上都是通过mSessionBinder的实现。


这时候,我们基本上可以做一个大概的猜测,

1. 客户端使用MediaSession类做播放器(并实现MediaSession.Callback供控制端调用);

这个作为受控端

2. 控制端

可以是任意app,通过调用服务查询session,然后就可以控制session的操作。并向session注册自己的callback,以便session状态改变时通知自己。


这篇博客总结的不错,可以参考 http://blog.csdn.net/belyxiong/article/details/42039665









  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值