Loading api/current.txt +6 −1 Original line number Diff line number Diff line Loading @@ -23008,8 +23008,9 @@ package android.media { field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } public class MediaPlayer implements android.media.VolumeAutomation { public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { ctor public MediaPlayer(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; Loading @@ -23031,6 +23032,8 @@ package android.media { method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); Loading @@ -23046,6 +23049,7 @@ package android.media { method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException; method public void seekTo(long, int); Loading Loading @@ -23082,6 +23086,7 @@ package android.media { method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener); method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setPlaybackParams(android.media.PlaybackParams); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); method public void setSyncParams(android.media.SyncParams); api/system-current.txt +6 −1 Original line number Diff line number Diff line Loading @@ -24901,8 +24901,9 @@ package android.media { field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } public class MediaPlayer implements android.media.VolumeAutomation { public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { ctor public MediaPlayer(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; Loading @@ -24924,6 +24925,8 @@ package android.media { method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); Loading @@ -24939,6 +24942,7 @@ package android.media { method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException; method public void seekTo(long, int); Loading Loading @@ -24975,6 +24979,7 @@ package android.media { method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener); method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setPlaybackParams(android.media.PlaybackParams); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); method public void setSyncParams(android.media.SyncParams); api/test-current.txt +6 −1 Original line number Diff line number Diff line Loading @@ -23211,8 +23211,9 @@ package android.media { field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } public class MediaPlayer implements android.media.VolumeAutomation { public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { ctor public MediaPlayer(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; Loading @@ -23234,6 +23235,8 @@ package android.media { method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); Loading @@ -23249,6 +23252,7 @@ package android.media { method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException; method public void seekTo(long, int); Loading Loading @@ -23285,6 +23289,7 @@ package android.media { method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener); method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setPlaybackParams(android.media.PlaybackParams); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); method public void setSyncParams(android.media.SyncParams); media/java/android/media/MediaPlayer.java +163 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.system.Os; import android.system.OsConstants; import android.util.Log; import android.util.Pair; import android.util.ArrayMap; import android.view.Surface; import android.view.SurfaceHolder; import android.widget.VideoView; Loading @@ -58,6 +59,7 @@ import android.media.SubtitleData; import android.media.SubtitleTrack.RenderingWidget; import android.media.SyncParams; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import libcore.io.IoBridge; Loading Loading @@ -577,6 +579,7 @@ import java.util.Vector; public class MediaPlayer extends PlayerBase implements SubtitleController.Listener , VolumeAutomation , AudioRouting { /** Constant to retrieve only the new metadata since the last Loading Loading @@ -1417,6 +1420,155 @@ public class MediaPlayer extends PlayerBase private native @Nullable VolumeShaper.State native_getVolumeShaperState(int id); //-------------------------------------------------------------------------- // Explicit Routing //-------------------- private AudioDeviceInfo mPreferredDevice = null; /** * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route * the output from this MediaPlayer. * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source. * If deviceInfo is null, default routing is restored. * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and * does not correspond to a valid audio device. */ @Override public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { if (deviceInfo != null && !deviceInfo.isSink()) { return false; } int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0; boolean status = native_setOutputDevice(preferredDeviceId); if (status == true) { synchronized (this) { mPreferredDevice = deviceInfo; } } return status; } /** * Returns the selected output specified by {@link #setPreferredDevice}. Note that this * is not guaranteed to correspond to the actual device being used for playback. */ @Override public AudioDeviceInfo getPreferredDevice() { synchronized (this) { return mPreferredDevice; } } /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer * Note: The query is only valid if the MediaPlayer is currently playing. * If the player is not playing, the returned device can be null or correspond to previously * selected device when the player was last active. */ @Override public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); if (deviceId == 0) { return null; } AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS); for (int i = 0; i < devices.length; i++) { if (devices[i].getId() == deviceId) { return devices[i]; } } return null; } /* * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler. */ private void enableNativeRoutingCallbacksLocked(boolean enabled) { if (mRoutingChangeListeners.size() == 0) { native_enableDeviceCallback(enabled); } } /** * The list of AudioRouting.OnRoutingChangedListener interfaces added (with * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)} * by an app to receive (re)routing notifications. */ @GuardedBy("mRoutingChangeListeners") private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>(); /** * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing * changes on this MediaPlayer. * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive * notifications of rerouting events. * @param handler Specifies the {@link Handler} object for the thread on which to execute * the callback. If <code>null</code>, the handler on the main looper will be used. */ @Override public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, Handler handler) { synchronized (mRoutingChangeListeners) { if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { enableNativeRoutingCallbacksLocked(true); mRoutingChangeListeners.put( listener, new NativeRoutingEventHandlerDelegate(this, listener, handler)); } } } /** * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added * to receive rerouting notifications. * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface * to remove. */ @Override public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { synchronized (mRoutingChangeListeners) { if (mRoutingChangeListeners.containsKey(listener)) { mRoutingChangeListeners.remove(listener); enableNativeRoutingCallbacksLocked(false); } } } /** * Helper class to handle the forwarding of native events to the appropriate listener * (potentially) handled in a different thread */ private class NativeRoutingEventHandlerDelegate { private MediaPlayer mMediaPlayer; private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener; private Handler mHandler; NativeRoutingEventHandlerDelegate(final MediaPlayer mediaPlayer, final AudioRouting.OnRoutingChangedListener listener, Handler handler) { mMediaPlayer = mediaPlayer; mOnRoutingChangedListener = listener; mHandler = handler != null ? handler : mEventHandler; } void notifyClient() { if (mHandler != null) { mHandler.post(new Runnable() { @Override public void run() { if (mOnRoutingChangedListener != null) { mOnRoutingChangedListener.onRoutingChanged(mMediaPlayer); } } }); } } } private native final boolean native_setOutputDevice(int deviceId); private native final int native_getRoutedDeviceId(); private native final void native_enableDeviceCallback(boolean enabled); /** * Set the low-level power management behavior for this MediaPlayer. This * can be used when the MediaPlayer is not playing through a SurfaceHolder Loading Loading @@ -3176,6 +3328,7 @@ public class MediaPlayer extends PlayerBase private static final int MEDIA_SUBTITLE_DATA = 201; private static final int MEDIA_META_DATA = 202; private static final int MEDIA_DRM_INFO = 210; private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000; private TimeProvider mTimeProvider; Loading Loading @@ -3414,6 +3567,16 @@ public class MediaPlayer extends PlayerBase case MEDIA_NOP: // interface test message - ignore break; case MEDIA_AUDIO_ROUTING_CHANGED: AudioManager.resetAudioPortGeneration(); synchronized (mRoutingChangeListeners) { for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { delegate.notifyClient(); } } return; default: Log.e(TAG, "Unknown message type " + msg.what); return; Loading media/jni/android_media_MediaPlayer.cpp +43 −0 Original line number Diff line number Diff line Loading @@ -1387,6 +1387,44 @@ static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz) // Modular DRM end // ---------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////////// // AudioRouting begin static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { return false; } return mp->setOutputDevice(device_id) == NO_ERROR; } static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { return AUDIO_PORT_HANDLE_NONE; } return mp->getRoutedDeviceId(); } static void android_media_MediaPlayer_enableDeviceCallback( JNIEnv* env, jobject thiz, jboolean enabled) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { return; } status_t status = mp->enableAudioDeviceCallback(enabled); if (status != NO_ERROR) { jniThrowException(env, "java/lang/IllegalStateException", NULL); ALOGE("enable device callback failed: %d", status); } } // AudioRouting end // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { { "nativeSetDataSource", Loading Loading @@ -1448,6 +1486,11 @@ static const JNINativeMethod gMethods[] = { // Modular DRM { "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm }, { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm }, // AudioRouting {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice}, {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId}, {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback}, }; // This function only registers the native methods Loading Loading
api/current.txt +6 −1 Original line number Diff line number Diff line Loading @@ -23008,8 +23008,9 @@ package android.media { field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } public class MediaPlayer implements android.media.VolumeAutomation { public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { ctor public MediaPlayer(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; Loading @@ -23031,6 +23032,8 @@ package android.media { method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); Loading @@ -23046,6 +23049,7 @@ package android.media { method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException; method public void seekTo(long, int); Loading Loading @@ -23082,6 +23086,7 @@ package android.media { method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener); method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setPlaybackParams(android.media.PlaybackParams); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); method public void setSyncParams(android.media.SyncParams);
api/system-current.txt +6 −1 Original line number Diff line number Diff line Loading @@ -24901,8 +24901,9 @@ package android.media { field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } public class MediaPlayer implements android.media.VolumeAutomation { public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { ctor public MediaPlayer(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; Loading @@ -24924,6 +24925,8 @@ package android.media { method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); Loading @@ -24939,6 +24942,7 @@ package android.media { method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException; method public void seekTo(long, int); Loading Loading @@ -24975,6 +24979,7 @@ package android.media { method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener); method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setPlaybackParams(android.media.PlaybackParams); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); method public void setSyncParams(android.media.SyncParams);
api/test-current.txt +6 −1 Original line number Diff line number Diff line Loading @@ -23211,8 +23211,9 @@ package android.media { field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } public class MediaPlayer implements android.media.VolumeAutomation { public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { ctor public MediaPlayer(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; Loading @@ -23234,6 +23235,8 @@ package android.media { method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); Loading @@ -23249,6 +23252,7 @@ package android.media { method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException; method public void seekTo(long, int); Loading Loading @@ -23285,6 +23289,7 @@ package android.media { method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener); method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setPlaybackParams(android.media.PlaybackParams); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); method public void setSyncParams(android.media.SyncParams);
media/java/android/media/MediaPlayer.java +163 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.system.Os; import android.system.OsConstants; import android.util.Log; import android.util.Pair; import android.util.ArrayMap; import android.view.Surface; import android.view.SurfaceHolder; import android.widget.VideoView; Loading @@ -58,6 +59,7 @@ import android.media.SubtitleData; import android.media.SubtitleTrack.RenderingWidget; import android.media.SyncParams; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import libcore.io.IoBridge; Loading Loading @@ -577,6 +579,7 @@ import java.util.Vector; public class MediaPlayer extends PlayerBase implements SubtitleController.Listener , VolumeAutomation , AudioRouting { /** Constant to retrieve only the new metadata since the last Loading Loading @@ -1417,6 +1420,155 @@ public class MediaPlayer extends PlayerBase private native @Nullable VolumeShaper.State native_getVolumeShaperState(int id); //-------------------------------------------------------------------------- // Explicit Routing //-------------------- private AudioDeviceInfo mPreferredDevice = null; /** * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route * the output from this MediaPlayer. * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source. * If deviceInfo is null, default routing is restored. * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and * does not correspond to a valid audio device. */ @Override public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { if (deviceInfo != null && !deviceInfo.isSink()) { return false; } int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0; boolean status = native_setOutputDevice(preferredDeviceId); if (status == true) { synchronized (this) { mPreferredDevice = deviceInfo; } } return status; } /** * Returns the selected output specified by {@link #setPreferredDevice}. Note that this * is not guaranteed to correspond to the actual device being used for playback. */ @Override public AudioDeviceInfo getPreferredDevice() { synchronized (this) { return mPreferredDevice; } } /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer * Note: The query is only valid if the MediaPlayer is currently playing. * If the player is not playing, the returned device can be null or correspond to previously * selected device when the player was last active. */ @Override public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); if (deviceId == 0) { return null; } AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS); for (int i = 0; i < devices.length; i++) { if (devices[i].getId() == deviceId) { return devices[i]; } } return null; } /* * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler. */ private void enableNativeRoutingCallbacksLocked(boolean enabled) { if (mRoutingChangeListeners.size() == 0) { native_enableDeviceCallback(enabled); } } /** * The list of AudioRouting.OnRoutingChangedListener interfaces added (with * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)} * by an app to receive (re)routing notifications. */ @GuardedBy("mRoutingChangeListeners") private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>(); /** * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing * changes on this MediaPlayer. * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive * notifications of rerouting events. * @param handler Specifies the {@link Handler} object for the thread on which to execute * the callback. If <code>null</code>, the handler on the main looper will be used. */ @Override public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, Handler handler) { synchronized (mRoutingChangeListeners) { if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { enableNativeRoutingCallbacksLocked(true); mRoutingChangeListeners.put( listener, new NativeRoutingEventHandlerDelegate(this, listener, handler)); } } } /** * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added * to receive rerouting notifications. * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface * to remove. */ @Override public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { synchronized (mRoutingChangeListeners) { if (mRoutingChangeListeners.containsKey(listener)) { mRoutingChangeListeners.remove(listener); enableNativeRoutingCallbacksLocked(false); } } } /** * Helper class to handle the forwarding of native events to the appropriate listener * (potentially) handled in a different thread */ private class NativeRoutingEventHandlerDelegate { private MediaPlayer mMediaPlayer; private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener; private Handler mHandler; NativeRoutingEventHandlerDelegate(final MediaPlayer mediaPlayer, final AudioRouting.OnRoutingChangedListener listener, Handler handler) { mMediaPlayer = mediaPlayer; mOnRoutingChangedListener = listener; mHandler = handler != null ? handler : mEventHandler; } void notifyClient() { if (mHandler != null) { mHandler.post(new Runnable() { @Override public void run() { if (mOnRoutingChangedListener != null) { mOnRoutingChangedListener.onRoutingChanged(mMediaPlayer); } } }); } } } private native final boolean native_setOutputDevice(int deviceId); private native final int native_getRoutedDeviceId(); private native final void native_enableDeviceCallback(boolean enabled); /** * Set the low-level power management behavior for this MediaPlayer. This * can be used when the MediaPlayer is not playing through a SurfaceHolder Loading Loading @@ -3176,6 +3328,7 @@ public class MediaPlayer extends PlayerBase private static final int MEDIA_SUBTITLE_DATA = 201; private static final int MEDIA_META_DATA = 202; private static final int MEDIA_DRM_INFO = 210; private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000; private TimeProvider mTimeProvider; Loading Loading @@ -3414,6 +3567,16 @@ public class MediaPlayer extends PlayerBase case MEDIA_NOP: // interface test message - ignore break; case MEDIA_AUDIO_ROUTING_CHANGED: AudioManager.resetAudioPortGeneration(); synchronized (mRoutingChangeListeners) { for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { delegate.notifyClient(); } } return; default: Log.e(TAG, "Unknown message type " + msg.what); return; Loading
media/jni/android_media_MediaPlayer.cpp +43 −0 Original line number Diff line number Diff line Loading @@ -1387,6 +1387,44 @@ static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz) // Modular DRM end // ---------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////////// // AudioRouting begin static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { return false; } return mp->setOutputDevice(device_id) == NO_ERROR; } static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { return AUDIO_PORT_HANDLE_NONE; } return mp->getRoutedDeviceId(); } static void android_media_MediaPlayer_enableDeviceCallback( JNIEnv* env, jobject thiz, jboolean enabled) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { return; } status_t status = mp->enableAudioDeviceCallback(enabled); if (status != NO_ERROR) { jniThrowException(env, "java/lang/IllegalStateException", NULL); ALOGE("enable device callback failed: %d", status); } } // AudioRouting end // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { { "nativeSetDataSource", Loading Loading @@ -1448,6 +1486,11 @@ static const JNINativeMethod gMethods[] = { // Modular DRM { "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm }, { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm }, // AudioRouting {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice}, {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId}, {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback}, }; // This function only registers the native methods Loading