Skip to content

Update DefaultAudioSink.java#3309

Open
AndresBC-123 wants to merge 1193 commits into
androidx:mainfrom
AndresBC-123:patch-3
Open

Update DefaultAudioSink.java#3309
AndresBC-123 wants to merge 1193 commits into
androidx:mainfrom
AndresBC-123:patch-3

Conversation

@AndresBC-123

Copy link
Copy Markdown

Custom audio processors are allowed on any type of audio.

icbaker and others added 30 commits November 21, 2025 10:58
PiperOrigin-RevId: 832360077
(cherry picked from commit b550a71)
PiperOrigin-RevId: 833253928
(cherry picked from commit 07c91d2)
PiperOrigin-RevId: 833259723
(cherry picked from commit b0c438d)
In `DefaultHlsPlaylistTracker`, we have a `FirstPrimaryMediaPlaylistListener` which handles the load errors of the first media playlist and applies exclusion according
to the `LoadErrorHandlingPolicy` before the first media period has been created and prepared. It actually implements `PlaylistEventListener`, and according to the javadoc of `PlaylistEventListener.onPlaylistError`, the return boolean value suggests whether the playlist will be excluded from future loads, and then is used to instruct the `Loader` whether to retry to load the failed playlist (if exclusion failed, we retry the failed playlist, otherwise we do not retry).

However, the `FirstPrimaryMediaPlaylistListener` always return `false` for `onPlaylistError` even the failed playlist url has been excluded and we have selected a new primary url - https://github.com/androidx/media/blob/main/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTracker.java#L928. The linked `excludedPlaylist()` method returns a boolean value suggesting if the regarding url is primary despite of being excluded, which I further interpret it as "this url used to be primary, and we cannot find another primary url, and it remains primary", thus this return value being `true` suggests that the exclusion failed, otherwise it suggests that the exclusion succeeded, then we shouldn't retry the failed url as it is no longer primary.

PiperOrigin-RevId: 833297663
(cherry picked from commit 738e844)
These should have been part of androidx@b770edf

PiperOrigin-RevId: 833302067
(cherry picked from commit 58b1549)
- Adds `setVideoCodecParameters` and listener methods for video.
- Refactors common audio/video parameter logic to MediaCodecRenderer.

PiperOrigin-RevId: 833317008
(cherry picked from commit b8513f2)
The implementation of `processFragmentationUnitPacket` should not
mutate its `ParsableByteArray` parameter, since this is ultimately
backed by an 'immutable' `RtpPacket.payloadData` field.

Previous to this change, the
`RtpH265ReaderTest.consume_validMixedFragmentationPacketsAndSingleNALU`
test would fail if
`consume_invalidAggregationPacketWithSingleNalu_throwsParserException`
or
`consume_mixedInvalidFragmentationPacketAndValidSingleNALU` ran before
it, due to this unexpected mutation.

PiperOrigin-RevId: 833423314
(cherry picked from commit f60dda2)
For live, the public content position with which to query
the pending asset lists must be converted to a period
position with the windowPositionInFirstPeriodUs of the
window with which the content position was calculated.

Thus for a live stream, this conversion of the content
position must always be done with the timeline that has
been used by the player when returning `getContentPosition()`.

#cherrypick

PiperOrigin-RevId: 833434897
(cherry picked from commit eca14a1)
This is a refactoring that makes insertion more robust
in case interstitials are not in order of their
resulting ad insertion position.

#cherrypick

PiperOrigin-RevId: 833454035
(cherry picked from commit c763bdc)
#cherrypick

PiperOrigin-RevId: 833710784
(cherry picked from commit 0ca4223)
PiperOrigin-RevId: 833735833
(cherry picked from commit e3e5f20)
Fix a couple of tests that were passing invalid hex strings (odd number
of chars) where the final char was previously being silently truncated.

PiperOrigin-RevId: 833749765
(cherry picked from commit c54c9b2)
This is the equivalent change that was already done for all custom
controller->session commands in androidx@14ce152.

