OSDN Git Service

MediaSession2: Add a way to notify errors between session and player
authorJaewan Kim <jaewan@google.com>
Mon, 19 Feb 2018 03:19:13 +0000 (12:19 +0900)
committerJaewan Kim <jaewan@google.com>
Wed, 21 Feb 2018 17:02:43 +0000 (02:02 +0900)
This is proposed during the offline meeting

Test: Run all MediaComponents tests once
Change-Id: I3ebd6284792a934bf1411a447e65970ad53a1f42

media/java/android/media/MediaPlayerInterface.java
media/java/android/media/MediaSession2.java
media/java/android/media/PlaybackState2.java
media/java/android/media/update/MediaSession2Provider.java
media/java/android/media/update/PlaybackState2Provider.java
media/java/android/media/update/StaticProvider.java

index 78e2391..b81c3d6 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.media.MediaSession2.PlaylistParams;
@@ -29,13 +30,56 @@ import java.util.concurrent.Executor;
  */
 public interface MediaPlayerInterface {
     /**
-     * Listens change in {@link PlaybackState2}.
+     * Unspecified media player error.
      */
-    interface PlaybackListener {
+    int MEDIA_ERROR_UNKNOWN = MediaPlayer2.MEDIA_ERROR_UNKNOWN;
+
+    /**
+     * The video is streamed and its container is not valid for progressive
+     * playback i.e the video's index (e.g moov atom) is not at the start of the
+     * file.
+     */
+    int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK =
+            MediaPlayer2.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK;
+
+    /**
+     * File or network related operation errors.
+     */
+    int MEDIA_ERROR_IO = MediaPlayer2.MEDIA_ERROR_IO;
+
+    /**
+     * Bitstream is not conforming to the related coding standard or file spec.
+     */
+    int MEDIA_ERROR_MALFORMED = MediaPlayer2.MEDIA_ERROR_MALFORMED;
+
+    /**
+     * Bitstream is conforming to the related coding standard or file spec, but
+     * the media framework does not support the feature.
+     */
+    int MEDIA_ERROR_UNSUPPORTED = MediaPlayer2.MEDIA_ERROR_UNSUPPORTED;
+
+    /**
+     * Some operation takes too long to complete, usually more than 3-5 seconds.
+     */
+    int MEDIA_ERROR_TIMED_OUT = MediaPlayer2.MEDIA_ERROR_TIMED_OUT;
+
+    /**
+     * Callbacks to listens to the changes in {@link PlaybackState2} and error.
+     */
+    interface EventCallback {
         /**
          * Called when {@link PlaybackState2} for this player is changed.
          */
-        void onPlaybackChanged(PlaybackState2 state);
+        default void onPlaybackStateChanged(PlaybackState2 state) { }
+
+        /**
+         * Called to indicate an error.
+         *
+         * @param mediaId optional mediaId to indicate error
+         * @param what what
+         * @param extra
+         */
+        default void onError(@Nullable String mediaId, int what, int extra) { }
     }
 
     // Transport controls that session will send command directly to this player.
@@ -75,17 +119,18 @@ public interface MediaPlayerInterface {
     PlaylistParams getPlaylistParams();
 
     /**
-     * Add a {@link PlaybackListener} to be invoked when the playback state is changed.
+     * Register a {@link EventCallback}.
      *
-     * @param executor the Handler that will receive the listener
-     * @param listener the listener that will be run
+     * @param executor a callback executor
+     * @param callback a EventCallback
      */
-    void addPlaybackListener(Executor executor, PlaybackListener listener);
+    void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull EventCallback callback);
 
     /**
-     * Remove previously added {@link PlaybackListener}.
+     * Unregister previously registered {@link EventCallback}.
      *
-     * @param listener the listener to be removed
+     * @param callback a EventCallback
      */
-    void removePlaybackListener(PlaybackListener listener);
+    void unregisterEventCallback(@NonNull EventCallback callback);
 }
index 83b083a..63e4e65 100644 (file)
@@ -24,7 +24,7 @@ import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.media.MediaPlayerInterface.PlaybackListener;
+import android.media.MediaPlayerInterface.EventCallback;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.Callback;
 import android.media.session.PlaybackState;
@@ -41,7 +41,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.IInterface;
 import android.os.ResultReceiver;
-import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -1058,8 +1057,9 @@ public class MediaSession2 implements AutoCloseable {
      * to. Events from the {@link MediaController2} will be sent directly to the underlying
      * player on the {@link Handler} where the session is created on.
      * <p>
-     * If the new player is successfully set, {@link PlaybackListener}
-     * will be called to tell the current playback state of the new player.
+     * If the new player is successfully set,
+     * {@link EventCallback#onPlaybackStateChanged(PlaybackState2)} will be called to tell the
+     * current playback state of the new player.
      * <p>
      * For the remote playback case which you want to handle volume by yourself, use
      * {@link #setPlayer(MediaPlayerInterface, VolumeProvider2)}.
@@ -1325,28 +1325,28 @@ public class MediaSession2 implements AutoCloseable {
     }
 
     /*
-     * Add a {@link PlaybackListener} to listen changes in the underlying
-     * {@link MediaPlayerInterface}. Listener will be called immediately to tell the current value.
+     * Register {@link EventCallback} to listen changes in the underlying
+     * {@link MediaPlayerInterface}, regardless of the change in the underlying player.
      * <p>
-     * Added listeners will be also called when the underlying player is changed.
+     * Registered callbacks will be also called when the underlying player is changed.
      *
-     * @param executor the call listener
-     * @param listener the listener that will be run
-     * @throws IllegalArgumentException when either the listener or handler is {@code null}.
+     * @param executor a callback Executor
+     * @param callback a EventCallback
+     * @throws IllegalArgumentException if executor or callback is {@code null}.
      */
-    public void addPlaybackListener(@NonNull @CallbackExecutor Executor executor,
-            @NonNull PlaybackListener listener) {
-        mProvider.addPlaybackListener_impl(executor, listener);
+    public void registerPlayerEventCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull EventCallback callback) {
+        mProvider.registerPlayerEventCallback_impl(executor, callback);
     }
 
     /**
-     * Remove previously added {@link PlaybackListener}.
+     * Unregister the previously registered {@link EventCallback}.
      *
-     * @param listener the listener to be removed
-     * @throws IllegalArgumentException if the listener is {@code null}.
+     * @param callback the callback to be removed
+     * @throws IllegalArgumentException if the callback is {@code null}.
      */
-    public void removePlaybackListener(@NonNull PlaybackListener listener) {
-        mProvider.removePlaybackListener_impl(listener);
+    public void unregisterPlayerEventCallback(@NonNull EventCallback callback) {
+        mProvider.unregisterPlayerEventCallback_impl(callback);
     }
 
     /**
index 627974a..a95b8f2 100644 (file)
@@ -34,7 +34,7 @@ import java.lang.annotation.RetentionPolicy;
  * @hide
  */
 public final class PlaybackState2 {
-    // Similar to the PlaybackState2 with following changes
+    // Similar to the PlaybackState with following changes
     //    - Not implement Parcelable and added from/toBundle()
     //    - Removed playback state that doesn't match with the MediaPlayer2
     //      Full list should be finalized when the MediaPlayer2 has getter for the playback state.
@@ -73,6 +73,7 @@ public final class PlaybackState2 {
     //         |    EventCallback.onBufferingUpdate()   |                                        |
     //         +----------------------------------------+----------------------------------------+
     //    - Removed actions and custom actions.
+    //    - Removed error string
     //    - Repeat mode / shuffle mode is now in the PlaylistParams
     // TODO(jaewan): Replace states from MediaPlayer2
     /**
@@ -110,8 +111,7 @@ public final class PlaybackState2 {
     public final static int STATE_BUFFERING = 4;
 
     /**
-     * State indicating this item is currently in an error state. The error
-     * message should also be set when entering this state.
+     * State indicating this item is currently in an error state.
      */
     public final static int STATE_ERROR = 5;
 
@@ -122,13 +122,10 @@ public final class PlaybackState2 {
 
     private final PlaybackState2Provider mProvider;
 
-    // TODO(jaewan): Better error handling?
-    //               E.g. media item at #2 has issue, but continue playing #3
-    //                    login error. fire intent xxx to login
     public PlaybackState2(@NonNull Context context, int state, long position, long updateTime,
-            float speed, long bufferedPosition, long activeItemId, CharSequence error) {
+            float speed, long bufferedPosition, long activeItemId) {
         mProvider = ApiLoader.getProvider(context).createPlaybackState2(context, this, state,
-                position, updateTime, speed, bufferedPosition, activeItemId, error);
+                position, updateTime, speed, bufferedPosition, activeItemId);
     }
 
     @Override
@@ -141,10 +138,8 @@ public final class PlaybackState2 {
      * <ul>
      * <li> {@link PlaybackState2#STATE_NONE}</li>
      * <li> {@link PlaybackState2#STATE_STOPPED}</li>
-     * <li> {@link PlaybackState2#STATE_PREPARED}</li>
      * <li> {@link PlaybackState2#STATE_PAUSED}</li>
      * <li> {@link PlaybackState2#STATE_PLAYING}</li>
-     * <li> {@link PlaybackState2#STATE_FINISH}</li>
      * <li> {@link PlaybackState2#STATE_BUFFERING}</li>
      * <li> {@link PlaybackState2#STATE_ERROR}</li>
      * </ul>
@@ -182,14 +177,6 @@ public final class PlaybackState2 {
     }
 
     /**
-     * Get a user readable error message. This should be set when the state is
-     * {@link PlaybackState2#STATE_ERROR}.
-     */
-    public CharSequence getErrorMessage() {
-        return mProvider.getErrorMessage_impl();
-    }
-
-    /**
      * Get the elapsed real time at which position was last updated. If the
      * position has never been set this will return 0;
      *
index 159e230..fc1f671 100644 (file)
@@ -20,7 +20,7 @@ import android.app.PendingIntent;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
 import android.media.MediaPlayerInterface;
-import android.media.MediaPlayerInterface.PlaybackListener;
+import android.media.MediaPlayerInterface.EventCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
@@ -61,8 +61,8 @@ public interface MediaSession2Provider extends TransportControlProvider {
     void setPlaylistParams_impl(PlaylistParams params);
     PlaylistParams getPlaylistParams_impl();
 
-    void addPlaybackListener_impl(Executor executor, PlaybackListener listener);
-    void removePlaybackListener_impl(PlaybackListener listener);
+    void registerPlayerEventCallback_impl(Executor executor, EventCallback callback);
+    void unregisterPlayerEventCallback_impl(EventCallback callback);
 
     interface CommandProvider {
         int getCommandCode_impl();
index 2875e98..93f769c 100644 (file)
@@ -33,8 +33,6 @@ public interface PlaybackState2Provider {
 
     float getPlaybackSpeed_impl();
 
-    CharSequence getErrorMessage_impl();
-
     long getLastPositionUpdateTime_impl();
 
     long getCurrentPlaylistItemIndex_impl();
index 4f6f09b..29a3034 100644 (file)
@@ -133,7 +133,6 @@ public interface StaticProvider {
     Rating2 newPercentageRating_Rating2(Context context, float percent);
 
     PlaybackState2Provider createPlaybackState2(Context context, PlaybackState2 instance, int state,
-            long position, long updateTime, float speed, long bufferedPosition, long activeItemId,
-            CharSequence error);
+            long position, long updateTime, float speed, long bufferedPosition, long activeItemId);
     PlaybackState2 fromBundle_PlaybackState2(Context context, Bundle bundle);
 }