diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 1903199bcb..835d6a33fc 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -276,6 +276,13 @@ public final class CastPlayer extends BasePlayer { return null; } + @Override + @Nullable + public DeviceComponent getDeviceComponent() { + // TODO(b/151792305): Implement the component. + return null; + } + @Override public Looper getApplicationLooper() { return Looper.getMainLooper(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index b701d0b9d4..f2c049e731 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -215,6 +215,12 @@ import java.util.concurrent.TimeoutException; return null; } + @Override + @Nullable + public DeviceComponent getDeviceComponent() { + return null; + } + @Override public Looper getPlaybackLooper() { return internalPlayer.getPlaybackLooper(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Player.java b/library/core/src/main/java/com/google/android/exoplayer2/Player.java index 0184ea29e5..518e331298 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Player.java @@ -27,6 +27,8 @@ import com.google.android.exoplayer2.C.VideoScalingMode; import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioListener; import com.google.android.exoplayer2.audio.AuxEffectInfo; +import com.google.android.exoplayer2.device.DeviceInfo; +import com.google.android.exoplayer2.device.DeviceListener; import com.google.android.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.text.TextOutput; @@ -367,6 +369,48 @@ public interface Player { void removeMetadataOutput(MetadataOutput output); } + /** The device component of a {@link Player}. */ + // Note: It's mostly from the androidx.media.VolumeProviderCompat and + // androidx.media.MediaControllerCompat.PlaybackInfo. + interface DeviceComponent { + + /** Adds a listener to receive device events. */ + void addDeviceListener(DeviceListener listener); + + /** Removes a listener of device events. */ + void removeDeviceListener(DeviceListener listener); + + /** Gets the device information. */ + DeviceInfo getDeviceInfo(); + + /** + * Gets the current volume of the device. + * + *
For devices with {@link DeviceInfo#PLAYBACK_TYPE_LOCAL local playback}, the volume + * returned by this method varies according to the current {@link C.StreamType stream type}. The + * stream type is determined by {@link AudioAttributes#usage} which can be converted to stream + * type with {@link Util#getStreamTypeForAudioUsage(int)}. The audio attributes can be set to + * the player by calling {@link AudioComponent#setAudioAttributes}. + * + *
For devices with {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote playback}, the volume of + * the remote device is returned. + */ + int getDeviceVolume(); + + /** + * Sets the volume of the device. + * + * @param volume The volume to set. + */ + void setDeviceVolume(int volume); + + /** Increases the volume of the device. */ + void increaseDeviceVolume(); + + /** Decreases the volume of the device. */ + void decreaseDeviceVolume(); + } + /** * Listener of changes in player state. All methods have no-op default implementations to allow * selective overrides. @@ -733,6 +777,10 @@ public interface Player { @Nullable MetadataComponent getMetadataComponent(); + /** Returns the component of this player for playback device, or null if it's not supported. */ + @Nullable + DeviceComponent getDeviceComponent(); + /** * Returns the {@link Looper} associated with the application thread that's used to access the * player and on which player events are received. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 9861c324ab..aee9100397 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -484,6 +484,13 @@ public class SimpleExoPlayer extends BasePlayer return this; } + @Override + @Nullable + public DeviceComponent getDeviceComponent() { + // TODO(b/145595776): Return this after implementing DeviceComponent. + return null; + } + /** * Sets the video scaling mode. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java new file mode 100644 index 0000000000..43c37028ea --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java @@ -0,0 +1,79 @@ +/* + * Copyright 2020 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.device; + +import androidx.annotation.IntDef; +import androidx.annotation.Nullable; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Information about the playback device. */ +public final class DeviceInfo { + + /** Types of playback. One of {@link #PLAYBACK_TYPE_LOCAL} or {@link #PLAYBACK_TYPE_REMOTE}. */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) + @IntDef({ + PLAYBACK_TYPE_LOCAL, + PLAYBACK_TYPE_REMOTE, + }) + public @interface PlaybackType {} + /** Playback happens on the local device (e.g. phone). */ + public static final int PLAYBACK_TYPE_LOCAL = 0; + /** Playback happens outside of the device (e.g. a cast device). */ + public static final int PLAYBACK_TYPE_REMOTE = 1; + + /** The type of playback. */ + public final @PlaybackType int playbackType; + /** The minimum volume that the device supports. */ + public final int minVolume; + /** The maximum volume that the device supports. */ + public final int maxVolume; + + /** Creates device information. */ + public DeviceInfo(@PlaybackType int playbackType, int minVolume, int maxVolume) { + this.playbackType = playbackType; + this.minVolume = minVolume; + this.maxVolume = maxVolume; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof DeviceInfo)) { + return false; + } + DeviceInfo other = (DeviceInfo) obj; + return playbackType == other.playbackType + && minVolume == other.minVolume + && maxVolume == other.maxVolume; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + playbackType; + result = 31 * result + minVolume; + result = 31 * result + maxVolume; + return result; + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/device/DeviceListener.java b/library/core/src/main/java/com/google/android/exoplayer2/device/DeviceListener.java new file mode 100644 index 0000000000..f310b6d553 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/device/DeviceListener.java @@ -0,0 +1,28 @@ +/* + * Copyright 2020 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.device; + +import com.google.android.exoplayer2.Player; + +/** A listener for changes of {@link Player.DeviceComponent}. */ +public interface DeviceListener { + + /** Called when the device information changes. */ + default void onDeviceInfoChanged(DeviceInfo deviceInfo) {} + + /** Called when the device volume changes. */ + default void onDeviceVolumeChanged(int volume) {} +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/device/package-info.java b/library/core/src/main/java/com/google/android/exoplayer2/device/package-info.java new file mode 100644 index 0000000000..400a2e1b50 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/device/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2020 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. + */ +@NonNullApi +package com.google.android.exoplayer2.device; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java index 09ea8eb924..5337685be4 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java @@ -58,6 +58,11 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer { throw new UnsupportedOperationException(); } + @Override + public DeviceComponent getDeviceComponent() { + throw new UnsupportedOperationException(); + } + @Override public Looper getPlaybackLooper() { throw new UnsupportedOperationException();