# ExoPlayerTestRunner

Artifact: [androidx.media3:media3-test-utils](https://developer.android.com/jetpack/androidx/releases/media3) [View Source](https://cs.android.com/search?q=file:androidx/media3/test/utils/ExoPlayerTestRunner.java+class:androidx.media3.test.utils.ExoPlayerTestRunner)

*** ** * ** ***


```
@UnstableApi
public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedule.Callback
```

<br />

*** ** * ** ***

Helper class to run an ExoPlayer test.

## Summary

| ### Nested types |
|---|
| `public final class https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner.Builder` Builder to set-up an `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner`. |

| ### Constants |
|---|---|
| `static final https://developer.android.com/reference/androidx/media3/common/Format` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#AUDIO_FORMAT()` A generic audio `https://developer.android.com/reference/androidx/media3/common/Format` which can be used to set up a `https://developer.android.com/reference/androidx/media3/test/utils/FakeMediaSource`. |
| `static final https://developer.android.com/reference/androidx/media3/common/Format` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#VIDEO_FORMAT()` A generic video `https://developer.android.com/reference/androidx/media3/common/Format` which can be used to set up a `https://developer.android.com/reference/androidx/media3/test/utils/FakeMediaSource`. |

| ### Public methods |
|---|---|
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#assertNoPositionDiscontinuities()()` Asserts that `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)` was not called. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#assertPlaybackStatesEqual(java.lang.Integer...)(Integer[] states)` Asserts that the playback states reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlaybackStateChanged(int)` are equal to the provided playback states. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#assertPlayedPeriodIndices(java.lang.Integer...)(Integer[] periodIndices)` Asserts that the indices of played periods is equal to the provided list of periods. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#assertPositionDiscontinuityReasonsEqual(java.lang.Integer...)( Integer[] discontinuityReasons )` Asserts that the discontinuity reasons reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)` are equal to the provided values. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#assertTimelineChangeReasonsEqual(java.lang.Integer...)(Integer[] reasons)` Asserts that the timeline change reasons reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onTimelineChanged(androidx.media3.common.Timeline,int)` are equal to the provided timeline change reasons. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#assertTimelinesSame(androidx.media3.common.Timeline...)(Timeline[] timelines)` Asserts that the timelines reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onTimelineChanged(androidx.media3.common.Timeline,int)` are the same to the provided timelines. |
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | `@https://checkerframework.org/api/com/google/errorprone/annotations/CanIgnoreReturnValue.html https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#blockUntilActionScheduleFinished(long)(long timeoutMs)` Blocks the current thread until the action schedule finished. |
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | `@https://checkerframework.org/api/com/google/errorprone/annotations/CanIgnoreReturnValue.html https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#blockUntilEnded(long)(long timeoutMs)` Blocks the current thread until the test runner finishes. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#onActionScheduleFinished()()` Called when action schedule finished executing all its actions. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#onMediaItemTransition(androidx.media3.common.MediaItem,int)( @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/MediaItem mediaItem, @https://developer.android.com/reference/androidx/media3/common/Player.MediaItemTransitionReason int reason )` Called when playback transitions to a media item or starts repeating a media item according to the current `https://developer.android.com/reference/androidx/media3/common/Player#getRepeatMode()`. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#onPlaybackStateChanged(int)(@https://developer.android.com/reference/androidx/media3/common/Player.State int playbackState)` Called when the value returned from `https://developer.android.com/reference/androidx/media3/common/Player#getPlaybackState()` changes. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#onPlayerError(androidx.media3.common.PlaybackException)(https://developer.android.com/reference/androidx/media3/common/PlaybackException error)` Called when an error occurs. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)( https://developer.android.com/reference/androidx/media3/common/Player.PositionInfo oldPosition, https://developer.android.com/reference/androidx/media3/common/Player.PositionInfo newPosition, @https://developer.android.com/reference/androidx/media3/common/Player.DiscontinuityReason int reason )` Called when a position discontinuity occurs. |
| `void` | `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#onTimelineChanged(androidx.media3.common.Timeline,int)( https://developer.android.com/reference/androidx/media3/common/Timeline timeline, @https://developer.android.com/reference/androidx/media3/common/Player.TimelineChangeReason int reason )` Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getCurrentTimeline()` changes. |
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | `@https://checkerframework.org/api/com/google/errorprone/annotations/CanIgnoreReturnValue.html https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#start()()` Starts the test runner on its own thread. |
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | `@https://checkerframework.org/api/com/google/errorprone/annotations/CanIgnoreReturnValue.html https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#start(boolean)(boolean doPrepare)` Starts the test runner on its own thread. |

### Inherited methods

From [androidx.media3.common.Player.Listener](https://developer.android.com/reference/androidx/media3/common/Player.Listener) `void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onAudioAttributesChanged(androidx.media3.common.AudioAttributes)(https://developer.android.com/reference/androidx/media3/common/AudioAttributes audioAttributes)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getAudioAttributes()` changes.
`void` `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi
https://developer.android.com/reference/androidx/media3/common/Player.Listener#onAudioSessionIdChanged(int)(int audioSessionId)`

Called when the audio session ID changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onAvailableCommandsChanged(androidx.media3.common.Player.Commands)(https://developer.android.com/reference/androidx/media3/common/Player.Commands availableCommands)`

Called when the value returned from `https://developer.android.com/reference/androidx/media3/common/Player#isCommandAvailable(int)` changes for at least one `https://developer.android.com/reference/androidx/media3/common/Player.Command`.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onCues(androidx.media3.common.text.CueGroup)(https://developer.android.com/reference/androidx/media3/common/text/CueGroup cueGroup)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getCurrentCues()` changes.
`void` `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi
[onCues](https://developer.android.com/reference/androidx/media3/common/Player.Listener#onCues(java.util.List<androidx.media3.common.text.Cue>))(https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/common/text/Cue> cues)`

**This method is deprecated.**

Use `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onCues(androidx.media3.common.text.CueGroup)` instead.

<br />

`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onDeviceInfoChanged(androidx.media3.common.DeviceInfo)(https://developer.android.com/reference/androidx/media3/common/DeviceInfo deviceInfo)`

Called when the device information changes
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onDeviceVolumeChanged(int,boolean)(int volume, boolean muted)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getDeviceVolume()` or `https://developer.android.com/reference/androidx/media3/common/Player#isDeviceMuted()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onEvents(androidx.media3.common.Player,androidx.media3.common.Player.Events)(https://developer.android.com/reference/androidx/media3/common/Player player, https://developer.android.com/reference/androidx/media3/common/Player.Events events)`

Called when one or more player states changed.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onIsLoadingChanged(boolean)(boolean isLoading)`

Called when the player starts or stops loading the source.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onIsPlayingChanged(boolean)(boolean isPlaying)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#isPlaying()` changes.
`void` `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi
[onLoadingChanged](https://developer.android.com/reference/androidx/media3/common/Player.Listener#onLoadingChanged(boolean))(boolean isLoading)`

**This method is deprecated.**

Use `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onIsLoadingChanged(boolean)` instead.

<br />

`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onMaxSeekToPreviousPositionChanged(long)(long maxSeekToPreviousPositionMs)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getMaxSeekToPreviousPosition()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onMediaMetadataChanged(androidx.media3.common.MediaMetadata)(https://developer.android.com/reference/androidx/media3/common/MediaMetadata mediaMetadata)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getMediaMetadata()` changes.
`void` `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi
https://developer.android.com/reference/androidx/media3/common/Player.Listener#onMetadata(androidx.media3.common.Metadata)(https://developer.android.com/reference/androidx/media3/common/Metadata metadata)`

Called when there is metadata associated with the current playback time.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlayWhenReadyChanged(boolean,int)(
boolean playWhenReady,
@https://developer.android.com/reference/androidx/media3/common/Player.PlayWhenReadyChangeReason int reason
)`

Called when the value returned from `https://developer.android.com/reference/androidx/media3/common/Player#getPlayWhenReady()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlaybackParametersChanged(androidx.media3.common.PlaybackParameters)(https://developer.android.com/reference/androidx/media3/common/PlaybackParameters playbackParameters)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getPlaybackParameters()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlaybackSuppressionReasonChanged(int)(
@https://developer.android.com/reference/androidx/media3/common/Player.PlaybackSuppressionReason int playbackSuppressionReason
)`

Called when the value returned from `https://developer.android.com/reference/androidx/media3/common/Player#getPlaybackSuppressionReason()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlayerErrorChanged(androidx.media3.common.PlaybackException)(@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/PlaybackException error)`

Called when the `https://developer.android.com/reference/androidx/media3/common/PlaybackException` returned by `https://developer.android.com/reference/androidx/media3/common/Player#getPlayerError()` changes.
`void` `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi
[onPlayerStateChanged](https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlayerStateChanged(boolean,int))(
boolean playWhenReady,
@https://developer.android.com/reference/androidx/media3/common/Player.State int playbackState
)`

**This method is deprecated.**

Use `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlaybackStateChanged(int)` and `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlayWhenReadyChanged(boolean,int)` instead.

<br />

`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlaylistMetadataChanged(androidx.media3.common.MediaMetadata)(https://developer.android.com/reference/androidx/media3/common/MediaMetadata mediaMetadata)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getPlaylistMetadata()` changes.
`void` `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi
[onPositionDiscontinuity](https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(int))(@https://developer.android.com/reference/androidx/media3/common/Player.DiscontinuityReason int reason)`

**This method is deprecated.**

Use `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)` instead.

<br />

`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onRenderedFirstFrame()()`

Called when a frame is rendered for the first time since setting the surface, or since the renderer was reset, or since the stream being rendered was changed.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onRepeatModeChanged(int)(@https://developer.android.com/reference/androidx/media3/common/Player.RepeatMode int repeatMode)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getRepeatMode()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onSeekBackIncrementChanged(long)(long seekBackIncrementMs)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getSeekBackIncrement()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onSeekForwardIncrementChanged(long)(long seekForwardIncrementMs)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getSeekForwardIncrement()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onShuffleModeEnabledChanged(boolean)(boolean shuffleModeEnabled)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getShuffleModeEnabled()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onSkipSilenceEnabledChanged(boolean)(boolean skipSilenceEnabled)`

Called when skipping silences is enabled or disabled in the audio stream.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onSurfaceSizeChanged(int,int)(int width, int height)`

Called each time there's a change in the size of the surface onto which the video is being rendered.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onTrackSelectionParametersChanged(androidx.media3.common.TrackSelectionParameters)(https://developer.android.com/reference/androidx/media3/common/TrackSelectionParameters parameters)`

Called when the value returned from `https://developer.android.com/reference/androidx/media3/common/Player#getTrackSelectionParameters()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onTracksChanged(androidx.media3.common.Tracks)(https://developer.android.com/reference/androidx/media3/common/Tracks tracks)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getCurrentTracks()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onVideoSizeChanged(androidx.media3.common.VideoSize)(https://developer.android.com/reference/androidx/media3/common/VideoSize videoSize)`

Called each time when `https://developer.android.com/reference/androidx/media3/common/Player#getVideoSize()` changes.
`void` `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onVolumeChanged(float)(float volume)`

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getVolume()` changes.

## Constants

### AUDIO_FORMAT

```
public static final Format AUDIO_FORMAT
```

A generic audio `https://developer.android.com/reference/androidx/media3/common/Format` which can be used to set up a `https://developer.android.com/reference/androidx/media3/test/utils/FakeMediaSource`.

### VIDEO_FORMAT

```
public static final Format VIDEO_FORMAT
```

A generic video `https://developer.android.com/reference/androidx/media3/common/Format` which can be used to set up a `https://developer.android.com/reference/androidx/media3/test/utils/FakeMediaSource`.

## Public methods

### assertNoPositionDiscontinuities

```
public void assertNoPositionDiscontinuities()
```

Asserts that `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)` was not called.

### assertPlaybackStatesEqual

```
public void assertPlaybackStatesEqual(Integer[] states)
```

Asserts that the playback states reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPlaybackStateChanged(int)` are equal to the provided playback states.

### assertPlayedPeriodIndices

```
public void assertPlayedPeriodIndices(Integer[] periodIndices)
```

Asserts that the indices of played periods is equal to the provided list of periods. A period is considered to be played if it was the current period after a position discontinuity or a media source preparation. When the same period is repeated automatically due to enabled repeat modes, it is reported twice. Seeks within the current period are not reported.

| Parameters |
|---|---|
| `Integer[] periodIndices` | A list of expected period indices. |

### assertPositionDiscontinuityReasonsEqual

```
public void assertPositionDiscontinuityReasonsEqual(
    Integer[] discontinuityReasons
)
```

Asserts that the discontinuity reasons reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)` are equal to the provided values.

| Parameters |
|---|---|
| `Integer[] discontinuityReasons` | The expected discontinuity reasons. |

### assertTimelineChangeReasonsEqual

```
public void assertTimelineChangeReasonsEqual(Integer[] reasons)
```

Asserts that the timeline change reasons reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onTimelineChanged(androidx.media3.common.Timeline,int)` are equal to the provided timeline change reasons.

### assertTimelinesSame

```
public void assertTimelinesSame(Timeline[] timelines)
```

Asserts that the timelines reported by `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onTimelineChanged(androidx.media3.common.Timeline,int)` are the same to the provided timelines. This assert differs from testing equality by not comparing period ids which may be different due to id mapping of child source period ids.

| Parameters |
|---|---|
| `Timeline[] timelines` | A list of expected `https://developer.android.com/reference/androidx/media3/common/Timeline`s. |

### blockUntilActionScheduleFinished

```
@CanIgnoreReturnValue
public ExoPlayerTestRunner blockUntilActionScheduleFinished(long timeoutMs)
```

Blocks the current thread until the action schedule finished. This does not release the test runner and the test must still call `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner#blockUntilEnded(long)`.

| Parameters |
|---|---|
| `long timeoutMs` | The maximum time to wait for the action schedule to finish. |

| Returns |
|---|---|
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | This test runner. |

| Throws |
|---|---|
| `https://developer.android.com/reference/java/util/concurrent/TimeoutException.html` | If the action schedule did not finish within the specified timeout. |
| `https://developer.android.com/reference/java/lang/InterruptedException.html` | If the test thread gets interrupted while waiting. |

### blockUntilEnded

```
@CanIgnoreReturnValue
public ExoPlayerTestRunner blockUntilEnded(long timeoutMs)
```

Blocks the current thread until the test runner finishes. A test is deemed to be finished when the playback state transitioned to `https://developer.android.com/reference/androidx/media3/common/Player#STATE_ENDED()` or `https://developer.android.com/reference/androidx/media3/common/Player#STATE_IDLE()` for the specified number of times. The test also finishes when an `https://developer.android.com/reference/androidx/media3/exoplayer/ExoPlaybackException` is thrown.

| Parameters |
|---|---|
| `long timeoutMs` | The maximum time to wait for the test runner to finish. If this time elapsed the method will throw a `https://developer.android.com/reference/java/util/concurrent/TimeoutException.html`. |

| Returns |
|---|---|
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | This test runner. |

| Throws |
|---|---|
| `https://developer.android.com/reference/java/lang/Exception.html` | If any exception occurred during playback, release, or due to a timeout. |

### onActionScheduleFinished

```
public void onActionScheduleFinished()
```

Called when action schedule finished executing all its actions.

### onMediaItemTransition

```
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem,
    @Player.MediaItemTransitionReason int reason
)
```

Called when playback transitions to a media item or starts repeating a media item according to the current `https://developer.android.com/reference/androidx/media3/common/Player#getRepeatMode()`.

Note that this callback is also called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getCurrentTimeline()` becomes non-empty or empty.

`https://developer.android.com/reference/androidx/media3/common/Player.Listener#onEvents(androidx.media3.common.Player,androidx.media3.common.Player.Events)` will also be called to report this event along with other events that happen in the same `https://developer.android.com/reference/android/os/Looper.html` message queue iteration.

| Parameters |
|---|---|
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/MediaItem mediaItem` | The `https://developer.android.com/reference/androidx/media3/common/MediaItem`. May be null if the playlist becomes empty. |
| `@https://developer.android.com/reference/androidx/media3/common/Player.MediaItemTransitionReason int reason` | The reason for the transition. |

### onPlaybackStateChanged

```
public void onPlaybackStateChanged(@Player.State int playbackState)
```

Called when the value returned from `https://developer.android.com/reference/androidx/media3/common/Player#getPlaybackState()` changes.

`https://developer.android.com/reference/androidx/media3/common/Player.Listener#onEvents(androidx.media3.common.Player,androidx.media3.common.Player.Events)` will also be called to report this event along with other events that happen in the same `https://developer.android.com/reference/android/os/Looper.html` message queue iteration.

| Parameters |
|---|---|
| `@https://developer.android.com/reference/androidx/media3/common/Player.State int playbackState` | The new playback `https://developer.android.com/reference/androidx/media3/common/Player.State`. |

### onPlayerError

```
public void onPlayerError(PlaybackException error)
```

Called when an error occurs. The playback state will transition to `https://developer.android.com/reference/androidx/media3/common/Player#STATE_IDLE()` immediately after this method is called. The player instance can still be used, and `https://developer.android.com/reference/androidx/media3/common/Player#release()` must still be called on the player should it no longer be required.

`https://developer.android.com/reference/androidx/media3/common/Player.Listener#onEvents(androidx.media3.common.Player,androidx.media3.common.Player.Events)` will also be called to report this event along with other events that happen in the same `https://developer.android.com/reference/android/os/Looper.html` message queue iteration.

Implementations of Player may pass an instance of a subclass of `https://developer.android.com/reference/androidx/media3/common/PlaybackException` to this method in order to include more information about the error.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/common/PlaybackException error` | The error. |

### onPositionDiscontinuity

```
public void onPositionDiscontinuity(
    Player.PositionInfo oldPosition,
    Player.PositionInfo newPosition,
    @Player.DiscontinuityReason int reason
)
```

Called when a position discontinuity occurs.

A position discontinuity occurs when the playing period changes, the playback position jumps within the period currently being played, or when the playing period has been skipped or removed.

`https://developer.android.com/reference/androidx/media3/common/Player.Listener#onEvents(androidx.media3.common.Player,androidx.media3.common.Player.Events)` will also be called to report this event along with other events that happen in the same `https://developer.android.com/reference/android/os/Looper.html` message queue iteration.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/common/Player.PositionInfo oldPosition` | The position before the discontinuity. |
| `https://developer.android.com/reference/androidx/media3/common/Player.PositionInfo newPosition` | The position after the discontinuity. |
| `@https://developer.android.com/reference/androidx/media3/common/Player.DiscontinuityReason int reason` | The `https://developer.android.com/reference/androidx/media3/common/Player.DiscontinuityReason` responsible for the discontinuity. |

### onTimelineChanged

```
public void onTimelineChanged(
    Timeline timeline,
    @Player.TimelineChangeReason int reason
)
```

Called when the value of `https://developer.android.com/reference/androidx/media3/common/Player#getCurrentTimeline()` changes.

Note that the current `https://developer.android.com/reference/androidx/media3/common/MediaItem` or playback position may change as a result of a timeline change. If playback can't continue smoothly because of this timeline change, a separate `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onPositionDiscontinuity(androidx.media3.common.Player.PositionInfo,androidx.media3.common.Player.PositionInfo,int)` callback will be triggered.

`https://developer.android.com/reference/androidx/media3/common/Player.Listener#onEvents(androidx.media3.common.Player,androidx.media3.common.Player.Events)` will also be called to report this event along with other events that happen in the same `https://developer.android.com/reference/android/os/Looper.html` message queue iteration.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/common/Timeline timeline` | The latest timeline. Never null, but may be empty. |
| `@https://developer.android.com/reference/androidx/media3/common/Player.TimelineChangeReason int reason` | The `https://developer.android.com/reference/androidx/media3/common/Player.TimelineChangeReason` responsible for this timeline change. |

### start

```
@CanIgnoreReturnValue
public ExoPlayerTestRunner start()
```

Starts the test runner on its own thread. This will trigger the creation of the player, the listener registration, the start of the action schedule, the initial set of media items and the preparation of the player.

| Returns |
|---|---|
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | This test runner. |

### start

```
@CanIgnoreReturnValue
public ExoPlayerTestRunner start(boolean doPrepare)
```

Starts the test runner on its own thread. This will trigger the creation of the player, the listener registration, the start of the action schedule and the initial set of media items.

| Parameters |
|---|---|
| `boolean doPrepare` | Whether the player should be prepared. |

| Returns |
|---|---|
| `https://developer.android.com/reference/androidx/media3/test/utils/ExoPlayerTestRunner` | This test runner. |