blob: 5845e48db6e5bb3ed80ef40f5e02a30b98f87492 [file] [log] [blame]
RoboErik07c70772014-03-20 13:33:52 -07001/*
2 * Copyright (C) 2014 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 */
16package com.android.onemedia.provider;
17
Jeff Brownff0215d2014-07-14 04:05:08 -070018import android.media.routing.MediaRouteSelector;
19import android.media.routing.MediaRouteService;
20import android.media.routing.MediaRouter.ConnectionInfo;
21import android.media.routing.MediaRouter.ConnectionRequest;
22import android.media.routing.MediaRouter.DestinationInfo;
23import android.media.routing.MediaRouter.DiscoveryRequest;
24import android.media.routing.MediaRouter.RouteInfo;
RoboErik07c70772014-03-20 13:33:52 -070025import android.media.session.PlaybackState;
26import android.os.Bundle;
27import android.os.Handler;
Jeff Brownff0215d2014-07-14 04:05:08 -070028import android.os.Process;
29import android.support.media.protocols.MediaPlayerProtocol;
30import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
31import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
RoboErikc785a782014-07-14 13:40:43 -070032import android.os.Looper;
33import android.os.ResultReceiver;
34import android.os.SystemClock;
RoboErik07c70772014-03-20 13:33:52 -070035import android.util.Log;
36
37import com.android.onemedia.playback.LocalRenderer;
38import com.android.onemedia.playback.Renderer;
39import com.android.onemedia.playback.RequestUtils;
40
41import java.util.ArrayList;
RoboErik07c70772014-03-20 13:33:52 -070042
43/**
44 * Test of MediaRouteProvider. Show a dummy provider with a simple interface for
45 * playing music.
46 */
Jeff Brownff0215d2014-07-14 04:05:08 -070047public class OneMediaRouteProvider extends MediaRouteService {
RoboErik07c70772014-03-20 13:33:52 -070048 private static final String TAG = "OneMRP";
49 private static final boolean DEBUG = true;
50
Jeff Brownff0215d2014-07-14 04:05:08 -070051 private static final String TEST_DESTINATION_ID = "testDestination";
52 private static final String TEST_ROUTE_ID = "testRoute";
53
RoboErik07c70772014-03-20 13:33:52 -070054 private Renderer mRenderer;
55 private RenderListener mRenderListener;
56 private PlaybackState mPlaybackState;
RoboErik07c70772014-03-20 13:33:52 -070057 private Handler mHandler;
58
Jeff Brownff0215d2014-07-14 04:05:08 -070059 private OneStub mStub;
60
RoboErik07c70772014-03-20 13:33:52 -070061 @Override
62 public void onCreate() {
63 mHandler = new Handler();
RoboErik07c70772014-03-20 13:33:52 -070064 mRenderer = new LocalRenderer(this, null);
65 mRenderListener = new RenderListener();
RoboErikc785a782014-07-14 13:40:43 -070066 PlaybackState.Builder bob = new PlaybackState.Builder();
67 bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
68 mPlaybackState = bob.build();
RoboErik07c70772014-03-20 13:33:52 -070069
70 mRenderer.registerListener(mRenderListener);
RoboErik07c70772014-03-20 13:33:52 -070071 }
72
73 @Override
Jeff Brownff0215d2014-07-14 04:05:08 -070074 public ClientSession onCreateClientSession(ClientInfo client) {
75 if (client.getUid() != Process.myUid()) {
76 // for testing purposes, only allow connections from this application
77 // since this provider is not fully featured
78 return null;
RoboErik07c70772014-03-20 13:33:52 -070079 }
Jeff Brownff0215d2014-07-14 04:05:08 -070080 return new OneSession(client);
RoboErik07c70772014-03-20 13:33:52 -070081 }
82
Jeff Brownff0215d2014-07-14 04:05:08 -070083 private final class OneSession extends ClientSession {
84 private final ClientInfo mClient;
RoboErik07c70772014-03-20 13:33:52 -070085
Jeff Brownff0215d2014-07-14 04:05:08 -070086 public OneSession(ClientInfo client) {
87 mClient = client;
RoboErik07c70772014-03-20 13:33:52 -070088 }
89
90 @Override
Jeff Brownff0215d2014-07-14 04:05:08 -070091 public boolean onStartDiscovery(DiscoveryRequest req, DiscoveryCallback callback) {
92 for (MediaRouteSelector selector : req.getSelectors()) {
93 if (isMatch(selector)) {
94 DestinationInfo destination = new DestinationInfo.Builder(
95 TEST_DESTINATION_ID, getServiceMetadata(), "OneMedia")
96 .setDescription("Test route from OneMedia app.")
97 .build();
98 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
99 routes.add(new RouteInfo.Builder(
100 TEST_ROUTE_ID, destination, selector).build());
101 callback.onDestinationFound(destination, routes);
102 return true;
103 }
104 }
105 return false;
106 }
107
108 @Override
109 public void onStopDiscovery() {
110 }
111
112 @Override
113 public boolean onConnect(ConnectionRequest req, ConnectionCallback callback) {
114 if (req.getRoute().getId().equals(TEST_ROUTE_ID)) {
115 mStub = new OneStub();
116 ConnectionInfo connection = new ConnectionInfo.Builder(req.getRoute())
117 .setProtocolStub(MediaPlayerProtocol.class, mStub)
118 .build();
119 callback.onConnected(connection);
120 return true;
121 }
122 return false;
123 }
124
125 @Override
126 public void onDisconnect() {
127 mStub = null;
128 }
129
130 private boolean isMatch(MediaRouteSelector selector) {
131 if (!selector.containsProtocol(MediaPlayerProtocol.class)) {
132 return false;
133 }
134 for (String protocol : selector.getRequiredProtocols()) {
135 if (!protocol.equals(MediaPlayerProtocol.class.getName())) {
136 return false;
137 }
138 }
139 return true;
140 }
141 }
142
143 private final class OneStub extends MediaPlayerProtocol.Stub {
144 MediaInfo mMediaInfo;
145
146 public OneStub() {
147 super(mHandler);
148 }
149
150 @Override
151 public void onLoad(MediaInfo mediaInfo, boolean autoplay, long playPosition,
152 Bundle extras) {
RoboErik07c70772014-03-20 13:33:52 -0700153 if (DEBUG) {
Jeff Brownff0215d2014-07-14 04:05:08 -0700154 Log.d(TAG, "Attempting to play " + mediaInfo.getContentId());
RoboErik07c70772014-03-20 13:33:52 -0700155 }
156 // look up the route and send a play command to it
Jeff Brownff0215d2014-07-14 04:05:08 -0700157 mMediaInfo = mediaInfo;
RoboErik07c70772014-03-20 13:33:52 -0700158 Bundle bundle = new Bundle();
Jeff Brownff0215d2014-07-14 04:05:08 -0700159 bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, mediaInfo.getContentId());
RoboErik07c70772014-03-20 13:33:52 -0700160 mRenderer.setContent(bundle);
RoboErik07c70772014-03-20 13:33:52 -0700161 }
162
163 @Override
Jeff Brownff0215d2014-07-14 04:05:08 -0700164 public void onPlay(Bundle extras) {
RoboErik07c70772014-03-20 13:33:52 -0700165 mRenderer.onPlay();
RoboErik07c70772014-03-20 13:33:52 -0700166 }
167
168 @Override
Jeff Brownff0215d2014-07-14 04:05:08 -0700169 public void onPause(Bundle extras) {
RoboErik07c70772014-03-20 13:33:52 -0700170 mRenderer.onPause();
RoboErik07c70772014-03-20 13:33:52 -0700171 }
172 }
173
174 private class RenderListener implements Renderer.Listener {
175
176 @Override
177 public void onError(int type, int extra, Bundle extras, Throwable error) {
178 Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
Jeff Brownff0215d2014-07-14 04:05:08 -0700179 sendStatusUpdate(PlaybackState.STATE_ERROR);
RoboErik07c70772014-03-20 13:33:52 -0700180 }
181
182 @Override
183 public void onStateChanged(int newState) {
RoboErikf1372422014-04-23 14:38:17 -0700184 long position = -1;
185 if (mRenderer != null) {
186 position = mRenderer.getSeekPosition();
187 }
RoboErikc785a782014-07-14 13:40:43 -0700188 int pbState;
189 float rate = 0;
190 String errorMsg = null;
RoboErik07c70772014-03-20 13:33:52 -0700191 switch (newState) {
192 case Renderer.STATE_ENDED:
193 case Renderer.STATE_STOPPED:
RoboErikc785a782014-07-14 13:40:43 -0700194 pbState = PlaybackState.STATE_STOPPED;
RoboErik07c70772014-03-20 13:33:52 -0700195 break;
196 case Renderer.STATE_INIT:
197 case Renderer.STATE_PREPARING:
RoboErikc785a782014-07-14 13:40:43 -0700198 pbState = PlaybackState.STATE_BUFFERING;
RoboErik07c70772014-03-20 13:33:52 -0700199 break;
200 case Renderer.STATE_ERROR:
RoboErikc785a782014-07-14 13:40:43 -0700201 pbState = PlaybackState.STATE_ERROR;
RoboErik07c70772014-03-20 13:33:52 -0700202 break;
203 case Renderer.STATE_PAUSED:
RoboErikc785a782014-07-14 13:40:43 -0700204 pbState = PlaybackState.STATE_PAUSED;
RoboErik07c70772014-03-20 13:33:52 -0700205 break;
206 case Renderer.STATE_PLAYING:
RoboErikc785a782014-07-14 13:40:43 -0700207 pbState = PlaybackState.STATE_PLAYING;
208 rate = 1;
RoboErik07c70772014-03-20 13:33:52 -0700209 break;
210 default:
RoboErikc785a782014-07-14 13:40:43 -0700211 pbState = PlaybackState.STATE_ERROR;
212 errorMsg = "unknown state";
RoboErik07c70772014-03-20 13:33:52 -0700213 break;
214 }
RoboErikc785a782014-07-14 13:40:43 -0700215 PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
216 bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
217 bob.setErrorMessage(errorMsg);
218 mPlaybackState = bob.build();
RoboErik07c70772014-03-20 13:33:52 -0700219
Jeff Brownff0215d2014-07-14 04:05:08 -0700220 sendStatusUpdate(mPlaybackState.getState());
RoboErik07c70772014-03-20 13:33:52 -0700221 }
222
223 @Override
224 public void onBufferingUpdate(int percent) {
225 }
226
227 @Override
228 public void onFocusLost() {
RoboErikc785a782014-07-14 13:40:43 -0700229 Log.d(TAG, "Focus lost, pausing");
230 // Don't update state here, we'll get a separate call to
231 // onStateChanged when it pauses
RoboErikf1372422014-04-23 14:38:17 -0700232 mRenderer.onPause();
RoboErik07c70772014-03-20 13:33:52 -0700233 }
234
235 @Override
236 public void onNextStarted() {
237 }
Jeff Brownff0215d2014-07-14 04:05:08 -0700238
239 private void sendStatusUpdate(int state) {
240 if (mStub != null) {
241 MediaStatus status = new MediaStatus(1, mStub.mMediaInfo);
242 switch (state) {
243 case PlaybackState.STATE_BUFFERING:
244 case PlaybackState.STATE_FAST_FORWARDING:
245 case PlaybackState.STATE_REWINDING:
246 case PlaybackState.STATE_SKIPPING_TO_NEXT:
247 case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
248 status.setPlayerState(MediaStatus.PLAYER_STATE_BUFFERING);
249 break;
250 case PlaybackState.STATE_CONNECTING:
251 case PlaybackState.STATE_STOPPED:
252 status.setPlayerState(MediaStatus.PLAYER_STATE_IDLE);
253 break;
254 case PlaybackState.STATE_PAUSED:
255 status.setPlayerState(MediaStatus.PLAYER_STATE_PAUSED);
256 break;
257 case PlaybackState.STATE_PLAYING:
258 status.setPlayerState(MediaStatus.PLAYER_STATE_PLAYING);
259 break;
260 case PlaybackState.STATE_NONE:
261 case PlaybackState.STATE_ERROR:
262 default:
263 status.setPlayerState(MediaStatus.PLAYER_STATE_UNKNOWN);
264 break;
265 }
266 mStub.sendStatusUpdatedEvent(status, null);
267 }
268 }
RoboErik07c70772014-03-20 13:33:52 -0700269 }
270}