Android MediaPlayer state machine



 

 

 

 

 

 

Control of playing audio/video files and streams is managed through a state machine. The following figure shows the lifecycle and states of a MediaPlayer object supported by playback control operations. The ellipse represents the state in which the MediaPlayer object may reside. The arcs represent playback control operations that drive MediaPlayer transitions between states. There are two types of arcs here. Arcs starting with one arrow represent synchronous method calls, while arcs starting with double arrows represent asynchronous method calls.
 
Android MediaPlayer state machine

Through this picture, we can know that a MediaPlayer object has the following states:

1) When a MediaPlayer object is just created with the new operator or the reset() method is called, it is in the Idle state. When the release() method is called, it is in the End state. Between these two states is the life cycle of the MediaPlayer object.
1.1) There is a small but important difference between a newly constructed MediaPlayer object and a MediaPlayer object whose reset() method is called. In Idle state, call getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop( ), seekTo(int), prepare() or prepareAsync() methods are programming errors. When a MediaPlayer object is just constructed, the internal playback engine and the state of the object have not changed. If the above methods are called at this time, the framework will not be able to call back the OnErrorListener.onError() method registered by the client program; but if this After the MediaPlayer object calls the reset() method, and then calls the above methods, the internal playback engine will call back the OnErrorListener.onError() method registered by the client program, and pass in the error status.
1.2) We recommend that once a MediaPlayer object is no longer in use, the release() method should be called immediately to release the resources associated with the MediaPlayer object in the internal playback engine. The resources may include monomorphic components such as hardware acceleration components. If the release() method is not called, subsequent instances of the MediaPlayer object may not be able to use such monomorphic hardware resources, thus returning to software implementation or failing to run. Once the MediaPlayer object enters the End state, it can no longer be used, and there is no way to move to another state.
1.3) In addition, MediaPlayer objects created with the new operator are in the Idle state, while those created by the overloaded create() convenience method are not in the Idle state. In fact, if the overloaded create() method is successfully called, then the objects are already in the Prepare state.

2) In general, some playback control operations may fail due to various reasons, such as unsupported audio/video formats, lack of interlaced audio/video, too high resolution, stream timeout, etc. Therefore, error reporting and recovery are very important in this case. Occasionally, due to a programming error, it may happen that a playback control operation is called while in an invalid state. In all of these error conditions, the internal playback engine calls an OnErrorListener.onError() method provided by the client programmer. Client programmers can register OnErrorListener by calling MediaPlayer.setOnErrorListener (android.media.MediaPlayer.OnErrorListener) method.
2.1) Once an error occurs, the MediaPlayer object will enter the Error state.
2.2) In order to reuse a MediaPlayer object in the Error state, the reset() method can be called to restore the object to the Idle state.
2.3) It is a good programming practice to register an OnErrorListener to know the error occurred in the internal playback engine.
2.4) Calling some methods in an illegal state, such as prepare(), prepareAsync() and setDataSource(), will throw an IllegalStateException.

3) Calling the setDataSource(FileDescriptor) method, or the setDataSource(String) method, or the setDataSource(Context, Uri) method, or the setDataSource(FileDescriptor, long, long) method will cause the object in the Idle state to migrate to the Initialized state.
3.1) If the setDataSource() method is called when the MediaPlayer is in another state, an IllegalStateException will be thrown.
3.2) A good programming practice is not to ignore the IllegalArgumentException and IOException that may be thrown when the setDataSource() method is called.

4) Before starting playback, the MediaPlayer object must enter the Prepared state.
4.1) There are two methods (synchronous and asynchronous) to make the MediaPlayer object enter the Prepared state: either call the prepare() method (synchronous), and the return of this method indicates that the MediaPlayer object has entered the Prepared state; or call the prepareAsync() method ( Asynchronous), this method will put this MediaPlayer object into the Preparing state and return, and the internal playback engine will continue the unfinished preparation work. The OnPreparedListener.onPrepared() listener method provided by the client programmer is called when the synchronous version returns or when the preparation for the asynchronous version is completely completed. You can call MediaPlayer.setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener) method to register OnPreparedListener.
4.2) Preparing is an intermediate state, the result of calling any method with side effects in this state is unknown!
4.3) Calling the prepare() and prepareAsync() methods in an inappropriate state will throw an IllegalStateException. When the MediaPlayer object is in the Prepared state, you can adjust the audio/video properties, such as volume, whether to keep the screen on during playback, loop playback, etc.

5) To start playback, the start() method must be called. When this method returns successfully, the object of MediaPlayer is in the Started state. The isPlaying() method can be called to test whether a MediaPlayer object is in the Started state.
5.1) When in the Started state, the internal playback engine will call the OnBufferingUpdateListener.onBufferingUpdate() callback method provided by the client programmer. This callback method allows the application to track the buffering status of streaming playback.
5.2) Calling the start() method on a MediaPlayer object that is already in the Started state has no effect.

6) The playback can be paused, stopped, and the current playback position adjusted. When the pause() method is called and returned, the MediaPlayer object will enter the Paused state. Note that the transition between the Started and Paused states is asynchronous in the internal playback engine. So it may take a while to update the state in the isPlaying() method, which may take a few seconds if streaming content is being played.
6.1) Calling the start() method will cause a MediaPlayer object in the Paused state to resume playback from where it was previously paused. When the start() method is called, the state of the MediaPlayer object will change to the Started state again.
6.2) The pause() method of a MediaPlayer object that is already in the Paused state has no effect.

7) Calling the stop() method will stop playback, and will also put a MediaPlayer in the Started, Paused, Prepared or PlaybackCompleted state into the Stopped state.
7.1) The stop() method of a MediaPlayer object that is already in the Stopped state has no effect.

8) Call the seekTo() method to adjust the playback position.
8.1) The seekTo(int) method is executed asynchronously, so it can return immediately, but the actual positioning playback operation may take a while to complete, especially when playing streaming audio/video. When the actual positioning playback operation is completed, the internal playback engine will call the OnSeekComplete.onSeekComplete() callback method provided by the client programmer. It can be registered through the setOnSeekCompleteListener(OnSeekCompleteListener) method.
8.2) Note that the seekTo(int) method can also be called in other states, such as Prepared, Paused and PlaybackCompleted states. In addition, the current playback position can actually be obtained by calling the getCurrentPosition() method, which can help an application such as a music player to continuously update the playback progress

9) When the playback reaches the end of the stream, the playback is completed.
9.1) If the setLooping(boolean) method is called to open the loop mode, then the MediaPlayer object will re-enter the Started state.
9.2) If the loop mode is not enabled, the internal playback engine will call the OnCompletion.onCompletion() callback method provided by the client programmer. It can be set by calling the MediaPlayer.setOnCompletionListener(OnCompletionListener) method. Once the internal playback engine calls the OnCompletion.onCompletion() callback method, it means that the MediaPlayer object has entered the PlaybackCompleted state.
9.3) When in the PlaybackCompleted state, you can call the start() method again to make the MediaPlayer object enter the Started state again.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326396052&siteId=291194637