OSDN Git Service

Update media session test application for new media router.
authorJeff Brown <jeffbrown@google.com>
Mon, 14 Jul 2014 11:05:08 +0000 (04:05 -0700)
committerJeff Brown <jeffbrown@google.com>
Mon, 14 Jul 2014 11:38:15 +0000 (04:38 -0700)
Change-Id: I3c19e008d211099b4d7320e3f195850cfb4dd927

tests/OneMedia/Android.mk
tests/OneMedia/AndroidManifest.xml
tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
tests/OneMedia/src/com/android/onemedia/PlayerController.java
tests/OneMedia/src/com/android/onemedia/PlayerSession.java
tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java
tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java

index 93b9c9a..4feac68 100644 (file)
@@ -10,8 +10,7 @@ LOCAL_PACKAGE_NAME := OneMedia
 LOCAL_CERTIFICATE := platform
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-        android-support-v7-appcompat \
-        android-support-v7-mediarouter
+    android-support-media-protocols
 
 LOCAL_PROGUARD_ENABLED := disabled
 
index 504d471..9d78ca5 100644 (file)
             android:process="com.android.onemedia.service" />
         <service
             android:name=".provider.OneMediaRouteProvider"
-            android:permission="android.permission.BIND_ROUTE_PROVIDER"
+            android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE"
             android:exported="true"
             android:process="com.android.onemedia.provider">
             <intent-filter>
-                <action android:name="com.android.media.session.MediaRouteProvider" />
+                <action android:name="android.media.routing.MediaRouteService" />
             </intent-filter>
           </service>
     </application>
index ee407ad..894377b 100644 (file)
@@ -28,8 +28,6 @@ import android.widget.CheckBox;
 import android.widget.EditText;
 import android.widget.TextView;
 
