diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java
index f35d745892..0c46ac48da 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.upstream;
import android.os.Handler;
import androidx.annotation.Nullable;
+import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -106,6 +107,14 @@ public interface BandwidthMeter {
/** Returns the estimated bitrate. */
long getBitrateEstimate();
+ /**
+ * Returns the estimated time to first byte, in microseconds, or {@link C#TIME_UNSET} if no
+ * estimate is available.
+ */
+ default long getTimeToFirstByteEstimateUs() {
+ return C.TIME_UNSET;
+ }
+
/**
* Returns the {@link TransferListener} that this instance uses to gather bandwidth information
* from data transfers. May be null if the implementation does not listen to data transfers.
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeter.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeter.java
deleted file mode 100644
index 5015b361e6..0000000000
--- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeter.java
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * 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.
- *
- *
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
- DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS = createInitialBitrateCountryGroupAssignment();
-
- /** Default initial Wifi bitrate estimate in bits per second. */
- public static final ImmutableList 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 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 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 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 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 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 getInitialBitrateEstimatesForCountry(String countryCode) {
- List groupIndices = getCountryGroupIndices(countryCode);
- Map 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 getCountryGroupIndices(String countryCode) {
- ImmutableList 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 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 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.
- *
- * 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> 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 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 bandwidthMeterReference = bandwidthMeters.get(i);
- ExperimentalBandwidthMeter bandwidthMeter = bandwidthMeterReference.get();
- if (bandwidthMeter == null) {
- bandwidthMeters.remove(i);
- }
- }
- }
- }
-
- private static ImmutableListMultimap
- createInitialBitrateCountryGroupAssignment() {
- ImmutableListMultimap.Builder 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();
- }
-}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java
new file mode 100644
index 0000000000..fce1f29ea3
--- /dev/null
+++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.google.android.exoplayer2.C;
+
+/** Provides an estimate of the time to first byte of a transfer. */
+public interface TimeToFirstByteEstimator {
+ /**
+ * Returns the estimated time to first byte of the response body, in microseconds, or {@link
+ * C#TIME_UNSET} if no estimate is available.
+ */
+ long getTimeToFirstByteEstimateUs();
+
+ /** Resets the estimator. The estimator should drop all samples and reset to its initial state. */
+ void reset();
+
+ /**
+ * Called when a transfer is being initialized.
+ *
+ * @param dataSpec Describes the data for which the transfer is initialized.
+ */
+ void onTransferInitializing(DataSpec dataSpec);
+
+ /**
+ * Called when a transfer starts.
+ *
+ * @param dataSpec Describes the data being transferred.
+ */
+ void onTransferStart(DataSpec dataSpec);
+}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeterTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeterTest.java
deleted file mode 100644
index cb4675badb..0000000000
--- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeterTest.java
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * 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;
- }
-}