package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.MediaSession2.PlaylistParams;
*/
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.
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);
}
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;
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;
* 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)}.
}
/*
- * 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);
}
/**
* @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.
// | 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
/**
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;
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
* <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>
}
/**
- * 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;
*
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;
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();
float getPlaybackSpeed_impl();
- CharSequence getErrorMessage_impl();
-
long getLastPositionUpdateTime_impl();
long getCurrentPlaylistItemIndex_impl();
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);
}