From bd664ad786f60620db11172dc5eea6eb143b3823 Mon Sep 17 00:00:00 2001 From: christosts Date: Mon, 6 Feb 2023 17:21:02 +0000 Subject: [PATCH 01/33] Detect HEVC HDR10 codec profile more accurately In MediaCodecUtil, use Format.colorInfo, besides the codec string, to accurately map to a 10bit HEVC profile. PiperOrigin-RevId: 507500071 (cherry picked from commit a50ea94525d2522436fbc812dec12aee53b3c1bf) --- RELEASENOTES.md | 6 ++++++ .../exoplayer/mediacodec/MediaCodecUtil.java | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 38c631388ea..82074383a41 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -32,6 +32,12 @@ This release corresponds to the * Audio: * Use the compressed audio format bitrate to calculate the min buffer size for `AudioTrack` in direct playbacks (passthrough). + * Fix bug where some playbacks fail when tunneling is enabled and + `AudioProcessors` are active, e.g. for gapless trimming + ([#10847](https://github.com/google/ExoPlayer/issues/10847)). +* Video: + * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of + `HEVCProfileMain10`. * Text: * Fix `TextRenderer` passing an invalid (negative) index to `Subtitle.getEventTime` if a subtitle file contains no cues. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecUtil.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecUtil.java index e97e053084d..81af112a670 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecUtil.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecUtil.java @@ -252,7 +252,7 @@ public static Pair getCodecProfileAndLevel(Format format) { return getVp9ProfileAndLevel(format.codecs, parts); case CODEC_ID_HEV1: case CODEC_ID_HVC1: - return getHevcProfileAndLevel(format.codecs, parts); + return getHevcProfileAndLevel(format.codecs, parts, format.colorInfo); case CODEC_ID_AV01: return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo); case CODEC_ID_MP4A: @@ -731,7 +731,8 @@ private static Pair getDolbyVisionProfileAndLevel( } @Nullable - private static Pair getHevcProfileAndLevel(String codec, String[] parts) { + private static Pair getHevcProfileAndLevel( + String codec, String[] parts, @Nullable ColorInfo colorInfo) { if (parts.length < 4) { // The codec has fewer parts than required by the HEVC codec string format. Log.w(TAG, "Ignoring malformed HEVC codec string: " + codec); @@ -748,7 +749,15 @@ private static Pair getHevcProfileAndLevel(String codec, Strin if ("1".equals(profileString)) { profile = CodecProfileLevel.HEVCProfileMain; } else if ("2".equals(profileString)) { - profile = CodecProfileLevel.HEVCProfileMain10; + if (colorInfo != null && colorInfo.colorTransfer == C.COLOR_TRANSFER_ST2084) { + profile = CodecProfileLevel.HEVCProfileMain10HDR10; + } else { + // For all other cases, we map to the Main10 profile. Note that this includes HLG + // HDR. On Android 13+, the platform guarantees that a decoder that advertises + // HEVCProfileMain10 will be able to decode HLG. This is not guaranteed for older + // Android versions, but we still map to Main10 for backwards compatibility. + profile = CodecProfileLevel.HEVCProfileMain10; + } } else { Log.w(TAG, "Unknown HEVC profile string: " + profileString); return null; From ba2b9b3d67d1133e77c402978ed10bb8f9e791fa Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 7 Feb 2023 12:06:49 +0000 Subject: [PATCH 02/33] Fix AudioTrackPositionTracker logic for playback speed adjustments The AudioTrackPositionTracker needs to correct positions by the speed set on the AudioTrack itself whenever it makes estimations based on real-time (=the real-time playout duration is not equal to the media duration played). This happens for the main playback path already, but not for the mode in which the position is estimated from the playback head position and also not in the phase after the track has been stopped. Both cases are not very noticeable during normal playback, but become relevant when playing in offload mode. PiperOrigin-RevId: 507736408 (cherry picked from commit 01d7bc72794b98d19cad2be5c70de2f755bff9f1) --- .../exoplayer/audio/AudioTrackPositionTracker.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java index 952c5fb8b6e..417d0fb0273 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java @@ -253,6 +253,7 @@ public void setAudioTrackPlaybackSpeed(float audioTrackPlaybackSpeed) { if (audioTimestampPoller != null) { audioTimestampPoller.reset(); } + resetSyncParams(); } public long getCurrentPositionUs(boolean sourceEnded) { @@ -282,7 +283,9 @@ public long getCurrentPositionUs(boolean sourceEnded) { // getPlaybackHeadPositionUs() only has a granularity of ~20 ms, so we base the position off // the system clock (and a smoothed offset between it and the playhead position) so as to // prevent jitter in the reported positions. - positionUs = systemTimeUs + smoothedPlayheadOffsetUs; + positionUs = + Util.getMediaDurationForPlayoutDuration( + systemTimeUs + smoothedPlayheadOffsetUs, audioTrackPlaybackSpeed); } if (!sourceEnded) { positionUs = max(0, positionUs - latencyUs); @@ -452,7 +455,9 @@ private void maybeSampleSyncParams() { long systemTimeUs = System.nanoTime() / 1000; if (systemTimeUs - lastPlayheadSampleTimeUs >= MIN_PLAYHEAD_OFFSET_SAMPLE_INTERVAL_US) { // Take a new sample and update the smoothed offset between the system clock and the playhead. - playheadOffsets[nextPlayheadOffsetIndex] = playbackPositionUs - systemTimeUs; + playheadOffsets[nextPlayheadOffsetIndex] = + Util.getPlayoutDurationForMediaDuration(playbackPositionUs, audioTrackPlaybackSpeed) + - systemTimeUs; nextPlayheadOffsetIndex = (nextPlayheadOffsetIndex + 1) % MAX_PLAYHEAD_OFFSET_COUNT; if (playheadOffsetCount < MAX_PLAYHEAD_OFFSET_COUNT) { playheadOffsetCount++; @@ -580,7 +585,9 @@ private long getPlaybackHeadPosition() { if (stopTimestampUs != C.TIME_UNSET) { // Simulate the playback head position up to the total number of frames submitted. long elapsedTimeSinceStopUs = (SystemClock.elapsedRealtime() * 1000) - stopTimestampUs; - long framesSinceStop = (elapsedTimeSinceStopUs * outputSampleRate) / C.MICROS_PER_SECOND; + long mediaTimeSinceStopUs = + Util.getMediaDurationForPlayoutDuration(elapsedTimeSinceStopUs, audioTrackPlaybackSpeed); + long framesSinceStop = (mediaTimeSinceStopUs * outputSampleRate) / C.MICROS_PER_SECOND; return min(endPlaybackHeadPosition, stopPlaybackHeadPosition + framesSinceStop); } From e89c14aaf3163ebc649571d45613f7aba8c162ba Mon Sep 17 00:00:00 2001 From: microkatz <45770613+microkatz@users.noreply.github.com> Date: Wed, 8 Feb 2023 14:08:36 +0000 Subject: [PATCH 03/33] Merge pull request #248 from lemondoglol:update-segment-size PiperOrigin-RevId: 507784608 (cherry picked from commit ecd91d865c0888c6cc1aa3554877f4df798f5379) --- RELEASENOTES.md | 3 ++ .../exoplayer/offline/SegmentDownloader.java | 36 +++++++++++++++--- .../dash/offline/DashDownloader.java | 38 +++++++++++++++++-- .../exoplayer/hls/offline/HlsDownloader.java | 38 +++++++++++++++++-- .../smoothstreaming/offline/SsDownloader.java | 34 +++++++++++++++-- 5 files changed, 135 insertions(+), 14 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 82074383a41..c23254bf53d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -20,6 +20,9 @@ This release corresponds to the for seeking. * Use theme when loading drawables on API 21+ ([#220](https://github.com/androidx/media/issues/220)). + * Make the maximum difference of the start time of two segments to be + merged configurable in `SegmentDownloader` and subclasses + ([#248](https://github.com/androidx/media/pull/248)). * Add `ConcatenatingMediaSource2` that allows combining multiple media items into a single window ([#247](https://github.com/androidx/media/issues/247)). diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/SegmentDownloader.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/SegmentDownloader.java index d4b8ece7262..7a8ac0ba2bf 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/SegmentDownloader.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/SegmentDownloader.java @@ -75,8 +75,9 @@ public int compareTo(Segment other) { } } + public static final long DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS = 20 * C.MILLIS_PER_SECOND; + private static final int BUFFER_SIZE_BYTES = 128 * 1024; - private static final long MAX_MERGED_SEGMENT_START_TIME_DIFF_US = 20 * C.MICROS_PER_SECOND; private final DataSpec manifestDataSpec; private final Parser manifestParser; @@ -86,6 +87,7 @@ public int compareTo(Segment other) { private final CacheKeyFactory cacheKeyFactory; @Nullable private final PriorityTaskManager priorityTaskManager; private final Executor executor; + private final long maxMergedSegmentStartTimeDiffUs; /** * The currently active runnables. @@ -99,6 +101,24 @@ public int compareTo(Segment other) { private volatile boolean isCanceled; + /** + * @deprecated Use {@link SegmentDownloader#SegmentDownloader(MediaItem, Parser, + * CacheDataSource.Factory, Executor, long)} instead. + */ + @Deprecated + public SegmentDownloader( + MediaItem mediaItem, + Parser manifestParser, + CacheDataSource.Factory cacheDataSourceFactory, + Executor executor) { + this( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); + } + /** * @param mediaItem The {@link MediaItem} to be downloaded. * @param manifestParser A parser for manifests belonging to the media to be downloaded. @@ -107,12 +127,16 @@ public int compareTo(Segment other) { * @param executor An {@link Executor} used to make requests for the media being downloaded. * Providing an {@link Executor} that uses multiple threads will speed up the download by * allowing parts of it to be executed in parallel. + * @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two + * segments, up to which the segments (of the same URI) should be merged into a single + * download segment, in milliseconds. */ public SegmentDownloader( MediaItem mediaItem, Parser manifestParser, CacheDataSource.Factory cacheDataSourceFactory, - Executor executor) { + Executor executor, + long maxMergedSegmentStartTimeDiffMs) { checkNotNull(mediaItem.localConfiguration); this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri); this.manifestParser = manifestParser; @@ -123,6 +147,7 @@ public SegmentDownloader( cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory(); priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager(); activeRunnables = new ArrayList<>(); + maxMergedSegmentStartTimeDiffUs = Util.msToUs(maxMergedSegmentStartTimeDiffMs); } @Override @@ -145,7 +170,7 @@ public final void download(@Nullable ProgressListener progressListener) // Sort the segments so that we download media in the right order from the start of the // content, and merge segments where possible to minimize the number of server round trips. Collections.sort(segments); - mergeSegments(segments, cacheKeyFactory); + mergeSegments(segments, cacheKeyFactory, maxMergedSegmentStartTimeDiffUs); // Scan the segments, removing any that are fully downloaded. int totalSegments = segments.size(); @@ -416,7 +441,8 @@ private void removeActiveRunnable(int index) { } } - private static void mergeSegments(List segments, CacheKeyFactory keyFactory) { + private static void mergeSegments( + List segments, CacheKeyFactory keyFactory, long maxMergedSegmentStartTimeDiffUs) { HashMap lastIndexByCacheKey = new HashMap<>(); int nextOutIndex = 0; for (int i = 0; i < segments.size(); i++) { @@ -425,7 +451,7 @@ private static void mergeSegments(List segments, CacheKeyFactory keyFac @Nullable Integer lastIndex = lastIndexByCacheKey.get(cacheKey); @Nullable Segment lastSegment = lastIndex == null ? null : segments.get(lastIndex); if (lastSegment == null - || segment.startTimeUs > lastSegment.startTimeUs + MAX_MERGED_SEGMENT_START_TIME_DIFF_US + || segment.startTimeUs > lastSegment.startTimeUs + maxMergedSegmentStartTimeDiffUs || !canMergeSegments(lastSegment.dataSpec, segment.dataSpec)) { lastIndexByCacheKey.put(cacheKey, nextOutIndex); segments.set(nextOutIndex, segment); diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/offline/DashDownloader.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/offline/DashDownloader.java index e3c41727288..73a59291b3c 100644 --- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/offline/DashDownloader.java +++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/offline/DashDownloader.java @@ -100,7 +100,30 @@ public DashDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSour */ public DashDownloader( MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) { - this(mediaItem, new DashManifestParser(), cacheDataSourceFactory, executor); + this( + mediaItem, + new DashManifestParser(), + cacheDataSourceFactory, + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); + } + + /** + * @deprecated Use {@link DashDownloader#DashDownloader(MediaItem, Parser, + * CacheDataSource.Factory, Executor, long)} instead. + */ + @Deprecated + public DashDownloader( + MediaItem mediaItem, + Parser manifestParser, + CacheDataSource.Factory cacheDataSourceFactory, + Executor executor) { + this( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); } /** @@ -113,13 +136,22 @@ public DashDownloader( * @param executor An {@link Executor} used to make requests for the media being downloaded. * Providing an {@link Executor} that uses multiple threads will speed up the download by * allowing parts of it to be executed in parallel. + * @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two + * segments, up to which the segments (of the same URI) should be merged into a single + * download segment, in milliseconds. */ public DashDownloader( MediaItem mediaItem, Parser manifestParser, CacheDataSource.Factory cacheDataSourceFactory, - Executor executor) { - super(mediaItem, manifestParser, cacheDataSourceFactory, executor); + Executor executor, + long maxMergedSegmentStartTimeDiffMs) { + super( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + maxMergedSegmentStartTimeDiffMs); baseUrlExclusionList = new BaseUrlExclusionList(); } diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java index 777694e9f63..7c82bee608a 100644 --- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java +++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java @@ -89,7 +89,30 @@ public HlsDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSourc */ public HlsDownloader( MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) { - this(mediaItem, new HlsPlaylistParser(), cacheDataSourceFactory, executor); + this( + mediaItem, + new HlsPlaylistParser(), + cacheDataSourceFactory, + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); + } + + /** + * @deprecated Use {@link HlsDownloader#HlsDownloader(MediaItem, Parser, CacheDataSource.Factory, + * Executor, long)} instead. + */ + @Deprecated + public HlsDownloader( + MediaItem mediaItem, + Parser manifestParser, + CacheDataSource.Factory cacheDataSourceFactory, + Executor executor) { + this( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); } /** @@ -102,13 +125,22 @@ public HlsDownloader( * @param executor An {@link Executor} used to make requests for the media being downloaded. * Providing an {@link Executor} that uses multiple threads will speed up the download by * allowing parts of it to be executed in parallel. + * @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two + * segments, up to which the segments (of the same URI) should be merged into a single + * download segment, in milliseconds. */ public HlsDownloader( MediaItem mediaItem, Parser manifestParser, CacheDataSource.Factory cacheDataSourceFactory, - Executor executor) { - super(mediaItem, manifestParser, cacheDataSourceFactory, executor); + Executor executor, + long maxMergedSegmentStartTimeDiffMs) { + super( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + maxMergedSegmentStartTimeDiffMs); } @Override diff --git a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/offline/SsDownloader.java b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/offline/SsDownloader.java index 4ca632271bb..6d2ded5a4c8 100644 --- a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/offline/SsDownloader.java +++ b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/offline/SsDownloader.java @@ -93,7 +93,26 @@ public SsDownloader( .build(), new SsManifestParser(), cacheDataSourceFactory, - executor); + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); + } + + /** + * @deprecated Use {@link SsDownloader#SsDownloader(MediaItem, Parser, CacheDataSource.Factory, + * Executor, long)} instead. + */ + @Deprecated + public SsDownloader( + MediaItem mediaItem, + Parser manifestParser, + CacheDataSource.Factory cacheDataSourceFactory, + Executor executor) { + this( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_MS); } /** @@ -106,13 +125,22 @@ public SsDownloader( * @param executor An {@link Executor} used to make requests for the media being downloaded. * Providing an {@link Executor} that uses multiple threads will speed up the download by * allowing parts of it to be executed in parallel. + * @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two + * segments, up to which the segments (of the same URI) should be merged into a single + * download segment, in milliseconds. */ public SsDownloader( MediaItem mediaItem, Parser manifestParser, CacheDataSource.Factory cacheDataSourceFactory, - Executor executor) { - super(mediaItem, manifestParser, cacheDataSourceFactory, executor); + Executor executor, + long maxMergedSegmentStartTimeDiffMs) { + super( + mediaItem, + manifestParser, + cacheDataSourceFactory, + executor, + maxMergedSegmentStartTimeDiffMs); } @Override From 70db68713479147db22d45cfbe6472577c9d1a2b Mon Sep 17 00:00:00 2001 From: christosts Date: Tue, 14 Feb 2023 14:24:36 +0000 Subject: [PATCH 04/33] Merge pull request #10959 from balachandarlinks:handle-sql-exception-in-cached-content-index PiperOrigin-RevId: 508323432 (cherry picked from commit 1249dcdc47a4c3b4dbd642c3991945b23de8112b) --- .../datasource/cache/CachedContentIndex.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/datasource/src/main/java/androidx/media3/datasource/cache/CachedContentIndex.java b/libraries/datasource/src/main/java/androidx/media3/datasource/cache/CachedContentIndex.java index 0d403fb1738..36c2d454296 100644 --- a/libraries/datasource/src/main/java/androidx/media3/datasource/cache/CachedContentIndex.java +++ b/libraries/datasource/src/main/java/androidx/media3/datasource/cache/CachedContentIndex.java @@ -794,11 +794,15 @@ public void initialize(long uid) { @Override public boolean exists() throws DatabaseIOException { - return VersionTable.getVersion( - databaseProvider.getReadableDatabase(), - VersionTable.FEATURE_CACHE_CONTENT_METADATA, - checkNotNull(hexUid)) - != VersionTable.VERSION_UNSET; + try { + return VersionTable.getVersion( + databaseProvider.getReadableDatabase(), + VersionTable.FEATURE_CACHE_CONTENT_METADATA, + checkNotNull(hexUid)) + != VersionTable.VERSION_UNSET; + } catch (SQLException e) { + throw new DatabaseIOException(e); + } } @Override From 0ebb8ff367ea31a8d4bae86c542f7cf39afed737 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 10 Feb 2023 10:08:46 +0000 Subject: [PATCH 05/33] Document spatialization behavior constants. PiperOrigin-RevId: 508602059 (cherry picked from commit 6066ce43f66317f708e6e0076580e1bc1182186d) --- libraries/common/src/main/java/androidx/media3/common/C.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index ac44ebb6036..112b2ea8413 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -331,7 +331,10 @@ private C() {} */ @UnstableApi public static final int ENCODING_OPUS = AudioFormat.ENCODING_OPUS; - /** Represents the behavior affecting whether spatialization will be used. */ + /** + * Represents the behavior affecting whether spatialization will be used. One of {@link + * #SPATIALIZATION_BEHAVIOR_AUTO} or {@link #SPATIALIZATION_BEHAVIOR_NEVER}. + */ @Documented @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) From 3cc93b1f1dcb8248365c1826e03aed046f5c321e Mon Sep 17 00:00:00 2001 From: ibaker Date: Fri, 10 Feb 2023 11:44:14 +0000 Subject: [PATCH 06/33] Add null check to `ExoPlayerImpl.isTunnelingEnabled` `TrackSelectorResult.rendererConfigurations` can contain null elements: > A null entry indicates the corresponding renderer should be disabled. This wasn't caught by the nullness checker because `ExoPlayerImpl` is currently excluded from analysis. #minor-release Issue: google/ExoPlayer#10977 PiperOrigin-RevId: 508619169 (cherry picked from commit a6dfcf779942cb76c495fb5f7bc5444da6147b9d) --- RELEASENOTES.md | 2 ++ .../main/java/androidx/media3/exoplayer/ExoPlayerImpl.java | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c23254bf53d..2bacce6b3c7 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -32,6 +32,8 @@ This release corresponds to the parsing trak atoms. * Correctly skip samples when seeking directly to a sync frame in fMP4 ([#10941](https://github.com/google/ExoPlayer/issues/10941)). + * Fix `NullPointerException` when calling `ExoPlayer.isTunnelingEnabled` + ([#10977](https://github.com/google/ExoPlayer/issues/10977)). * Audio: * Use the compressed audio format bitrate to calculate the min buffer size for `AudioTrack` in direct playbacks (passthrough). diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java index 525b2df9c43..10c64a7e982 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java @@ -1724,8 +1724,9 @@ public void setDeviceMuted(boolean muted) { @Override public boolean isTunnelingEnabled() { verifyApplicationThread(); - for (RendererConfiguration config : playbackInfo.trackSelectorResult.rendererConfigurations) { - if (config.tunneling) { + for (@Nullable + RendererConfiguration config : playbackInfo.trackSelectorResult.rendererConfigurations) { + if (config != null && config.tunneling) { return true; } } From 3696076f0f08f8bcc9c32c0fa322ed48c42e8179 Mon Sep 17 00:00:00 2001 From: christosts Date: Fri, 10 Feb 2023 13:44:34 +0000 Subject: [PATCH 07/33] AsynchronousMediaCodecAdapter: surface queueing errors sooner The AsynchronousMediaCodecAdapter's queuing thread stores any exceptions raised by MediaCodec and re-throws them on the next call to queueInputBuffer()/queueSecureInputBuffer(). However, if MediaCodec raises and error while queueing, it goes into a failed state and does not announce available input buffers. If there is no input available input buffer, the MediaCodecRenderer will never call queueInputBuffer()/queueSecureInputBuffer(), hence playback is stalled. This change surfaces the queueing error through the adapter's dequeueing methods. PiperOrigin-RevId: 508637346 (cherry picked from commit 706431059cadf1b503ea8f95fd482d41f48e1a1c) --- .../AsynchronousMediaCodecAdapter.java | 2 ++ .../AsynchronousMediaCodecBufferEnqueuer.java | 3 +- .../AsynchronousMediaCodecCallback.java | 3 +- .../AsynchronousMediaCodecAdapterTest.java | 28 +++++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapter.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapter.java index 91aa86ca068..9377aaace6d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapter.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapter.java @@ -191,11 +191,13 @@ public void releaseOutputBuffer(int index, long renderTimeStampNs) { @Override public int dequeueInputBufferIndex() { + bufferEnqueuer.maybeThrowException(); return asynchronousMediaCodecCallback.dequeueInputBufferIndex(); } @Override public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) { + bufferEnqueuer.maybeThrowException(); return asynchronousMediaCodecCallback.dequeueOutputBufferIndex(bufferInfo); } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java index 10f0a24e155..bba85feff94 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java @@ -162,7 +162,8 @@ public void waitUntilQueueingComplete() throws InterruptedException { blockUntilHandlerThreadIsIdle(); } - private void maybeThrowException() { + /** Throw any exception that occurred on the enqueuer's background queueing thread. */ + public void maybeThrowException() { @Nullable RuntimeException exception = pendingRuntimeException.getAndSet(null); if (exception != null) { throw exception; diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecCallback.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecCallback.java index 67c6649d27c..e950d3ac73a 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecCallback.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecCallback.java @@ -263,11 +263,12 @@ private void flushInternal() { // else, pendingOutputFormat may already be non-null following a previous flush, and remains // set in this case. + // mediaCodecException is not reset to null. If the codec has raised an error, then it remains + // in FAILED_STATE even after flushing. availableInputBuffers.clear(); availableOutputBuffers.clear(); bufferInfos.clear(); formats.clear(); - mediaCodecException = null; } @GuardedBy("lock") diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapterTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapterTest.java index 98707a32261..ee7026a6694 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapterTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/AsynchronousMediaCodecAdapterTest.java @@ -80,6 +80,20 @@ public void dequeueInputBufferIndex_withMediaCodecError_throwsException() throws assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex()); } + @Test + public void dequeueInputBufferIndex_withPendingQueueingError_throwsException() { + // Force MediaCodec to throw an error by attempting to queue input buffer -1. + adapter.queueInputBuffer( + /* index= */ -1, + /* offset= */ 0, + /* size= */ 0, + /* presentationTimeUs= */ 0, + /* flags= */ 0); + shadowOf(queueingThread.getLooper()).idle(); + + assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex()); + } + @Test public void dequeueInputBufferIndex_afterShutdown_returnsTryAgainLater() { adapter.release(); @@ -123,6 +137,20 @@ public void dequeueOutputBufferIndex_withMediaCodecError_throwsException() throw assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo)); } + @Test + public void dequeueOutputBufferIndex_withPendingQueueingError_throwsException() { + // Force MediaCodec to throw an error by attempting to queue input buffer -1. + adapter.queueInputBuffer( + /* index= */ -1, + /* offset= */ 0, + /* size= */ 0, + /* presentationTimeUs= */ 0, + /* flags= */ 0); + shadowOf(queueingThread.getLooper()).idle(); + + assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo)); + } + @Test public void dequeueOutputBufferIndex_afterShutdown_returnsTryAgainLater() { int index = adapter.dequeueInputBufferIndex(); From f2753e2e27c4699db07559b5b68a4f736f864fbd Mon Sep 17 00:00:00 2001 From: bachinger Date: Mon, 13 Feb 2023 12:26:04 +0000 Subject: [PATCH 08/33] Add ad event listeners in the Looper event of the ad manager callback #minor-release PiperOrigin-RevId: 509189206 (cherry picked from commit 51929625cfeff17af413c1a06c87e10e72f218d1) --- RELEASENOTES.md | 2 + .../ImaServerSideAdInsertionMediaSource.java | 40 ++++++------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2bacce6b3c7..dfed41bfdbc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -103,6 +103,8 @@ This release corresponds to the * Add a method `focusSkipButton()` to the `ImaServerSideAdInsertionMediaSource.AdsLoader` to programmatically request to focus the skip button. + * Fix a bug which prevented playback from starting for a DAI stream + without any ads. * Bump IMA SDK version to 3.29.0. * Demo app: * Request notification permission for download notifications at runtime diff --git a/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java b/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java index e029b74578f..d9ec2dbe37d 100644 --- a/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java +++ b/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java @@ -554,11 +554,10 @@ public void prepareSourceInternal(@Nullable TransferListener mediaTransferListen StreamManagerLoadable streamManagerLoadable = new StreamManagerLoadable( sdkAdsLoader, - adsLoader.configuration, + /* imaServerSideAdInsertionMediaSource= */ this, streamRequest, streamPlayer, - applicationAdErrorListener, - loadVideoTimeoutMs); + applicationAdErrorListener); loader.startLoading( streamManagerLoadable, new StreamManagerLoadableCallback(), @@ -633,7 +632,6 @@ private void setStreamManager(@Nullable StreamManager streamManager) { } this.streamManager.removeAdEventListener(componentListener); this.streamManager.destroy(); - this.streamManager = null; } this.streamManager = streamManager; if (streamManager != null) { @@ -644,6 +642,12 @@ private void setStreamManager(@Nullable StreamManager streamManager) { if (applicationAdErrorListener != null) { streamManager.addAdErrorListener(applicationAdErrorListener); } + AdsRenderingSettings adsRenderingSettings = + ImaSdkFactory.getInstance().createAdsRenderingSettings(); + adsRenderingSettings.setLoadVideoTimeout(loadVideoTimeoutMs); + adsRenderingSettings.setFocusSkipButtonWhenAvailable( + adsLoader.configuration.focusSkipButtonWhenAvailable); + streamManager.init(adsRenderingSettings); } } @@ -952,7 +956,6 @@ private final class StreamManagerLoadableCallback @Override public void onLoadCompleted( StreamManagerLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) { - mainHandler.post(() -> setStreamManager(checkNotNull(loadable.getStreamManager()))); setContentUri(checkNotNull(loadable.getContentUri())); } @@ -983,14 +986,12 @@ private static class StreamManagerLoadable implements Loadable, AdsLoadedListener, AdErrorListener { private final com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader; - private final ServerSideAdInsertionConfiguration serverSideAdInsertionConfiguration; + private final ImaServerSideAdInsertionMediaSource imaServerSideAdInsertionMediaSource; private final StreamRequest request; private final StreamPlayer streamPlayer; @Nullable private final AdErrorListener adErrorListener; - private final int loadVideoTimeoutMs; private final ConditionVariable conditionVariable; - @Nullable private volatile StreamManager streamManager; @Nullable private volatile Uri contentUri; private volatile boolean cancelled; private volatile boolean error; @@ -1000,17 +1001,15 @@ private static class StreamManagerLoadable /** Creates an instance. */ private StreamManagerLoadable( com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader, - ServerSideAdInsertionConfiguration serverSideAdInsertionConfiguration, + ImaServerSideAdInsertionMediaSource imaServerSideAdInsertionMediaSource, StreamRequest request, StreamPlayer streamPlayer, - @Nullable AdErrorListener adErrorListener, - int loadVideoTimeoutMs) { + @Nullable AdErrorListener adErrorListener) { this.adsLoader = adsLoader; - this.serverSideAdInsertionConfiguration = serverSideAdInsertionConfiguration; + this.imaServerSideAdInsertionMediaSource = imaServerSideAdInsertionMediaSource; this.request = request; this.streamPlayer = streamPlayer; this.adErrorListener = adErrorListener; - this.loadVideoTimeoutMs = loadVideoTimeoutMs; conditionVariable = new ConditionVariable(); errorCode = -1; } @@ -1021,12 +1020,6 @@ public Uri getContentUri() { return contentUri; } - /** Returns the stream manager or null if not yet loaded. */ - @Nullable - public StreamManager getStreamManager() { - return streamManager; - } - // Implement Loadable. @Override @@ -1080,14 +1073,7 @@ public void onAdsManagerLoaded(AdsManagerLoadedEvent event) { conditionVariable.open(); return; } - AdsRenderingSettings adsRenderingSettings = - ImaSdkFactory.getInstance().createAdsRenderingSettings(); - adsRenderingSettings.setLoadVideoTimeout(loadVideoTimeoutMs); - adsRenderingSettings.setFocusSkipButtonWhenAvailable( - serverSideAdInsertionConfiguration.focusSkipButtonWhenAvailable); - // After initialization completed the streamUri will be reported to the streamPlayer. - streamManager.init(adsRenderingSettings); - this.streamManager = streamManager; + imaServerSideAdInsertionMediaSource.setStreamManager(streamManager); } // AdErrorEvent.AdErrorListener implementation. From cfe861ed89870f383ab0ac28268979b9f9aeaaa6 Mon Sep 17 00:00:00 2001 From: michaelkatz Date: Mon, 13 Feb 2023 14:18:53 +0000 Subject: [PATCH 09/33] Catch IllegalArgumentExceptions in RTSP Response parsing In parsing Describe RTSP response messages, IllegalArgumentExceptions are thrown for invalid parameters and values. These exceptions were not caught and crashed the Playback thread. Now these exceptions will be caught and their errors forwarded to the proper error handling listeners. Issue: google/ExoPlayer#10971 PiperOrigin-RevId: 509207881 (cherry picked from commit a8c87453db02658a21293b44b017a70d5ae1125d) --- RELEASENOTES.md | 6 ++ .../media3/exoplayer/rtsp/RtspClient.java | 2 +- .../media3/exoplayer/rtsp/RtspMediaTrack.java | 25 +++++--- .../media3/exoplayer/rtsp/RtspClientTest.java | 64 +++++++++++++++++++ 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index dfed41bfdbc..2b984f4350f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -84,6 +84,12 @@ This release corresponds to the ([#233](https://github.com/androidx/media/issues/233)). * Make `QueueTimeline` more robust in case of a shady legacy session state ([#241](https://github.com/androidx/media/issues/241)). + * Fix a bug where notification play/pause button doesn't update with + player state ([#192](https://github.com/androidx/media/issues/192)). +* RTSP: + * Catch the IllegalArgumentException thrown in parsing of invalid RTSP + Describe response messages + ([#10971](https://github.com/google/ExoPlayer/issues/10971)). * Metadata: * Parse multiple null-separated values from ID3 frames, as permitted by ID3 v2.4. diff --git a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspClient.java b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspClient.java index 84bcc4cd8dc..c8ac907a8df 100644 --- a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspClient.java +++ b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspClient.java @@ -652,7 +652,7 @@ private void handleRtspResponse(List message) { default: throw new IllegalStateException(); } - } catch (ParserException e) { + } catch (ParserException | IllegalArgumentException e) { dispatchRtspError(new RtspPlaybackException(e)); } } diff --git a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java index b3d79404a2e..b96d3d54b92 100644 --- a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java +++ b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java @@ -159,7 +159,8 @@ * @param sessionUri The {@link Uri} of the RTSP playback session. */ public RtspMediaTrack(MediaDescription mediaDescription, Uri sessionUri) { - checkArgument(mediaDescription.attributes.containsKey(ATTR_CONTROL)); + checkArgument( + mediaDescription.attributes.containsKey(ATTR_CONTROL), "missing attribute control"); payloadFormat = generatePayloadFormat(mediaDescription); uri = extractTrackUri(sessionUri, castNonNull(mediaDescription.attributes.get(ATTR_CONTROL))); } @@ -210,7 +211,7 @@ public int hashCode() { switch (mimeType) { case MimeTypes.AUDIO_AAC: checkArgument(channelCount != C.INDEX_UNSET); - checkArgument(!fmtpParameters.isEmpty()); + checkArgument(!fmtpParameters.isEmpty(), "missing attribute fmtp"); if (mediaEncoding.equals(RtpPayloadFormat.RTP_MEDIA_MPEG4_LATM_AUDIO)) { // cpresent is defined in RFC3016 Section 5.3. cpresent=0 means the config fmtp parameter // must exist. @@ -259,11 +260,11 @@ public int hashCode() { formatBuilder.setWidth(DEFAULT_H263_WIDTH).setHeight(DEFAULT_H263_HEIGHT); break; case MimeTypes.VIDEO_H264: - checkArgument(!fmtpParameters.isEmpty()); + checkArgument(!fmtpParameters.isEmpty(), "missing attribute fmtp"); processH264FmtpAttribute(formatBuilder, fmtpParameters); break; case MimeTypes.VIDEO_H265: - checkArgument(!fmtpParameters.isEmpty()); + checkArgument(!fmtpParameters.isEmpty(), "missing attribute fmtp"); processH265FmtpAttribute(formatBuilder, fmtpParameters); break; case MimeTypes.VIDEO_VP8: @@ -312,7 +313,8 @@ private static void processAacFmtpAttribute( ImmutableMap fmtpAttributes, int channelCount, int sampleRate) { - checkArgument(fmtpAttributes.containsKey(PARAMETER_PROFILE_LEVEL_ID)); + checkArgument( + fmtpAttributes.containsKey(PARAMETER_PROFILE_LEVEL_ID), "missing profile-level-id param"); String profileLevel = checkNotNull(fmtpAttributes.get(PARAMETER_PROFILE_LEVEL_ID)); formatBuilder.setCodecs(AAC_CODECS_PREFIX + profileLevel); formatBuilder.setInitializationData( @@ -380,10 +382,10 @@ private static byte[] getInitializationDataFromParameterSet(String parameterSet) private static void processH264FmtpAttribute( Format.Builder formatBuilder, ImmutableMap fmtpAttributes) { - checkArgument(fmtpAttributes.containsKey(PARAMETER_SPROP_PARAMS)); + checkArgument(fmtpAttributes.containsKey(PARAMETER_SPROP_PARAMS), "missing sprop parameter"); String spropParameterSets = checkNotNull(fmtpAttributes.get(PARAMETER_SPROP_PARAMS)); String[] parameterSets = Util.split(spropParameterSets, ","); - checkArgument(parameterSets.length == 2); + checkArgument(parameterSets.length == 2, "empty sprop value"); ImmutableList initializationData = ImmutableList.of( getInitializationDataFromParameterSet(parameterSets[0]), @@ -418,11 +420,14 @@ private static void processH265FmtpAttribute( maxDonDiff == 0, "non-zero sprop-max-don-diff " + maxDonDiff + " is not supported"); } - checkArgument(fmtpAttributes.containsKey(PARAMETER_H265_SPROP_VPS)); + checkArgument( + fmtpAttributes.containsKey(PARAMETER_H265_SPROP_VPS), "missing sprop-vps parameter"); String spropVPS = checkNotNull(fmtpAttributes.get(PARAMETER_H265_SPROP_VPS)); - checkArgument(fmtpAttributes.containsKey(PARAMETER_H265_SPROP_SPS)); + checkArgument( + fmtpAttributes.containsKey(PARAMETER_H265_SPROP_SPS), "missing sprop-sps parameter"); String spropSPS = checkNotNull(fmtpAttributes.get(PARAMETER_H265_SPROP_SPS)); - checkArgument(fmtpAttributes.containsKey(PARAMETER_H265_SPROP_PPS)); + checkArgument( + fmtpAttributes.containsKey(PARAMETER_H265_SPROP_PPS), "missing sprop-pps parameter"); String spropPPS = checkNotNull(fmtpAttributes.get(PARAMETER_H265_SPROP_PPS)); ImmutableList initializationData = ImmutableList.of( diff --git a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java index f7b7ab41b81..104f6ae9c34 100644 --- a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java +++ b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java @@ -389,4 +389,68 @@ public void onSessionTimelineRequestFailed( RobolectricUtil.runMainLooperUntil(timelineRequestFailed::get); assertThat(rtspClient.getState()).isEqualTo(RtspClient.RTSP_STATE_UNINITIALIZED); } + + @Test + public void connectServerAndClient_sdpInDescribeResponseHasInvalidFmtpAttr_doesNotUpdateTimeline() + throws Exception { + class ResponseProvider implements RtspServer.ResponseProvider { + @Override + public RtspResponse getOptionsResponse() { + return new RtspResponse( + /* status= */ 200, + new RtspHeaders.Builder().add(RtspHeaders.PUBLIC, "OPTIONS, DESCRIBE").build()); + } + + @Override + public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) { + String testMediaSdpInfo = + "v=0\r\n" + + "o=- 1600785369059721 1 IN IP4 192.168.2.176\r\n" + + "s=video, streamed by ExoPlayer\r\n" + + "i=test.mkv\r\n" + + "t=0 0\r\n" + + "a=tool:ExoPlayer\r\n" + + "a=type:broadcast\r\n" + + "a=control:*\r\n" + + "a=range:npt=0-30.102\r\n" + + "m=video 0 RTP/AVP 96\r\n" + + "c=IN IP4 0.0.0.0\r\n" + + "b=AS:500\r\n" + + "a=rtpmap:96 H264/90000\r\n" + + "a=fmtp:96" + + " packetization-mode=1;profile-level-id=64001F;sprop-parameter-sets=\r\n" + + "a=control:track1\r\n"; + return RtspTestUtils.newDescribeResponseWithSdpMessage( + /* sessionDescription= */ testMediaSdpInfo, + // This session description has no tracks. + /* rtpPacketStreamDumps= */ ImmutableList.of(), + requestedUri); + } + } + rtspServer = new RtspServer(new ResponseProvider()); + + AtomicBoolean timelineRequestFailed = new AtomicBoolean(); + rtspClient = + new RtspClient( + new SessionInfoListener() { + @Override + public void onSessionTimelineUpdated( + RtspSessionTiming timing, ImmutableList tracks) {} + + @Override + public void onSessionTimelineRequestFailed( + String message, @Nullable Throwable cause) { + timelineRequestFailed.set(true); + } + }, + EMPTY_PLAYBACK_LISTENER, + /* userAgent= */ "ExoPlayer:RtspClientTest", + RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), + SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); + rtspClient.start(); + + RobolectricUtil.runMainLooperUntil(timelineRequestFailed::get); + assertThat(rtspClient.getState()).isEqualTo(RtspClient.RTSP_STATE_UNINITIALIZED); + } } From 6a273a5f907be8dd64d4428f622640c7864fffdf Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 14 Feb 2023 10:54:01 +0000 Subject: [PATCH 10/33] Add exception cause to thrown exception PiperOrigin-RevId: 509473556 (cherry picked from commit 56803bf1ad3e4df2ebd8d7b38f5a9f4740dc702f) --- .../media3/exoplayer/offline/DefaultDownloaderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DefaultDownloaderFactory.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DefaultDownloaderFactory.java index 437490eea38..1fee9d80cbd 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DefaultDownloaderFactory.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DefaultDownloaderFactory.java @@ -105,7 +105,7 @@ private Downloader createDownloader(DownloadRequest request, @C.ContentType int return constructor.newInstance(mediaItem, cacheDataSourceFactory, executor); } catch (Exception e) { throw new IllegalStateException( - "Failed to instantiate downloader for content type " + contentType); + "Failed to instantiate downloader for content type " + contentType, e); } } From 3b00561b49ae212faf3c8db34d9cc98bc7cad866 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 16 Feb 2023 23:36:31 +0000 Subject: [PATCH 11/33] Fix error in documentation string The current javadoc refers to the SessionCallback#onConnected, which doesn't exist. PiperOrigin-RevId: 510261965 (cherry picked from commit fc642eb45f6c997a2a501bcc3ea19043cd9911eb) --- .../src/main/java/androidx/media3/session/MediaSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java index f3045d3cda1..1a2c7b2e813 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java @@ -371,7 +371,7 @@ public static final class ControllerInfo { * @param remoteUserInfo The remote user info. * @param trusted {@code true} if trusted, {@code false} otherwise. * @param cb ControllerCb. Can be {@code null} only when a MediaBrowserCompat connects to - * MediaSessionService and ControllerInfo is needed for SessionCallback#onConnected(). + * MediaSessionService and ControllerInfo is needed for {@code SessionCallback#onConnect()}. * @param connectionHints A session-specific argument sent from the controller for the * connection. The contents of this bundle may affect the connection result. */ From 629a75ed1cf7fa4fb5b140d0dd6010438153b0a9 Mon Sep 17 00:00:00 2001 From: bachinger Date: Fri, 17 Feb 2023 17:55:44 +0000 Subject: [PATCH 12/33] Map `PLAYER_STATE_LOADING` to `STATE_BUFFERING` #minor-release Issue: androidx/media#245 PiperOrigin-RevId: 510456793 (cherry picked from commit ba49b6b81b9a6a01aa16381cca70886bc205c5c5) --- RELEASENOTES.md | 3 +++ .../cast/src/main/java/androidx/media3/cast/CastPlayer.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2b984f4350f..b2e3e689273 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -101,6 +101,9 @@ This release corresponds to the * Cast extension: * Bump Cast SDK version to 21.2.0. * IMA extension: + * Map `PLAYER_STATE_LOADING` to `STATE_BUFFERING` + ([#245](\(https://github.com/androidx/media/issues/245\)). +* IMA extension * Remove player listener of the `ImaServerSideAdInsertionMediaSource` on the application thread to avoid threading issues. * Add a property `focusSkipButtonWhenAvailable` to the diff --git a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java index 8d2a0cbde1b..dbf61395bd6 100644 --- a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java +++ b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java @@ -1237,6 +1237,7 @@ private static int fetchPlaybackState(RemoteMediaClient remoteMediaClient) { int receiverAppStatus = remoteMediaClient.getPlayerState(); switch (receiverAppStatus) { case MediaStatus.PLAYER_STATE_BUFFERING: + case MediaStatus.PLAYER_STATE_LOADING: return STATE_BUFFERING; case MediaStatus.PLAYER_STATE_PLAYING: case MediaStatus.PLAYER_STATE_PAUSED: @@ -1299,6 +1300,7 @@ private static boolean isTrackActive(long id, long[] activeTrackIds) { return false; } + @SuppressWarnings("VisibleForTests") private static int getCastRepeatMode(@RepeatMode int repeatMode) { switch (repeatMode) { case REPEAT_MODE_ONE: From 0e5dad5269ae81d6177c69140eaac642e608e0c6 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 20 Feb 2023 11:49:34 +0000 Subject: [PATCH 13/33] Reduce number of calls to AudioTrack.getPlaybackHeadPosition This call may cause performance overhead in some situations, for example if the AudioTrack needs to query an offload DSP for the current position. We don't need to check this multiple times per doSomeWork iteration as the value is unlikely to change in any meaningful way. PiperOrigin-RevId: 510957116 (cherry picked from commit 9eccf09165f39d89d502065f897d120b97f47f66) --- .../audio/AudioTrackPositionTracker.java | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java index 417d0fb0273..98b6202060e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java @@ -15,6 +15,7 @@ */ package androidx.media3.exoplayer.audio; +import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Util.castNonNull; import static java.lang.Math.max; import static java.lang.Math.min; @@ -26,7 +27,6 @@ import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.media3.common.C; -import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Util; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -146,6 +146,9 @@ void onSystemTimeUsMismatch( /** The duration of time used to smooth over an adjustment between position sampling modes. */ private static final long MODE_SWITCH_SMOOTHING_DURATION_US = C.MICROS_PER_SECOND; + /** Minimum update interval for getting the raw playback head position, in milliseconds. */ + private static final long RAW_PLAYBACK_HEAD_POSITION_UPDATE_INTERVAL_MS = 5; + private static final long FORCE_RESET_WORKAROUND_TIMEOUT_MS = 200; private static final int MAX_PLAYHEAD_OFFSET_COUNT = 10; @@ -174,7 +177,8 @@ void onSystemTimeUsMismatch( private boolean isOutputPcm; private long lastLatencySampleTimeUs; - private long lastRawPlaybackHeadPosition; + private long lastRawPlaybackHeadPositionSampleTimeMs; + private long rawPlaybackHeadPosition; private long rawPlaybackHeadWrapCount; private long passthroughWorkaroundPauseOffset; private int nextPlayheadOffsetIndex; @@ -199,7 +203,7 @@ void onSystemTimeUsMismatch( * @param listener A listener for position tracking events. */ public AudioTrackPositionTracker(Listener listener) { - this.listener = Assertions.checkNotNull(listener); + this.listener = checkNotNull(listener); if (Util.SDK_INT >= 18) { try { getLatencyMethod = AudioTrack.class.getMethod("getLatency", (Class[]) null); @@ -235,7 +239,7 @@ public void setAudioTrack( needsPassthroughWorkarounds = isPassthrough && needsPassthroughWorkarounds(outputEncoding); isOutputPcm = Util.isEncodingLinearPcm(outputEncoding); bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET; - lastRawPlaybackHeadPosition = 0; + rawPlaybackHeadPosition = 0; rawPlaybackHeadWrapCount = 0; passthroughWorkaroundPauseOffset = 0; hasData = false; @@ -257,7 +261,7 @@ public void setAudioTrackPlaybackSpeed(float audioTrackPlaybackSpeed) { } public long getCurrentPositionUs(boolean sourceEnded) { - if (Assertions.checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) { + if (checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) { maybeSampleSyncParams(); } @@ -265,7 +269,7 @@ public long getCurrentPositionUs(boolean sourceEnded) { // Otherwise, derive a smoothed position by sampling the track's frame position. long systemTimeUs = System.nanoTime() / 1000; long positionUs; - AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller); + AudioTimestampPoller audioTimestampPoller = checkNotNull(this.audioTimestampPoller); boolean useGetTimestampMode = audioTimestampPoller.hasAdvancingTimestamp(); if (useGetTimestampMode) { // Calculate the speed-adjusted position using the timestamp (which may be in the future). @@ -332,12 +336,12 @@ public long getCurrentPositionUs(boolean sourceEnded) { /** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */ public void start() { - Assertions.checkNotNull(audioTimestampPoller).reset(); + checkNotNull(audioTimestampPoller).reset(); } /** Returns whether the audio track is in the playing state. */ public boolean isPlaying() { - return Assertions.checkNotNull(audioTrack).getPlayState() == PLAYSTATE_PLAYING; + return checkNotNull(audioTrack).getPlayState() == PLAYSTATE_PLAYING; } /** @@ -348,7 +352,7 @@ public boolean isPlaying() { * @return Whether the caller can write data to the track. */ public boolean mayHandleBuffer(long writtenFrames) { - @PlayState int playState = Assertions.checkNotNull(audioTrack).getPlayState(); + @PlayState int playState = checkNotNull(audioTrack).getPlayState(); if (needsPassthroughWorkarounds) { // An AC-3 audio track continues to play data written while it is paused. Stop writing so its // buffer empties. See [Internal: b/18899620]. @@ -429,7 +433,7 @@ public boolean pause() { if (stopTimestampUs == C.TIME_UNSET) { // The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't // supply an advancing position. - Assertions.checkNotNull(audioTimestampPoller).reset(); + checkNotNull(audioTimestampPoller).reset(); return true; } // We've handled the end of the stream already, so there's no need to pause the track. @@ -480,7 +484,7 @@ private void maybeSampleSyncParams() { } private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) { - AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller); + AudioTimestampPoller audioTimestampPoller = checkNotNull(this.audioTimestampPoller); if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) { return; } @@ -516,8 +520,7 @@ private void maybeUpdateLatency(long systemTimeUs) { // Compute the audio track latency, excluding the latency due to the buffer (leaving // latency due to the mixer and audio hardware driver). latencyUs = - castNonNull((Integer) getLatencyMethod.invoke(Assertions.checkNotNull(audioTrack))) - * 1000L + castNonNull((Integer) getLatencyMethod.invoke(checkNotNull(audioTrack))) * 1000L - bufferSizeUs; // Check that the latency is non-negative. latencyUs = max(latencyUs, 0); @@ -555,7 +558,7 @@ private void resetSyncParams() { */ private boolean forceHasPendingData() { return needsPassthroughWorkarounds - && Assertions.checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED + && checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED && getPlaybackHeadPosition() == 0; } @@ -581,36 +584,44 @@ private long getPlaybackHeadPositionUs() { * @return The playback head position, in frames. */ private long getPlaybackHeadPosition() { - AudioTrack audioTrack = Assertions.checkNotNull(this.audioTrack); + long currentTimeMs = SystemClock.elapsedRealtime(); if (stopTimestampUs != C.TIME_UNSET) { // Simulate the playback head position up to the total number of frames submitted. - long elapsedTimeSinceStopUs = (SystemClock.elapsedRealtime() * 1000) - stopTimestampUs; + long elapsedTimeSinceStopUs = (currentTimeMs * 1000) - stopTimestampUs; long mediaTimeSinceStopUs = Util.getMediaDurationForPlayoutDuration(elapsedTimeSinceStopUs, audioTrackPlaybackSpeed); long framesSinceStop = (mediaTimeSinceStopUs * outputSampleRate) / C.MICROS_PER_SECOND; return min(endPlaybackHeadPosition, stopPlaybackHeadPosition + framesSinceStop); } + if (currentTimeMs - lastRawPlaybackHeadPositionSampleTimeMs + >= RAW_PLAYBACK_HEAD_POSITION_UPDATE_INTERVAL_MS) { + updateRawPlaybackHeadPosition(currentTimeMs); + lastRawPlaybackHeadPositionSampleTimeMs = currentTimeMs; + } + return rawPlaybackHeadPosition + (rawPlaybackHeadWrapCount << 32); + } + private void updateRawPlaybackHeadPosition(long currentTimeMs) { + AudioTrack audioTrack = checkNotNull(this.audioTrack); int state = audioTrack.getPlayState(); if (state == PLAYSTATE_STOPPED) { - // The audio track hasn't been started. - return 0; + // The audio track hasn't been started. Keep initial zero timestamp. + return; } - long rawPlaybackHeadPosition = 0xFFFFFFFFL & audioTrack.getPlaybackHeadPosition(); if (needsPassthroughWorkarounds) { // Work around an issue with passthrough/direct AudioTracks on platform API versions 21/22 // where the playback head position jumps back to zero on paused passthrough/direct audio // tracks. See [Internal: b/19187573]. if (state == PLAYSTATE_PAUSED && rawPlaybackHeadPosition == 0) { - passthroughWorkaroundPauseOffset = lastRawPlaybackHeadPosition; + passthroughWorkaroundPauseOffset = this.rawPlaybackHeadPosition; } rawPlaybackHeadPosition += passthroughWorkaroundPauseOffset; } if (Util.SDK_INT <= 29) { if (rawPlaybackHeadPosition == 0 - && lastRawPlaybackHeadPosition > 0 + && this.rawPlaybackHeadPosition > 0 && state == PLAYSTATE_PLAYING) { // If connecting a Bluetooth audio device fails, the AudioTrack may be left in a state // where its Java API is in the playing state, but the native track is stopped. When this @@ -618,19 +629,18 @@ private long getPlaybackHeadPosition() { // playback head position and force the track to be reset after // {@link #FORCE_RESET_WORKAROUND_TIMEOUT_MS} has elapsed. if (forceResetWorkaroundTimeMs == C.TIME_UNSET) { - forceResetWorkaroundTimeMs = SystemClock.elapsedRealtime(); + forceResetWorkaroundTimeMs = currentTimeMs; } - return lastRawPlaybackHeadPosition; + return; } else { forceResetWorkaroundTimeMs = C.TIME_UNSET; } } - if (lastRawPlaybackHeadPosition > rawPlaybackHeadPosition) { + if (this.rawPlaybackHeadPosition > rawPlaybackHeadPosition) { // The value must have wrapped around. rawPlaybackHeadWrapCount++; } - lastRawPlaybackHeadPosition = rawPlaybackHeadPosition; - return rawPlaybackHeadPosition + (rawPlaybackHeadWrapCount << 32); + this.rawPlaybackHeadPosition = rawPlaybackHeadPosition; } } From 58a977e0c048012936633dbdfb581269edb68c65 Mon Sep 17 00:00:00 2001 From: christosts Date: Mon, 20 Feb 2023 12:38:42 +0000 Subject: [PATCH 14/33] Skip rendering multiple frames on the same vsync When rendering frames at a rate higher than the screen refresh rate, e.g. playing at 8x, the player is releasing multiple frames at the same release time (nanos) which are then dropped by the platform. The output buffers are available later and as a result MediaCodec cannot keep up decoding fast enough. This change skips releasing multiple video frames on the same vsync period and proactivelly drops the frame. The frame is counted as skipped rather than dropped to differentiate with frames dropped due to slow decoding. PiperOrigin-RevId: 510964976 (cherry picked from commit ab7e84fb34b7ef4b13e492e1f8918345c712ec30) --- .../exoplayer/video/MediaCodecVideoRenderer.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java index 1bd45fc24aa..6b9d4b567d8 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java @@ -153,6 +153,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private long lastRenderRealtimeUs; private long totalVideoFrameProcessingOffsetUs; private int videoFrameProcessingOffsetCount; + private long lastFrameReleaseTimeNs; private int currentWidth; private int currentHeight; @@ -1128,9 +1129,18 @@ && maybeDropBuffersToKeyframe(positionUs, treatDroppedBuffersAsSkipped)) { if (Util.SDK_INT >= 21) { // Let the underlying framework time the release. if (earlyUs < 50000) { - notifyFrameMetadataListener(presentationTimeUs, adjustedReleaseTimeNs, format); - renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs); + if (adjustedReleaseTimeNs == lastFrameReleaseTimeNs) { + // This frame should be displayed on the same vsync with the previous released frame. We + // are likely rendering frames at a rate higher than the screen refresh rate. Skip + // this buffer so that it's returned to MediaCodec sooner otherwise MediaCodec may not + // be able to keep decoding with this rate [b/263454203]. + skipOutputBuffer(codec, bufferIndex, presentationTimeUs); + } else { + notifyFrameMetadataListener(presentationTimeUs, adjustedReleaseTimeNs, format); + renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs); + } updateVideoFrameProcessingOffsetCounters(earlyUs); + lastFrameReleaseTimeNs = adjustedReleaseTimeNs; return true; } } else { From 5ab4223f2a1a0cde45300a97eb45037fe5beba52 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 23 Feb 2023 16:02:14 +0000 Subject: [PATCH 15/33] Use ArrayDeque for pending output stream changes. The current logic uses manual array operations to keep track of pending changes. Modernize this code by using an ArrayDeque and a data class. This also allows to extend the output stream information in the future. This also fixes a bug where a position reset accidentally assigns a pending stream offset instead of keeping the current one. PiperOrigin-RevId: 511787571 (cherry picked from commit f0420124954527e7f3eb529ca24f2a51dc7319f9) --- .../mediacodec/MediaCodecRenderer.java | 110 +++++++----------- 1 file changed, 42 insertions(+), 68 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index 815b4c369ea..a4a602eef4d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -208,10 +208,6 @@ private static String buildCustomDiagnosticInfo(int errorCode) { */ private static final long MAX_CODEC_HOTSWAP_TIME_MS = 1000; - // Generally there is zero or one pending output stream offset. We track more offsets to allow for - // pending output streams that have fewer frames than the codec latency. - private static final int MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT = 10; - @Documented @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) @@ -306,9 +302,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) { private final TimedValueQueue formatQueue; private final ArrayList decodeOnlyPresentationTimestamps; private final MediaCodec.BufferInfo outputBufferInfo; - private final long[] pendingOutputStreamStartPositionsUs; - private final long[] pendingOutputStreamOffsetsUs; - private final long[] pendingOutputStreamSwitchTimesUs; + private final ArrayDeque pendingOutputStreamChanges; @Nullable private Format inputFormat; @Nullable private Format outputFormat; @@ -363,9 +357,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) { private boolean pendingOutputEndOfStream; @Nullable private ExoPlaybackException pendingPlaybackException; protected DecoderCounters decoderCounters; - private long outputStreamStartPositionUs; - private long outputStreamOffsetUs; - private int pendingOutputStreamOffsetCount; + private OutputStreamInfo outputStreamInfo; /** * @param trackType The {@link C.TrackType track type} that the renderer handles. @@ -398,11 +390,8 @@ public MediaCodecRenderer( currentPlaybackSpeed = 1f; targetPlaybackSpeed = 1f; renderTimeLimitMs = C.TIME_UNSET; - pendingOutputStreamStartPositionsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; - pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; - pendingOutputStreamSwitchTimesUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; - outputStreamStartPositionUs = C.TIME_UNSET; - setOutputStreamOffsetUs(C.TIME_UNSET); + pendingOutputStreamChanges = new ArrayDeque<>(); + setOutputStreamInfo(OutputStreamInfo.UNSET); // MediaCodec outputs audio buffers in native endian: // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers // and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness. @@ -648,23 +637,14 @@ protected void onEnabled(boolean joining, boolean mayRenderStartOfStream) @Override protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) throws ExoPlaybackException { - if (this.outputStreamOffsetUs == C.TIME_UNSET) { - checkState(this.outputStreamStartPositionUs == C.TIME_UNSET); - this.outputStreamStartPositionUs = startPositionUs; - setOutputStreamOffsetUs(offsetUs); + if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) { + checkState(outputStreamInfo.startPositionUs == C.TIME_UNSET); + setOutputStreamInfo( + new OutputStreamInfo( + /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs)); } else { - if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) { - Log.w( - TAG, - "Too many stream changes, so dropping offset: " - + pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]); - } else { - pendingOutputStreamOffsetCount++; - } - pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1] = startPositionUs; - pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs; - pendingOutputStreamSwitchTimesUs[pendingOutputStreamOffsetCount - 1] = - largestQueuedPresentationTimeUs; + pendingOutputStreamChanges.add( + new OutputStreamInfo(largestQueuedPresentationTimeUs, startPositionUs, offsetUs)); } } @@ -687,12 +667,7 @@ protected void onPositionReset(long positionUs, boolean joining) throws ExoPlayb waitingForFirstSampleInFormat = true; } formatQueue.clear(); - if (pendingOutputStreamOffsetCount != 0) { - setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]); - outputStreamStartPositionUs = - pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1]; - pendingOutputStreamOffsetCount = 0; - } + pendingOutputStreamChanges.clear(); } @Override @@ -706,9 +681,8 @@ public void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpe @Override protected void onDisabled() { inputFormat = null; - outputStreamStartPositionUs = C.TIME_UNSET; - setOutputStreamOffsetUs(C.TIME_UNSET); - pendingOutputStreamOffsetCount = 0; + setOutputStreamInfo(OutputStreamInfo.UNSET); + pendingOutputStreamChanges.clear(); flushOrReleaseCodec(); } @@ -1593,29 +1567,9 @@ protected void onQueueInputBuffer(DecoderInputBuffer buffer) throws ExoPlaybackE */ @CallSuper protected void onProcessedOutputBuffer(long presentationTimeUs) { - while (pendingOutputStreamOffsetCount != 0 - && presentationTimeUs >= pendingOutputStreamSwitchTimesUs[0]) { - outputStreamStartPositionUs = pendingOutputStreamStartPositionsUs[0]; - setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[0]); - pendingOutputStreamOffsetCount--; - System.arraycopy( - pendingOutputStreamStartPositionsUs, - /* srcPos= */ 1, - pendingOutputStreamStartPositionsUs, - /* destPos= */ 0, - pendingOutputStreamOffsetCount); - System.arraycopy( - pendingOutputStreamOffsetsUs, - /* srcPos= */ 1, - pendingOutputStreamOffsetsUs, - /* destPos= */ 0, - pendingOutputStreamOffsetCount); - System.arraycopy( - pendingOutputStreamSwitchTimesUs, - /* srcPos= */ 1, - pendingOutputStreamSwitchTimesUs, - /* destPos= */ 0, - pendingOutputStreamOffsetCount); + if (!pendingOutputStreamChanges.isEmpty() + && presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) { + setOutputStreamInfo(pendingOutputStreamChanges.poll()); onProcessedStreamChange(); } } @@ -2062,13 +2016,13 @@ protected final void setPendingOutputEndOfStream() { * boolean, Format)} to get the playback position with respect to the media. */ protected final long getOutputStreamOffsetUs() { - return outputStreamOffsetUs; + return outputStreamInfo.streamOffsetUs; } - private void setOutputStreamOffsetUs(long outputStreamOffsetUs) { - this.outputStreamOffsetUs = outputStreamOffsetUs; - if (outputStreamOffsetUs != C.TIME_UNSET) { - onOutputStreamOffsetUsChanged(outputStreamOffsetUs); + private void setOutputStreamInfo(OutputStreamInfo outputStreamInfo) { + this.outputStreamInfo = outputStreamInfo; + if (outputStreamInfo.streamOffsetUs != C.TIME_UNSET) { + onOutputStreamOffsetUsChanged(outputStreamInfo.streamOffsetUs); } } @@ -2515,6 +2469,26 @@ private static boolean codecNeedsMonoChannelCountWorkaround(String name, Format && "OMX.MTK.AUDIO.DECODER.MP3".equals(name); } + private static final class OutputStreamInfo { + + public static final OutputStreamInfo UNSET = + new OutputStreamInfo( + /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, + /* startPositionUs= */ C.TIME_UNSET, + /* streamOffsetUs= */ C.TIME_UNSET); + + public final long previousStreamLastBufferTimeUs; + public final long startPositionUs; + public final long streamOffsetUs; + + public OutputStreamInfo( + long previousStreamLastBufferTimeUs, long startPositionUs, long streamOffsetUs) { + this.previousStreamLastBufferTimeUs = previousStreamLastBufferTimeUs; + this.startPositionUs = startPositionUs; + this.streamOffsetUs = streamOffsetUs; + } + } + @RequiresApi(31) private static final class Api31 { private Api31() {} From a09bb70053b2c2f01517bcaf5ec19cc0bc9efab8 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 24 Feb 2023 10:42:37 +0000 Subject: [PATCH 16/33] Do not specify export flags for protected system broadcasts. Protected system broadcasts should not specify the export flag. Marking them as NOT_EXPORTED breaks sticky broadcasts in some cases. Issue: google/ExoPlayer#10970 PiperOrigin-RevId: 512020154 (cherry picked from commit 93e117928c157ef338faa46dea25ee114f18d3eb) --- RELEASENOTES.md | 119 ++++++++++++------ .../common/util/NetworkTypeObserver.java | 2 +- .../androidx/media3/common/util/Util.java | 31 +---- .../exoplayer/AudioBecomingNoisyManager.java | 5 +- .../media3/exoplayer/StreamVolumeManager.java | 2 +- .../exoplayer/audio/AudioCapabilities.java | 4 +- .../audio/AudioCapabilitiesReceiver.java | 4 +- .../exoplayer/scheduler/Requirements.java | 8 +- .../scheduler/RequirementsWatcher.java | 2 +- 9 files changed, 100 insertions(+), 77 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b2e3e689273..aaa533e8c48 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,11 +1,76 @@ # Release notes +### Unreleased changes + +* Core library: + * Add suppression reason for unsuitable audio route and play when ready + change reason for suppressed too long. + ([#15](https://github.com/androidx/media/issues/15)). + * Make the maximum difference of the start time of two segments to be + merged configurable in `SegmentDownloader` and subclasses + ([#248](https://github.com/androidx/media/pull/248)). + * Add `ExoPlayer.setVideoEffects()` for using `Effect` during video + playback. + * Update `SampleQueue` to store `sourceId` as a `long` rather than an + `int`. This changes the signatures of public methods + `SampleQueue.sourceId` and `SampleQueue.peekSourceId`. + * Fix network type detection on API 33 + ([#10970](https://github.com/google/ExoPlayer/issues/10970)). + * Make the maximum difference of the start time of two segments to be + merged configurable in `SegmentDownloader` and subclasses + ([#248](https://github.com/androidx/media/pull/248)). +* Extractors: + * Fix `NullPointerException` when calling `ExoPlayer.isTunnelingEnabled` + ([#10977](https://github.com/google/ExoPlayer/issues/10977)). +* Audio: + * Fix bug where some playbacks fail when tunneling is enabled and + `AudioProcessors` are active, e.g. for gapless trimming + ([#10847](https://github.com/google/ExoPlayer/issues/10847)). + * Encapsulate Opus frames in Ogg packets in direct playbacks (offload). +* Video: + * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of + `HEVCProfileMain10`. +* DASH: + * Add full parsing for image adaptation sets, including tile counts + ([#3752](https://github.com/google/ExoPlayer/issues/3752)). +* RTSP: + * Catch the IllegalArgumentException thrown in parsing of invalid RTSP + Describe response messages + ([#10971](https://github.com/google/ExoPlayer/issues/10971)). +* Session: + * Fix a bug where notification play/pause button doesn't update with + player state ([#192](https://github.com/androidx/media/issues/192)). + * Fix a bug where notification play/pause button doesn't update with + player state ([#192](https://github.com/androidx/media/issues/192)). +* RTSP: + * Catch the IllegalArgumentException thrown in parsing of invalid RTSP + Describe response messages + ([#10971](https://github.com/google/ExoPlayer/issues/10971)). +* Metadata: + * Parse multiple null-separated values from ID3 frames, as permitted by + ID3 v2.4. + * Add `MediaMetadata.mediaType` to denote the type of content or the type + of folder described by the metadata. + * Add `MediaMetadata.isBrowsable` as a replacement for + `MediaMetadata.folderType`. The folder type will be deprecated in the + next release. +* Transformer: + * Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`. + Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and + `Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)` + instead. + * Remove `Transformer.startTransformation(MediaItem, + ParcelFileDescriptor)`. +* Remove deprecated symbols: + * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` + instead. + ### 1.0.0-rc01 (2023-02-16) This release corresponds to the [ExoPlayer 2.18.3 release](https://github.com/google/ExoPlayer/releases/tag/r2.18.3). -* Core library: +* Core library: * Tweak the renderer's decoder ordering logic to uphold the `MediaCodecSelector`'s preferences, even if a decoder reports it may not be able to play the media performantly. For example with default @@ -20,35 +85,29 @@ This release corresponds to the for seeking. * Use theme when loading drawables on API 21+ ([#220](https://github.com/androidx/media/issues/220)). - * Make the maximum difference of the start time of two segments to be - merged configurable in `SegmentDownloader` and subclasses - ([#248](https://github.com/androidx/media/pull/248)). * Add `ConcatenatingMediaSource2` that allows combining multiple media items into a single window ([#247](https://github.com/androidx/media/issues/247)). -* Extractors: +* Extractors: * Throw a `ParserException` instead of a `NullPointerException` if the sample table (stbl) is missing a required sample description (stsd) when parsing trak atoms. * Correctly skip samples when seeking directly to a sync frame in fMP4 ([#10941](https://github.com/google/ExoPlayer/issues/10941)). * Fix `NullPointerException` when calling `ExoPlayer.isTunnelingEnabled` - ([#10977](https://github.com/google/ExoPlayer/issues/10977)). -* Audio: - * Use the compressed audio format bitrate to calculate the min buffer size + ([#10977](https://github.com/google/ExoPlayer/issues/10977)). +* Audio: + * Use the compressed audio format bitrate to calculate the min buffer size for `AudioTrack` in direct playbacks (passthrough). - * Fix bug where some playbacks fail when tunneling is enabled and - `AudioProcessors` are active, e.g. for gapless trimming - ([#10847](https://github.com/google/ExoPlayer/issues/10847)). -* Video: - * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of - `HEVCProfileMain10`. -* Text: + * Fix bug where some playbacks fail when tunneling is enabled and + `AudioProcessors` are active, e.g. for gapless trimming + ([#10847](https://github.com/google/ExoPlayer/issues/10847)). +* Text: * Fix `TextRenderer` passing an invalid (negative) index to `Subtitle.getEventTime` if a subtitle file contains no cues. * SubRip: Add support for UTF-16 files if they start with a byte order mark. -* Metadata: +* Metadata: * Parse multiple null-separated values from ID3 frames, as permitted by ID3 v2.4. * Add `MediaMetadata.mediaType` to denote the type of content or the type @@ -56,10 +115,10 @@ This release corresponds to the * Add `MediaMetadata.isBrowsable` as a replacement for `MediaMetadata.folderType`. The folder type will be deprecated in the next release. -* DASH: +* DASH: * Add full parsing for image adaptation sets, including tile counts ([#3752](https://github.com/google/ExoPlayer/issues/3752)). -* UI: +* UI: * Fix the deprecated `PlayerView.setControllerVisibilityListener(PlayerControlView.VisibilityListener)` to ensure visibility changes are passed to the registered listener @@ -67,7 +126,7 @@ This release corresponds to the * Fix the ordering of the center player controls in `PlayerView` when using a right-to-left (RTL) layout ([#227](https://github.com/androidx/media/issues/227)). -* Session: +* Session: * Add abstract `SimpleBasePlayer` to help implement the `Player` interface for custom players. * Add helper method to convert platform session token to Media3 @@ -84,26 +143,12 @@ This release corresponds to the ([#233](https://github.com/androidx/media/issues/233)). * Make `QueueTimeline` more robust in case of a shady legacy session state ([#241](https://github.com/androidx/media/issues/241)). - * Fix a bug where notification play/pause button doesn't update with - player state ([#192](https://github.com/androidx/media/issues/192)). -* RTSP: - * Catch the IllegalArgumentException thrown in parsing of invalid RTSP - Describe response messages - ([#10971](https://github.com/google/ExoPlayer/issues/10971)). -* Metadata: - * Parse multiple null-separated values from ID3 frames, as permitted by - ID3 v2.4. - * Add `MediaMetadata.mediaType` to denote the type of content or the type - of folder described by the metadata. - * Add `MediaMetadata.isBrowsable` as a replacement for - `MediaMetadata.folderType`. The folder type will be deprecated in the - next release. -* Cast extension: +* Cast extension: * Bump Cast SDK version to 21.2.0. -* IMA extension: +* IMA extension: * Map `PLAYER_STATE_LOADING` to `STATE_BUFFERING` ([#245](\(https://github.com/androidx/media/issues/245\)). -* IMA extension +* IMA extension * Remove player listener of the `ImaServerSideAdInsertionMediaSource` on the application thread to avoid threading issues. * Add a property `focusSkipButtonWhenAvailable` to the @@ -115,7 +160,7 @@ This release corresponds to the * Fix a bug which prevented playback from starting for a DAI stream without any ads. * Bump IMA SDK version to 3.29.0. -* Demo app: +* Demo app: * Request notification permission for download notifications at runtime ([#10884](https://github.com/google/ExoPlayer/issues/10884)). diff --git a/libraries/common/src/main/java/androidx/media3/common/util/NetworkTypeObserver.java b/libraries/common/src/main/java/androidx/media3/common/util/NetworkTypeObserver.java index 4e97ab796c5..7b64795466c 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/NetworkTypeObserver.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/NetworkTypeObserver.java @@ -94,7 +94,7 @@ private NetworkTypeObserver(Context context) { networkType = C.NETWORK_TYPE_UNKNOWN; IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - Util.registerReceiverNotExported(context, new Receiver(), filter); + context.registerReceiver(new Receiver(), filter); } /** diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 464db2648d9..a079c488d97 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -206,6 +206,10 @@ public static byte[] toByteArray(InputStream inputStream) throws IOException { * apps. This will be enforced by specifying {@link Context#RECEIVER_NOT_EXPORTED} if {@link * #SDK_INT} is 33 or above. * + *

Do not use this method if registering a receiver for a protected + * system broadcast. + * * @param context The context on which {@link Context#registerReceiver} will be called. * @param receiver The {@link BroadcastReceiver} to register. This value may be null. * @param filter Selects the Intent broadcasts to be received. @@ -222,33 +226,6 @@ public static Intent registerReceiverNotExported( } } - /** - * Registers a {@link BroadcastReceiver} that's not intended to receive broadcasts from other - * apps. This will be enforced by specifying {@link Context#RECEIVER_NOT_EXPORTED} if {@link - * #SDK_INT} is 33 or above. - * - * @param context The context on which {@link Context#registerReceiver} will be called. - * @param receiver The {@link BroadcastReceiver} to register. This value may be null. - * @param filter Selects the Intent broadcasts to be received. - * @param handler Handler identifying the thread that will receive the Intent. - * @return The first sticky intent found that matches {@code filter}, or null if there are none. - */ - @UnstableApi - @Nullable - public static Intent registerReceiverNotExported( - Context context, BroadcastReceiver receiver, IntentFilter filter, Handler handler) { - if (SDK_INT < 33) { - return context.registerReceiver(receiver, filter, /* broadcastPermission= */ null, handler); - } else { - return context.registerReceiver( - receiver, - filter, - /* broadcastPermission= */ null, - handler, - Context.RECEIVER_NOT_EXPORTED); - } - } - /** * Calls {@link Context#startForegroundService(Intent)} if {@link #SDK_INT} is 26 or higher, or * {@link Context#startService(Intent)} otherwise. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/AudioBecomingNoisyManager.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/AudioBecomingNoisyManager.java index 625c6090b6b..04fd1482bd8 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/AudioBecomingNoisyManager.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/AudioBecomingNoisyManager.java @@ -21,7 +21,6 @@ import android.content.IntentFilter; import android.media.AudioManager; import android.os.Handler; -import androidx.media3.common.util.Util; /* package */ final class AudioBecomingNoisyManager { @@ -47,8 +46,8 @@ public AudioBecomingNoisyManager(Context context, Handler eventHandler, EventLis */ public void setEnabled(boolean enabled) { if (enabled && !receiverRegistered) { - Util.registerReceiverNotExported( - context, receiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); + context.registerReceiver( + receiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); receiverRegistered = true; } else if (!enabled && receiverRegistered) { context.unregisterReceiver(receiver); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java index 1fc7dc48287..c5a82301549 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java @@ -75,7 +75,7 @@ public StreamVolumeManager(Context context, Handler eventHandler, Listener liste VolumeChangeReceiver receiver = new VolumeChangeReceiver(); IntentFilter filter = new IntentFilter(VOLUME_CHANGED_ACTION); try { - Util.registerReceiverNotExported(applicationContext, receiver, filter); + applicationContext.registerReceiver(receiver, filter); this.receiver = receiver; } catch (RuntimeException e) { Log.w(TAG, "Error registering stream volume receiver", e); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 6cb10f07311..9888db45a6d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -88,8 +88,8 @@ public final class AudioCapabilities { @SuppressWarnings("InlinedApi") public static AudioCapabilities getCapabilities(Context context) { Intent intent = - Util.registerReceiverNotExported( - context, /* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG)); + context.registerReceiver( + /* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG)); return getCapabilities(context, intent); } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilitiesReceiver.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilitiesReceiver.java index 1cfef2accc9..671ddb5aa6d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilitiesReceiver.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilitiesReceiver.java @@ -93,7 +93,9 @@ public AudioCapabilities register() { @Nullable Intent stickyIntent = null; if (receiver != null) { IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG); - stickyIntent = Util.registerReceiverNotExported(context, receiver, intentFilter, handler); + stickyIntent = + context.registerReceiver( + receiver, intentFilter, /* broadcastPermission= */ null, handler); } audioCapabilities = AudioCapabilities.getCapabilities(context, stickyIntent); return audioCapabilities; diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/Requirements.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/Requirements.java index ab87aa361cb..53ad113710b 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/Requirements.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/Requirements.java @@ -184,8 +184,8 @@ public boolean checkRequirements(Context context) { private boolean isDeviceCharging(Context context) { @Nullable Intent batteryStatus = - Util.registerReceiverNotExported( - context, /* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + context.registerReceiver( + /* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); if (batteryStatus == null) { return false; } @@ -203,8 +203,8 @@ private boolean isDeviceIdle(Context context) { } private boolean isStorageNotLow(Context context) { - return Util.registerReceiverNotExported( - context, /* receiver= */ null, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW)) + return context.registerReceiver( + /* receiver= */ null, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW)) == null; } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/RequirementsWatcher.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/RequirementsWatcher.java index 541224221c9..d214bc95af9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/RequirementsWatcher.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/scheduler/RequirementsWatcher.java @@ -111,7 +111,7 @@ public RequirementsWatcher(Context context, Listener listener, Requirements requ filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); } receiver = new DeviceStatusChangeReceiver(); - Util.registerReceiverNotExported(context, receiver, filter, handler); + context.registerReceiver(receiver, filter, /* broadcastPermission= */ null, handler); return notMetRequirements; } From abf1eb8b8ab51a6d331d8472bdd765dfec865dbb Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 27 Feb 2023 10:11:19 +0000 Subject: [PATCH 17/33] Use more realistic time values for MediaCodecVideoRendererTest This test became flaky after https://github.com/androidx/media/commit/ab7e84fb34b7ef4b13e492e1f8918345c712ec30 because some of the unrealistic frame times ended up on the same release time. Using realistic numbers avoids the flakiness. PiperOrigin-RevId: 512566469 (cherry picked from commit 0c8ce183fe7e2f065ca4dea33818566e9aeff48f) --- .../video/MediaCodecVideoRendererTest.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java index d42ab38fe02..b7ad8dc6c26 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java @@ -16,6 +16,7 @@ package androidx.media3.exoplayer.video; import static android.view.Display.DEFAULT_DISPLAY; +import static androidx.media3.common.util.Util.msToUs; import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM; import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.format; import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample; @@ -59,6 +60,7 @@ import com.google.common.collect.ImmutableList; import java.util.Collections; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.junit.After; import org.junit.Before; @@ -72,6 +74,7 @@ import org.robolectric.Shadows; import org.robolectric.shadows.ShadowDisplay; import org.robolectric.shadows.ShadowLooper; +import org.robolectric.shadows.ShadowSystemClock; /** Unit test for {@link MediaCodecVideoRenderer}. */ @RunWith(AndroidJUnit4.class) @@ -261,7 +264,7 @@ public void render_sendsVideoSizeChangeWithCurrentFormatValues() throws Exceptio /* initialFormat= */ pAsp1, ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME))); fakeSampleStream.writeData(/* startPositionUs= */ 0); - + SystemClock.setCurrentTimeMillis(876_000_000); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, new Format[] {pAsp1, pAsp2, pAsp3}, @@ -272,25 +275,27 @@ public void render_sendsVideoSizeChangeWithCurrentFormatValues() throws Exceptio /* startPositionUs= */ 0, /* offsetUs */ 0); mediaCodecVideoRenderer.start(); - mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); - mediaCodecVideoRenderer.render(/* positionUs= */ 250, SystemClock.elapsedRealtime() * 1000); + mediaCodecVideoRenderer.render(/* positionUs= */ 0, msToUs(SystemClock.elapsedRealtime())); + ShadowSystemClock.advanceBy(10, TimeUnit.MILLISECONDS); + mediaCodecVideoRenderer.render(/* positionUs= */ 10_000, msToUs(SystemClock.elapsedRealtime())); fakeSampleStream.append( ImmutableList.of( format(pAsp2), - oneByteSample(/* timeUs= */ 5_000), - oneByteSample(/* timeUs= */ 10_000), - format(pAsp3), - oneByteSample(/* timeUs= */ 15_000), oneByteSample(/* timeUs= */ 20_000), + oneByteSample(/* timeUs= */ 40_000), + format(pAsp3), + oneByteSample(/* timeUs= */ 60_000), + oneByteSample(/* timeUs= */ 80_000), END_OF_STREAM_ITEM)); - fakeSampleStream.writeData(/* startPositionUs= */ 5_000); + fakeSampleStream.writeData(/* startPositionUs= */ 20_000); mediaCodecVideoRenderer.setCurrentStreamFinal(); - int pos = 500; + int positionUs = 20_000; do { - mediaCodecVideoRenderer.render(/* positionUs= */ pos, SystemClock.elapsedRealtime() * 1000); - pos += 250; + ShadowSystemClock.advanceBy(10, TimeUnit.MILLISECONDS); + mediaCodecVideoRenderer.render(positionUs, msToUs(SystemClock.elapsedRealtime())); + positionUs += 10_000; } while (!mediaCodecVideoRenderer.isEnded()); shadowOf(testMainLooper).idle(); From f011cc814ab04bd2041734a0eed1df1b2c6d74dd Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 27 Feb 2023 10:41:38 +0000 Subject: [PATCH 18/33] Correctly update output info if previous stream has been fully rendered The output info for a new stream is marked pending until the last sample of the previous stream has been processed. However, this fails if the previous stream has already been fully processed. We need to detect this case explicitly to avoid signalling the output change one sample too late. #minor-release PiperOrigin-RevId: 512572854 (cherry picked from commit 7ffcc6f7ea648fb89b487f4c381b1d886cc8a638) --- .../exoplayer/mediacodec/MediaCodecRenderer.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index a4a602eef4d..cad2720ff22 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -358,6 +358,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) { @Nullable private ExoPlaybackException pendingPlaybackException; protected DecoderCounters decoderCounters; private OutputStreamInfo outputStreamInfo; + private long lastProcessedOutputBufferTimeUs; /** * @param trackType The {@link C.TrackType track type} that the renderer handles. @@ -408,6 +409,7 @@ public MediaCodecRenderer( codecHotswapDeadlineMs = C.TIME_UNSET; largestQueuedPresentationTimeUs = C.TIME_UNSET; lastBufferInStreamPresentationTimeUs = C.TIME_UNSET; + lastProcessedOutputBufferTimeUs = C.TIME_UNSET; codecDrainState = DRAIN_STATE_NONE; codecDrainAction = DRAIN_ACTION_NONE; } @@ -637,8 +639,11 @@ protected void onEnabled(boolean joining, boolean mayRenderStartOfStream) @Override protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) throws ExoPlaybackException { - if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) { - checkState(outputStreamInfo.startPositionUs == C.TIME_UNSET); + if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET + || (pendingOutputStreamChanges.isEmpty() + && lastProcessedOutputBufferTimeUs != C.TIME_UNSET + && lastProcessedOutputBufferTimeUs >= largestQueuedPresentationTimeUs)) { + // This is the first stream, or the previous has been fully output already. setOutputStreamInfo( new OutputStreamInfo( /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs)); @@ -871,6 +876,7 @@ protected void resetCodecStateForFlush() { decodeOnlyPresentationTimestamps.clear(); largestQueuedPresentationTimeUs = C.TIME_UNSET; lastBufferInStreamPresentationTimeUs = C.TIME_UNSET; + lastProcessedOutputBufferTimeUs = C.TIME_UNSET; if (c2Mp3TimestampTracker != null) { c2Mp3TimestampTracker.reset(); } @@ -1567,6 +1573,7 @@ protected void onQueueInputBuffer(DecoderInputBuffer buffer) throws ExoPlaybackE */ @CallSuper protected void onProcessedOutputBuffer(long presentationTimeUs) { + lastProcessedOutputBufferTimeUs = presentationTimeUs; if (!pendingOutputStreamChanges.isEmpty() && presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) { setOutputStreamInfo(pendingOutputStreamChanges.poll()); From 512ca609b28332f27709b2df46ccfb5678a83495 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 27 Feb 2023 11:25:10 +0000 Subject: [PATCH 19/33] Add workaround for wrong PerformancePoints on some devices. Some devices were reported to have wrong PerformancePoint sets that cause 60 fps to be marked as unsupported even though they are supported. Issue: google/ExoPlayer#10898 PiperOrigin-RevId: 512580395 (cherry picked from commit d0cbf0fce84aa73be5eb68935d6a4dd2f2e1dc3d) --- RELEASENOTES.md | 17 ++++++++--------- .../exoplayer/mediacodec/MediaCodecInfo.java | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index aaa533e8c48..62210b405db 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -30,7 +30,11 @@ * Video: * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of `HEVCProfileMain10`. -* DASH: +* Add workaround for a device issue on Chromecast with Google TV and + Lenovo M10 FHD Plus that causes 60fps AVC streams to be marked as + unsupported + ([#10898](https://github.com/google/ExoPlayer/issues/10898)). +* DASH: * Add full parsing for image adaptation sets, including tile counts ([#3752](https://github.com/google/ExoPlayer/issues/3752)). * RTSP: @@ -94,15 +98,10 @@ This release corresponds to the parsing trak atoms. * Correctly skip samples when seeking directly to a sync frame in fMP4 ([#10941](https://github.com/google/ExoPlayer/issues/10941)). - * Fix `NullPointerException` when calling `ExoPlayer.isTunnelingEnabled` - ([#10977](https://github.com/google/ExoPlayer/issues/10977)). -* Audio: - * Use the compressed audio format bitrate to calculate the min buffer size +* Audio: + * Use the compressed audio format bitrate to calculate the min buffer size for `AudioTrack` in direct playbacks (passthrough). - * Fix bug where some playbacks fail when tunneling is enabled and - `AudioProcessors` are active, e.g. for gapless trimming - ([#10847](https://github.com/google/ExoPlayer/issues/10847)). -* Text: +* Text: * Fix `TextRenderer` passing an invalid (negative) index to `Subtitle.getEventTime` if a subtitle file contains no cues. * SubRip: Add support for UTF-16 files if they start with a byte order diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecInfo.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecInfo.java index e49a9a5a3cc..d36f9eb07b9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecInfo.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecInfo.java @@ -857,7 +857,7 @@ private static boolean needsAdaptationFlushWorkaround(String mimeType) { * @param name The name of the codec. * @return Whether to enable the workaround. */ - private static final boolean needsRotatedVerticalResolutionWorkaround(String name) { + private static boolean needsRotatedVerticalResolutionWorkaround(String name) { if ("OMX.MTK.VIDEO.DECODER.HEVC".equals(name) && "mcv5a".equals(Util.DEVICE)) { // See https://github.com/google/ExoPlayer/issues/6612. return false; @@ -876,6 +876,17 @@ private static boolean needsProfileExcludedWorkaround(String mimeType, int profi && ("sailfish".equals(Util.DEVICE) || "marlin".equals(Util.DEVICE)); } + /** Whether the device is known to have wrong {@link PerformancePoint} declarations. */ + private static boolean needsIgnorePerformancePointsWorkaround() { + // See https://github.com/google/ExoPlayer/issues/10898 and [internal ref: b/267324685]. + return /* Chromecast with Google TV */ Util.DEVICE.equals("sabrina") + || Util.DEVICE.equals("boreal") + /* Lenovo Tablet M10 FHD Plus */ + || Util.MODEL.startsWith("Lenovo TB-X605") + || Util.MODEL.startsWith("Lenovo TB-X606") + || Util.MODEL.startsWith("Lenovo TB-X616"); + } + /** Possible outcomes of evaluating PerformancePoint coverage */ @Documented @Retention(RetentionPolicy.SOURCE) @@ -900,7 +911,9 @@ private static final class Api29 { VideoCapabilities videoCapabilities, int width, int height, double frameRate) { List performancePointList = videoCapabilities.getSupportedPerformancePoints(); - if (performancePointList == null || performancePointList.isEmpty()) { + if (performancePointList == null + || performancePointList.isEmpty() + || needsIgnorePerformancePointsWorkaround()) { return COVERAGE_RESULT_NO_EMPTY_LIST; } From 5822d683ead77f2f039c972d2492de0a5d78a8d7 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 27 Feb 2023 12:04:59 +0000 Subject: [PATCH 20/33] Ensure output format is updated in sync with stream changes. MediaCodecRenderer currently has two independent paths to trigger events at stream changes: 1. Detection of the last output buffer of the old stream to trigger onProcessedStreamChange and setting the new output stream offset. 2. Detection of the first input buffer of the new stream to trigger onOutputFormatChanged. Both events are identical for most media. However, there are two problematic cases: A. (1) happens after (2). This may happen if the declared media duration is shorter than the actual last sample timestamp. B. (2) is too late and there are output samples between (1) and (2). This can happen if the new media outputs samples with a timestamp less than the first input timestamp. This can be made more robust by: - Keeping a separate formatQueue for each stream to avoid case A. - Force outputting the first format after a stream change to avoid case B. Issue: google/ExoPlayer#8594 PiperOrigin-RevId: 512586838 (cherry picked from commit 3970343846d7bae5d8ae331d74241c50777ce18a) --- RELEASENOTES.md | 6 +- .../mediacodec/MediaCodecRenderer.java | 33 +- .../mediacodec/MediaCodecRendererTest.java | 323 ++++++++++++++++++ 3 files changed, 348 insertions(+), 14 deletions(-) create mode 100644 libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 62210b405db..ff4dbf6f146 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -27,10 +27,12 @@ `AudioProcessors` are active, e.g. for gapless trimming ([#10847](https://github.com/google/ExoPlayer/issues/10847)). * Encapsulate Opus frames in Ogg packets in direct playbacks (offload). -* Video: + * Fix broken gapless MP3 playback on Samsung devices + ([#8594](https://github.com/google/ExoPlayer/issues/8594)). +* Video: * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of `HEVCProfileMain10`. -* Add workaround for a device issue on Chromecast with Google TV and + * Add workaround for a device issue on Chromecast with Google TV and Lenovo M10 FHD Plus that causes 60fps AVC streams to be marked as unsupported ([#10898](https://github.com/google/ExoPlayer/issues/10898)). diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index cad2720ff22..a752432fa04 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -299,7 +299,6 @@ private static String buildCustomDiagnosticInfo(int errorCode) { private final DecoderInputBuffer buffer; private final DecoderInputBuffer bypassSampleBuffer; private final BatchBuffer bypassBatchBuffer; - private final TimedValueQueue formatQueue; private final ArrayList decodeOnlyPresentationTimestamps; private final MediaCodec.BufferInfo outputBufferInfo; private final ArrayDeque pendingOutputStreamChanges; @@ -359,6 +358,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) { protected DecoderCounters decoderCounters; private OutputStreamInfo outputStreamInfo; private long lastProcessedOutputBufferTimeUs; + private boolean needToNotifyOutputFormatChangeAfterStreamChange; /** * @param trackType The {@link C.TrackType track type} that the renderer handles. @@ -385,7 +385,6 @@ public MediaCodecRenderer( buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); bypassSampleBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT); bypassBatchBuffer = new BatchBuffer(); - formatQueue = new TimedValueQueue<>(); decodeOnlyPresentationTimestamps = new ArrayList<>(); outputBufferInfo = new MediaCodec.BufferInfo(); currentPlaybackSpeed = 1f; @@ -597,13 +596,15 @@ protected final void setPendingPlaybackException(ExoPlaybackException exception) protected final void updateOutputFormatForTime(long presentationTimeUs) throws ExoPlaybackException { boolean outputFormatChanged = false; - @Nullable Format format = formatQueue.pollFloor(presentationTimeUs); - if (format == null && codecOutputMediaFormatChanged) { - // If the codec's output MediaFormat has changed then there should be a corresponding Format - // change, which we've not found. Check the Format queue in case the corresponding - // presentation timestamp is greater than presentationTimeUs, which can happen for some codecs - // [Internal ref: b/162719047]. - format = formatQueue.pollFirst(); + @Nullable Format format = outputStreamInfo.formatQueue.pollFloor(presentationTimeUs); + if (format == null + && needToNotifyOutputFormatChangeAfterStreamChange + && codecOutputMediaFormat != null) { + // After a stream change or after the initial start, there should be an input format change, + // which we've not found. Check the Format queue in case the corresponding presentation + // timestamp is greater than presentationTimeUs, which can happen for some codecs + // [Internal ref: b/162719047 and https://github.com/google/ExoPlayer/issues/8594]. + format = outputStreamInfo.formatQueue.pollFirst(); } if (format != null) { outputFormat = format; @@ -612,6 +613,7 @@ protected final void updateOutputFormatForTime(long presentationTimeUs) if (outputFormatChanged || (codecOutputMediaFormatChanged && outputFormat != null)) { onOutputFormatChanged(outputFormat, codecOutputMediaFormat); codecOutputMediaFormatChanged = false; + needToNotifyOutputFormatChangeAfterStreamChange = false; } } @@ -668,10 +670,10 @@ protected void onPositionReset(long positionUs, boolean joining) throws ExoPlayb // If there is a format change on the input side still pending propagation to the output, we // need to queue a format next time a buffer is read. This is because we may not read a new // input format after the position reset. - if (formatQueue.size() > 0) { + if (outputStreamInfo.formatQueue.size() > 0) { waitingForFirstSampleInFormat = true; } - formatQueue.clear(); + outputStreamInfo.formatQueue.clear(); pendingOutputStreamChanges.clear(); } @@ -1333,7 +1335,11 @@ private boolean feedInputBuffer() throws ExoPlaybackException { decodeOnlyPresentationTimestamps.add(presentationTimeUs); } if (waitingForFirstSampleInFormat) { - formatQueue.add(presentationTimeUs, inputFormat); + if (!pendingOutputStreamChanges.isEmpty()) { + pendingOutputStreamChanges.peekLast().formatQueue.add(presentationTimeUs, inputFormat); + } else { + outputStreamInfo.formatQueue.add(presentationTimeUs, inputFormat); + } waitingForFirstSampleInFormat = false; } largestQueuedPresentationTimeUs = max(largestQueuedPresentationTimeUs, presentationTimeUs); @@ -2029,6 +2035,7 @@ protected final long getOutputStreamOffsetUs() { private void setOutputStreamInfo(OutputStreamInfo outputStreamInfo) { this.outputStreamInfo = outputStreamInfo; if (outputStreamInfo.streamOffsetUs != C.TIME_UNSET) { + needToNotifyOutputFormatChangeAfterStreamChange = true; onOutputStreamOffsetUsChanged(outputStreamInfo.streamOffsetUs); } } @@ -2487,12 +2494,14 @@ private static final class OutputStreamInfo { public final long previousStreamLastBufferTimeUs; public final long startPositionUs; public final long streamOffsetUs; + public final TimedValueQueue formatQueue; public OutputStreamInfo( long previousStreamLastBufferTimeUs, long startPositionUs, long streamOffsetUs) { this.previousStreamLastBufferTimeUs = previousStreamLastBufferTimeUs; this.startPositionUs = startPositionUs; this.streamOffsetUs = streamOffsetUs; + this.formatQueue = new TimedValueQueue<>(); } } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java new file mode 100644 index 00000000000..ac86669ee56 --- /dev/null +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package androidx.media3.exoplayer.mediacodec; + +import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_YES_WITHOUT_RECONFIGURATION; +import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM; +import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.spy; + +import android.media.MediaCrypto; +import android.media.MediaFormat; +import android.os.SystemClock; +import androidx.annotation.Nullable; +import androidx.media3.common.C; +import androidx.media3.common.Format; +import androidx.media3.common.MimeTypes; +import androidx.media3.exoplayer.DecoderReuseEvaluation; +import androidx.media3.exoplayer.ExoPlaybackException; +import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.RendererConfiguration; +import androidx.media3.exoplayer.analytics.PlayerId; +import androidx.media3.exoplayer.drm.DrmSessionEventListener; +import androidx.media3.exoplayer.drm.DrmSessionManager; +import androidx.media3.exoplayer.upstream.DefaultAllocator; +import androidx.media3.test.utils.FakeSampleStream; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.common.collect.ImmutableList; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; + +/** Unit tests for {@link MediaCodecRenderer} */ +@RunWith(AndroidJUnit4.class) +public class MediaCodecRendererTest { + + @Test + public void render_withReplaceStream_triggersOutputCallbacksInCorrectOrder() throws Exception { + Format format1 = + new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build(); + Format format2 = + new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1500).build(); + FakeSampleStream fakeSampleStream1 = + createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300); + FakeSampleStream fakeSampleStream2 = + createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200); + MediaCodecRenderer renderer = spy(new TestRenderer()); + renderer.init(/* index= */ 0, PlayerId.UNSET); + + renderer.enable( + RendererConfiguration.DEFAULT, + new Format[] {format1}, + fakeSampleStream1, + /* positionUs= */ 0, + /* joining= */ false, + /* mayRenderStartOfStream= */ true, + /* startPositionUs= */ 0, + /* offsetUs= */ 0); + renderer.start(); + long positionUs = 0; + while (!renderer.hasReadStreamToEnd()) { + renderer.render(positionUs, SystemClock.elapsedRealtime()); + positionUs += 100; + } + renderer.replaceStream( + new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 400); + renderer.setCurrentStreamFinal(); + while (!renderer.isEnded()) { + renderer.render(positionUs, SystemClock.elapsedRealtime()); + positionUs += 100; + } + + InOrder inOrder = inOrder(renderer); + inOrder.verify(renderer).onOutputStreamOffsetUsChanged(0); + inOrder.verify(renderer).onOutputFormatChanged(eq(format1), any()); + inOrder.verify(renderer).onProcessedOutputBuffer(0); + inOrder.verify(renderer).onProcessedOutputBuffer(100); + inOrder.verify(renderer).onProcessedOutputBuffer(200); + inOrder.verify(renderer).onProcessedOutputBuffer(300); + inOrder.verify(renderer).onOutputStreamOffsetUsChanged(400); + inOrder.verify(renderer).onProcessedStreamChange(); + inOrder.verify(renderer).onOutputFormatChanged(eq(format2), any()); + inOrder.verify(renderer).onProcessedOutputBuffer(400); + inOrder.verify(renderer).onProcessedOutputBuffer(500); + inOrder.verify(renderer).onProcessedOutputBuffer(600); + } + + @Test + public void + render_withReplaceStreamAndBufferBeyondDuration_triggersOutputCallbacksInCorrectOrder() + throws Exception { + Format format1 = + new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build(); + Format format2 = + new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1500).build(); + FakeSampleStream fakeSampleStream1 = + createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500, 600); + FakeSampleStream fakeSampleStream2 = + createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200); + MediaCodecRenderer renderer = spy(new TestRenderer()); + renderer.init(/* index= */ 0, PlayerId.UNSET); + + renderer.enable( + RendererConfiguration.DEFAULT, + new Format[] {format1}, + fakeSampleStream1, + /* positionUs= */ 0, + /* joining= */ false, + /* mayRenderStartOfStream= */ true, + /* startPositionUs= */ 0, + /* offsetUs= */ 0); + renderer.start(); + long positionUs = 0; + while (!renderer.hasReadStreamToEnd()) { + renderer.render(positionUs, SystemClock.elapsedRealtime()); + positionUs += 100; + } + renderer.replaceStream( + new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 400); + renderer.setCurrentStreamFinal(); + while (!renderer.isEnded()) { + renderer.render(positionUs, SystemClock.elapsedRealtime()); + positionUs += 100; + } + + InOrder inOrder = inOrder(renderer); + inOrder.verify(renderer).onOutputStreamOffsetUsChanged(0); + inOrder.verify(renderer).onOutputFormatChanged(eq(format1), any()); + inOrder.verify(renderer).onProcessedOutputBuffer(0); + inOrder.verify(renderer).onProcessedOutputBuffer(100); + inOrder.verify(renderer).onProcessedOutputBuffer(200); + inOrder.verify(renderer).onProcessedOutputBuffer(300); + inOrder.verify(renderer).onProcessedOutputBuffer(400); + inOrder.verify(renderer).onProcessedOutputBuffer(500); + inOrder.verify(renderer).onProcessedOutputBuffer(600); + inOrder.verify(renderer).onOutputStreamOffsetUsChanged(400); + inOrder.verify(renderer).onProcessedStreamChange(); + inOrder.verify(renderer).onOutputFormatChanged(eq(format2), any()); + inOrder.verify(renderer).onProcessedOutputBuffer(400); + inOrder.verify(renderer).onProcessedOutputBuffer(500); + inOrder.verify(renderer).onProcessedOutputBuffer(600); + } + + @Test + public void + render_withReplaceStreamAndBufferLessThanStartPosition_triggersOutputCallbacksInCorrectOrder() + throws Exception { + Format format1 = + new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build(); + Format format2 = + new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1500).build(); + FakeSampleStream fakeSampleStream1 = + createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300); + FakeSampleStream fakeSampleStream2 = + createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200, 300, 400); + MediaCodecRenderer renderer = spy(new TestRenderer()); + renderer.init(/* index= */ 0, PlayerId.UNSET); + + renderer.enable( + RendererConfiguration.DEFAULT, + new Format[] {format1}, + fakeSampleStream1, + /* positionUs= */ 0, + /* joining= */ false, + /* mayRenderStartOfStream= */ true, + /* startPositionUs= */ 0, + /* offsetUs= */ 0); + renderer.start(); + long positionUs = 0; + while (!renderer.hasReadStreamToEnd()) { + renderer.render(positionUs, SystemClock.elapsedRealtime()); + positionUs += 100; + } + renderer.replaceStream( + new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 200); + renderer.setCurrentStreamFinal(); + while (!renderer.isEnded()) { + renderer.render(positionUs, SystemClock.elapsedRealtime()); + positionUs += 100; + } + + InOrder inOrder = inOrder(renderer); + inOrder.verify(renderer).onOutputStreamOffsetUsChanged(0); + inOrder.verify(renderer).onOutputFormatChanged(eq(format1), any()); + inOrder.verify(renderer).onProcessedOutputBuffer(0); + inOrder.verify(renderer).onProcessedOutputBuffer(100); + inOrder.verify(renderer).onProcessedOutputBuffer(200); + inOrder.verify(renderer).onProcessedOutputBuffer(300); + inOrder.verify(renderer).onOutputStreamOffsetUsChanged(200); + inOrder.verify(renderer).onProcessedStreamChange(); + inOrder.verify(renderer).onOutputFormatChanged(eq(format2), any()); + inOrder.verify(renderer).onProcessedOutputBuffer(200); + inOrder.verify(renderer).onProcessedOutputBuffer(300); + inOrder.verify(renderer).onProcessedOutputBuffer(400); + inOrder.verify(renderer).onProcessedOutputBuffer(500); + inOrder.verify(renderer).onProcessedOutputBuffer(600); + } + + private FakeSampleStream createFakeSampleStream(Format format, long... sampleTimesUs) { + ImmutableList.Builder sampleListBuilder = + ImmutableList.builder(); + for (long sampleTimeUs : sampleTimesUs) { + sampleListBuilder.add(oneByteSample(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME)); + } + sampleListBuilder.add(END_OF_STREAM_ITEM); + FakeSampleStream sampleStream = + new FakeSampleStream( + new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024), + /* mediaSourceEventDispatcher= */ null, + DrmSessionManager.DRM_UNSUPPORTED, + new DrmSessionEventListener.EventDispatcher(), + /* initialFormat= */ format, + sampleListBuilder.build()); + sampleStream.writeData(/* startPositionUs= */ 0); + return sampleStream; + } + + private static class TestRenderer extends MediaCodecRenderer { + + public TestRenderer() { + super( + C.TRACK_TYPE_AUDIO, + MediaCodecAdapter.Factory.DEFAULT, + /* mediaCodecSelector= */ (mimeType, requiresSecureDecoder, requiresTunnelingDecoder) -> + Collections.singletonList( + MediaCodecInfo.newInstance( + /* name= */ "name", + /* mimeType= */ mimeType, + /* codecMimeType= */ mimeType, + /* capabilities= */ null, + /* hardwareAccelerated= */ false, + /* softwareOnly= */ true, + /* vendor= */ false, + /* forceDisableAdaptive= */ false, + /* forceSecure= */ false)), + /* enableDecoderFallback= */ false, + /* assumedMinimumCodecOperatingRate= */ 44100); + } + + @Override + public String getName() { + return "test"; + } + + @Override + protected @Capabilities int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format) + throws MediaCodecUtil.DecoderQueryException { + return RendererCapabilities.create(C.FORMAT_HANDLED); + } + + @Override + protected List getDecoderInfos( + MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) + throws MediaCodecUtil.DecoderQueryException { + return mediaCodecSelector.getDecoderInfos( + format.sampleMimeType, + /* requiresSecureDecoder= */ false, + /* requiresTunnelingDecoder= */ false); + } + + @Override + protected MediaCodecAdapter.Configuration getMediaCodecConfiguration( + MediaCodecInfo codecInfo, + Format format, + @Nullable MediaCrypto crypto, + float codecOperatingRate) { + return MediaCodecAdapter.Configuration.createForAudioDecoding( + codecInfo, new MediaFormat(), format, crypto); + } + + @Override + protected boolean processOutputBuffer( + long positionUs, + long elapsedRealtimeUs, + @Nullable MediaCodecAdapter codec, + @Nullable ByteBuffer buffer, + int bufferIndex, + int bufferFlags, + int sampleCount, + long bufferPresentationTimeUs, + boolean isDecodeOnlyBuffer, + boolean isLastBuffer, + Format format) + throws ExoPlaybackException { + if (bufferPresentationTimeUs <= positionUs) { + // Only release buffers when the position advances far enough for realistic behavior where + // input of buffers to the codec is faster than output. + codec.releaseOutputBuffer(bufferIndex, /* render= */ true); + return true; + } + return false; + } + + @Override + protected DecoderReuseEvaluation canReuseCodec( + MediaCodecInfo codecInfo, Format oldFormat, Format newFormat) { + return new DecoderReuseEvaluation( + codecInfo.name, + oldFormat, + newFormat, + REUSE_RESULT_YES_WITHOUT_RECONFIGURATION, + /* discardReasons= */ 0); + } + } +} From ad428004fd46f2d754f3ecd4e0e12cbae579ed5e Mon Sep 17 00:00:00 2001 From: tianyifeng Date: Fri, 10 Feb 2023 14:57:53 +0000 Subject: [PATCH 21/33] Update notification play/pause button with matching player state Issue: androidx/media#192 PiperOrigin-RevId: 508649684 (cherry picked from commit e1d12fc395d9f9edb28755a5b1026e26b378e005) --- RELEASENOTES.md | 21 +++++++++++++++++++ .../session/MediaNotificationManager.java | 4 +++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ff4dbf6f146..7a931129aca 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -145,6 +145,27 @@ This release corresponds to the * Make `QueueTimeline` more robust in case of a shady legacy session state ([#241](https://github.com/androidx/media/issues/241)). * Cast extension: + * Fix a bug where notification play/pause button doesn't update with + player state ([#192](https://github.com/androidx/media/issues/192)). +* Metadata: + * Parse multiple null-separated values from ID3 frames, as permitted by + ID3 v2.4. + * Add `MediaMetadata.mediaType` to denote the type of content or the type + of folder described by the metadata. + * Add `MediaMetadata.isBrowsable` as a replacement for + `MediaMetadata.folderType`. The folder type will be deprecated in the + next release. +* Transformer: + * Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`. + Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and + `Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)` + instead. + * Remove `Transformer.startTransformation(MediaItem, + ParcelFileDescriptor)`. +* Remove deprecated symbols: + * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` + instead. +* Cast extension * Bump Cast SDK version to 21.2.0. * IMA extension: * Map `PLAYER_STATE_LOADING` to `STATE_BUFFERING` diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java b/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java index 27c0cc4ece6..30afcb411b8 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java @@ -219,9 +219,11 @@ private void updateNotificationInternal( if (startInForegroundRequired) { startForeground(mediaNotification); } else { - maybeStopForegroundService(/* removeNotifications= */ false); + // Notification manager has to be updated first to avoid missing updates + // (https://github.com/androidx/media/issues/192). notificationManagerCompat.notify( mediaNotification.notificationId, mediaNotification.notification); + maybeStopForegroundService(/* removeNotifications= */ false); } } From f690ebdf46115e6c1a4f0ac595de1ac4c9fd9ddb Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 27 Feb 2023 18:06:36 +0000 Subject: [PATCH 22/33] Fix some playback parameter signalling problems. Playback parameter signalling can be quite complex because (a) the renderer clock often has a delay before it realizes that it doesn't support a previously set speed and (b) the speed set on media clock sometimes intentionally differs from the one surfaced to the user, e.g. during live speed adjustment or when overriding ad playback speed to 1.0f. This change fixes two problems related to this signalling: 1. When resetting the media clock speed at a period transition, we don't currently tell the renderers that this happened. 2. When a delayed speed change update from the media clock is pending and the renderer for this media clock is disabled before the change can be handled, the pending update becomes stale but it still applied later and overrides any other valid speed set in the meantime. Both edge cases are also covered by extended or new player tests. Issue: google/ExoPlayer#10882 PiperOrigin-RevId: 512658918 (cherry picked from commit e79b47ccff39363543c514937aef517a855994f0) --- RELEASENOTES.md | 3 + .../exoplayer/ExoPlayerImplInternal.java | 26 ++- .../media3/exoplayer/ExoPlayerTest.java | 204 ++++++++++++------ 3 files changed, 162 insertions(+), 71 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7a931129aca..77227fbcaec 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -29,6 +29,9 @@ * Encapsulate Opus frames in Ogg packets in direct playbacks (offload). * Fix broken gapless MP3 playback on Samsung devices ([#8594](https://github.com/google/ExoPlayer/issues/8594)). + * Fix bug where playback speeds set immediately after disabling audio may + be overridden by a previous speed change + ([#10882](https://github.com/google/ExoPlayer/issues/10882)). * Video: * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of `HEVCProfileMain10`. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java index 6c3c64075b7..e84ea1e7e09 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java @@ -946,7 +946,7 @@ && shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, playbackInfo.periodI livePlaybackSpeedControl.getAdjustedPlaybackSpeed( getCurrentLiveOffsetUs(), getTotalBufferedDurationUs()); if (mediaClock.getPlaybackParameters().speed != adjustedSpeed) { - mediaClock.setPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed)); + setMediaClockPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed)); handlePlaybackParameters( playbackInfo.playbackParameters, /* currentPlaybackSpeed= */ mediaClock.getPlaybackParameters().speed, @@ -956,6 +956,12 @@ && shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, playbackInfo.periodI } } + private void setMediaClockPlaybackParameters(PlaybackParameters playbackParameters) { + // Previously sent speed updates from the media clock now become stale. + handler.removeMessages(MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL); + mediaClock.setPlaybackParameters(playbackParameters); + } + private void notifyTrackSelectionRebuffer() { MediaPeriodHolder periodHolder = queue.getPlayingPeriod(); while (periodHolder != null) { @@ -1342,7 +1348,7 @@ private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackExce private void setPlaybackParametersInternal(PlaybackParameters playbackParameters) throws ExoPlaybackException { - mediaClock.setPlaybackParameters(playbackParameters); + setMediaClockPlaybackParameters(playbackParameters); handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true); } @@ -1657,7 +1663,7 @@ private void maybeTriggerPendingMessages(long oldPeriodPositionUs, long newPerio nextPendingMessageIndexHint = nextPendingMessageIndex; } - private void ensureStopped(Renderer renderer) throws ExoPlaybackException { + private void ensureStopped(Renderer renderer) { if (renderer.getState() == Renderer.STATE_STARTED) { renderer.stop(); } @@ -1914,14 +1920,20 @@ private void updatePlaybackSpeedSettingsForNewPeriod( MediaPeriodId newPeriodId, Timeline oldTimeline, MediaPeriodId oldPeriodId, - long positionForTargetOffsetOverrideUs) { + long positionForTargetOffsetOverrideUs) + throws ExoPlaybackException { if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) { // Live playback speed control is unused for the current period, reset speed to user-defined // playback parameters or 1.0 for ad playback. PlaybackParameters targetPlaybackParameters = newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters; if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) { - mediaClock.setPlaybackParameters(targetPlaybackParameters); + setMediaClockPlaybackParameters(targetPlaybackParameters); + handlePlaybackParameters( + playbackInfo.playbackParameters, + targetPlaybackParameters.speed, + /* updatePlaybackInfo= */ false, + /* acknowledgeCommand= */ false); } return; } @@ -1970,7 +1982,7 @@ private long getMaxRendererReadPositionUs() { return maxReadPositionUs; } - private void updatePeriods() throws ExoPlaybackException, IOException { + private void updatePeriods() throws ExoPlaybackException { if (playbackInfo.timeline.isEmpty() || !mediaSourceList.isPrepared()) { // No periods available. return; @@ -2012,7 +2024,7 @@ private void maybeUpdateLoadingPeriod() throws ExoPlaybackException { } } - private void maybeUpdateReadingPeriod() { + private void maybeUpdateReadingPeriod() throws ExoPlaybackException { @Nullable MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod(); if (readingPeriodHolder == null) { return; diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index fb2ae47b596..d258b7123a2 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -89,6 +89,7 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Looper; +import android.util.Pair; import android.view.Surface; import androidx.annotation.Nullable; import androidx.media3.common.AdPlaybackState; @@ -129,13 +130,13 @@ import androidx.media3.exoplayer.source.TrackGroupArray; import androidx.media3.exoplayer.source.WrappingMediaSource; import androidx.media3.exoplayer.source.ads.ServerSideAdInsertionMediaSource; +import androidx.media3.exoplayer.text.TextOutput; import androidx.media3.exoplayer.trackselection.DefaultTrackSelector; import androidx.media3.exoplayer.upstream.Allocation; import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.Loader; import androidx.media3.extractor.metadata.id3.BinaryFrame; import androidx.media3.extractor.metadata.id3.TextInformationFrame; -import androidx.media3.test.utils.Action; import androidx.media3.test.utils.ActionSchedule; import androidx.media3.test.utils.ActionSchedule.PlayerRunnable; import androidx.media3.test.utils.ActionSchedule.PlayerTarget; @@ -3843,41 +3844,29 @@ public void adInMovingLiveWindow_keepsContentPosition() throws Exception { @Test public void setPlaybackSpeedConsecutivelyNotifiesListenerForEveryChangeOnceAndIsMasked() throws Exception { + ExoPlayer player = new TestExoPlayerBuilder(context).build(); List maskedPlaybackSpeeds = new ArrayList<>(); - Action getPlaybackSpeedAction = - new Action("getPlaybackSpeed", /* description= */ null) { - @Override - protected void doActionImpl( - ExoPlayer player, DefaultTrackSelector trackSelector, @Nullable Surface surface) { - maskedPlaybackSpeeds.add(player.getPlaybackParameters().speed); - } - }; - ActionSchedule actionSchedule = - new ActionSchedule.Builder(TAG) - .pause() - .waitForPlaybackState(Player.STATE_READY) - .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.1f)) - .apply(getPlaybackSpeedAction) - .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.2f)) - .apply(getPlaybackSpeedAction) - .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.3f)) - .apply(getPlaybackSpeedAction) - .play() - .build(); List reportedPlaybackSpeeds = new ArrayList<>(); - Player.Listener listener = + player.addListener( new Player.Listener() { @Override public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { reportedPlaybackSpeeds.add(playbackParameters.speed); } - }; - new ExoPlayerTestRunner.Builder(context) - .setActionSchedule(actionSchedule) - .setPlayerListener(listener) - .build() - .start() - .blockUntilEnded(TIMEOUT_MS); + }); + player.setMediaSource( + new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.AUDIO_FORMAT)); + player.prepare(); + runUntilPlaybackState(player, Player.STATE_READY); + + player.setPlaybackSpeed(1.1f); + maskedPlaybackSpeeds.add(player.getPlaybackParameters().speed); + player.setPlaybackSpeed(1.2f); + maskedPlaybackSpeeds.add(player.getPlaybackParameters().speed); + player.setPlaybackSpeed(1.3f); + maskedPlaybackSpeeds.add(player.getPlaybackParameters().speed); + runUntilPendingCommandsAreFullyHandled(player); + player.release(); assertThat(reportedPlaybackSpeeds).containsExactly(1.1f, 1.2f, 1.3f).inOrder(); assertThat(maskedPlaybackSpeeds).isEqualTo(reportedPlaybackSpeeds); @@ -3887,46 +3876,28 @@ public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { public void setUnsupportedPlaybackSpeedConsecutivelyNotifiesListenerForEveryChangeOnceAndResetsOnceHandled() throws Exception { - Renderer renderer = - new FakeMediaClockRenderer(C.TRACK_TYPE_AUDIO) { - @Override - public long getPositionUs() { - return 0; - } - - @Override - public void setPlaybackParameters(PlaybackParameters playbackParameters) {} - - @Override - public PlaybackParameters getPlaybackParameters() { - return PlaybackParameters.DEFAULT; - } - }; - ActionSchedule actionSchedule = - new ActionSchedule.Builder(TAG) - .pause() - .waitForPlaybackState(Player.STATE_READY) - .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.1f)) - .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.2f)) - .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.3f)) - .play() + ExoPlayer player = + new TestExoPlayerBuilder(context) + .setRenderers(new AudioClockRendererWithoutSpeedChangeSupport()) .build(); List reportedPlaybackParameters = new ArrayList<>(); - Player.Listener listener = + player.addListener( new Player.Listener() { @Override public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { reportedPlaybackParameters.add(playbackParameters); } - }; - new ExoPlayerTestRunner.Builder(context) - .setSupportedFormats(ExoPlayerTestRunner.AUDIO_FORMAT) - .setRenderers(renderer) - .setActionSchedule(actionSchedule) - .setPlayerListener(listener) - .build() - .start() - .blockUntilEnded(TIMEOUT_MS); + }); + player.setMediaSource( + new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.AUDIO_FORMAT)); + player.prepare(); + runUntilPlaybackState(player, Player.STATE_READY); + + player.setPlaybackSpeed(1.1f); + player.setPlaybackSpeed(1.2f); + player.setPlaybackSpeed(1.3f); + runUntilPendingCommandsAreFullyHandled(player); + player.release(); assertThat(reportedPlaybackParameters) .containsExactly( @@ -3937,6 +3908,51 @@ public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { .inOrder(); } + @Test + public void + setUnsupportedPlaybackSpeedDirectlyFollowedByDisablingTheRendererAndSupportedPlaybackSpeed_keepsCorrectFinalSpeedAndInformsListenersCorrectly() + throws Exception { + ExoPlayer player = + new TestExoPlayerBuilder(context) + .setRenderers(new AudioClockRendererWithoutSpeedChangeSupport()) + .build(); + List reportedPlaybackParameters = new ArrayList<>(); + player.addListener( + new Player.Listener() { + @Override + public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { + reportedPlaybackParameters.add(playbackParameters); + } + }); + player.setMediaSource( + new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.AUDIO_FORMAT)); + player.prepare(); + runUntilPlaybackState(player, Player.STATE_READY); + + player.setPlaybackSpeed(2f); + // We need to do something that reliably triggers a position sync with the renderer, but no + // further playback progress as we want to test what happens if the parameter reset is still + // pending when we disable the audio renderer below. Calling play and pause will achieve this. + player.play(); + player.pause(); + // Disabling the audio renderer and setting a new speed should work, and should not be affected + // by the still pending parameter reset from above. + player.setTrackSelectionParameters( + player + .getTrackSelectionParameters() + .buildUpon() + .setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, /* disabled= */ true) + .build()); + player.setPlaybackSpeed(5f); + runUntilPendingCommandsAreFullyHandled(player); + player.release(); + + assertThat(reportedPlaybackParameters) + .containsExactly( + new PlaybackParameters(/* speed= */ 2f), new PlaybackParameters(/* speed= */ 5f)) + .inOrder(); + } + @Test public void simplePlaybackHasNoPlaybackSuppression() throws Exception { ActionSchedule actionSchedule = @@ -10071,8 +10087,10 @@ public void playerIdle_withSetPlaybackSpeed_usesPlaybackParameterSpeedWithPitchU @Test public void setPlaybackSpeed_withAdPlayback_onlyAppliesToContent() throws Exception { - // Create renderer with media clock to listen to playback parameter changes. + // Create renderer with media clock to listen to playback parameter changes and reported speed + // changes. ArrayList playbackParameters = new ArrayList<>(); + ArrayList> speedChanges = new ArrayList<>(); FakeMediaClockRenderer audioRenderer = new FakeMediaClockRenderer(C.TRACK_TYPE_AUDIO) { private long positionUs; @@ -10100,6 +10118,12 @@ public PlaybackParameters getPlaybackParameters() { ? PlaybackParameters.DEFAULT : Iterables.getLast(playbackParameters); } + + @Override + public void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpeed) + throws ExoPlaybackException { + speedChanges.add(Pair.create(currentPlaybackSpeed, targetPlaybackSpeed)); + } }; ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(audioRenderer).build(); AdPlaybackState adPlaybackState = @@ -10132,7 +10156,7 @@ public PlaybackParameters getPlaybackParameters() { runUntilPlaybackState(player, Player.STATE_ENDED); player.release(); - // Assert that the renderer received the playback speed updates at each ad/content boundary. + // Assert that the media clock received the playback parameters at each ad/content boundary. assertThat(playbackParameters) .containsExactly( /* preroll ad */ new PlaybackParameters(1f), @@ -10143,6 +10167,18 @@ public PlaybackParameters getPlaybackParameters() { /* content after postroll */ new PlaybackParameters(5f)) .inOrder(); + // Assert that the renderer received the speed changes at each ad/content boundary. + assertThat(speedChanges) + .containsExactly( + /* initial setup */ Pair.create(5f, 5f), + /* preroll ad */ Pair.create(1f, 5f), + /* content after preroll */ Pair.create(5f, 5f), + /* midroll ad */ Pair.create(1f, 5f), + /* content after midroll */ Pair.create(5f, 5f), + /* postroll ad */ Pair.create(1f, 5f), + /* content after postroll */ Pair.create(5f, 5f)) + .inOrder(); + // Assert that user-set speed was reported, but none of the ad overrides. verify(mockListener).onPlaybackParametersChanged(any()); verify(mockListener).onPlaybackParametersChanged(new PlaybackParameters(5.0f)); @@ -12436,6 +12472,46 @@ public Loader.LoadErrorAction onLoadError( } } + private static final class AudioClockRendererWithoutSpeedChangeSupport + extends FakeMediaClockRenderer { + + private PlaybackParameters playbackParameters; + private boolean delayingPlaybackParameterReset; + private long positionUs; + + public AudioClockRendererWithoutSpeedChangeSupport() { + super(C.TRACK_TYPE_AUDIO); + playbackParameters = PlaybackParameters.DEFAULT; + } + + @Override + protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { + super.onPositionReset(positionUs, joining); + this.positionUs = positionUs; + } + + @Override + public long getPositionUs() { + return positionUs; + } + + @Override + public void setPlaybackParameters(PlaybackParameters playbackParameters) { + this.playbackParameters = playbackParameters; + // Similar to a real renderer, the missing speed support is only detected with a delay. + delayingPlaybackParameterReset = true; + } + + @Override + public PlaybackParameters getPlaybackParameters() { + if (delayingPlaybackParameterReset) { + delayingPlaybackParameterReset = false; + return playbackParameters; + } + return PlaybackParameters.DEFAULT; + } + } + /** * Returns an argument matcher for {@link Timeline} instances that ignores period and window uids. */ From b44fb574b553c4878dc7a32c1fa3cbd2800c3f76 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 28 Feb 2023 11:15:05 +0000 Subject: [PATCH 23/33] Ensure getPlaybackHeadPosition isn't called if not needed Once the value returned from AudioTimestampPoller advances, we only need getPlaybackHeadPosition to sample sync params and verify the returned timestamp. Both of these happen less often and we can avoid calling getPlaybackHeadPosition if we don't actually need it. PiperOrigin-RevId: 512882170 (cherry picked from commit 408b4449ff75e29a9bda7adc1b530b993fc47814) --- .../audio/AudioTrackPositionTracker.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java index 98b6202060e..414cf24d403 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java @@ -451,13 +451,13 @@ public void reset() { } private void maybeSampleSyncParams() { - long playbackPositionUs = getPlaybackHeadPositionUs(); - if (playbackPositionUs == 0) { - // The AudioTrack hasn't output anything yet. - return; - } long systemTimeUs = System.nanoTime() / 1000; if (systemTimeUs - lastPlayheadSampleTimeUs >= MIN_PLAYHEAD_OFFSET_SAMPLE_INTERVAL_US) { + long playbackPositionUs = getPlaybackHeadPositionUs(); + if (playbackPositionUs == 0) { + // The AudioTrack hasn't output anything yet. + return; + } // Take a new sample and update the smoothed offset between the system clock and the playhead. playheadOffsets[nextPlayheadOffsetIndex] = Util.getPlayoutDurationForMediaDuration(playbackPositionUs, audioTrackPlaybackSpeed) @@ -479,11 +479,11 @@ private void maybeSampleSyncParams() { return; } - maybePollAndCheckTimestamp(systemTimeUs, playbackPositionUs); + maybePollAndCheckTimestamp(systemTimeUs); maybeUpdateLatency(systemTimeUs); } - private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) { + private void maybePollAndCheckTimestamp(long systemTimeUs) { AudioTimestampPoller audioTimestampPoller = checkNotNull(this.audioTimestampPoller); if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) { return; @@ -492,6 +492,7 @@ private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPosition // Check the timestamp and accept/reject it. long audioTimestampSystemTimeUs = audioTimestampPoller.getTimestampSystemTimeUs(); long audioTimestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames(); + long playbackPositionUs = getPlaybackHeadPositionUs(); if (Math.abs(audioTimestampSystemTimeUs - systemTimeUs) > MAX_AUDIO_TIMESTAMP_OFFSET_US) { listener.onSystemTimeUsMismatch( audioTimestampPositionFrames, From ee4ac61640a7a4609cf60477df19dd1b81d5f9d1 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 28 Feb 2023 12:08:27 +0000 Subject: [PATCH 24/33] Update translations #minor-release PiperOrigin-RevId: 512890813 (cherry picked from commit a7faa5bfd8c82e22c7d99378cf78f31a57274db2) --- .../src/main/res/values-af/strings.xml | 14 ------ .../src/main/res/values-am/strings.xml | 14 ------ .../src/main/res/values-ar/strings.xml | 14 ------ .../src/main/res/values-az/strings.xml | 14 ------ .../src/main/res/values-b+sr+Latn/strings.xml | 14 ------ .../src/main/res/values-be/strings.xml | 14 ------ .../src/main/res/values-bg/strings.xml | 14 ------ .../src/main/res/values-bn/strings.xml | 14 ------ .../src/main/res/values-bs/strings.xml | 14 ------ .../src/main/res/values-ca/strings.xml | 14 ------ .../src/main/res/values-cs/strings.xml | 14 ------ .../src/main/res/values-da/strings.xml | 14 ------ .../src/main/res/values-de/strings.xml | 14 ------ .../src/main/res/values-el/strings.xml | 14 ------ .../src/main/res/values-en-rAU/strings.xml | 14 ------ .../src/main/res/values-en-rGB/strings.xml | 14 ------ .../src/main/res/values-en-rIN/strings.xml | 14 ------ .../src/main/res/values-es-rUS/strings.xml | 14 ------ .../src/main/res/values-es/strings.xml | 14 ------ .../src/main/res/values-et/strings.xml | 14 ------ .../src/main/res/values-eu/strings.xml | 14 ------ .../src/main/res/values-fa/strings.xml | 14 ------ .../src/main/res/values-fi/strings.xml | 14 ------ .../src/main/res/values-fr-rCA/strings.xml | 14 ------ .../src/main/res/values-fr/strings.xml | 14 ------ .../src/main/res/values-gl/strings.xml | 14 ------ .../src/main/res/values-gu/strings.xml | 14 ------ .../src/main/res/values-hi/strings.xml | 14 ------ .../src/main/res/values-hr/strings.xml | 14 ------ .../src/main/res/values-hu/strings.xml | 14 ------ .../src/main/res/values-hy/strings.xml | 14 ------ .../src/main/res/values-in/strings.xml | 14 ------ .../src/main/res/values-is/strings.xml | 14 ------ .../src/main/res/values-it/strings.xml | 14 ------ .../src/main/res/values-iw/strings.xml | 14 ------ .../src/main/res/values-ja/strings.xml | 14 ------ .../src/main/res/values-ka/strings.xml | 14 ------ .../src/main/res/values-kk/strings.xml | 14 ------ .../src/main/res/values-km/strings.xml | 14 ------ .../src/main/res/values-kn/strings.xml | 14 ------ .../src/main/res/values-ko/strings.xml | 14 ------ .../src/main/res/values-ky/strings.xml | 14 ------ .../src/main/res/values-lo/strings.xml | 14 ------ .../src/main/res/values-lt/strings.xml | 14 ------ .../src/main/res/values-lv/strings.xml | 14 ------ .../src/main/res/values-mk/strings.xml | 14 ------ .../src/main/res/values-ml/strings.xml | 14 ------ .../src/main/res/values-mn/strings.xml | 14 ------ .../src/main/res/values-mr/strings.xml | 14 ------ .../src/main/res/values-ms/strings.xml | 14 ------ .../src/main/res/values-my/strings.xml | 14 ------ .../src/main/res/values-nb/strings.xml | 14 ------ .../src/main/res/values-ne/strings.xml | 14 ------ .../src/main/res/values-nl/strings.xml | 14 ------ .../src/main/res/values-pa/strings.xml | 14 ------ .../src/main/res/values-pl/strings.xml | 14 ------ .../src/main/res/values-pt-rPT/strings.xml | 14 ------ .../src/main/res/values-pt/strings.xml | 14 ------ .../src/main/res/values-ro/strings.xml | 16 +------ .../src/main/res/values-ru/strings.xml | 14 ------ .../src/main/res/values-si/strings.xml | 14 ------ .../src/main/res/values-sk/strings.xml | 14 ------ .../src/main/res/values-sl/strings.xml | 14 ------ .../src/main/res/values-sq/strings.xml | 14 ------ .../src/main/res/values-sr/strings.xml | 14 ------ .../src/main/res/values-sv/strings.xml | 14 ------ .../src/main/res/values-sw/strings.xml | 14 ------ .../src/main/res/values-ta/strings.xml | 14 ------ .../src/main/res/values-te/strings.xml | 14 ------ .../src/main/res/values-th/strings.xml | 14 ------ .../src/main/res/values-tl/strings.xml | 14 ------ .../src/main/res/values-tr/strings.xml | 14 ------ .../src/main/res/values-uk/strings.xml | 14 ------ .../src/main/res/values-ur/strings.xml | 14 ------ .../src/main/res/values-uz/strings.xml | 14 ------ .../src/main/res/values-vi/strings.xml | 14 ------ .../src/main/res/values-zh-rCN/strings.xml | 14 ------ .../src/main/res/values-zh-rHK/strings.xml | 14 ------ .../src/main/res/values-zh-rTW/strings.xml | 14 ------ .../src/main/res/values-zu/strings.xml | 14 ------ .../src/main/res/values-af/strings.xml | 14 ------ .../src/main/res/values-am/strings.xml | 14 ------ .../src/main/res/values-ar/strings.xml | 16 +------ .../src/main/res/values-az/strings.xml | 14 ------ .../src/main/res/values-b+sr+Latn/strings.xml | 14 ------ .../src/main/res/values-be/strings.xml | 14 ------ .../src/main/res/values-bg/strings.xml | 14 ------ .../src/main/res/values-bn/strings.xml | 14 ------ .../src/main/res/values-bs/strings.xml | 14 ------ .../src/main/res/values-ca/strings.xml | 14 ------ .../src/main/res/values-cs/strings.xml | 14 ------ .../src/main/res/values-da/strings.xml | 14 ------ .../src/main/res/values-de/strings.xml | 14 ------ .../src/main/res/values-el/strings.xml | 14 ------ .../src/main/res/values-en-rAU/strings.xml | 14 ------ .../src/main/res/values-en-rGB/strings.xml | 14 ------ .../src/main/res/values-en-rIN/strings.xml | 14 ------ .../src/main/res/values-es-rUS/strings.xml | 14 ------ .../src/main/res/values-es/strings.xml | 14 ------ .../src/main/res/values-et/strings.xml | 14 ------ .../src/main/res/values-eu/strings.xml | 14 ------ .../src/main/res/values-fa/strings.xml | 14 ------ .../src/main/res/values-fi/strings.xml | 14 ------ .../src/main/res/values-fr-rCA/strings.xml | 14 ------ .../src/main/res/values-fr/strings.xml | 14 ------ .../src/main/res/values-gl/strings.xml | 14 ------ .../src/main/res/values-gu/strings.xml | 14 ------ .../src/main/res/values-hi/strings.xml | 14 ------ .../src/main/res/values-hr/strings.xml | 14 ------ .../src/main/res/values-hu/strings.xml | 14 ------ .../src/main/res/values-hy/strings.xml | 14 ------ .../src/main/res/values-in/strings.xml | 14 ------ .../src/main/res/values-is/strings.xml | 14 ------ .../src/main/res/values-it/strings.xml | 14 ------ .../src/main/res/values-iw/strings.xml | 14 ------ .../src/main/res/values-ja/strings.xml | 14 ------ .../src/main/res/values-ka/strings.xml | 14 ------ .../src/main/res/values-kk/strings.xml | 18 +------- .../src/main/res/values-km/strings.xml | 14 ------ .../src/main/res/values-kn/strings.xml | 14 ------ .../src/main/res/values-ko/strings.xml | 14 ------ .../src/main/res/values-ky/strings.xml | 14 ------ .../src/main/res/values-lo/strings.xml | 14 ------ .../src/main/res/values-lt/strings.xml | 14 ------ .../src/main/res/values-lv/strings.xml | 14 ------ .../src/main/res/values-mk/strings.xml | 14 ------ .../src/main/res/values-ml/strings.xml | 14 ------ .../src/main/res/values-mn/strings.xml | 14 ------ .../src/main/res/values-mr/strings.xml | 14 ------ .../src/main/res/values-ms/strings.xml | 14 ------ .../src/main/res/values-my/strings.xml | 14 ------ .../src/main/res/values-nb/strings.xml | 14 ------ .../src/main/res/values-ne/strings.xml | 14 ------ .../src/main/res/values-nl/strings.xml | 14 ------ .../src/main/res/values-pa/strings.xml | 14 ------ .../src/main/res/values-pl/strings.xml | 14 ------ .../src/main/res/values-pt-rPT/strings.xml | 14 ------ .../src/main/res/values-pt/strings.xml | 14 ------ .../src/main/res/values-ro/strings.xml | 14 ------ .../src/main/res/values-ru/strings.xml | 14 ------ .../src/main/res/values-si/strings.xml | 14 ------ .../src/main/res/values-sk/strings.xml | 14 ------ .../src/main/res/values-sl/strings.xml | 14 ------ .../src/main/res/values-sq/strings.xml | 14 ------ .../src/main/res/values-sr/strings.xml | 14 ------ .../src/main/res/values-sv/strings.xml | 14 ------ .../src/main/res/values-sw/strings.xml | 14 ------ .../src/main/res/values-ta/strings.xml | 14 ------ .../src/main/res/values-te/strings.xml | 14 ------ .../src/main/res/values-th/strings.xml | 14 ------ .../src/main/res/values-tl/strings.xml | 14 ------ .../src/main/res/values-tr/strings.xml | 14 ------ .../src/main/res/values-uk/strings.xml | 14 ------ .../src/main/res/values-ur/strings.xml | 14 ------ .../src/main/res/values-uz/strings.xml | 14 ------ .../src/main/res/values-vi/strings.xml | 14 ------ .../src/main/res/values-zh-rCN/strings.xml | 14 ------ .../src/main/res/values-zh-rHK/strings.xml | 14 ------ .../src/main/res/values-zh-rTW/strings.xml | 14 ------ .../src/main/res/values-zu/strings.xml | 14 ------ .../ui/src/main/res/values-af/strings.xml | 14 ------ .../ui/src/main/res/values-am/strings.xml | 16 +------ .../ui/src/main/res/values-ar/strings.xml | 14 ------ .../ui/src/main/res/values-az/strings.xml | 14 ------ .../src/main/res/values-b+sr+Latn/strings.xml | 14 ------ .../ui/src/main/res/values-be/strings.xml | 14 ------ .../ui/src/main/res/values-bg/strings.xml | 14 ------ .../ui/src/main/res/values-bn/strings.xml | 14 ------ .../ui/src/main/res/values-bs/strings.xml | 14 ------ .../ui/src/main/res/values-ca/strings.xml | 14 ------ .../ui/src/main/res/values-cs/strings.xml | 14 ------ .../ui/src/main/res/values-da/strings.xml | 14 ------ .../ui/src/main/res/values-de/strings.xml | 14 ------ .../ui/src/main/res/values-el/strings.xml | 14 ------ .../ui/src/main/res/values-en-rAU/strings.xml | 14 ------ .../ui/src/main/res/values-en-rGB/strings.xml | 14 ------ .../ui/src/main/res/values-en-rIN/strings.xml | 14 ------ .../ui/src/main/res/values-es-rUS/strings.xml | 14 ------ .../ui/src/main/res/values-es/strings.xml | 26 +++-------- .../ui/src/main/res/values-et/strings.xml | 14 ------ .../ui/src/main/res/values-eu/strings.xml | 14 ------ .../ui/src/main/res/values-fa/strings.xml | 14 ------ .../ui/src/main/res/values-fi/strings.xml | 14 ------ .../ui/src/main/res/values-fr-rCA/strings.xml | 14 ------ .../ui/src/main/res/values-fr/strings.xml | 14 ------ .../ui/src/main/res/values-gl/strings.xml | 16 +------ .../ui/src/main/res/values-gu/strings.xml | 14 ------ .../ui/src/main/res/values-hi/strings.xml | 14 ------ .../ui/src/main/res/values-hr/strings.xml | 14 ------ .../ui/src/main/res/values-hu/strings.xml | 14 ------ .../ui/src/main/res/values-hy/strings.xml | 14 ------ .../ui/src/main/res/values-in/strings.xml | 14 ------ .../ui/src/main/res/values-is/strings.xml | 14 ------ .../ui/src/main/res/values-it/strings.xml | 14 ------ .../ui/src/main/res/values-iw/strings.xml | 34 +------------- .../ui/src/main/res/values-ja/strings.xml | 14 ------ .../ui/src/main/res/values-ka/strings.xml | 14 ------ .../ui/src/main/res/values-kk/strings.xml | 20 ++------ .../ui/src/main/res/values-km/strings.xml | 14 ------ .../ui/src/main/res/values-kn/strings.xml | 14 ------ .../ui/src/main/res/values-ko/strings.xml | 14 ------ .../ui/src/main/res/values-ky/strings.xml | 16 +------ .../ui/src/main/res/values-lo/strings.xml | 14 ------ .../ui/src/main/res/values-lt/strings.xml | 14 ------ .../ui/src/main/res/values-lv/strings.xml | 14 ------ .../ui/src/main/res/values-mk/strings.xml | 14 ------ .../ui/src/main/res/values-ml/strings.xml | 16 +------ .../ui/src/main/res/values-mn/strings.xml | 14 ------ .../ui/src/main/res/values-mr/strings.xml | 14 ------ .../ui/src/main/res/values-ms/strings.xml | 14 ------ .../ui/src/main/res/values-my/strings.xml | 14 ------ .../ui/src/main/res/values-nb/strings.xml | 14 ------ .../ui/src/main/res/values-ne/strings.xml | 14 ------ .../ui/src/main/res/values-nl/strings.xml | 14 ------ .../ui/src/main/res/values-pa/strings.xml | 14 ------ .../ui/src/main/res/values-pl/strings.xml | 14 ------ .../ui/src/main/res/values-pt-rPT/strings.xml | 14 ------ .../ui/src/main/res/values-pt/strings.xml | 14 ------ .../ui/src/main/res/values-ro/strings.xml | 46 +++++++------------ .../ui/src/main/res/values-ru/strings.xml | 14 ------ .../ui/src/main/res/values-si/strings.xml | 14 ------ .../ui/src/main/res/values-sk/strings.xml | 14 ------ .../ui/src/main/res/values-sl/strings.xml | 14 ------ .../ui/src/main/res/values-sq/strings.xml | 14 ------ .../ui/src/main/res/values-sr/strings.xml | 14 ------ .../ui/src/main/res/values-sv/strings.xml | 14 ------ .../ui/src/main/res/values-sw/strings.xml | 14 ------ .../ui/src/main/res/values-ta/strings.xml | 14 ------ .../ui/src/main/res/values-te/strings.xml | 24 ++-------- .../ui/src/main/res/values-th/strings.xml | 14 ------ .../ui/src/main/res/values-tl/strings.xml | 14 ------ .../ui/src/main/res/values-tr/strings.xml | 14 ------ .../ui/src/main/res/values-uk/strings.xml | 14 ------ .../ui/src/main/res/values-ur/strings.xml | 14 ------ .../ui/src/main/res/values-uz/strings.xml | 14 ------ .../ui/src/main/res/values-vi/strings.xml | 14 ------ .../ui/src/main/res/values-zh-rCN/strings.xml | 14 ------ .../ui/src/main/res/values-zh-rHK/strings.xml | 14 ------ .../ui/src/main/res/values-zh-rTW/strings.xml | 14 ------ .../ui/src/main/res/values-zu/strings.xml | 14 ------ 240 files changed, 40 insertions(+), 3416 deletions(-) diff --git a/libraries/exoplayer/src/main/res/values-af/strings.xml b/libraries/exoplayer/src/main/res/values-af/strings.xml index c1a57f9246c..b935a4cf89b 100644 --- a/libraries/exoplayer/src/main/res/values-af/strings.xml +++ b/libraries/exoplayer/src/main/res/values-af/strings.xml @@ -1,18 +1,4 @@ - Aflaai Aflaaie diff --git a/libraries/exoplayer/src/main/res/values-am/strings.xml b/libraries/exoplayer/src/main/res/values-am/strings.xml index a16ac064b34..93a8ae066bc 100644 --- a/libraries/exoplayer/src/main/res/values-am/strings.xml +++ b/libraries/exoplayer/src/main/res/values-am/strings.xml @@ -1,18 +1,4 @@ - አውርድ የወረዱ diff --git a/libraries/exoplayer/src/main/res/values-ar/strings.xml b/libraries/exoplayer/src/main/res/values-ar/strings.xml index 6b03d0fdd64..14db1306223 100644 --- a/libraries/exoplayer/src/main/res/values-ar/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ar/strings.xml @@ -1,18 +1,4 @@ - تنزيل عمليات التنزيل diff --git a/libraries/exoplayer/src/main/res/values-az/strings.xml b/libraries/exoplayer/src/main/res/values-az/strings.xml index 1193607b284..28e9dcb0103 100644 --- a/libraries/exoplayer/src/main/res/values-az/strings.xml +++ b/libraries/exoplayer/src/main/res/values-az/strings.xml @@ -1,18 +1,4 @@ - Endirin Endirmələr diff --git a/libraries/exoplayer/src/main/res/values-b+sr+Latn/strings.xml b/libraries/exoplayer/src/main/res/values-b+sr+Latn/strings.xml index 49d5ff23c4c..c8e8eeb7868 100644 --- a/libraries/exoplayer/src/main/res/values-b+sr+Latn/strings.xml +++ b/libraries/exoplayer/src/main/res/values-b+sr+Latn/strings.xml @@ -1,18 +1,4 @@ - Preuzmi Preuzimanja diff --git a/libraries/exoplayer/src/main/res/values-be/strings.xml b/libraries/exoplayer/src/main/res/values-be/strings.xml index 54b219e042d..1539008d72f 100644 --- a/libraries/exoplayer/src/main/res/values-be/strings.xml +++ b/libraries/exoplayer/src/main/res/values-be/strings.xml @@ -1,18 +1,4 @@ - Спампаваць Спампоўкі diff --git a/libraries/exoplayer/src/main/res/values-bg/strings.xml b/libraries/exoplayer/src/main/res/values-bg/strings.xml index 420fa00b979..af37d820785 100644 --- a/libraries/exoplayer/src/main/res/values-bg/strings.xml +++ b/libraries/exoplayer/src/main/res/values-bg/strings.xml @@ -1,18 +1,4 @@ - Изтегляне Изтегляния diff --git a/libraries/exoplayer/src/main/res/values-bn/strings.xml b/libraries/exoplayer/src/main/res/values-bn/strings.xml index c4a6c3686e7..be8ed9cdaab 100644 --- a/libraries/exoplayer/src/main/res/values-bn/strings.xml +++ b/libraries/exoplayer/src/main/res/values-bn/strings.xml @@ -1,18 +1,4 @@ - ডাউনলোড করুন ডাউনলোড diff --git a/libraries/exoplayer/src/main/res/values-bs/strings.xml b/libraries/exoplayer/src/main/res/values-bs/strings.xml index 5ca81f27803..5fe387cefb6 100644 --- a/libraries/exoplayer/src/main/res/values-bs/strings.xml +++ b/libraries/exoplayer/src/main/res/values-bs/strings.xml @@ -1,18 +1,4 @@ - Preuzmi Preuzimanja diff --git a/libraries/exoplayer/src/main/res/values-ca/strings.xml b/libraries/exoplayer/src/main/res/values-ca/strings.xml index 6c80546d7b9..ecb381f5349 100644 --- a/libraries/exoplayer/src/main/res/values-ca/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ca/strings.xml @@ -1,18 +1,4 @@ - Baixa Baixades diff --git a/libraries/exoplayer/src/main/res/values-cs/strings.xml b/libraries/exoplayer/src/main/res/values-cs/strings.xml index f916f076e32..54a112a9ee9 100644 --- a/libraries/exoplayer/src/main/res/values-cs/strings.xml +++ b/libraries/exoplayer/src/main/res/values-cs/strings.xml @@ -1,18 +1,4 @@ - Stáhnout Stahování diff --git a/libraries/exoplayer/src/main/res/values-da/strings.xml b/libraries/exoplayer/src/main/res/values-da/strings.xml index dca960dbd42..1b15b1f605b 100644 --- a/libraries/exoplayer/src/main/res/values-da/strings.xml +++ b/libraries/exoplayer/src/main/res/values-da/strings.xml @@ -1,18 +1,4 @@ - Download Downloads diff --git a/libraries/exoplayer/src/main/res/values-de/strings.xml b/libraries/exoplayer/src/main/res/values-de/strings.xml index 92904131e1c..848bfb2d4d6 100644 --- a/libraries/exoplayer/src/main/res/values-de/strings.xml +++ b/libraries/exoplayer/src/main/res/values-de/strings.xml @@ -1,18 +1,4 @@ - Herunterladen Downloads diff --git a/libraries/exoplayer/src/main/res/values-el/strings.xml b/libraries/exoplayer/src/main/res/values-el/strings.xml index e079173d120..8ef5c20f72d 100644 --- a/libraries/exoplayer/src/main/res/values-el/strings.xml +++ b/libraries/exoplayer/src/main/res/values-el/strings.xml @@ -1,18 +1,4 @@ - Λήψη Λήψεις diff --git a/libraries/exoplayer/src/main/res/values-en-rAU/strings.xml b/libraries/exoplayer/src/main/res/values-en-rAU/strings.xml index 27fb6389f8b..639a151801e 100644 --- a/libraries/exoplayer/src/main/res/values-en-rAU/strings.xml +++ b/libraries/exoplayer/src/main/res/values-en-rAU/strings.xml @@ -1,18 +1,4 @@ - Download Downloads diff --git a/libraries/exoplayer/src/main/res/values-en-rGB/strings.xml b/libraries/exoplayer/src/main/res/values-en-rGB/strings.xml index 27fb6389f8b..639a151801e 100644 --- a/libraries/exoplayer/src/main/res/values-en-rGB/strings.xml +++ b/libraries/exoplayer/src/main/res/values-en-rGB/strings.xml @@ -1,18 +1,4 @@ - Download Downloads diff --git a/libraries/exoplayer/src/main/res/values-en-rIN/strings.xml b/libraries/exoplayer/src/main/res/values-en-rIN/strings.xml index 27fb6389f8b..639a151801e 100644 --- a/libraries/exoplayer/src/main/res/values-en-rIN/strings.xml +++ b/libraries/exoplayer/src/main/res/values-en-rIN/strings.xml @@ -1,18 +1,4 @@ - Download Downloads diff --git a/libraries/exoplayer/src/main/res/values-es-rUS/strings.xml b/libraries/exoplayer/src/main/res/values-es-rUS/strings.xml index 45b331f4771..545c55ac86d 100644 --- a/libraries/exoplayer/src/main/res/values-es-rUS/strings.xml +++ b/libraries/exoplayer/src/main/res/values-es-rUS/strings.xml @@ -1,18 +1,4 @@ - Descargar Descargas diff --git a/libraries/exoplayer/src/main/res/values-es/strings.xml b/libraries/exoplayer/src/main/res/values-es/strings.xml index 6d13c5fd219..a7a8edeaba1 100644 --- a/libraries/exoplayer/src/main/res/values-es/strings.xml +++ b/libraries/exoplayer/src/main/res/values-es/strings.xml @@ -1,18 +1,4 @@ - Descargar Descargas diff --git a/libraries/exoplayer/src/main/res/values-et/strings.xml b/libraries/exoplayer/src/main/res/values-et/strings.xml index 67df50e2675..5ac51b75cbf 100644 --- a/libraries/exoplayer/src/main/res/values-et/strings.xml +++ b/libraries/exoplayer/src/main/res/values-et/strings.xml @@ -1,18 +1,4 @@ - Allalaadimine Allalaadimised diff --git a/libraries/exoplayer/src/main/res/values-eu/strings.xml b/libraries/exoplayer/src/main/res/values-eu/strings.xml index e2e0ca7b9e8..d476d29b7bc 100644 --- a/libraries/exoplayer/src/main/res/values-eu/strings.xml +++ b/libraries/exoplayer/src/main/res/values-eu/strings.xml @@ -1,18 +1,4 @@ - Deskargak Deskargak diff --git a/libraries/exoplayer/src/main/res/values-fa/strings.xml b/libraries/exoplayer/src/main/res/values-fa/strings.xml index ad7b14e934a..271919fbc1b 100644 --- a/libraries/exoplayer/src/main/res/values-fa/strings.xml +++ b/libraries/exoplayer/src/main/res/values-fa/strings.xml @@ -1,18 +1,4 @@ - بارگیری بارگیری‌ها diff --git a/libraries/exoplayer/src/main/res/values-fi/strings.xml b/libraries/exoplayer/src/main/res/values-fi/strings.xml index 6fbdf45fac4..15f1a38628c 100644 --- a/libraries/exoplayer/src/main/res/values-fi/strings.xml +++ b/libraries/exoplayer/src/main/res/values-fi/strings.xml @@ -1,18 +1,4 @@ - Lataa Lataukset diff --git a/libraries/exoplayer/src/main/res/values-fr-rCA/strings.xml b/libraries/exoplayer/src/main/res/values-fr-rCA/strings.xml index 9610fd2e14f..e177a5d7534 100644 --- a/libraries/exoplayer/src/main/res/values-fr-rCA/strings.xml +++ b/libraries/exoplayer/src/main/res/values-fr-rCA/strings.xml @@ -1,18 +1,4 @@ - Télécharger Téléchargements diff --git a/libraries/exoplayer/src/main/res/values-fr/strings.xml b/libraries/exoplayer/src/main/res/values-fr/strings.xml index 22f02999768..274278bf4ad 100644 --- a/libraries/exoplayer/src/main/res/values-fr/strings.xml +++ b/libraries/exoplayer/src/main/res/values-fr/strings.xml @@ -1,18 +1,4 @@ - Télécharger Téléchargements diff --git a/libraries/exoplayer/src/main/res/values-gl/strings.xml b/libraries/exoplayer/src/main/res/values-gl/strings.xml index 6764ddb4d3b..46f80721b57 100644 --- a/libraries/exoplayer/src/main/res/values-gl/strings.xml +++ b/libraries/exoplayer/src/main/res/values-gl/strings.xml @@ -1,18 +1,4 @@ - Descargar Descargas diff --git a/libraries/exoplayer/src/main/res/values-gu/strings.xml b/libraries/exoplayer/src/main/res/values-gu/strings.xml index 27821e22999..5d2b5874e50 100644 --- a/libraries/exoplayer/src/main/res/values-gu/strings.xml +++ b/libraries/exoplayer/src/main/res/values-gu/strings.xml @@ -1,18 +1,4 @@ - ડાઉનલોડ કરો ડાઉનલોડ diff --git a/libraries/exoplayer/src/main/res/values-hi/strings.xml b/libraries/exoplayer/src/main/res/values-hi/strings.xml index d839e3f3fa3..17a17adcdd2 100644 --- a/libraries/exoplayer/src/main/res/values-hi/strings.xml +++ b/libraries/exoplayer/src/main/res/values-hi/strings.xml @@ -1,18 +1,4 @@ - डाउनलोड करें डाउनलोड की गई मीडिया फ़ाइलें diff --git a/libraries/exoplayer/src/main/res/values-hr/strings.xml b/libraries/exoplayer/src/main/res/values-hr/strings.xml index 031e629fd84..05d7cfa4481 100644 --- a/libraries/exoplayer/src/main/res/values-hr/strings.xml +++ b/libraries/exoplayer/src/main/res/values-hr/strings.xml @@ -1,18 +1,4 @@ - Preuzmi Preuzimanja diff --git a/libraries/exoplayer/src/main/res/values-hu/strings.xml b/libraries/exoplayer/src/main/res/values-hu/strings.xml index e511a695948..d19171d9750 100644 --- a/libraries/exoplayer/src/main/res/values-hu/strings.xml +++ b/libraries/exoplayer/src/main/res/values-hu/strings.xml @@ -1,18 +1,4 @@ - Letöltés Letöltések diff --git a/libraries/exoplayer/src/main/res/values-hy/strings.xml b/libraries/exoplayer/src/main/res/values-hy/strings.xml index 61d61e87041..4fc4e86bcb4 100644 --- a/libraries/exoplayer/src/main/res/values-hy/strings.xml +++ b/libraries/exoplayer/src/main/res/values-hy/strings.xml @@ -1,18 +1,4 @@ - Ներբեռնել Ներբեռնումներ diff --git a/libraries/exoplayer/src/main/res/values-in/strings.xml b/libraries/exoplayer/src/main/res/values-in/strings.xml index ce650eb479b..e20aac9971f 100644 --- a/libraries/exoplayer/src/main/res/values-in/strings.xml +++ b/libraries/exoplayer/src/main/res/values-in/strings.xml @@ -1,18 +1,4 @@ - Download Download diff --git a/libraries/exoplayer/src/main/res/values-is/strings.xml b/libraries/exoplayer/src/main/res/values-is/strings.xml index 713dbc50b86..6c62e12ee42 100644 --- a/libraries/exoplayer/src/main/res/values-is/strings.xml +++ b/libraries/exoplayer/src/main/res/values-is/strings.xml @@ -1,18 +1,4 @@ - Sækja Niðurhal diff --git a/libraries/exoplayer/src/main/res/values-it/strings.xml b/libraries/exoplayer/src/main/res/values-it/strings.xml index 709bb8e5b45..03a7a64d1af 100644 --- a/libraries/exoplayer/src/main/res/values-it/strings.xml +++ b/libraries/exoplayer/src/main/res/values-it/strings.xml @@ -1,18 +1,4 @@ - Scarica Download diff --git a/libraries/exoplayer/src/main/res/values-iw/strings.xml b/libraries/exoplayer/src/main/res/values-iw/strings.xml index dadb93b0167..41010d65f8e 100644 --- a/libraries/exoplayer/src/main/res/values-iw/strings.xml +++ b/libraries/exoplayer/src/main/res/values-iw/strings.xml @@ -1,18 +1,4 @@ - הורדה הורדות diff --git a/libraries/exoplayer/src/main/res/values-ja/strings.xml b/libraries/exoplayer/src/main/res/values-ja/strings.xml index b4df8db16c7..f32b0bfc75a 100644 --- a/libraries/exoplayer/src/main/res/values-ja/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ja/strings.xml @@ -1,18 +1,4 @@ - ダウンロード ダウンロード diff --git a/libraries/exoplayer/src/main/res/values-ka/strings.xml b/libraries/exoplayer/src/main/res/values-ka/strings.xml index 34fa93ac36b..2460d0c4b7c 100644 --- a/libraries/exoplayer/src/main/res/values-ka/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ka/strings.xml @@ -1,18 +1,4 @@ - ჩამოტვირთვა ჩამოტვირთვები diff --git a/libraries/exoplayer/src/main/res/values-kk/strings.xml b/libraries/exoplayer/src/main/res/values-kk/strings.xml index a0e7f49af14..616fb42af59 100644 --- a/libraries/exoplayer/src/main/res/values-kk/strings.xml +++ b/libraries/exoplayer/src/main/res/values-kk/strings.xml @@ -1,18 +1,4 @@ - Жүктеп алу Жүктеп алынғандар diff --git a/libraries/exoplayer/src/main/res/values-km/strings.xml b/libraries/exoplayer/src/main/res/values-km/strings.xml index d284e7b78ad..2089642a4a3 100644 --- a/libraries/exoplayer/src/main/res/values-km/strings.xml +++ b/libraries/exoplayer/src/main/res/values-km/strings.xml @@ -1,18 +1,4 @@ - ទាញយក ទាញយក diff --git a/libraries/exoplayer/src/main/res/values-kn/strings.xml b/libraries/exoplayer/src/main/res/values-kn/strings.xml index c311225089f..7747d1256b3 100644 --- a/libraries/exoplayer/src/main/res/values-kn/strings.xml +++ b/libraries/exoplayer/src/main/res/values-kn/strings.xml @@ -1,18 +1,4 @@ - ಡೌನ್‌ಲೋಡ್‌ ಡೌನ್‌ಲೋಡ್‌ಗಳು diff --git a/libraries/exoplayer/src/main/res/values-ko/strings.xml b/libraries/exoplayer/src/main/res/values-ko/strings.xml index 3bbdd2cb6c8..a87dce92cc1 100644 --- a/libraries/exoplayer/src/main/res/values-ko/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ko/strings.xml @@ -1,18 +1,4 @@ - 다운로드 다운로드 diff --git a/libraries/exoplayer/src/main/res/values-ky/strings.xml b/libraries/exoplayer/src/main/res/values-ky/strings.xml index 8cf2921bc38..6ce6949e2b2 100644 --- a/libraries/exoplayer/src/main/res/values-ky/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ky/strings.xml @@ -1,18 +1,4 @@ - Жүктөп алуу Жүктөлүп алынгандар diff --git a/libraries/exoplayer/src/main/res/values-lo/strings.xml b/libraries/exoplayer/src/main/res/values-lo/strings.xml index 0b7f314f91c..1ff16ef04f1 100644 --- a/libraries/exoplayer/src/main/res/values-lo/strings.xml +++ b/libraries/exoplayer/src/main/res/values-lo/strings.xml @@ -1,18 +1,4 @@ - ດາວໂຫລດ ດາວໂຫລດ diff --git a/libraries/exoplayer/src/main/res/values-lt/strings.xml b/libraries/exoplayer/src/main/res/values-lt/strings.xml index afc749c88aa..c81cdd10928 100644 --- a/libraries/exoplayer/src/main/res/values-lt/strings.xml +++ b/libraries/exoplayer/src/main/res/values-lt/strings.xml @@ -1,18 +1,4 @@ - Atsisiųsti Atsisiuntimai diff --git a/libraries/exoplayer/src/main/res/values-lv/strings.xml b/libraries/exoplayer/src/main/res/values-lv/strings.xml index 1899c273e46..0213b5e0621 100644 --- a/libraries/exoplayer/src/main/res/values-lv/strings.xml +++ b/libraries/exoplayer/src/main/res/values-lv/strings.xml @@ -1,18 +1,4 @@ - Lejupielādēt Lejupielādes diff --git a/libraries/exoplayer/src/main/res/values-mk/strings.xml b/libraries/exoplayer/src/main/res/values-mk/strings.xml index 58a1de488ab..6e1c3aecfcd 100644 --- a/libraries/exoplayer/src/main/res/values-mk/strings.xml +++ b/libraries/exoplayer/src/main/res/values-mk/strings.xml @@ -1,18 +1,4 @@ - Преземи Преземања diff --git a/libraries/exoplayer/src/main/res/values-ml/strings.xml b/libraries/exoplayer/src/main/res/values-ml/strings.xml index 5c75164da85..2e0653da43e 100644 --- a/libraries/exoplayer/src/main/res/values-ml/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ml/strings.xml @@ -1,18 +1,4 @@ - ഡൗൺലോഡ് ഡൗൺലോഡുകൾ diff --git a/libraries/exoplayer/src/main/res/values-mn/strings.xml b/libraries/exoplayer/src/main/res/values-mn/strings.xml index 6e7aac5dc9a..95b30da3ce3 100644 --- a/libraries/exoplayer/src/main/res/values-mn/strings.xml +++ b/libraries/exoplayer/src/main/res/values-mn/strings.xml @@ -1,18 +1,4 @@ - Татах Татaлт diff --git a/libraries/exoplayer/src/main/res/values-mr/strings.xml b/libraries/exoplayer/src/main/res/values-mr/strings.xml index 0d98194d6a3..0c37597ddae 100644 --- a/libraries/exoplayer/src/main/res/values-mr/strings.xml +++ b/libraries/exoplayer/src/main/res/values-mr/strings.xml @@ -1,18 +1,4 @@ - डाउनलोड करा डाउनलोड diff --git a/libraries/exoplayer/src/main/res/values-ms/strings.xml b/libraries/exoplayer/src/main/res/values-ms/strings.xml index f4d08d49d37..3033c3c93f8 100644 --- a/libraries/exoplayer/src/main/res/values-ms/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ms/strings.xml @@ -1,18 +1,4 @@ - Muat turun Muat turun diff --git a/libraries/exoplayer/src/main/res/values-my/strings.xml b/libraries/exoplayer/src/main/res/values-my/strings.xml index 9e308724ad4..88294129a9c 100644 --- a/libraries/exoplayer/src/main/res/values-my/strings.xml +++ b/libraries/exoplayer/src/main/res/values-my/strings.xml @@ -1,18 +1,4 @@ - ဒေါင်းလုဒ် လုပ်ရန် ဒေါင်းလုဒ်များ diff --git a/libraries/exoplayer/src/main/res/values-nb/strings.xml b/libraries/exoplayer/src/main/res/values-nb/strings.xml index 5d5b46b28c5..026d9be10d7 100644 --- a/libraries/exoplayer/src/main/res/values-nb/strings.xml +++ b/libraries/exoplayer/src/main/res/values-nb/strings.xml @@ -1,18 +1,4 @@ - Last ned Nedlastinger diff --git a/libraries/exoplayer/src/main/res/values-ne/strings.xml b/libraries/exoplayer/src/main/res/values-ne/strings.xml index deff7e8e415..a1a014bf7bb 100644 --- a/libraries/exoplayer/src/main/res/values-ne/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ne/strings.xml @@ -1,18 +1,4 @@ - डाउनलोड गर्नुहोस् डाउनलोडहरू diff --git a/libraries/exoplayer/src/main/res/values-nl/strings.xml b/libraries/exoplayer/src/main/res/values-nl/strings.xml index 589296d9a65..c8eeb8553dd 100644 --- a/libraries/exoplayer/src/main/res/values-nl/strings.xml +++ b/libraries/exoplayer/src/main/res/values-nl/strings.xml @@ -1,18 +1,4 @@ - Downloaden Downloads diff --git a/libraries/exoplayer/src/main/res/values-pa/strings.xml b/libraries/exoplayer/src/main/res/values-pa/strings.xml index 86236f9e03d..ee5031015df 100644 --- a/libraries/exoplayer/src/main/res/values-pa/strings.xml +++ b/libraries/exoplayer/src/main/res/values-pa/strings.xml @@ -1,18 +1,4 @@ - ਡਾਊਨਲੋਡ ਕਰੋ ਡਾਊਨਲੋਡ diff --git a/libraries/exoplayer/src/main/res/values-pl/strings.xml b/libraries/exoplayer/src/main/res/values-pl/strings.xml index 63fc39fac73..40633af74cd 100644 --- a/libraries/exoplayer/src/main/res/values-pl/strings.xml +++ b/libraries/exoplayer/src/main/res/values-pl/strings.xml @@ -1,18 +1,4 @@ - Pobierz Pobieranie diff --git a/libraries/exoplayer/src/main/res/values-pt-rPT/strings.xml b/libraries/exoplayer/src/main/res/values-pt-rPT/strings.xml index 6c9f639ec98..1988ac95eb1 100644 --- a/libraries/exoplayer/src/main/res/values-pt-rPT/strings.xml +++ b/libraries/exoplayer/src/main/res/values-pt-rPT/strings.xml @@ -1,18 +1,4 @@ - Transferir Transferências diff --git a/libraries/exoplayer/src/main/res/values-pt/strings.xml b/libraries/exoplayer/src/main/res/values-pt/strings.xml index c38d90d176f..59889e55d58 100644 --- a/libraries/exoplayer/src/main/res/values-pt/strings.xml +++ b/libraries/exoplayer/src/main/res/values-pt/strings.xml @@ -1,18 +1,4 @@ - Fazer o download Downloads diff --git a/libraries/exoplayer/src/main/res/values-ro/strings.xml b/libraries/exoplayer/src/main/res/values-ro/strings.xml index a4a7afa1a65..56355afa1f6 100644 --- a/libraries/exoplayer/src/main/res/values-ro/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ro/strings.xml @@ -1,20 +1,6 @@ - - Descărcați + Descarcă Descărcări Se descarcă Descărcarea a fost finalizată diff --git a/libraries/exoplayer/src/main/res/values-ru/strings.xml b/libraries/exoplayer/src/main/res/values-ru/strings.xml index b989fd3bc1e..c2b7f7f3603 100644 --- a/libraries/exoplayer/src/main/res/values-ru/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ru/strings.xml @@ -1,18 +1,4 @@ - Скачать Скачивания diff --git a/libraries/exoplayer/src/main/res/values-si/strings.xml b/libraries/exoplayer/src/main/res/values-si/strings.xml index 36b652c2cca..2b9b3289fd2 100644 --- a/libraries/exoplayer/src/main/res/values-si/strings.xml +++ b/libraries/exoplayer/src/main/res/values-si/strings.xml @@ -1,18 +1,4 @@ - බාගන්න බාගැනීම් diff --git a/libraries/exoplayer/src/main/res/values-sk/strings.xml b/libraries/exoplayer/src/main/res/values-sk/strings.xml index fec40af4e2e..4581322c61a 100644 --- a/libraries/exoplayer/src/main/res/values-sk/strings.xml +++ b/libraries/exoplayer/src/main/res/values-sk/strings.xml @@ -1,18 +1,4 @@ - Stiahnuť Stiahnuté diff --git a/libraries/exoplayer/src/main/res/values-sl/strings.xml b/libraries/exoplayer/src/main/res/values-sl/strings.xml index 025ba4a0e68..460643ebb8e 100644 --- a/libraries/exoplayer/src/main/res/values-sl/strings.xml +++ b/libraries/exoplayer/src/main/res/values-sl/strings.xml @@ -1,18 +1,4 @@ - Prenos Prenosi diff --git a/libraries/exoplayer/src/main/res/values-sq/strings.xml b/libraries/exoplayer/src/main/res/values-sq/strings.xml index 836ff91e416..b3e916ef4c5 100644 --- a/libraries/exoplayer/src/main/res/values-sq/strings.xml +++ b/libraries/exoplayer/src/main/res/values-sq/strings.xml @@ -1,18 +1,4 @@ - Shkarko Shkarkimet diff --git a/libraries/exoplayer/src/main/res/values-sr/strings.xml b/libraries/exoplayer/src/main/res/values-sr/strings.xml index aad22873536..f537b8e38f0 100644 --- a/libraries/exoplayer/src/main/res/values-sr/strings.xml +++ b/libraries/exoplayer/src/main/res/values-sr/strings.xml @@ -1,18 +1,4 @@ - Преузми Преузимања diff --git a/libraries/exoplayer/src/main/res/values-sv/strings.xml b/libraries/exoplayer/src/main/res/values-sv/strings.xml index 34ea63ab33d..a645a70f8c3 100644 --- a/libraries/exoplayer/src/main/res/values-sv/strings.xml +++ b/libraries/exoplayer/src/main/res/values-sv/strings.xml @@ -1,18 +1,4 @@ - Ladda ned Nedladdningar diff --git a/libraries/exoplayer/src/main/res/values-sw/strings.xml b/libraries/exoplayer/src/main/res/values-sw/strings.xml index f2ea0ebb2fe..e6d112427fd 100644 --- a/libraries/exoplayer/src/main/res/values-sw/strings.xml +++ b/libraries/exoplayer/src/main/res/values-sw/strings.xml @@ -1,18 +1,4 @@ - Pakua Vipakuliwa diff --git a/libraries/exoplayer/src/main/res/values-ta/strings.xml b/libraries/exoplayer/src/main/res/values-ta/strings.xml index b9dd46a955d..bd9cdbf5d4c 100644 --- a/libraries/exoplayer/src/main/res/values-ta/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ta/strings.xml @@ -1,18 +1,4 @@ - பதிவிறக்கும் பட்டன் பதிவிறக்கங்கள் diff --git a/libraries/exoplayer/src/main/res/values-te/strings.xml b/libraries/exoplayer/src/main/res/values-te/strings.xml index fe1f48a955d..cf0480ebb08 100644 --- a/libraries/exoplayer/src/main/res/values-te/strings.xml +++ b/libraries/exoplayer/src/main/res/values-te/strings.xml @@ -1,18 +1,4 @@ - డౌన్‌లోడ్ చేయి డౌన్‌లోడ్‌లు diff --git a/libraries/exoplayer/src/main/res/values-th/strings.xml b/libraries/exoplayer/src/main/res/values-th/strings.xml index c888cd3b721..73cba4d678c 100644 --- a/libraries/exoplayer/src/main/res/values-th/strings.xml +++ b/libraries/exoplayer/src/main/res/values-th/strings.xml @@ -1,18 +1,4 @@ - ดาวน์โหลด ดาวน์โหลด diff --git a/libraries/exoplayer/src/main/res/values-tl/strings.xml b/libraries/exoplayer/src/main/res/values-tl/strings.xml index 3b04a687a5f..4e68f6f05c3 100644 --- a/libraries/exoplayer/src/main/res/values-tl/strings.xml +++ b/libraries/exoplayer/src/main/res/values-tl/strings.xml @@ -1,18 +1,4 @@ - I-download Mga Download diff --git a/libraries/exoplayer/src/main/res/values-tr/strings.xml b/libraries/exoplayer/src/main/res/values-tr/strings.xml index 2b9252ec7c2..24a75afb362 100644 --- a/libraries/exoplayer/src/main/res/values-tr/strings.xml +++ b/libraries/exoplayer/src/main/res/values-tr/strings.xml @@ -1,18 +1,4 @@ - İndir İndirilenler diff --git a/libraries/exoplayer/src/main/res/values-uk/strings.xml b/libraries/exoplayer/src/main/res/values-uk/strings.xml index 7fbb8955de0..2413efd778f 100644 --- a/libraries/exoplayer/src/main/res/values-uk/strings.xml +++ b/libraries/exoplayer/src/main/res/values-uk/strings.xml @@ -1,18 +1,4 @@ - Завантажити Завантаження diff --git a/libraries/exoplayer/src/main/res/values-ur/strings.xml b/libraries/exoplayer/src/main/res/values-ur/strings.xml index 966f4062735..b9dd50dd8a4 100644 --- a/libraries/exoplayer/src/main/res/values-ur/strings.xml +++ b/libraries/exoplayer/src/main/res/values-ur/strings.xml @@ -1,18 +1,4 @@ - ڈاؤن لوڈ کریں ڈاؤن لوڈز diff --git a/libraries/exoplayer/src/main/res/values-uz/strings.xml b/libraries/exoplayer/src/main/res/values-uz/strings.xml index 85aaf73a8cd..21e3ed45d50 100644 --- a/libraries/exoplayer/src/main/res/values-uz/strings.xml +++ b/libraries/exoplayer/src/main/res/values-uz/strings.xml @@ -1,18 +1,4 @@ - Yuklab olish Yuklanmalar diff --git a/libraries/exoplayer/src/main/res/values-vi/strings.xml b/libraries/exoplayer/src/main/res/values-vi/strings.xml index 1e97ed5e5d5..3b74a5541a2 100644 --- a/libraries/exoplayer/src/main/res/values-vi/strings.xml +++ b/libraries/exoplayer/src/main/res/values-vi/strings.xml @@ -1,18 +1,4 @@ - Tải xuống Tài nguyên đã tải xuống diff --git a/libraries/exoplayer/src/main/res/values-zh-rCN/strings.xml b/libraries/exoplayer/src/main/res/values-zh-rCN/strings.xml index 1d24d8cab34..4031209c29c 100644 --- a/libraries/exoplayer/src/main/res/values-zh-rCN/strings.xml +++ b/libraries/exoplayer/src/main/res/values-zh-rCN/strings.xml @@ -1,18 +1,4 @@ - 下载 下载内容 diff --git a/libraries/exoplayer/src/main/res/values-zh-rHK/strings.xml b/libraries/exoplayer/src/main/res/values-zh-rHK/strings.xml index 1b4279329fc..eb4c8197467 100644 --- a/libraries/exoplayer/src/main/res/values-zh-rHK/strings.xml +++ b/libraries/exoplayer/src/main/res/values-zh-rHK/strings.xml @@ -1,18 +1,4 @@ - 下載 下載內容 diff --git a/libraries/exoplayer/src/main/res/values-zh-rTW/strings.xml b/libraries/exoplayer/src/main/res/values-zh-rTW/strings.xml index f696d26abfc..c95bfd95a2b 100644 --- a/libraries/exoplayer/src/main/res/values-zh-rTW/strings.xml +++ b/libraries/exoplayer/src/main/res/values-zh-rTW/strings.xml @@ -1,18 +1,4 @@ - 下載 下載 diff --git a/libraries/exoplayer/src/main/res/values-zu/strings.xml b/libraries/exoplayer/src/main/res/values-zu/strings.xml index f1d3047458b..4e2a4172614 100644 --- a/libraries/exoplayer/src/main/res/values-zu/strings.xml +++ b/libraries/exoplayer/src/main/res/values-zu/strings.xml @@ -1,18 +1,4 @@ - Landa Ukulandwa diff --git a/libraries/session/src/main/res/values-af/strings.xml b/libraries/session/src/main/res/values-af/strings.xml index 8ff1ece685b..08c05430ee2 100755 --- a/libraries/session/src/main/res/values-af/strings.xml +++ b/libraries/session/src/main/res/values-af/strings.xml @@ -1,18 +1,4 @@ - Speel tans Speel diff --git a/libraries/session/src/main/res/values-am/strings.xml b/libraries/session/src/main/res/values-am/strings.xml index 167aa23d487..503a47a0b94 100755 --- a/libraries/session/src/main/res/values-am/strings.xml +++ b/libraries/session/src/main/res/values-am/strings.xml @@ -1,18 +1,4 @@ - አሁን እየተጫወተ ያለ አጫውት diff --git a/libraries/session/src/main/res/values-ar/strings.xml b/libraries/session/src/main/res/values-ar/strings.xml index 140f15247bc..78c978f9331 100755 --- a/libraries/session/src/main/res/values-ar/strings.xml +++ b/libraries/session/src/main/res/values-ar/strings.xml @@ -1,20 +1,6 @@ - - التعرف التلقائي على الوسائط + قيد التشغيل الآن تشغيل إيقاف مؤقت ترجيع إلى العنصر السابق diff --git a/libraries/session/src/main/res/values-az/strings.xml b/libraries/session/src/main/res/values-az/strings.xml index 9b026dc7896..3de48f1eee7 100755 --- a/libraries/session/src/main/res/values-az/strings.xml +++ b/libraries/session/src/main/res/values-az/strings.xml @@ -1,18 +1,4 @@ - İndi oxudulur Oxudun diff --git a/libraries/session/src/main/res/values-b+sr+Latn/strings.xml b/libraries/session/src/main/res/values-b+sr+Latn/strings.xml index aab80ab5a70..9fc56865f39 100755 --- a/libraries/session/src/main/res/values-b+sr+Latn/strings.xml +++ b/libraries/session/src/main/res/values-b+sr+Latn/strings.xml @@ -1,18 +1,4 @@ - Trenutno svira Pusti diff --git a/libraries/session/src/main/res/values-be/strings.xml b/libraries/session/src/main/res/values-be/strings.xml index b01d57052af..ff390a7a97f 100755 --- a/libraries/session/src/main/res/values-be/strings.xml +++ b/libraries/session/src/main/res/values-be/strings.xml @@ -1,18 +1,4 @@ - Зараз іграе Прайграць diff --git a/libraries/session/src/main/res/values-bg/strings.xml b/libraries/session/src/main/res/values-bg/strings.xml index e24ec1e9bc5..b720ead2c11 100755 --- a/libraries/session/src/main/res/values-bg/strings.xml +++ b/libraries/session/src/main/res/values-bg/strings.xml @@ -1,18 +1,4 @@ - Възпроизвеждано сега съдържание Пускане diff --git a/libraries/session/src/main/res/values-bn/strings.xml b/libraries/session/src/main/res/values-bn/strings.xml index 2694309f6a8..4cb73e9a463 100755 --- a/libraries/session/src/main/res/values-bn/strings.xml +++ b/libraries/session/src/main/res/values-bn/strings.xml @@ -1,18 +1,4 @@ - এখন চলছে চালান diff --git a/libraries/session/src/main/res/values-bs/strings.xml b/libraries/session/src/main/res/values-bs/strings.xml index 2441a1fca81..46f4b9c07d1 100755 --- a/libraries/session/src/main/res/values-bs/strings.xml +++ b/libraries/session/src/main/res/values-bs/strings.xml @@ -1,18 +1,4 @@ - Trenutno se reproducira Reproduciranje diff --git a/libraries/session/src/main/res/values-ca/strings.xml b/libraries/session/src/main/res/values-ca/strings.xml index f9bf84a2639..368e7fc64b6 100755 --- a/libraries/session/src/main/res/values-ca/strings.xml +++ b/libraries/session/src/main/res/values-ca/strings.xml @@ -1,18 +1,4 @@ - S\'està reproduint Reprodueix diff --git a/libraries/session/src/main/res/values-cs/strings.xml b/libraries/session/src/main/res/values-cs/strings.xml index 9c1f3dc49f4..9c373bd834f 100755 --- a/libraries/session/src/main/res/values-cs/strings.xml +++ b/libraries/session/src/main/res/values-cs/strings.xml @@ -1,18 +1,4 @@ - Přehrává se Přehrát diff --git a/libraries/session/src/main/res/values-da/strings.xml b/libraries/session/src/main/res/values-da/strings.xml index c8236d5ab09..79c8487541f 100755 --- a/libraries/session/src/main/res/values-da/strings.xml +++ b/libraries/session/src/main/res/values-da/strings.xml @@ -1,18 +1,4 @@ - Afspilles nu Afspil diff --git a/libraries/session/src/main/res/values-de/strings.xml b/libraries/session/src/main/res/values-de/strings.xml index f6685e59991..24fc22bb1f0 100755 --- a/libraries/session/src/main/res/values-de/strings.xml +++ b/libraries/session/src/main/res/values-de/strings.xml @@ -1,18 +1,4 @@ - Läuft gerade Wiedergabe diff --git a/libraries/session/src/main/res/values-el/strings.xml b/libraries/session/src/main/res/values-el/strings.xml index 0d90dca7f97..255b6a74bfb 100755 --- a/libraries/session/src/main/res/values-el/strings.xml +++ b/libraries/session/src/main/res/values-el/strings.xml @@ -1,18 +1,4 @@ - Ακούγεται τώρα Αναπαραγωγή diff --git a/libraries/session/src/main/res/values-en-rAU/strings.xml b/libraries/session/src/main/res/values-en-rAU/strings.xml index 0bf10abd2dc..aef8b741e64 100755 --- a/libraries/session/src/main/res/values-en-rAU/strings.xml +++ b/libraries/session/src/main/res/values-en-rAU/strings.xml @@ -1,18 +1,4 @@ - Now playing Play diff --git a/libraries/session/src/main/res/values-en-rGB/strings.xml b/libraries/session/src/main/res/values-en-rGB/strings.xml index 0bf10abd2dc..aef8b741e64 100755 --- a/libraries/session/src/main/res/values-en-rGB/strings.xml +++ b/libraries/session/src/main/res/values-en-rGB/strings.xml @@ -1,18 +1,4 @@ - Now playing Play diff --git a/libraries/session/src/main/res/values-en-rIN/strings.xml b/libraries/session/src/main/res/values-en-rIN/strings.xml index 0bf10abd2dc..aef8b741e64 100755 --- a/libraries/session/src/main/res/values-en-rIN/strings.xml +++ b/libraries/session/src/main/res/values-en-rIN/strings.xml @@ -1,18 +1,4 @@ - Now playing Play diff --git a/libraries/session/src/main/res/values-es-rUS/strings.xml b/libraries/session/src/main/res/values-es-rUS/strings.xml index c3ea5dcb072..8986aeb307c 100755 --- a/libraries/session/src/main/res/values-es-rUS/strings.xml +++ b/libraries/session/src/main/res/values-es-rUS/strings.xml @@ -1,18 +1,4 @@ - Está sonando Reproducir diff --git a/libraries/session/src/main/res/values-es/strings.xml b/libraries/session/src/main/res/values-es/strings.xml index 1a8880ecdb1..99e401b71fa 100755 --- a/libraries/session/src/main/res/values-es/strings.xml +++ b/libraries/session/src/main/res/values-es/strings.xml @@ -1,18 +1,4 @@ - Está sonando Reproducir diff --git a/libraries/session/src/main/res/values-et/strings.xml b/libraries/session/src/main/res/values-et/strings.xml index 4bd8e64a455..a6bd4c2becc 100755 --- a/libraries/session/src/main/res/values-et/strings.xml +++ b/libraries/session/src/main/res/values-et/strings.xml @@ -1,18 +1,4 @@ - Hetkel mängimas Esitamine diff --git a/libraries/session/src/main/res/values-eu/strings.xml b/libraries/session/src/main/res/values-eu/strings.xml index f53cc746a70..c57640f6136 100755 --- a/libraries/session/src/main/res/values-eu/strings.xml +++ b/libraries/session/src/main/res/values-eu/strings.xml @@ -1,18 +1,4 @@ - Orain erreproduzitzen Erreproduzitu diff --git a/libraries/session/src/main/res/values-fa/strings.xml b/libraries/session/src/main/res/values-fa/strings.xml index eb8a961f982..01501389914 100755 --- a/libraries/session/src/main/res/values-fa/strings.xml +++ b/libraries/session/src/main/res/values-fa/strings.xml @@ -1,18 +1,4 @@ - درحال پخش پخش diff --git a/libraries/session/src/main/res/values-fi/strings.xml b/libraries/session/src/main/res/values-fi/strings.xml index a4d6637218c..2adf214fbd5 100755 --- a/libraries/session/src/main/res/values-fi/strings.xml +++ b/libraries/session/src/main/res/values-fi/strings.xml @@ -1,18 +1,4 @@ - Nyt toistetaan Toista diff --git a/libraries/session/src/main/res/values-fr-rCA/strings.xml b/libraries/session/src/main/res/values-fr-rCA/strings.xml index fe00e2480b4..bdf99bf638a 100755 --- a/libraries/session/src/main/res/values-fr-rCA/strings.xml +++ b/libraries/session/src/main/res/values-fr-rCA/strings.xml @@ -1,18 +1,4 @@ - En cours de lecture Lire diff --git a/libraries/session/src/main/res/values-fr/strings.xml b/libraries/session/src/main/res/values-fr/strings.xml index bda0e76cd5b..ffc27ff8a09 100755 --- a/libraries/session/src/main/res/values-fr/strings.xml +++ b/libraries/session/src/main/res/values-fr/strings.xml @@ -1,18 +1,4 @@ - En cours de lecture Lecture diff --git a/libraries/session/src/main/res/values-gl/strings.xml b/libraries/session/src/main/res/values-gl/strings.xml index 97c0b5ae91a..96f6019adc6 100755 --- a/libraries/session/src/main/res/values-gl/strings.xml +++ b/libraries/session/src/main/res/values-gl/strings.xml @@ -1,18 +1,4 @@ - Reproducindo Reproducir diff --git a/libraries/session/src/main/res/values-gu/strings.xml b/libraries/session/src/main/res/values-gu/strings.xml index 3c2e5830395..1fcceea9478 100755 --- a/libraries/session/src/main/res/values-gu/strings.xml +++ b/libraries/session/src/main/res/values-gu/strings.xml @@ -1,18 +1,4 @@ - હાલમાં ચાલી રહી છે ચલાવો diff --git a/libraries/session/src/main/res/values-hi/strings.xml b/libraries/session/src/main/res/values-hi/strings.xml index 99a792cdd5e..4b6951be58c 100755 --- a/libraries/session/src/main/res/values-hi/strings.xml +++ b/libraries/session/src/main/res/values-hi/strings.xml @@ -1,18 +1,4 @@ - अभी चल रहा है चलाएं diff --git a/libraries/session/src/main/res/values-hr/strings.xml b/libraries/session/src/main/res/values-hr/strings.xml index 3fa32acbfbb..fe1eae0a7f0 100755 --- a/libraries/session/src/main/res/values-hr/strings.xml +++ b/libraries/session/src/main/res/values-hr/strings.xml @@ -1,18 +1,4 @@ - Upravo svira Reproduciraj diff --git a/libraries/session/src/main/res/values-hu/strings.xml b/libraries/session/src/main/res/values-hu/strings.xml index 2ff84c81f99..b1abc67ce96 100755 --- a/libraries/session/src/main/res/values-hu/strings.xml +++ b/libraries/session/src/main/res/values-hu/strings.xml @@ -1,18 +1,4 @@ - Most játszott tartalom Lejátszás diff --git a/libraries/session/src/main/res/values-hy/strings.xml b/libraries/session/src/main/res/values-hy/strings.xml index c5507fa8a15..1385a9cf42a 100755 --- a/libraries/session/src/main/res/values-hy/strings.xml +++ b/libraries/session/src/main/res/values-hy/strings.xml @@ -1,18 +1,4 @@ - Այժմ նվագարկվում է Նվագարկել diff --git a/libraries/session/src/main/res/values-in/strings.xml b/libraries/session/src/main/res/values-in/strings.xml index 142339374a6..b818baec7c5 100755 --- a/libraries/session/src/main/res/values-in/strings.xml +++ b/libraries/session/src/main/res/values-in/strings.xml @@ -1,18 +1,4 @@ - Sedang diputar Putar diff --git a/libraries/session/src/main/res/values-is/strings.xml b/libraries/session/src/main/res/values-is/strings.xml index dfc6267d5a2..249da58ac22 100755 --- a/libraries/session/src/main/res/values-is/strings.xml +++ b/libraries/session/src/main/res/values-is/strings.xml @@ -1,18 +1,4 @@ - Í spilun Spila diff --git a/libraries/session/src/main/res/values-it/strings.xml b/libraries/session/src/main/res/values-it/strings.xml index 0be1260e555..0ea7666b8fc 100755 --- a/libraries/session/src/main/res/values-it/strings.xml +++ b/libraries/session/src/main/res/values-it/strings.xml @@ -1,18 +1,4 @@ - Ora in riproduzione Riproduci diff --git a/libraries/session/src/main/res/values-iw/strings.xml b/libraries/session/src/main/res/values-iw/strings.xml index d5232cf89b5..a7fcd9a24d3 100755 --- a/libraries/session/src/main/res/values-iw/strings.xml +++ b/libraries/session/src/main/res/values-iw/strings.xml @@ -1,18 +1,4 @@ - הפריט שמופעל עכשיו הפעלה diff --git a/libraries/session/src/main/res/values-ja/strings.xml b/libraries/session/src/main/res/values-ja/strings.xml index 44957a4eeda..2db5cf15a34 100755 --- a/libraries/session/src/main/res/values-ja/strings.xml +++ b/libraries/session/src/main/res/values-ja/strings.xml @@ -1,18 +1,4 @@ - 再生中 再生 diff --git a/libraries/session/src/main/res/values-ka/strings.xml b/libraries/session/src/main/res/values-ka/strings.xml index 44e49caf122..bf4371548ec 100755 --- a/libraries/session/src/main/res/values-ka/strings.xml +++ b/libraries/session/src/main/res/values-ka/strings.xml @@ -1,18 +1,4 @@ - ამჟამად უკრავს დაკვრა diff --git a/libraries/session/src/main/res/values-kk/strings.xml b/libraries/session/src/main/res/values-kk/strings.xml index 98f22c78074..e88b1cf39e5 100755 --- a/libraries/session/src/main/res/values-kk/strings.xml +++ b/libraries/session/src/main/res/values-kk/strings.xml @@ -1,24 +1,10 @@ - Қазір ойнап тұр Ойнату Кідірту - Алдыңғы мазмұнға өту - Келесі мазмұнға өту + Алдыңғы контентке өту + Келесі контентке өту Артқа айналдыру Алға айналдыру Аутентификация қажет diff --git a/libraries/session/src/main/res/values-km/strings.xml b/libraries/session/src/main/res/values-km/strings.xml index b12cf6a8941..1d595590012 100755 --- a/libraries/session/src/main/res/values-km/strings.xml +++ b/libraries/session/src/main/res/values-km/strings.xml @@ -1,18 +1,4 @@ - កំពុងចាក់ ចាក់ diff --git a/libraries/session/src/main/res/values-kn/strings.xml b/libraries/session/src/main/res/values-kn/strings.xml index 485b09c0bfa..eb709d4c596 100755 --- a/libraries/session/src/main/res/values-kn/strings.xml +++ b/libraries/session/src/main/res/values-kn/strings.xml @@ -1,18 +1,4 @@ - ಇದೀಗ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ ಪ್ಲೇ ಮಾಡಿ diff --git a/libraries/session/src/main/res/values-ko/strings.xml b/libraries/session/src/main/res/values-ko/strings.xml index 015471fe5e4..5d6fae98c3d 100755 --- a/libraries/session/src/main/res/values-ko/strings.xml +++ b/libraries/session/src/main/res/values-ko/strings.xml @@ -1,18 +1,4 @@ - 지금 재생 중 재생 diff --git a/libraries/session/src/main/res/values-ky/strings.xml b/libraries/session/src/main/res/values-ky/strings.xml index 350724d9e09..081cccf540c 100755 --- a/libraries/session/src/main/res/values-ky/strings.xml +++ b/libraries/session/src/main/res/values-ky/strings.xml @@ -1,18 +1,4 @@ - Ойноп жатат Ойнотуу diff --git a/libraries/session/src/main/res/values-lo/strings.xml b/libraries/session/src/main/res/values-lo/strings.xml index 337bd7be33b..6a7310245f9 100755 --- a/libraries/session/src/main/res/values-lo/strings.xml +++ b/libraries/session/src/main/res/values-lo/strings.xml @@ -1,18 +1,4 @@ - ກຳລັງຫຼິ້ນຕອນນີ້ ຫຼິ້ນ diff --git a/libraries/session/src/main/res/values-lt/strings.xml b/libraries/session/src/main/res/values-lt/strings.xml index a8c02c98af7..3a8f7ec3e0f 100755 --- a/libraries/session/src/main/res/values-lt/strings.xml +++ b/libraries/session/src/main/res/values-lt/strings.xml @@ -1,18 +1,4 @@ - Dabar leidžiama Paleisti diff --git a/libraries/session/src/main/res/values-lv/strings.xml b/libraries/session/src/main/res/values-lv/strings.xml index 030bb7a5499..7283e50af17 100755 --- a/libraries/session/src/main/res/values-lv/strings.xml +++ b/libraries/session/src/main/res/values-lv/strings.xml @@ -1,18 +1,4 @@ - Tagad atskaņo Atskaņot diff --git a/libraries/session/src/main/res/values-mk/strings.xml b/libraries/session/src/main/res/values-mk/strings.xml index 19487a2d570..41b8e9fa041 100755 --- a/libraries/session/src/main/res/values-mk/strings.xml +++ b/libraries/session/src/main/res/values-mk/strings.xml @@ -1,18 +1,4 @@ - Сега е пуштено Пушти diff --git a/libraries/session/src/main/res/values-ml/strings.xml b/libraries/session/src/main/res/values-ml/strings.xml index 0b68af763fa..8a15c5b4ca8 100755 --- a/libraries/session/src/main/res/values-ml/strings.xml +++ b/libraries/session/src/main/res/values-ml/strings.xml @@ -1,18 +1,4 @@ - ഇപ്പോൾ പ്ലേ ചെയ്യുന്നത് പ്ലേ ചെയ്യുക diff --git a/libraries/session/src/main/res/values-mn/strings.xml b/libraries/session/src/main/res/values-mn/strings.xml index 5b9c2604fcb..0efbb93de65 100755 --- a/libraries/session/src/main/res/values-mn/strings.xml +++ b/libraries/session/src/main/res/values-mn/strings.xml @@ -1,18 +1,4 @@ - Одоо тоглуулж байна Тоглуулах diff --git a/libraries/session/src/main/res/values-mr/strings.xml b/libraries/session/src/main/res/values-mr/strings.xml index 35c8acf4769..e00fdc1a4ea 100755 --- a/libraries/session/src/main/res/values-mr/strings.xml +++ b/libraries/session/src/main/res/values-mr/strings.xml @@ -1,18 +1,4 @@ - आता प्ले करत आहे प्ले करा diff --git a/libraries/session/src/main/res/values-ms/strings.xml b/libraries/session/src/main/res/values-ms/strings.xml index 120211affc3..5cf79880885 100755 --- a/libraries/session/src/main/res/values-ms/strings.xml +++ b/libraries/session/src/main/res/values-ms/strings.xml @@ -1,18 +1,4 @@ - Sedang dimainkan Main diff --git a/libraries/session/src/main/res/values-my/strings.xml b/libraries/session/src/main/res/values-my/strings.xml index ea9920abc44..9e6f91f7618 100755 --- a/libraries/session/src/main/res/values-my/strings.xml +++ b/libraries/session/src/main/res/values-my/strings.xml @@ -1,18 +1,4 @@ - ယခု ဖွင့်နေသည် ဖွင့်ရန် diff --git a/libraries/session/src/main/res/values-nb/strings.xml b/libraries/session/src/main/res/values-nb/strings.xml index fefb5ea8354..4712949ceb7 100755 --- a/libraries/session/src/main/res/values-nb/strings.xml +++ b/libraries/session/src/main/res/values-nb/strings.xml @@ -1,18 +1,4 @@ - Spilles nå Spill av diff --git a/libraries/session/src/main/res/values-ne/strings.xml b/libraries/session/src/main/res/values-ne/strings.xml index 8d282366c80..9955dd5503f 100755 --- a/libraries/session/src/main/res/values-ne/strings.xml +++ b/libraries/session/src/main/res/values-ne/strings.xml @@ -1,18 +1,4 @@ - अहिले प्ले भइरहेको प्ले गर्नुहोस् diff --git a/libraries/session/src/main/res/values-nl/strings.xml b/libraries/session/src/main/res/values-nl/strings.xml index f3735156e43..b451512da36 100755 --- a/libraries/session/src/main/res/values-nl/strings.xml +++ b/libraries/session/src/main/res/values-nl/strings.xml @@ -1,18 +1,4 @@ - Wordt nu afgespeeld Afspelen diff --git a/libraries/session/src/main/res/values-pa/strings.xml b/libraries/session/src/main/res/values-pa/strings.xml index 86653fca741..ad0de6dc75b 100755 --- a/libraries/session/src/main/res/values-pa/strings.xml +++ b/libraries/session/src/main/res/values-pa/strings.xml @@ -1,18 +1,4 @@ - ਹੁਣੇ ਚੱਲ ਰਿਹਾ ਹੈ ਚਲਾਓ diff --git a/libraries/session/src/main/res/values-pl/strings.xml b/libraries/session/src/main/res/values-pl/strings.xml index 10eddbef385..00acc8b75b1 100755 --- a/libraries/session/src/main/res/values-pl/strings.xml +++ b/libraries/session/src/main/res/values-pl/strings.xml @@ -1,18 +1,4 @@ - Odtwarzam teraz Odtwórz diff --git a/libraries/session/src/main/res/values-pt-rPT/strings.xml b/libraries/session/src/main/res/values-pt-rPT/strings.xml index 0be33ad385c..d341ca707bd 100755 --- a/libraries/session/src/main/res/values-pt-rPT/strings.xml +++ b/libraries/session/src/main/res/values-pt-rPT/strings.xml @@ -1,18 +1,4 @@ - A tocar Reproduzir diff --git a/libraries/session/src/main/res/values-pt/strings.xml b/libraries/session/src/main/res/values-pt/strings.xml index 7bd7d795207..a422f4d3137 100755 --- a/libraries/session/src/main/res/values-pt/strings.xml +++ b/libraries/session/src/main/res/values-pt/strings.xml @@ -1,18 +1,4 @@ - Tocando agora Tocar diff --git a/libraries/session/src/main/res/values-ro/strings.xml b/libraries/session/src/main/res/values-ro/strings.xml index dd6fc779bd4..3de84449660 100755 --- a/libraries/session/src/main/res/values-ro/strings.xml +++ b/libraries/session/src/main/res/values-ro/strings.xml @@ -1,18 +1,4 @@ - Se redă acum Redă diff --git a/libraries/session/src/main/res/values-ru/strings.xml b/libraries/session/src/main/res/values-ru/strings.xml index b643018ac04..ff8bc44ce29 100755 --- a/libraries/session/src/main/res/values-ru/strings.xml +++ b/libraries/session/src/main/res/values-ru/strings.xml @@ -1,18 +1,4 @@ - Играет сейчас Воспроизвести diff --git a/libraries/session/src/main/res/values-si/strings.xml b/libraries/session/src/main/res/values-si/strings.xml index 48c60ddef80..706d6b07aef 100755 --- a/libraries/session/src/main/res/values-si/strings.xml +++ b/libraries/session/src/main/res/values-si/strings.xml @@ -1,18 +1,4 @@ - Now playing වාදනය කරන්න diff --git a/libraries/session/src/main/res/values-sk/strings.xml b/libraries/session/src/main/res/values-sk/strings.xml index f2d31acf055..27342a51c71 100755 --- a/libraries/session/src/main/res/values-sk/strings.xml +++ b/libraries/session/src/main/res/values-sk/strings.xml @@ -1,18 +1,4 @@ - Prehráva sa Prehrať diff --git a/libraries/session/src/main/res/values-sl/strings.xml b/libraries/session/src/main/res/values-sl/strings.xml index ab3fa88897a..bab26908b59 100755 --- a/libraries/session/src/main/res/values-sl/strings.xml +++ b/libraries/session/src/main/res/values-sl/strings.xml @@ -1,18 +1,4 @@ - Zdaj se predvaja Predvajaj diff --git a/libraries/session/src/main/res/values-sq/strings.xml b/libraries/session/src/main/res/values-sq/strings.xml index c8ebb5046d6..bd2c4b0afd6 100755 --- a/libraries/session/src/main/res/values-sq/strings.xml +++ b/libraries/session/src/main/res/values-sq/strings.xml @@ -1,18 +1,4 @@ - Gjej këngën Luaj diff --git a/libraries/session/src/main/res/values-sr/strings.xml b/libraries/session/src/main/res/values-sr/strings.xml index e3f7665ac3e..fb872219373 100755 --- a/libraries/session/src/main/res/values-sr/strings.xml +++ b/libraries/session/src/main/res/values-sr/strings.xml @@ -1,18 +1,4 @@ - Тренутно свира Пусти diff --git a/libraries/session/src/main/res/values-sv/strings.xml b/libraries/session/src/main/res/values-sv/strings.xml index ad53a1d6e4d..d613f5e2e5b 100755 --- a/libraries/session/src/main/res/values-sv/strings.xml +++ b/libraries/session/src/main/res/values-sv/strings.xml @@ -1,18 +1,4 @@ - Nu spelas Spela upp diff --git a/libraries/session/src/main/res/values-sw/strings.xml b/libraries/session/src/main/res/values-sw/strings.xml index 241fb50b780..4678bf1b0c8 100755 --- a/libraries/session/src/main/res/values-sw/strings.xml +++ b/libraries/session/src/main/res/values-sw/strings.xml @@ -1,18 +1,4 @@ - Inayocheza sasa Cheza diff --git a/libraries/session/src/main/res/values-ta/strings.xml b/libraries/session/src/main/res/values-ta/strings.xml index e0b65856a23..1e441e48439 100755 --- a/libraries/session/src/main/res/values-ta/strings.xml +++ b/libraries/session/src/main/res/values-ta/strings.xml @@ -1,18 +1,4 @@ - இப்போது பிளே ஆவது பிளே செய்யும் diff --git a/libraries/session/src/main/res/values-te/strings.xml b/libraries/session/src/main/res/values-te/strings.xml index e8a3734789a..f51ad9575ca 100755 --- a/libraries/session/src/main/res/values-te/strings.xml +++ b/libraries/session/src/main/res/values-te/strings.xml @@ -1,18 +1,4 @@ - ప్రస్తుతం ప్లే అవుతున్నది ప్లే చేయండి diff --git a/libraries/session/src/main/res/values-th/strings.xml b/libraries/session/src/main/res/values-th/strings.xml index 683e2aae68b..f3a5ecdb6a8 100755 --- a/libraries/session/src/main/res/values-th/strings.xml +++ b/libraries/session/src/main/res/values-th/strings.xml @@ -1,18 +1,4 @@ - กำลังเล่น เล่น diff --git a/libraries/session/src/main/res/values-tl/strings.xml b/libraries/session/src/main/res/values-tl/strings.xml index 995740a809b..8345460f875 100755 --- a/libraries/session/src/main/res/values-tl/strings.xml +++ b/libraries/session/src/main/res/values-tl/strings.xml @@ -1,18 +1,4 @@ - Nagpi-play ngayon I-play diff --git a/libraries/session/src/main/res/values-tr/strings.xml b/libraries/session/src/main/res/values-tr/strings.xml index 2795069c690..93fa1a469c5 100755 --- a/libraries/session/src/main/res/values-tr/strings.xml +++ b/libraries/session/src/main/res/values-tr/strings.xml @@ -1,18 +1,4 @@ - Şimdi oynatılıyor Oynat diff --git a/libraries/session/src/main/res/values-uk/strings.xml b/libraries/session/src/main/res/values-uk/strings.xml index 4786db3ce7e..56f0532c175 100755 --- a/libraries/session/src/main/res/values-uk/strings.xml +++ b/libraries/session/src/main/res/values-uk/strings.xml @@ -1,18 +1,4 @@ - Зараз відтворюється Відтворити diff --git a/libraries/session/src/main/res/values-ur/strings.xml b/libraries/session/src/main/res/values-ur/strings.xml index 423908db8a2..877371bfc19 100755 --- a/libraries/session/src/main/res/values-ur/strings.xml +++ b/libraries/session/src/main/res/values-ur/strings.xml @@ -1,18 +1,4 @@ - ابھی چل رہا ہے چلائیں diff --git a/libraries/session/src/main/res/values-uz/strings.xml b/libraries/session/src/main/res/values-uz/strings.xml index fed30dd6275..1356dd54939 100755 --- a/libraries/session/src/main/res/values-uz/strings.xml +++ b/libraries/session/src/main/res/values-uz/strings.xml @@ -1,18 +1,4 @@ - Bu qaysi musiqa Ijro diff --git a/libraries/session/src/main/res/values-vi/strings.xml b/libraries/session/src/main/res/values-vi/strings.xml index 9307041370b..ebb77b0a243 100755 --- a/libraries/session/src/main/res/values-vi/strings.xml +++ b/libraries/session/src/main/res/values-vi/strings.xml @@ -1,18 +1,4 @@ - Đang phát Phát diff --git a/libraries/session/src/main/res/values-zh-rCN/strings.xml b/libraries/session/src/main/res/values-zh-rCN/strings.xml index 0db79165949..bb5ef13433b 100755 --- a/libraries/session/src/main/res/values-zh-rCN/strings.xml +++ b/libraries/session/src/main/res/values-zh-rCN/strings.xml @@ -1,18 +1,4 @@ - 正在播放 播放 diff --git a/libraries/session/src/main/res/values-zh-rHK/strings.xml b/libraries/session/src/main/res/values-zh-rHK/strings.xml index 87716dc283e..1c6da3a07f7 100755 --- a/libraries/session/src/main/res/values-zh-rHK/strings.xml +++ b/libraries/session/src/main/res/values-zh-rHK/strings.xml @@ -1,18 +1,4 @@ - 正在播放 播放 diff --git a/libraries/session/src/main/res/values-zh-rTW/strings.xml b/libraries/session/src/main/res/values-zh-rTW/strings.xml index e7603e7d905..1c10d0755b8 100755 --- a/libraries/session/src/main/res/values-zh-rTW/strings.xml +++ b/libraries/session/src/main/res/values-zh-rTW/strings.xml @@ -1,18 +1,4 @@ - 現正播放 播放 diff --git a/libraries/session/src/main/res/values-zu/strings.xml b/libraries/session/src/main/res/values-zu/strings.xml index 4f5ee5ddddd..d50537842a2 100755 --- a/libraries/session/src/main/res/values-zu/strings.xml +++ b/libraries/session/src/main/res/values-zu/strings.xml @@ -1,18 +1,4 @@ - Okudlala manje Dlala diff --git a/libraries/ui/src/main/res/values-af/strings.xml b/libraries/ui/src/main/res/values-af/strings.xml index dd372298485..775029f1e22 100644 --- a/libraries/ui/src/main/res/values-af/strings.xml +++ b/libraries/ui/src/main/res/values-af/strings.xml @@ -1,18 +1,4 @@ - Wys spelerkontroles Versteek spelerkontroles diff --git a/libraries/ui/src/main/res/values-am/strings.xml b/libraries/ui/src/main/res/values-am/strings.xml index 343e45fbb8f..82802a43cd9 100644 --- a/libraries/ui/src/main/res/values-am/strings.xml +++ b/libraries/ui/src/main/res/values-am/strings.xml @@ -1,18 +1,4 @@ - የተጫዋች መቆጣጠሪያዎችን አሳይ የተጫዋች መቆጣጠሪያዎችን ደብቅ @@ -57,7 +43,7 @@ ቪዲዮ ኦዲዮ - ጽሑፍ + ጽሁፍ ምንም ራስ-ሰር ያልታወቀ diff --git a/libraries/ui/src/main/res/values-ar/strings.xml b/libraries/ui/src/main/res/values-ar/strings.xml index bef7a468e5d..804acfc4d65 100644 --- a/libraries/ui/src/main/res/values-ar/strings.xml +++ b/libraries/ui/src/main/res/values-ar/strings.xml @@ -1,18 +1,4 @@ - عرض عناصر التحكم بالمشغّل إخفاء عناصر التحكم بالمشغّل diff --git a/libraries/ui/src/main/res/values-az/strings.xml b/libraries/ui/src/main/res/values-az/strings.xml index 86ea0522682..90653578f00 100644 --- a/libraries/ui/src/main/res/values-az/strings.xml +++ b/libraries/ui/src/main/res/values-az/strings.xml @@ -1,18 +1,4 @@ - Oyunçu nəzarətlərini göstərin Oyunçu nəzarətlərini gizlədin diff --git a/libraries/ui/src/main/res/values-b+sr+Latn/strings.xml b/libraries/ui/src/main/res/values-b+sr+Latn/strings.xml index 2acf688bca3..ae0185ea3d3 100644 --- a/libraries/ui/src/main/res/values-b+sr+Latn/strings.xml +++ b/libraries/ui/src/main/res/values-b+sr+Latn/strings.xml @@ -1,18 +1,4 @@ - Prikaži kontrole plejera Sakrij kontrole plejera diff --git a/libraries/ui/src/main/res/values-be/strings.xml b/libraries/ui/src/main/res/values-be/strings.xml index 05ea71c4720..041453ecb2a 100644 --- a/libraries/ui/src/main/res/values-be/strings.xml +++ b/libraries/ui/src/main/res/values-be/strings.xml @@ -1,18 +1,4 @@ - Паказаць элементы кіравання прайгравальніка Схаваць элементы кіравання прайгравальніка diff --git a/libraries/ui/src/main/res/values-bg/strings.xml b/libraries/ui/src/main/res/values-bg/strings.xml index 3a898ed4bde..5870895d62c 100644 --- a/libraries/ui/src/main/res/values-bg/strings.xml +++ b/libraries/ui/src/main/res/values-bg/strings.xml @@ -1,18 +1,4 @@ - Показване на контролите на плейъра Скриване на контролите на плейъра diff --git a/libraries/ui/src/main/res/values-bn/strings.xml b/libraries/ui/src/main/res/values-bn/strings.xml index 2235db434bf..d8e8450755e 100644 --- a/libraries/ui/src/main/res/values-bn/strings.xml +++ b/libraries/ui/src/main/res/values-bn/strings.xml @@ -1,18 +1,4 @@ - প্লেয়ার নিয়ন্ত্রণগুলি দেখুন প্লেয়ার নিয়ন্ত্রণগুলি লুকান diff --git a/libraries/ui/src/main/res/values-bs/strings.xml b/libraries/ui/src/main/res/values-bs/strings.xml index 3793c330c1f..1981474f164 100644 --- a/libraries/ui/src/main/res/values-bs/strings.xml +++ b/libraries/ui/src/main/res/values-bs/strings.xml @@ -1,18 +1,4 @@ - Prikaži kontrole plejera Sakrij kontrole plejera diff --git a/libraries/ui/src/main/res/values-ca/strings.xml b/libraries/ui/src/main/res/values-ca/strings.xml index ba2e8374a9f..56b646a258d 100644 --- a/libraries/ui/src/main/res/values-ca/strings.xml +++ b/libraries/ui/src/main/res/values-ca/strings.xml @@ -1,18 +1,4 @@ - Mostra els controls del reproductor Amaga els controls del reproductor diff --git a/libraries/ui/src/main/res/values-cs/strings.xml b/libraries/ui/src/main/res/values-cs/strings.xml index bb0f85369ae..48943a497dd 100644 --- a/libraries/ui/src/main/res/values-cs/strings.xml +++ b/libraries/ui/src/main/res/values-cs/strings.xml @@ -1,18 +1,4 @@ - Zobrazit ovládací prvky přehrávače Skrýt ovládací prvky přehrávače diff --git a/libraries/ui/src/main/res/values-da/strings.xml b/libraries/ui/src/main/res/values-da/strings.xml index 71ff36a1a3c..d7486b4b9ac 100644 --- a/libraries/ui/src/main/res/values-da/strings.xml +++ b/libraries/ui/src/main/res/values-da/strings.xml @@ -1,18 +1,4 @@ - Vis afspilningsknapper Skjul afspilningsknapper diff --git a/libraries/ui/src/main/res/values-de/strings.xml b/libraries/ui/src/main/res/values-de/strings.xml index ff160f6a6a5..f035521b139 100644 --- a/libraries/ui/src/main/res/values-de/strings.xml +++ b/libraries/ui/src/main/res/values-de/strings.xml @@ -1,18 +1,4 @@ - Player-Steuerelemente anzeigen Player-Steuerelemente ausblenden diff --git a/libraries/ui/src/main/res/values-el/strings.xml b/libraries/ui/src/main/res/values-el/strings.xml index c4ed289befe..a715576c611 100644 --- a/libraries/ui/src/main/res/values-el/strings.xml +++ b/libraries/ui/src/main/res/values-el/strings.xml @@ -1,18 +1,4 @@ - Εμφάν. στοιχείων ελέγχου προγράμματος αναπαραγωγής Απόκρ. στοιχείων ελέγχου προγράμματος αναπαραγωγής diff --git a/libraries/ui/src/main/res/values-en-rAU/strings.xml b/libraries/ui/src/main/res/values-en-rAU/strings.xml index af859027975..f312573b976 100644 --- a/libraries/ui/src/main/res/values-en-rAU/strings.xml +++ b/libraries/ui/src/main/res/values-en-rAU/strings.xml @@ -1,18 +1,4 @@ - Show player controls Hide player controls diff --git a/libraries/ui/src/main/res/values-en-rGB/strings.xml b/libraries/ui/src/main/res/values-en-rGB/strings.xml index af859027975..f312573b976 100644 --- a/libraries/ui/src/main/res/values-en-rGB/strings.xml +++ b/libraries/ui/src/main/res/values-en-rGB/strings.xml @@ -1,18 +1,4 @@ - Show player controls Hide player controls diff --git a/libraries/ui/src/main/res/values-en-rIN/strings.xml b/libraries/ui/src/main/res/values-en-rIN/strings.xml index af859027975..f312573b976 100644 --- a/libraries/ui/src/main/res/values-en-rIN/strings.xml +++ b/libraries/ui/src/main/res/values-en-rIN/strings.xml @@ -1,18 +1,4 @@ - Show player controls Hide player controls diff --git a/libraries/ui/src/main/res/values-es-rUS/strings.xml b/libraries/ui/src/main/res/values-es-rUS/strings.xml index 0bc0f6c546d..30e3056b704 100644 --- a/libraries/ui/src/main/res/values-es-rUS/strings.xml +++ b/libraries/ui/src/main/res/values-es-rUS/strings.xml @@ -1,18 +1,4 @@ - Mostrar controles del reproductor Ocultar controles del reproductor diff --git a/libraries/ui/src/main/res/values-es/strings.xml b/libraries/ui/src/main/res/values-es/strings.xml index 924d3490388..076f352c128 100644 --- a/libraries/ui/src/main/res/values-es/strings.xml +++ b/libraries/ui/src/main/res/values-es/strings.xml @@ -1,18 +1,4 @@ - Mostrar controles del reproductor Ocultar controles de jugador @@ -47,13 +33,13 @@ Habilitar subtítulos Velocidad - ×0,25 - ×0,5 - ×0,75 + 0,25x + 0,5x + 0,75x Normal - ×1,25 - ×1,5 - ×2 + 1,25x + 1,5x + 2x Vídeo Audio diff --git a/libraries/ui/src/main/res/values-et/strings.xml b/libraries/ui/src/main/res/values-et/strings.xml index faa44e483f4..22dd590ee02 100644 --- a/libraries/ui/src/main/res/values-et/strings.xml +++ b/libraries/ui/src/main/res/values-et/strings.xml @@ -1,18 +1,4 @@ - Kuva pleieri juhtnupud Peida pleieri juhtnupud diff --git a/libraries/ui/src/main/res/values-eu/strings.xml b/libraries/ui/src/main/res/values-eu/strings.xml index 90441518b1a..08fc4df563f 100644 --- a/libraries/ui/src/main/res/values-eu/strings.xml +++ b/libraries/ui/src/main/res/values-eu/strings.xml @@ -1,18 +1,4 @@ - Erakutsi erreproduzigailua kontrolatzeko aukerak Ezkutatu erreproduzigailua kontrolatzeko aukerak diff --git a/libraries/ui/src/main/res/values-fa/strings.xml b/libraries/ui/src/main/res/values-fa/strings.xml index c25aa14a7c4..a7963d437f4 100644 --- a/libraries/ui/src/main/res/values-fa/strings.xml +++ b/libraries/ui/src/main/res/values-fa/strings.xml @@ -1,18 +1,4 @@ - نمایش کنترل‌های پخش‌کننده پنهان کردن کنترل‌های پخش‌کننده diff --git a/libraries/ui/src/main/res/values-fi/strings.xml b/libraries/ui/src/main/res/values-fi/strings.xml index f57744643c0..2ab098e46fe 100644 --- a/libraries/ui/src/main/res/values-fi/strings.xml +++ b/libraries/ui/src/main/res/values-fi/strings.xml @@ -1,18 +1,4 @@ - Näytä soittimen säätimet Näytä soittimen säätimet diff --git a/libraries/ui/src/main/res/values-fr-rCA/strings.xml b/libraries/ui/src/main/res/values-fr-rCA/strings.xml index 5faeb0b5b2a..8b5a19053e7 100644 --- a/libraries/ui/src/main/res/values-fr-rCA/strings.xml +++ b/libraries/ui/src/main/res/values-fr-rCA/strings.xml @@ -1,18 +1,4 @@ - Afficher les commandes du lecteur Masquer les commandes du lecteur diff --git a/libraries/ui/src/main/res/values-fr/strings.xml b/libraries/ui/src/main/res/values-fr/strings.xml index cc876a8bf30..cc2386dcddd 100644 --- a/libraries/ui/src/main/res/values-fr/strings.xml +++ b/libraries/ui/src/main/res/values-fr/strings.xml @@ -1,18 +1,4 @@ - Afficher les commandes du lecteur Masquer les commandes du lecteur diff --git a/libraries/ui/src/main/res/values-gl/strings.xml b/libraries/ui/src/main/res/values-gl/strings.xml index 932434af285..125daae7f89 100644 --- a/libraries/ui/src/main/res/values-gl/strings.xml +++ b/libraries/ui/src/main/res/values-gl/strings.xml @@ -1,18 +1,4 @@ - Mostrar controis do reprodutor Ocultar controis do reprodutor @@ -71,6 +57,6 @@ Complementaria Comentarios Subtítulos - %1$.2f Mbps + %1$.2f Mb/s %1$s, %2$s diff --git a/libraries/ui/src/main/res/values-gu/strings.xml b/libraries/ui/src/main/res/values-gu/strings.xml index 955ccf1f93f..d912bae2919 100644 --- a/libraries/ui/src/main/res/values-gu/strings.xml +++ b/libraries/ui/src/main/res/values-gu/strings.xml @@ -1,18 +1,4 @@ - પ્લેયર માટેના નિયંત્રણો બતાવો પ્લેયર માટેના નિયંત્રણો છુપાવો diff --git a/libraries/ui/src/main/res/values-hi/strings.xml b/libraries/ui/src/main/res/values-hi/strings.xml index fe18f2a16ad..37113b18d42 100644 --- a/libraries/ui/src/main/res/values-hi/strings.xml +++ b/libraries/ui/src/main/res/values-hi/strings.xml @@ -1,18 +1,4 @@ - प्लेयर नियंत्रण दिखाएं प्लेयर नियंत्रण छिपाएं diff --git a/libraries/ui/src/main/res/values-hr/strings.xml b/libraries/ui/src/main/res/values-hr/strings.xml index 320e47aef83..f58e02d5307 100644 --- a/libraries/ui/src/main/res/values-hr/strings.xml +++ b/libraries/ui/src/main/res/values-hr/strings.xml @@ -1,18 +1,4 @@ - Prikaži kontrole playera Sakrij kontrole playera diff --git a/libraries/ui/src/main/res/values-hu/strings.xml b/libraries/ui/src/main/res/values-hu/strings.xml index 7f24082f549..66801d37092 100644 --- a/libraries/ui/src/main/res/values-hu/strings.xml +++ b/libraries/ui/src/main/res/values-hu/strings.xml @@ -1,18 +1,4 @@ - Lejátszásvezérlők mutatása Lejátszásvezérlők elrejtése diff --git a/libraries/ui/src/main/res/values-hy/strings.xml b/libraries/ui/src/main/res/values-hy/strings.xml index f77b1831189..5171913fbe9 100644 --- a/libraries/ui/src/main/res/values-hy/strings.xml +++ b/libraries/ui/src/main/res/values-hy/strings.xml @@ -1,18 +1,4 @@ - Ցուցադրել նվագարկչի կառավարները Թաքցնել նվագարկչի կառավարները diff --git a/libraries/ui/src/main/res/values-in/strings.xml b/libraries/ui/src/main/res/values-in/strings.xml index b010d3c7392..9afe0208caf 100644 --- a/libraries/ui/src/main/res/values-in/strings.xml +++ b/libraries/ui/src/main/res/values-in/strings.xml @@ -1,18 +1,4 @@ - Menampilkan kontrol pemutar Menyembunyikan kontrol pemutar diff --git a/libraries/ui/src/main/res/values-is/strings.xml b/libraries/ui/src/main/res/values-is/strings.xml index 20f603c476c..fe4d96f02c0 100644 --- a/libraries/ui/src/main/res/values-is/strings.xml +++ b/libraries/ui/src/main/res/values-is/strings.xml @@ -1,18 +1,4 @@ - Sýna spilunarstýringar Fela spilunarstýringar diff --git a/libraries/ui/src/main/res/values-it/strings.xml b/libraries/ui/src/main/res/values-it/strings.xml index b97ae066454..c6f6c12d00a 100644 --- a/libraries/ui/src/main/res/values-it/strings.xml +++ b/libraries/ui/src/main/res/values-it/strings.xml @@ -1,18 +1,4 @@ - Mostra i controlli del player Nascondi i controlli del player diff --git a/libraries/ui/src/main/res/values-iw/strings.xml b/libraries/ui/src/main/res/values-iw/strings.xml index c5499212c4a..0b61a2c4342 100644 --- a/libraries/ui/src/main/res/values-iw/strings.xml +++ b/libraries/ui/src/main/res/values-iw/strings.xml @@ -1,32 +1,4 @@ - - הצגת פקדי הנגן הסתרת פקדי הנגן @@ -43,16 +15,14 @@ הפסקה הרצה אחורה - הרצה שנייה אחת (%d) אחורה + הרצה %d שניות אחורה הרצה %d שניות אחורה - הרצה %d שניות אחורה הרצה %d שניות אחורה הרצה קדימה - הרצה שנייה אחת (%d) קדימה + הרצה %d שניות קדימה הרצה %d שניות קדימה - הרצה %d שניות קדימה הרצה %d שניות קדימה המצב הנוכחי: ללא חזרה. לחצן להחלפת מצב החזרה. diff --git a/libraries/ui/src/main/res/values-ja/strings.xml b/libraries/ui/src/main/res/values-ja/strings.xml index f8970f64ee5..c5017b3c72b 100644 --- a/libraries/ui/src/main/res/values-ja/strings.xml +++ b/libraries/ui/src/main/res/values-ja/strings.xml @@ -1,18 +1,4 @@ - プレーヤーのコントロールを表示する プレーヤーのコントロールを非表示にする diff --git a/libraries/ui/src/main/res/values-ka/strings.xml b/libraries/ui/src/main/res/values-ka/strings.xml index 2ff75b72dd6..65c048bff70 100644 --- a/libraries/ui/src/main/res/values-ka/strings.xml +++ b/libraries/ui/src/main/res/values-ka/strings.xml @@ -1,18 +1,4 @@ - დამკვრელის სამართავი ღილაკების ჩვენება დამკვრელის სამართავი ღილაკების დამალვა diff --git a/libraries/ui/src/main/res/values-kk/strings.xml b/libraries/ui/src/main/res/values-kk/strings.xml index 86d41df02bb..3296c2b5575 100644 --- a/libraries/ui/src/main/res/values-kk/strings.xml +++ b/libraries/ui/src/main/res/values-kk/strings.xml @@ -1,18 +1,4 @@ - Ойнатқышты басқару элементтерін көрсету Ойнатқышты басқару элементтерін жасыру @@ -37,9 +23,9 @@ %d секунд алға айналдыру %d секунд алға айналдыру - Қазіргі режим: еш мазмұн қайталанбайды. Қайталау режимін ауыстыру. - Қазіргі режим: бір мазмұн қайталанады. Қайталау режимін ауыстыру. - Қазіргі режим: барлық мазмұн қайталанады Қайталау режимін ауыстыру. + Қазіргі режим: еш контент қайталанбайды. Қайталау режимін ауыстыру. + Қазіргі режим: бір контент қайталанады. Қайталау режимін ауыстыру. + Қазіргі режим: барлық контент қайталанады Қайталау режимін ауыстыру. Араластыру режимін өшіру Араластыру режимін қосу VR режимі diff --git a/libraries/ui/src/main/res/values-km/strings.xml b/libraries/ui/src/main/res/values-km/strings.xml index 3e8fd004a16..c8da4e15a96 100644 --- a/libraries/ui/src/main/res/values-km/strings.xml +++ b/libraries/ui/src/main/res/values-km/strings.xml @@ -1,18 +1,4 @@ - បង្ហាញការគ្រប់គ្រងកម្មវិធីចាក់ចម្រៀង លាក់ការគ្រប់គ្រងកម្មវិធីចាក់ចម្រៀង diff --git a/libraries/ui/src/main/res/values-kn/strings.xml b/libraries/ui/src/main/res/values-kn/strings.xml index 45b2417f5b8..5dcf85112df 100644 --- a/libraries/ui/src/main/res/values-kn/strings.xml +++ b/libraries/ui/src/main/res/values-kn/strings.xml @@ -1,18 +1,4 @@ - ಪ್ಲೇಯರ್ ನಿಯಂತ್ರಣಗಳನ್ನು ತೋರಿಸಿ ಪ್ಲೇಯರ್ ನಿಯಂತ್ರಣಗಳನ್ನು ಮರೆಮಾಡಿ diff --git a/libraries/ui/src/main/res/values-ko/strings.xml b/libraries/ui/src/main/res/values-ko/strings.xml index b6e8d231ea4..d0a0f942c50 100644 --- a/libraries/ui/src/main/res/values-ko/strings.xml +++ b/libraries/ui/src/main/res/values-ko/strings.xml @@ -1,18 +1,4 @@ - 플레이어 컨트롤 표시 플레이어 컨트롤 숨기기 diff --git a/libraries/ui/src/main/res/values-ky/strings.xml b/libraries/ui/src/main/res/values-ky/strings.xml index 29601c0253a..818f69e1ead 100644 --- a/libraries/ui/src/main/res/values-ky/strings.xml +++ b/libraries/ui/src/main/res/values-ky/strings.xml @@ -1,23 +1,9 @@ - Ойноткучту башкаруу элементтерин көрсөтүү Ойноткучту башкаруу элементтерин жашыруу Ойнотуу көрсөткүчү - Жөндөөлөр + Параметрлер Кошумча жөндөөлөрдү жашыруу Кошумча жөндөөлөрдү көрсөтүү Толук экранга кирүү diff --git a/libraries/ui/src/main/res/values-lo/strings.xml b/libraries/ui/src/main/res/values-lo/strings.xml index bd0f103425b..3126375a156 100644 --- a/libraries/ui/src/main/res/values-lo/strings.xml +++ b/libraries/ui/src/main/res/values-lo/strings.xml @@ -1,18 +1,4 @@ - ສະ​ແດງຕົວຄວບ​ຄຸມ​ເຄື່ອງ​ຫຼິ້ນ ເຊື່ອງຕົວຄວບ​ຄຸມ​ເຄື່ອງ​ຫຼິ້ນ diff --git a/libraries/ui/src/main/res/values-lt/strings.xml b/libraries/ui/src/main/res/values-lt/strings.xml index f1d221e9bf6..020629ad608 100644 --- a/libraries/ui/src/main/res/values-lt/strings.xml +++ b/libraries/ui/src/main/res/values-lt/strings.xml @@ -1,18 +1,4 @@ - Rodyti leistuvės valdiklius Slėpti leistuvės valdiklius diff --git a/libraries/ui/src/main/res/values-lv/strings.xml b/libraries/ui/src/main/res/values-lv/strings.xml index 0d0ec51c3c6..ef264ca156b 100644 --- a/libraries/ui/src/main/res/values-lv/strings.xml +++ b/libraries/ui/src/main/res/values-lv/strings.xml @@ -1,18 +1,4 @@ - Rādīt atskaņotāja vadīklas Slēpt atskaņotāja vadīklas diff --git a/libraries/ui/src/main/res/values-mk/strings.xml b/libraries/ui/src/main/res/values-mk/strings.xml index a5d13326e4d..95fe201eb9c 100644 --- a/libraries/ui/src/main/res/values-mk/strings.xml +++ b/libraries/ui/src/main/res/values-mk/strings.xml @@ -1,18 +1,4 @@ - Прикажи ги контролите на плеерот Сокриј ги контролите на плеерот diff --git a/libraries/ui/src/main/res/values-ml/strings.xml b/libraries/ui/src/main/res/values-ml/strings.xml index 4d1e4e995a8..984452145e8 100644 --- a/libraries/ui/src/main/res/values-ml/strings.xml +++ b/libraries/ui/src/main/res/values-ml/strings.xml @@ -1,18 +1,4 @@ - പ്ലേയർ നിയന്ത്രണങ്ങൾ കാണിക്കുക പ്ലേയർ നിയന്ത്രണങ്ങൾ മറയ്ക്കുക @@ -59,7 +45,7 @@ ഓഡിയോ ടെക്‌സ്റ്റ് ഒന്നുമില്ല - സ്വമേധയാ + സ്വയമേവ അജ്ഞാതം %1$d × %2$d മോണോ diff --git a/libraries/ui/src/main/res/values-mn/strings.xml b/libraries/ui/src/main/res/values-mn/strings.xml index 56273ce0e51..667ef287b93 100644 --- a/libraries/ui/src/main/res/values-mn/strings.xml +++ b/libraries/ui/src/main/res/values-mn/strings.xml @@ -1,18 +1,4 @@ - Тоглуулагчийн удирдлагыг харуулах Тоглуулагчийн удирдлагыг нуух diff --git a/libraries/ui/src/main/res/values-mr/strings.xml b/libraries/ui/src/main/res/values-mr/strings.xml index 303f5ca52f6..ffde009be05 100644 --- a/libraries/ui/src/main/res/values-mr/strings.xml +++ b/libraries/ui/src/main/res/values-mr/strings.xml @@ -1,18 +1,4 @@ - प्लेअर नियंत्रणे दर्शवा प्लेअर नियंत्रणे लपवा diff --git a/libraries/ui/src/main/res/values-ms/strings.xml b/libraries/ui/src/main/res/values-ms/strings.xml index 2758851781c..f051ca62645 100644 --- a/libraries/ui/src/main/res/values-ms/strings.xml +++ b/libraries/ui/src/main/res/values-ms/strings.xml @@ -1,18 +1,4 @@ - Tunjukkan kawalan pemain Sembunyikan kawalan pemain diff --git a/libraries/ui/src/main/res/values-my/strings.xml b/libraries/ui/src/main/res/values-my/strings.xml index 89ad8e56361..eaa9531ee9c 100644 --- a/libraries/ui/src/main/res/values-my/strings.xml +++ b/libraries/ui/src/main/res/values-my/strings.xml @@ -1,18 +1,4 @@ - ပလေယာ ခလုတ်များကို ပြရန် ပလေယာ ခလုတ်များကို ဝှက်ရန် diff --git a/libraries/ui/src/main/res/values-nb/strings.xml b/libraries/ui/src/main/res/values-nb/strings.xml index 075270b6dc6..e444db3ebec 100644 --- a/libraries/ui/src/main/res/values-nb/strings.xml +++ b/libraries/ui/src/main/res/values-nb/strings.xml @@ -1,18 +1,4 @@ - Vis avspillingskontrollene Skjul avspillingskontrollene diff --git a/libraries/ui/src/main/res/values-ne/strings.xml b/libraries/ui/src/main/res/values-ne/strings.xml index 586aea713f8..bf8d43e1d73 100644 --- a/libraries/ui/src/main/res/values-ne/strings.xml +++ b/libraries/ui/src/main/res/values-ne/strings.xml @@ -1,18 +1,4 @@ - प्लेयरसम्बन्धी नियन्त्रणहरू देखाउनुहोस् प्लेयरसम्बन्धी नियन्त्रणहरू लुकाउनुहोस् diff --git a/libraries/ui/src/main/res/values-nl/strings.xml b/libraries/ui/src/main/res/values-nl/strings.xml index eaf36592007..2a1f32bcdc6 100644 --- a/libraries/ui/src/main/res/values-nl/strings.xml +++ b/libraries/ui/src/main/res/values-nl/strings.xml @@ -1,18 +1,4 @@ - Afspeelbediening tonen Afspeelbediening verbergen diff --git a/libraries/ui/src/main/res/values-pa/strings.xml b/libraries/ui/src/main/res/values-pa/strings.xml index e2579cd646a..2c882f2d37e 100644 --- a/libraries/ui/src/main/res/values-pa/strings.xml +++ b/libraries/ui/src/main/res/values-pa/strings.xml @@ -1,18 +1,4 @@ - ਪਲੇਅਰ ਕੰਟਰੋਲਾਂ ਨੂੰ ਦਿਖਾਓ ਪਲੇਅਰ ਕੰਟਰੋਲਾਂ ਨੂੰ ਲੁਕਾਓ diff --git a/libraries/ui/src/main/res/values-pl/strings.xml b/libraries/ui/src/main/res/values-pl/strings.xml index ec5bfca1589..f6489e8cef8 100644 --- a/libraries/ui/src/main/res/values-pl/strings.xml +++ b/libraries/ui/src/main/res/values-pl/strings.xml @@ -1,18 +1,4 @@ - Pokaż elementy sterujące odtwarzacza Ukryj elementy sterujące odtwarzacza diff --git a/libraries/ui/src/main/res/values-pt-rPT/strings.xml b/libraries/ui/src/main/res/values-pt-rPT/strings.xml index 6e70f79c534..76aa421cab8 100644 --- a/libraries/ui/src/main/res/values-pt-rPT/strings.xml +++ b/libraries/ui/src/main/res/values-pt-rPT/strings.xml @@ -1,18 +1,4 @@ - Mostrar controlos do leitor Ocultar controlos do leitor diff --git a/libraries/ui/src/main/res/values-pt/strings.xml b/libraries/ui/src/main/res/values-pt/strings.xml index 80a7f426695..be152306b02 100644 --- a/libraries/ui/src/main/res/values-pt/strings.xml +++ b/libraries/ui/src/main/res/values-pt/strings.xml @@ -1,18 +1,4 @@ - Mostrar controles do player Ocultar controles do player diff --git a/libraries/ui/src/main/res/values-ro/strings.xml b/libraries/ui/src/main/res/values-ro/strings.xml index 0448518b56d..d67cc4c3a9e 100644 --- a/libraries/ui/src/main/res/values-ro/strings.xml +++ b/libraries/ui/src/main/res/values-ro/strings.xml @@ -1,52 +1,38 @@ - Afișează comenzile playerului Ascunde comenzile playerului Progresul redării Setări - Ascundeți setările suplimentare - Afișați setările suplimentare - Accesați în ecran complet - Ieșiți din ecranul complet + Ascunde setările suplimentare + Afișează setările suplimentare + Accesează în ecran complet + Ieși din ecranul complet Înapoi Înainte - Întrerupeți - Redați - Opriți - Derulați înapoi + Întrerupe + Redă + Oprește + Derulează înapoi Derulează înapoi cu %d secundă Derulează înapoi cu %d secunde Derulează înapoi cu %d de secunde - Derulați rapid înainte + Derulează rapid înainte Derulează rapid înainte cu %d secundă Derulează rapid înainte cu %d secunde Derulează rapid înainte cu %d de secunde - Mod actual: nu se repetă. Comutați modul repetare. - Mod actual: se repetă una. Comutați modul repetare. - Mod curent: se repetă tot. Comutați modul repetare. - Dezactivați modul sortare aleatorie - Activați modul sortare aleatorie + Mod actual: nu se repetă. Comută modul repetare. + Mod actual: se repetă una. Comută modul repetare. + Mod curent: se repetă tot. Comută modul repetare. + Dezactivează modul sortare aleatorie + Activează modul sortare aleatorie Mod RV - Dezactivați subtitrările - Activați subtitrările + Dezactivează subtitrările + Activează subtitrările Viteză 0,25x diff --git a/libraries/ui/src/main/res/values-ru/strings.xml b/libraries/ui/src/main/res/values-ru/strings.xml index 36d9b4c01e8..d08bfeb7583 100644 --- a/libraries/ui/src/main/res/values-ru/strings.xml +++ b/libraries/ui/src/main/res/values-ru/strings.xml @@ -1,18 +1,4 @@ - Показать панель управления Скрыть панель управления diff --git a/libraries/ui/src/main/res/values-si/strings.xml b/libraries/ui/src/main/res/values-si/strings.xml index a78f8597187..e19521ca7b2 100644 --- a/libraries/ui/src/main/res/values-si/strings.xml +++ b/libraries/ui/src/main/res/values-si/strings.xml @@ -1,18 +1,4 @@ - ධාවක පාලන පෙන්වන්න ධාවක පාලන සඟවන්න diff --git a/libraries/ui/src/main/res/values-sk/strings.xml b/libraries/ui/src/main/res/values-sk/strings.xml index 75204eed520..abb31c30ce2 100644 --- a/libraries/ui/src/main/res/values-sk/strings.xml +++ b/libraries/ui/src/main/res/values-sk/strings.xml @@ -1,18 +1,4 @@ - Zobraziť ovládacie prvky prehrávača Skryť ovládacie prvky prehrávača diff --git a/libraries/ui/src/main/res/values-sl/strings.xml b/libraries/ui/src/main/res/values-sl/strings.xml index 5bc58e7ae8b..77c82d17282 100644 --- a/libraries/ui/src/main/res/values-sl/strings.xml +++ b/libraries/ui/src/main/res/values-sl/strings.xml @@ -1,18 +1,4 @@ - Prikaz kontrolnikov predvajalnika Skrivanje kontrolnikov predvajalnika diff --git a/libraries/ui/src/main/res/values-sq/strings.xml b/libraries/ui/src/main/res/values-sq/strings.xml index 0357753ac88..b814f210a9b 100644 --- a/libraries/ui/src/main/res/values-sq/strings.xml +++ b/libraries/ui/src/main/res/values-sq/strings.xml @@ -1,18 +1,4 @@ - Shfaq komandat e luajtësit Fshih komandat e luajtësit diff --git a/libraries/ui/src/main/res/values-sr/strings.xml b/libraries/ui/src/main/res/values-sr/strings.xml index d20d287b1cc..23ce2ca335a 100644 --- a/libraries/ui/src/main/res/values-sr/strings.xml +++ b/libraries/ui/src/main/res/values-sr/strings.xml @@ -1,18 +1,4 @@ - Прикажи контроле плејера Сакриј контроле плејера diff --git a/libraries/ui/src/main/res/values-sv/strings.xml b/libraries/ui/src/main/res/values-sv/strings.xml index 73edb04ff01..64b401a72d3 100644 --- a/libraries/ui/src/main/res/values-sv/strings.xml +++ b/libraries/ui/src/main/res/values-sv/strings.xml @@ -1,18 +1,4 @@ - Visa spelarkontroller Dölj spelarkontroller diff --git a/libraries/ui/src/main/res/values-sw/strings.xml b/libraries/ui/src/main/res/values-sw/strings.xml index 015e31701de..02308a65cac 100644 --- a/libraries/ui/src/main/res/values-sw/strings.xml +++ b/libraries/ui/src/main/res/values-sw/strings.xml @@ -1,18 +1,4 @@ - Onyesha vidhibiti vya kichezaji Ficha vidhibiti vya kichezaji diff --git a/libraries/ui/src/main/res/values-ta/strings.xml b/libraries/ui/src/main/res/values-ta/strings.xml index 36172865b90..bdae9c86327 100644 --- a/libraries/ui/src/main/res/values-ta/strings.xml +++ b/libraries/ui/src/main/res/values-ta/strings.xml @@ -1,18 +1,4 @@ - பிளேயர் கட்டுப்பாடுகளைக் காட்டும் பிளேயர் கட்டுப்பாடுகளை மறைக்கும் diff --git a/libraries/ui/src/main/res/values-te/strings.xml b/libraries/ui/src/main/res/values-te/strings.xml index 124b8a99bab..7485b6b4232 100644 --- a/libraries/ui/src/main/res/values-te/strings.xml +++ b/libraries/ui/src/main/res/values-te/strings.xml @@ -1,18 +1,4 @@ - ప్లేయర్ నియంత్రణలను చూపు ప్లేయర్ నియంత్రణలను దాచిపెట్టు @@ -21,7 +7,7 @@ అదనపు సెట్టింగ్‌లను దాచు అదనపు సెట్టింగ్‌లను చూపు ఫుల్ స్క్రీన్‌లోకి ప్రవేశించు - ఫుల్ స్క్రీన్ నుండి నిష్క్రమించు + ఫుల్ స్క్రీన్ నుండి నిష్క్రమించండి మునుపటి తర్వాత పాజ్ చేయండి @@ -32,14 +18,14 @@ %d సెకండ్ రివైండ్ చేయండి %d సెకన్లు రివైండ్ చేయండి - వేగంగా ఫార్వార్డ్ చేయండి + వేగంగా ఫార్వర్డ్ చేయండి %d సెకండ్ వేగంగా ఫార్వర్డ్ చేయండి %d సెకన్లు వేగంగా ఫార్వర్డ్ చేయండి - ప్రస్తుత మోడ్: ఏదీ పునరావృతం చేయవద్దు. పునరావృతం మోడ్‌ను టోగుల్ చేయండి. - ప్రస్తుత మోడ్: ఒకదానిని పునరావృతం చేయండి. పునరావృతం మోడ్‌ను టోగుల్ చేయండి. - ప్రస్తుత మోడ్: అన్నింటిని పునరావృతం చేయండి. పునరావృతం మోడ్‌ను టోగుల్ చేయండి. + ప్రస్తుత మోడ్: ఏదీ రిపీట్‌ చేయవద్దు. రిపీట్‌ మోడ్‌ను టోగుల్ చేయండి. + ప్రస్తుత మోడ్: ఒకదానిని రిపీట్‌ చేయండి. రిపీట్‌ మోడ్‌ను టోగుల్ చేయండి. + ప్రస్తుత మోడ్: అన్నింటిని రిపీట్‌ చేయండి. రిపీట్‌ మోడ్‌ను టోగుల్ చేయండి. షఫుల్ మోడ్‌ను డిజేబుల్ చేయండి షఫుల్ మోడ్‌ను ఎనేబుల్ చేయండి వర్చువల్ రియాలిటీ మోడ్ diff --git a/libraries/ui/src/main/res/values-th/strings.xml b/libraries/ui/src/main/res/values-th/strings.xml index fdb108348e3..5584dcf93c3 100644 --- a/libraries/ui/src/main/res/values-th/strings.xml +++ b/libraries/ui/src/main/res/values-th/strings.xml @@ -1,18 +1,4 @@ - แสดงแผงควบคุมโปรแกรมเล่น ซ่อนตัวควบคุมโปรแกรมเล่น diff --git a/libraries/ui/src/main/res/values-tl/strings.xml b/libraries/ui/src/main/res/values-tl/strings.xml index 0757b261da3..04c4c2fa685 100644 --- a/libraries/ui/src/main/res/values-tl/strings.xml +++ b/libraries/ui/src/main/res/values-tl/strings.xml @@ -1,18 +1,4 @@ - Ipakita ang mga kontrol ng player Itago ang mga kontrol ng player diff --git a/libraries/ui/src/main/res/values-tr/strings.xml b/libraries/ui/src/main/res/values-tr/strings.xml index b2fd8b6fa4f..6058a4c36f6 100644 --- a/libraries/ui/src/main/res/values-tr/strings.xml +++ b/libraries/ui/src/main/res/values-tr/strings.xml @@ -1,18 +1,4 @@ - Oynatıcı kontrollerini göster Oynatıcı kontrollerini gizle diff --git a/libraries/ui/src/main/res/values-uk/strings.xml b/libraries/ui/src/main/res/values-uk/strings.xml index 2ffcc61d1cd..7d3307db51c 100644 --- a/libraries/ui/src/main/res/values-uk/strings.xml +++ b/libraries/ui/src/main/res/values-uk/strings.xml @@ -1,18 +1,4 @@ - Показувати елементи керування програвачем Сховати елементи керування програвачем diff --git a/libraries/ui/src/main/res/values-ur/strings.xml b/libraries/ui/src/main/res/values-ur/strings.xml index 1e410c9712e..0c49e5d4454 100644 --- a/libraries/ui/src/main/res/values-ur/strings.xml +++ b/libraries/ui/src/main/res/values-ur/strings.xml @@ -1,18 +1,4 @@ - پلیئر کنٹرولز دکھائیں پلیئر کنٹرولز چھپائیں diff --git a/libraries/ui/src/main/res/values-uz/strings.xml b/libraries/ui/src/main/res/values-uz/strings.xml index f7639dd95b6..7b173200947 100644 --- a/libraries/ui/src/main/res/values-uz/strings.xml +++ b/libraries/ui/src/main/res/values-uz/strings.xml @@ -1,18 +1,4 @@ - Pleyer tugmalarini chiqarish Pleyer tugmalarini berkitish diff --git a/libraries/ui/src/main/res/values-vi/strings.xml b/libraries/ui/src/main/res/values-vi/strings.xml index 400d321f5e5..1749d4f5ddd 100644 --- a/libraries/ui/src/main/res/values-vi/strings.xml +++ b/libraries/ui/src/main/res/values-vi/strings.xml @@ -1,18 +1,4 @@ - Hiển thị các nút điều khiển trình phát Ẩn các nút điều khiển trình phát diff --git a/libraries/ui/src/main/res/values-zh-rCN/strings.xml b/libraries/ui/src/main/res/values-zh-rCN/strings.xml index 4fedf2ae07b..d32d6a44829 100644 --- a/libraries/ui/src/main/res/values-zh-rCN/strings.xml +++ b/libraries/ui/src/main/res/values-zh-rCN/strings.xml @@ -1,18 +1,4 @@ - 显示播放器控件 隐藏播放器控件 diff --git a/libraries/ui/src/main/res/values-zh-rHK/strings.xml b/libraries/ui/src/main/res/values-zh-rHK/strings.xml index 88a0239c57f..354f58c69ab 100644 --- a/libraries/ui/src/main/res/values-zh-rHK/strings.xml +++ b/libraries/ui/src/main/res/values-zh-rHK/strings.xml @@ -1,18 +1,4 @@ - 顯示播放器控制項 隱藏播放器控制項 diff --git a/libraries/ui/src/main/res/values-zh-rTW/strings.xml b/libraries/ui/src/main/res/values-zh-rTW/strings.xml index 27dc2bcfd61..4249568e953 100644 --- a/libraries/ui/src/main/res/values-zh-rTW/strings.xml +++ b/libraries/ui/src/main/res/values-zh-rTW/strings.xml @@ -1,18 +1,4 @@ - 顯示播放器控制選項 隱藏播放器控制選項 diff --git a/libraries/ui/src/main/res/values-zu/strings.xml b/libraries/ui/src/main/res/values-zu/strings.xml index 05d78e556e6..7752fcb7722 100644 --- a/libraries/ui/src/main/res/values-zu/strings.xml +++ b/libraries/ui/src/main/res/values-zu/strings.xml @@ -1,18 +1,4 @@ - Bonisa izilawuli zesidlali Fihla izilawuli zesidlali From 7d6a359a8558b03eaf183e0ce20728aefa5a529f Mon Sep 17 00:00:00 2001 From: christosts Date: Tue, 28 Feb 2023 12:46:21 +0000 Subject: [PATCH 25/33] Minor change in ForwardingPlayer javadoc #minor-release PiperOrigin-RevId: 512897269 (cherry picked from commit 42fae152d0ad381c8bbb0858f596770529f11f40) --- .../src/main/java/androidx/media3/common/ForwardingPlayer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java index 2640a0a7e46..957ab7d2194 100644 --- a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java +++ b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java @@ -28,7 +28,7 @@ import java.util.List; /** - * A {@link Player} that forwards operations to another {@link Player}. Applications can use this + * A {@link Player} that forwards method calls to another {@link Player}. Applications can use this * class to suppress or modify specific operations, by overriding the respective methods. */ @UnstableApi From ddd5e9bc19ae3c5a6ecd3e345ff38080e5aa4b96 Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 1 Mar 2023 10:21:05 +0000 Subject: [PATCH 26/33] Remove @see tags with tags These are not supported by Dackka #minor-release PiperOrigin-RevId: 513176533 (cherry picked from commit c07cf3dc414b562652cdd4f3b0e91f80493a2c40) --- .../media3/common/util/ColorParser.java | 8 +++-- .../exoplayer/upstream/SlidingPercentile.java | 8 +++-- .../smoothstreaming/manifest/SsManifest.java | 4 +-- .../manifest/SsManifestParser.java | 4 +-- .../media3/extractor/FlacStreamMetadata.java | 20 +++++++----- .../media3/extractor/VorbisBitArray.java | 4 +-- .../androidx/media3/extractor/VorbisUtil.java | 32 +++++++++++-------- .../extractor/text/ttml/TtmlDecoder.java | 2 +- .../extractor/text/webvtt/WebvttCssStyle.java | 6 ++-- .../extractor/text/webvtt/WebvttDecoder.java | 2 +- .../extractor/text/ttml/TtmlDecoderTest.java | 11 +++---- .../media3/transformer/MssimCalculator.java | 2 +- 12 files changed, 59 insertions(+), 44 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/ColorParser.java b/libraries/common/src/main/java/androidx/media3/common/util/ColorParser.java index 3d1f7a6349d..f0550b07895 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/ColorParser.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/ColorParser.java @@ -27,8 +27,12 @@ /** * Parser for color expressions found in styling formats, e.g. TTML and CSS. * - * @see WebVTT CSS Styling - * @see Timed Text Markup Language 2 (TTML2) - 10.3.5 + *

See also: + * + *

*/ @UnstableApi public final class ColorParser { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/SlidingPercentile.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/SlidingPercentile.java index ca3d0fadbc9..b555b3c40fc 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/SlidingPercentile.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/SlidingPercentile.java @@ -30,8 +30,12 @@ * rate observations. This is an alternative to sliding mean and exponential averaging which suffer * from susceptibility to outliers and slow adaptation to step functions. * - * @see Wiki: Moving average - * @see Wiki: Selection algorithm + *

See the following Wikipedia articles: + * + *

*/ @UnstableApi public class SlidingPercentile { diff --git a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifest.java b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifest.java index 38c17af3957..ccc9663ac8c 100644 --- a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifest.java +++ b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifest.java @@ -34,8 +34,8 @@ /** * Represents a SmoothStreaming manifest. * - * @see IIS Smooth - * Streaming Client Manifest Format + *

See the IIS Smooth + * Streaming Client Manifest Format */ @UnstableApi public class SsManifest implements FilterableManifest { diff --git a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifestParser.java b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifestParser.java index 6ac0a245601..4160e6b3a91 100644 --- a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifestParser.java +++ b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/manifest/SsManifestParser.java @@ -51,8 +51,8 @@ /** * Parses SmoothStreaming client manifests. * - * @see IIS Smooth - * Streaming Client Manifest Format + *

See the IIS Smooth + * Streaming Client Manifest Format */ @UnstableApi public class SsManifestParser implements ParsingLoadable.Parser { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/FlacStreamMetadata.java b/libraries/extractor/src/main/java/androidx/media3/extractor/FlacStreamMetadata.java index debb1f84a8a..7c2a9712cec 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/FlacStreamMetadata.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/FlacStreamMetadata.java @@ -33,14 +33,18 @@ /** * Holder for FLAC metadata. * - * @see FLAC format - * METADATA_BLOCK_STREAMINFO - * @see FLAC format - * METADATA_BLOCK_SEEKTABLE - * @see FLAC format - * METADATA_BLOCK_VORBIS_COMMENT - * @see FLAC format - * METADATA_BLOCK_PICTURE + *

See the following spec references: + * + *

*/ @UnstableApi public final class FlacStreamMetadata { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisBitArray.java b/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisBitArray.java index a1bfbbe059b..40e4b1392c3 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisBitArray.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisBitArray.java @@ -23,8 +23,8 @@ /** * Wraps a byte array, providing methods that allow it to be read as a Vorbis bitstream. * - * @see Vorbis bitpacking - * specification + *

See the Vorbis + * bitpacking specification */ @UnstableApi public final class VorbisBitArray { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisUtil.java index 240afed6db0..68832975f18 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/VorbisUtil.java @@ -52,8 +52,8 @@ public CommentHeader(String vendor, String[] comments, int length) { /** * Vorbis identification header. * - * @see Vorbis - * spec/Identification header + *

See the Vorbis + * spec/Identification header */ public static final class VorbisIdHeader { @@ -135,8 +135,9 @@ public Mode(boolean blockFlag, int windowType, int transformType, int mapping) { /** * Returns ilog(x), which is the index of the highest set bit in {@code x}. * - * @see Vorbis - * spec + *

See the Vorbis + * spec + * * @param x the value of which the ilog should be calculated. * @return ilog(x) */ @@ -152,8 +153,9 @@ public static int iLog(int x) { /** * Reads a Vorbis identification header from {@code headerData}. * - * @see Vorbis - * spec/Identification header + *

See the Vorbis + * spec/Identification header + * * @param headerData a {@link ParsableByteArray} wrapping the header data. * @return a {@link VorbisUtil.VorbisIdHeader} with meta data. * @throws ParserException thrown if invalid capture pattern is detected. @@ -202,8 +204,9 @@ public static VorbisIdHeader readVorbisIdentificationHeader(ParsableByteArray he /** * Reads a Vorbis comment header. * - * @see Vorbis - * spec/Comment header + *

See the Vorbis + * spec/Comment header + * * @param headerData A {@link ParsableByteArray} wrapping the header data. * @return A {@link VorbisUtil.CommentHeader} with all the comments. * @throws ParserException If an error occurs parsing the comment header. @@ -219,8 +222,9 @@ public static CommentHeader readVorbisCommentHeader(ParsableByteArray headerData * *

The data provided may not contain the Vorbis metadata common header and the framing bit. * - * @see Vorbis - * spec/Comment header + *

See the Vorbis + * spec/Comment header + * * @param headerData A {@link ParsableByteArray} wrapping the header data. * @param hasMetadataHeader Whether the {@code headerData} contains a Vorbis metadata common * header preceding the comment header. @@ -349,8 +353,9 @@ public static boolean verifyVorbisHeaderCapturePattern( * That's why we need to partially decode or at least read the entire setup header to know where * to start reading the modes. * - * @see Vorbis - * spec/Setup header + *

See the Vorbis + * spec/Setup header + * * @param headerData a {@link ParsableByteArray} containing setup header data. * @param channels the number of channels. * @return an array of {@link Mode}s. @@ -592,7 +597,8 @@ private static CodeBook readBook(VorbisBitArray bitArray) throws ParserException } /** - * @see _book_maptype1_quantvals + * See the _book_maptype1_quantvals */ private static long mapType1QuantValues(long entries, long dimension) { return (long) Math.floor(Math.pow(entries, 1.d / dimension)); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlDecoder.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlDecoder.java index b5f53a35fb4..f9dea101f13 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlDecoder.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlDecoder.java @@ -65,7 +65,7 @@ *

  • cell-resolution * * - * @see TTML specification + *

    See the TTML specification */ @UnstableApi public final class TtmlDecoder extends SimpleSubtitleDecoder { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttCssStyle.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttCssStyle.java index 623f8fd057c..e27eefdb0fe 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttCssStyle.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttCssStyle.java @@ -36,10 +36,10 @@ import java.util.Set; /** - * Style object of a Css style block in a Webvtt file. + * Style object of a CSS style block in a WebVTT file. * - * @see W3C specification - Apply - * CSS properties + *

    See the Apply CSS properties + * section of the W3C specification */ @UnstableApi public final class WebvttCssStyle { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttDecoder.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttDecoder.java index 6a0daf58930..cb74c2b6ab9 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttDecoder.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttDecoder.java @@ -29,7 +29,7 @@ /** * A {@link SimpleSubtitleDecoder} for WebVTT. * - * @see WebVTT specification + *

    See the WebVTT specification. */ @UnstableApi public final class WebvttDecoder extends SimpleSubtitleDecoder { diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/text/ttml/TtmlDecoderTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/text/ttml/TtmlDecoderTest.java index 78b7a4def73..c1b9a69fec5 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/text/ttml/TtmlDecoderTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/text/ttml/TtmlDecoderTest.java @@ -112,14 +112,11 @@ public void inheritInlineAttributes() throws IOException, SubtitleDecoderExcepti * Regression test for devices on JellyBean where some named colors are not correctly defined on * framework level. Tests that lime resolves to #FF00FF00 not #00FF00 * . - * - * @throws IOException thrown if reading subtitle file fails. - * @see - * JellyBean Color - * Kitkat Color */ + // JellyBean Color: + // https://github.com/android/platform_frameworks_base/blob/jb-mr2-release/graphics/java/android/graphics/Color.java#L414 + // KitKat Color: + // https://github.com/android/platform_frameworks_base/blob/kitkat-mr2.2-release/graphics/java/android/graphics/Color.java#L414 @Test public void lime() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/MssimCalculator.java b/libraries/transformer/src/main/java/androidx/media3/transformer/MssimCalculator.java index ca7bbe632b7..e0dd32ef775 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/MssimCalculator.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/MssimCalculator.java @@ -23,7 +23,7 @@ * *

    MSSIM divides the image into windows, calculates SSIM of each, then returns the average. * - * @see The SSIM paper. + *

    See the SSIM paper. */ /* package */ final class MssimCalculator { // Referred to as 'L' in the SSIM paper, this constant defines the maximum pixel values. The From dbf737de0833d1b54fad965cfd2f784230dd8b1d Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 1 Mar 2023 17:27:15 +0000 Subject: [PATCH 27/33] Merge pull request #255 from mayurk2:use_edts_offset_if_it_is_for_entire_file PiperOrigin-RevId: 513213229 (cherry picked from commit 17499cefcc1b27d90ecdf136bd3b2e4856ddcaf1) --- .../extractor/mp4/FragmentedMp4Extractor.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java index 4ccca487c82..5cb4b55da91 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java @@ -970,6 +970,26 @@ private static long parseTfdt(ParsableByteArray tfdt) { return version == 1 ? tfdt.readUnsignedLongToLong() : tfdt.readUnsignedInt(); } + private static boolean isEdtsListDurationForEntireMediaTimeline(Track track) { + // Currently we only support a single edit that moves the entire media timeline (indicated by + // duration == 0 or (editListDurationUs + editListMediaTimeUs) >= track duration. + // Other uses of edit lists are uncommon and unsupported. + if (track.editListDurations == null + || track.editListDurations.length != 1 + || track.editListMediaTimes == null) { + return false; + } + if (track.editListDurations[0] == 0) { + return true; + } + long editListEndMediaTimeUs = + Util.scaleLargeTimestamp( + track.editListDurations[0] + track.editListMediaTimes[0], + C.MICROS_PER_SECOND, + track.movieTimescale); + return editListEndMediaTimeUs >= track.durationUs; + } + /** * Parses a trun atom (defined in 14496-12). * @@ -1017,11 +1037,8 @@ private static int parseTrun( // ensure that the first frame's presentation timestamp is zero. long edtsOffset = 0; - // Currently we only support a single edit that moves the entire media timeline (indicated by - // duration == 0). Other uses of edit lists are uncommon and unsupported. - if (track.editListDurations != null - && track.editListDurations.length == 1 - && track.editListDurations[0] == 0) { + // Currently we only support a single edit that moves the entire media timeline. + if (isEdtsListDurationForEntireMediaTimeline(track)) { edtsOffset = castNonNull(track.editListMediaTimes)[0]; } From 64c6d8f351bf1f3b7b31906819aa98ca03235b18 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 2 Mar 2023 10:46:54 +0000 Subject: [PATCH 28/33] Update release notes for 1.0.0-rc02 PiperOrigin-RevId: 513483809 (cherry picked from commit df11545ba18f9bf3e6e9c87c3bdb30bfb0723279) --- RELEASENOTES.md | 130 +++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 79 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 77227fbcaec..d10f149eb47 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,32 +2,47 @@ ### Unreleased changes -* Core library: - * Add suppression reason for unsuitable audio route and play when ready +* Core library: + * Add suppression reason for unsuitable audio route and play when ready change reason for suppressed too long. ([#15](https://github.com/androidx/media/issues/15)). - * Make the maximum difference of the start time of two segments to be - merged configurable in `SegmentDownloader` and subclasses - ([#248](https://github.com/androidx/media/pull/248)). - * Add `ExoPlayer.setVideoEffects()` for using `Effect` during video + * Add `ExoPlayer.setVideoEffects()` for using `Effect` during video playback. - * Update `SampleQueue` to store `sourceId` as a `long` rather than an + * Update `SampleQueue` to store `sourceId` as a `long` rather than an `int`. This changes the signatures of public methods `SampleQueue.sourceId` and `SampleQueue.peekSourceId`. - * Fix network type detection on API 33 - ([#10970](https://github.com/google/ExoPlayer/issues/10970)). - * Make the maximum difference of the start time of two segments to be - merged configurable in `SegmentDownloader` and subclasses - ([#248](https://github.com/androidx/media/pull/248)). -* Extractors: - * Fix `NullPointerException` when calling `ExoPlayer.isTunnelingEnabled` - ([#10977](https://github.com/google/ExoPlayer/issues/10977)). -* Audio: +* Audio: * Fix bug where some playbacks fail when tunneling is enabled and `AudioProcessors` are active, e.g. for gapless trimming ([#10847](https://github.com/google/ExoPlayer/issues/10847)). * Encapsulate Opus frames in Ogg packets in direct playbacks (offload). - * Fix broken gapless MP3 playback on Samsung devices +* Transformer: + * Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`. + Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and + `Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)` + instead. + * Remove `Transformer.startTransformation(MediaItem, + ParcelFileDescriptor)`. +* Remove deprecated symbols: + * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` + instead. + +### 1.0.0-rc02 (2023-03-02) + +This release corresponds to the +[ExoPlayer 2.18.4 release](https://github.com/google/ExoPlayer/releases/tag/r2.18.4). + +* Core library: + * Fix network type detection on API 33 + ([#10970](https://github.com/google/ExoPlayer/issues/10970)). + * Fix `NullPointerException` when calling `ExoPlayer.isTunnelingEnabled` + ([#10977](https://github.com/google/ExoPlayer/issues/10977)). +* Downloads: + * Make the maximum difference of the start time of two segments to be + merged configurable in `SegmentDownloader` and subclasses + ([#248](https://github.com/androidx/media/pull/248)). +* Audio: + * Fix broken gapless MP3 playback on Samsung devices ([#8594](https://github.com/google/ExoPlayer/issues/8594)). * Fix bug where playback speeds set immediately after disabling audio may be overridden by a previous speed change @@ -35,51 +50,29 @@ * Video: * Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of `HEVCProfileMain10`. - * Add workaround for a device issue on Chromecast with Google TV and + * Add workaround for a device issue on Chromecast with Google TV and Lenovo M10 FHD Plus that causes 60fps AVC streams to be marked as unsupported ([#10898](https://github.com/google/ExoPlayer/issues/10898)). -* DASH: - * Add full parsing for image adaptation sets, including tile counts - ([#3752](https://github.com/google/ExoPlayer/issues/3752)). -* RTSP: - * Catch the IllegalArgumentException thrown in parsing of invalid RTSP - Describe response messages - ([#10971](https://github.com/google/ExoPlayer/issues/10971)). -* Session: - * Fix a bug where notification play/pause button doesn't update with - player state ([#192](https://github.com/androidx/media/issues/192)). - * Fix a bug where notification play/pause button doesn't update with - player state ([#192](https://github.com/androidx/media/issues/192)). + * Fix frame release performance issues when playing media with a frame + rate far higher than the screen refresh rate. +* Cast: + * Fix transient `STATE_IDLE` when transitioning between media items + ([#245](https://github.com/androidx/media/issues/245)). * RTSP: * Catch the IllegalArgumentException thrown in parsing of invalid RTSP Describe response messages ([#10971](https://github.com/google/ExoPlayer/issues/10971)). -* Metadata: - * Parse multiple null-separated values from ID3 frames, as permitted by - ID3 v2.4. - * Add `MediaMetadata.mediaType` to denote the type of content or the type - of folder described by the metadata. - * Add `MediaMetadata.isBrowsable` as a replacement for - `MediaMetadata.folderType`. The folder type will be deprecated in the - next release. -* Transformer: - * Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`. - Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and - `Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)` - instead. - * Remove `Transformer.startTransformation(MediaItem, - ParcelFileDescriptor)`. -* Remove deprecated symbols: - * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` - instead. +* Session: + * Fix a bug where notification play/pause button doesn't update with + player state ([#192](https://github.com/androidx/media/issues/192)). ### 1.0.0-rc01 (2023-02-16) This release corresponds to the [ExoPlayer 2.18.3 release](https://github.com/google/ExoPlayer/releases/tag/r2.18.3). -* Core library: +* Core library: * Tweak the renderer's decoder ordering logic to uphold the `MediaCodecSelector`'s preferences, even if a decoder reports it may not be able to play the media performantly. For example with default @@ -97,7 +90,7 @@ This release corresponds to the * Add `ConcatenatingMediaSource2` that allows combining multiple media items into a single window ([#247](https://github.com/androidx/media/issues/247)). -* Extractors: +* Extractors: * Throw a `ParserException` instead of a `NullPointerException` if the sample table (stbl) is missing a required sample description (stsd) when parsing trak atoms. @@ -111,7 +104,7 @@ This release corresponds to the `Subtitle.getEventTime` if a subtitle file contains no cues. * SubRip: Add support for UTF-16 files if they start with a byte order mark. -* Metadata: +* Metadata: * Parse multiple null-separated values from ID3 frames, as permitted by ID3 v2.4. * Add `MediaMetadata.mediaType` to denote the type of content or the type @@ -119,10 +112,10 @@ This release corresponds to the * Add `MediaMetadata.isBrowsable` as a replacement for `MediaMetadata.folderType`. The folder type will be deprecated in the next release. -* DASH: +* DASH: * Add full parsing for image adaptation sets, including tile counts ([#3752](https://github.com/google/ExoPlayer/issues/3752)). -* UI: +* UI: * Fix the deprecated `PlayerView.setControllerVisibilityListener(PlayerControlView.VisibilityListener)` to ensure visibility changes are passed to the registered listener @@ -130,7 +123,7 @@ This release corresponds to the * Fix the ordering of the center player controls in `PlayerView` when using a right-to-left (RTL) layout ([#227](https://github.com/androidx/media/issues/227)). -* Session: +* Session: * Add abstract `SimpleBasePlayer` to help implement the `Player` interface for custom players. * Add helper method to convert platform session token to Media3 @@ -147,33 +140,12 @@ This release corresponds to the ([#233](https://github.com/androidx/media/issues/233)). * Make `QueueTimeline` more robust in case of a shady legacy session state ([#241](https://github.com/androidx/media/issues/241)). -* Cast extension: - * Fix a bug where notification play/pause button doesn't update with - player state ([#192](https://github.com/androidx/media/issues/192)). -* Metadata: - * Parse multiple null-separated values from ID3 frames, as permitted by - ID3 v2.4. - * Add `MediaMetadata.mediaType` to denote the type of content or the type - of folder described by the metadata. - * Add `MediaMetadata.isBrowsable` as a replacement for - `MediaMetadata.folderType`. The folder type will be deprecated in the - next release. -* Transformer: - * Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`. - Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and - `Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)` - instead. - * Remove `Transformer.startTransformation(MediaItem, - ParcelFileDescriptor)`. -* Remove deprecated symbols: - * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` - instead. -* Cast extension +* Cast extension: * Bump Cast SDK version to 21.2.0. -* IMA extension: +* IMA extension: * Map `PLAYER_STATE_LOADING` to `STATE_BUFFERING` ([#245](\(https://github.com/androidx/media/issues/245\)). -* IMA extension +* IMA extension * Remove player listener of the `ImaServerSideAdInsertionMediaSource` on the application thread to avoid threading issues. * Add a property `focusSkipButtonWhenAvailable` to the @@ -185,7 +157,7 @@ This release corresponds to the * Fix a bug which prevented playback from starting for a DAI stream without any ads. * Bump IMA SDK version to 3.29.0. -* Demo app: +* Demo app: * Request notification permission for download notifications at runtime ([#10884](https://github.com/google/ExoPlayer/issues/10884)). From 67fd41a49d0d227a46a5b02818d37f2b586e85bc Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 2 Mar 2023 11:14:00 +0000 Subject: [PATCH 29/33] Bump version numbers to Media3 1.0.0-rc02 and ExoPlayer 2.18.4 #minor-release PiperOrigin-RevId: 513488487 (cherry picked from commit cd753bd7b8c3206b509949e851f515ca465e4c89) --- .github/ISSUE_TEMPLATE/bug.yml | 1 + constants.gradle | 4 ++-- .../main/java/androidx/media3/common/MediaLibraryInfo.java | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 005d4e2e68f..ab94d9922e4 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -17,6 +17,7 @@ body: label: Media3 Version description: What version of Media3 are you using? options: + - 1.0.0-rc02 - 1.0.0-rc01 - 1.0.0-beta03 - 1.0.0-beta02 diff --git a/constants.gradle b/constants.gradle index 39884d57c73..f1fa589e943 100644 --- a/constants.gradle +++ b/constants.gradle @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. project.ext { - releaseVersion = '1.0.0-rc01' - releaseVersionCode = 1_000_000_2_01 + releaseVersion = '1.0.0-rc02' + releaseVersionCode = 1_000_000_2_02 minSdkVersion = 16 appTargetSdkVersion = 33 // API version before restricting local file access. diff --git a/libraries/common/src/main/java/androidx/media3/common/MediaLibraryInfo.java b/libraries/common/src/main/java/androidx/media3/common/MediaLibraryInfo.java index ad013f4cd3c..64cdc2d9964 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MediaLibraryInfo.java +++ b/libraries/common/src/main/java/androidx/media3/common/MediaLibraryInfo.java @@ -29,11 +29,11 @@ public final class MediaLibraryInfo { /** The version of the library expressed as a string, for example "1.2.3" or "1.2.3-beta01". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "1.0.0-rc01"; + public static final String VERSION = "1.0.0-rc02"; /** The version of the library expressed as {@code TAG + "/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "AndroidXMedia3/1.0.0-rc01"; + public static final String VERSION_SLASHY = "AndroidXMedia3/1.0.0-rc02"; /** * The version of the library expressed as an integer, for example 1002003300. @@ -47,7 +47,7 @@ public final class MediaLibraryInfo { * (123-045-006-3-00). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 1_000_000_2_01; + public static final int VERSION_INT = 1_000_000_2_02; /** Whether the library was compiled with {@link Assertions} checks enabled. */ public static final boolean ASSERTIONS_ENABLED = true; From d47675f017e3e079b2b6e4394118c57c86be3f28 Mon Sep 17 00:00:00 2001 From: bachinger Date: Thu, 2 Mar 2023 12:36:33 +0000 Subject: [PATCH 30/33] Fix some JavaDoc in the Media3 session module #minor-release PiperOrigin-RevId: 513501046 (cherry picked from commit 6042bec18a4b30449a20d1e858bac799cc6d18c3) --- .../androidx/media3/session/MediaSession.java | 83 +++++++++++-------- .../media3/session/MediaSessionImpl.java | 2 +- .../media3/session/MediaSessionService.java | 32 +++---- 3 files changed, 65 insertions(+), 52 deletions(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java index 1a2c7b2e813..c1cd0c6e4aa 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java @@ -67,14 +67,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** - * A session that allows a media app to expose its transport controls and playback information in a - * process to other processes including the Android framework and other apps. The common use cases - * are as follows: + * A session that allows a media app to expose its player functionality, information of the playlist + * and the media item currently being played to other processes including the Android framework and + * other apps. The common use cases are as follows: * *

      - *
    • Bluetooth/wired headset key events support - *
    • Android Auto/Wearable support - *
    • Separating UI process and playback process + *
    • Receiving and dispatching media key events (for instance Bluetooth/wired headset and remote + * control devices). + *
    • Publish media playback information and player commands to SystemUI (media notification) and + * Android Auto/Wear OS. + *
    • Separating UI process and playback process. *
    * *

    A session should be created when an app wants to publish media playback information or handle @@ -82,9 +84,8 @@ * sessions can be created to provide finer grain controls of media. See Supporting Multiple Sessions for details. * - *

    If you want to support background playback, {@link MediaSessionService} is preferred. With the - * service, your playback can be revived even after playback is finished. See {@link - * MediaSessionService} for details. + *

    If an app wants to support playback when in the background, using a {@link + * MediaSessionService} is the preferred approach. See {@link MediaSessionService} for details. * *

    Topics covered here: * @@ -103,7 +104,7 @@ * #getToken() session token} to other processes to allow them to create a {@link MediaController} * to interact with the session. * - *

    When a session receives transport control commands, the session sends the commands directly to + *

    When a session receives playback commands, the session calls corresponding methods directly on * the underlying player set by {@link Builder#Builder(Context, Player)} or {@link * #setPlayer(Player)}. * @@ -113,15 +114,15 @@ * *

    Threading Model

    * - *

    The instances are thread safe, but should be used on the thread with a looper. + *

    The instances are thread safe, but must be used on a thread with a looper. * - *

    {@link Callback} methods will be called from the application thread associated with the {@link + *

    {@link Callback} methods will be called on the application thread associated with the {@link * Player#getApplicationLooper() application looper} of the underlying player. When a new player is - * set by {@link #setPlayer}, the player should use the same application looper as the previous one. + * set by {@link #setPlayer}, the player must use the same application looper as the previous one. * - *

    The session listens to events from the underlying player via {@link Player.Listener} and - * expects the callback methods to be called from the application thread. If the player violates the - * threading contract, {@link IllegalStateException} will be thrown. + *

    The session listens to player events via {@link Player.Listener} and expects the callback + * methods to be called on the application thread. If the player violates the threading contract, an + * {@link IllegalStateException} will be thrown. * *

    Media Key Events Mapping

    * @@ -160,7 +161,10 @@ *
  • *
  • {@link Player#play()} otherwise
  • * - *
  • For a double tap, {@link Player#seekToNext()}
  • + *
  • In case the media key events are coming from another package ID than the package ID of + * the media app (events coming for instance from Bluetooth), a double tap generating two + * key events within a brief amount of time, is converted to {@link Player#seekToNext()} + *
  • * * * @@ -193,16 +197,15 @@ * media or remote playback, since the audio focus policy * recommends not playing multiple audio content at the same time. Also, keep in mind that multiple - * media sessions would make Android Auto and Bluetooth device with display to show your apps + * media sessions would make Android Auto and Bluetooth devices with display to show your app * multiple times, because they list up media sessions, not media apps. * *

    Backward Compatibility with Legacy Session APIs

    * - *

    An active {@link MediaSessionCompat} is internally created with the session for the backward - * compatibility. It's used to handle incoming connection and commands from {@link - * MediaControllerCompat}, and helps to utilize existing APIs that are built with legacy media - * session APIs. Use {@link #getSessionCompatToken} to get the legacy token of {@link - * MediaSessionCompat}. + *

    An active {@link MediaSessionCompat} is internally created with the session for backwards + * compatibility. It's used to handle incoming connections and commands from {@link + * MediaControllerCompat} instances, and helps to utilize existing APIs that are built with legacy + * media session APIs. * *

    Backward Compatibility with Legacy Controller APIs

    * @@ -211,10 +214,10 @@ * {@linkplain MediaControllerCompat AndroidX controller compat}. However, {@link ControllerInfo} * may not be precise for legacy controllers. See {@link ControllerInfo} for the details. * - *

    Unknown package name nor UID doesn't mean that you should disallow connection nor commands. - * For SDK levels where such issues happen, session tokens could only be obtained by trusted - * controllers (e.g. Bluetooth, Auto, ...), so it may be better for you to allow them as you did - * with legacy sessions. + *

    Neither an unknown package name nor an unknown UID mean that you should disallow a connection + * or commands per se. For SDK levels where such issues happen, session tokens can only be obtained + * by trusted controllers (e.g. Bluetooth, Auto, ...). This means only trusted controllers can + * connect and an app can accept such controllers in the same way as with legacy sessions. */ public class MediaSession { @@ -242,7 +245,7 @@ public static final class Builder extends BuilderBaseA client can use this pending intent to start an activity belonging to this session. When - * this pending intent is for instance included in the notification {@linkplain - * NotificationCompat.Builder#setContentIntent(PendingIntent) as the content intent}, tapping - * the notification will open this activity. - * - *

    See 'Start an - * Activity from a Notification' also. + *

    A client can use this pending intent to start an activity belonging to this session. On + * API levels below 33 the pending intent can be used {@linkplain + * NotificationCompat.Builder#setContentIntent(PendingIntent) as the content intent}. Tapping + * the notification will then send that pending intent and open the activity (see 'Start an Activity from + * a Notification'). For API levels starting with 33, the media notification reads the + * pending intent directly from the session. * * @param pendingIntent The pending intent. * @return The builder to allow chaining. @@ -290,6 +293,13 @@ public Builder setId(String id) { * Sets a callback for the {@link MediaSession} to handle incoming requests from {link * MediaController}. * + *

    Apps that want to allow controllers to {@linkplain MediaController#setMediaItems(List) + * set} or {@linkplain MediaController#addMediaItems(List) add} media items to the playlist, + * must use a callback and override its {@link + * MediaSession.Callback#onSetMediaItems(MediaSession, ControllerInfo, List, int, long)} or + * {@link MediaSession.Callback#onSetMediaItems(MediaSession, ControllerInfo, List, int, long)} + * methods. + * * @param callback The callback. * @return The builder to allow chaining. */ @@ -371,7 +381,8 @@ public static final class ControllerInfo { * @param remoteUserInfo The remote user info. * @param trusted {@code true} if trusted, {@code false} otherwise. * @param cb ControllerCb. Can be {@code null} only when a MediaBrowserCompat connects to - * MediaSessionService and ControllerInfo is needed for {@code SessionCallback#onConnect()}. + * MediaSessionService and ControllerInfo is needed for {@link + * MediaSession.Callback#onConnect(MediaSession, ControllerInfo)}. * @param connectionHints A session-specific argument sent from the controller for the * connection. The contents of this bundle may affect the connection result. */ diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index 9d32853015e..67acd1aca68 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -447,7 +447,7 @@ public ListenableFuture sendCustomCommand( public MediaSession.ConnectionResult onConnectOnHandler(ControllerInfo controller) { return checkNotNull( - callback.onConnect(instance, controller), "onConntext must return non-null future"); + callback.onConnect(instance, controller), "onConnect must return non-null future"); } public void onPostConnectOnHandler(ControllerInfo controller) { diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java index a93a6cf8a79..30b76997f51 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java @@ -57,26 +57,27 @@ /** * Superclass to be extended by services hosting {@link MediaSession media sessions}. * - *

    It's highly recommended for an app to use this class if they want to keep media playback in - * the background. The service allows other apps to know that your app supports {@link MediaSession} - * even when your app isn't running. For example, a user voice command may start your app to play - * media. + *

    It's highly recommended for an app to use this class if media playback should continue while + * in the background. The service allows other apps to know that your app supports {@link + * MediaSession} even when your app isn't running. This way, a user voice command may be able start + * your app to play media. * *

    To extend this class, declare the intent filter in your {@code AndroidManifest.xml}: * *

    {@code
      * 
    + *   android:foregroundServiceType="mediaPlayback"
    + *   android:exported="true">
      *   
      *     
      *   
      * 
      * }
    * - *

    You may also declare {@code android.media.browse.MediaBrowserService} for compatibility with - * {@link android.support.v4.media.MediaBrowserCompat}. This service can handle the case - * automatically. + *

    You may also declare the action {@code android.media.browse.MediaBrowserService} for + * compatibility with {@link android.support.v4.media.MediaBrowserCompat}. This service can handle + * the case automatically. * *

    It's recommended for an app to have a single service declared in the manifest. Otherwise, your * app might be shown twice in the list of the controller apps, or another app might fail to pick @@ -93,10 +94,10 @@ *

    Service Lifecycle

    * *

    A media session service is a bound service and its foreground - * service type must include mediaPlayback. When a {@link MediaController} is created - * for the service, the controller binds to the service. {@link #onGetSession(ControllerInfo)} will - * be called from {@link #onBind(Intent)}. + * href="https://developer.android.com/guide/topics/manifest/service-element#foregroundservicetype"> + * foreground service type must include mediaPlayback. When a {@link MediaController} + * is created for the service, the controller binds to the service. {@link + * #onGetSession(ControllerInfo)} will be called from {@link #onBind(Intent)}. * *

    After binding, the session's {@link MediaSession.Callback#onConnect(MediaSession, * MediaSession.ControllerInfo)} will be called to accept or reject the connection request from the @@ -115,8 +116,8 @@ * #onUpdateNotification(MediaSession)}. In this case, you must also start or stop the service from * the foreground, when playback starts or stops respectively. * - *

    The service will be destroyed when all sessions are closed, or no controller is binding to the - * service while the service is in the background. + *

    The service will be destroyed when all sessions are {@linkplain MediaController#release() + * released}, or no controller is binding to the service while the service is in the background. * *

    Supporting Multiple Sessions

    * @@ -247,7 +248,8 @@ public void onCreate() { * Adds a {@link MediaSession} to this service. This is not necessary for most media apps. See Supporting Multiple Sessions for details. * - *

    The added session will be removed automatically when it's closed. + *

    The added session will be removed automatically {@linkplain MediaSession#release() when the + * session is released}. * * @param session A session to be added. * @see #removeSession(MediaSession) From 2e6484d53b8d0cd7339420418d7bc9c22368efe6 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 2 Mar 2023 17:15:21 +0000 Subject: [PATCH 31/33] Remove unreleased changed --- RELEASENOTES.md | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d10f149eb47..a4fc09272fc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,32 +1,5 @@ # Release notes -### Unreleased changes - -* Core library: - * Add suppression reason for unsuitable audio route and play when ready - change reason for suppressed too long. - ([#15](https://github.com/androidx/media/issues/15)). - * Add `ExoPlayer.setVideoEffects()` for using `Effect` during video - playback. - * Update `SampleQueue` to store `sourceId` as a `long` rather than an - `int`. This changes the signatures of public methods - `SampleQueue.sourceId` and `SampleQueue.peekSourceId`. -* Audio: - * Fix bug where some playbacks fail when tunneling is enabled and - `AudioProcessors` are active, e.g. for gapless trimming - ([#10847](https://github.com/google/ExoPlayer/issues/10847)). - * Encapsulate Opus frames in Ogg packets in direct playbacks (offload). -* Transformer: - * Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`. - Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and - `Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)` - instead. - * Remove `Transformer.startTransformation(MediaItem, - ParcelFileDescriptor)`. -* Remove deprecated symbols: - * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` - instead. - ### 1.0.0-rc02 (2023-03-02) This release corresponds to the From 7958737655c199f18016366e0af4509b97af5801 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 2 Mar 2023 15:34:54 +0000 Subject: [PATCH 32/33] Fix lint-baseline.xml for latest UI translations #minor-release PiperOrigin-RevId: 513533248 (cherry picked from commit 8498e4b4445ae88665c6cdbc4e47e8e6ca7b7303) --- libraries/ui/lint-baseline.xml | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/libraries/ui/lint-baseline.xml b/libraries/ui/lint-baseline.xml index 0b6a29a68ca..dafdad02fd5 100644 --- a/libraries/ui/lint-baseline.xml +++ b/libraries/ui/lint-baseline.xml @@ -22,7 +22,7 @@ errorLine2=" ^"> @@ -33,7 +33,18 @@ errorLine2=" ^"> + + + + @@ -44,7 +55,7 @@ errorLine2=" ^"> @@ -55,7 +66,18 @@ errorLine2=" ^"> + + + + From af30f00ee684154ffc22023f85203b57092ba3ec Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 2 Mar 2023 17:17:11 +0000 Subject: [PATCH 33/33] Add missing RELEASENOTES line PiperOrigin-RevId: 513556883 (cherry picked from commit e2cb32f34ce016877fa7d2f4acc38511e7c261c0) --- RELEASENOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a4fc09272fc..b5a6a75e466 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -39,6 +39,10 @@ This release corresponds to the * Session: * Fix a bug where notification play/pause button doesn't update with player state ([#192](https://github.com/androidx/media/issues/192)). +* IMA extension: + * Fix a bug which prevented DAI streams without any ads from starting + because the first (and in the case without ads the only) `LOADED` event + wasn't received. ### 1.0.0-rc01 (2023-02-16)