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 38c631388e..82074383a4 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 e97e053084..81af112a67 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 final class MediaCodecUtil { 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 @@ public final class MediaCodecUtil { } @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 @@ public final class MediaCodecUtil { 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 952c5fb8b6..417d0fb027 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 @@ import java.lang.reflect.Method; if (audioTimestampPoller != null) { audioTimestampPoller.reset(); } + resetSyncParams(); } public long getCurrentPositionUs(boolean sourceEnded) { @@ -282,7 +283,9 @@ import java.lang.reflect.Method; // 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 @@ import java.lang.reflect.Method; 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 @@ import java.lang.reflect.Method; 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 82074383a4..c23254bf53 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 d4b8ece726..7a8ac0ba2b 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 abstract class SegmentDownloader> impleme } } + 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 abstract class SegmentDownloader> impleme 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 abstract class SegmentDownloader> impleme 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 abstract class SegmentDownloader> impleme * @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 abstract class SegmentDownloader> impleme cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory(); priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager(); activeRunnables = new ArrayList<>(); + maxMergedSegmentStartTimeDiffUs = Util.msToUs(maxMergedSegmentStartTimeDiffMs); } @Override @@ -145,7 +170,7 @@ public abstract class SegmentDownloader> impleme // 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 @@ public abstract class SegmentDownloader> impleme } } - 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 @@ public abstract class SegmentDownloader> impleme @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 e3c4172728..73a59291b3 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 final class DashDownloader extends SegmentDownloader { */ 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 final class DashDownloader extends SegmentDownloader { * @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 777694e9f6..7c82bee608 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 final class HlsDownloader extends SegmentDownloader { */ 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 final class HlsDownloader extends SegmentDownloader { * @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 4ca632271b..6d2ded5a4c 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 final class SsDownloader extends SegmentDownloader { .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 final class SsDownloader extends SegmentDownloader { * @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 0d403fb173..36c2d45429 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @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 ac44ebb603..112b2ea841 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 @@ public final class 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 c23254bf53..2bacce6b3c 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 525b2df9c4..10c64a7e98 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 @@ import java.util.concurrent.TimeoutException; @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 91aa86ca06..9377aaace6 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 @@ import java.nio.ByteBuffer; @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 10f0a24e15..bba85feff9 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 @@ class AsynchronousMediaCodecBufferEnqueuer { 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 67c6649d27..e950d3ac73 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; // 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 98707a3226..ee7026a669 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 class AsynchronousMediaCodecAdapterTest { 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 class AsynchronousMediaCodecAdapterTest { 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 2bacce6b3c..dfed41bfdb 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 e029b74578..d9ec2dbe37 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 final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou StreamManagerLoadable streamManagerLoadable = new StreamManagerLoadable( sdkAdsLoader, - adsLoader.configuration, + /* imaServerSideAdInsertionMediaSource= */ this, streamRequest, streamPlayer, - applicationAdErrorListener, - loadVideoTimeoutMs); + applicationAdErrorListener); loader.startLoading( streamManagerLoadable, new StreamManagerLoadableCallback(), @@ -633,7 +632,6 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou } this.streamManager.removeAdEventListener(componentListener); this.streamManager.destroy(); - this.streamManager = null; } this.streamManager = streamManager; if (streamManager != null) { @@ -644,6 +642,12 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou 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 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou @Override public void onLoadCompleted( StreamManagerLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) { - mainHandler.post(() -> setStreamManager(checkNotNull(loadable.getStreamManager()))); setContentUri(checkNotNull(loadable.getContentUri())); } @@ -983,14 +986,12 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou 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 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou /** 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 final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou 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 final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou 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 dfed41bfdb..2b984f4350 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 84bcc4cd8d..c8ac907a8d 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; 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 b3d79404a2..b96d3d54b9 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 @@ import com.google.common.collect.ImmutableMap; * @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 @@ import com.google.common.collect.ImmutableMap; 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 @@ import com.google.common.collect.ImmutableMap; 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 @@ import com.google.common.collect.ImmutableMap; 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 @@ import com.google.common.collect.ImmutableMap; 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 @@ import com.google.common.collect.ImmutableMap; 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 f7b7ab41b8..104f6ae9c3 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 final class RtspClientTest { 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 437490eea3..1fee9d80cb 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 @@ public class DefaultDownloaderFactory implements DownloaderFactory { 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 f3045d3cda..1a2c7b2e81 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 class MediaSession { * @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 2b984f4350..b2e3e68927 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 8d2a0cbde1..dbf61395bd 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 @@ public final class CastPlayer extends BasePlayer { 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 @@ public final class CastPlayer extends BasePlayer { 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 417d0fb027..98b6202060 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 android.os.SystemClock; 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 @@ import java.lang.reflect.Method; /** 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 @@ import java.lang.reflect.Method; 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 @@ import java.lang.reflect.Method; * @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 @@ import java.lang.reflect.Method; 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 @@ import java.lang.reflect.Method; } 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 @@ import java.lang.reflect.Method; // 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 @@ import java.lang.reflect.Method; /** 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 @@ import java.lang.reflect.Method; * @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 @@ import java.lang.reflect.Method; 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 @@ import java.lang.reflect.Method; } 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 @@ import java.lang.reflect.Method; // 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 @@ import java.lang.reflect.Method; */ private boolean forceHasPendingData() { return needsPassthroughWorkarounds - && Assertions.checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED + && checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED && getPlaybackHeadPosition() == 0; } @@ -581,36 +584,44 @@ import java.lang.reflect.Method; * @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 @@ import java.lang.reflect.Method; // 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 1bd45fc24a..6b9d4b567d 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 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { 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 815b4c369e..a4a602eef4 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { */ 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 abstract class MediaCodecRenderer extends BaseRenderer { @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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { */ @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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { * 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { && "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 b2e3e68927..aaa533e8c4 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 4e97ab796c..7b64795466 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 @@ public final class NetworkTypeObserver { 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 464db2648d..a079c488d9 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 final class Util { * 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 final class Util { } } - /** - * 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 625c6090b6..04fd1482bd 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.Intent; 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 @@ import androidx.media3.common.util.Util; */ 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 1fc7dc4828..c5a8230154 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 @@ import androidx.media3.common.util.Util; 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 6cb10f0731..9888db45a6 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 1cfef2accc..671ddb5aa6 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 final class AudioCapabilitiesReceiver { @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 ab87aa361c..53ad113710 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 final class Requirements implements Parcelable { 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 @@ public final class Requirements implements Parcelable { } 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 541224221c..d214bc95af 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 final class RequirementsWatcher { 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 d42ab38fe0..b7ad8dc6c2 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 androidx.test.ext.junit.runners.AndroidJUnit4; 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.mockito.junit.MockitoRule; 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 class MediaCodecVideoRendererTest { /* 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 class MediaCodecVideoRendererTest { /* 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 a4a602eef4..cad2720ff2 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @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 abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { decodeOnlyPresentationTimestamps.clear(); largestQueuedPresentationTimeUs = C.TIME_UNSET; lastBufferInStreamPresentationTimeUs = C.TIME_UNSET; + lastProcessedOutputBufferTimeUs = C.TIME_UNSET; if (c2Mp3TimestampTracker != null) { c2Mp3TimestampTracker.reset(); } @@ -1567,6 +1573,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { */ @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 aaa533e8c4..62210b405d 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 e49a9a5a3c..d36f9eb07b 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 @@ public final class MediaCodecInfo { * @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 @@ public final class MediaCodecInfo { && ("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 @@ public final class MediaCodecInfo { 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 62210b405d..ff4dbf6f14 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 cad2720ff2..a752432fa0 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { if (outputFormatChanged || (codecOutputMediaFormatChanged && outputFormat != null)) { onOutputFormatChanged(outputFormat, codecOutputMediaFormat); codecOutputMediaFormatChanged = false; + needToNotifyOutputFormatChangeAfterStreamChange = false; } } @@ -668,10 +670,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { // 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private void setOutputStreamInfo(OutputStreamInfo outputStreamInfo) { this.outputStreamInfo = outputStreamInfo; if (outputStreamInfo.streamOffsetUs != C.TIME_UNSET) { + needToNotifyOutputFormatChangeAfterStreamChange = true; onOutputStreamOffsetUsChanged(outputStreamInfo.streamOffsetUs); } } @@ -2487,12 +2494,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { 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 0000000000..ac86669ee5 --- /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 ff4dbf6f14..7a931129ac 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 27c0cc4ece..30afcb411b 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 @@ import java.util.concurrent.TimeoutException; 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 7a931129ac..77227fbcae 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 6c3c64075b..e84ea1e7e0 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 @@ import java.util.concurrent.atomic.AtomicBoolean; 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 @@ import java.util.concurrent.atomic.AtomicBoolean; } } + 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 @@ import java.util.concurrent.atomic.AtomicBoolean; private void setPlaybackParametersInternal(PlaybackParameters playbackParameters) throws ExoPlaybackException { - mediaClock.setPlaybackParameters(playbackParameters); + setMediaClockPlaybackParameters(playbackParameters); handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true); } @@ -1657,7 +1663,7 @@ import java.util.concurrent.atomic.AtomicBoolean; 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 @@ import java.util.concurrent.atomic.AtomicBoolean; 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 @@ import java.util.concurrent.atomic.AtomicBoolean; 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 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - 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 fb2ae47b59..d258b7123a 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.graphics.SurfaceTexture; 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.SinglePeriodTimeline; 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 final class ExoPlayerTest { @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 final class ExoPlayerTest { 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 final class ExoPlayerTest { .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 final class ExoPlayerTest { @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 final class ExoPlayerTest { ? 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 final class ExoPlayerTest { 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 final class ExoPlayerTest { /* 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 final class ExoPlayerTest { } } + 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 98b6202060..414cf24d40 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 @@ import java.lang.reflect.Method; } 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 @@ import java.lang.reflect.Method; 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 @@ import java.lang.reflect.Method; // 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 c1a57f9246..b935a4cf89 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 a16ac064b3..93a8ae066b 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 6b03d0fdd6..14db130622 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 1193607b28..28e9dcb010 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 49d5ff23c4..c8e8eeb786 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 54b219e042..1539008d72 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 420fa00b97..af37d82078 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 c4a6c3686e..be8ed9cdaa 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 5ca81f2780..5fe387cefb 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 6c80546d7b..ecb381f534 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 f916f076e3..54a112a9ee 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 dca960dbd4..1b15b1f605 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 92904131e1..848bfb2d4d 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 e079173d12..8ef5c20f72 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 27fb6389f8..639a151801 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 27fb6389f8..639a151801 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 27fb6389f8..639a151801 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 45b331f477..545c55ac86 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 6d13c5fd21..a7a8edeaba 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 67df50e267..5ac51b75cb 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 e2e0ca7b9e..d476d29b7b 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 ad7b14e934..271919fbc1 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 6fbdf45fac..15f1a38628 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 9610fd2e14..e177a5d753 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 22f0299976..274278bf4a 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 6764ddb4d3..46f80721b5 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 27821e2299..5d2b5874e5 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 d839e3f3fa..17a17adcdd 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 031e629fd8..05d7cfa448 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 e511a69594..d19171d975 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 61d61e8704..4fc4e86bcb 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 ce650eb479..e20aac9971 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 713dbc50b8..6c62e12ee4 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 709bb8e5b4..03a7a64d1a 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 dadb93b016..41010d65f8 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 b4df8db16c..f32b0bfc75 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 34fa93ac36..2460d0c4b7 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 a0e7f49af1..616fb42af5 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 d284e7b78a..2089642a4a 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 c311225089..7747d1256b 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 3bbdd2cb6c..a87dce92cc 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 8cf2921bc3..6ce6949e2b 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 0b7f314f91..1ff16ef04f 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 afc749c88a..c81cdd1092 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 1899c273e4..0213b5e062 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 58a1de488a..6e1c3aecfc 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 5c75164da8..2e0653da43 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 6e7aac5dc9..95b30da3ce 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 0d98194d6a..0c37597dda 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 f4d08d49d3..3033c3c93f 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 9e308724ad..88294129a9 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 5d5b46b28c..026d9be10d 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 deff7e8e41..a1a014bf7b 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 589296d9a6..c8eeb8553d 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 86236f9e03..ee5031015d 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 63fc39fac7..40633af74c 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 6c9f639ec9..1988ac95eb 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 c38d90d176..59889e55d5 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 a4a7afa1a6..56355afa1f 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 b989fd3bc1..c2b7f7f360 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 36b652c2cc..2b9b3289fd 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 fec40af4e2..4581322c61 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 025ba4a0e6..460643ebb8 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 836ff91e41..b3e916ef4c 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 aad2287353..f537b8e38f 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 34ea63ab33..a645a70f8c 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 f2ea0ebb2f..e6d112427f 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 b9dd46a955..bd9cdbf5d4 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 fe1f48a955..cf0480ebb0 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 c888cd3b72..73cba4d678 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 3b04a687a5..4e68f6f05c 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 2b9252ec7c..24a75afb36 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 7fbb8955de..2413efd778 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 966f406273..b9dd50dd8a 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 85aaf73a8c..21e3ed45d5 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 1e97ed5e5d..3b74a5541a 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 1d24d8cab3..4031209c29 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 1b4279329f..eb4c819746 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 f696d26abf..c95bfd95a2 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 f1d3047458..4e2a417261 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 8ff1ece685..08c05430ee 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 167aa23d48..503a47a0b9 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 140f15247b..78c978f933 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 9b026dc789..3de48f1eee 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 aab80ab5a7..9fc56865f3 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 b01d57052a..ff390a7a97 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 e24ec1e9bc..b720ead2c1 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 2694309f6a..4cb73e9a46 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 2441a1fca8..46f4b9c07d 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 f9bf84a263..368e7fc64b 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 9c1f3dc49f..9c373bd834 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 c8236d5ab0..79c8487541 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 f6685e5999..24fc22bb1f 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 0d90dca7f9..255b6a74bf 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 0bf10abd2d..aef8b741e6 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 0bf10abd2d..aef8b741e6 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 0bf10abd2d..aef8b741e6 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 c3ea5dcb07..8986aeb307 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 1a8880ecdb..99e401b71f 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 4bd8e64a45..a6bd4c2bec 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 f53cc746a7..c57640f613 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 eb8a961f98..0150138991 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 a4d6637218..2adf214fbd 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 fe00e2480b..bdf99bf638 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 bda0e76cd5..ffc27ff8a0 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 97c0b5ae91..96f6019adc 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 3c2e583039..1fcceea947 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 99a792cdd5..4b6951be58 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 3fa32acbfb..fe1eae0a7f 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 2ff84c81f9..b1abc67ce9 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 c5507fa8a1..1385a9cf42 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 142339374a..b818baec7c 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 dfc6267d5a..249da58ac2 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 0be1260e55..0ea7666b8f 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 d5232cf89b..a7fcd9a24d 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 44957a4eed..2db5cf15a3 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 44e49caf12..bf4371548e 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 98f22c7807..e88b1cf39e 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 b12cf6a894..1d59559001 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 485b09c0bf..eb709d4c59 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 015471fe5e..5d6fae98c3 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 350724d9e0..081cccf540 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 337bd7be33..6a7310245f 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 a8c02c98af..3a8f7ec3e0 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 030bb7a549..7283e50af1 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 19487a2d57..41b8e9fa04 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 0b68af763f..8a15c5b4ca 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 5b9c2604fc..0efbb93de6 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 35c8acf476..e00fdc1a4e 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 120211affc..5cf7988088 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 ea9920abc4..9e6f91f761 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 fefb5ea835..4712949ceb 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 8d282366c8..9955dd5503 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 f3735156e4..b451512da3 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 86653fca74..ad0de6dc75 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 10eddbef38..00acc8b75b 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 0be33ad385..d341ca707b 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 7bd7d79520..a422f4d313 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 dd6fc779bd..3de8444966 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 b643018ac0..ff8bc44ce2 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 48c60ddef8..706d6b07ae 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 f2d31acf05..27342a51c7 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 ab3fa88897..bab26908b5 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 c8ebb5046d..bd2c4b0afd 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 e3f7665ac3..fb87221937 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 ad53a1d6e4..d613f5e2e5 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 241fb50b78..4678bf1b0c 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 e0b65856a2..1e441e4843 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 e8a3734789..f51ad9575c 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 683e2aae68..f3a5ecdb6a 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 995740a809..8345460f87 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 2795069c69..93fa1a469c 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 4786db3ce7..56f0532c17 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 423908db8a..877371bfc1 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 fed30dd627..1356dd5493 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 9307041370..ebb77b0a24 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 0db7916594..bb5ef13433 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 87716dc283..1c6da3a07f 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 e7603e7d90..1c10d0755b 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 4f5ee5dddd..d50537842a 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 dd37229848..775029f1e2 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 343e45fbb8..82802a43cd 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 bef7a468e5..804acfc4d6 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 86ea052268..90653578f0 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 2acf688bca..ae0185ea3d 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 05ea71c472..041453ecb2 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 3a898ed4bd..5870895d62 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 2235db434b..d8e8450755 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 3793c330c1..1981474f16 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 ba2e8374a9..56b646a258 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 bb0f85369a..48943a497d 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 71ff36a1a3..d7486b4b9a 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 ff160f6a6a..f035521b13 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 c4ed289bef..a715576c61 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 af85902797..f312573b97 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 af85902797..f312573b97 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 af85902797..f312573b97 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 0bc0f6c546..30e3056b70 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 924d349038..076f352c12 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 faa44e483f..22dd590ee0 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 90441518b1..08fc4df563 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 c25aa14a7c..a7963d437f 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 f57744643c..2ab098e46f 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 5faeb0b5b2..8b5a19053e 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 cc876a8bf3..cc2386dcdd 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 932434af28..125daae7f8 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 955ccf1f93..d912bae291 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 fe18f2a16a..37113b18d4 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 320e47aef8..f58e02d530 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 7f24082f54..66801d3709 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 f77b183118..5171913fbe 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 b010d3c739..9afe0208ca 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 20f603c476..fe4d96f02c 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 b97ae06645..c6f6c12d00 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 c5499212c4..0b61a2c434 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 f8970f64ee..c5017b3c72 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 2ff75b72dd..65c048bff7 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 86d41df02b..3296c2b557 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 3e8fd004a1..c8da4e15a9 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 45b2417f5b..5dcf85112d 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 b6e8d231ea..d0a0f942c5 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 29601c0253..818f69e1ea 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 bd0f103425..3126375a15 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 f1d221e9bf..020629ad60 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 0d0ec51c3c..ef264ca156 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 a5d13326e4..95fe201eb9 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 4d1e4e995a..984452145e 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 56273ce0e5..667ef287b9 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 303f5ca52f..ffde009be0 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 2758851781..f051ca6264 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 89ad8e5636..eaa9531ee9 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 075270b6dc..e444db3ebe 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 586aea713f..bf8d43e1d7 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 eaf3659200..2a1f32bcdc 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 e2579cd646..2c882f2d37 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 ec5bfca158..f6489e8cef 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 6e70f79c53..76aa421cab 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 80a7f42669..be152306b0 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 0448518b56..d67cc4c3a9 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 36d9b4c01e..d08bfeb758 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 a78f859718..e19521ca7b 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 75204eed52..abb31c30ce 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 5bc58e7ae8..77c82d1728 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 0357753ac8..b814f210a9 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 d20d287b1c..23ce2ca335 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 73edb04ff0..64b401a72d 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 015e31701d..02308a65ca 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 36172865b9..bdae9c8632 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 124b8a99ba..7485b6b423 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 fdb108348e..5584dcf93c 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 0757b261da..04c4c2fa68 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 b2fd8b6fa4..6058a4c36f 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 2ffcc61d1c..7d3307db51 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 1e410c9712..0c49e5d445 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 f7639dd95b..7b17320094 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 400d321f5e..1749d4f5dd 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 4fedf2ae07..d32d6a4482 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 88a0239c57..354f58c69a 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 27dc2bcfd6..4249568e95 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 05d78e556e..7752fcb772 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 2640a0a7e4..957ab7d219 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 androidx.media3.common.util.UnstableApi; 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 3d1f7a6349..f0550b0789 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 @@ import java.util.regex.Pattern; /** * 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 ca3d0fadbc..b555b3c40f 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 @@ import java.util.Comparator; * 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 38c17af395..ccc9663ac8 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 @@ import java.util.UUID; /** * 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 6ac0a24560..4160e6b3a9 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 @@ import org.xmlpull.v1.XmlPullParserFactory; /** * 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 debb1f84a8..7c2a9712ce 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 @@ import java.util.List; /** * 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 a1bfbbe059..40e4b1392c 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 @@ import androidx.media3.common.util.UnstableApi; /** * 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 240afed6db..68832975f1 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 final class VorbisUtil { /** * Vorbis identification header. * - * @see Vorbis - * spec/Identification header + *

See the Vorbis + * spec/Identification header */ public static final class VorbisIdHeader { @@ -135,8 +135,9 @@ public final class VorbisUtil { /** * 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 final class VorbisUtil { /** * 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 final class VorbisUtil { /** * 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 final class VorbisUtil { * *

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 final class VorbisUtil { * 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 @@ public final class VorbisUtil { } /** - * @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 b5f53a35fb..f9dea101f1 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 @@ import org.xmlpull.v1.XmlPullParserFactory; *

  • 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 623f8fd057..e27eefdb0f 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.HashSet; 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 6a0daf5893..cb74c2b6ab 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 @@ import java.util.List; /** * 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 78b7a4def7..c1b9a69fec 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 final class TtmlDecoderTest { * 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 ca7bbe632b..e0dd32ef77 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 @@ import static java.lang.Math.pow; * *

    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 4ccca487c8..5cb4b55da9 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 @@ public class FragmentedMp4Extractor implements Extractor { 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 @@ public class FragmentedMp4Extractor implements Extractor { // 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 77227fbcae..d10f149eb4 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 005d4e2e68..ab94d9922e 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 39884d57c7..f1fa589e94 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 ad013f4cd3..64cdc2d996 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 1a2c7b2e81..c1cd0c6e4a 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 java.util.List; 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * #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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * *

    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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; *
  • *
  • {@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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * {@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 class MediaSession { * Creates a builder for {@link MediaSession}. * * @param context The context. - * @param player The underlying player to perform playback and handle transport controls. + * @param player The underlying player to perform playback and handle player commands. * @throws IllegalArgumentException if {@link Player#canAdvertiseSession()} returns false. */ public Builder(Context context, Player player) { @@ -253,13 +256,13 @@ public class MediaSession { * Sets a {@link PendingIntent} to launch an {@link android.app.Activity} for the {@link * MediaSession}. This can be used as a quick link to an ongoing media screen. * - *

    A 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 class MediaSession { * 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 class MediaSession { * @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 9d32853015..67acd1aca6 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 @@ import org.checkerframework.checker.initialization.qual.Initialized; 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 a93a6cf8a7..30b76997f5 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * 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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; *

    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 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * #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 abstract class MediaSessionService extends Service { * 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 d10f149eb4..a4fc09272f 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 0b6a29a68c..dafdad02fd 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 a4fc09272f..b5a6a75e46 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)