-import com.android.onemedia.playback.Renderer;
-
 public class OnePlayerActivity extends Activity {
     private static final String TAG = "OnePlayerActivity";
 
index 145b389..802f473 100644 (file)
@@ -18,7 +18,6 @@ package com.android.onemedia;
 
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
-import android.media.session.RouteInfo;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
@@ -121,7 +120,7 @@ public class PlayerController {
     }
 
     public void showRoutePicker() {
-        mController.showRoutePicker();
+        // TODO
     }
 
     private void unbindFromService() {
@@ -173,11 +172,6 @@ public class PlayerController {
 
     private class SessionCallback extends MediaController.Callback {
         @Override
-        public void onRouteChanged(RouteInfo route) {
-            // TODO
-        }
-
-        @Override
         public void onPlaybackStateChanged(PlaybackState state) {
             if (state == null) {
                 return;
index a220107..7c0eabe 100644 (file)
@@ -17,14 +17,17 @@ package com.android.onemedia;
 
 import android.content.Context;
 import android.content.Intent;
-import android.media.session.Route;
-import android.media.session.RouteInfo;
-import android.media.session.RouteOptions;
-import android.media.session.RoutePlaybackControls;
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.MediaRouter;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.RouteInfo;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
 import android.util.Log;
 import android.view.KeyEvent;
 
@@ -34,11 +37,13 @@ import com.android.onemedia.playback.Renderer;
 import com.android.onemedia.playback.RequestUtils;
 
 import java.util.ArrayList;
+import java.util.List;
 
 public class PlayerSession {
     private static final String TAG = "PlayerSession";
 
     protected MediaSession mSession;
+    protected MediaRouter mRouter;
     protected Context mContext;
     protected Renderer mRenderer;
     protected MediaSession.Callback mCallback;
@@ -46,10 +51,6 @@ public class PlayerSession {
 
     protected PlaybackState mPlaybackState;
     protected Listener mListener;
-    protected ArrayList<RouteOptions> mRouteOptions;
-    protected Route mRoute;
-    protected RoutePlaybackControls mRouteControls;
-    protected RouteListener mRouteListener;
 
     private String mContent;
 
@@ -63,41 +64,53 @@ public class PlayerSession {
                 | PlaybackState.ACTION_PLAY);
 
         mRenderer.registerListener(mRenderListener);
-
-        // TODO need an easier way to build route options
-        mRouteOptions = new ArrayList<RouteOptions>();
-        RouteOptions.Builder bob = new RouteOptions.Builder();
-        bob.addInterface(RoutePlaybackControls.NAME);
-        mRouteOptions.add(bob.build());
-        mRouteListener = new RouteListener();
     }
 
     public void createSession() {
-        if (mSession != null) {
-            mSession.release();
-        }
+        releaseSession();
+
         MediaSessionManager man = (MediaSessionManager) mContext
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
+
+        mRouter = new MediaRouter(mContext);
+        mRouter.addSelector(new MediaRouteSelector.Builder()
+                .addRequiredProtocol(MediaPlayerProtocol.class)
+                .build());
+        mRouter.addSelector(new MediaRouteSelector.Builder()
+                .setRequiredFeatures(MediaRouter.ROUTE_FEATURE_LIVE_AUDIO)
+                .setOptionalFeatures(MediaRouter.ROUTE_FEATURE_LIVE_VIDEO)
+                .build());
+        mRouter.setRoutingCallback(new RoutingCallback(), null);
+
         mSession = man.createSession("OneMedia");
         mSession.addCallback(mCallback);
         mSession.addTransportControlsCallback(new TransportCallback());
         mSession.setPlaybackState(mPlaybackState);
         mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
-        mSession.setRouteOptions(mRouteOptions);
+        mSession.setMediaRouter(mRouter);
         mSession.setActive(true);
     }
 
     public void onDestroy() {
-        if (mSession != null) {
-            mSession.release();
-        }
+        releaseSession();
         if (mRenderer != null) {
             mRenderer.unregisterListener(mRenderListener);
             mRenderer.onDestroy();
         }
     }
 
+    private void releaseSession() {
+        if (mSession != null) {
+            mSession.release();
+            mSession = null;
+        }
+        if (mRouter != null) {
+            mRouter.release();
+            mRouter = null;
+        }
+    }
+
     public void setListener(Listener listener) {
         mListener = listener;
     }
@@ -218,40 +231,6 @@ public class PlayerSession {
                 }
             }
         }
-
-        @Override
-        public void onRequestRouteChange(RouteInfo route) {
-            if (mRenderer != null) {
-                mRenderer.onStop();
-            }
-            if (route == null) {
-                // Use local route
-                mRoute = null;
-                mRenderer = new LocalRenderer(mContext, null);
-                mRenderer.registerListener(mRenderListener);
-                updateState(PlaybackState.STATE_NONE);
-            } else {
-                // Use remote route
-                mSession.connect(route, mRouteOptions.get(0));
-                mRenderer = null;
-                updateState(PlaybackState.STATE_CONNECTING);
-            }
-        }
-
-        @Override
-        public void onRouteConnected(Route route) {
-            mRoute = route;
-            mRouteControls = RoutePlaybackControls.from(route);
-            mRouteControls.addListener(mRouteListener);
-            Log.d(TAG, "Connected to route, registering listener");
-            mRenderer = new OneMRPRenderer(mRouteControls);
-            updateState(PlaybackState.STATE_NONE);
-        }
-
-        @Override
-        public void onRouteDisconnected(Route route, int reason) {
-
-        }
     }
 
     private class TransportCallback extends MediaSession.TransportControlsCallback {
@@ -266,12 +245,62 @@ public class PlayerSession {
         }
     }
 
-    private class RouteListener extends RoutePlaybackControls.Listener {
+    private class RoutingCallback extends MediaRouter.RoutingCallback {
         @Override
-        public void onPlaybackStateChange(int state) {
-            Log.d(TAG, "Updating state to " + state);
-            updateState(state);
+        public void onConnectionStateChanged(int state) {
+            if (state == MediaRouter.CONNECTION_STATE_CONNECTING) {
+                if (mRenderer != null) {
+                    mRenderer.onStop();
+                }
+                mRenderer = null;
+                updateState(PlaybackState.STATE_CONNECTING);
+                return;
+            }
+
+            MediaRouter.ConnectionInfo connection = mRouter.getConnection();
+            if (connection != null) {
+                MediaPlayerProtocol protocol =
+                        connection.getProtocolObject(MediaPlayerProtocol.class);
+                if (protocol != null) {
+                    Log.d(TAG, "Connected to route using media player protocol");
+
+                    protocol.setCallback(new PlayerCallback(), null);
+                    mRenderer = new OneMRPRenderer(protocol);
+                    updateState(PlaybackState.STATE_NONE);
+                    return;
+                }
+            }
+
+            // Use local route
+            mRenderer = new LocalRenderer(mContext, null);
+            mRenderer.registerListener(mRenderListener);
+            updateState(PlaybackState.STATE_NONE);
         }
     }
 
+    private class PlayerCallback extends MediaPlayerProtocol.Callback {
+        @Override
+        public void onStatusUpdated(MediaStatus status, Bundle extras) {
+            if (status != null) {
+                Log.d(TAG, "Received status update: " + status.toBundle());
+                switch (status.getPlayerState()) {
+                    case MediaStatus.PLAYER_STATE_BUFFERING:
+                        updateState(PlaybackState.STATE_BUFFERING);
+                        break;
+                    case MediaStatus.PLAYER_STATE_IDLE:
+                        updateState(PlaybackState.STATE_STOPPED);
+                        break;
+                    case MediaStatus.PLAYER_STATE_PAUSED:
+                        updateState(PlaybackState.STATE_PAUSED);
+                        break;
+                    case MediaStatus.PLAYER_STATE_PLAYING:
+                        updateState(PlaybackState.STATE_PLAYING);
+                        break;
+                    case MediaStatus.PLAYER_STATE_UNKNOWN:
+                        updateState(PlaybackState.STATE_NONE);
+                        break;
+                }
+            } 
+        }
+    }
 }
index 05516d2..c133325 100644 (file)
  */
 package com.android.onemedia.playback;
 
+import android.media.MediaMetadata;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.v7.media.MediaItemMetadata;
 
 /**
  * TODO: Insert description here. (generated by epastern)
@@ -35,11 +35,11 @@ public class MediaItem implements Parcelable {
     }
 
     public String getTitle() {
-        return mBundle.getString(MediaItemMetadata.KEY_TITLE);
+        return mBundle.getString(MediaMetadata.METADATA_KEY_TITLE);
     }
 
     public String getArtist() {
-        return mBundle.getString(MediaItemMetadata.KEY_ALBUM_ARTIST);
+        return mBundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST);
     }
 
     /* (non-Javadoc)
index 9b0a2b2..55eb92c 100644 (file)
@@ -1,39 +1,42 @@
 package com.android.onemedia.playback;
 
-import android.media.session.RoutePlaybackControls;
 import android.os.Bundle;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
 
 /**
  * Renderer for communicating with the OneMRP route
  */
 public class OneMRPRenderer extends Renderer {
-    private final RoutePlaybackControls mControls;
+    private final MediaPlayerProtocol mProtocol;
 
-    public OneMRPRenderer(RoutePlaybackControls controls) {
+    public OneMRPRenderer(MediaPlayerProtocol protocol) {
         super(null, null);
-        mControls = controls;
+        mProtocol = protocol;
     }
 
     @Override
     public void setContent(Bundle request) {
-        mControls.playNow(request.getString(RequestUtils.EXTRA_KEY_SOURCE));
+        MediaInfo mediaInfo = new MediaInfo(request.getString(RequestUtils.EXTRA_KEY_SOURCE),
+                MediaInfo.STREAM_TYPE_BUFFERED, "audio/mp3");
+        mProtocol.load(mediaInfo, true, 0, null);
     }
 
     @Override
     public boolean onStop() {
-        mControls.pause();
+        mProtocol.stop(null);
         return true;
     }
 
     @Override
     public boolean onPlay() {
-        mControls.resume();
+        mProtocol.play(null);
         return true;
     }
 
     @Override
     public boolean onPause() {
-        mControls.pause();
+        mProtocol.pause(null);
         return true;
     }
 
index dd0d982..3778c5f 100644 (file)
@@ -16,7 +16,6 @@
 package com.android.onemedia.playback;
 
 import android.os.Bundle;
-import android.support.v7.media.MediaItemMetadata;
 
 import java.util.HashMap;
 import java.util.Map;
index f2d691c..2e1478b 100644 (file)
  */
 package com.android.onemedia.provider;
 
-import android.media.routeprovider.RouteConnection;
-import android.media.routeprovider.RouteInterfaceHandler;
-import android.media.routeprovider.RoutePlaybackControlsHandler;
-import android.media.routeprovider.RouteProviderService;
-import android.media.routeprovider.RouteRequest;
-import android.media.session.RouteInfo;
-import android.media.session.RoutePlaybackControls;
-import android.media.session.RouteInterface;
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.MediaRouteService;
+import android.media.routing.MediaRouter.ConnectionInfo;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.DiscoveryRequest;
+import android.media.routing.MediaRouter.RouteInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
-import android.os.ResultReceiver;
+import android.os.Process;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
+import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
 import android.util.Log;
 
 import com.android.onemedia.playback.LocalRenderer;
@@ -35,29 +36,28 @@ import com.android.onemedia.playback.Renderer;
 import com.android.onemedia.playback.RequestUtils;
 
 import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
 
 /**
  * Test of MediaRouteProvider. Show a dummy provider with a simple interface for
  * playing music.
  */
-public class OneMediaRouteProvider extends RouteProviderService {
+public class OneMediaRouteProvider extends MediaRouteService {
     private static final String TAG = "OneMRP";
     private static final boolean DEBUG = true;
 
+    private static final String TEST_DESTINATION_ID = "testDestination";
+    private static final String TEST_ROUTE_ID = "testRoute";
+
     private Renderer mRenderer;
     private RenderListener mRenderListener;
     private PlaybackState mPlaybackState;
-    private RouteConnection mConnection;
-    private RoutePlaybackControlsHandler mControls;
-    private String mRouteId;
     private Handler mHandler;
 
+    private OneStub mStub;
+
     @Override
     public void onCreate() {
         mHandler = new Handler();
-        mRouteId = UUID.randomUUID().toString();
         mRenderer = new LocalRenderer(this, null);
         mRenderListener = new RenderListener();
         mPlaybackState = new PlaybackState();
@@ -65,81 +65,106 @@ public class OneMediaRouteProvider extends RouteProviderService {
                 | PlaybackState.ACTION_PLAY);
 
         mRenderer.registerListener(mRenderListener);
+    }
 
-        if (DEBUG) {
-            Log.d(TAG, "onCreate, routeId is " + mRouteId);
+    @Override
+    public ClientSession onCreateClientSession(ClientInfo client) {
+        if (client.getUid() != Process.myUid()) {
+            // for testing purposes, only allow connections from this application
+            // since this provider is not fully featured
+            return null;
         }
+        return new OneSession(client);
     }
 
-    @Override
-    public List<RouteInfo> getMatchingRoutes(List<RouteRequest> requests) {
-        RouteInfo.Builder bob = new RouteInfo.Builder();
-        bob.setName("OneMedia").setId(mRouteId);
-        // TODO add a helper library for generating route info with the correct
-        // options
-        Log.d(TAG, "Requests:");
-        for (RouteRequest request : requests) {
-            List<String> ifaces = request.getConnectionOptions().getInterfaceNames();
-            Log.d(TAG, "  request ifaces:" + ifaces.toString());
-            if (ifaces != null && ifaces.size() == 1
-                    && RoutePlaybackControls.NAME.equals(ifaces.get(0))) {
-                bob.addRouteOptions(request.getConnectionOptions());
+    private final class OneSession extends ClientSession {
+        private final ClientInfo mClient;
+
+        public OneSession(ClientInfo client) {
+            mClient = client;
+        }
+
+        @Override
+        public boolean onStartDiscovery(DiscoveryRequest req, DiscoveryCallback callback) {
+            for (MediaRouteSelector selector : req.getSelectors()) {
+                if (isMatch(selector)) {
+                    DestinationInfo destination = new DestinationInfo.Builder(
+                            TEST_DESTINATION_ID, getServiceMetadata(), "OneMedia")
+                            .setDescription("Test route from OneMedia app.")
+                            .build();
+                    ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
+                    routes.add(new RouteInfo.Builder(
+                            TEST_ROUTE_ID, destination, selector).build());
+                    callback.onDestinationFound(destination, routes);
+                    return true;
+                }
             }
+            return false;
         }
-        ArrayList<RouteInfo> result = new ArrayList<RouteInfo>();
-        if (bob.getOptionsSize() > 0) {
-            RouteInfo info = bob.build();
-            result.add(info);
+
+        @Override
+        public void onStopDiscovery() {
         }
-        if (DEBUG) {
-            Log.d(TAG, "getRoutes returning " + result.toString());
+
+        @Override
+        public boolean onConnect(ConnectionRequest req, ConnectionCallback callback) {
+            if (req.getRoute().getId().equals(TEST_ROUTE_ID)) {
+                mStub = new OneStub();
+                ConnectionInfo connection = new ConnectionInfo.Builder(req.getRoute())
+                        .setProtocolStub(MediaPlayerProtocol.class, mStub)
+                        .build();
+                callback.onConnected(connection);
+                return true;
+            }
+            return false;
         }
-        return result;
-    }
 
-    @Override
-    public RouteConnection connect(RouteInfo route, RouteRequest request) {
-        if (mConnection != null) {
-            disconnect(mConnection);
+        @Override
+        public void onDisconnect() {
+            mStub = null;
         }
-        RouteConnection connection = new RouteConnection(this, route);
-        mControls = RoutePlaybackControlsHandler.addTo(connection);
-        mControls.addListener(new PlayHandler(mRouteId), mHandler);
-        if (DEBUG) {
-            Log.d(TAG, "Connected to route");
+
+        private boolean isMatch(MediaRouteSelector selector) {
+            if (!selector.containsProtocol(MediaPlayerProtocol.class)) {
+                return false;
+            }
+            for (String protocol : selector.getRequiredProtocols()) {
+                if (!protocol.equals(MediaPlayerProtocol.class.getName())) {
+                    return false;
+                }
+            }
+            return true;
         }
-        return connection;
     }
 
-    private class PlayHandler extends RoutePlaybackControlsHandler.Listener {
-        private final String mRouteId;
+    private final class OneStub extends MediaPlayerProtocol.Stub {
+        MediaInfo mMediaInfo;
 
-        public PlayHandler(String routeId) {
-            mRouteId = routeId;
+        public OneStub() {
+            super(mHandler);
         }
 
         @Override
-        public void playNow(String content, ResultReceiver cb) {
+        public void onLoad(MediaInfo mediaInfo, boolean autoplay, long playPosition,
+                Bundle extras) {
             if (DEBUG) {
-                Log.d(TAG, "Attempting to play " + content);
+                Log.d(TAG, "Attempting to play " + mediaInfo.getContentId());
             }
             // look up the route and send a play command to it
+            mMediaInfo = mediaInfo;
             Bundle bundle = new Bundle();
-            bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, content);
+            bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, mediaInfo.getContentId());
             mRenderer.setContent(bundle);
-            RouteInterfaceHandler.sendResult(cb, RouteInterface.RESULT_SUCCESS, null);
         }
 
         @Override
-        public boolean resume() {
+        public void onPlay(Bundle extras) {
             mRenderer.onPlay();
-            return true;
         }
 
         @Override
-        public boolean pause() {
+        public void onPause(Bundle extras) {
             mRenderer.onPause();
-            return true;
         }
     }
 
@@ -148,9 +173,7 @@ public class OneMediaRouteProvider extends RouteProviderService {
         @Override
         public void onError(int type, int extra, Bundle extras, Throwable error) {
             Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
-            if (mControls != null) {
-                mControls.sendPlaybackChangeEvent(PlaybackState.STATE_ERROR);
-            }
+            sendStatusUpdate(PlaybackState.STATE_ERROR);
         }
 
         @Override
@@ -186,7 +209,7 @@ public class OneMediaRouteProvider extends RouteProviderService {
                     break;
             }
 
-            mControls.sendPlaybackChangeEvent(mPlaybackState.getState());
+            sendStatusUpdate(mPlaybackState.getState());
         }
 
         @Override
@@ -203,5 +226,36 @@ public class OneMediaRouteProvider extends RouteProviderService {
         @Override
         public void onNextStarted() {
         }
+
+        private void sendStatusUpdate(int state) {
+            if (mStub != null) {
+                MediaStatus status = new MediaStatus(1, mStub.mMediaInfo);
+                switch (state) {
+                    case PlaybackState.STATE_BUFFERING:
+                    case PlaybackState.STATE_FAST_FORWARDING:
+                    case PlaybackState.STATE_REWINDING:
+                    case PlaybackState.STATE_SKIPPING_TO_NEXT:
+                    case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_BUFFERING);
+                        break;
+                    case PlaybackState.STATE_CONNECTING:
+                    case PlaybackState.STATE_STOPPED:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_IDLE);
+                        break;
+                    case PlaybackState.STATE_PAUSED:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_PAUSED);
+                        break;
+                    case PlaybackState.STATE_PLAYING:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_PLAYING);
+                        break;
+                    case PlaybackState.STATE_NONE:
+                    case PlaybackState.STATE_ERROR:
+                    default:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_UNKNOWN);
+                        break;
+                }
+                mStub.sendStatusUpdatedEvent(status, null);
+            }
+        }
     }
 }