PiperOrigin-RevId: 833764701
(cherry picked from commit 5831b84)
This change moves the core logic for media extraction from `MediaExtractorCompat` into a new `MediaExtractorCompatInternal` class.

Following this change, `MediaExtractorCompat` becomes a thin wrapper that delegates all of its calls to an instance of `MediaExtractorCompatInternal`.

This is a preparatory refactoring to enable the future introduction of `MediaExtractorCompat` in the new `:media3-inspector` module. It allows both the existing (and soon-to-be-deprecated) class and the new one to share the same underlying implementation during the migration period without creating circular dependencies. This pattern is similar to the one used for `MetadataRetriever` in androidx@a1bc8de.

#cherrypick

PiperOrigin-RevId: 833785780
(cherry picked from commit 7fcdbec)
PiperOrigin-RevId: 833823330
(cherry picked from commit a4a6f6d)
Fixes an issue where ConcatenatingMediaSource2 produces a different playback
dump compared to clipped MediaItem, when non-reference frame dropping is enabled.
The difference is caused by period duration for ConcatenatingMediaSource2 which
becomes known after the initial stream change.

PiperOrigin-RevId: 833830040
(cherry picked from commit e72c8fb)
This change introduces a new `androidx.media3.inspector.MediaExtractorCompat` in the `:inspector` module, establishing it as the new home for this media inspection utility.

The new `MediaExtractorCompat` utilizes the existing `MediaExtractorCompatInternal` implementation, which was extracted in androidx@7fcdbec. The `androidx.media3.exoplayer.MediaExtractorCompat` is now deprecated in favor of this new class.

This follows the pattern established by `MetadataRetriever` in androidx@c008eaf to centralize inspection tools in the `:inspector` module.

The associated tests (`MediaExtractorCompatTest` and `MediaExtractorContractTest`) have been moved from the `:exoplayer` module to `:inspector` to align with the new class location.

#cherrypick

PiperOrigin-RevId: 833838905
(cherry picked from commit 05f35b6)
The button enable state depends on the available commands. When they
change though, the isEnabled state is only updated for the next
recomposition. This means that calling onClick() may happen at a point
where the button is still "enabled", but the command can no longer be
called.

The method contract is to be callable when isEnabled==true, so we
should change all assertion to check this explicitly. Because of
this edge case, we also need to verify the relevant player commands
are available just before calling the respective player method.

#cherrypick

PiperOrigin-RevId: 833841451
(cherry picked from commit 348a384)
Currently, the lifecycle of the update job is only loosely
coupled to the observeProgress method call. It's started
by this call, but not stopped if the observation goes out
of scope. It may also be started (without ever calling
observeProgress) by updating the tick interval.

To avoid surprising effects or overruning update jobs,
we can more clearly align the job lifecycle to run
for at most as long as the observeProgress method.

#cherrypick

PiperOrigin-RevId: 833857639
(cherry picked from commit 1bc92b8)
#cherrypick

