1.9.0 (2025-12-17)
- Common Library:
- Update
minSdkto23in line with other AndroidX libraries. - Add
PlayerTransferState, which facilitates transferring the playback state acrossPlayerinstances. - Add
void mute()andvoid unmute()methods to Player that preserve and consequently restore Player's volume before and after setting it to zero. - Publish utility classes
WakeLockManager,WifiLockManager,AudioFocusManager,AudioBecomingNoisyManagerandStuckPlayerDetectorpreviously used byExoPlayerinternally to allow reuse for other players (#1893). - Fix
ForwardingPlayerlistener handling when the underlying delegate player uses reference equality for comparing listener instances (#2675). - Add a
Player.listenTosuspending extension function in themedia3-common-ktxlibrary that specifies the particularPlayer.Eventsthat should be acted upon. - Fix a crash in
BasePlayer.getBufferedPercentageresulting from integer overflow when the reported buffered position is implausibly much larger than the reported duration (#2750). - Fix auto-detection of
TrackGrouptrack type by not ignoring custom sample MIME type and falling back to using the potentially wrong track type from the container MIME type (#2860).
- Update
- ExoPlayer:
- Add a stuck player detection that triggers a
StuckPlayerExceptionplayer error if the player seems stuck. This happens in the following cases, where each default timeout can be configured inExoPlayer.Builderif required:- After 10 minutes of
STATE_BUFFERINGwhile trying to play and no buffering progress. - After 10 seconds of
STATE_READYwhile trying to play and no playback progress. - After 1 minute of
STATE_READYbeyond the declared duration without reaching the end of the item. - After 10 minutes with a playback suppression reason while trying to play.
- After 10 minutes of
- Enable wake lock handling by default to fix issues with buffering during background playback. This is equivalent to setting
ExoPlayer.Builder.setWakeModetoC.WAKE_MODE_LOCAL. - Add listening logic to automatically update the virtual device ID when a change is reported to the
Contextoriginally passed toExoPlayer.Builder. - Add
ExoPlayer.setVirtualDeviceIdto manually update the virtual device ID obtained from theContextpassed toExoPlayer.Builder. - Ensure renderers don't consume data from the next playlist item more than 10 seconds before the end of the current item.
- Add
setSeekBackIncrementMs,setSeekForwardIncrementMsandsetMaxSeekToPreviousPositionMstoExoPlayerto update these settings after construction (#2736). - Add pre-caching functionality in
DefaultPreloadManager. Apps now can returnDefaultPreloadManager.PreloadStatus.specifiedRangeCached(startPositionMs, durationMs)orDefaultPreloadManager.PreloadStatus.specifiedRangeCached(durationMs)viaTargetPreloadStatusControl.getTargetPreloadStatus(T rankingData)to indicate that a media item needs to be pre-cached. - Use pre-caching functionality of
DefaultPreloadManagerin shortform demo app. - Add
DefaultLoadControl.Buildersetters for local playback and adjust default values ofDefaultLoadControlto work well with a wide range of local files. - Fix bug where setting an empty playlist can leave the player in
STATE_READYorSTATE_BUFFERING. - Enhance the preload manager APIs:
- Add
addMediaItems(List<MediaItem>, List<T>)andaddMediaSources(List<MediaSource>, List<T>)that add the media items or media sources in batch, and automatically callinvalidate()afterwards. - Add
removeMediaItems((List<MediaItem>)andremoveMediaSources(List<MediaSource>)that remove the media items or media sources in batch, and make sure that preload manager does not start to preload or continue preloading any of them after removal. - Allow
DefaultPreloadManager.setCurrentPlayingIndex(int)to invalidate itself automatically. Apps don't need to callinvalidate()explicitly anymore after updating the current playing index.
- Add
- Add capability to skip keyframe reset for forward seeks within the same group of pictures while in scrubbing mode.
- Add
DefaultLoadControl.Builder.setPlayerTargetBufferBytes(String, int)for apps to set a value of target buffer bytes for a player with the specifiedplayerName. TheDefaultLoadControlcan now make decisions of each player separately based on its own allocated bytes and target buffer bytes. - Add
SkipInfoto theAdPlaybackState.AdGroupto carry skip information for each ad in the ad group. - Fix bug where calling
removeMediaItems(List)during playing a post-roll created a crash (#2746). - Fix some stuttering in playlist playback where frames were mistakenly always set as the last sample and rendered.
- Enable retry path if player fails to generate audio session ID (#2382, #2678).
- Add support to control the total buffer bytes for the sources in
DefaultPreloadManagerto avoid total buffer bytes for preloading from growing arbitrarily. To use the default control logic, Apps can set the target buffer bytes for preloading viaDefaultLoadControl.Builder.setPlayerTargetBufferBytes(String, int)for aplayerNameofPlayerId.Preload.name("preload"), and inject the createdDefaultLoadControlviaDefaultPreloadManager.Builder.setLoadControl(LoadControl). - Add
cloneAndSet(int, int)toShuffleOrderwith a default implementation (#2834). - Append content resume offset when skipping ad playback after seek adjustment or auto transition (#2484).
- Add API to set and observe codec parameters for audio and video tracks. This feature is implemented for
MediaCodecbased renderers and requires API 29+.- Use
ExoPlayer.setAudioCodecParameters()andExoPlayer.setVideoCodecParameters()to apply parameters. - Use
ExoPlayer.addAudioCodecParametersChangeListener()andExoPlayer.addVideoCodecParametersChangeListener()to listen for changes. Observing vendor-specific keys requires API 31+.
- Use
- Fix
IllegalStateExceptioncaused by setting an empty media source after seeking to a non-zero position and then preparing the player with a non-empty media source. - Fix bug where seeking into other media items while in scrubbing mode could cause
IllegalStateException. - Fix potential
NullPointerExceptioninDefaultPlaybackSessionManager(#2885). - Enable improvements in seeking performance for eligible videos.
- Re-enable use of asynchronous decryption in MediaCodec on API 36+ where timeout issues with this platform API have been fixed (#1641).
- Change the default value of
MediaCodecVideoRenderer.experimentalSetLateThresholdToDropDecoderInputUsto 15ms and enable more efficient dropping of video frames before decoding for eligible videos. - Add maximum memory limit to the automatic memory calculation in
DefaultLoadControl. This should only take effect if an excessive number of tracks get selected (#2860). - Fix bug where, if playing in a playlist or repeat mode, seeking in scrub mode near the end could cause a seek to the next media item.
- Add a stuck player detection that triggers a
- CompositionPlayer:
- Publish
CompositionPlayerunder a new@ExperimentalApiannotation to indicate it is available for experimentation, but is still under development. Some APIs are likely to change significantly in future releases, and there are known issues and limitations with some use-cases (some undocumented). - Add support for
COMMAND_SET_AUDIO_ATTRIBUTESand audio focus handling inCompositionPlayer. - Add support for speed changing in secondary sequences in
CompositionPlayer. - Add support for
EditedMediaItem.removeVideo.
- Publish
- Transformer:
- Use
InAppMp4Muxeras default muxer. - Add
EditedMediaItem.Builder#setSpeed()and deprecateEffects#createExperimentalSpeedChangingEffects(). - Replace
forceAudioTrackandforceVideoTrackwithtrackTypesinEditedMediaItemSequence.
- Use
- Track Selection:
- Add
TrackSelectionParameters.selectTextByDefaultto prefer the selection of any text track without specifying other more specific preferences. - Add
preferredVideoLabels,preferredAudioLabelsandpreferredTextLabelsinTrackSelectionParametersto specify a preference for tracks with a specific label, for example those read from HLS NAME tags (#1666).
- Add
- Extractors:
- FLAC: Tighten header detection to reduce the chance of finding spurious headers in the encoded FLAC data, resulting in decoding errors (#558).
- MP3: Allow gaps between (and before) ID3 tags at the beginning of MP3 files (#811, #5718).
- MP3: Increase sniffing limit to 128kB to match the existing search limit for a sync byte (#2713).
- MP3: Change
FLAG_ENABLE_INDEX_SEEKINGto prefer seeking information from metadata headers (like Xing and VBRI) when available, falling back to index-based seeking if no other seeking information is present. This improves performance for files with seeking metadata (#2839). - MP3: Change
Mp3Extractorto default to a constant bitrate (CBR) assumption when no seeking metadata (e.g., Xing, VBRI) is found, even whenFLAG_ENABLE_INDEX_SEEKINGis set. This is based on the MP3 specification's history, where CBR was standard and VBR requires explicit headers. This improves immediate seekability for files without metadata at the cost of potential accuracy for VBR files lacking headers. Index seeking is now used as a fallback if the CBR assumption is not seekable (e.g., for streams of unknown length) (#2848). - MP4: Disambiguate between
audio/mpeg(MP3),audio/mpeg-L1andaudio/mpeg-L2MIME types by peeking the layer value of the first sample before emitting a track format from the extractor (#2683). - MP4: Improve sniffing efficiency of very large files by assuming a
stblbox larger than 1MB implies the file must be non-fragmented (#2650). - MP4: Add support for
©mvn(movement name) and©mvi(movement index) metadata, these are now emitted asTextInformationFrameobjects inFormat.metadatawith IDs ofMVNMandMVINrespectively (#2754). - MP4: Ignore tracks with missing
stsdbox (instead of failing to parse the whole file). - Matroska: Add support for DTS-HD detection (#6225).
- Fix an issue in
MatroskaExtractorwhere seeking could be inaccurate for files with multiple tracks. Cue points are now correctly associated with their respective tracks, leading to more precise seeking. - MPEG-TS: Fix
IllegalArgumentExceptionfromReorderingBufferQueuecaused by PES packets with no timestamp (#2764). - Add support for extracting HEIC Motion Photos. The
HeifExtractorcan now parse HEIC files containing embedded video and audio tracks.
- Inspector:
- Introduced a new
:media3-inspectormodule to serve as the dedicated home for media inspection utilities. This module now houses a newandroidx.media3.inspector.MetadataRetriever, which will provide a unified API for both metadata and frame extraction. The existingandroidx.media3.exoplayer.MetadataRetrieveris now deprecated in favor of this new version. - Introduced
androidx.media3.inspector.FrameExtractor, a new public API for frame extraction. ThisAutoCloseableclass provides a way to extract frames with support for HDR video, video effects, and custom decoder selection. It should be created via itsBuilderfor a specificMediaItem. - FrameExtractor: Add
getThumbnail()to extract a representative thumbnail frame from a media file without requiring a specific timestamp. - Add
androidx.media3.inspector.MediaExtractorCompat, a drop-in replacement for the platform'sandroid.media.MediaExtractorthat provides a way to extract raw, encoded media samples from a media file. The existingandroidx.media3.exoplayer.MediaExtractorCompatis now deprecated in favor of this new class.
- Introduced a new
- Audio:
- Make
AudioProcessorinstances aware of seeking. - Allow injecting the new
AudioOutputProviderinterface intoDefaultAudioSink.Builderto support custom audio output paths. The default isAudioTrackAudioOutputProvider. - Handle seeks in
GainProcessor. - Utilize AC-4 decoder profile and level capabilities in track format support assessment (#2580).
- Avoid potential delays caused by handling routing change callbacks at the beginning of playback (#2646).
- Allow codec reuse for EAC3, EAC3-JOC and AC-4 formats (#1346).
- Add support for float PCM samples in
Sonic. - Add support for 16 bit PCM samples in
ToFloatPcmAudioProcessor.
- Make
- Video:
- Disable codec reuse for Dolby-Vision content with different profiles.
- Re-enable workaround for wrongly reported performance points for secure codecs (#2856).
- Text:
- Fix parsing of CEA-6/708 subtitles in Dolby Vision content (#2775).
- Image:
- Fix ScrubbingMode issue where player gets stuck while scrubbing a DASH thumbnail track (#2815).
- DRM:
- Change the return type of
MediaDrmCallbackmethods frombyte[]to a newMediaDrmCallback.Responsetype, to allow returning extra optional information. This is a source breaking change, but breakages can be easily resolved by wrapping the previousbyte[]return value withnew Responsebefore returning. - Add key request info like URL and latency to
AnalyticsListener.onDrmKeysLoaded(#1001). - Move provisioning request data from a URL parameter to the POST body.
- Change the return type of
- Effect:
- Add
Presentation.copyWithUnsetSideRoundedToto round the unset output side whenPresentationis created with a single side length.
- Add
- Muxers:
- Add
MediaMuxerCompat, a drop-in replacement for frameworkMediaMuxer. - Add
MuxerUtil.createMotionPhotoFromJpegImageAndBmffVideo()to allow Motion Photo creation. - Add
WebmMuxerto allow muxing ofOPUS,VORBIS,VP8andVP9media streams into awebmfile format.
- Add
- IMA extension:
- Removal of custom proguard rules, so that apps can use those released in IMA android archive instead.
- Add
ImaServerSideAdInsertionUriBuilder.setNetworkCode, a new API for setting the Google Ad Manager network code for the IMA SDK to handle ads identifiers as specified in Google Ad Manager settings. Network codes are optional but recommended for Full service stream requests. To find the network code, see this article. - Bump IMA dependency to 3.37.0 which requires enabling core library desugaring. This must also be enabled by dependent apps too. See IMA's config notes.
- Support IMA DAI custom UI options in SSAI URI builder. Custom UI options for server side ad insertion include “Skippable” and “About This Ad” rendering support. The feature is currently available for selected publishers behind an allow list. This change also upgrades the IMA SDK version to 3.38.0 (release notes) to access the custom UI options API.
- Fix issue where content preparation error for content after an ad would be wrongly reported as an ad playback error (#2656).
- Session:
- Add new parameter to
MediaSession.Callback.onPlaybackResumptionto indicate if the call happens to gather information only or to start playback (#1764). - Update
MediaSession.ControllerInfo.isTrustedto also declare controllers from the own app as trusted (#2542). - Add
MediaSessionService.triggerNotificationUpdateto manually trigger a notification update (#1833). - Add
ProgressListenerto custom command methods. - Change the default value for
MediaLibrarySession.Builder.setLibraryErrorReplicationModeto non fatal. - Add a
Contextparameter toMediaButtonReceiver.onForegroundServiceStartNotAllowedException(#2625). - Read the volume control ID from the platform
PlaybackInfoinstead of fetching it via binder. This ensures that playback type and volume control ID are read atomically and do match to each other. - Fix bug where
ACTION_UPkey events were filtered out before passing them to the callback for custom handling. This brings parity with what media1 did and the platform does (#2637). - Fix bug where
getCurrentTimeline()was called byPlayerWrappereven when the command isn't available (#2665). - Fix bug where a message was left in the message queue of the main looper which caused a memory leak after the service terminated (#2692).
- When connected to a legacy session app with a
MediaBrowser, custom commands are sent to the session only if the custom action is advertised as a custom action inPlaybackStateCompatof the legacy session. All other custom actions are sent to the service. - Implemented
onAudioSessionIdChangedto notify media controllers when an audio session ID is set by the session (#244). - Fix bug where
KEYCODE_HEADSETHOOKdid not start the player upon and media key eventIntentarriving inonStartCommand(). This is fixed by handling 'KEYCODE_HEADSETHOOK' just likeKEYCODE_MEDIA_PLAY_PAUSE(#2816). - Fix a bug where Surface size was not communicated between the session and the controller, resulting in the failure to apply video effects in demo-session. If you are using a controller, this might be a breaking change if your player cannot handle a
setVideoSurfaceHoldercall. - Fix propagation of non-
StringCharSequencemetadata values like span-styled strings (#2853). - Add
CommandButton.executeActionso that controllers can more easily trigger the intended action. Also allow to specify parameters for some player and session commands to define which action to trigger. - Add backwards-compatibility for
CommandButtoninstances usingPlayer.Commandor non-customSessionCommandto define their action. These are now correctly represented in platform media sessions, for example for System UI or Android Auto. - Fix issue where the same
Bitmapis compressed multiple times when connecting aMediaControllerto a platform media session.
- Add new parameter to
- UI:
- Add
ProgressStateWithTickIntervalclass and the correspondingrememberProgressStateWithTickIntervalComposable tomedia3-ui-composemodule. This state holder is used indemo-composeto display the current position and duration in text form. - Add
MuteButtonStatetoui-composethat handles muting of thePlayervolume. This state holder is used indemo-composeto display mute/unmute toggle button. - Add
ProgressStateWithTickCountclasses and the correspondingrememberProgressStateWithTickCountComposable tomedia3-ui-composemodule. This state holder is used indemo-composeto display progress as a horizontal read-only progress bar. - Add
ContentFrameComposable tomedia3-ui-composewhich combinesPlayerSurfacemanagement with aspect ratio resizing and covering with a shutter. - Work around a known API 34 platform bug causing stretched/cropped videos when using
SurfaceViewinside a ComposeAndroidViewand hence affectingContentFrameandPlayerSurfaceComposables withSURFACE_TYPE_SURFACE_VIEW(#1237, #2811). - Create a new
media3-ui-compose-material3module and add Material3-themed Composables (PlayPauseButton, NextButton, PreviousButton, SeekBackButton, SeekForwardButton, RepeatButton, ShuffleButton, MuteButton) to it. - Add
TimeTextcomposable tomedia3-ui-compose-material3for displaying player progress in a textual form. It can be configured to show the current position, duration, or remaining time. - Add support for placing a media route button in the
PlayerView. - Use
BidiFormatterto correctly display punctuation in RTL text subtitles (#11214).
- Add
- HLS extension:
- Parse HLS interstitial skip attributes.
- Map skip control attributes from the HLS playlist and the asset list document into the
AdPlaybackStatefor public access. - Fix bug where the start time of the playlist was dropped when the EXT-X-PROGRAM-START-DATE tag defining the start time was removed from a playlist (#2760).
- Use binary search to find the segment index of a given position in the playlist (#2826).
- Add
HlsInterstitialsAdsLoader.skipCurrentAd()andskipCurrentAdGroup()and corresponding methods to skip ads and ad groups by index. - Add
HlsInterstitialsAdsLoader.Listener.onAdStartedto report the start of an ad period (#2859). - Accept space as a date/time separator in ISO 8601 date-time strings.
- Properly handle fetching the next chunk for an
HlsMediaPlaylistwith no segments (#2821). - Use the default start position for pre rolls with live streams.
- DASH extension:
- Fix
UnsupportedOperationExceptionwhen playing DASH streams with a non-hierarchicaldata:URI manifest (#2688). - Reset
LiveConfigurationto the value provided by theMediaItemof theDashMediaSourcewhen released and when the media item is updated by the user (#2606). - Avoid crashes caused by invalid manifest updates that were not reported as player errors (#2805).
- Fix
- RTSP extension:
- Handle error of missing RTP packets when processing fragmented NAL units for H264 and H265 (#2613).
- Decoder extensions (FFmpeg, VP9, AV1, etc.):
- AV1 Extension: The AV1 software decoder now uses the high-performance
dav1dlibrary, replacing the previouslibgav1implementation for improved decoding speed. - FFmpeg extension: Fix an issue that prevented some FLAC files from playing by ensuring the
STREAMINFOblock is correctly parsed and passed to the decoder (#2887).
- AV1 Extension: The AV1 software decoder now uses the high-performance
- Cast extension:
- Add
CastPlayer.Builder, which enablesCastPlayerto do both local and Cast playback. To keep the oldCastPlayerbehavior of supporting only Cast playback, you can useRemoteCastPlayer. The pre-existingCastPlayerconstructors keep their old behavior, but are deprecated in favour of using theCastPlayerorRemoteCastPlayerbuilders instead. - Stop enforcing a non-null mime type in
DefaultMediaItemConverter. - Use
MediaItem.mediaMetadata.mediaTypeto infer the Cast MEDIA_TYPE to use inDefaultCastOptionsProvider#toMediaQueueItem, when available. - Enable remote to local transfers in
DefaultCastOptionsProvider. - Add support for Cast in the Session demo.
- Add support for displaying a media route button on a Composable UI.
- Add support for displaying a media route button on an action bar menu.
- Add support for displaying a media route button as a View UI.
- Add
- Test Utilities:
- Add maximum time diff for the auto-advancing behavior of
FakeClock. It defaults to 1 second, but is configurable viaFakeClock.Builder. - Add maximum time diff between messages for
RobolectricUtil.runMainLooperUntil(andrunLooperUntil). It defaults to 1 second, but is configurable via new overloads of these methods. - Move
CapturingRenderersFactoryfromtest-utilstotest-utils-robolectric.
- Add maximum time diff for the auto-advancing behavior of
- Remove deprecated symbols:
- Remove deprecated
DefaultPreloadManagerconstructor. UseDefaultPreloadManager.Builderinstead. - Removed deprecated
EditedMediaItemSequenceconstructors. UseEditedMediaItemSequence.Builderinstead. - Remove
BitmapFactoryImageDecoder.BitmapDecoder. UseExternallyLoadedImageDecoderinstead. - Remove deprecated
ShadowMediaCodecConfig.forAllSupportedMimeTypes(). UseShadowMediaCodecConfig.withAllDefaultSupportedCodecs()instead. - Remove deprecated
ShadowMediaCodecConfig.withNoDefaultSupportedMimeTypes(). UseShadowMediaCodecConfig.withNoDefaultSupportedCodecs()instead.
- Remove deprecated