mirror of
https://github.com/samsonjs/media.git
synced 2026-03-31 10:25:48 +00:00
Implement DeviceComponent of SimpleExoPlayer
PiperOrigin-RevId: 305460260
This commit is contained in:
parent
7504ce763e
commit
dbfb6b183c
4 changed files with 514 additions and 3 deletions
|
|
@ -63,6 +63,8 @@
|
|||
* Update `CachedContentIndex` to use `SecureRandom` for generating the
|
||||
initialization vector used to encrypt the cache contents.
|
||||
* Remove deprecated members in `DefaultTrackSelector`.
|
||||
* Add `Player.DeviceComponent` and implement it for `SimpleExoPlayer` so
|
||||
that the device volume can be controlled by player.
|
||||
* Text:
|
||||
* Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming
|
||||
later).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SdkSuppress;
|
||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Unit tests for {@link StreamVolumeManager}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StreamVolumeManagerTest {
|
||||
|
||||
private static final long TIMEOUT_MS = 1_000;
|
||||
|
||||
private AudioManager audioManager;
|
||||
private TestListener testListener;
|
||||
private DummyMainThread testThread;
|
||||
private StreamVolumeManager streamVolumeManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
testListener = new TestListener();
|
||||
|
||||
testThread = new DummyMainThread();
|
||||
testThread.runOnMainThread(
|
||||
() ->
|
||||
streamVolumeManager =
|
||||
new StreamVolumeManager(context, new Handler(Looper.myLooper()), testListener));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
testThread.runOnMainThread(() -> streamVolumeManager.release());
|
||||
testThread.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SdkSuppress(minSdkVersion = 28)
|
||||
public void getMinVolume_returnsStreamMinVolume() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int streamMinVolume = audioManager.getStreamMinVolume(C.STREAM_TYPE_DEFAULT);
|
||||
assertThat(streamVolumeManager.getMinVolume()).isEqualTo(streamMinVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMaxVolume_returnsStreamMaxVolume() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int streamMaxVolume = audioManager.getStreamMaxVolume(C.STREAM_TYPE_DEFAULT);
|
||||
assertThat(streamVolumeManager.getMaxVolume()).isEqualTo(streamMaxVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVolume_returnsStreamVolume() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int streamVolume = audioManager.getStreamVolume(C.STREAM_TYPE_DEFAULT);
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(streamVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setVolume_changesStreamVolume() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
if (minVolume == maxVolume) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldVolume = streamVolumeManager.getVolume();
|
||||
int targetVolume = oldVolume == maxVolume ? minVolume : maxVolume;
|
||||
|
||||
streamVolumeManager.setVolume(targetVolume);
|
||||
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(targetVolume);
|
||||
assertThat(testListener.lastStreamVolume).isEqualTo(targetVolume);
|
||||
assertThat(audioManager.getStreamVolume(C.STREAM_TYPE_DEFAULT)).isEqualTo(targetVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setVolume_withOutOfRange_isIgnored() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
int oldVolume = streamVolumeManager.getVolume();
|
||||
|
||||
streamVolumeManager.setVolume(maxVolume + 1);
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(oldVolume);
|
||||
|
||||
streamVolumeManager.setVolume(minVolume - 1);
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(oldVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increaseVolume_increasesStreamVolumeByOne() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
if (minVolume == maxVolume) {
|
||||
return;
|
||||
}
|
||||
|
||||
streamVolumeManager.setVolume(minVolume);
|
||||
int targetVolume = minVolume + 1;
|
||||
|
||||
streamVolumeManager.increaseVolume();
|
||||
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(targetVolume);
|
||||
assertThat(testListener.lastStreamVolume).isEqualTo(targetVolume);
|
||||
assertThat(audioManager.getStreamVolume(C.STREAM_TYPE_DEFAULT)).isEqualTo(targetVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increaseVolume_onMaxVolume_isIgnored() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
|
||||
streamVolumeManager.setVolume(maxVolume);
|
||||
streamVolumeManager.increaseVolume();
|
||||
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(maxVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decreaseVolume_decreasesStreamVolumeByOne() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
if (minVolume == maxVolume) {
|
||||
return;
|
||||
}
|
||||
|
||||
streamVolumeManager.setVolume(maxVolume);
|
||||
int targetVolume = maxVolume - 1;
|
||||
|
||||
streamVolumeManager.decreaseVolume();
|
||||
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(targetVolume);
|
||||
assertThat(testListener.lastStreamVolume).isEqualTo(targetVolume);
|
||||
assertThat(audioManager.getStreamVolume(C.STREAM_TYPE_DEFAULT)).isEqualTo(targetVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decreaseVolume_onMinVolume_isIgnored() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
|
||||
streamVolumeManager.setVolume(minVolume);
|
||||
streamVolumeManager.decreaseVolume();
|
||||
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(minVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setStreamType_notifiesStreamTypeAndVolume() {
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
if (minVolume == maxVolume) {
|
||||
return;
|
||||
}
|
||||
|
||||
int testStreamType = C.STREAM_TYPE_ALARM;
|
||||
int testStreamVolume = audioManager.getStreamVolume(testStreamType);
|
||||
|
||||
int oldVolume = streamVolumeManager.getVolume();
|
||||
if (oldVolume == testStreamVolume) {
|
||||
int differentVolume = oldVolume == minVolume ? maxVolume : minVolume;
|
||||
streamVolumeManager.setVolume(differentVolume);
|
||||
}
|
||||
|
||||
streamVolumeManager.setStreamType(testStreamType);
|
||||
|
||||
assertThat(testListener.lastStreamType).isEqualTo(testStreamType);
|
||||
assertThat(testListener.lastStreamVolume).isEqualTo(testStreamVolume);
|
||||
assertThat(streamVolumeManager.getVolume()).isEqualTo(testStreamVolume);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStreamVolumeChanged_isCalled_whenAudioManagerChangesIt() throws Exception {
|
||||
AtomicInteger targetVolumeRef = new AtomicInteger();
|
||||
testThread.runOnMainThread(
|
||||
() -> {
|
||||
int minVolume = streamVolumeManager.getMinVolume();
|
||||
int maxVolume = streamVolumeManager.getMaxVolume();
|
||||
if (minVolume == maxVolume) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldVolume = streamVolumeManager.getVolume();
|
||||
int targetVolume = oldVolume == maxVolume ? minVolume : maxVolume;
|
||||
targetVolumeRef.set(targetVolume);
|
||||
|
||||
audioManager.setStreamVolume(C.STREAM_TYPE_DEFAULT, targetVolume, /* flags= */ 0);
|
||||
});
|
||||
|
||||
testListener.onStreamVolumeChangedLatch.await(TIMEOUT_MS, MILLISECONDS);
|
||||
assertThat(testListener.lastStreamVolume).isEqualTo(targetVolumeRef.get());
|
||||
}
|
||||
|
||||
private static class TestListener implements StreamVolumeManager.Listener {
|
||||
|
||||
@C.StreamType private int lastStreamType;
|
||||
private int lastStreamVolume;
|
||||
public final CountDownLatch onStreamVolumeChangedLatch;
|
||||
|
||||
public TestListener() {
|
||||
onStreamVolumeChangedLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamTypeChanged(@C.StreamType int streamType) {
|
||||
lastStreamType = streamType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamVolumeChanged(int streamVolume) {
|
||||
lastStreamVolume = streamVolume;
|
||||
onStreamVolumeChangedLatch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,6 +36,8 @@ import com.google.android.exoplayer2.audio.AudioListener;
|
|||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.AuxEffectInfo;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.device.DeviceInfo;
|
||||
import com.google.android.exoplayer2.device.DeviceListener;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||
|
|
@ -73,7 +75,8 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
Player.AudioComponent,
|
||||
Player.VideoComponent,
|
||||
Player.TextComponent,
|
||||
Player.MetadataComponent {
|
||||
Player.MetadataComponent,
|
||||
Player.DeviceComponent {
|
||||
|
||||
/** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */
|
||||
@Deprecated
|
||||
|
|
@ -330,6 +333,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
private final CopyOnWriteArraySet<AudioListener> audioListeners;
|
||||
private final CopyOnWriteArraySet<TextOutput> textOutputs;
|
||||
private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs;
|
||||
private final CopyOnWriteArraySet<DeviceListener> deviceListeners;
|
||||
private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners;
|
||||
private final CopyOnWriteArraySet<AudioRendererEventListener> audioDebugListeners;
|
||||
private final BandwidthMeter bandwidthMeter;
|
||||
|
|
@ -337,6 +341,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
|
||||
private final AudioBecomingNoisyManager audioBecomingNoisyManager;
|
||||
private final AudioFocusManager audioFocusManager;
|
||||
private final StreamVolumeManager streamVolumeManager;
|
||||
private final WakeLockManager wakeLockManager;
|
||||
private final WifiLockManager wifiLockManager;
|
||||
|
||||
|
|
@ -364,6 +369,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
@Nullable private PriorityTaskManager priorityTaskManager;
|
||||
private boolean isPriorityTaskManagerRegistered;
|
||||
private boolean playerReleased;
|
||||
private DeviceInfo deviceInfo;
|
||||
|
||||
/** @param builder The {@link Builder} to obtain all construction parameters. */
|
||||
protected SimpleExoPlayer(Builder builder) {
|
||||
|
|
@ -414,6 +420,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
audioListeners = new CopyOnWriteArraySet<>();
|
||||
textOutputs = new CopyOnWriteArraySet<>();
|
||||
metadataOutputs = new CopyOnWriteArraySet<>();
|
||||
deviceListeners = new CopyOnWriteArraySet<>();
|
||||
videoDebugListeners = new CopyOnWriteArraySet<>();
|
||||
audioDebugListeners = new CopyOnWriteArraySet<>();
|
||||
eventHandler = new Handler(looper);
|
||||
|
|
@ -456,8 +463,10 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
audioBecomingNoisyManager =
|
||||
new AudioBecomingNoisyManager(context, eventHandler, componentListener);
|
||||
audioFocusManager = new AudioFocusManager(context, eventHandler, componentListener);
|
||||
streamVolumeManager = new StreamVolumeManager(context, eventHandler, componentListener);
|
||||
wakeLockManager = new WakeLockManager(context);
|
||||
wifiLockManager = new WifiLockManager(context);
|
||||
deviceInfo = createDeviceInfo(streamVolumeManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -487,8 +496,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
@Override
|
||||
@Nullable
|
||||
public DeviceComponent getDeviceComponent() {
|
||||
// TODO(b/145595776): Return this after implementing DeviceComponent.
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -684,6 +692,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
.send();
|
||||
}
|
||||
}
|
||||
streamVolumeManager.setStreamType(Util.getStreamTypeForAudioUsage(audioAttributes.usage));
|
||||
for (AudioListener audioListener : audioListeners) {
|
||||
audioListener.onAudioAttributesChanged(audioAttributes);
|
||||
}
|
||||
|
|
@ -1565,6 +1574,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
public void release() {
|
||||
verifyApplicationThread();
|
||||
audioBecomingNoisyManager.setEnabled(false);
|
||||
streamVolumeManager.release();
|
||||
wakeLockManager.setStayAwake(false);
|
||||
wifiLockManager.setStayAwake(false);
|
||||
audioFocusManager.release();
|
||||
|
|
@ -1743,6 +1753,46 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDeviceListener(DeviceListener listener) {
|
||||
deviceListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDeviceListener(DeviceListener listener) {
|
||||
deviceListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceInfo getDeviceInfo() {
|
||||
verifyApplicationThread();
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceVolume() {
|
||||
verifyApplicationThread();
|
||||
return streamVolumeManager.getVolume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeviceVolume(int volume) {
|
||||
verifyApplicationThread();
|
||||
streamVolumeManager.setVolume(volume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increaseDeviceVolume() {
|
||||
verifyApplicationThread();
|
||||
streamVolumeManager.increaseVolume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decreaseDeviceVolume() {
|
||||
verifyApplicationThread();
|
||||
streamVolumeManager.decreaseVolume();
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
private void removeSurfaceCallbacks() {
|
||||
|
|
@ -1898,6 +1948,13 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
}
|
||||
}
|
||||
|
||||
private static DeviceInfo createDeviceInfo(StreamVolumeManager streamVolumeManager) {
|
||||
return new DeviceInfo(
|
||||
DeviceInfo.PLAYBACK_TYPE_LOCAL,
|
||||
streamVolumeManager.getMinVolume(),
|
||||
streamVolumeManager.getMaxVolume());
|
||||
}
|
||||
|
||||
private static int getPlayWhenReadyChangeReason(boolean playWhenReady, int playerCommand) {
|
||||
return playWhenReady && playerCommand != AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY
|
||||
? PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS
|
||||
|
|
@ -1913,6 +1970,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
TextureView.SurfaceTextureListener,
|
||||
AudioFocusManager.PlayerControl,
|
||||
AudioBecomingNoisyManager.EventListener,
|
||||
StreamVolumeManager.Listener,
|
||||
Player.EventListener {
|
||||
|
||||
// VideoRendererEventListener implementation
|
||||
|
|
@ -2145,6 +2203,26 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY);
|
||||
}
|
||||
|
||||
// StreamVolumeManager.Listener implementation.
|
||||
|
||||
@Override
|
||||
public void onStreamTypeChanged(@C.StreamType int streamType) {
|
||||
DeviceInfo deviceInfo = createDeviceInfo(streamVolumeManager);
|
||||
if (!deviceInfo.equals(SimpleExoPlayer.this.deviceInfo)) {
|
||||
SimpleExoPlayer.this.deviceInfo = deviceInfo;
|
||||
for (DeviceListener deviceListener : deviceListeners) {
|
||||
deviceListener.onDeviceInfoChanged(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamVolumeChanged(int streamVolume) {
|
||||
for (DeviceListener deviceListener : deviceListeners) {
|
||||
deviceListener.onDeviceVolumeChanged(streamVolume);
|
||||
}
|
||||
}
|
||||
|
||||
// Player.EventListener implementation.
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Handler;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/** A manager that wraps {@link AudioManager} to control/listen audio stream volume. */
|
||||
/* package */ final class StreamVolumeManager {
|
||||
|
||||
/** A listener for changes in the manager. */
|
||||
public interface Listener {
|
||||
|
||||
/** Called when the audio stream type is changed. */
|
||||
void onStreamTypeChanged(@C.StreamType int streamType);
|
||||
|
||||
/** Called when the audio stream volume is changed. */
|
||||
void onStreamVolumeChanged(int streamVolume);
|
||||
}
|
||||
|
||||
// TODO(b/151280453): Replace the hidden intent action with an official one.
|
||||
// Copied from AudioManager#VOLUME_CHANGED_ACTION
|
||||
private static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
|
||||
|
||||
// TODO(b/153317944): Allow users to override these flags.
|
||||
private static final int VOLUME_FLAGS = AudioManager.FLAG_SHOW_UI;
|
||||
|
||||
private final Context applicationContext;
|
||||
private final Handler eventHandler;
|
||||
private final Listener listener;
|
||||
private final AudioManager audioManager;
|
||||
private final VolumeChangeReceiver receiver;
|
||||
|
||||
@C.StreamType private int streamType;
|
||||
private int volume;
|
||||
|
||||
/** Creates a manager. */
|
||||
public StreamVolumeManager(Context context, Handler eventHandler, Listener listener) {
|
||||
applicationContext = context.getApplicationContext();
|
||||
this.eventHandler = eventHandler;
|
||||
this.listener = listener;
|
||||
audioManager =
|
||||
Assertions.checkStateNotNull(
|
||||
(AudioManager) applicationContext.getSystemService(Context.AUDIO_SERVICE));
|
||||
|
||||
streamType = C.STREAM_TYPE_DEFAULT;
|
||||
volume = audioManager.getStreamVolume(streamType);
|
||||
|
||||
receiver = new VolumeChangeReceiver();
|
||||
IntentFilter filter = new IntentFilter(VOLUME_CHANGED_ACTION);
|
||||
applicationContext.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
/** Sets the audio stream type. */
|
||||
public void setStreamType(@C.StreamType int streamType) {
|
||||
if (this.streamType == streamType) {
|
||||
return;
|
||||
}
|
||||
this.streamType = streamType;
|
||||
|
||||
updateVolumeAndNotifyIfChanged();
|
||||
listener.onStreamTypeChanged(streamType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum volume for the current audio stream. It can be changed if {@link
|
||||
* #setStreamType(int)} is called.
|
||||
*/
|
||||
public int getMinVolume() {
|
||||
return Util.SDK_INT >= 28 ? audioManager.getStreamMinVolume(streamType) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum volume for the current audio stream. It can be changed if {@link
|
||||
* #setStreamType(int)} is called.
|
||||
*/
|
||||
public int getMaxVolume() {
|
||||
return audioManager.getStreamMaxVolume(streamType);
|
||||
}
|
||||
|
||||
/** Gets the current volume for the current audio stream. */
|
||||
public int getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the volume with the given value for the current audio stream. The value should be between
|
||||
* {@link #getMinVolume()} and {@link #getMaxVolume()}, otherwise it will be ignored.
|
||||
*/
|
||||
public void setVolume(int volume) {
|
||||
if (volume < getMinVolume() || volume > getMaxVolume()) {
|
||||
return;
|
||||
}
|
||||
audioManager.setStreamVolume(streamType, volume, VOLUME_FLAGS);
|
||||
updateVolumeAndNotifyIfChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the volume by one for the current audio stream. It will be ignored if the current
|
||||
* volume is equal to {@link #getMaxVolume()}.
|
||||
*/
|
||||
public void increaseVolume() {
|
||||
if (volume >= getMaxVolume()) {
|
||||
return;
|
||||
}
|
||||
audioManager.adjustStreamVolume(streamType, AudioManager.ADJUST_RAISE, VOLUME_FLAGS);
|
||||
updateVolumeAndNotifyIfChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the volume by one for the current audio stream. It will be ignored if the current
|
||||
* volume is equal to {@link #getMinVolume()}.
|
||||
*/
|
||||
public void decreaseVolume() {
|
||||
if (volume <= getMinVolume()) {
|
||||
return;
|
||||
}
|
||||
audioManager.adjustStreamVolume(streamType, AudioManager.ADJUST_LOWER, VOLUME_FLAGS);
|
||||
updateVolumeAndNotifyIfChanged();
|
||||
}
|
||||
|
||||
/** Releases the manager. It must be called when the manager is no longer required. */
|
||||
public void release() {
|
||||
applicationContext.unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
private void updateVolumeAndNotifyIfChanged() {
|
||||
int newVolume = audioManager.getStreamVolume(streamType);
|
||||
if (volume != newVolume) {
|
||||
volume = newVolume;
|
||||
listener.onStreamVolumeChanged(newVolume);
|
||||
}
|
||||
}
|
||||
|
||||
private final class VolumeChangeReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
eventHandler.post(StreamVolumeManager.this::updateVolumeAndNotifyIfChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue