1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.media; 18 19 import android.content.Context; 20 import android.media.DataSourceDesc; 21 import android.media.session.MediaSession; 22 import android.media.session.PlaybackState; 23 import android.net.Uri; 24 import android.os.Build; 25 import android.os.Bundle; 26 import android.support.annotation.RequiresApi; 27 28 import com.android.support.mediarouter.media.MediaItemStatus; 29 import com.android.support.mediarouter.media.MediaRouter; 30 import com.android.support.mediarouter.media.MediaSessionStatus; 31 import com.android.support.mediarouter.media.RemotePlaybackClient; 32 import com.android.support.mediarouter.media.RemotePlaybackClient.ItemActionCallback; 33 import com.android.support.mediarouter.media.RemotePlaybackClient.SessionActionCallback; 34 import com.android.support.mediarouter.media.RemotePlaybackClient.StatusCallback; 35 36 import java.util.Map; 37 38 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 39 public class RoutePlayer extends MediaSession.Callback { 40 public static final long PLAYBACK_ACTIONS = PlaybackState.ACTION_PAUSE 41 | PlaybackState.ACTION_PLAY | PlaybackState.ACTION_SEEK_TO 42 | PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_REWIND; 43 44 private RemotePlaybackClient mClient; 45 private String mSessionId; 46 private String mItemId; 47 private PlayerEventCallback mCallback; 48 49 private StatusCallback mStatusCallback = new StatusCallback() { 50 @Override 51 public void onItemStatusChanged(Bundle data, 52 String sessionId, MediaSessionStatus sessionStatus, 53 String itemId, MediaItemStatus itemStatus) { 54 updateSessionStatus(sessionId, sessionStatus); 55 updateItemStatus(itemId, itemStatus); 56 } 57 }; 58 RoutePlayer(Context context, MediaRouter.RouteInfo route)59 public RoutePlayer(Context context, MediaRouter.RouteInfo route) { 60 mClient = new RemotePlaybackClient(context, route); 61 mClient.setStatusCallback(mStatusCallback); 62 mClient.startSession(null, new SessionActionCallback() { 63 @Override 64 public void onResult(Bundle data, 65 String sessionId, MediaSessionStatus sessionStatus) { 66 updateSessionStatus(sessionId, sessionStatus); 67 } 68 }); 69 } 70 71 @Override onPlay()72 public void onPlay() { 73 mClient.resume(null, new SessionActionCallback() { 74 @Override 75 public void onResult(Bundle data, 76 String sessionId, MediaSessionStatus sessionStatus) { 77 updateSessionStatus(sessionId, sessionStatus); 78 } 79 }); 80 } 81 82 @Override onPause()83 public void onPause() { 84 mClient.pause(null, new SessionActionCallback() { 85 @Override 86 public void onResult(Bundle data, 87 String sessionId, MediaSessionStatus sessionStatus) { 88 updateSessionStatus(sessionId, sessionStatus); 89 } 90 }); 91 } 92 93 @Override onSeekTo(long pos)94 public void onSeekTo(long pos) { 95 mClient.seek(mItemId, pos, null, new ItemActionCallback() { 96 @Override 97 public void onResult(Bundle data, 98 String sessionId, MediaSessionStatus sessionStatus, 99 String itemId, MediaItemStatus itemStatus) { 100 updateSessionStatus(sessionId, sessionStatus); 101 updateItemStatus(itemId, itemStatus); 102 } 103 }); 104 } 105 106 @Override onStop()107 public void onStop() { 108 mClient.stop(null, new SessionActionCallback() { 109 @Override 110 public void onResult(Bundle data, 111 String sessionId, MediaSessionStatus sessionStatus) { 112 updateSessionStatus(sessionId, sessionStatus); 113 } 114 }); 115 } 116 setPlayerEventCallback(PlayerEventCallback callback)117 public void setPlayerEventCallback(PlayerEventCallback callback) { 118 mCallback = callback; 119 } 120 openVideo(DataSourceDesc dsd)121 public void openVideo(DataSourceDesc dsd) { 122 mClient.play(dsd.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() { 123 @Override 124 public void onResult(Bundle data, 125 String sessionId, MediaSessionStatus sessionStatus, 126 String itemId, MediaItemStatus itemStatus) { 127 updateSessionStatus(sessionId, sessionStatus); 128 updateItemStatus(itemId, itemStatus); 129 playInternal(dsd.getUri()); 130 } 131 }); 132 } 133 release()134 public void release() { 135 if (mClient != null) { 136 mClient.release(); 137 mClient = null; 138 } 139 if (mCallback != null) { 140 mCallback = null; 141 } 142 } 143 playInternal(Uri uri)144 private void playInternal(Uri uri) { 145 mClient.play(uri, "video/mp4", null, 0, null, new ItemActionCallback() { 146 @Override 147 public void onResult(Bundle data, 148 String sessionId, MediaSessionStatus sessionStatus, 149 String itemId, MediaItemStatus itemStatus) { 150 updateSessionStatus(sessionId, sessionStatus); 151 updateItemStatus(itemId, itemStatus); 152 } 153 }); 154 } 155 updateSessionStatus(String sessionId, MediaSessionStatus sessionStatus)156 private void updateSessionStatus(String sessionId, MediaSessionStatus sessionStatus) { 157 mSessionId = sessionId; 158 } 159 updateItemStatus(String itemId, MediaItemStatus itemStatus)160 private void updateItemStatus(String itemId, MediaItemStatus itemStatus) { 161 mItemId = itemId; 162 if (itemStatus == null || mCallback == null) return; 163 mCallback.onPlayerStateChanged(itemStatus); 164 } 165 166 public static abstract class PlayerEventCallback { onPlayerStateChanged(MediaItemStatus itemStatus)167 public void onPlayerStateChanged(MediaItemStatus itemStatus) { } 168 } 169 } 170