Class ShadowMediaPlayer
MediaPlayer with Robolectric.
This shadow implementation provides much of the functionality needed to emulate MediaPlayer initialization and playback behavior without having to play actual media files. A
summary of the features included are:
- Construction-time callback hook
ShadowMediaPlayer.CreateListenerso that newly-createdMediaPlayerinstances can have their shadows configured before they are used. - Emulation of the
OnCompletionListener,OnErrorListener,OnInfoListener,OnPreparedListenerandOnSeekCompleteListener. - Full support of the
MediaPlayerinternal states and their transition map. - Configure time parameters such as playback duration, preparation delay and
setSeekDelay(int). - Emulation of asynchronous callback events during playback through Robolectric's scheduling
system using the
ShadowMediaPlayer.MediaInfoinner class. - Emulation of error behavior when methods are called from invalid states, or to throw
assertions when methods are invoked in invalid states (using
setInvalidStateBehavior(org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior)). - Emulation of different playback behaviors based on the current data source, as passed in to
setDataSource(), usingaddMediaInfo(org.robolectric.shadows.util.DataSource, org.robolectric.shadows.ShadowMediaPlayer.MediaInfo)orsetMediaInfoProvider(MediaInfoProvider). - Emulation of exceptions when calling
setDataSource(org.robolectric.shadows.util.DataSource)usingaddException(org.robolectric.shadows.util.DataSource, java.lang.RuntimeException).
addException(DataSource, IOException) or a ShadowMediaPlayer.MediaInfo instance
for that data source using addMediaInfo(DataSource, MediaInfo) or setMediaInfoProvider(MediaInfoProvider) before calling setDataSource(org.robolectric.shadows.util.DataSource), otherwise
you'll get an IllegalArgumentException.
The current features of ShadowMediaPlayer were focused on development for testing
playback of audio tracks. Thus support for emulating timed text and video events is incomplete.
None of these features would be particularly onerous to add/fix - contributions welcome, of
course!
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceCallback interface for clients that wish to be informed when a newMediaPlayerinstance is constructed.static enumPossible behavior modes for the media player when a method is invoked in an invalid state.static interfacestatic classClass specifying information for an emulated media object.static interfaceProvides aShadowMediaPlayer.MediaInfofor a givenDataSource.static enumPossible states for the media player to be in. -
Field Summary
FieldsModifier and TypeFieldDescriptionprotected static ShadowMediaPlayer.CreateListenerListener that is called when a new MediaPlayer is constructed.static final int -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected voidprotected void__constructor__(Context context, int sessionId) protected static voidprotected void_pause()SimulatesMediaPlayer._pause().protected void_release()Simulates call toMediaPlayer._release().protected void_reset()Simulates call toMediaPlayer._reset().protected void_stop()Simulates call toMediaPlayer.release().static voidaddException(DataSource dataSource, IOException e) static voidaddException(DataSource dataSource, RuntimeException e) static voidaddMediaInfo(DataSource dataSource, ShadowMediaPlayer.MediaInfo info) Adds aShadowMediaPlayer.MediaInfofor aDataSource.protected voidattachAuxEffect(int effectId) protected static MediaPlayerprotected static MediaPlayervoiddoSetDataSource(DataSource dataSource) Sets the data source without doing any other emulation.voiddoStart()Starts simulated playback.voiddoStop()Pauses simulated playback.protected intintUseful for assertions.protected intSimulates call toMediaPlayer.getCurrentPosition().intRetrieves the current position without doing the state checking that the emulated version ofgetCurrentPosition()does.Retrieves the data source (if any) that was passed in tosetDataSource(DataSource).protected intSimulates call toMediaPlayer.getDuration().intRetrieves the current duration without doing the state checking that the emulated version does.Retrieves theHandlerobject used by thisShadowMediaPlayer.Retrieves current flag specifying the behavior of the media player when a method is invoked in an invalid state.floatRetrieves the current setting for the left channel volume.Retrieves the currently selectedShadowMediaPlayer.MediaInfo.static ShadowMediaPlayer.MediaInfogetMediaInfo(DataSource dataSource) intRetrieves the pending seek setting.floatintintRetrieves the resource ID used in the call tocreate(Context, int)(if any).Retrieves the source path (if any) that was passed in toMediaPlayer.setDataSource(Context, Uri, Map)orMediaPlayer.setDataSource(Context, Uri).getState()Retrieves the current state of theMediaPlayer.intNote: This has a funny name at the moment to avoid having to produce an API-specific shadow - if it were calledgetAudioStreamType()then theRobolectricWiringTestwill inform us that it should be annotated withImplementation, because there is a private method in the later API versions with the same name, however this would fail on earlier versions.protected intprotected intvoidSimulates end-of-playback.voidinvokeErrorListener(int what, int extra) Allows test cases to directly simulate invocation of the OnError event.voidinvokeInfoListener(int what, int extra) Allows test cases to directly simulate invocation of the OnInfo event.voidAllows test cases to simulate 'prepared' state by invoking callback.voidAllows test cases to simulate seek completion by invoking callback.protected booleanprotected booleanbooleanTests to see if the player is in the PREPARED state.booleanTests to see if the player is really playing.protected booleannative_setOutputDevice(int preferredDeviceId) voidvoidpostEventDelayed(ShadowMediaPlayer.MediaEvent e, long delay) protected voidprepare()SimulatesMediaPlayer.prepareAsync().protected voidSimulatesMediaPlayer.prepareAsync().static voidprotected voidseekTo(int seekTo) Simulates seeking to specified position.protected voidseekTo(long seekTo, int mode) protected voidsetAudioSessionId(int sessionId) protected voidsetAudioStreamType(int audioStreamType) static voidsetCreateListener(ShadowMediaPlayer.CreateListener createListener) Sets a listener that is invoked whenever a new shadowedMediaPlayerobject is constructed.voidsetCurrentPosition(int position) Sets the current position, bypassing the normal state checking.protected voidsetDataSource(Context context, Uri uri) protected voidprotected voidsetDataSource(Context context, Uri uri, Map<String, String> headers, List<HttpCookie> cookies) protected voidsetDataSource(AssetFileDescriptor assetFileDescriptor) protected voidsetDataSource(MediaDataSource mediaDataSource) protected voidsetDataSource(FileDescriptor fd, long offset, long length) protected voidsetDataSource(String path) protected voidsetDataSource(String uri, Map<String, String> headers) voidsetDataSource(DataSource dataSource) Common code path for allsetDataSource()implementations.voidsetInvalidStateBehavior(ShadowMediaPlayer.InvalidStateBehavior invalidStateBehavior) Specifies how the media player should behave when a method is invoked in an invalid state.protected voidsetLooping(boolean looping) static voidsetMediaInfoProvider(ShadowMediaPlayer.MediaInfoProvider mediaInfoProvider) Sets aShadowMediaPlayer.MediaInfoProviderto be used to getShadowMediaPlayer.MediaInfofor anyDataSource.protected voidprotected voidprotected voidsetOnInfoListener(MediaPlayer.OnInfoListener listener) protected voidprotected voidvoidsetSeekDelay(int seekDelay) Sets the length of time (ms) that seekTo() will delay before completing.voidsetState(ShadowMediaPlayer.State state) Forces the @link MediaPlayer} into the specified state.protected voidsetVolume(float left, float right) protected voidstart()Simulates private native methodMediaPlayer._start().Methods inherited from class org.robolectric.shadows.ShadowPlayerBase
getService
-
Field Details
-
createListener
Listener that is called when a new MediaPlayer is constructed.- See Also:
-
MEDIA_EVENT
public static final int MEDIA_EVENT- See Also:
-
-
Constructor Details
-
ShadowMediaPlayer
public ShadowMediaPlayer()
-
-
Method Details
-
__staticInitializer__
-
postEvent
-
postEventDelayed
-
create
-
create
-
__constructor__
-
__constructor__
-
setDataSource
Common code path for allsetDataSource()implementations.* Checks for any specified exceptions for the specified data source and throws them. * Checks the current state and throws an exception if it is in an invalid state. * If no exception is thrown in either of the previous two steps, then
doSetDataSource(DataSource)is called to set the data source. * Sets the player state toINITIALIZED. Usually this method would not be called directly, but indirectly through one of the othersetDataSource(String)implementations, which useDataSource.toDataSource(String)methods to convert their discrete parameters into a singleDataSourceinstance.- Parameters:
dataSource- the data source that is being set.- Throws:
IOException- if the specified data source has been configured to throw an IO exception.- See Also:
-
setDataSource
- Throws:
IOException
-
setDataSource
@Implementation(maxSdk=25) protected void setDataSource(Context context, Uri uri) throws IOException - Throws:
IOException
-
setDataSource
@Implementation(maxSdk=25) protected void setDataSource(Context context, Uri uri, Map<String, String> headers) throws IOException- Throws:
IOException
-
setDataSource
@Implementation(minSdk=26) protected void setDataSource(Context context, Uri uri, Map<String, String> headers, List<HttpCookie> cookies) throws IOException- Throws:
IOException
-
setDataSource
@Implementation protected void setDataSource(String uri, Map<String, String> headers) throws IOException- Throws:
IOException
-
setDataSource
@Implementation protected void setDataSource(FileDescriptor fd, long offset, long length) throws IOException - Throws:
IOException
-
setDataSource
@Implementation(minSdk=23) protected void setDataSource(MediaDataSource mediaDataSource) throws IOException - Throws:
IOException
-
setDataSource
@Implementation(minSdk=24) protected void setDataSource(AssetFileDescriptor assetFileDescriptor) throws IOException - Throws:
IOException
-
doSetDataSource
Sets the data source without doing any other emulation. Sets the internal data source only. Calling directly can be useful for setting up aShadowMediaPlayerinstance during specific testing so that you don't have to clutter your tests catching exceptions you know won't be thrown.- Parameters:
dataSource- the data source that is being set.- See Also:
-
getMediaInfo
-
addMediaInfo
Adds aShadowMediaPlayer.MediaInfofor aDataSource. -
setMediaInfoProvider
Sets aShadowMediaPlayer.MediaInfoProviderto be used to getShadowMediaPlayer.MediaInfofor anyDataSource.This overrides any
ShadowMediaPlayer.MediaInfopreviously set by callingaddMediaInfo(org.robolectric.shadows.util.DataSource, org.robolectric.shadows.ShadowMediaPlayer.MediaInfo), i.e.,ShadowMediaPlayer.MediaInfoprovided by thisShadowMediaPlayer.MediaInfoProviderwill be used instead. -
addException
-
addException
-
setOnCompletionListener
-
setOnSeekCompleteListener
@Implementation protected void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener) -
setOnPreparedListener
-
setOnInfoListener
-
setOnErrorListener
-
isLooping
-
setLooping
-
setVolume
-
isPlaying
-
prepare
SimulatesMediaPlayer.prepareAsync(). Sleeps forpreparationDelayms by callingSystemClock.sleep(long)before callinginvokePreparedListener().If
preparationDelayis not positive and non-zero, there is no sleep. -
prepareAsync
SimulatesMediaPlayer.prepareAsync(). Sets state to PREPARING and posts a callback toinvokePreparedListener()if the current preparation delay for the current media (seegetMediaInfo()) is >= 0, otherwise the test suite is responsible for callinginvokePreparedListener()directly if required. -
start
Simulates private native methodMediaPlayer._start(). Sets state to STARTED and callsdoStart()to start scheduling playback callback events.If the current state is PLAYBACK_COMPLETED, the current position is reset to zero before starting playback.
- See Also:
-
isReallyPlaying
public boolean isReallyPlaying()Tests to see if the player is really playing.The player is defined as "really playing" if simulated playback events (including playback completion) are being scheduled and invoked and
currentPositionis being updated as time passes. Note that while the player will normally be really playing if in the STARTED state, this is not always the case - for example, if a pending seek is in progress, or perhaps a buffer underrun is being simulated. -
doStart
public void doStart()Starts simulated playback. Until this method is called, the player is not "really playing" (seeisReallyPlaying()for a definition of "really playing").This method is used internally by the various shadow method implementations of the MediaPlayer public API, but may also be called directly by the test suite if you wish to simulate an internal pause. For example, to simulate a buffer underrun (player is in PLAYING state but isn't actually advancing the current position through the media), you could call
doStop()to mark the start of the buffer underrun anddoStart()to mark its end and restart normal playback (which is whatscheduleBufferUnderrunAtOffset()does).- See Also:
-
doStop
public void doStop()Pauses simulated playback. After this method is called, the player is no longer "really playing" (seeisReallyPlaying()for a definition of "really playing").This method is used internally by the various shadow method implementations of the MediaPlayer public API, but may also be called directly by the test suite if you wish to simulate an internal pause.
- See Also:
-
_pause
SimulatesMediaPlayer._pause(). InvokesdoStop()to suspend playback event callbacks and sets the state to PAUSED.- See Also:
-
_release
Simulates call toMediaPlayer._release(). CallsdoStop()to suspend playback event callbacks and sets the state to END. -
_reset
Simulates call toMediaPlayer._reset(). CallsdoStop()to suspend playback event callbacks and sets the state to IDLE. -
_stop
Simulates call toMediaPlayer.release(). CallsdoStop()to suspend playback event callbacks and sets the state to STOPPED. -
attachAuxEffect
-
getAudioSessionId
-
getCurrentPosition
Simulates call toMediaPlayer.getCurrentPosition(). Simply does the state validity checks and then invokesgetCurrentPositionRaw()to calculate the simulated playback position.- Returns:
- The current offset (in ms) of the simulated playback.
- See Also:
-
getDuration
Simulates call toMediaPlayer.getDuration(). Retrieves the duration as defined by the currentShadowMediaPlayer.MediaInfoinstance.- Returns:
- The duration (in ms) of the current simulated playback.
- See Also:
-
getVideoHeight
-
getVideoWidth
-
seekTo
Simulates seeking to specified position. The seek will complete afterseekDelayms (defaults to 0), or else if seekDelay is negative then the controlling test is expected to simulate seek completion by manually invokinginvokeSeekCompleteListener().- Parameters:
seekTo- the offset (in ms) from the start of the track to seek to.
-
seekTo
-
setAudioSessionId
-
setAudioStreamType
-
setCreateListener
Sets a listener that is invoked whenever a new shadowedMediaPlayerobject is constructed.Registering a listener gives you a chance to customize the shadowed object appropriately without needing to modify the application-under-test to provide access to the instance at the appropriate point in its life cycle. This is useful because normally a new
MediaPlayeris created andsetDataSource()is invoked soon after, without a break in the code. Using this callback means you don't have to change this common pattern just so that you can customize the shadow for testing.- Parameters:
createListener- the listener to be invoked
-
getHandler
Retrieves theHandlerobject used by thisShadowMediaPlayer. Can be used for posting custom asynchronous events to the thread (eg, asynchronous errors). Use this for scheduling events to take place at a particular "real" time (ie, time as measured by the scheduler). For scheduling events to occur at a particular playback offset (no matter how long playback may be paused for, or where you seek to, etc), seeShadowMediaPlayer.MediaInfo.scheduleEventAtOffset(int, ShadowMediaPlayer.MediaEvent)and its various helpers.- Returns:
- Handler object that can be used to schedule asynchronous events on this media player.
-
getInvalidStateBehavior
Retrieves current flag specifying the behavior of the media player when a method is invoked in an invalid state. SeesetInvalidStateBehavior(InvalidStateBehavior)for a discussion of the available modes and their associated behaviors.- Returns:
- The current invalid state behavior mode.
- See Also:
-
setInvalidStateBehavior
Specifies how the media player should behave when a method is invoked in an invalid state. Three modes are supported (as defined by theShadowMediaPlayer.InvalidStateBehaviorenum):
No invalid state checking is done at all. All methods can be invoked from any state without throwing any exceptions or invoking the error listener.SILENTThis mode is provided primarily for backwards compatibility, and for this reason it is the default. For proper testing one of the other two modes is probably preferable.
The shadow will attempt to emulate the behavior of the actualEMULATEMediaPlayerimplementation. This is based on a reading of the documentation and on actual experiments done on a Jelly Bean device. The official documentation is not all that clear, but basically methods fall into three categories:- Those that log an error when invoked in an invalid state but don't throw an exception or
invoke
onError(). An example isgetVideoHeight(). - Synchronous error handling: methods always throw an exception (usually
IllegalStateExceptionbut don't invokeonError(). Examples areprepare()andsetDataSource(String). - Asynchronous error handling: methods don't throw an exception but invoke
onError().
IllegalStateExceptionwhen invoked from the END state.To complicate matters slightly, the official documentation sometimes contradicts observed behavior. For example, the documentation says it is illegal to call
setDataSource(org.robolectric.shadows.util.DataSource)from the ERROR state - however, in practice it works fine. Conversely, the documentation says that it is legal to invokegetCurrentPosition()from the INITIALIZED state, however testing showed that this caused an error. Wherever there is a discrepancy between documented and observed behavior, this implementation has gone with the most conservative implementation (ie, it is illegal to invokesetDataSource(org.robolectric.shadows.util.DataSource)from the ERROR state and likewise illegal to invokegetCurrentPosition()from the INITIALIZED state.
The shadow will raise an assertion any time that a method is invoked in an invalid state. The philosophy behind this mode is that to invoke a method in an invalid state is a programming error - a bug, pure and simple. As such it should be discovered and eliminated at development and testing time, rather than anticipated and handled at runtime. Asserting is a way of testing for these bugs during testing.ASSERT- Parameters:
invalidStateBehavior- the behavior mode for this shadow to use during testing.- See Also:
- Those that log an error when invoked in an invalid state but don't throw an exception or
invoke
-
getMediaInfo
Retrieves the currently selectedShadowMediaPlayer.MediaInfo. This instance is used to define current duration, preparation delay, exceptions forsetDataSource(), playback events, etc. -
setCurrentPosition
public void setCurrentPosition(int position) Sets the current position, bypassing the normal state checking. Use with care.- Parameters:
position- the new playback position.
-
getCurrentPositionRaw
public int getCurrentPositionRaw()Retrieves the current position without doing the state checking that the emulated version ofgetCurrentPosition()does.- Returns:
- The current playback position within the current clip.
-
getDurationRaw
public int getDurationRaw()Retrieves the current duration without doing the state checking that the emulated version does.- Returns:
- The duration of the current clip loaded by the player.
-
getState
Retrieves the current state of theMediaPlayer. Uses the states as defined in theMediaPlayerdocumentation.- Returns:
- The current state of the
MediaPlayer, as defined in the MediaPlayer documentation. - See Also:
-
setState
Forces the @link MediaPlayer} into the specified state. Uses the states as defined in theMediaPlayerdocumentation.Note that by invoking this method directly you can get the player into an inconsistent state that a real player could not be put in (eg, in the END state but with playback events still happening). Use with care.
- Parameters:
state- the new state of theMediaPlayer, as defined in the MediaPlayer documentation.- See Also:
-
getTheAudioStreamType
public int getTheAudioStreamType()Note: This has a funny name at the moment to avoid having to produce an API-specific shadow - if it were calledgetAudioStreamType()then theRobolectricWiringTestwill inform us that it should be annotated withImplementation, because there is a private method in the later API versions with the same name, however this would fail on earlier versions.- Returns:
- audioStreamType
-
getSeekDelay
public int getSeekDelay()- Returns:
- seekDelay
-
setSeekDelay
public void setSeekDelay(int seekDelay) Sets the length of time (ms) that seekTo() will delay before completing. Default is 0. If set to -1, then seekTo() will not call the OnSeekCompleteListener automatically; you will need to call invokeSeekCompleteListener() manually.- Parameters:
seekDelay- length of time to delay (ms)
-
getAuxEffect
public int getAuxEffect()Useful for assertions.- Returns:
- The current
auxEffectsetting.
-
getPendingSeek
public int getPendingSeek()Retrieves the pending seek setting.- Returns:
- The position to which the shadow player is seeking for the seek in progress (ie, after
the call to
seekTo(int)but before a call toinvokeSeekCompleteListener()). Returns-1if no seek is in progress.
-
getDataSource
Retrieves the data source (if any) that was passed in tosetDataSource(DataSource).Useful for assertions.
- Returns:
- The source passed in to
setDataSource.
-
getSourceUri
Retrieves the source path (if any) that was passed in toMediaPlayer.setDataSource(Context, Uri, Map)orMediaPlayer.setDataSource(Context, Uri).- Returns:
- The source Uri passed in to
setDataSource.
-
getSourceResId
public int getSourceResId()Retrieves the resource ID used in the call tocreate(Context, int)(if any).- Returns:
- The resource ID passed in to
create(), or-1if a different method of setting the source was used.
-
getLeftVolume
public float getLeftVolume()Retrieves the current setting for the left channel volume.- Returns:
- The left channel volume.
-
getRightVolume
public float getRightVolume()- Returns:
- The right channel volume.
-
native_setOutputDevice
-
isPrepared
public boolean isPrepared()Tests to see if the player is in the PREPARED state. This is mainly used for backward compatibility.getState()may be more useful for new testing applications.- Returns:
trueif the MediaPlayer is in the PREPARED state, false otherwise.
-
getOnCompletionListener
- Returns:
- the OnCompletionListener
-
getOnPreparedListener
- Returns:
- the OnPreparedListener
-
invokePreparedListener
public void invokePreparedListener()Allows test cases to simulate 'prepared' state by invoking callback. Sets the player's state to PREPARED and invokes thepreparedListener() -
invokeCompletionListener
public void invokeCompletionListener()Simulates end-of-playback. Changes the player into PLAYBACK_COMPLETED state and callsonCompletion()if a listener has been set. -
invokeSeekCompleteListener
public void invokeSeekCompleteListener()Allows test cases to simulate seek completion by invoking callback. -
invokeInfoListener
public void invokeInfoListener(int what, int extra) Allows test cases to directly simulate invocation of the OnInfo event.- Parameters:
what- parameter to pass in towhatinMediaPlayer.OnInfoListener.onInfo(MediaPlayer, int, int).extra- parameter to pass in toextrainMediaPlayer.OnInfoListener.onInfo(MediaPlayer, int, int).
-
invokeErrorListener
public void invokeErrorListener(int what, int extra) Allows test cases to directly simulate invocation of the OnError event.- Parameters:
what- parameter to pass in towhatinMediaPlayer.OnErrorListener.onError(MediaPlayer, int, int).extra- parameter to pass in toextrainMediaPlayer.OnErrorListener.onError(MediaPlayer, int, int).
-
resetStaticState
-