/* * ServeStream: A HTTP stream browser/player for Android * Copyright 2013 William Seemann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.servestream.media; import java.io.FileDescriptor; import java.io.IOException; import android.content.Context; import android.media.AudioManager; /** * Provides a unified interface for dealing with audio files and * other media files. */ public abstract class AbstractMediaPlayer { /** * Default constructor. * <p>When done with the MediaPlayer, you should call {@link #release()}, * to free the resources. If not released, too many MediaPlayer instances may * result in an exception.</p> */ protected AbstractMediaPlayer() { } /** * Sets the data source (file-path or http/rtsp URL) to use. * * @param context the current context * @param id the database identifier of the file to play * * <p>When <code>path</code> refers to a local file, the file may actually be opened by a * process other than the calling application. This implies that the pathname * should be an absolute path (as any other process runs with unspecified current working * directory), and that the pathname should reference a world-readable file. * As an alternative, the application could first open the file for reading, * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}. */ public abstract void setDataSource(Context context, long id) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; /** * Sets the data source (file-path or http/rtsp URL) to use. * * @param path the path of the file, or the http/rtsp URL of the stream you want to play * @throws IllegalStateException if it is called in an invalid state * * <p>When <code>path</code> refers to a local file, the file may actually be opened by a * process other than the calling application. This implies that the pathname * should be an absolute path (as any other process runs with unspecified current working * directory), and that the pathname should reference a world-readable file. * As an alternative, the application could first open the file for reading, * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}. */ public abstract void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; /** * Prepares the player for playback, synchronously. * * After setting the datasource and the display surface, you need to either * call prepare() or prepareAsync(). For files, it is OK to call prepare(), * which blocks until MediaPlayer is ready for playback. * * @throws IllegalStateException if it is called in an invalid state */ public abstract void prepare() throws IOException, IllegalStateException; /** * Prepares the player for playback, asynchronously. * * After setting the datasource and the display surface, you need to either * call prepare() or prepareAsync(). For streams, you should call prepareAsync(), * which returns immediately, rather than blocking until enough data has been * buffered. * * @throws IllegalStateException if it is called in an invalid state */ public abstract void prepareAsync() throws IllegalStateException; /** * Starts or resumes playback. If playback had previously been paused, * playback will continue from where it was paused. If playback had * been stopped, or never started before, playback will start at the * beginning. * * @throws IllegalStateException if it is called in an invalid state */ public abstract void start() throws IllegalStateException; /** * Stops playback after playback has been stopped or paused. * * @throws IllegalStateException if the internal player engine has not been * initialized. */ public abstract void stop() throws IllegalStateException; /** * Pauses playback. Call start() to resume. * * @throws IllegalStateException if the internal player engine has not been * initialized. */ public abstract void pause() throws IllegalStateException; /** * Seeks to specified time position. * * @param msec the offset in milliseconds from the start to seek to * @throws IllegalStateException if the internal player engine has not been * initialized */ public abstract void seekTo(int msec) throws IllegalStateException; /** * Gets the current playback position. * * @return the current position in milliseconds */ public abstract int getCurrentPosition(); /** * Gets the duration of the file. * * @return the duration in milliseconds */ public abstract int getDuration(); /** * Set the MediaPlayer to start when this MediaPlayer finishes playback * (i.e. reaches the end of the stream). * The media framework will attempt to transition from this player to * the next as seamlessly as possible. The next player can be set at * any time before completion. The next player must be prepared by the * app, and the application should not call start() on it. * The next MediaPlayer must be different from 'this'. An exception * will be thrown if next == this. * The application may call setNextMediaPlayer(null) to indicate no * next player should be started at the end of playback. * If the current player is looping, it will keep looping and the next * player will not be started. * * @param next the player to start after this one completes playback. * */ // TODO add this back //public abstract void setNextMediaPlayer(AbstractMediaPlayer next); /** * Releases resources associated with this MediaPlayer object. * It is considered good practice to call this method when you're * done using the MediaPlayer. In particular, whenever an Activity * of an application is paused (its onPause() method is called), * or stopped (its onStop() method is called), this method should be * invoked to release the MediaPlayer object, unless the application * has a special need to keep the object around. In addition to * unnecessary resources (such as memory and instances of codecs) * being held, failure to call this method immediately if a * MediaPlayer object is no longer needed may also lead to * continuous battery consumption for mobile devices, and playback * failure for other applications if no multiple instances of the * same codec are supported on a device. Even if multiple instances * of the same codec are supported, some performance degradation * may be expected when unnecessary multiple instances are used * at the same time. */ public abstract void release(); /** * Resets the MediaPlayer to its uninitialized state. After calling * this method, you will have to initialize it again by setting the * data source and calling prepare(). */ public abstract void reset(); /** * Sets the volume on this player. * This API is recommended for balancing the output of audio streams * within an application. Unless you are writing an application to * control user settings, this API should be used in preference to * {@link AudioManager#setStreamVolume(int, int, int)} which sets the volume of ALL streams of * a particular type. Note that the passed volume values are raw scalars. * UI controls should be scaled logarithmically. * * @param leftVolume left volume scalar * @param rightVolume right volume scalar */ public abstract void setVolume(float leftVolume, float rightVolume); /** * Sets the audio session ID. * * @param sessionId the audio session ID. * The audio session ID is a system wide unique identifier for the audio stream played by * this MediaPlayer instance. * The primary use of the audio session ID is to associate audio effects to a particular * instance of MediaPlayer: if an audio session ID is provided when creating an audio effect, * this effect will be applied only to the audio content of media players within the same * audio session and not to the output mix. * When created, a MediaPlayer instance automatically generates its own audio session ID. * However, it is possible to force this player to be part of an already existing audio session * by calling this method. * This method must be called before one of the overloaded <code> setDataSource </code> methods. * @throws IllegalStateException if it is called in an invalid state */ public abstract void setAudioSessionId(int sessionId) throws IllegalArgumentException, IllegalStateException; /** * Returns the audio session ID. * * @return the audio session ID. {@see #setAudioSessionId(int)} * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer was contructed. */ public abstract int getAudioSessionId(); /** * Interface definition for a callback to be invoked when the media * source is ready for playback. */ public interface OnPreparedListener { /** * Called when the media file is ready for playback. * * @param mp the MediaPlayer that is ready for playback */ void onPrepared(AbstractMediaPlayer mp); } /** * Register a callback to be invoked when the media source is ready * for playback. * * @param listener the callback that will be run */ public void setOnPreparedListener(OnPreparedListener listener) { mOnPreparedListener = listener; } protected OnPreparedListener mOnPreparedListener; /** * Interface definition for a callback to be invoked when playback of * a media source has completed. */ public interface OnCompletionListener { /** * Called when the end of a media source is reached during playback. * * @param mp the MediaPlayer that reached the end of the file */ void onCompletion(AbstractMediaPlayer mp); } /** * Register a callback to be invoked when the end of a media source * has been reached during playback. * * @param listener the callback that will be run */ public void setOnCompletionListener(OnCompletionListener listener) { mOnCompletionListener = listener; } protected OnCompletionListener mOnCompletionListener; /** * Interface definition of a callback to be invoked when there * has been an error during an asynchronous operation (other errors * will throw exceptions at method call time). */ public interface OnErrorListener { /** * Called to indicate an error. * * @param mp the MediaPlayer the error pertains to * @param what the type of error that has occurred: * <ul> * <li>{@link #MEDIA_ERROR_UNKNOWN} * <li>{@link #MEDIA_ERROR_SERVER_DIED} * </ul> * @param extra an extra code, specific to the error. Typically * implementation dependent. * <ul> * <li>{@link #MEDIA_ERROR_IO} * <li>{@link #MEDIA_ERROR_MALFORMED} * <li>{@link #MEDIA_ERROR_UNSUPPORTED} * <li>{@link #MEDIA_ERROR_TIMED_OUT} * </ul> * @return True if the method handled the error, false if it didn't. * Returning false, or not having an OnErrorListener at all, will * cause the OnCompletionListener to be called. */ boolean onError(AbstractMediaPlayer mp, int what, int extra); } /** * Register a callback to be invoked when an error has happened * during an asynchronous operation. * * @param listener the callback that will be run */ public void setOnErrorListener(OnErrorListener listener) { mOnErrorListener = listener; } protected OnErrorListener mOnErrorListener; /** * Interface definition of a callback to be invoked to communicate some * info and/or warning about the media or its playback. */ public interface OnInfoListener { /** * Called to indicate an info or a warning. * * @param mp the MediaPlayer the info pertains to. * @param what the type of info or warning. * <ul> * <li>{@link #MEDIA_INFO_UNKNOWN} * <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING} * <li>{@link #MEDIA_INFO_BUFFERING_START} * <li>{@link #MEDIA_INFO_BUFFERING_END} * <li>{@link #MEDIA_INFO_BAD_INTERLEAVING} * <li>{@link #MEDIA_INFO_NOT_SEEKABLE} * <li>{@link #MEDIA_INFO_METADATA_UPDATE} * </ul> * @param extra an extra code, specific to the info. Typically * implementation dependant. * @return True if the method handled the info, false if it didn't. * Returning false, or not having an OnErrorListener at all, will * cause the info to be discarded. */ boolean onInfo(AbstractMediaPlayer mp, int what, int extra); } /** A new set of metadata is available. * @see android.media.MediaPlayer.OnInfoListener */ public static final int MEDIA_INFO_METADATA_UPDATE = 802; /** * Register a callback to be invoked when an info/warning is available. * * @param listener the callback that will be run */ public void setOnInfoListener(OnInfoListener listener) { mOnInfoListener = listener; } protected OnInfoListener mOnInfoListener; }