PiperOrigin-RevId: 833874736
(cherry picked from commit 5847c0a)
This type has been `@VisibleForTesting` since it was introduced in the
library in [1.2.0](https://github.com/androidx/media/blob/1.2.0/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/image/BitmapFactoryImageDecoder.java#L56),
and has been deprecated since [1.8.0](https://github.com/androidx/media/blob/1.8.0/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/image/BitmapFactoryImageDecoder.java#L60).

This change migrates the last few tests away from this interface to
`ExternallyLoadedImageDecoder`.

PiperOrigin-RevId: 834188416
(cherry picked from commit 950befa)
PiperOrigin-RevId: 834247649
(cherry picked from commit a930199)
The underlying timeout error in the platform seems to be
fixed and we can re-enable the optimization.

Issue: androidx#1641

PiperOrigin-RevId: 834262179
(cherry picked from commit 414c260)
And use it in `RtpH265ReaderTest` to fix an order-dependent test
failure caused by some tests mutating some of the `static final byte[]`
"constants".

PiperOrigin-RevId: 834328148
(cherry picked from commit 291b5c8)
The issue arises from a race condition where multiple code paths can attempt to release the worker thread. This can lead to an `IllegalStateException` if a message is posted to the handler of an already-dead thread.

This change fixes the race condition by introducing a `synchronized release()` method in `RetrievalTask`. This method uses a boolean flag to ensure that the `MESSAGE_RELEASE` is sent only once, making the release operation idempotent. All three call sites that can trigger a release now use this synchronized method.

Fixes: Issue: androidx#2899

#cherrypick

PiperOrigin-RevId: 834771336
(cherry picked from commit ba17180)
We calculate the memory usage based on the selected tracks. However,
this process only has a minimum limit to ensure successful playback,
but no maximum limit to avoid memory issues.

Adding a maximum limits helps with edge cases selecting multiple
video tracks or a large amount of additional audio/text tracks. Most
playback should be unaffected and any custom override of
calculateTotalTargetBufferBytes() is also unaffected.

Issue: androidx#2860
PiperOrigin-RevId: 834798077
(cherry picked from commit 43a8d9f)
When the sample mime type resolves to UNKNOWN, we currently fall back
to the container mime type to resolve the track type. This is unexpected
for sample mime types that are set, but not recognized, because the
container mime type is often set to the "primary" track in a muxed file.
We should only use the container mime type if the sample mime type is
not set at all.

Issue: androidx#2860

#cherrypick

PiperOrigin-RevId: 834842598
(cherry picked from commit d96978f)
All button state have a repeating pattern of updating their internal
state values in 3 different places. The observe method is also
re-implemented in the same pattern in all classes. This allows us
to move the shared pattern to a helper class, so no state update
code duplication is needed and all relevant logic is in a single
readable place.

PiperOrigin-RevId: 834853446
(cherry picked from commit 856bb1b)
Prevent skipping keyframe reset when renderers have had their decoders flushed while processing a seek. This can occur when seeking near the end of a media item while playing a playlist or with repeat mode. This ensures the player correctly handles the seek within the current item's bounds.

The solution is that a renderer that has not received a keyframe yet must return false to `supportsResetPositionWithoutKeyFrameReset`.

#cherrypick

PiperOrigin-RevId: 835139084
(cherry picked from commit d352612)
tianyif and others added 26 commits May 6, 2026 12:42
In `PreloadMediaSource.PreloadMediaPeriodCallback.onPrepared()`, we do not access the `preloadingMediaPeriodAndKey` immediately, instead we post another handler event and access it there. If a `PreloadMediaSource` gets calls of `clear()` or `releasePreloadMediaSource()` where we clears the `PreloadMediaPeriod`, it is possible that the period releasing and `preloadingMediaPeriodAndKey` nullification happen in between `onPrepared()` and the execution of the posted handler event, then the NPE will occur.

As a fix, in the execution of the posted event in `PreloadMediaSource.PreloadMediaPeriodCallback.onPrepared()` and `PreloadMediaSource.PreloadMediaPeriodCallback.onContinueLoadingRequested()`, we should check the presence of the `preloadingMediaPeriodAndKey` before attempting to access it.

PiperOrigin-RevId: 884602600
(cherry picked from commit 5f7e0dd)
In some scenearios, a MediaCodec decoder may reach a faulty state and release itself without the Renderer's knowledge. In these cases, attempts to call `codec.flush()` or `codec.release()` may throw `IllegalStateExceptions`. This is why the calls to `renderer.disable()` & `renderer.reset()` are in try/catch blocks in ExoPlayerImplInternal.resetInternal() (which is generally called when an ExoPlaybackException is thrown).

The solution is to wrap these calls in try/catch blocks in `RendererHolder.disablePrewarming`.

PiperOrigin-RevId: 886184981
(cherry picked from commit f459358)
Previously, `FrameExtractor` would hang indefinitely when processing
unsupported media. For example, when provided with an audio-only file,
the internally paused `ExoPlayer` would sit in `STATE_READY` forever
because the playback position never advanced to the end of the track.

This change introduces safety mechanisms in `FrameExtractorInternal`
to prevent these hangs and fail gracefully:
- Early failure: Intercepts `onTracksChanged` to throw an
  `IllegalArgumentException` if no video track is found.
- Subsequent request failure: Checks cached tracks directly in `submitTask`
  for already-prepared players to fail instantly, avoiding downstream
  `NullPointerException`s.
- Safety net: Listens for `Player.STATE_ENDED` to catch empty tracks
  or zero-duration clips, throwing an `IllegalStateException` when
  the stream ends without outputting a frame.

Additionally, safe null checks are added to the `PlayerListener`
callbacks to prevent `NullPointerException` race conditions during
asynchronous error propagation and frame deduplication.

PiperOrigin-RevId: 886212247
(cherry picked from commit abba9d1)
Attempting to extract frames from DRM protected media (like Widevine
L1 or L3) often results in blank or garbled frames because the OS
restricts pixel readback from secure surfaces (enforced strictly at
the hardware level for L1, and frequently at the framework level for L3).

This change prevents this by failing fast and throwing an
`UnsupportedOperationException` when encrypted media is encountered.

To cleanly implement this alongside existing track checks, all track validation logic is centralized into a new `assertTracksSupported` helper in `FrameExtractorInternal`. The DRM check intelligently inspects
ExoPlayer's track selection to:
- Reject the extraction if a DRM protected video track is actively selected.
- Reject the extraction if no clear video track is selected but a DRM
  track exists in the file (handling cases where the track selector drops
  the encrypted track because no `DrmSessionManager` is present).
- Safely allow extraction to proceed if the player successfully falls
  back to a clear video track.

PiperOrigin-RevId: 886243312
(cherry picked from commit e5d69ae)
PiperOrigin-RevId: 886243586
(cherry picked from commit 2949c6c)
If MediaSource preparation throws an unchecked RuntimeException,
it crashes the shared background worker thread.
Because this thread is shared, a single crash poisons the static worker
pool, causing all subsequent metadata retrievals to silently ignore
messages and hang indefinitely.

This catches RuntimeExceptions within the message loop, ensuring the
error is properly propagated to the caller's future. It also wraps the
release sequence in a finally block to guarantee that the worker thread
reference is always released, allowing the thread to survive and
continue serving future requests.

PiperOrigin-RevId: 886821955
(cherry picked from commit 5568f19)
The logic can be improved to not discard the codec if the frame rates
are compatible (a multiple of each other), as this wouldn't generally
cause a problem even if the screen refresh rate stays the same.

We should also keep secure codecs at ABR transitions where they are
otherwise likely to introduce a black frame at the transition point,
which is more of a problem than the potentially misaligned screen
refresh rate.

Issue: androidx#3120
PiperOrigin-RevId: 886822660
(cherry picked from commit 070291b)
This is already done for the pending evaluation of discontinuity and
matches the logic in ClippingMediaPeriod and ProgressiveMediaPeriod
for similar steps.

The window of opportunity is so tiny/non-existant, that it's not
really feasible to write a test for it that triggers a problem
(it might not even be a problem in fact, more of a correctness fix).

Issue: androidx#3081
PiperOrigin-RevId: 886855683
(cherry picked from commit 345988b)
Corrected instances of `{code}` to the proper Javadoc tag `{@code}` in comments.

PiperOrigin-RevId: 888668429
(cherry picked from commit d85b17f)
PiperOrigin-RevId: 888783836
(cherry picked from commit 73adbb2)
The previous code was incorrectly treating the byte values as signed when converting them to ints, resulting in level 150 creating a codec string like `apv1.apvf33.apvl-106.apvb0`.

#cherrypick

PiperOrigin-RevId: 889138527
(cherry picked from commit 05d56f4)
This adds a test for the current behaviour, to ensure that a follow-up
change to resolve Issue: androidx#3136 works as expected.

The overall handling of supplemental codecs may change as a result of
Issue: androidx#3135.

#cherrypick

PiperOrigin-RevId: 889176663
(cherry picked from commit b476856)
PiperOrigin-RevId: 889504787
(cherry picked from commit 1eafe45)
This was pointed out as part of Issue: androidx#2978 but I'm sending it
separately to keep the code history clearer.

This CL also removes a stale comment that should have been removed as
part of androidx@bdf7e6f.

PiperOrigin-RevId: 889730426
(cherry picked from commit 4a32661)
PiperOrigin-RevId: 890443273
(cherry picked from commit 7eb9074)
These `ListenableFuture` instances come from subclasses of
`SimpleBasePlayer`, so they could implement unexpected `.equals()`
semantics, which could lead to very confusing/buggy `SimpleBasePlayer`
behaviour. This change switches to `Sets.newIdentityHashSet` to resolve
the problem by making it clear we intend to compare these futures only
by identity equality instead of `equals()`.

PiperOrigin-RevId: 891660169
(cherry picked from commit 5a0687b)
Apps can setup ExoPlayer with a different thread than the main thread. In
such a case we need to propagate exceptions across thread boundaries to make
sure an exception is actually handled in the same way when the app thread
is not the main thread.

Issue: androidx#2499
PiperOrigin-RevId: 891693820
(cherry picked from commit dd8c4b8)
PiperOrigin-RevId: 892465841
(cherry picked from commit a88d61e)
Avoid calling binder methods on known dead recipients. If a binder
dies, we already auto-release the controller, but the log spam
comes from the release logic itself. So this change is adding extra
checks for all calls triggered from within MediaController.release()

PiperOrigin-RevId: 892824209
(cherry picked from commit efadb0c)
We previously gated on FLAG_HANDLES_QUEUE_COMMANDS too, which
is wrong because FLAG_HANDLES_QUEUE_COMMANDS only guards access to
methods like add/removeQueueItem.

#cherrypick

PiperOrigin-RevId: 892978981
(cherry picked from commit 2168260)
* Fix NPE in MediaSessionImpl caused by a race condition where isMediaNotificationControllerConnected is true but the actual controller has already disconnected from the connected controllers list during session shutdown.
* Replace checkNotNull(getMediaNotificationControllerInfo()) with null-safe fallbacks in resolveControllerInfoForCallback(), applyMediaButtonKeyEvent(), and MediaLibrarySessionImpl.getRecentMediaItemAtDeviceBootTime().
* When the notification controller is null, gracefully degrade: fall back to the original controller info or return early (event not handled), instead of crashing.
* Addresses upstream Media3 bug (GitHub issue androidx#2770) that surfaces during background playback stop commands from System UI / Bluetooth / notification dismissal.

Issue: androidx#2770
PiperOrigin-RevId: 893029141
(cherry picked from commit 464e3be)
This change expands the shared `androidx.media3.test.utils.FakeTrackSelection` to support specific track selections and proper exclusion logic (via `super.excludeTrack` and `super.isTrackExcluded`).

PiperOrigin-RevId: 896417851
(cherry picked from commit c83db1b)
Before this change, `FragmentedMp4Extractor` only output the seek map
for the first `sidx` box it encountered unless `FLAG_MERGE_FRAGMENTED_SIDX`
was enabled. This locked the total reported duration of the media to the
length of the first segment for playbacks that did not opt-in to the
upfront linear scan.

This change restores progressive duration updates by unconditionally
emitting a seek map whenever a `sidx` box is encountered during normal
playback extraction. It uses the `ChunkIndexMerger` to combine the newly
encountered `sidx` data with previously read boxes. This fixes the
regression where the duration was stuck, and prevents the older
regression where previous seek points were overwritten (breaking
backward seekability).

The active upfront linear scan logic tied to `FLAG_MERGE_FRAGMENTED_SIDX`
remains unaffected.

Issue: androidx#3154
PiperOrigin-RevId: 896438268
(cherry picked from commit 3fca19b)
PiperOrigin-RevId: 911984945
(cherry picked from commit 5d17087)
PiperOrigin-RevId: 912005951
(cherry picked from commit 0024781)
Custom audio processors are allowed on any type of audio.
@icbaker

icbaker commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Please target this change against the main branch.

@AndresBC-123 AndresBC-123 changed the base branch from release to main July 1, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.