mirror of
https://github.com/androidx/media.git
synced 2025-04-29 22:36:54 +08:00
Implement device volume adjustment in CastPlayer
Issue: androidx/media#2089 PiperOrigin-RevId: 747861812
This commit is contained in:
parent
70e7121a51
commit
405365c228
@ -71,6 +71,9 @@
|
|||||||
* MIDI extension:
|
* MIDI extension:
|
||||||
* Leanback extension:
|
* Leanback extension:
|
||||||
* Cast extension:
|
* Cast extension:
|
||||||
|
* Add support for `getDeviceVolume()`, `setDeviceVolume()`,
|
||||||
|
`getDeviceMuted()`, and `setDeviceMuted()`
|
||||||
|
([#2089](https://github.com/androidx/media/issues/2089)).
|
||||||
* Test Utilities:
|
* Test Utilities:
|
||||||
* Removed `transformer.TestUtil.addAudioDecoders(String...)`,
|
* Removed `transformer.TestUtil.addAudioDecoders(String...)`,
|
||||||
`transformer.TestUtil.addAudioEncoders(String...)`, and
|
`transformer.TestUtil.addAudioEncoders(String...)`, and
|
||||||
|
@ -29,6 +29,7 @@ import android.media.MediaRouter2.TransferCallback;
|
|||||||
import android.media.RouteDiscoveryPreference;
|
import android.media.RouteDiscoveryPreference;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.util.Range;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
@ -59,6 +60,7 @@ import androidx.media3.common.util.Log;
|
|||||||
import androidx.media3.common.util.Size;
|
import androidx.media3.common.util.Size;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import com.google.android.gms.cast.Cast;
|
||||||
import com.google.android.gms.cast.CastStatusCodes;
|
import com.google.android.gms.cast.CastStatusCodes;
|
||||||
import com.google.android.gms.cast.MediaInfo;
|
import com.google.android.gms.cast.MediaInfo;
|
||||||
import com.google.android.gms.cast.MediaQueueItem;
|
import com.google.android.gms.cast.MediaQueueItem;
|
||||||
@ -73,6 +75,7 @@ import com.google.android.gms.cast.framework.media.RemoteMediaClient.MediaChanne
|
|||||||
import com.google.android.gms.common.api.PendingResult;
|
import com.google.android.gms.common.api.PendingResult;
|
||||||
import com.google.android.gms.common.api.ResultCallback;
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
@ -93,12 +96,23 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
@UnstableApi
|
@UnstableApi
|
||||||
public final class CastPlayer extends BasePlayer {
|
public final class CastPlayer extends BasePlayer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum volume to use for {@link #getDeviceVolume()} and {@link #setDeviceVolume}.
|
||||||
|
*
|
||||||
|
* <p>These methods are implemented around {@link CastSession#setVolume} and {@link
|
||||||
|
* CastSession#getVolume} which operate on a {@code [0, 1]} range. So this value allows us to
|
||||||
|
* convert to and from the int-based volume scale that {@link #getDeviceVolume()} uses.
|
||||||
|
*/
|
||||||
|
private static final int MAX_VOLUME = 20;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote} {@link DeviceInfo} with a null {@link
|
* A {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote} {@link DeviceInfo} with a null {@link
|
||||||
* DeviceInfo#routingControllerId}.
|
* DeviceInfo#routingControllerId}.
|
||||||
*/
|
*/
|
||||||
public static final DeviceInfo DEVICE_INFO_REMOTE_EMPTY =
|
public static final DeviceInfo DEVICE_INFO_REMOTE_EMPTY =
|
||||||
new DeviceInfo.Builder(DeviceInfo.PLAYBACK_TYPE_REMOTE).build();
|
new DeviceInfo.Builder(DeviceInfo.PLAYBACK_TYPE_REMOTE).setMaxVolume(MAX_VOLUME).build();
|
||||||
|
|
||||||
|
private static final Range<Integer> VOLUME_RANGE = new Range<>(0, MAX_VOLUME);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
MediaLibraryInfo.registerModule("media3.cast");
|
MediaLibraryInfo.registerModule("media3.cast");
|
||||||
@ -113,6 +127,11 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
COMMAND_STOP,
|
COMMAND_STOP,
|
||||||
COMMAND_SEEK_TO_DEFAULT_POSITION,
|
COMMAND_SEEK_TO_DEFAULT_POSITION,
|
||||||
COMMAND_SEEK_TO_MEDIA_ITEM,
|
COMMAND_SEEK_TO_MEDIA_ITEM,
|
||||||
|
COMMAND_GET_DEVICE_VOLUME,
|
||||||
|
COMMAND_ADJUST_DEVICE_VOLUME,
|
||||||
|
COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS,
|
||||||
|
COMMAND_SET_DEVICE_VOLUME,
|
||||||
|
COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS,
|
||||||
COMMAND_SET_REPEAT_MODE,
|
COMMAND_SET_REPEAT_MODE,
|
||||||
COMMAND_SET_SPEED_AND_PITCH,
|
COMMAND_SET_SPEED_AND_PITCH,
|
||||||
COMMAND_GET_CURRENT_MEDIA_ITEM,
|
COMMAND_GET_CURRENT_MEDIA_ITEM,
|
||||||
@ -144,6 +163,8 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
@Nullable private final Api30Impl api30Impl;
|
@Nullable private final Api30Impl api30Impl;
|
||||||
|
|
||||||
// Result callbacks.
|
// Result callbacks.
|
||||||
|
private final Cast.Listener castListener;
|
||||||
|
|
||||||
private final StatusListener statusListener;
|
private final StatusListener statusListener;
|
||||||
private final SeekResultCallback seekResultCallback;
|
private final SeekResultCallback seekResultCallback;
|
||||||
|
|
||||||
@ -154,7 +175,10 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
// Internal state.
|
// Internal state.
|
||||||
private final StateHolder<Boolean> playWhenReady;
|
private final StateHolder<Boolean> playWhenReady;
|
||||||
private final StateHolder<Integer> repeatMode;
|
private final StateHolder<Integer> repeatMode;
|
||||||
|
private boolean isMuted;
|
||||||
|
private int deviceVolume;
|
||||||
private final StateHolder<PlaybackParameters> playbackParameters;
|
private final StateHolder<PlaybackParameters> playbackParameters;
|
||||||
|
@Nullable private CastSession castSession;
|
||||||
@Nullable private RemoteMediaClient remoteMediaClient;
|
@Nullable private RemoteMediaClient remoteMediaClient;
|
||||||
private CastTimeline currentTimeline;
|
private CastTimeline currentTimeline;
|
||||||
private Tracks currentTracks;
|
private Tracks currentTracks;
|
||||||
@ -257,6 +281,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
this.maxSeekToPreviousPositionMs = maxSeekToPreviousPositionMs;
|
this.maxSeekToPreviousPositionMs = maxSeekToPreviousPositionMs;
|
||||||
timelineTracker = new CastTimelineTracker(mediaItemConverter);
|
timelineTracker = new CastTimelineTracker(mediaItemConverter);
|
||||||
period = new Timeline.Period();
|
period = new Timeline.Period();
|
||||||
|
castListener = new CastListener();
|
||||||
statusListener = new StatusListener();
|
statusListener = new StatusListener();
|
||||||
seekResultCallback = new SeekResultCallback();
|
seekResultCallback = new SeekResultCallback();
|
||||||
listeners =
|
listeners =
|
||||||
@ -266,6 +291,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
(listener, flags) -> listener.onEvents(/* player= */ this, new Events(flags)));
|
(listener, flags) -> listener.onEvents(/* player= */ this, new Events(flags)));
|
||||||
playWhenReady = new StateHolder<>(false);
|
playWhenReady = new StateHolder<>(false);
|
||||||
repeatMode = new StateHolder<>(REPEAT_MODE_OFF);
|
repeatMode = new StateHolder<>(REPEAT_MODE_OFF);
|
||||||
|
deviceVolume = MAX_VOLUME;
|
||||||
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
|
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
|
||||||
playbackState = STATE_IDLE;
|
playbackState = STATE_IDLE;
|
||||||
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
|
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
|
||||||
@ -278,8 +304,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
|
|
||||||
SessionManager sessionManager = castContext.getSessionManager();
|
SessionManager sessionManager = castContext.getSessionManager();
|
||||||
sessionManager.addSessionManagerListener(statusListener, CastSession.class);
|
sessionManager.addSessionManagerListener(statusListener, CastSession.class);
|
||||||
CastSession session = sessionManager.getCurrentCastSession();
|
setCastSession(sessionManager.getCurrentCastSession());
|
||||||
setRemoteMediaClient(session != null ? session.getRemoteMediaClient() : null);
|
|
||||||
updateInternalStateAndNotifyIfChanged();
|
updateInternalStateAndNotifyIfChanged();
|
||||||
if (SDK_INT >= 30 && context != null) {
|
if (SDK_INT >= 30 && context != null) {
|
||||||
api30Impl = new Api30Impl(context);
|
api30Impl = new Api30Impl(context);
|
||||||
@ -829,16 +854,14 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
return deviceInfo;
|
return deviceInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method is not supported and always returns {@code 0}. */
|
|
||||||
@Override
|
@Override
|
||||||
public int getDeviceVolume() {
|
public int getDeviceVolume() {
|
||||||
return 0;
|
return deviceVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method is not supported and always returns {@code false}. */
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDeviceMuted() {
|
public boolean isDeviceMuted() {
|
||||||
return false;
|
return isMuted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -846,44 +869,79 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public void setDeviceVolume(int volume) {}
|
public void setDeviceVolume(@IntRange(from = 0) int volume) {
|
||||||
|
setDeviceVolume(volume, /* flags= */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
/** This method is not supported and does nothing. */
|
|
||||||
@Override
|
@Override
|
||||||
public void setDeviceVolume(int volume, @C.VolumeFlags int flags) {}
|
public void setDeviceVolume(@IntRange(from = 0) int volume, @C.VolumeFlags int flags) {
|
||||||
|
if (castSession == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
volume = VOLUME_RANGE.clamp(volume);
|
||||||
|
try {
|
||||||
|
// See [Internal ref: b/399691860] for context on why we don't use
|
||||||
|
// RemoteMediaClient.setStreamVolume.
|
||||||
|
castSession.setVolume((float) volume / MAX_VOLUME);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Ignoring setDeviceVolume due to exception", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDeviceVolumeAndNotifyIfChanged(volume, isMuted);
|
||||||
|
listeners.flushEvents();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #increaseDeviceVolume(int)} instead.
|
* @deprecated Use {@link #increaseDeviceVolume(int)} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public void increaseDeviceVolume() {}
|
public void increaseDeviceVolume() {
|
||||||
|
increaseDeviceVolume(/* flags= */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
/** This method is not supported and does nothing. */
|
|
||||||
@Override
|
@Override
|
||||||
public void increaseDeviceVolume(@C.VolumeFlags int flags) {}
|
public void increaseDeviceVolume(@C.VolumeFlags int flags) {
|
||||||
|
setDeviceVolume(getDeviceVolume() + 1, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #decreaseDeviceVolume(int)} instead.
|
* @deprecated Use {@link #decreaseDeviceVolume(int)} (int)} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public void decreaseDeviceVolume() {}
|
public void decreaseDeviceVolume() {
|
||||||
|
decreaseDeviceVolume(/* flags= */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
/** This method is not supported and does nothing. */
|
|
||||||
@Override
|
@Override
|
||||||
public void decreaseDeviceVolume(@C.VolumeFlags int flags) {}
|
public void decreaseDeviceVolume(@C.VolumeFlags int flags) {
|
||||||
|
setDeviceVolume(getDeviceVolume() - 1, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #setDeviceMuted(boolean, int)} instead.
|
* @deprecated Use {@link #setDeviceMuted(boolean, int)} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public void setDeviceMuted(boolean muted) {}
|
public void setDeviceMuted(boolean muted) {
|
||||||
|
setDeviceMuted(muted, /* flags= */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
/** This method is not supported and does nothing. */
|
|
||||||
@Override
|
@Override
|
||||||
public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) {}
|
public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) {
|
||||||
|
if (castSession == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
castSession.setMute(muted);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Ignoring setDeviceMuted due to exception", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDeviceVolumeAndNotifyIfChanged(deviceVolume, muted);
|
||||||
|
listeners.flushEvents();
|
||||||
|
}
|
||||||
|
|
||||||
/** This method is not supported and does nothing. */
|
/** This method is not supported and does nothing. */
|
||||||
@Override
|
@Override
|
||||||
@ -906,6 +964,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
? getCurrentTimeline().getPeriod(oldWindowIndex, period, /* setIds= */ true).uid
|
? getCurrentTimeline().getPeriod(oldWindowIndex, period, /* setIds= */ true).uid
|
||||||
: null;
|
: null;
|
||||||
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null);
|
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null);
|
||||||
|
updateVolumeAndNotifyIfChanged();
|
||||||
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
|
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
|
||||||
updatePlaybackRateAndNotifyIfChanged(/* resultCallback= */ null);
|
updatePlaybackRateAndNotifyIfChanged(/* resultCallback= */ null);
|
||||||
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
|
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
|
||||||
@ -1014,6 +1073,14 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresNonNull("castSession")
|
||||||
|
private void updateVolumeAndNotifyIfChanged() {
|
||||||
|
if (castSession != null) {
|
||||||
|
int deviceVolume = VOLUME_RANGE.clamp((int) Math.round(castSession.getVolume() * MAX_VOLUME));
|
||||||
|
setDeviceVolumeAndNotifyIfChanged(deviceVolume, castSession.isMute());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresNonNull("remoteMediaClient")
|
@RequiresNonNull("remoteMediaClient")
|
||||||
private void updateRepeatModeAndNotifyIfChanged(@Nullable ResultCallback<?> resultCallback) {
|
private void updateRepeatModeAndNotifyIfChanged(@Nullable ResultCallback<?> resultCallback) {
|
||||||
if (repeatMode.acceptsUpdate(resultCallback)) {
|
if (repeatMode.acceptsUpdate(resultCallback)) {
|
||||||
@ -1255,6 +1322,17 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
/* adIndexInAdGroup= */ C.INDEX_UNSET);
|
/* adIndexInAdGroup= */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDeviceVolumeAndNotifyIfChanged(
|
||||||
|
@IntRange(from = 0) int deviceVolume, boolean isMuted) {
|
||||||
|
if (this.deviceVolume != deviceVolume || this.isMuted != isMuted) {
|
||||||
|
this.deviceVolume = deviceVolume;
|
||||||
|
this.isMuted = isMuted;
|
||||||
|
listeners.queueEvent(
|
||||||
|
Player.EVENT_DEVICE_VOLUME_CHANGED,
|
||||||
|
listener -> listener.onDeviceVolumeChanged(deviceVolume, isMuted));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setRepeatModeAndNotifyIfChanged(@Player.RepeatMode int repeatMode) {
|
private void setRepeatModeAndNotifyIfChanged(@Player.RepeatMode int repeatMode) {
|
||||||
if (this.repeatMode.value != repeatMode) {
|
if (this.repeatMode.value != repeatMode) {
|
||||||
this.repeatMode.value = repeatMode;
|
this.repeatMode.value = repeatMode;
|
||||||
@ -1307,7 +1385,16 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRemoteMediaClient(@Nullable RemoteMediaClient remoteMediaClient) {
|
private void setCastSession(@Nullable CastSession castSession) {
|
||||||
|
if (this.castSession != null) {
|
||||||
|
this.castSession.removeCastListener(castListener);
|
||||||
|
}
|
||||||
|
if (castSession != null) {
|
||||||
|
castSession.addCastListener(castListener);
|
||||||
|
}
|
||||||
|
this.castSession = castSession;
|
||||||
|
RemoteMediaClient remoteMediaClient =
|
||||||
|
castSession != null ? castSession.getRemoteMediaClient() : null;
|
||||||
if (this.remoteMediaClient == remoteMediaClient) {
|
if (this.remoteMediaClient == remoteMediaClient) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
return;
|
return;
|
||||||
@ -1468,22 +1555,22 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSessionStarted(CastSession castSession, String s) {
|
public void onSessionStarted(CastSession castSession, String s) {
|
||||||
setRemoteMediaClient(castSession.getRemoteMediaClient());
|
setCastSession(castSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSessionResumed(CastSession castSession, boolean b) {
|
public void onSessionResumed(CastSession castSession, boolean b) {
|
||||||
setRemoteMediaClient(castSession.getRemoteMediaClient());
|
setCastSession(castSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSessionEnded(CastSession castSession, int i) {
|
public void onSessionEnded(CastSession castSession, int i) {
|
||||||
setRemoteMediaClient(null);
|
setCastSession(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSessionSuspended(CastSession castSession, int i) {
|
public void onSessionSuspended(CastSession castSession, int i) {
|
||||||
setRemoteMediaClient(null);
|
setCastSession(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1645,6 +1732,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
// TODO b/364580007 - Populate volume information, and implement Player volume-related
|
// TODO b/364580007 - Populate volume information, and implement Player volume-related
|
||||||
// methods.
|
// methods.
|
||||||
return new DeviceInfo.Builder(DeviceInfo.PLAYBACK_TYPE_REMOTE)
|
return new DeviceInfo.Builder(DeviceInfo.PLAYBACK_TYPE_REMOTE)
|
||||||
|
.setMaxVolume(MAX_VOLUME)
|
||||||
.setRoutingControllerId(remoteController.getId())
|
.setRoutingControllerId(remoteController.getId())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@ -1676,4 +1764,13 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class CastListener extends Cast.Listener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVolumeChanged() {
|
||||||
|
updateVolumeAndNotifyIfChanged();
|
||||||
|
listeners.flushEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ import androidx.media3.common.Player.Listener;
|
|||||||
import androidx.media3.common.Timeline;
|
import androidx.media3.common.Timeline;
|
||||||
import androidx.media3.common.util.Assertions;
|
import androidx.media3.common.util.Assertions;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.android.gms.cast.Cast;
|
||||||
import com.google.android.gms.cast.MediaInfo;
|
import com.google.android.gms.cast.MediaInfo;
|
||||||
import com.google.android.gms.cast.MediaQueueItem;
|
import com.google.android.gms.cast.MediaQueueItem;
|
||||||
import com.google.android.gms.cast.MediaStatus;
|
import com.google.android.gms.cast.MediaStatus;
|
||||||
@ -83,6 +84,7 @@ import com.google.android.gms.cast.framework.media.RemoteMediaClient;
|
|||||||
import com.google.android.gms.common.api.PendingResult;
|
import com.google.android.gms.common.api.PendingResult;
|
||||||
import com.google.android.gms.common.api.ResultCallback;
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -102,6 +104,7 @@ public class CastPlayerTest {
|
|||||||
|
|
||||||
private CastPlayer castPlayer;
|
private CastPlayer castPlayer;
|
||||||
private DefaultMediaItemConverter mediaItemConverter;
|
private DefaultMediaItemConverter mediaItemConverter;
|
||||||
|
private Cast.Listener castListener;
|
||||||
private RemoteMediaClient.Callback remoteMediaClientCallback;
|
private RemoteMediaClient.Callback remoteMediaClientCallback;
|
||||||
|
|
||||||
@Mock private RemoteMediaClient mockRemoteMediaClient;
|
@Mock private RemoteMediaClient mockRemoteMediaClient;
|
||||||
@ -117,6 +120,7 @@ public class CastPlayerTest {
|
|||||||
private ArgumentCaptor<ResultCallback<RemoteMediaClient.MediaChannelResult>>
|
private ArgumentCaptor<ResultCallback<RemoteMediaClient.MediaChannelResult>>
|
||||||
setResultCallbackArgumentCaptor;
|
setResultCallbackArgumentCaptor;
|
||||||
|
|
||||||
|
@Captor private ArgumentCaptor<Cast.Listener> castListenerArgumentCaptor;
|
||||||
@Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor;
|
@Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor;
|
||||||
@Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor;
|
@Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor;
|
||||||
@Captor private ArgumentCaptor<MediaItem> mediaItemCaptor;
|
@Captor private ArgumentCaptor<MediaItem> mediaItemCaptor;
|
||||||
@ -139,6 +143,8 @@ public class CastPlayerTest {
|
|||||||
mediaItemConverter = new DefaultMediaItemConverter();
|
mediaItemConverter = new DefaultMediaItemConverter();
|
||||||
castPlayer = new CastPlayer(mockCastContext, mediaItemConverter);
|
castPlayer = new CastPlayer(mockCastContext, mediaItemConverter);
|
||||||
castPlayer.addListener(mockListener);
|
castPlayer.addListener(mockListener);
|
||||||
|
verify(mockCastSession).addCastListener(castListenerArgumentCaptor.capture());
|
||||||
|
castListener = castListenerArgumentCaptor.getValue();
|
||||||
verify(mockRemoteMediaClient).registerCallback(callbackArgumentCaptor.capture());
|
verify(mockRemoteMediaClient).registerCallback(callbackArgumentCaptor.capture());
|
||||||
remoteMediaClientCallback = callbackArgumentCaptor.getValue();
|
remoteMediaClientCallback = callbackArgumentCaptor.getValue();
|
||||||
}
|
}
|
||||||
@ -1398,10 +1404,10 @@ public class CastPlayerTest {
|
|||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_MEDIA_ITEM)).isTrue();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_MEDIA_ITEM)).isTrue();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isFalse();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_VOLUME)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_VOLUME)).isFalse();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isTrue();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_VOLUME)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_VOLUME)).isFalse();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)).isTrue();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)).isTrue();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_VIDEO_SURFACE)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_VIDEO_SURFACE)).isFalse();
|
||||||
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_TEXT)).isFalse();
|
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_TEXT)).isFalse();
|
||||||
assertThat(castPlayer.isCommandAvailable(Player.COMMAND_RELEASE)).isTrue();
|
assertThat(castPlayer.isCommandAvailable(Player.COMMAND_RELEASE)).isTrue();
|
||||||
@ -1935,6 +1941,40 @@ public class CastPlayerTest {
|
|||||||
assertThat(deviceInfo.playbackType).isEqualTo(DeviceInfo.PLAYBACK_TYPE_REMOTE);
|
assertThat(deviceInfo.playbackType).isEqualTo(DeviceInfo.PLAYBACK_TYPE_REMOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setDeviceVolume_updatesCastSessionVolume() throws IOException {
|
||||||
|
int maxVolume = castPlayer.getDeviceInfo().maxVolume;
|
||||||
|
int volumeToSet = 10;
|
||||||
|
castPlayer.addListener(mockListener);
|
||||||
|
castPlayer.setDeviceVolume(volumeToSet, /* flags= */ 0);
|
||||||
|
|
||||||
|
verify(mockListener, times(1)).onDeviceVolumeChanged(volumeToSet, /* muted= */ false);
|
||||||
|
verify(mockCastSession).setVolume((double) volumeToSet / maxVolume);
|
||||||
|
assertThat(castPlayer.getDeviceVolume()).isEqualTo(volumeToSet);
|
||||||
|
|
||||||
|
double newCastSessionVolume = .25;
|
||||||
|
int expectedDeviceVolume = (int) (newCastSessionVolume * maxVolume);
|
||||||
|
when(mockCastSession.getVolume()).thenReturn(newCastSessionVolume);
|
||||||
|
castListener.onVolumeChanged();
|
||||||
|
assertThat(castPlayer.getDeviceVolume()).isEqualTo(expectedDeviceVolume);
|
||||||
|
verify(mockListener, times(1)).onDeviceVolumeChanged(volumeToSet, /* muted= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setDeviceMuted_mutesCastSession() throws IOException {
|
||||||
|
castPlayer.addListener(mockListener);
|
||||||
|
castPlayer.setDeviceMuted(true, /* flags= */ 0);
|
||||||
|
|
||||||
|
verify(mockListener, times(1)).onDeviceVolumeChanged(0, /* muted= */ true);
|
||||||
|
verify(mockCastSession).setMute(true);
|
||||||
|
assertThat(castPlayer.isDeviceMuted()).isEqualTo(true);
|
||||||
|
|
||||||
|
when(mockCastSession.isMute()).thenReturn(false);
|
||||||
|
castListener.onVolumeChanged();
|
||||||
|
assertThat(castPlayer.isDeviceMuted()).isEqualTo(false);
|
||||||
|
verify(mockListener, times(1)).onDeviceVolumeChanged(0, /* muted= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
private int[] createMediaQueueItemIds(int numberOfIds) {
|
private int[] createMediaQueueItemIds(int numberOfIds) {
|
||||||
int[] mediaQueueItemIds = new int[numberOfIds];
|
int[] mediaQueueItemIds = new int[numberOfIds];
|
||||||
for (int i = 0; i < numberOfIds; i++) {
|
for (int i = 0; i < numberOfIds; i++) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user