Loading media/java/android/media/MediaRouter.java +133 −28 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.display.WifiDisplay; import android.hardware.display.WifiDisplayStatus; import android.media.session.MediaSession; import android.media.session.RemoteVolumeProvider; import android.os.Handler; import android.os.IBinder; import android.os.Process; Loading Loading @@ -58,6 +60,7 @@ import java.util.concurrent.CopyOnWriteArrayList; public class MediaRouter { private static final String TAG = "MediaRouter"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean USE_SESSIONS = true; static class Static implements DisplayManager.DisplayListener { final Context mAppContext; Loading Loading @@ -1980,6 +1983,7 @@ public class MediaRouter { */ public static class UserRouteInfo extends RouteInfo { RemoteControlClient mRcc; SessionVolumeProvider mSvp; UserRouteInfo(RouteCategory category) { super(category); Loading Loading @@ -2100,9 +2104,13 @@ public class MediaRouter { public void setPlaybackType(int type) { if (mPlaybackType != type) { mPlaybackType = type; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); } } } /** * Defines whether volume for the playback associated with this route is fixed Loading @@ -2113,10 +2121,14 @@ public class MediaRouter { public void setVolumeHandling(int volumeHandling) { if (mVolumeHandling != volumeHandling) { mVolumeHandling = volumeHandling; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc( RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); } } } /** * Defines at what volume the playback associated with this route is performed (for user Loading @@ -2127,7 +2139,13 @@ public class MediaRouter { volume = Math.max(0, Math.min(volume, getVolumeMax())); if (mVolume != volume) { mVolume = volume; if (USE_SESSIONS) { if (mSvp != null) { mSvp.notifyVolumeChanged(); } } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); } dispatchRouteVolumeChanged(this); if (mGroup != null) { mGroup.memberVolumeChanged(this); Loading Loading @@ -2166,9 +2184,13 @@ public class MediaRouter { public void setVolumeMax(int volumeMax) { if (mVolumeMax != volumeMax) { mVolumeMax = volumeMax; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); } } } /** * Defines over what stream type the media is presented. Loading @@ -2177,12 +2199,20 @@ public class MediaRouter { public void setPlaybackStream(int stream) { if (mPlaybackStream != stream) { mPlaybackStream = stream; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); } } } private void updatePlaybackInfoOnRcc() { if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { if (USE_SESSIONS) { configureSessionVolume(); } else { if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { mRcc.setPlaybackInformation( RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); mRcc.setPlaybackInformation( Loading @@ -2193,7 +2223,8 @@ public class MediaRouter { RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); mRcc.setPlaybackInformation( RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); // let AudioService know whom to call when remote volume needs to be updated // let AudioService know whom to call when remote volume // needs to be updated try { sStatic.mAudioService.registerRemoteVolumeObserverForRcc( mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); Loading @@ -2202,12 +2233,86 @@ public class MediaRouter { } } } } private void configureSessionVolume() { if (mRcc == null) { if (DEBUG) { Log.d(TAG, "No Rcc to configure volume for route " + mName); } return; } MediaSession session = mRcc.getMediaSession(); if (session == null) { if (DEBUG) { Log.d(TAG, "Rcc has no session to configure volume"); } return; } if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { int volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_FIXED; switch (mVolumeHandling) { case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_ABSOLUTE; break; case RemoteControlClient.PLAYBACK_VOLUME_FIXED: default: break; } // Only register a new listener if necessary if (mSvp == null || mSvp.getVolumeControl() != volumeControl || mSvp.getMaxVolume() != mVolumeMax) { mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax); session.setPlaybackToRemote(mSvp); } } else { // We only know how to handle local and remote, fall back to local if not remote. session.setPlaybackToLocal(mPlaybackStream); mSvp = null; } } private void setPlaybackInfoOnRcc(int what, int value) { if (mRcc != null) { mRcc.setPlaybackInformation(what, value); } } class SessionVolumeProvider extends RemoteVolumeProvider { public SessionVolumeProvider(int volumeControl, int maxVolume) { super(volumeControl, maxVolume); } @Override public int onGetCurrentVolume() { return mVcb == null ? 0 : mVcb.route.mVolume; } @Override public void onSetVolumeTo(final int volume) { sStatic.mHandler.post(new Runnable() { @Override public void run() { if (mVcb != null) { mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); } } }); } @Override public void onAdjustVolumeBy(final int delta) { sStatic.mHandler.post(new Runnable() { @Override public void run() { if (mVcb != null) { mVcb.vcb.onVolumeUpdateRequest(mVcb.route, delta); } } }); } } } /** Loading media/java/android/media/session/MediaSession.java +31 −13 Original line number Diff line number Diff line Loading @@ -277,6 +277,7 @@ public final class MediaSession { throw new IllegalArgumentException("volumeProvider may not be null!"); } mVolumeProvider = volumeProvider; volumeProvider.setSession(this); try { mBinder.configureVolumeHandling(VOLUME_TYPE_REMOTE, volumeProvider.getVolumeControl(), Loading Loading @@ -522,6 +523,24 @@ public final class MediaSession { } } /** * Notify the system that the remove volume changed. * * @param provider The provider that is handling volume changes. * @hide */ void notifyRemoteVolumeChanged(RemoteVolumeProvider provider) { if (provider == null || provider != mVolumeProvider) { Log.w(TAG, "Received update from stale volume provider"); return; } try { mBinder.setCurrentVolume(provider.onGetCurrentVolume()); } catch (RemoteException e) { Log.e(TAG, "Error in notifyVolumeChanged", e); } } private void dispatchPlay() { postToTransportCallbacks(TransportMessageHandler.MSG_PLAY); } Loading Loading @@ -963,27 +982,26 @@ public final class MediaSession { @Override public void onRouteStateChange(int state) throws RemoteException { // TODO } /* * (non-Javadoc) * @see android.media.session.ISessionCallback#onAdjustVolumeBy(int) */ @Override public void onAdjustVolumeBy(int delta) throws RemoteException { // TODO(epastern): Auto-generated method stub MediaSession session = mMediaSession.get(); if (session != null) { if (session.mVolumeProvider != null) { session.mVolumeProvider.onAdjustVolumeBy(delta); } } } /* * (non-Javadoc) * @see android.media.session.ISessionCallback#onSetVolumeTo(int) */ @Override public void onSetVolumeTo(int value) throws RemoteException { // TODO(epastern): Auto-generated method stub MediaSession session = mMediaSession.get(); if (session != null) { if (session.mVolumeProvider != null) { session.mVolumeProvider.onSetVolumeTo(value); } } } } Loading media/java/android/media/session/RemoteVolumeProvider.java +14 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ package android.media.session; import android.os.RemoteException; import android.util.Log; /** * Handles requests to adjust or set the volume on a session. This is also used * to push volume updates back to the session after a request has been handled. Loading @@ -22,6 +25,7 @@ package android.media.session; * {@link MediaSession#setPlaybackToRemote}. */ public abstract class RemoteVolumeProvider { private static final String TAG = "RemoteVolumeProvider"; /** * The volume is fixed and can not be modified. Requests to change volume Loading @@ -46,6 +50,8 @@ public abstract class RemoteVolumeProvider { private final int mControlType; private final int mMaxVolume; private MediaSession mSession; /** * Create a new volume provider for handling volume events. You must specify * the type of volume control and the maximum volume that can be used. Loading Loading @@ -88,7 +94,7 @@ public abstract class RemoteVolumeProvider { * Notify the system that the remote playback's volume has been changed. */ public final void notifyVolumeChanged() { // TODO mSession.notifyRemoteVolumeChanged(this); } /** Loading @@ -107,4 +113,11 @@ public abstract class RemoteVolumeProvider { */ public void onAdjustVolumeBy(int delta) { } /** * @hide */ void setSession(MediaSession session) { mSession = session; } } No newline at end of file Loading
media/java/android/media/MediaRouter.java +133 −28 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.display.WifiDisplay; import android.hardware.display.WifiDisplayStatus; import android.media.session.MediaSession; import android.media.session.RemoteVolumeProvider; import android.os.Handler; import android.os.IBinder; import android.os.Process; Loading Loading @@ -58,6 +60,7 @@ import java.util.concurrent.CopyOnWriteArrayList; public class MediaRouter { private static final String TAG = "MediaRouter"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean USE_SESSIONS = true; static class Static implements DisplayManager.DisplayListener { final Context mAppContext; Loading Loading @@ -1980,6 +1983,7 @@ public class MediaRouter { */ public static class UserRouteInfo extends RouteInfo { RemoteControlClient mRcc; SessionVolumeProvider mSvp; UserRouteInfo(RouteCategory category) { super(category); Loading Loading @@ -2100,9 +2104,13 @@ public class MediaRouter { public void setPlaybackType(int type) { if (mPlaybackType != type) { mPlaybackType = type; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); } } } /** * Defines whether volume for the playback associated with this route is fixed Loading @@ -2113,10 +2121,14 @@ public class MediaRouter { public void setVolumeHandling(int volumeHandling) { if (mVolumeHandling != volumeHandling) { mVolumeHandling = volumeHandling; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc( RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); } } } /** * Defines at what volume the playback associated with this route is performed (for user Loading @@ -2127,7 +2139,13 @@ public class MediaRouter { volume = Math.max(0, Math.min(volume, getVolumeMax())); if (mVolume != volume) { mVolume = volume; if (USE_SESSIONS) { if (mSvp != null) { mSvp.notifyVolumeChanged(); } } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); } dispatchRouteVolumeChanged(this); if (mGroup != null) { mGroup.memberVolumeChanged(this); Loading Loading @@ -2166,9 +2184,13 @@ public class MediaRouter { public void setVolumeMax(int volumeMax) { if (mVolumeMax != volumeMax) { mVolumeMax = volumeMax; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); } } } /** * Defines over what stream type the media is presented. Loading @@ -2177,12 +2199,20 @@ public class MediaRouter { public void setPlaybackStream(int stream) { if (mPlaybackStream != stream) { mPlaybackStream = stream; if (USE_SESSIONS) { configureSessionVolume(); } else { setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); } } } private void updatePlaybackInfoOnRcc() { if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { if (USE_SESSIONS) { configureSessionVolume(); } else { if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { mRcc.setPlaybackInformation( RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); mRcc.setPlaybackInformation( Loading @@ -2193,7 +2223,8 @@ public class MediaRouter { RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); mRcc.setPlaybackInformation( RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); // let AudioService know whom to call when remote volume needs to be updated // let AudioService know whom to call when remote volume // needs to be updated try { sStatic.mAudioService.registerRemoteVolumeObserverForRcc( mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); Loading @@ -2202,12 +2233,86 @@ public class MediaRouter { } } } } private void configureSessionVolume() { if (mRcc == null) { if (DEBUG) { Log.d(TAG, "No Rcc to configure volume for route " + mName); } return; } MediaSession session = mRcc.getMediaSession(); if (session == null) { if (DEBUG) { Log.d(TAG, "Rcc has no session to configure volume"); } return; } if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { int volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_FIXED; switch (mVolumeHandling) { case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_ABSOLUTE; break; case RemoteControlClient.PLAYBACK_VOLUME_FIXED: default: break; } // Only register a new listener if necessary if (mSvp == null || mSvp.getVolumeControl() != volumeControl || mSvp.getMaxVolume() != mVolumeMax) { mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax); session.setPlaybackToRemote(mSvp); } } else { // We only know how to handle local and remote, fall back to local if not remote. session.setPlaybackToLocal(mPlaybackStream); mSvp = null; } } private void setPlaybackInfoOnRcc(int what, int value) { if (mRcc != null) { mRcc.setPlaybackInformation(what, value); } } class SessionVolumeProvider extends RemoteVolumeProvider { public SessionVolumeProvider(int volumeControl, int maxVolume) { super(volumeControl, maxVolume); } @Override public int onGetCurrentVolume() { return mVcb == null ? 0 : mVcb.route.mVolume; } @Override public void onSetVolumeTo(final int volume) { sStatic.mHandler.post(new Runnable() { @Override public void run() { if (mVcb != null) { mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); } } }); } @Override public void onAdjustVolumeBy(final int delta) { sStatic.mHandler.post(new Runnable() { @Override public void run() { if (mVcb != null) { mVcb.vcb.onVolumeUpdateRequest(mVcb.route, delta); } } }); } } } /** Loading
media/java/android/media/session/MediaSession.java +31 −13 Original line number Diff line number Diff line Loading @@ -277,6 +277,7 @@ public final class MediaSession { throw new IllegalArgumentException("volumeProvider may not be null!"); } mVolumeProvider = volumeProvider; volumeProvider.setSession(this); try { mBinder.configureVolumeHandling(VOLUME_TYPE_REMOTE, volumeProvider.getVolumeControl(), Loading Loading @@ -522,6 +523,24 @@ public final class MediaSession { } } /** * Notify the system that the remove volume changed. * * @param provider The provider that is handling volume changes. * @hide */ void notifyRemoteVolumeChanged(RemoteVolumeProvider provider) { if (provider == null || provider != mVolumeProvider) { Log.w(TAG, "Received update from stale volume provider"); return; } try { mBinder.setCurrentVolume(provider.onGetCurrentVolume()); } catch (RemoteException e) { Log.e(TAG, "Error in notifyVolumeChanged", e); } } private void dispatchPlay() { postToTransportCallbacks(TransportMessageHandler.MSG_PLAY); } Loading Loading @@ -963,27 +982,26 @@ public final class MediaSession { @Override public void onRouteStateChange(int state) throws RemoteException { // TODO } /* * (non-Javadoc) * @see android.media.session.ISessionCallback#onAdjustVolumeBy(int) */ @Override public void onAdjustVolumeBy(int delta) throws RemoteException { // TODO(epastern): Auto-generated method stub MediaSession session = mMediaSession.get(); if (session != null) { if (session.mVolumeProvider != null) { session.mVolumeProvider.onAdjustVolumeBy(delta); } } } /* * (non-Javadoc) * @see android.media.session.ISessionCallback#onSetVolumeTo(int) */ @Override public void onSetVolumeTo(int value) throws RemoteException { // TODO(epastern): Auto-generated method stub MediaSession session = mMediaSession.get(); if (session != null) { if (session.mVolumeProvider != null) { session.mVolumeProvider.onSetVolumeTo(value); } } } } Loading
media/java/android/media/session/RemoteVolumeProvider.java +14 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ package android.media.session; import android.os.RemoteException; import android.util.Log; /** * Handles requests to adjust or set the volume on a session. This is also used * to push volume updates back to the session after a request has been handled. Loading @@ -22,6 +25,7 @@ package android.media.session; * {@link MediaSession#setPlaybackToRemote}. */ public abstract class RemoteVolumeProvider { private static final String TAG = "RemoteVolumeProvider"; /** * The volume is fixed and can not be modified. Requests to change volume Loading @@ -46,6 +50,8 @@ public abstract class RemoteVolumeProvider { private final int mControlType; private final int mMaxVolume; private MediaSession mSession; /** * Create a new volume provider for handling volume events. You must specify * the type of volume control and the maximum volume that can be used. Loading Loading @@ -88,7 +94,7 @@ public abstract class RemoteVolumeProvider { * Notify the system that the remote playback's volume has been changed. */ public final void notifyVolumeChanged() { // TODO mSession.notifyRemoteVolumeChanged(this); } /** Loading @@ -107,4 +113,11 @@ public abstract class RemoteVolumeProvider { */ public void onAdjustVolumeBy(int delta) { } /** * @hide */ void setSession(MediaSession session) { mSession = session; } } No newline at end of file