mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
commit
1ef427f640
1
.github/ISSUE_TEMPLATE/bug.yml
vendored
1
.github/ISSUE_TEMPLATE/bug.yml
vendored
@ -17,6 +17,7 @@ body:
|
|||||||
label: Media3 Version
|
label: Media3 Version
|
||||||
description: What version of Media3 are you using?
|
description: What version of Media3 are you using?
|
||||||
options:
|
options:
|
||||||
|
- 1.0.0-rc02
|
||||||
- 1.0.0-rc01
|
- 1.0.0-rc01
|
||||||
- 1.0.0-beta03
|
- 1.0.0-beta03
|
||||||
- 1.0.0-beta02
|
- 1.0.0-beta02
|
||||||
|
@ -1,5 +1,49 @@
|
|||||||
# Release notes
|
# Release notes
|
||||||
|
|
||||||
|
### 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
|
||||||
|
([#10882](https://github.com/google/ExoPlayer/issues/10882)).
|
||||||
|
* Video:
|
||||||
|
* Map HEVC HDR10 format to `HEVCProfileMain10HDR10` instead of
|
||||||
|
`HEVCProfileMain10`.
|
||||||
|
* 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)).
|
||||||
|
* 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)).
|
||||||
|
* 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)
|
### 1.0.0-rc01 (2023-02-16)
|
||||||
|
|
||||||
This release corresponds to the
|
This release corresponds to the
|
||||||
@ -73,17 +117,12 @@ This release corresponds to the
|
|||||||
([#233](https://github.com/androidx/media/issues/233)).
|
([#233](https://github.com/androidx/media/issues/233)).
|
||||||
* Make `QueueTimeline` more robust in case of a shady legacy session state
|
* Make `QueueTimeline` more robust in case of a shady legacy session state
|
||||||
([#241](https://github.com/androidx/media/issues/241)).
|
([#241](https://github.com/androidx/media/issues/241)).
|
||||||
* 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.
|
* 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
|
||||||
* Remove player listener of the `ImaServerSideAdInsertionMediaSource` on
|
* Remove player listener of the `ImaServerSideAdInsertionMediaSource` on
|
||||||
the application thread to avoid threading issues.
|
the application thread to avoid threading issues.
|
||||||
* Add a property `focusSkipButtonWhenAvailable` to the
|
* Add a property `focusSkipButtonWhenAvailable` to the
|
||||||
@ -92,6 +131,8 @@ This release corresponds to the
|
|||||||
* Add a method `focusSkipButton()` to the
|
* Add a method `focusSkipButton()` to the
|
||||||
`ImaServerSideAdInsertionMediaSource.AdsLoader` to programmatically
|
`ImaServerSideAdInsertionMediaSource.AdsLoader` to programmatically
|
||||||
request to focus the skip button.
|
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.
|
* Bump IMA SDK version to 3.29.0.
|
||||||
* Demo app:
|
* Demo app:
|
||||||
* Request notification permission for download notifications at runtime
|
* Request notification permission for download notifications at runtime
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
project.ext {
|
project.ext {
|
||||||
releaseVersion = '1.0.0-rc01'
|
releaseVersion = '1.0.0-rc02'
|
||||||
releaseVersionCode = 1_000_000_2_01
|
releaseVersionCode = 1_000_000_2_02
|
||||||
minSdkVersion = 16
|
minSdkVersion = 16
|
||||||
appTargetSdkVersion = 33
|
appTargetSdkVersion = 33
|
||||||
// API version before restricting local file access.
|
// API version before restricting local file access.
|
||||||
|
@ -1237,6 +1237,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
int receiverAppStatus = remoteMediaClient.getPlayerState();
|
int receiverAppStatus = remoteMediaClient.getPlayerState();
|
||||||
switch (receiverAppStatus) {
|
switch (receiverAppStatus) {
|
||||||
case MediaStatus.PLAYER_STATE_BUFFERING:
|
case MediaStatus.PLAYER_STATE_BUFFERING:
|
||||||
|
case MediaStatus.PLAYER_STATE_LOADING:
|
||||||
return STATE_BUFFERING;
|
return STATE_BUFFERING;
|
||||||
case MediaStatus.PLAYER_STATE_PLAYING:
|
case MediaStatus.PLAYER_STATE_PLAYING:
|
||||||
case MediaStatus.PLAYER_STATE_PAUSED:
|
case MediaStatus.PLAYER_STATE_PAUSED:
|
||||||
@ -1299,6 +1300,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("VisibleForTests")
|
||||||
private static int getCastRepeatMode(@RepeatMode int repeatMode) {
|
private static int getCastRepeatMode(@RepeatMode int repeatMode) {
|
||||||
switch (repeatMode) {
|
switch (repeatMode) {
|
||||||
case REPEAT_MODE_ONE:
|
case REPEAT_MODE_ONE:
|
||||||
|
@ -331,7 +331,10 @@ public final class C {
|
|||||||
*/
|
*/
|
||||||
@UnstableApi public static final int ENCODING_OPUS = AudioFormat.ENCODING_OPUS;
|
@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
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@Target(TYPE_USE)
|
@Target(TYPE_USE)
|
||||||
|
@ -28,7 +28,7 @@ import androidx.media3.common.util.UnstableApi;
|
|||||||
import java.util.List;
|
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.
|
* class to suppress or modify specific operations, by overriding the respective methods.
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
|
@ -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". */
|
/** 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.
|
// 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}. */
|
/** The version of the library expressed as {@code TAG + "/" + VERSION}. */
|
||||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
// 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.
|
* 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).
|
* (123-045-006-3-00).
|
||||||
*/
|
*/
|
||||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
// 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. */
|
/** Whether the library was compiled with {@link Assertions} checks enabled. */
|
||||||
public static final boolean ASSERTIONS_ENABLED = true;
|
public static final boolean ASSERTIONS_ENABLED = true;
|
||||||
|
@ -27,8 +27,12 @@ import java.util.regex.Pattern;
|
|||||||
/**
|
/**
|
||||||
* Parser for color expressions found in styling formats, e.g. TTML and CSS.
|
* Parser for color expressions found in styling formats, e.g. TTML and CSS.
|
||||||
*
|
*
|
||||||
* @see <a href="https://w3c.github.io/webvtt/#styling">WebVTT CSS Styling</a>
|
* <p>See also:
|
||||||
* @see <a href="https://www.w3.org/TR/ttml2/">Timed Text Markup Language 2 (TTML2) - 10.3.5</a>
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li><a href="https://w3c.github.io/webvtt/#styling">WebVTT CSS Styling</a>
|
||||||
|
* <li><a href="https://www.w3.org/TR/ttml2/">Timed Text Markup Language 2 (TTML2) - 10.3.5</a>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public final class ColorParser {
|
public final class ColorParser {
|
||||||
|
@ -94,7 +94,7 @@ public final class NetworkTypeObserver {
|
|||||||
networkType = C.NETWORK_TYPE_UNKNOWN;
|
networkType = C.NETWORK_TYPE_UNKNOWN;
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
Util.registerReceiverNotExported(context, new Receiver(), filter);
|
context.registerReceiver(new Receiver(), filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -206,6 +206,10 @@ public final class Util {
|
|||||||
* apps. This will be enforced by specifying {@link Context#RECEIVER_NOT_EXPORTED} if {@link
|
* apps. This will be enforced by specifying {@link Context#RECEIVER_NOT_EXPORTED} if {@link
|
||||||
* #SDK_INT} is 33 or above.
|
* #SDK_INT} is 33 or above.
|
||||||
*
|
*
|
||||||
|
* <p>Do not use this method if registering a receiver for a <a
|
||||||
|
* href="https://android.googlesource.com/platform/frameworks/base/+/master/core/res/AndroidManifest.xml">protected
|
||||||
|
* system broadcast</a>.
|
||||||
|
*
|
||||||
* @param context The context on which {@link Context#registerReceiver} will be called.
|
* @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 receiver The {@link BroadcastReceiver} to register. This value may be null.
|
||||||
* @param filter Selects the Intent broadcasts to be received.
|
* @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
|
* Calls {@link Context#startForegroundService(Intent)} if {@link #SDK_INT} is 26 or higher, or
|
||||||
* {@link Context#startService(Intent)} otherwise.
|
* {@link Context#startService(Intent)} otherwise.
|
||||||
|
@ -794,11 +794,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists() throws DatabaseIOException {
|
public boolean exists() throws DatabaseIOException {
|
||||||
|
try {
|
||||||
return VersionTable.getVersion(
|
return VersionTable.getVersion(
|
||||||
databaseProvider.getReadableDatabase(),
|
databaseProvider.getReadableDatabase(),
|
||||||
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
||||||
checkNotNull(hexUid))
|
checkNotNull(hexUid))
|
||||||
!= VersionTable.VERSION_UNSET;
|
!= VersionTable.VERSION_UNSET;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DatabaseIOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -21,7 +21,6 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import androidx.media3.common.util.Util;
|
|
||||||
|
|
||||||
/* package */ final class AudioBecomingNoisyManager {
|
/* package */ final class AudioBecomingNoisyManager {
|
||||||
|
|
||||||
@ -47,8 +46,8 @@ import androidx.media3.common.util.Util;
|
|||||||
*/
|
*/
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
if (enabled && !receiverRegistered) {
|
if (enabled && !receiverRegistered) {
|
||||||
Util.registerReceiverNotExported(
|
context.registerReceiver(
|
||||||
context, receiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
|
receiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
|
||||||
receiverRegistered = true;
|
receiverRegistered = true;
|
||||||
} else if (!enabled && receiverRegistered) {
|
} else if (!enabled && receiverRegistered) {
|
||||||
context.unregisterReceiver(receiver);
|
context.unregisterReceiver(receiver);
|
||||||
|
@ -1724,8 +1724,9 @@ import java.util.concurrent.TimeoutException;
|
|||||||
@Override
|
@Override
|
||||||
public boolean isTunnelingEnabled() {
|
public boolean isTunnelingEnabled() {
|
||||||
verifyApplicationThread();
|
verifyApplicationThread();
|
||||||
for (RendererConfiguration config : playbackInfo.trackSelectorResult.rendererConfigurations) {
|
for (@Nullable
|
||||||
if (config.tunneling) {
|
RendererConfiguration config : playbackInfo.trackSelectorResult.rendererConfigurations) {
|
||||||
|
if (config != null && config.tunneling) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -946,7 +946,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
livePlaybackSpeedControl.getAdjustedPlaybackSpeed(
|
livePlaybackSpeedControl.getAdjustedPlaybackSpeed(
|
||||||
getCurrentLiveOffsetUs(), getTotalBufferedDurationUs());
|
getCurrentLiveOffsetUs(), getTotalBufferedDurationUs());
|
||||||
if (mediaClock.getPlaybackParameters().speed != adjustedSpeed) {
|
if (mediaClock.getPlaybackParameters().speed != adjustedSpeed) {
|
||||||
mediaClock.setPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed));
|
setMediaClockPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed));
|
||||||
handlePlaybackParameters(
|
handlePlaybackParameters(
|
||||||
playbackInfo.playbackParameters,
|
playbackInfo.playbackParameters,
|
||||||
/* currentPlaybackSpeed= */ mediaClock.getPlaybackParameters().speed,
|
/* 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() {
|
private void notifyTrackSelectionRebuffer() {
|
||||||
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
|
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
|
||||||
while (periodHolder != null) {
|
while (periodHolder != null) {
|
||||||
@ -1342,7 +1348,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
private void setPlaybackParametersInternal(PlaybackParameters playbackParameters)
|
private void setPlaybackParametersInternal(PlaybackParameters playbackParameters)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
mediaClock.setPlaybackParameters(playbackParameters);
|
setMediaClockPlaybackParameters(playbackParameters);
|
||||||
handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true);
|
handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1657,7 +1663,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
nextPendingMessageIndexHint = nextPendingMessageIndex;
|
nextPendingMessageIndexHint = nextPendingMessageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureStopped(Renderer renderer) throws ExoPlaybackException {
|
private void ensureStopped(Renderer renderer) {
|
||||||
if (renderer.getState() == Renderer.STATE_STARTED) {
|
if (renderer.getState() == Renderer.STATE_STARTED) {
|
||||||
renderer.stop();
|
renderer.stop();
|
||||||
}
|
}
|
||||||
@ -1914,14 +1920,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
MediaPeriodId newPeriodId,
|
MediaPeriodId newPeriodId,
|
||||||
Timeline oldTimeline,
|
Timeline oldTimeline,
|
||||||
MediaPeriodId oldPeriodId,
|
MediaPeriodId oldPeriodId,
|
||||||
long positionForTargetOffsetOverrideUs) {
|
long positionForTargetOffsetOverrideUs)
|
||||||
|
throws ExoPlaybackException {
|
||||||
if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) {
|
if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) {
|
||||||
// Live playback speed control is unused for the current period, reset speed to user-defined
|
// Live playback speed control is unused for the current period, reset speed to user-defined
|
||||||
// playback parameters or 1.0 for ad playback.
|
// playback parameters or 1.0 for ad playback.
|
||||||
PlaybackParameters targetPlaybackParameters =
|
PlaybackParameters targetPlaybackParameters =
|
||||||
newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters;
|
newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters;
|
||||||
if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) {
|
if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) {
|
||||||
mediaClock.setPlaybackParameters(targetPlaybackParameters);
|
setMediaClockPlaybackParameters(targetPlaybackParameters);
|
||||||
|
handlePlaybackParameters(
|
||||||
|
playbackInfo.playbackParameters,
|
||||||
|
targetPlaybackParameters.speed,
|
||||||
|
/* updatePlaybackInfo= */ false,
|
||||||
|
/* acknowledgeCommand= */ false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1970,7 +1982,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
return maxReadPositionUs;
|
return maxReadPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePeriods() throws ExoPlaybackException, IOException {
|
private void updatePeriods() throws ExoPlaybackException {
|
||||||
if (playbackInfo.timeline.isEmpty() || !mediaSourceList.isPrepared()) {
|
if (playbackInfo.timeline.isEmpty() || !mediaSourceList.isPrepared()) {
|
||||||
// No periods available.
|
// No periods available.
|
||||||
return;
|
return;
|
||||||
@ -2012,7 +2024,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeUpdateReadingPeriod() {
|
private void maybeUpdateReadingPeriod() throws ExoPlaybackException {
|
||||||
@Nullable MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
|
@Nullable MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
|
||||||
if (readingPeriodHolder == null) {
|
if (readingPeriodHolder == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -75,7 +75,7 @@ import androidx.media3.common.util.Util;
|
|||||||
VolumeChangeReceiver receiver = new VolumeChangeReceiver();
|
VolumeChangeReceiver receiver = new VolumeChangeReceiver();
|
||||||
IntentFilter filter = new IntentFilter(VOLUME_CHANGED_ACTION);
|
IntentFilter filter = new IntentFilter(VOLUME_CHANGED_ACTION);
|
||||||
try {
|
try {
|
||||||
Util.registerReceiverNotExported(applicationContext, receiver, filter);
|
applicationContext.registerReceiver(receiver, filter);
|
||||||
this.receiver = receiver;
|
this.receiver = receiver;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.w(TAG, "Error registering stream volume receiver", e);
|
Log.w(TAG, "Error registering stream volume receiver", e);
|
||||||
|
@ -88,8 +88,8 @@ public final class AudioCapabilities {
|
|||||||
@SuppressWarnings("InlinedApi")
|
@SuppressWarnings("InlinedApi")
|
||||||
public static AudioCapabilities getCapabilities(Context context) {
|
public static AudioCapabilities getCapabilities(Context context) {
|
||||||
Intent intent =
|
Intent intent =
|
||||||
Util.registerReceiverNotExported(
|
context.registerReceiver(
|
||||||
context, /* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG));
|
/* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG));
|
||||||
return getCapabilities(context, intent);
|
return getCapabilities(context, intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,9 @@ public final class AudioCapabilitiesReceiver {
|
|||||||
@Nullable Intent stickyIntent = null;
|
@Nullable Intent stickyIntent = null;
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG);
|
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);
|
audioCapabilities = AudioCapabilities.getCapabilities(context, stickyIntent);
|
||||||
return audioCapabilities;
|
return audioCapabilities;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.exoplayer.audio;
|
package androidx.media3.exoplayer.audio;
|
||||||
|
|
||||||
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Util.castNonNull;
|
import static androidx.media3.common.util.Util.castNonNull;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
@ -26,7 +27,6 @@ import android.os.SystemClock;
|
|||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.util.Assertions;
|
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.Retention;
|
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. */
|
/** 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;
|
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 long FORCE_RESET_WORKAROUND_TIMEOUT_MS = 200;
|
||||||
|
|
||||||
private static final int MAX_PLAYHEAD_OFFSET_COUNT = 10;
|
private static final int MAX_PLAYHEAD_OFFSET_COUNT = 10;
|
||||||
@ -174,7 +177,8 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
private boolean isOutputPcm;
|
private boolean isOutputPcm;
|
||||||
private long lastLatencySampleTimeUs;
|
private long lastLatencySampleTimeUs;
|
||||||
private long lastRawPlaybackHeadPosition;
|
private long lastRawPlaybackHeadPositionSampleTimeMs;
|
||||||
|
private long rawPlaybackHeadPosition;
|
||||||
private long rawPlaybackHeadWrapCount;
|
private long rawPlaybackHeadWrapCount;
|
||||||
private long passthroughWorkaroundPauseOffset;
|
private long passthroughWorkaroundPauseOffset;
|
||||||
private int nextPlayheadOffsetIndex;
|
private int nextPlayheadOffsetIndex;
|
||||||
@ -199,7 +203,7 @@ import java.lang.reflect.Method;
|
|||||||
* @param listener A listener for position tracking events.
|
* @param listener A listener for position tracking events.
|
||||||
*/
|
*/
|
||||||
public AudioTrackPositionTracker(Listener listener) {
|
public AudioTrackPositionTracker(Listener listener) {
|
||||||
this.listener = Assertions.checkNotNull(listener);
|
this.listener = checkNotNull(listener);
|
||||||
if (Util.SDK_INT >= 18) {
|
if (Util.SDK_INT >= 18) {
|
||||||
try {
|
try {
|
||||||
getLatencyMethod = AudioTrack.class.getMethod("getLatency", (Class<?>[]) null);
|
getLatencyMethod = AudioTrack.class.getMethod("getLatency", (Class<?>[]) null);
|
||||||
@ -235,7 +239,7 @@ import java.lang.reflect.Method;
|
|||||||
needsPassthroughWorkarounds = isPassthrough && needsPassthroughWorkarounds(outputEncoding);
|
needsPassthroughWorkarounds = isPassthrough && needsPassthroughWorkarounds(outputEncoding);
|
||||||
isOutputPcm = Util.isEncodingLinearPcm(outputEncoding);
|
isOutputPcm = Util.isEncodingLinearPcm(outputEncoding);
|
||||||
bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
|
bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
|
||||||
lastRawPlaybackHeadPosition = 0;
|
rawPlaybackHeadPosition = 0;
|
||||||
rawPlaybackHeadWrapCount = 0;
|
rawPlaybackHeadWrapCount = 0;
|
||||||
passthroughWorkaroundPauseOffset = 0;
|
passthroughWorkaroundPauseOffset = 0;
|
||||||
hasData = false;
|
hasData = false;
|
||||||
@ -253,10 +257,11 @@ import java.lang.reflect.Method;
|
|||||||
if (audioTimestampPoller != null) {
|
if (audioTimestampPoller != null) {
|
||||||
audioTimestampPoller.reset();
|
audioTimestampPoller.reset();
|
||||||
}
|
}
|
||||||
|
resetSyncParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCurrentPositionUs(boolean sourceEnded) {
|
public long getCurrentPositionUs(boolean sourceEnded) {
|
||||||
if (Assertions.checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) {
|
if (checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) {
|
||||||
maybeSampleSyncParams();
|
maybeSampleSyncParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +269,7 @@ import java.lang.reflect.Method;
|
|||||||
// Otherwise, derive a smoothed position by sampling the track's frame position.
|
// Otherwise, derive a smoothed position by sampling the track's frame position.
|
||||||
long systemTimeUs = System.nanoTime() / 1000;
|
long systemTimeUs = System.nanoTime() / 1000;
|
||||||
long positionUs;
|
long positionUs;
|
||||||
AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller);
|
AudioTimestampPoller audioTimestampPoller = checkNotNull(this.audioTimestampPoller);
|
||||||
boolean useGetTimestampMode = audioTimestampPoller.hasAdvancingTimestamp();
|
boolean useGetTimestampMode = audioTimestampPoller.hasAdvancingTimestamp();
|
||||||
if (useGetTimestampMode) {
|
if (useGetTimestampMode) {
|
||||||
// Calculate the speed-adjusted position using the timestamp (which may be in the future).
|
// Calculate the speed-adjusted position using the timestamp (which may be in the future).
|
||||||
@ -282,7 +287,9 @@ import java.lang.reflect.Method;
|
|||||||
// getPlaybackHeadPositionUs() only has a granularity of ~20 ms, so we base the position off
|
// 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
|
// the system clock (and a smoothed offset between it and the playhead position) so as to
|
||||||
// prevent jitter in the reported positions.
|
// prevent jitter in the reported positions.
|
||||||
positionUs = systemTimeUs + smoothedPlayheadOffsetUs;
|
positionUs =
|
||||||
|
Util.getMediaDurationForPlayoutDuration(
|
||||||
|
systemTimeUs + smoothedPlayheadOffsetUs, audioTrackPlaybackSpeed);
|
||||||
}
|
}
|
||||||
if (!sourceEnded) {
|
if (!sourceEnded) {
|
||||||
positionUs = max(0, positionUs - latencyUs);
|
positionUs = max(0, positionUs - latencyUs);
|
||||||
@ -329,12 +336,12 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */
|
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */
|
||||||
public void start() {
|
public void start() {
|
||||||
Assertions.checkNotNull(audioTimestampPoller).reset();
|
checkNotNull(audioTimestampPoller).reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether the audio track is in the playing state. */
|
/** Returns whether the audio track is in the playing state. */
|
||||||
public boolean isPlaying() {
|
public boolean isPlaying() {
|
||||||
return Assertions.checkNotNull(audioTrack).getPlayState() == PLAYSTATE_PLAYING;
|
return checkNotNull(audioTrack).getPlayState() == PLAYSTATE_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,7 +352,7 @@ import java.lang.reflect.Method;
|
|||||||
* @return Whether the caller can write data to the track.
|
* @return Whether the caller can write data to the track.
|
||||||
*/
|
*/
|
||||||
public boolean mayHandleBuffer(long writtenFrames) {
|
public boolean mayHandleBuffer(long writtenFrames) {
|
||||||
@PlayState int playState = Assertions.checkNotNull(audioTrack).getPlayState();
|
@PlayState int playState = checkNotNull(audioTrack).getPlayState();
|
||||||
if (needsPassthroughWorkarounds) {
|
if (needsPassthroughWorkarounds) {
|
||||||
// An AC-3 audio track continues to play data written while it is paused. Stop writing so its
|
// An AC-3 audio track continues to play data written while it is paused. Stop writing so its
|
||||||
// buffer empties. See [Internal: b/18899620].
|
// buffer empties. See [Internal: b/18899620].
|
||||||
@ -426,7 +433,7 @@ import java.lang.reflect.Method;
|
|||||||
if (stopTimestampUs == C.TIME_UNSET) {
|
if (stopTimestampUs == C.TIME_UNSET) {
|
||||||
// The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't
|
// The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't
|
||||||
// supply an advancing position.
|
// supply an advancing position.
|
||||||
Assertions.checkNotNull(audioTimestampPoller).reset();
|
checkNotNull(audioTimestampPoller).reset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// We've handled the end of the stream already, so there's no need to pause the track.
|
// We've handled the end of the stream already, so there's no need to pause the track.
|
||||||
@ -444,15 +451,17 @@ import java.lang.reflect.Method;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void maybeSampleSyncParams() {
|
private void maybeSampleSyncParams() {
|
||||||
|
long systemTimeUs = System.nanoTime() / 1000;
|
||||||
|
if (systemTimeUs - lastPlayheadSampleTimeUs >= MIN_PLAYHEAD_OFFSET_SAMPLE_INTERVAL_US) {
|
||||||
long playbackPositionUs = getPlaybackHeadPositionUs();
|
long playbackPositionUs = getPlaybackHeadPositionUs();
|
||||||
if (playbackPositionUs == 0) {
|
if (playbackPositionUs == 0) {
|
||||||
// The AudioTrack hasn't output anything yet.
|
// The AudioTrack hasn't output anything yet.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
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.
|
// 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;
|
nextPlayheadOffsetIndex = (nextPlayheadOffsetIndex + 1) % MAX_PLAYHEAD_OFFSET_COUNT;
|
||||||
if (playheadOffsetCount < MAX_PLAYHEAD_OFFSET_COUNT) {
|
if (playheadOffsetCount < MAX_PLAYHEAD_OFFSET_COUNT) {
|
||||||
playheadOffsetCount++;
|
playheadOffsetCount++;
|
||||||
@ -470,12 +479,12 @@ import java.lang.reflect.Method;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
maybePollAndCheckTimestamp(systemTimeUs, playbackPositionUs);
|
maybePollAndCheckTimestamp(systemTimeUs);
|
||||||
maybeUpdateLatency(systemTimeUs);
|
maybeUpdateLatency(systemTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) {
|
private void maybePollAndCheckTimestamp(long systemTimeUs) {
|
||||||
AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller);
|
AudioTimestampPoller audioTimestampPoller = checkNotNull(this.audioTimestampPoller);
|
||||||
if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) {
|
if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -483,6 +492,7 @@ import java.lang.reflect.Method;
|
|||||||
// Check the timestamp and accept/reject it.
|
// Check the timestamp and accept/reject it.
|
||||||
long audioTimestampSystemTimeUs = audioTimestampPoller.getTimestampSystemTimeUs();
|
long audioTimestampSystemTimeUs = audioTimestampPoller.getTimestampSystemTimeUs();
|
||||||
long audioTimestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames();
|
long audioTimestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames();
|
||||||
|
long playbackPositionUs = getPlaybackHeadPositionUs();
|
||||||
if (Math.abs(audioTimestampSystemTimeUs - systemTimeUs) > MAX_AUDIO_TIMESTAMP_OFFSET_US) {
|
if (Math.abs(audioTimestampSystemTimeUs - systemTimeUs) > MAX_AUDIO_TIMESTAMP_OFFSET_US) {
|
||||||
listener.onSystemTimeUsMismatch(
|
listener.onSystemTimeUsMismatch(
|
||||||
audioTimestampPositionFrames,
|
audioTimestampPositionFrames,
|
||||||
@ -511,8 +521,7 @@ import java.lang.reflect.Method;
|
|||||||
// Compute the audio track latency, excluding the latency due to the buffer (leaving
|
// Compute the audio track latency, excluding the latency due to the buffer (leaving
|
||||||
// latency due to the mixer and audio hardware driver).
|
// latency due to the mixer and audio hardware driver).
|
||||||
latencyUs =
|
latencyUs =
|
||||||
castNonNull((Integer) getLatencyMethod.invoke(Assertions.checkNotNull(audioTrack)))
|
castNonNull((Integer) getLatencyMethod.invoke(checkNotNull(audioTrack))) * 1000L
|
||||||
* 1000L
|
|
||||||
- bufferSizeUs;
|
- bufferSizeUs;
|
||||||
// Check that the latency is non-negative.
|
// Check that the latency is non-negative.
|
||||||
latencyUs = max(latencyUs, 0);
|
latencyUs = max(latencyUs, 0);
|
||||||
@ -550,7 +559,7 @@ import java.lang.reflect.Method;
|
|||||||
*/
|
*/
|
||||||
private boolean forceHasPendingData() {
|
private boolean forceHasPendingData() {
|
||||||
return needsPassthroughWorkarounds
|
return needsPassthroughWorkarounds
|
||||||
&& Assertions.checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED
|
&& checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED
|
||||||
&& getPlaybackHeadPosition() == 0;
|
&& getPlaybackHeadPosition() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,34 +585,44 @@ import java.lang.reflect.Method;
|
|||||||
* @return The playback head position, in frames.
|
* @return The playback head position, in frames.
|
||||||
*/
|
*/
|
||||||
private long getPlaybackHeadPosition() {
|
private long getPlaybackHeadPosition() {
|
||||||
AudioTrack audioTrack = Assertions.checkNotNull(this.audioTrack);
|
long currentTimeMs = SystemClock.elapsedRealtime();
|
||||||
if (stopTimestampUs != C.TIME_UNSET) {
|
if (stopTimestampUs != C.TIME_UNSET) {
|
||||||
// Simulate the playback head position up to the total number of frames submitted.
|
// 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 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);
|
return min(endPlaybackHeadPosition, stopPlaybackHeadPosition + framesSinceStop);
|
||||||
}
|
}
|
||||||
|
if (currentTimeMs - lastRawPlaybackHeadPositionSampleTimeMs
|
||||||
int state = audioTrack.getPlayState();
|
>= RAW_PLAYBACK_HEAD_POSITION_UPDATE_INTERVAL_MS) {
|
||||||
if (state == PLAYSTATE_STOPPED) {
|
updateRawPlaybackHeadPosition(currentTimeMs);
|
||||||
// The audio track hasn't been started.
|
lastRawPlaybackHeadPositionSampleTimeMs = currentTimeMs;
|
||||||
return 0;
|
}
|
||||||
|
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. Keep initial zero timestamp.
|
||||||
|
return;
|
||||||
|
}
|
||||||
long rawPlaybackHeadPosition = 0xFFFFFFFFL & audioTrack.getPlaybackHeadPosition();
|
long rawPlaybackHeadPosition = 0xFFFFFFFFL & audioTrack.getPlaybackHeadPosition();
|
||||||
if (needsPassthroughWorkarounds) {
|
if (needsPassthroughWorkarounds) {
|
||||||
// Work around an issue with passthrough/direct AudioTracks on platform API versions 21/22
|
// 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
|
// where the playback head position jumps back to zero on paused passthrough/direct audio
|
||||||
// tracks. See [Internal: b/19187573].
|
// tracks. See [Internal: b/19187573].
|
||||||
if (state == PLAYSTATE_PAUSED && rawPlaybackHeadPosition == 0) {
|
if (state == PLAYSTATE_PAUSED && rawPlaybackHeadPosition == 0) {
|
||||||
passthroughWorkaroundPauseOffset = lastRawPlaybackHeadPosition;
|
passthroughWorkaroundPauseOffset = this.rawPlaybackHeadPosition;
|
||||||
}
|
}
|
||||||
rawPlaybackHeadPosition += passthroughWorkaroundPauseOffset;
|
rawPlaybackHeadPosition += passthroughWorkaroundPauseOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Util.SDK_INT <= 29) {
|
if (Util.SDK_INT <= 29) {
|
||||||
if (rawPlaybackHeadPosition == 0
|
if (rawPlaybackHeadPosition == 0
|
||||||
&& lastRawPlaybackHeadPosition > 0
|
&& this.rawPlaybackHeadPosition > 0
|
||||||
&& state == PLAYSTATE_PLAYING) {
|
&& state == PLAYSTATE_PLAYING) {
|
||||||
// If connecting a Bluetooth audio device fails, the AudioTrack may be left in a state
|
// 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
|
// where its Java API is in the playing state, but the native track is stopped. When this
|
||||||
@ -611,19 +630,18 @@ import java.lang.reflect.Method;
|
|||||||
// playback head position and force the track to be reset after
|
// playback head position and force the track to be reset after
|
||||||
// {@link #FORCE_RESET_WORKAROUND_TIMEOUT_MS} has elapsed.
|
// {@link #FORCE_RESET_WORKAROUND_TIMEOUT_MS} has elapsed.
|
||||||
if (forceResetWorkaroundTimeMs == C.TIME_UNSET) {
|
if (forceResetWorkaroundTimeMs == C.TIME_UNSET) {
|
||||||
forceResetWorkaroundTimeMs = SystemClock.elapsedRealtime();
|
forceResetWorkaroundTimeMs = currentTimeMs;
|
||||||
}
|
}
|
||||||
return lastRawPlaybackHeadPosition;
|
return;
|
||||||
} else {
|
} else {
|
||||||
forceResetWorkaroundTimeMs = C.TIME_UNSET;
|
forceResetWorkaroundTimeMs = C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastRawPlaybackHeadPosition > rawPlaybackHeadPosition) {
|
if (this.rawPlaybackHeadPosition > rawPlaybackHeadPosition) {
|
||||||
// The value must have wrapped around.
|
// The value must have wrapped around.
|
||||||
rawPlaybackHeadWrapCount++;
|
rawPlaybackHeadWrapCount++;
|
||||||
}
|
}
|
||||||
lastRawPlaybackHeadPosition = rawPlaybackHeadPosition;
|
this.rawPlaybackHeadPosition = rawPlaybackHeadPosition;
|
||||||
return rawPlaybackHeadPosition + (rawPlaybackHeadWrapCount << 32);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,11 +191,13 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int dequeueInputBufferIndex() {
|
public int dequeueInputBufferIndex() {
|
||||||
|
bufferEnqueuer.maybeThrowException();
|
||||||
return asynchronousMediaCodecCallback.dequeueInputBufferIndex();
|
return asynchronousMediaCodecCallback.dequeueInputBufferIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
|
public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
|
||||||
|
bufferEnqueuer.maybeThrowException();
|
||||||
return asynchronousMediaCodecCallback.dequeueOutputBufferIndex(bufferInfo);
|
return asynchronousMediaCodecCallback.dequeueOutputBufferIndex(bufferInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,8 @@ class AsynchronousMediaCodecBufferEnqueuer {
|
|||||||
blockUntilHandlerThreadIsIdle();
|
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);
|
@Nullable RuntimeException exception = pendingRuntimeException.getAndSet(null);
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
throw exception;
|
throw exception;
|
||||||
|
@ -263,11 +263,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
// else, pendingOutputFormat may already be non-null following a previous flush, and remains
|
// else, pendingOutputFormat may already be non-null following a previous flush, and remains
|
||||||
// set in this case.
|
// 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();
|
availableInputBuffers.clear();
|
||||||
availableOutputBuffers.clear();
|
availableOutputBuffers.clear();
|
||||||
bufferInfos.clear();
|
bufferInfos.clear();
|
||||||
formats.clear();
|
formats.clear();
|
||||||
mediaCodecException = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
|
@ -857,7 +857,7 @@ public final class MediaCodecInfo {
|
|||||||
* @param name The name of the codec.
|
* @param name The name of the codec.
|
||||||
* @return Whether to enable the workaround.
|
* @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)) {
|
if ("OMX.MTK.VIDEO.DECODER.HEVC".equals(name) && "mcv5a".equals(Util.DEVICE)) {
|
||||||
// See https://github.com/google/ExoPlayer/issues/6612.
|
// See https://github.com/google/ExoPlayer/issues/6612.
|
||||||
return false;
|
return false;
|
||||||
@ -876,6 +876,17 @@ public final class MediaCodecInfo {
|
|||||||
&& ("sailfish".equals(Util.DEVICE) || "marlin".equals(Util.DEVICE));
|
&& ("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 */
|
/** Possible outcomes of evaluating PerformancePoint coverage */
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@ -900,7 +911,9 @@ public final class MediaCodecInfo {
|
|||||||
VideoCapabilities videoCapabilities, int width, int height, double frameRate) {
|
VideoCapabilities videoCapabilities, int width, int height, double frameRate) {
|
||||||
List<PerformancePoint> performancePointList =
|
List<PerformancePoint> performancePointList =
|
||||||
videoCapabilities.getSupportedPerformancePoints();
|
videoCapabilities.getSupportedPerformancePoints();
|
||||||
if (performancePointList == null || performancePointList.isEmpty()) {
|
if (performancePointList == null
|
||||||
|
|| performancePointList.isEmpty()
|
||||||
|
|| needsIgnorePerformancePointsWorkaround()) {
|
||||||
return COVERAGE_RESULT_NO_EMPTY_LIST;
|
return COVERAGE_RESULT_NO_EMPTY_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,10 +208,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
*/
|
*/
|
||||||
private static final long MAX_CODEC_HOTSWAP_TIME_MS = 1000;
|
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
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@Target(TYPE_USE)
|
@Target(TYPE_USE)
|
||||||
@ -303,12 +299,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
private final DecoderInputBuffer buffer;
|
private final DecoderInputBuffer buffer;
|
||||||
private final DecoderInputBuffer bypassSampleBuffer;
|
private final DecoderInputBuffer bypassSampleBuffer;
|
||||||
private final BatchBuffer bypassBatchBuffer;
|
private final BatchBuffer bypassBatchBuffer;
|
||||||
private final TimedValueQueue<Format> formatQueue;
|
|
||||||
private final ArrayList<Long> decodeOnlyPresentationTimestamps;
|
private final ArrayList<Long> decodeOnlyPresentationTimestamps;
|
||||||
private final MediaCodec.BufferInfo outputBufferInfo;
|
private final MediaCodec.BufferInfo outputBufferInfo;
|
||||||
private final long[] pendingOutputStreamStartPositionsUs;
|
private final ArrayDeque<OutputStreamInfo> pendingOutputStreamChanges;
|
||||||
private final long[] pendingOutputStreamOffsetsUs;
|
|
||||||
private final long[] pendingOutputStreamSwitchTimesUs;
|
|
||||||
|
|
||||||
@Nullable private Format inputFormat;
|
@Nullable private Format inputFormat;
|
||||||
@Nullable private Format outputFormat;
|
@Nullable private Format outputFormat;
|
||||||
@ -363,9 +356,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
private boolean pendingOutputEndOfStream;
|
private boolean pendingOutputEndOfStream;
|
||||||
@Nullable private ExoPlaybackException pendingPlaybackException;
|
@Nullable private ExoPlaybackException pendingPlaybackException;
|
||||||
protected DecoderCounters decoderCounters;
|
protected DecoderCounters decoderCounters;
|
||||||
private long outputStreamStartPositionUs;
|
private OutputStreamInfo outputStreamInfo;
|
||||||
private long outputStreamOffsetUs;
|
private long lastProcessedOutputBufferTimeUs;
|
||||||
private int pendingOutputStreamOffsetCount;
|
private boolean needToNotifyOutputFormatChangeAfterStreamChange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param trackType The {@link C.TrackType track type} that the renderer handles.
|
* @param trackType The {@link C.TrackType track type} that the renderer handles.
|
||||||
@ -392,17 +385,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
||||||
bypassSampleBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
|
bypassSampleBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
|
||||||
bypassBatchBuffer = new BatchBuffer();
|
bypassBatchBuffer = new BatchBuffer();
|
||||||
formatQueue = new TimedValueQueue<>();
|
|
||||||
decodeOnlyPresentationTimestamps = new ArrayList<>();
|
decodeOnlyPresentationTimestamps = new ArrayList<>();
|
||||||
outputBufferInfo = new MediaCodec.BufferInfo();
|
outputBufferInfo = new MediaCodec.BufferInfo();
|
||||||
currentPlaybackSpeed = 1f;
|
currentPlaybackSpeed = 1f;
|
||||||
targetPlaybackSpeed = 1f;
|
targetPlaybackSpeed = 1f;
|
||||||
renderTimeLimitMs = C.TIME_UNSET;
|
renderTimeLimitMs = C.TIME_UNSET;
|
||||||
pendingOutputStreamStartPositionsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
|
pendingOutputStreamChanges = new ArrayDeque<>();
|
||||||
pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
|
setOutputStreamInfo(OutputStreamInfo.UNSET);
|
||||||
pendingOutputStreamSwitchTimesUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
|
|
||||||
outputStreamStartPositionUs = C.TIME_UNSET;
|
|
||||||
setOutputStreamOffsetUs(C.TIME_UNSET);
|
|
||||||
// MediaCodec outputs audio buffers in native endian:
|
// MediaCodec outputs audio buffers in native endian:
|
||||||
// https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers
|
// https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers
|
||||||
// and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness.
|
// and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness.
|
||||||
@ -419,6 +408,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
codecHotswapDeadlineMs = C.TIME_UNSET;
|
codecHotswapDeadlineMs = C.TIME_UNSET;
|
||||||
largestQueuedPresentationTimeUs = C.TIME_UNSET;
|
largestQueuedPresentationTimeUs = C.TIME_UNSET;
|
||||||
lastBufferInStreamPresentationTimeUs = C.TIME_UNSET;
|
lastBufferInStreamPresentationTimeUs = C.TIME_UNSET;
|
||||||
|
lastProcessedOutputBufferTimeUs = C.TIME_UNSET;
|
||||||
codecDrainState = DRAIN_STATE_NONE;
|
codecDrainState = DRAIN_STATE_NONE;
|
||||||
codecDrainAction = DRAIN_ACTION_NONE;
|
codecDrainAction = DRAIN_ACTION_NONE;
|
||||||
}
|
}
|
||||||
@ -606,13 +596,15 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
protected final void updateOutputFormatForTime(long presentationTimeUs)
|
protected final void updateOutputFormatForTime(long presentationTimeUs)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
boolean outputFormatChanged = false;
|
boolean outputFormatChanged = false;
|
||||||
@Nullable Format format = formatQueue.pollFloor(presentationTimeUs);
|
@Nullable Format format = outputStreamInfo.formatQueue.pollFloor(presentationTimeUs);
|
||||||
if (format == null && codecOutputMediaFormatChanged) {
|
if (format == null
|
||||||
// If the codec's output MediaFormat has changed then there should be a corresponding Format
|
&& needToNotifyOutputFormatChangeAfterStreamChange
|
||||||
// change, which we've not found. Check the Format queue in case the corresponding
|
&& codecOutputMediaFormat != null) {
|
||||||
// presentation timestamp is greater than presentationTimeUs, which can happen for some codecs
|
// After a stream change or after the initial start, there should be an input format change,
|
||||||
// [Internal ref: b/162719047].
|
// which we've not found. Check the Format queue in case the corresponding presentation
|
||||||
format = formatQueue.pollFirst();
|
// 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) {
|
if (format != null) {
|
||||||
outputFormat = format;
|
outputFormat = format;
|
||||||
@ -621,6 +613,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
if (outputFormatChanged || (codecOutputMediaFormatChanged && outputFormat != null)) {
|
if (outputFormatChanged || (codecOutputMediaFormatChanged && outputFormat != null)) {
|
||||||
onOutputFormatChanged(outputFormat, codecOutputMediaFormat);
|
onOutputFormatChanged(outputFormat, codecOutputMediaFormat);
|
||||||
codecOutputMediaFormatChanged = false;
|
codecOutputMediaFormatChanged = false;
|
||||||
|
needToNotifyOutputFormatChangeAfterStreamChange = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,23 +641,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
@Override
|
@Override
|
||||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
if (this.outputStreamOffsetUs == C.TIME_UNSET) {
|
if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET
|
||||||
checkState(this.outputStreamStartPositionUs == C.TIME_UNSET);
|
|| (pendingOutputStreamChanges.isEmpty()
|
||||||
this.outputStreamStartPositionUs = startPositionUs;
|
&& lastProcessedOutputBufferTimeUs != C.TIME_UNSET
|
||||||
setOutputStreamOffsetUs(offsetUs);
|
&& lastProcessedOutputBufferTimeUs >= largestQueuedPresentationTimeUs)) {
|
||||||
|
// This is the first stream, or the previous has been fully output already.
|
||||||
|
setOutputStreamInfo(
|
||||||
|
new OutputStreamInfo(
|
||||||
|
/* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs));
|
||||||
} else {
|
} else {
|
||||||
if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) {
|
pendingOutputStreamChanges.add(
|
||||||
Log.w(
|
new OutputStreamInfo(largestQueuedPresentationTimeUs, startPositionUs, offsetUs));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,16 +670,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
// If there is a format change on the input side still pending propagation to the output, we
|
// 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
|
// 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.
|
// input format after the position reset.
|
||||||
if (formatQueue.size() > 0) {
|
if (outputStreamInfo.formatQueue.size() > 0) {
|
||||||
waitingForFirstSampleInFormat = true;
|
waitingForFirstSampleInFormat = true;
|
||||||
}
|
}
|
||||||
formatQueue.clear();
|
outputStreamInfo.formatQueue.clear();
|
||||||
if (pendingOutputStreamOffsetCount != 0) {
|
pendingOutputStreamChanges.clear();
|
||||||
setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]);
|
|
||||||
outputStreamStartPositionUs =
|
|
||||||
pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1];
|
|
||||||
pendingOutputStreamOffsetCount = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -706,9 +688,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
@Override
|
@Override
|
||||||
protected void onDisabled() {
|
protected void onDisabled() {
|
||||||
inputFormat = null;
|
inputFormat = null;
|
||||||
outputStreamStartPositionUs = C.TIME_UNSET;
|
setOutputStreamInfo(OutputStreamInfo.UNSET);
|
||||||
setOutputStreamOffsetUs(C.TIME_UNSET);
|
pendingOutputStreamChanges.clear();
|
||||||
pendingOutputStreamOffsetCount = 0;
|
|
||||||
flushOrReleaseCodec();
|
flushOrReleaseCodec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,6 +878,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
decodeOnlyPresentationTimestamps.clear();
|
decodeOnlyPresentationTimestamps.clear();
|
||||||
largestQueuedPresentationTimeUs = C.TIME_UNSET;
|
largestQueuedPresentationTimeUs = C.TIME_UNSET;
|
||||||
lastBufferInStreamPresentationTimeUs = C.TIME_UNSET;
|
lastBufferInStreamPresentationTimeUs = C.TIME_UNSET;
|
||||||
|
lastProcessedOutputBufferTimeUs = C.TIME_UNSET;
|
||||||
if (c2Mp3TimestampTracker != null) {
|
if (c2Mp3TimestampTracker != null) {
|
||||||
c2Mp3TimestampTracker.reset();
|
c2Mp3TimestampTracker.reset();
|
||||||
}
|
}
|
||||||
@ -1353,7 +1335,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
decodeOnlyPresentationTimestamps.add(presentationTimeUs);
|
decodeOnlyPresentationTimestamps.add(presentationTimeUs);
|
||||||
}
|
}
|
||||||
if (waitingForFirstSampleInFormat) {
|
if (waitingForFirstSampleInFormat) {
|
||||||
formatQueue.add(presentationTimeUs, inputFormat);
|
if (!pendingOutputStreamChanges.isEmpty()) {
|
||||||
|
pendingOutputStreamChanges.peekLast().formatQueue.add(presentationTimeUs, inputFormat);
|
||||||
|
} else {
|
||||||
|
outputStreamInfo.formatQueue.add(presentationTimeUs, inputFormat);
|
||||||
|
}
|
||||||
waitingForFirstSampleInFormat = false;
|
waitingForFirstSampleInFormat = false;
|
||||||
}
|
}
|
||||||
largestQueuedPresentationTimeUs = max(largestQueuedPresentationTimeUs, presentationTimeUs);
|
largestQueuedPresentationTimeUs = max(largestQueuedPresentationTimeUs, presentationTimeUs);
|
||||||
@ -1593,29 +1579,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
*/
|
*/
|
||||||
@CallSuper
|
@CallSuper
|
||||||
protected void onProcessedOutputBuffer(long presentationTimeUs) {
|
protected void onProcessedOutputBuffer(long presentationTimeUs) {
|
||||||
while (pendingOutputStreamOffsetCount != 0
|
lastProcessedOutputBufferTimeUs = presentationTimeUs;
|
||||||
&& presentationTimeUs >= pendingOutputStreamSwitchTimesUs[0]) {
|
if (!pendingOutputStreamChanges.isEmpty()
|
||||||
outputStreamStartPositionUs = pendingOutputStreamStartPositionsUs[0];
|
&& presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) {
|
||||||
setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[0]);
|
setOutputStreamInfo(pendingOutputStreamChanges.poll());
|
||||||
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);
|
|
||||||
onProcessedStreamChange();
|
onProcessedStreamChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2062,13 +2029,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
* boolean, Format)} to get the playback position with respect to the media.
|
* boolean, Format)} to get the playback position with respect to the media.
|
||||||
*/
|
*/
|
||||||
protected final long getOutputStreamOffsetUs() {
|
protected final long getOutputStreamOffsetUs() {
|
||||||
return outputStreamOffsetUs;
|
return outputStreamInfo.streamOffsetUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOutputStreamOffsetUs(long outputStreamOffsetUs) {
|
private void setOutputStreamInfo(OutputStreamInfo outputStreamInfo) {
|
||||||
this.outputStreamOffsetUs = outputStreamOffsetUs;
|
this.outputStreamInfo = outputStreamInfo;
|
||||||
if (outputStreamOffsetUs != C.TIME_UNSET) {
|
if (outputStreamInfo.streamOffsetUs != C.TIME_UNSET) {
|
||||||
onOutputStreamOffsetUsChanged(outputStreamOffsetUs);
|
needToNotifyOutputFormatChangeAfterStreamChange = true;
|
||||||
|
onOutputStreamOffsetUsChanged(outputStreamInfo.streamOffsetUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2515,6 +2483,28 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
&& "OMX.MTK.AUDIO.DECODER.MP3".equals(name);
|
&& "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 final TimedValueQueue<Format> formatQueue;
|
||||||
|
|
||||||
|
public OutputStreamInfo(
|
||||||
|
long previousStreamLastBufferTimeUs, long startPositionUs, long streamOffsetUs) {
|
||||||
|
this.previousStreamLastBufferTimeUs = previousStreamLastBufferTimeUs;
|
||||||
|
this.startPositionUs = startPositionUs;
|
||||||
|
this.streamOffsetUs = streamOffsetUs;
|
||||||
|
this.formatQueue = new TimedValueQueue<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(31)
|
@RequiresApi(31)
|
||||||
private static final class Api31 {
|
private static final class Api31 {
|
||||||
private Api31() {}
|
private Api31() {}
|
||||||
|
@ -252,7 +252,7 @@ public final class MediaCodecUtil {
|
|||||||
return getVp9ProfileAndLevel(format.codecs, parts);
|
return getVp9ProfileAndLevel(format.codecs, parts);
|
||||||
case CODEC_ID_HEV1:
|
case CODEC_ID_HEV1:
|
||||||
case CODEC_ID_HVC1:
|
case CODEC_ID_HVC1:
|
||||||
return getHevcProfileAndLevel(format.codecs, parts);
|
return getHevcProfileAndLevel(format.codecs, parts, format.colorInfo);
|
||||||
case CODEC_ID_AV01:
|
case CODEC_ID_AV01:
|
||||||
return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo);
|
return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo);
|
||||||
case CODEC_ID_MP4A:
|
case CODEC_ID_MP4A:
|
||||||
@ -731,7 +731,8 @@ public final class MediaCodecUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static Pair<Integer, Integer> getHevcProfileAndLevel(String codec, String[] parts) {
|
private static Pair<Integer, Integer> getHevcProfileAndLevel(
|
||||||
|
String codec, String[] parts, @Nullable ColorInfo colorInfo) {
|
||||||
if (parts.length < 4) {
|
if (parts.length < 4) {
|
||||||
// The codec has fewer parts than required by the HEVC codec string format.
|
// The codec has fewer parts than required by the HEVC codec string format.
|
||||||
Log.w(TAG, "Ignoring malformed HEVC codec string: " + codec);
|
Log.w(TAG, "Ignoring malformed HEVC codec string: " + codec);
|
||||||
@ -748,7 +749,15 @@ public final class MediaCodecUtil {
|
|||||||
if ("1".equals(profileString)) {
|
if ("1".equals(profileString)) {
|
||||||
profile = CodecProfileLevel.HEVCProfileMain;
|
profile = CodecProfileLevel.HEVCProfileMain;
|
||||||
} else if ("2".equals(profileString)) {
|
} else if ("2".equals(profileString)) {
|
||||||
|
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;
|
profile = CodecProfileLevel.HEVCProfileMain10;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Unknown HEVC profile string: " + profileString);
|
Log.w(TAG, "Unknown HEVC profile string: " + profileString);
|
||||||
return null;
|
return null;
|
||||||
|
@ -105,7 +105,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
|
|||||||
return constructor.newInstance(mediaItem, cacheDataSourceFactory, executor);
|
return constructor.newInstance(mediaItem, cacheDataSourceFactory, executor);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Failed to instantiate downloader for content type " + contentType);
|
"Failed to instantiate downloader for content type " + contentType, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +75,9 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> 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 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 DataSpec manifestDataSpec;
|
||||||
private final Parser<M> manifestParser;
|
private final Parser<M> manifestParser;
|
||||||
@ -86,6 +87,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
private final CacheKeyFactory cacheKeyFactory;
|
private final CacheKeyFactory cacheKeyFactory;
|
||||||
@Nullable private final PriorityTaskManager priorityTaskManager;
|
@Nullable private final PriorityTaskManager priorityTaskManager;
|
||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
|
private final long maxMergedSegmentStartTimeDiffUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The currently active runnables.
|
* The currently active runnables.
|
||||||
@ -99,6 +101,24 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
|
|
||||||
private volatile boolean isCanceled;
|
private volatile boolean isCanceled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link SegmentDownloader#SegmentDownloader(MediaItem, Parser,
|
||||||
|
* CacheDataSource.Factory, Executor, long)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public SegmentDownloader(
|
||||||
|
MediaItem mediaItem,
|
||||||
|
Parser<M> 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 mediaItem The {@link MediaItem} to be downloaded.
|
||||||
* @param manifestParser A parser for manifests belonging to the media to be downloaded.
|
* @param manifestParser A parser for manifests belonging to the media to be downloaded.
|
||||||
@ -107,12 +127,16 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
* @param executor An {@link Executor} used to make requests for the media being downloaded.
|
* @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
|
* Providing an {@link Executor} that uses multiple threads will speed up the download by
|
||||||
* allowing parts of it to be executed in parallel.
|
* 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(
|
public SegmentDownloader(
|
||||||
MediaItem mediaItem,
|
MediaItem mediaItem,
|
||||||
Parser<M> manifestParser,
|
Parser<M> manifestParser,
|
||||||
CacheDataSource.Factory cacheDataSourceFactory,
|
CacheDataSource.Factory cacheDataSourceFactory,
|
||||||
Executor executor) {
|
Executor executor,
|
||||||
|
long maxMergedSegmentStartTimeDiffMs) {
|
||||||
checkNotNull(mediaItem.localConfiguration);
|
checkNotNull(mediaItem.localConfiguration);
|
||||||
this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri);
|
this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri);
|
||||||
this.manifestParser = manifestParser;
|
this.manifestParser = manifestParser;
|
||||||
@ -123,6 +147,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory();
|
cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory();
|
||||||
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();
|
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();
|
||||||
activeRunnables = new ArrayList<>();
|
activeRunnables = new ArrayList<>();
|
||||||
|
maxMergedSegmentStartTimeDiffUs = Util.msToUs(maxMergedSegmentStartTimeDiffMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -145,7 +170,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
// Sort the segments so that we download media in the right order from the start of the
|
// 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.
|
// content, and merge segments where possible to minimize the number of server round trips.
|
||||||
Collections.sort(segments);
|
Collections.sort(segments);
|
||||||
mergeSegments(segments, cacheKeyFactory);
|
mergeSegments(segments, cacheKeyFactory, maxMergedSegmentStartTimeDiffUs);
|
||||||
|
|
||||||
// Scan the segments, removing any that are fully downloaded.
|
// Scan the segments, removing any that are fully downloaded.
|
||||||
int totalSegments = segments.size();
|
int totalSegments = segments.size();
|
||||||
@ -416,7 +441,8 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void mergeSegments(List<Segment> segments, CacheKeyFactory keyFactory) {
|
private static void mergeSegments(
|
||||||
|
List<Segment> segments, CacheKeyFactory keyFactory, long maxMergedSegmentStartTimeDiffUs) {
|
||||||
HashMap<String, Integer> lastIndexByCacheKey = new HashMap<>();
|
HashMap<String, Integer> lastIndexByCacheKey = new HashMap<>();
|
||||||
int nextOutIndex = 0;
|
int nextOutIndex = 0;
|
||||||
for (int i = 0; i < segments.size(); i++) {
|
for (int i = 0; i < segments.size(); i++) {
|
||||||
@ -425,7 +451,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||||||
@Nullable Integer lastIndex = lastIndexByCacheKey.get(cacheKey);
|
@Nullable Integer lastIndex = lastIndexByCacheKey.get(cacheKey);
|
||||||
@Nullable Segment lastSegment = lastIndex == null ? null : segments.get(lastIndex);
|
@Nullable Segment lastSegment = lastIndex == null ? null : segments.get(lastIndex);
|
||||||
if (lastSegment == null
|
if (lastSegment == null
|
||||||
|| segment.startTimeUs > lastSegment.startTimeUs + MAX_MERGED_SEGMENT_START_TIME_DIFF_US
|
|| segment.startTimeUs > lastSegment.startTimeUs + maxMergedSegmentStartTimeDiffUs
|
||||||
|| !canMergeSegments(lastSegment.dataSpec, segment.dataSpec)) {
|
|| !canMergeSegments(lastSegment.dataSpec, segment.dataSpec)) {
|
||||||
lastIndexByCacheKey.put(cacheKey, nextOutIndex);
|
lastIndexByCacheKey.put(cacheKey, nextOutIndex);
|
||||||
segments.set(nextOutIndex, segment);
|
segments.set(nextOutIndex, segment);
|
||||||
|
@ -184,8 +184,8 @@ public final class Requirements implements Parcelable {
|
|||||||
private boolean isDeviceCharging(Context context) {
|
private boolean isDeviceCharging(Context context) {
|
||||||
@Nullable
|
@Nullable
|
||||||
Intent batteryStatus =
|
Intent batteryStatus =
|
||||||
Util.registerReceiverNotExported(
|
context.registerReceiver(
|
||||||
context, /* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
/* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||||
if (batteryStatus == null) {
|
if (batteryStatus == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -203,8 +203,8 @@ public final class Requirements implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStorageNotLow(Context context) {
|
private boolean isStorageNotLow(Context context) {
|
||||||
return Util.registerReceiverNotExported(
|
return context.registerReceiver(
|
||||||
context, /* receiver= */ null, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW))
|
/* receiver= */ null, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW))
|
||||||
== null;
|
== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ public final class RequirementsWatcher {
|
|||||||
filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
|
filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
|
||||||
}
|
}
|
||||||
receiver = new DeviceStatusChangeReceiver();
|
receiver = new DeviceStatusChangeReceiver();
|
||||||
Util.registerReceiverNotExported(context, receiver, filter, handler);
|
context.registerReceiver(receiver, filter, /* broadcastPermission= */ null, handler);
|
||||||
return notMetRequirements;
|
return notMetRequirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,12 @@ import java.util.Comparator;
|
|||||||
* rate observations. This is an alternative to sliding mean and exponential averaging which suffer
|
* rate observations. This is an alternative to sliding mean and exponential averaging which suffer
|
||||||
* from susceptibility to outliers and slow adaptation to step functions.
|
* from susceptibility to outliers and slow adaptation to step functions.
|
||||||
*
|
*
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/Moving_average">Wiki: Moving average</a>
|
* <p>See the following Wikipedia articles:
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/Selection_algorithm">Wiki: Selection algorithm</a>
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li><a href="http://en.wikipedia.org/wiki/Moving_average">Moving average</a>
|
||||||
|
* <li><a href="http://en.wikipedia.org/wiki/Selection_algorithm">Selection algorithm</a>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class SlidingPercentile {
|
public class SlidingPercentile {
|
||||||
|
@ -153,6 +153,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
private long lastRenderRealtimeUs;
|
private long lastRenderRealtimeUs;
|
||||||
private long totalVideoFrameProcessingOffsetUs;
|
private long totalVideoFrameProcessingOffsetUs;
|
||||||
private int videoFrameProcessingOffsetCount;
|
private int videoFrameProcessingOffsetCount;
|
||||||
|
private long lastFrameReleaseTimeNs;
|
||||||
|
|
||||||
private int currentWidth;
|
private int currentWidth;
|
||||||
private int currentHeight;
|
private int currentHeight;
|
||||||
@ -1128,9 +1129,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
if (Util.SDK_INT >= 21) {
|
if (Util.SDK_INT >= 21) {
|
||||||
// Let the underlying framework time the release.
|
// Let the underlying framework time the release.
|
||||||
if (earlyUs < 50000) {
|
if (earlyUs < 50000) {
|
||||||
|
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);
|
notifyFrameMetadataListener(presentationTimeUs, adjustedReleaseTimeNs, format);
|
||||||
renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs);
|
renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs);
|
||||||
|
}
|
||||||
updateVideoFrameProcessingOffsetCounters(earlyUs);
|
updateVideoFrameProcessingOffsetCounters(earlyUs);
|
||||||
|
lastFrameReleaseTimeNs = adjustedReleaseTimeNs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Aflaai</string>
|
<string name="exo_download_description">Aflaai</string>
|
||||||
<string name="exo_download_notification_channel_name">Aflaaie</string>
|
<string name="exo_download_notification_channel_name">Aflaaie</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">አውርድ</string>
|
<string name="exo_download_description">አውርድ</string>
|
||||||
<string name="exo_download_notification_channel_name">የወረዱ</string>
|
<string name="exo_download_notification_channel_name">የወረዱ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">تنزيل</string>
|
<string name="exo_download_description">تنزيل</string>
|
||||||
<string name="exo_download_notification_channel_name">عمليات التنزيل</string>
|
<string name="exo_download_notification_channel_name">عمليات التنزيل</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Endirin</string>
|
<string name="exo_download_description">Endirin</string>
|
||||||
<string name="exo_download_notification_channel_name">Endirmələr</string>
|
<string name="exo_download_notification_channel_name">Endirmələr</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Preuzmi</string>
|
<string name="exo_download_description">Preuzmi</string>
|
||||||
<string name="exo_download_notification_channel_name">Preuzimanja</string>
|
<string name="exo_download_notification_channel_name">Preuzimanja</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Спампаваць</string>
|
<string name="exo_download_description">Спампаваць</string>
|
||||||
<string name="exo_download_notification_channel_name">Спампоўкі</string>
|
<string name="exo_download_notification_channel_name">Спампоўкі</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Изтегляне</string>
|
<string name="exo_download_description">Изтегляне</string>
|
||||||
<string name="exo_download_notification_channel_name">Изтегляния</string>
|
<string name="exo_download_notification_channel_name">Изтегляния</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ডাউনলোড করুন</string>
|
<string name="exo_download_description">ডাউনলোড করুন</string>
|
||||||
<string name="exo_download_notification_channel_name">ডাউনলোড</string>
|
<string name="exo_download_notification_channel_name">ডাউনলোড</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Preuzmi</string>
|
<string name="exo_download_description">Preuzmi</string>
|
||||||
<string name="exo_download_notification_channel_name">Preuzimanja</string>
|
<string name="exo_download_notification_channel_name">Preuzimanja</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Baixa</string>
|
<string name="exo_download_description">Baixa</string>
|
||||||
<string name="exo_download_notification_channel_name">Baixades</string>
|
<string name="exo_download_notification_channel_name">Baixades</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Stáhnout</string>
|
<string name="exo_download_description">Stáhnout</string>
|
||||||
<string name="exo_download_notification_channel_name">Stahování</string>
|
<string name="exo_download_notification_channel_name">Stahování</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Download</string>
|
<string name="exo_download_description">Download</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Herunterladen</string>
|
<string name="exo_download_description">Herunterladen</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Λήψη</string>
|
<string name="exo_download_description">Λήψη</string>
|
||||||
<string name="exo_download_notification_channel_name">Λήψεις</string>
|
<string name="exo_download_notification_channel_name">Λήψεις</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Download</string>
|
<string name="exo_download_description">Download</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Download</string>
|
<string name="exo_download_description">Download</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Download</string>
|
<string name="exo_download_description">Download</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Descargar</string>
|
<string name="exo_download_description">Descargar</string>
|
||||||
<string name="exo_download_notification_channel_name">Descargas</string>
|
<string name="exo_download_notification_channel_name">Descargas</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Descargar</string>
|
<string name="exo_download_description">Descargar</string>
|
||||||
<string name="exo_download_notification_channel_name">Descargas</string>
|
<string name="exo_download_notification_channel_name">Descargas</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Allalaadimine</string>
|
<string name="exo_download_description">Allalaadimine</string>
|
||||||
<string name="exo_download_notification_channel_name">Allalaadimised</string>
|
<string name="exo_download_notification_channel_name">Allalaadimised</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Deskargak</string>
|
<string name="exo_download_description">Deskargak</string>
|
||||||
<string name="exo_download_notification_channel_name">Deskargak</string>
|
<string name="exo_download_notification_channel_name">Deskargak</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">بارگیری</string>
|
<string name="exo_download_description">بارگیری</string>
|
||||||
<string name="exo_download_notification_channel_name">بارگیریها</string>
|
<string name="exo_download_notification_channel_name">بارگیریها</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Lataa</string>
|
<string name="exo_download_description">Lataa</string>
|
||||||
<string name="exo_download_notification_channel_name">Lataukset</string>
|
<string name="exo_download_notification_channel_name">Lataukset</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Télécharger</string>
|
<string name="exo_download_description">Télécharger</string>
|
||||||
<string name="exo_download_notification_channel_name">Téléchargements</string>
|
<string name="exo_download_notification_channel_name">Téléchargements</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Télécharger</string>
|
<string name="exo_download_description">Télécharger</string>
|
||||||
<string name="exo_download_notification_channel_name">Téléchargements</string>
|
<string name="exo_download_notification_channel_name">Téléchargements</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Descargar</string>
|
<string name="exo_download_description">Descargar</string>
|
||||||
<string name="exo_download_notification_channel_name">Descargas</string>
|
<string name="exo_download_notification_channel_name">Descargas</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ડાઉનલોડ કરો</string>
|
<string name="exo_download_description">ડાઉનલોડ કરો</string>
|
||||||
<string name="exo_download_notification_channel_name">ડાઉનલોડ</string>
|
<string name="exo_download_notification_channel_name">ડાઉનલોડ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">डाउनलोड करें</string>
|
<string name="exo_download_description">डाउनलोड करें</string>
|
||||||
<string name="exo_download_notification_channel_name">डाउनलोड की गई मीडिया फ़ाइलें</string>
|
<string name="exo_download_notification_channel_name">डाउनलोड की गई मीडिया फ़ाइलें</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Preuzmi</string>
|
<string name="exo_download_description">Preuzmi</string>
|
||||||
<string name="exo_download_notification_channel_name">Preuzimanja</string>
|
<string name="exo_download_notification_channel_name">Preuzimanja</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Letöltés</string>
|
<string name="exo_download_description">Letöltés</string>
|
||||||
<string name="exo_download_notification_channel_name">Letöltések</string>
|
<string name="exo_download_notification_channel_name">Letöltések</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Ներբեռնել</string>
|
<string name="exo_download_description">Ներբեռնել</string>
|
||||||
<string name="exo_download_notification_channel_name">Ներբեռնումներ</string>
|
<string name="exo_download_notification_channel_name">Ներբեռնումներ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Download</string>
|
<string name="exo_download_description">Download</string>
|
||||||
<string name="exo_download_notification_channel_name">Download</string>
|
<string name="exo_download_notification_channel_name">Download</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Sækja</string>
|
<string name="exo_download_description">Sækja</string>
|
||||||
<string name="exo_download_notification_channel_name">Niðurhal</string>
|
<string name="exo_download_notification_channel_name">Niðurhal</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Scarica</string>
|
<string name="exo_download_description">Scarica</string>
|
||||||
<string name="exo_download_notification_channel_name">Download</string>
|
<string name="exo_download_notification_channel_name">Download</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">הורדה</string>
|
<string name="exo_download_description">הורדה</string>
|
||||||
<string name="exo_download_notification_channel_name">הורדות</string>
|
<string name="exo_download_notification_channel_name">הורדות</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ダウンロード</string>
|
<string name="exo_download_description">ダウンロード</string>
|
||||||
<string name="exo_download_notification_channel_name">ダウンロード</string>
|
<string name="exo_download_notification_channel_name">ダウンロード</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ჩამოტვირთვა</string>
|
<string name="exo_download_description">ჩამოტვირთვა</string>
|
||||||
<string name="exo_download_notification_channel_name">ჩამოტვირთვები</string>
|
<string name="exo_download_notification_channel_name">ჩამოტვირთვები</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Жүктеп алу</string>
|
<string name="exo_download_description">Жүктеп алу</string>
|
||||||
<string name="exo_download_notification_channel_name">Жүктеп алынғандар</string>
|
<string name="exo_download_notification_channel_name">Жүктеп алынғандар</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ទាញយក</string>
|
<string name="exo_download_description">ទាញយក</string>
|
||||||
<string name="exo_download_notification_channel_name">ទាញយក</string>
|
<string name="exo_download_notification_channel_name">ទាញយក</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ಡೌನ್ಲೋಡ್</string>
|
<string name="exo_download_description">ಡೌನ್ಲೋಡ್</string>
|
||||||
<string name="exo_download_notification_channel_name">ಡೌನ್ಲೋಡ್ಗಳು</string>
|
<string name="exo_download_notification_channel_name">ಡೌನ್ಲೋಡ್ಗಳು</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">다운로드</string>
|
<string name="exo_download_description">다운로드</string>
|
||||||
<string name="exo_download_notification_channel_name">다운로드</string>
|
<string name="exo_download_notification_channel_name">다운로드</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Жүктөп алуу</string>
|
<string name="exo_download_description">Жүктөп алуу</string>
|
||||||
<string name="exo_download_notification_channel_name">Жүктөлүп алынгандар</string>
|
<string name="exo_download_notification_channel_name">Жүктөлүп алынгандар</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ດາວໂຫລດ</string>
|
<string name="exo_download_description">ດາວໂຫລດ</string>
|
||||||
<string name="exo_download_notification_channel_name">ດາວໂຫລດ</string>
|
<string name="exo_download_notification_channel_name">ດາວໂຫລດ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Atsisiųsti</string>
|
<string name="exo_download_description">Atsisiųsti</string>
|
||||||
<string name="exo_download_notification_channel_name">Atsisiuntimai</string>
|
<string name="exo_download_notification_channel_name">Atsisiuntimai</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Lejupielādēt</string>
|
<string name="exo_download_description">Lejupielādēt</string>
|
||||||
<string name="exo_download_notification_channel_name">Lejupielādes</string>
|
<string name="exo_download_notification_channel_name">Lejupielādes</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Преземи</string>
|
<string name="exo_download_description">Преземи</string>
|
||||||
<string name="exo_download_notification_channel_name">Преземања</string>
|
<string name="exo_download_notification_channel_name">Преземања</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ഡൗൺലോഡ്</string>
|
<string name="exo_download_description">ഡൗൺലോഡ്</string>
|
||||||
<string name="exo_download_notification_channel_name">ഡൗൺലോഡുകൾ</string>
|
<string name="exo_download_notification_channel_name">ഡൗൺലോഡുകൾ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Татах</string>
|
<string name="exo_download_description">Татах</string>
|
||||||
<string name="exo_download_notification_channel_name">Татaлт</string>
|
<string name="exo_download_notification_channel_name">Татaлт</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">डाउनलोड करा</string>
|
<string name="exo_download_description">डाउनलोड करा</string>
|
||||||
<string name="exo_download_notification_channel_name">डाउनलोड</string>
|
<string name="exo_download_notification_channel_name">डाउनलोड</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Muat turun</string>
|
<string name="exo_download_description">Muat turun</string>
|
||||||
<string name="exo_download_notification_channel_name">Muat turun</string>
|
<string name="exo_download_notification_channel_name">Muat turun</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ဒေါင်းလုဒ် လုပ်ရန်</string>
|
<string name="exo_download_description">ဒေါင်းလုဒ် လုပ်ရန်</string>
|
||||||
<string name="exo_download_notification_channel_name">ဒေါင်းလုဒ်များ</string>
|
<string name="exo_download_notification_channel_name">ဒေါင်းလုဒ်များ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Last ned</string>
|
<string name="exo_download_description">Last ned</string>
|
||||||
<string name="exo_download_notification_channel_name">Nedlastinger</string>
|
<string name="exo_download_notification_channel_name">Nedlastinger</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">डाउनलोड गर्नुहोस्</string>
|
<string name="exo_download_description">डाउनलोड गर्नुहोस्</string>
|
||||||
<string name="exo_download_notification_channel_name">डाउनलोडहरू</string>
|
<string name="exo_download_notification_channel_name">डाउनलोडहरू</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Downloaden</string>
|
<string name="exo_download_description">Downloaden</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ਡਾਊਨਲੋਡ ਕਰੋ</string>
|
<string name="exo_download_description">ਡਾਊਨਲੋਡ ਕਰੋ</string>
|
||||||
<string name="exo_download_notification_channel_name">ਡਾਊਨਲੋਡ</string>
|
<string name="exo_download_notification_channel_name">ਡਾਊਨਲੋਡ</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Pobierz</string>
|
<string name="exo_download_description">Pobierz</string>
|
||||||
<string name="exo_download_notification_channel_name">Pobieranie</string>
|
<string name="exo_download_notification_channel_name">Pobieranie</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Transferir</string>
|
<string name="exo_download_description">Transferir</string>
|
||||||
<string name="exo_download_notification_channel_name">Transferências</string>
|
<string name="exo_download_notification_channel_name">Transferências</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Fazer o download</string>
|
<string name="exo_download_description">Fazer o download</string>
|
||||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||||
|
@ -1,20 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Descărcați</string>
|
<string name="exo_download_description">Descarcă</string>
|
||||||
<string name="exo_download_notification_channel_name">Descărcări</string>
|
<string name="exo_download_notification_channel_name">Descărcări</string>
|
||||||
<string name="exo_download_downloading">Se descarcă</string>
|
<string name="exo_download_downloading">Se descarcă</string>
|
||||||
<string name="exo_download_completed">Descărcarea a fost finalizată</string>
|
<string name="exo_download_completed">Descărcarea a fost finalizată</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Скачать</string>
|
<string name="exo_download_description">Скачать</string>
|
||||||
<string name="exo_download_notification_channel_name">Скачивания</string>
|
<string name="exo_download_notification_channel_name">Скачивания</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">බාගන්න</string>
|
<string name="exo_download_description">බාගන්න</string>
|
||||||
<string name="exo_download_notification_channel_name">බාගැනීම්</string>
|
<string name="exo_download_notification_channel_name">බාගැනීම්</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Stiahnuť</string>
|
<string name="exo_download_description">Stiahnuť</string>
|
||||||
<string name="exo_download_notification_channel_name">Stiahnuté</string>
|
<string name="exo_download_notification_channel_name">Stiahnuté</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Prenos</string>
|
<string name="exo_download_description">Prenos</string>
|
||||||
<string name="exo_download_notification_channel_name">Prenosi</string>
|
<string name="exo_download_notification_channel_name">Prenosi</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Shkarko</string>
|
<string name="exo_download_description">Shkarko</string>
|
||||||
<string name="exo_download_notification_channel_name">Shkarkimet</string>
|
<string name="exo_download_notification_channel_name">Shkarkimet</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Преузми</string>
|
<string name="exo_download_description">Преузми</string>
|
||||||
<string name="exo_download_notification_channel_name">Преузимања</string>
|
<string name="exo_download_notification_channel_name">Преузимања</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Ladda ned</string>
|
<string name="exo_download_description">Ladda ned</string>
|
||||||
<string name="exo_download_notification_channel_name">Nedladdningar</string>
|
<string name="exo_download_notification_channel_name">Nedladdningar</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">Pakua</string>
|
<string name="exo_download_description">Pakua</string>
|
||||||
<string name="exo_download_notification_channel_name">Vipakuliwa</string>
|
<string name="exo_download_notification_channel_name">Vipakuliwa</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">பதிவிறக்கும் பட்டன்</string>
|
<string name="exo_download_description">பதிவிறக்கும் பட்டன்</string>
|
||||||
<string name="exo_download_notification_channel_name">பதிவிறக்கங்கள்</string>
|
<string name="exo_download_notification_channel_name">பதிவிறக்கங்கள்</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">డౌన్లోడ్ చేయి</string>
|
<string name="exo_download_description">డౌన్లోడ్ చేయి</string>
|
||||||
<string name="exo_download_notification_channel_name">డౌన్లోడ్లు</string>
|
<string name="exo_download_notification_channel_name">డౌన్లోడ్లు</string>
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="exo_download_description">ดาวน์โหลด</string>
|
<string name="exo_download_description">ดาวน์โหลด</string>
|
||||||
<string name="exo_download_notification_channel_name">ดาวน์โหลด</string>
|
<string name="exo_download_notification_channel_name">ดาวน์โหลด</string>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user