RemotePlayer.java revision 76d965dc41863b33f887db33d283cb7f1523f60d
1a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang/*
2a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Copyright (C) 2013 The Android Open Source Project
3a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
4a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
5a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * you may not use this file except in compliance with the License.
6a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * You may obtain a copy of the License at
7a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
8a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
9a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
10a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Unless required by applicable law or agreed to in writing, software
11a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
12a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * See the License for the specific language governing permissions and
14a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * limitations under the License.
15a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang */
16a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
17a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangpackage com.example.android.supportv7.media;
18a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
19a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.Context;
20a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.Intent;
21cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhangimport android.graphics.Bitmap;
22a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.os.Bundle;
23a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaItemStatus;
24a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaRouter.ControlRequestCallback;
25a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaRouter.RouteInfo;
26a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaSessionStatus;
27a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient;
28a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient.ItemActionCallback;
29a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient.SessionActionCallback;
30a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient.StatusCallback;
31a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.util.Log;
32a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
33a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport java.util.ArrayList;
34a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport java.util.List;
35a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
36a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang/**
37a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Handles playback of media items using a remote route.
38a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
39a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * This class is used as a backend by PlaybackManager to feed media items to
40a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * the remote route. When the remote route doesn't support queuing, media items
41a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * are fed one-at-a-time; otherwise media items are enqueued to the remote side.
42a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang */
43a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangpublic class RemotePlayer extends Player {
44a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final String TAG = "RemotePlayer";
45a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
46a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private Context mContext;
47a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private RouteInfo mRoute;
48a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private boolean mEnqueuePending;
49cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    private String mTrackInfo = "";
50cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    private Bitmap mSnapshot;
51a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private List<PlaylistItem> mTempQueue = new ArrayList<PlaylistItem>();
52a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
53a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private RemotePlaybackClient mClient;
54a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private StatusCallback mStatusCallback = new StatusCallback() {
55a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
56a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onItemStatusChanged(Bundle data,
57a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                String sessionId, MediaSessionStatus sessionStatus,
58a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                String itemId, MediaItemStatus itemStatus) {
59a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            logStatus("onItemStatusChanged", sessionId, sessionStatus, itemId, itemStatus);
60a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mCallback != null) {
61a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (itemStatus.getPlaybackState() ==
62a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        MediaItemStatus.PLAYBACK_STATE_FINISHED) {
63a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onCompletion();
64a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                } else if (itemStatus.getPlaybackState() ==
65a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        MediaItemStatus.PLAYBACK_STATE_ERROR) {
66a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onError();
67a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
68a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
69a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
70a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
71a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
72a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onSessionStatusChanged(Bundle data,
73a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                String sessionId, MediaSessionStatus sessionStatus) {
74a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            logStatus("onSessionStatusChanged", sessionId, sessionStatus, null, null);
75a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mCallback != null) {
76a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mCallback.onPlaylistChanged();
77a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
78a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
79a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
80a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
81a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onSessionChanged(String sessionId) {
82a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (DEBUG) {
83a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.d(TAG, "onSessionChanged: sessionId=" + sessionId);
84a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
85a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
86a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    };
87a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
88a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public RemotePlayer(Context context) {
89a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mContext = context;
90a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
91a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
92a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
93a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean isRemotePlayback() {
94a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return true;
95a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
96a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
97a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
98a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean isQueuingSupported() {
99a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return mClient.isQueuingSupported();
100a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
101a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
102a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
103a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void connect(RouteInfo route) {
104a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mRoute = route;
105a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient = new RemotePlaybackClient(mContext, route);
106a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.setStatusCallback(mStatusCallback);
107a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
108a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
109a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "connected to: " + route
110a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    + ", isRemotePlaybackSupported: " + mClient.isRemotePlaybackSupported()
111a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    + ", isQueuingSupported: "+ mClient.isQueuingSupported());
112a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
113a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
114a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
115a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
116a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void release() {
117a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.release();
118a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
119a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
120a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "released.");
121a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
122a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
123a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
124a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    // basic playback operations that are always supported
125a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
126a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void play(final PlaylistItem item) {
127a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
128a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "play: item=" + item);
129a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
130a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.play(item.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() {
131a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
132a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
133a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
134a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("play: succeeded", sessionId, sessionStatus, itemId, itemStatus);
135a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                item.setRemoteItemId(itemId);
136a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getPosition() > 0) {
137a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    seekInternal(item);
138a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
139a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
140a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    pause();
1415d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                } else {
1425d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                    publishState(STATE_PLAYING);
143a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
144a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
145a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
146a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
147a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
148a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
149a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
150a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
151a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("play: failed", error, code);
152a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
153a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
154a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
155a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
156a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
157a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void seek(final PlaylistItem item) {
158a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        seekInternal(item);
159a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
160a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
161a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
162a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void getStatus(final PlaylistItem item, final boolean update) {
163a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession() || item.getRemoteItemId() == null) {
164a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // if session is not valid or item id not assigend yet.
165a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // just return, it's not fatal
166a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
167a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
168a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
169a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
170a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "getStatus: item=" + item + ", update=" + update);
171a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
172a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.getStatus(item.getRemoteItemId(), null, new ItemActionCallback() {
173a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
174a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
175a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
176a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("getStatus: succeeded", sessionId, sessionStatus, itemId, itemStatus);
177a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                int state = itemStatus.getPlaybackState();
178a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING
179a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        || state == MediaItemStatus.PLAYBACK_STATE_PAUSED
180a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        || state == MediaItemStatus.PLAYBACK_STATE_PENDING) {
181a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setState(state);
182a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setPosition(itemStatus.getContentPosition());
183a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setDuration(itemStatus.getContentDuration());
184a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setTimestamp(itemStatus.getTimestamp());
185a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
186a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (update && mCallback != null) {
187a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistReady();
188a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
189a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
190a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
191a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
192a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
193a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("getStatus: failed", error, code);
194a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (update && mCallback != null) {
195a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistReady();
196a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
197a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
198a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
199a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
200a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
201a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
202a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void pause() {
203a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
204a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // ignore if no session
205a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
206a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
207a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
208a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "pause");
209a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
210a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.pause(null, new SessionActionCallback() {
211a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
212a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
213a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("pause: succeeded", sessionId, sessionStatus, null, null);
214a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
215a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
216a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
2175d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                publishState(STATE_PAUSED);
218a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
219a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
220a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
221a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
222a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("pause: failed", error, code);
223a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
224a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
225a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
226a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
227a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
228a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void resume() {
229a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
230a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // ignore if no session
231a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
232a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
233a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
234a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "resume");
235a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
236a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.resume(null, new SessionActionCallback() {
237a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
238a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
239a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("resume: succeeded", sessionId, sessionStatus, null, null);
240a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
241a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
242a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
2435d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                publishState(STATE_PLAYING);
244a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
245a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
246a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
247a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
248a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("resume: failed", error, code);
249a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
250a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
251a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
252a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
253a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
254a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void stop() {
255a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
256a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // ignore if no session
257a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
258a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
2595d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik        publishState(STATE_IDLE);
260a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
261a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "stop");
262a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
263a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.stop(null, new SessionActionCallback() {
264a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
265a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
266a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("stop: succeeded", sessionId, sessionStatus, null, null);
267a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mClient.isSessionManagementSupported()) {
268a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    endSession();
269a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
270a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
271a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
272a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
273a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
274a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
275a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
276a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
277a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("stop: failed", error, code);
278a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
279a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
280a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
281a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
282a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    // enqueue & remove are only supported if isQueuingSupported() returns true
283a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
284a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void enqueue(final PlaylistItem item) {
285a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfQueuingUnsupported();
286a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
287a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession() && !mEnqueuePending) {
288a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mEnqueuePending = true;
289a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mClient.isSessionManagementSupported()) {
290a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                startSession(item);
291a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            } else {
292a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                enqueueInternal(item);
293a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
294a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } else if (mEnqueuePending){
295a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mTempQueue.add(item);
296a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } else {
297a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            enqueueInternal(item);
298a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
299a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
300a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
301a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
302a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public PlaylistItem remove(String itemId) {
303a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfNoSession();
304a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfQueuingUnsupported();
305a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
306a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
307a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "remove: itemId=" + itemId);
308a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
309a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.remove(itemId, null, new ItemActionCallback() {
310a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
311a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
312a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
313a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("remove: succeeded", sessionId, sessionStatus, itemId, itemStatus);
314a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
315a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
316a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
317a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
318a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("remove: failed", error, code);
319a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
320a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
321a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
322a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return null;
323a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
324a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
325a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
326cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    public void updateTrackInfo() {
327a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // clear stats info first
328cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        mTrackInfo = "";
329cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        mSnapshot = null;
330a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
331cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        Intent intent = new Intent(SampleMediaRouteProvider.ACTION_GET_TRACK_INFO);
332a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        intent.addCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE);
333a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
334a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mRoute != null && mRoute.supportsControlRequest(intent)) {
335a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            ControlRequestCallback callback = new ControlRequestCallback() {
336a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                @Override
337a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                public void onResult(Bundle data) {
338a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    if (DEBUG) {
339a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        Log.d(TAG, "getStatistics: succeeded: data=" + data);
340a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
341a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    if (data != null) {
342cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang                        mTrackInfo = data.getString(SampleMediaRouteProvider.TRACK_INFO_DESC);
343cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang                        mSnapshot = data.getParcelable(
344cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang                                SampleMediaRouteProvider.TRACK_INFO_SNAPSHOT);
345a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
346a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
347a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
348a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                @Override
349a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                public void onError(String error, Bundle data) {
350a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    Log.d(TAG, "getStatistics: failed: error=" + error + ", data=" + data);
351a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
352a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            };
353a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
354a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mRoute.sendControlRequest(intent, callback);
355a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
356a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
357a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
358a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
359cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    public String getDescription() {
360cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        return mTrackInfo;
361cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    }
362cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang
363cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    @Override
364cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    public Bitmap getSnapshot() {
365cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        return mSnapshot;
366a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
367a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
368a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void enqueueInternal(final PlaylistItem item) {
369a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfQueuingUnsupported();
370a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
371a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
372a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "enqueue: item=" + item);
373a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
374a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.enqueue(item.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() {
375a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
376a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
377a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
378a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("enqueue: succeeded", sessionId, sessionStatus, itemId, itemStatus);
379a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                item.setRemoteItemId(itemId);
380a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getPosition() > 0) {
381a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    seekInternal(item);
382a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
383a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
384a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    pause();
38576d965dc41863b33f887db33d283cb7f1523f60dJae Seo                } else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
38676d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    publishState(STATE_PLAYING);
387a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
388a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mEnqueuePending) {
389a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mEnqueuePending = false;
390a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    for (PlaylistItem item : mTempQueue) {
391a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        enqueueInternal(item);
392a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
393a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mTempQueue.clear();
394a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
395a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
396a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
397a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
398a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
399a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
400a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
401a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
402a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("enqueue: failed", error, code);
403a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
404a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
405a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
406a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
407a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
408a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
409a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
410a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void seekInternal(final PlaylistItem item) {
411a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfNoSession();
412a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
413a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
414a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "seek: item=" + item);
415a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
416a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.seek(item.getRemoteItemId(), item.getPosition(), null, new ItemActionCallback() {
417a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           @Override
418a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
419a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                   String itemId, MediaItemStatus itemStatus) {
420a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               logStatus("seek: succeeded", sessionId, sessionStatus, itemId, itemStatus);
421a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               if (mCallback != null) {
422a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                   mCallback.onPlaylistChanged();
423a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               }
424a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           }
425a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
426a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           @Override
427a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           public void onError(String error, int code, Bundle data) {
428a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               logError("seek: failed", error, code);
429a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           }
430a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
431a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
432a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
433a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void startSession(final PlaylistItem item) {
434a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.startSession(null, new SessionActionCallback() {
435a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
436a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
437a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("startSession: succeeded", sessionId, sessionStatus, null, null);
438a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                enqueueInternal(item);
439a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
440a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
441a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
442a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
443a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("startSession: failed", error, code);
444a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
445a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
446a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
447a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
448a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void endSession() {
449a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.endSession(null, new SessionActionCallback() {
450a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
451a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
452a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("endSession: succeeded", sessionId, sessionStatus, null, null);
453a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
454a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
455a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
456a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
457a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("endSession: failed", error, code);
458a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
459a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
460a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
461a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
462a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void logStatus(String message,
463a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            String sessionId, MediaSessionStatus sessionStatus,
464a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            String itemId, MediaItemStatus itemStatus) {
465a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
466a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            String result = "";
467a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (sessionId != null && sessionStatus != null) {
468a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                result += "sessionId=" + sessionId + ", sessionStatus=" + sessionStatus;
469a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
470a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (itemId != null & itemStatus != null) {
471a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                result += (result.isEmpty() ? "" : ", ")
472a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        + "itemId=" + itemId + ", itemStatus=" + itemStatus;
473a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
474a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, message + ": " + result);
475a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
476a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
477a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
478a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void logError(String message, String error, int code) {
479a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        Log.d(TAG, message + ": error=" + error + ", code=" + code);
480a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
481a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
482a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void throwIfNoSession() {
483a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
484a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            throw new IllegalStateException("Session is invalid");
485a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
486a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
487a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
488a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void throwIfQueuingUnsupported() {
489a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!isQueuingSupported()) {
490a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            throw new UnsupportedOperationException("Queuing is unsupported");
491a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
492a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
493a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang}
494