mirror of
https://github.com/samsonjs/media.git
synced 2026-04-04 11:05:47 +00:00
DataSource: Tighten contract to return -1 on premature end-of-input
PiperOrigin-RevId: 363001266
This commit is contained in:
parent
6c9f9f9def
commit
675b81e5f7
12 changed files with 1340 additions and 99 deletions
|
|
@ -33,7 +33,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
|
|
@ -478,10 +477,6 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
|
|||
|
||||
int read = castNonNull(responseByteStream).read(buffer, offset, readLength);
|
||||
if (read == -1) {
|
||||
if (bytesToRead != C.LENGTH_UNSET) {
|
||||
// End of stream reached having not read sufficient data.
|
||||
throw new EOFException();
|
||||
}
|
||||
return C.RESULT_END_OF_INPUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import com.google.android.exoplayer2.util.Log;
|
|||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
|
|
@ -692,10 +691,6 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
|
|||
|
||||
int read = castNonNull(inputStream).read(buffer, offset, readLength);
|
||||
if (read == -1) {
|
||||
if (bytesToRead != C.LENGTH_UNSET) {
|
||||
// End of stream reached having not read sufficient data.
|
||||
throw new EOFException();
|
||||
}
|
||||
return C.RESULT_END_OF_INPUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ public final class ProgressiveDownloader implements Downloader {
|
|||
new CacheWriter(
|
||||
dataSource,
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
progressListener);
|
||||
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();
|
||||
|
|
|
|||
|
|
@ -472,7 +472,6 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
|||
new CacheWriter(
|
||||
dataSource,
|
||||
segment.dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
temporaryBuffer,
|
||||
progressNotifier);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import android.net.Uri;
|
|||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
|
@ -111,10 +110,6 @@ public final class AssetDataSource extends BaseDataSource {
|
|||
}
|
||||
|
||||
if (bytesRead == -1) {
|
||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||
// End of stream reached having not read sufficient data.
|
||||
throw new AssetDataSourceException(new EOFException());
|
||||
}
|
||||
return C.RESULT_END_OF_INPUT;
|
||||
}
|
||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import android.content.res.AssetFileDescriptor;
|
|||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import java.io.EOFException;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
|
@ -147,10 +146,6 @@ public final class ContentDataSource extends BaseDataSource {
|
|||
}
|
||||
|
||||
if (bytesRead == -1) {
|
||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||
// End of stream reached having not read sufficient data.
|
||||
throw new ContentDataSourceException(new EOFException());
|
||||
}
|
||||
return C.RESULT_END_OF_INPUT;
|
||||
}
|
||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,720 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.upstream;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter.EventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* An experimental {@link BandwidthMeter} that estimates bandwidth by listening to data transfers.
|
||||
*
|
||||
* <p>The initial estimate is based on the current operator's network country code or the locale of
|
||||
* the user, as well as the network connection type. This can be configured in the {@link Builder}.
|
||||
*/
|
||||
public final class ExperimentalBandwidthMeter implements BandwidthMeter, TransferListener {
|
||||
|
||||
/**
|
||||
* Country groups used to determine the default initial bitrate estimate. The group assignment for
|
||||
* each country is a list for [Wifi, 2G, 3G, 4G, 5G_NSA].
|
||||
*/
|
||||
public static final ImmutableListMultimap<String, Integer>
|
||||
DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS = createInitialBitrateCountryGroupAssignment();
|
||||
|
||||
/** Default initial Wifi bitrate estimate in bits per second. */
|
||||
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI =
|
||||
ImmutableList.of(6_100_000L, 3_900_000L, 2_300_000L, 1_300_000L, 600_000L);
|
||||
|
||||
/** Default initial 2G bitrate estimates in bits per second. */
|
||||
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_2G =
|
||||
ImmutableList.of(230_000L, 159_000L, 142_000L, 127_000L, 112_000L);
|
||||
|
||||
/** Default initial 3G bitrate estimates in bits per second. */
|
||||
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_3G =
|
||||
ImmutableList.of(2_200_000L, 1_300_000L, 940_000L, 760_000L, 520_000L);
|
||||
|
||||
/** Default initial 4G bitrate estimates in bits per second. */
|
||||
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_4G =
|
||||
ImmutableList.of(4_400_000L, 2_300_000L, 1_500_000L, 1_100_000L, 660_000L);
|
||||
|
||||
/** Default initial 5G-NSA bitrate estimates in bits per second. */
|
||||
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA =
|
||||
ImmutableList.of(13_000_000L, 9_100_000L, 6_300_000L, 4_000_000L, 2_000_000L);
|
||||
|
||||
@Nullable private static ExperimentalBandwidthMeter singletonInstance;
|
||||
|
||||
/**
|
||||
* Default initial bitrate estimate used when the device is offline or the network type cannot be
|
||||
* determined, in bits per second.
|
||||
*/
|
||||
public static final long DEFAULT_INITIAL_BITRATE_ESTIMATE = 1_000_000;
|
||||
|
||||
/** Index for the Wifi group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
|
||||
private static final int COUNTRY_GROUP_INDEX_WIFI = 0;
|
||||
/** Index for the 2G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
|
||||
private static final int COUNTRY_GROUP_INDEX_2G = 1;
|
||||
/** Index for the 3G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
|
||||
private static final int COUNTRY_GROUP_INDEX_3G = 2;
|
||||
/** Index for the 4G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
|
||||
private static final int COUNTRY_GROUP_INDEX_4G = 3;
|
||||
/** Index for the 5G-NSA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
|
||||
private static final int COUNTRY_GROUP_INDEX_5G_NSA = 4;
|
||||
|
||||
/** Builder for a bandwidth meter. */
|
||||
public static final class Builder {
|
||||
|
||||
@Nullable private final Context context;
|
||||
|
||||
private Map<Integer, Long> initialBitrateEstimates;
|
||||
private Clock clock;
|
||||
private boolean resetOnNetworkTypeChange;
|
||||
|
||||
/**
|
||||
* Creates a builder with default parameters and without listener.
|
||||
*
|
||||
* @param context A context.
|
||||
*/
|
||||
public Builder(Context context) {
|
||||
// Handling of null is for backward compatibility only.
|
||||
this.context = context == null ? null : context.getApplicationContext();
|
||||
initialBitrateEstimates = getInitialBitrateEstimatesForCountry(Util.getCountryCode(context));
|
||||
clock = Clock.DEFAULT;
|
||||
resetOnNetworkTypeChange = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial bitrate estimate in bits per second that should be assumed when a bandwidth
|
||||
* estimate is unavailable.
|
||||
*
|
||||
* @param initialBitrateEstimate The initial bitrate estimate in bits per second.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setInitialBitrateEstimate(long initialBitrateEstimate) {
|
||||
for (Integer networkType : initialBitrateEstimates.keySet()) {
|
||||
setInitialBitrateEstimate(networkType, initialBitrateEstimate);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial bitrate estimate in bits per second that should be assumed when a bandwidth
|
||||
* estimate is unavailable and the current network connection is of the specified type.
|
||||
*
|
||||
* @param networkType The {@link C.NetworkType} this initial estimate is for.
|
||||
* @param initialBitrateEstimate The initial bitrate estimate in bits per second.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setInitialBitrateEstimate(
|
||||
@C.NetworkType int networkType, long initialBitrateEstimate) {
|
||||
initialBitrateEstimates.put(networkType, initialBitrateEstimate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial bitrate estimates to the default values of the specified country. The
|
||||
* initial estimates are used when a bandwidth estimate is unavailable.
|
||||
*
|
||||
* @param countryCode The ISO 3166-1 alpha-2 country code of the country whose default bitrate
|
||||
* estimates should be used.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setInitialBitrateEstimate(String countryCode) {
|
||||
initialBitrateEstimates =
|
||||
getInitialBitrateEstimatesForCountry(Util.toUpperInvariant(countryCode));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clock used to estimate bandwidth from data transfers. Should only be set for testing
|
||||
* purposes.
|
||||
*
|
||||
* @param clock The clock used to estimate bandwidth from data transfers.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setClock(Clock clock) {
|
||||
this.clock = clock;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to reset if the network type changes. The default value is {@code true}.
|
||||
*
|
||||
* @param resetOnNetworkTypeChange Whether to reset if the network type changes.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setResetOnNetworkTypeChange(boolean resetOnNetworkTypeChange) {
|
||||
this.resetOnNetworkTypeChange = resetOnNetworkTypeChange;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the bandwidth meter.
|
||||
*
|
||||
* @return A bandwidth meter with the configured properties.
|
||||
*/
|
||||
public ExperimentalBandwidthMeter build() {
|
||||
return new ExperimentalBandwidthMeter(
|
||||
context, initialBitrateEstimates, clock, resetOnNetworkTypeChange);
|
||||
}
|
||||
|
||||
private static Map<Integer, Long> getInitialBitrateEstimatesForCountry(String countryCode) {
|
||||
List<Integer> groupIndices = getCountryGroupIndices(countryCode);
|
||||
Map<Integer, Long> result = new HashMap<>(/* initialCapacity= */ 6);
|
||||
result.put(C.NETWORK_TYPE_UNKNOWN, DEFAULT_INITIAL_BITRATE_ESTIMATE);
|
||||
result.put(
|
||||
C.NETWORK_TYPE_WIFI,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices.get(COUNTRY_GROUP_INDEX_WIFI)));
|
||||
result.put(
|
||||
C.NETWORK_TYPE_2G,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_2G.get(groupIndices.get(COUNTRY_GROUP_INDEX_2G)));
|
||||
result.put(
|
||||
C.NETWORK_TYPE_3G,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_3G.get(groupIndices.get(COUNTRY_GROUP_INDEX_3G)));
|
||||
result.put(
|
||||
C.NETWORK_TYPE_4G,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G.get(groupIndices.get(COUNTRY_GROUP_INDEX_4G)));
|
||||
result.put(
|
||||
C.NETWORK_TYPE_5G,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get(
|
||||
groupIndices.get(COUNTRY_GROUP_INDEX_5G_NSA)));
|
||||
// Assume default Wifi speed for Ethernet to prevent using the slower fallback.
|
||||
result.put(
|
||||
C.NETWORK_TYPE_ETHERNET,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices.get(COUNTRY_GROUP_INDEX_WIFI)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ImmutableList<Integer> getCountryGroupIndices(String countryCode) {
|
||||
ImmutableList<Integer> groupIndices = DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS.get(countryCode);
|
||||
// Assume median group if not found.
|
||||
return groupIndices.isEmpty() ? ImmutableList.of(2, 2, 2, 2, 2) : groupIndices;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a singleton instance of an {@link ExperimentalBandwidthMeter} with default
|
||||
* configuration.
|
||||
*
|
||||
* @param context A {@link Context}.
|
||||
* @return The singleton instance.
|
||||
*/
|
||||
public static synchronized ExperimentalBandwidthMeter getSingletonInstance(Context context) {
|
||||
if (singletonInstance == null) {
|
||||
singletonInstance = new Builder(context).build();
|
||||
}
|
||||
return singletonInstance;
|
||||
}
|
||||
|
||||
@Nullable private final Context context;
|
||||
private final ImmutableMap<Integer, Long> initialBitrateEstimates;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final Clock clock;
|
||||
|
||||
private int streamCount;
|
||||
private long sampleStartTimeMs;
|
||||
private long sampleBytesTransferred;
|
||||
|
||||
@C.NetworkType private int networkType;
|
||||
private long bitrateEstimate;
|
||||
private long lastReportedBitrateEstimate;
|
||||
|
||||
private boolean networkTypeOverrideSet;
|
||||
@C.NetworkType private int networkTypeOverride;
|
||||
|
||||
private ExperimentalBandwidthMeter(
|
||||
@Nullable Context context,
|
||||
Map<Integer, Long> initialBitrateEstimates,
|
||||
Clock clock,
|
||||
boolean resetOnNetworkTypeChange) {
|
||||
this.context = context == null ? null : context.getApplicationContext();
|
||||
this.initialBitrateEstimates = ImmutableMap.copyOf(initialBitrateEstimates);
|
||||
this.eventDispatcher = new EventDispatcher();
|
||||
this.clock = clock;
|
||||
// Set the initial network type and bitrate estimate
|
||||
networkType = context == null ? C.NETWORK_TYPE_UNKNOWN : Util.getNetworkType(context);
|
||||
bitrateEstimate = getInitialBitrateEstimateForNetworkType(networkType);
|
||||
// Register to receive connectivity actions if possible.
|
||||
if (context != null && resetOnNetworkTypeChange) {
|
||||
ConnectivityActionReceiver connectivityActionReceiver =
|
||||
ConnectivityActionReceiver.getInstance(context);
|
||||
connectivityActionReceiver.register(/* bandwidthMeter= */ this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the network type. Handled in the same way as if the meter had detected a change from
|
||||
* the current network type to the specified network type internally.
|
||||
*
|
||||
* <p>Applications should not normally call this method. It is intended for testing purposes.
|
||||
*
|
||||
* @param networkType The overriding network type.
|
||||
*/
|
||||
public synchronized void setNetworkTypeOverride(@C.NetworkType int networkType) {
|
||||
networkTypeOverride = networkType;
|
||||
networkTypeOverrideSet = true;
|
||||
onConnectivityAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long getBitrateEstimate() {
|
||||
return bitrateEstimate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferListener getTransferListener() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventListener(Handler eventHandler, EventListener eventListener) {
|
||||
Assertions.checkNotNull(eventHandler);
|
||||
Assertions.checkNotNull(eventListener);
|
||||
eventDispatcher.addListener(eventHandler, eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEventListener(EventListener eventListener) {
|
||||
eventDispatcher.removeListener(eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransferInitializing(DataSource source, DataSpec dataSpec, boolean isNetwork) {
|
||||
// TODO: Track time for time-to-response estimation.
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onTransferStart(
|
||||
DataSource source, DataSpec dataSpec, boolean isNetwork) {
|
||||
if (!isTransferAtFullNetworkSpeed(dataSpec, isNetwork)) {
|
||||
return;
|
||||
}
|
||||
if (streamCount == 0) {
|
||||
sampleStartTimeMs = clock.elapsedRealtime();
|
||||
}
|
||||
streamCount++;
|
||||
|
||||
// TODO: Track time for time-to-response estimation.
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onBytesTransferred(
|
||||
DataSource source, DataSpec dataSpec, boolean isNetwork, int bytes) {
|
||||
if (!isTransferAtFullNetworkSpeed(dataSpec, isNetwork)) {
|
||||
return;
|
||||
}
|
||||
sampleBytesTransferred += bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onTransferEnd(DataSource source, DataSpec dataSpec, boolean isNetwork) {
|
||||
if (!isTransferAtFullNetworkSpeed(dataSpec, isNetwork)) {
|
||||
return;
|
||||
}
|
||||
Assertions.checkState(streamCount > 0);
|
||||
long nowMs = clock.elapsedRealtime();
|
||||
int sampleElapsedTimeMs = (int) (nowMs - sampleStartTimeMs);
|
||||
if (sampleElapsedTimeMs > 0) {
|
||||
// TODO: Add heuristic for bandwidth estimation.
|
||||
bitrateEstimate = (long) (sampleBytesTransferred * 8000f) / sampleElapsedTimeMs;
|
||||
maybeNotifyBandwidthSample(sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate);
|
||||
sampleStartTimeMs = nowMs;
|
||||
sampleBytesTransferred = 0;
|
||||
} // Else any sample bytes transferred will be carried forward into the next sample.
|
||||
streamCount--;
|
||||
}
|
||||
|
||||
private synchronized void onConnectivityAction() {
|
||||
int networkType =
|
||||
networkTypeOverrideSet
|
||||
? networkTypeOverride
|
||||
: (context == null ? C.NETWORK_TYPE_UNKNOWN : Util.getNetworkType(context));
|
||||
if (this.networkType == networkType) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.networkType = networkType;
|
||||
if (networkType == C.NETWORK_TYPE_OFFLINE
|
||||
|| networkType == C.NETWORK_TYPE_UNKNOWN
|
||||
|| networkType == C.NETWORK_TYPE_OTHER) {
|
||||
// It's better not to reset the bandwidth meter for these network types.
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the bitrate estimate and report it, along with any bytes transferred.
|
||||
this.bitrateEstimate = getInitialBitrateEstimateForNetworkType(networkType);
|
||||
long nowMs = clock.elapsedRealtime();
|
||||
int sampleElapsedTimeMs = streamCount > 0 ? (int) (nowMs - sampleStartTimeMs) : 0;
|
||||
maybeNotifyBandwidthSample(sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate);
|
||||
|
||||
// Reset the remainder of the state.
|
||||
sampleStartTimeMs = nowMs;
|
||||
sampleBytesTransferred = 0;
|
||||
}
|
||||
|
||||
private void maybeNotifyBandwidthSample(
|
||||
int elapsedMs, long bytesTransferred, long bitrateEstimate) {
|
||||
if (elapsedMs == 0 && bytesTransferred == 0 && bitrateEstimate == lastReportedBitrateEstimate) {
|
||||
return;
|
||||
}
|
||||
lastReportedBitrateEstimate = bitrateEstimate;
|
||||
eventDispatcher.bandwidthSample(elapsedMs, bytesTransferred, bitrateEstimate);
|
||||
}
|
||||
|
||||
private long getInitialBitrateEstimateForNetworkType(@C.NetworkType int networkType) {
|
||||
Long initialBitrateEstimate = initialBitrateEstimates.get(networkType);
|
||||
if (initialBitrateEstimate == null) {
|
||||
initialBitrateEstimate = initialBitrateEstimates.get(C.NETWORK_TYPE_UNKNOWN);
|
||||
}
|
||||
if (initialBitrateEstimate == null) {
|
||||
initialBitrateEstimate = DEFAULT_INITIAL_BITRATE_ESTIMATE;
|
||||
}
|
||||
return initialBitrateEstimate;
|
||||
}
|
||||
|
||||
private static boolean isTransferAtFullNetworkSpeed(DataSpec dataSpec, boolean isNetwork) {
|
||||
return isNetwork && !dataSpec.isFlagSet(DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: This class only holds a weak reference to bandwidth meter instances. It should not
|
||||
* be made non-static, since doing so adds a strong reference (i.e.,
|
||||
* ExperimentalBandwidthMeter.this).
|
||||
*/
|
||||
private static class ConnectivityActionReceiver extends BroadcastReceiver {
|
||||
|
||||
private static @MonotonicNonNull ConnectivityActionReceiver staticInstance;
|
||||
|
||||
private final Handler mainHandler;
|
||||
private final ArrayList<WeakReference<ExperimentalBandwidthMeter>> bandwidthMeters;
|
||||
|
||||
public static synchronized ConnectivityActionReceiver getInstance(Context context) {
|
||||
if (staticInstance == null) {
|
||||
staticInstance = new ConnectivityActionReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
context.registerReceiver(staticInstance, filter);
|
||||
}
|
||||
return staticInstance;
|
||||
}
|
||||
|
||||
private ConnectivityActionReceiver() {
|
||||
mainHandler = new Handler(Looper.getMainLooper());
|
||||
bandwidthMeters = new ArrayList<>();
|
||||
}
|
||||
|
||||
public synchronized void register(ExperimentalBandwidthMeter bandwidthMeter) {
|
||||
removeClearedReferences();
|
||||
bandwidthMeters.add(new WeakReference<>(bandwidthMeter));
|
||||
// Simulate an initial update on the main thread (like the sticky broadcast we'd receive if
|
||||
// we were to register a separate broadcast receiver for each bandwidth meter).
|
||||
mainHandler.post(() -> updateBandwidthMeter(bandwidthMeter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onReceive(Context context, Intent intent) {
|
||||
if (isInitialStickyBroadcast()) {
|
||||
return;
|
||||
}
|
||||
removeClearedReferences();
|
||||
for (int i = 0; i < bandwidthMeters.size(); i++) {
|
||||
WeakReference<ExperimentalBandwidthMeter> bandwidthMeterReference = bandwidthMeters.get(i);
|
||||
ExperimentalBandwidthMeter bandwidthMeter = bandwidthMeterReference.get();
|
||||
if (bandwidthMeter != null) {
|
||||
updateBandwidthMeter(bandwidthMeter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBandwidthMeter(ExperimentalBandwidthMeter bandwidthMeter) {
|
||||
bandwidthMeter.onConnectivityAction();
|
||||
}
|
||||
|
||||
private void removeClearedReferences() {
|
||||
for (int i = bandwidthMeters.size() - 1; i >= 0; i--) {
|
||||
WeakReference<ExperimentalBandwidthMeter> bandwidthMeterReference = bandwidthMeters.get(i);
|
||||
ExperimentalBandwidthMeter bandwidthMeter = bandwidthMeterReference.get();
|
||||
if (bandwidthMeter == null) {
|
||||
bandwidthMeters.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ImmutableListMultimap<String, Integer>
|
||||
createInitialBitrateCountryGroupAssignment() {
|
||||
ImmutableListMultimap.Builder<String, Integer> countryGroupAssignment =
|
||||
ImmutableListMultimap.builder();
|
||||
countryGroupAssignment.putAll("AD", 1, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("AE", 1, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("AF", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("AG", 4, 2, 1, 4, 2);
|
||||
countryGroupAssignment.putAll("AI", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("AL", 1, 1, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("AM", 2, 2, 1, 3, 2);
|
||||
countryGroupAssignment.putAll("AO", 3, 4, 3, 1, 2);
|
||||
countryGroupAssignment.putAll("AR", 2, 4, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("AS", 2, 2, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("AT", 0, 2, 0, 0, 0);
|
||||
countryGroupAssignment.putAll("AU", 0, 2, 0, 1, 1);
|
||||
countryGroupAssignment.putAll("AW", 1, 2, 0, 4, 2);
|
||||
countryGroupAssignment.putAll("AX", 0, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("AZ", 3, 3, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("BA", 1, 1, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("BB", 0, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("BD", 2, 0, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("BE", 0, 0, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("BF", 4, 4, 4, 2, 2);
|
||||
countryGroupAssignment.putAll("BG", 0, 1, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("BH", 1, 0, 2, 4, 3);
|
||||
countryGroupAssignment.putAll("BI", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("BJ", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("BL", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("BM", 0, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("BN", 3, 2, 1, 0, 2);
|
||||
countryGroupAssignment.putAll("BO", 1, 2, 4, 2, 2);
|
||||
countryGroupAssignment.putAll("BQ", 1, 2, 1, 3, 2);
|
||||
countryGroupAssignment.putAll("BR", 2, 4, 2, 2, 3);
|
||||
countryGroupAssignment.putAll("BS", 2, 2, 1, 3, 2);
|
||||
countryGroupAssignment.putAll("BT", 3, 0, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("BW", 3, 4, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("BY", 1, 1, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("BZ", 2, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("CA", 0, 3, 1, 2, 4);
|
||||
countryGroupAssignment.putAll("CD", 4, 3, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("CF", 4, 2, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("CG", 3, 4, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("CH", 0, 0, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("CI", 3, 3, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("CK", 2, 2, 3, 0, 2);
|
||||
countryGroupAssignment.putAll("CL", 1, 1, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("CM", 3, 4, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("CN", 2, 2, 2, 1, 4);
|
||||
countryGroupAssignment.putAll("CO", 2, 3, 4, 2, 2);
|
||||
countryGroupAssignment.putAll("CR", 2, 3, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("CU", 4, 4, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("CV", 2, 3, 1, 0, 2);
|
||||
countryGroupAssignment.putAll("CW", 1, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("CY", 1, 1, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("CZ", 0, 1, 0, 0, 1);
|
||||
countryGroupAssignment.putAll("DE", 0, 0, 1, 1, 0);
|
||||
countryGroupAssignment.putAll("DJ", 4, 0, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("DK", 0, 0, 1, 0, 0);
|
||||
countryGroupAssignment.putAll("DM", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("DO", 3, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("DZ", 3, 3, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("EC", 2, 4, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("EE", 0, 1, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("EG", 3, 4, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("EH", 2, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("ER", 4, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("ES", 0, 1, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("ET", 4, 4, 4, 1, 2);
|
||||
countryGroupAssignment.putAll("FI", 0, 0, 0, 0, 0);
|
||||
countryGroupAssignment.putAll("FJ", 3, 0, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("FK", 4, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("FM", 3, 2, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("FO", 1, 2, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("FR", 1, 1, 2, 0, 1);
|
||||
countryGroupAssignment.putAll("GA", 3, 4, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("GB", 0, 0, 1, 1, 1);
|
||||
countryGroupAssignment.putAll("GD", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("GE", 1, 1, 1, 3, 2);
|
||||
countryGroupAssignment.putAll("GF", 2, 2, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("GG", 1, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("GH", 3, 1, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("GI", 0, 2, 2, 0, 2);
|
||||
countryGroupAssignment.putAll("GL", 1, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("GM", 4, 3, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("GN", 3, 3, 4, 2, 2);
|
||||
countryGroupAssignment.putAll("GP", 2, 1, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("GQ", 4, 2, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("GR", 1, 2, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("GT", 3, 2, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("GU", 1, 2, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("GW", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("GY", 3, 3, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("HK", 0, 1, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("HN", 3, 1, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("HR", 1, 1, 0, 0, 3);
|
||||
countryGroupAssignment.putAll("HT", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("HU", 0, 0, 0, 0, 1);
|
||||
countryGroupAssignment.putAll("ID", 3, 2, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("IE", 0, 0, 1, 1, 3);
|
||||
countryGroupAssignment.putAll("IL", 1, 0, 2, 3, 4);
|
||||
countryGroupAssignment.putAll("IM", 0, 2, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("IN", 2, 1, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("IO", 4, 2, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("IQ", 3, 3, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("IR", 3, 2, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("IS", 0, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("IT", 0, 4, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("JE", 2, 2, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("JM", 3, 3, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("JO", 2, 2, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("JP", 0, 0, 0, 0, 3);
|
||||
countryGroupAssignment.putAll("KE", 3, 4, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("KG", 2, 0, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("KH", 1, 0, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("KI", 4, 2, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("KM", 4, 3, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("KN", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("KP", 4, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("KR", 0, 0, 1, 3, 1);
|
||||
countryGroupAssignment.putAll("KW", 1, 3, 0, 0, 0);
|
||||
countryGroupAssignment.putAll("KY", 1, 2, 0, 2, 2);
|
||||
countryGroupAssignment.putAll("KZ", 2, 2, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("LA", 2, 2, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("LB", 3, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("LC", 1, 2, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("LI", 0, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("LK", 2, 0, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("LR", 3, 4, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("LS", 3, 3, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("LT", 0, 0, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("LU", 1, 0, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("LV", 0, 0, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("LY", 4, 2, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("MA", 3, 2, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("MC", 0, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("MD", 1, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("ME", 1, 2, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("MF", 1, 2, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("MG", 3, 4, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("MH", 4, 2, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("MK", 1, 1, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("ML", 4, 4, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("MM", 2, 3, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("MN", 2, 4, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("MO", 0, 2, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("MP", 0, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("MQ", 2, 2, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("MR", 3, 0, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("MS", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("MT", 0, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("MU", 3, 1, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("MV", 4, 3, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("MW", 4, 2, 1, 0, 2);
|
||||
countryGroupAssignment.putAll("MX", 2, 4, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("MY", 1, 0, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("MZ", 3, 3, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("NA", 4, 3, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("NC", 2, 0, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("NE", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("NF", 2, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("NG", 3, 3, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("NI", 2, 1, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("NL", 0, 2, 3, 2, 0);
|
||||
countryGroupAssignment.putAll("NO", 0, 1, 2, 0, 0);
|
||||
countryGroupAssignment.putAll("NP", 2, 0, 4, 2, 2);
|
||||
countryGroupAssignment.putAll("NR", 3, 2, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("NU", 4, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("NZ", 0, 2, 1, 2, 4);
|
||||
countryGroupAssignment.putAll("OM", 2, 2, 1, 3, 2);
|
||||
countryGroupAssignment.putAll("PA", 1, 3, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("PE", 2, 3, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("PF", 2, 2, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("PG", 4, 4, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("PH", 2, 1, 3, 3, 4);
|
||||
countryGroupAssignment.putAll("PK", 3, 2, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("PL", 1, 0, 1, 2, 3);
|
||||
countryGroupAssignment.putAll("PM", 0, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("PR", 2, 1, 2, 2, 4);
|
||||
countryGroupAssignment.putAll("PS", 3, 3, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("PT", 0, 1, 1, 0, 2);
|
||||
countryGroupAssignment.putAll("PW", 1, 2, 4, 0, 2);
|
||||
countryGroupAssignment.putAll("PY", 2, 0, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("QA", 2, 3, 1, 2, 3);
|
||||
countryGroupAssignment.putAll("RE", 1, 0, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("RO", 0, 1, 0, 1, 1);
|
||||
countryGroupAssignment.putAll("RS", 1, 2, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("RU", 0, 1, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("RW", 3, 3, 4, 1, 2);
|
||||
countryGroupAssignment.putAll("SA", 2, 2, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("SB", 4, 2, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("SC", 4, 1, 1, 3, 2);
|
||||
countryGroupAssignment.putAll("SD", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("SE", 0, 0, 0, 0, 0);
|
||||
countryGroupAssignment.putAll("SG", 1, 0, 1, 2, 3);
|
||||
countryGroupAssignment.putAll("SH", 4, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("SI", 0, 0, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("SJ", 2, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("SK", 0, 1, 0, 0, 2);
|
||||
countryGroupAssignment.putAll("SL", 4, 3, 4, 0, 2);
|
||||
countryGroupAssignment.putAll("SM", 0, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("SN", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("SO", 3, 3, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("SR", 3, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("SS", 4, 4, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("ST", 2, 2, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("SV", 2, 1, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("SX", 2, 2, 1, 0, 2);
|
||||
countryGroupAssignment.putAll("SY", 4, 3, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("SZ", 4, 3, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("TC", 2, 2, 2, 0, 2);
|
||||
countryGroupAssignment.putAll("TD", 4, 3, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("TG", 3, 2, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("TH", 0, 3, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("TJ", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("TL", 4, 0, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("TM", 4, 2, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("TN", 2, 2, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("TO", 3, 2, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("TR", 1, 2, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("TT", 1, 4, 0, 1, 2);
|
||||
countryGroupAssignment.putAll("TV", 3, 2, 2, 4, 2);
|
||||
countryGroupAssignment.putAll("TW", 0, 0, 0, 0, 1);
|
||||
countryGroupAssignment.putAll("TZ", 3, 3, 3, 2, 2);
|
||||
countryGroupAssignment.putAll("UA", 0, 3, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("UG", 3, 2, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("US", 1, 1, 2, 2, 4);
|
||||
countryGroupAssignment.putAll("UY", 2, 1, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("UZ", 2, 1, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("VC", 1, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("VE", 4, 4, 4, 4, 2);
|
||||
countryGroupAssignment.putAll("VG", 2, 2, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("VI", 1, 2, 1, 2, 2);
|
||||
countryGroupAssignment.putAll("VN", 0, 1, 3, 4, 2);
|
||||
countryGroupAssignment.putAll("VU", 4, 0, 3, 1, 2);
|
||||
countryGroupAssignment.putAll("WF", 4, 2, 2, 2, 2);
|
||||
countryGroupAssignment.putAll("WS", 3, 1, 3, 1, 2);
|
||||
countryGroupAssignment.putAll("XK", 0, 1, 1, 1, 2);
|
||||
countryGroupAssignment.putAll("YE", 4, 4, 4, 3, 2);
|
||||
countryGroupAssignment.putAll("YT", 4, 2, 2, 3, 2);
|
||||
countryGroupAssignment.putAll("ZA", 3, 3, 2, 1, 2);
|
||||
countryGroupAssignment.putAll("ZM", 3, 2, 3, 3, 2);
|
||||
countryGroupAssignment.putAll("ZW", 3, 2, 4, 3, 2);
|
||||
return countryGroupAssignment.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.DataSpec;
|
|||
import com.google.android.exoplayer2.util.PriorityTaskManager;
|
||||
import com.google.android.exoplayer2.util.PriorityTaskManager.PriorityTooLowException;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
|
|
@ -51,7 +50,6 @@ public final class CacheWriter {
|
|||
private final CacheDataSource dataSource;
|
||||
private final Cache cache;
|
||||
private final DataSpec dataSpec;
|
||||
private final boolean allowShortContent;
|
||||
private final String cacheKey;
|
||||
private final byte[] temporaryBuffer;
|
||||
@Nullable private final ProgressListener progressListener;
|
||||
|
|
@ -65,10 +63,6 @@ public final class CacheWriter {
|
|||
/**
|
||||
* @param dataSource A {@link CacheDataSource} that writes to the target cache.
|
||||
* @param dataSpec Defines the data to be written.
|
||||
* @param allowShortContent Whether it's allowed for the content to end before the request as
|
||||
* defined by the {@link DataSpec}. If {@code true} and the request exceeds the length of the
|
||||
* content, then the content will be cached to the end. If {@code false} and the request
|
||||
* exceeds the length of the content, {@link #cache} will throw an {@link IOException}.
|
||||
* @param temporaryBuffer A temporary buffer to be used during caching, or {@code null} if the
|
||||
* writer should instantiate its own internal temporary buffer.
|
||||
* @param progressListener An optional progress listener.
|
||||
|
|
@ -76,13 +70,11 @@ public final class CacheWriter {
|
|||
public CacheWriter(
|
||||
CacheDataSource dataSource,
|
||||
DataSpec dataSpec,
|
||||
boolean allowShortContent,
|
||||
@Nullable byte[] temporaryBuffer,
|
||||
@Nullable ProgressListener progressListener) {
|
||||
this.dataSource = dataSource;
|
||||
this.cache = dataSource.getCache();
|
||||
this.dataSpec = dataSpec;
|
||||
this.allowShortContent = allowShortContent;
|
||||
this.temporaryBuffer =
|
||||
temporaryBuffer == null ? new byte[DEFAULT_BUFFER_SIZE_BYTES] : temporaryBuffer;
|
||||
this.progressListener = progressListener;
|
||||
|
|
@ -143,14 +135,6 @@ public final class CacheWriter {
|
|||
nextPosition += readBlockToCache(nextPosition, nextRequestLength);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove allowShortContent parameter, this code block, and return the number of bytes
|
||||
// cached. The caller can then check whether fewer bytes were cached than were requested.
|
||||
if (!allowShortContent
|
||||
&& dataSpec.length != C.LENGTH_UNSET
|
||||
&& nextPosition != dataSpec.position + dataSpec.length) {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -176,9 +160,11 @@ public final class CacheWriter {
|
|||
isDataSourceOpen = true;
|
||||
} catch (IOException e) {
|
||||
Util.closeQuietly(dataSource);
|
||||
if (allowShortContent
|
||||
&& isLastBlock
|
||||
&& DataSourceException.isCausedByPositionOutOfRange(e)) {
|
||||
// TODO: This exception handling may be required for interop with current HttpDataSource
|
||||
// implementations that (incorrectly) throw a position-out-of-range when opened exactly one
|
||||
// byte beyond the end of the resource. It should be removed when the HttpDataSource
|
||||
// implementations are fixed.
|
||||
if (isLastBlock && DataSourceException.isCausedByPositionOutOfRange(e)) {
|
||||
// The length of the request exceeds the length of the content. If we allow shorter
|
||||
// content and are reading the last block, fall through and try again with an unbounded
|
||||
// request to read up to the end of the content.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,583 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.upstream;
|
||||
|
||||
import static android.net.NetworkInfo.State.CONNECTED;
|
||||
import static android.net.NetworkInfo.State.DISCONNECTED;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.Uri;
|
||||
import android.telephony.TelephonyManager;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.testutil.FakeClock;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||
import java.util.Random;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowNetworkInfo;
|
||||
|
||||
/** Unit test for {@link ExperimentalBandwidthMeter}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class ExperimentalBandwidthMeterTest {
|
||||
|
||||
private static final int SIMULATED_TRANSFER_COUNT = 100;
|
||||
private static final String FAST_COUNTRY_ISO = "EE";
|
||||
private static final String SLOW_COUNTRY_ISO = "PG";
|
||||
|
||||
private TelephonyManager telephonyManager;
|
||||
private ConnectivityManager connectivityManager;
|
||||
private NetworkInfo networkInfoOffline;
|
||||
private NetworkInfo networkInfoWifi;
|
||||
private NetworkInfo networkInfo2g;
|
||||
private NetworkInfo networkInfo3g;
|
||||
private NetworkInfo networkInfo4g;
|
||||
private NetworkInfo networkInfoEthernet;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
connectivityManager =
|
||||
(ConnectivityManager)
|
||||
ApplicationProvider.getApplicationContext()
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
telephonyManager =
|
||||
(TelephonyManager)
|
||||
ApplicationProvider.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
|
||||
Shadows.shadowOf(telephonyManager).setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
networkInfoOffline =
|
||||
ShadowNetworkInfo.newInstance(
|
||||
DetailedState.DISCONNECTED,
|
||||
ConnectivityManager.TYPE_WIFI,
|
||||
/* subType= */ 0,
|
||||
/* isAvailable= */ false,
|
||||
DISCONNECTED);
|
||||
networkInfoWifi =
|
||||
ShadowNetworkInfo.newInstance(
|
||||
DetailedState.CONNECTED,
|
||||
ConnectivityManager.TYPE_WIFI,
|
||||
/* subType= */ 0,
|
||||
/* isAvailable= */ true,
|
||||
CONNECTED);
|
||||
networkInfo2g =
|
||||
ShadowNetworkInfo.newInstance(
|
||||
DetailedState.CONNECTED,
|
||||
ConnectivityManager.TYPE_MOBILE,
|
||||
TelephonyManager.NETWORK_TYPE_GPRS,
|
||||
/* isAvailable= */ true,
|
||||
CONNECTED);
|
||||
networkInfo3g =
|
||||
ShadowNetworkInfo.newInstance(
|
||||
DetailedState.CONNECTED,
|
||||
ConnectivityManager.TYPE_MOBILE,
|
||||
TelephonyManager.NETWORK_TYPE_HSDPA,
|
||||
/* isAvailable= */ true,
|
||||
CONNECTED);
|
||||
networkInfo4g =
|
||||
ShadowNetworkInfo.newInstance(
|
||||
DetailedState.CONNECTED,
|
||||
ConnectivityManager.TYPE_MOBILE,
|
||||
TelephonyManager.NETWORK_TYPE_LTE,
|
||||
/* isAvailable= */ true,
|
||||
CONNECTED);
|
||||
networkInfoEthernet =
|
||||
ShadowNetworkInfo.newInstance(
|
||||
DetailedState.CONNECTED,
|
||||
ConnectivityManager.TYPE_ETHERNET,
|
||||
/* subType= */ 0,
|
||||
/* isAvailable= */ true,
|
||||
CONNECTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor2G() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeterWifi =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateWifi = bandwidthMeterWifi.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter2g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateWifi).isGreaterThan(initialEstimate2g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor3G() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeterWifi =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateWifi = bandwidthMeterWifi.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo3g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter3g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateWifi).isGreaterThan(initialEstimate3g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor2G() {
|
||||
setActiveNetworkInfo(networkInfoEthernet);
|
||||
ExperimentalBandwidthMeter bandwidthMeterEthernet =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateEthernet = bandwidthMeterEthernet.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter2g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate2g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor3G() {
|
||||
setActiveNetworkInfo(networkInfoEthernet);
|
||||
ExperimentalBandwidthMeter bandwidthMeterEthernet =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateEthernet = bandwidthMeterEthernet.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo3g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter3g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate3g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor2G() {
|
||||
setActiveNetworkInfo(networkInfo4g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter4g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter2g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate4g).isGreaterThan(initialEstimate2g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor3G() {
|
||||
setActiveNetworkInfo(networkInfo4g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter4g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo3g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter3g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate4g).isGreaterThan(initialEstimate3g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_for3G_isGreaterThanEstimateFor2G() {
|
||||
setActiveNetworkInfo(networkInfo3g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter3g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
|
||||
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter2g =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate3g).isGreaterThan(initialEstimate2g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_forOffline_isReasonable() {
|
||||
setActiveNetworkInfo(networkInfoOffline);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isGreaterThan(100_000L);
|
||||
assertThat(initialEstimate).isLessThan(50_000_000L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
defaultInitialBitrateEstimate_forWifi_forFastCountry_isGreaterThanEstimateForSlowCountry() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterFast =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
|
||||
|
||||
setNetworkCountryIso(SLOW_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterSlow =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
defaultInitialBitrateEstimate_forEthernet_forFastCountry_isGreaterThanEstimateForSlowCountry() {
|
||||
setActiveNetworkInfo(networkInfoEthernet);
|
||||
setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterFast =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
|
||||
|
||||
setNetworkCountryIso(SLOW_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterSlow =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
defaultInitialBitrateEstimate_for2G_forFastCountry_isGreaterThanEstimateForSlowCountry() {
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterFast =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
|
||||
|
||||
setNetworkCountryIso(SLOW_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterSlow =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
defaultInitialBitrateEstimate_for3G_forFastCountry_isGreaterThanEstimateForSlowCountry() {
|
||||
setActiveNetworkInfo(networkInfo3g);
|
||||
setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterFast =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
|
||||
|
||||
setNetworkCountryIso(SLOW_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterSlow =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
defaultInitialBitrateEstimate_for4g_forFastCountry_isGreaterThanEstimateForSlowCountry() {
|
||||
setActiveNetworkInfo(networkInfo4g);
|
||||
setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterFast =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
|
||||
|
||||
setNetworkCountryIso(SLOW_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterSlow =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_whileConnectedToNetwork_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_whileOffline_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoOffline);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_forWifi_whileConnectedToWifi_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_forWifi_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_forEthernet_whileConnectedToEthernet_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoEthernet);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_ETHERNET, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_forEthernet_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_for2G_whileConnectedTo2G_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_2G, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_for2G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_2G, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_for3G_whileConnectedTo3G_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfo3g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_3G, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_for3G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_3G, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfo4g);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_4G, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_for4G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_4G, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_forOffline_whileOffline_setsInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoOffline);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_OFFLINE, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
initialBitrateEstimateOverwrite_forOffline_whileConnectedToNetwork_doesNotSetInitialEstimate() {
|
||||
setActiveNetworkInfo(networkInfoWifi);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(C.NETWORK_TYPE_OFFLINE, 123456789)
|
||||
.build();
|
||||
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialBitrateEstimateOverwrite_forCountry_usesDefaultValuesForCountry() {
|
||||
setNetworkCountryIso(SLOW_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterSlow =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
|
||||
|
||||
setNetworkCountryIso(FAST_COUNTRY_ISO);
|
||||
ExperimentalBandwidthMeter bandwidthMeterFastWithSlowOverwrite =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setInitialBitrateEstimate(SLOW_COUNTRY_ISO)
|
||||
.build();
|
||||
long initialEstimateFastWithSlowOverwrite =
|
||||
bandwidthMeterFastWithSlowOverwrite.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateFastWithSlowOverwrite).isEqualTo(initialEstimateSlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void networkTypeOverride_updatesBitrateEstimate() {
|
||||
setActiveNetworkInfo(networkInfoEthernet);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||
long initialEstimateEthernet = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
bandwidthMeter.setNetworkTypeOverride(C.NETWORK_TYPE_2G);
|
||||
long initialEstimate2g = bandwidthMeter.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate2g);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void networkTypeOverride_doesFullReset() {
|
||||
// Simulate transfers for an ethernet connection.
|
||||
setActiveNetworkInfo(networkInfoEthernet);
|
||||
FakeClock clock = new FakeClock(/* initialTimeMs= */ 0);
|
||||
ExperimentalBandwidthMeter bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setClock(clock)
|
||||
.build();
|
||||
long[] bitrateEstimatesWithNewInstance = simulateTransfers(bandwidthMeter, clock);
|
||||
|
||||
// Create a new instance and seed with some transfers.
|
||||
setActiveNetworkInfo(networkInfo2g);
|
||||
bandwidthMeter =
|
||||
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||
.setClock(clock)
|
||||
.build();
|
||||
simulateTransfers(bandwidthMeter, clock);
|
||||
|
||||
// Override the network type to ethernet and simulate transfers again.
|
||||
bandwidthMeter.setNetworkTypeOverride(C.NETWORK_TYPE_ETHERNET);
|
||||
long[] bitrateEstimatesAfterReset = simulateTransfers(bandwidthMeter, clock);
|
||||
|
||||
// If overriding the network type fully reset the bandwidth meter, we expect the bitrate
|
||||
// estimates generated during simulation to be the same.
|
||||
assertThat(bitrateEstimatesAfterReset).isEqualTo(bitrateEstimatesWithNewInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialBitrateEstimate_withoutContext_isReasonable() {
|
||||
ExperimentalBandwidthMeter bandwidthMeterWithBuilder =
|
||||
new ExperimentalBandwidthMeter.Builder(/* context= */ null).build();
|
||||
long initialEstimateWithBuilder = bandwidthMeterWithBuilder.getBitrateEstimate();
|
||||
|
||||
assertThat(initialEstimateWithBuilder).isGreaterThan(100_000L);
|
||||
assertThat(initialEstimateWithBuilder).isLessThan(50_000_000L);
|
||||
}
|
||||
|
||||
private void setActiveNetworkInfo(NetworkInfo networkInfo) {
|
||||
Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo);
|
||||
}
|
||||
|
||||
private void setNetworkCountryIso(String countryIso) {
|
||||
Shadows.shadowOf(telephonyManager).setNetworkCountryIso(countryIso);
|
||||
}
|
||||
|
||||
private static long[] simulateTransfers(
|
||||
ExperimentalBandwidthMeter bandwidthMeter, FakeClock clock) {
|
||||
long[] bitrateEstimates = new long[SIMULATED_TRANSFER_COUNT];
|
||||
Random random = new Random(/* seed= */ 0);
|
||||
DataSource dataSource = new FakeDataSource();
|
||||
DataSpec dataSpec = new DataSpec(Uri.parse("https://test.com"));
|
||||
for (int i = 0; i < SIMULATED_TRANSFER_COUNT; i++) {
|
||||
bandwidthMeter.onTransferStart(dataSource, dataSpec, /* isNetwork= */ true);
|
||||
clock.advanceTime(random.nextInt(/* bound= */ 5000));
|
||||
bandwidthMeter.onBytesTransferred(
|
||||
dataSource,
|
||||
dataSpec,
|
||||
/* isNetwork= */ true,
|
||||
/* bytes= */ random.nextInt(5 * 1024 * 1024));
|
||||
bandwidthMeter.onTransferEnd(dataSource, dataSpec, /* isNetwork= */ true);
|
||||
bitrateEstimates[i] = bandwidthMeter.getBitrateEstimate();
|
||||
}
|
||||
return bitrateEstimates;
|
||||
}
|
||||
}
|
||||
|
|
@ -364,7 +364,6 @@ public final class CacheDataSourceTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, upstream2),
|
||||
unboundedDataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
/* progressListener= */ null);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -414,7 +413,6 @@ public final class CacheDataSourceTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, upstream2),
|
||||
unboundedDataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
/* progressListener= */ null);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -439,7 +437,6 @@ public final class CacheDataSourceTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, upstream),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
/* progressListener= */ null);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -476,7 +473,6 @@ public final class CacheDataSourceTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, upstream),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
/* progressListener= */ null);
|
||||
cacheWriter.cache();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import com.google.android.exoplayer2.testutil.TestUtil;
|
|||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.FileDataSource;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
|
@ -72,7 +71,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
new DataSpec(Uri.parse("test_data")),
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -94,7 +92,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -106,7 +103,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
new DataSpec(testUri),
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -129,7 +125,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -153,7 +148,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -165,7 +159,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
new DataSpec(testUri),
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -187,7 +180,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ true,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
@ -196,24 +188,6 @@ public final class CacheWriterTest {
|
|||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheThrowEOFException() throws Exception {
|
||||
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);
|
||||
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
|
||||
|
||||
Uri testUri = Uri.parse("test_data");
|
||||
DataSpec dataSpec = new DataSpec(testUri, /* position= */ 0, /* length= */ 1000);
|
||||
|
||||
CacheWriter cacheWriter =
|
||||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
dataSpec,
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
/* progressListener= */ null);
|
||||
assertThrows(EOFException.class, cacheWriter::cache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cache_afterFailureOnClose_succeeds() throws Exception {
|
||||
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);
|
||||
|
|
@ -237,7 +211,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
cacheDataSource,
|
||||
new DataSpec(Uri.parse("test_data")),
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
|
||||
|
|
@ -276,7 +249,6 @@ public final class CacheWriterTest {
|
|||
new CacheWriter(
|
||||
new CacheDataSource(cache, dataSource),
|
||||
new DataSpec(Uri.parse("test_data")),
|
||||
/* allowShortContent= */ false,
|
||||
/* temporaryBuffer= */ null,
|
||||
counters);
|
||||
cacheWriter.cache();
|
||||
|
|
|
|||
|
|
@ -232,24 +232,27 @@ public abstract class DataSourceContractTest {
|
|||
DataSpec dataSpec =
|
||||
new DataSpec.Builder().setUri(resource.getUri()).setPosition(resourceLength).build();
|
||||
try {
|
||||
long length = dataSource.open(dataSpec);
|
||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
||||
// fewer bytes will be read in this case.
|
||||
if (length != C.LENGTH_UNSET) {
|
||||
assertThat(length).isEqualTo(0);
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] data =
|
||||
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
|
||||
assertThat(data).isEmpty();
|
||||
long length = dataSource.open(dataSpec);
|
||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
||||
// fewer bytes will be read in this case.
|
||||
if (length != C.LENGTH_UNSET) {
|
||||
assertThat(length).isEqualTo(0);
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] data =
|
||||
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
|
||||
assertThat(data).isEmpty();
|
||||
} catch (IOException e) {
|
||||
// TODO: Remove this catch once the one below is removed.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: Remove this catch and require that implementations do not throw.
|
||||
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: Remove this catch and require that implementations do not throw.
|
||||
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
|
|
@ -275,22 +278,25 @@ public abstract class DataSourceContractTest {
|
|||
.setLength(1)
|
||||
.build();
|
||||
try {
|
||||
long length = dataSource.open(dataSpec);
|
||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
||||
// fewer bytes will be read in this case.
|
||||
assertThat(length).isEqualTo(1);
|
||||
|
||||
try {
|
||||
byte[] data =
|
||||
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
|
||||
assertThat(data).isEmpty();
|
||||
long length = dataSource.open(dataSpec);
|
||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
||||
// fewer bytes will be read in this case.
|
||||
assertThat(length).isEqualTo(1);
|
||||
|
||||
try {
|
||||
byte[] data =
|
||||
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
|
||||
assertThat(data).isEmpty();
|
||||
} catch (IOException e) {
|
||||
// TODO: Remove this catch once the one below is removed.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: Remove this catch and require that implementations do not throw.
|
||||
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: Remove this catch and require that implementations do not throw.
|
||||
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue