mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add setPreferredAudioDevice method to ExoPlayer
This allows to access the associated functionality of AudioTrack and fills a feature gap to MediaPlayer, which has a similar method. Issue: androidx/media#135 PiperOrigin-RevId: 476398964
This commit is contained in:
parent
5b3efa8ad9
commit
a069ebda47
@ -27,6 +27,8 @@
|
||||
* Make `AudioTrackBufferSizeProvider` a public interface.
|
||||
* Add `WrappingMediaSource` to simplify wrapping a single `MediaSource`
|
||||
([#7279](https://github.com/google/ExoPlayer/issues/7279)).
|
||||
* Add `ExoPlayer.setPreferredAudioDevice` to set the preferred audio
|
||||
output device ([#135](https://github.com/androidx/media/issues/135)).
|
||||
* Metadata:
|
||||
* `MetadataRenderer` can now be configured to render metadata as soon as
|
||||
they are available. Create an instance with
|
||||
|
@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioTrack;
|
||||
import android.media.MediaCodec;
|
||||
import android.os.Looper;
|
||||
@ -29,6 +30,7 @@ import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
@ -1473,6 +1475,16 @@ public interface ExoPlayer extends Player {
|
||||
@UnstableApi
|
||||
void clearAuxEffectInfo();
|
||||
|
||||
/**
|
||||
* Sets the preferred audio device.
|
||||
*
|
||||
* @param audioDeviceInfo The preferred {@linkplain AudioDeviceInfo audio device}, or null to
|
||||
* restore the default.
|
||||
*/
|
||||
@UnstableApi
|
||||
@RequiresApi(23)
|
||||
void setPreferredAudioDevice(@Nullable AudioDeviceInfo audioDeviceInfo);
|
||||
|
||||
/**
|
||||
* Sets whether skipping silences in the audio stream is enabled.
|
||||
*
|
||||
|
@ -26,6 +26,7 @@ import static androidx.media3.exoplayer.Renderer.MSG_SET_AUDIO_SESSION_ID;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_AUX_EFFECT_INFO;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_CAMERA_MOTION_LISTENER;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_CHANGE_FRAME_RATE_STRATEGY;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_PREFERRED_AUDIO_DEVICE;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_SCALING_MODE;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_SKIP_SILENCE_ENABLED;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_VIDEO_FRAME_METADATA_LISTENER;
|
||||
@ -38,6 +39,7 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioTrack;
|
||||
import android.media.MediaFormat;
|
||||
@ -1442,6 +1444,13 @@ import java.util.concurrent.TimeoutException;
|
||||
setAuxEffectInfo(new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, /* sendLevel= */ 0f));
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
@Override
|
||||
public void setPreferredAudioDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
|
||||
verifyApplicationThread();
|
||||
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_PREFERRED_AUDIO_DEVICE, audioDeviceInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
verifyApplicationThread();
|
||||
|
@ -198,6 +198,13 @@ public interface Renderer extends PlayerMessage.Target {
|
||||
* <p>The message payload must be a {@link WakeupListener} instance.
|
||||
*/
|
||||
int MSG_SET_WAKEUP_LISTENER = 11;
|
||||
/**
|
||||
* The type of a message that can be passed to audio renderers via {@link
|
||||
* ExoPlayer#createMessage(PlayerMessage.Target)}. The message payload should be an {@link
|
||||
* android.media.AudioDeviceInfo} instance representing the preferred audio device, or null to
|
||||
* restore the default.
|
||||
*/
|
||||
int MSG_SET_PREFERRED_AUDIO_DEVICE = 12;
|
||||
/**
|
||||
* Applications or extensions may define custom {@code MSG_*} constants that can be passed to
|
||||
* renderers. These custom constants must be greater than or equal to this value.
|
||||
|
@ -16,6 +16,7 @@
|
||||
package androidx.media3.exoplayer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.os.Looper;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
@ -23,6 +24,7 @@ import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
@ -628,6 +630,13 @@ public class SimpleExoPlayer extends BasePlayer
|
||||
player.clearAuxEffectInfo();
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
@Override
|
||||
public void setPreferredAudioDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
|
||||
blockUntilConstructorFinished();
|
||||
player.setPreferredAudioDevice(audioDeviceInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
blockUntilConstructorFinished();
|
||||
|
@ -17,9 +17,11 @@ package androidx.media3.exoplayer.audio;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioTrack;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
import androidx.media3.common.C;
|
||||
@ -420,6 +422,15 @@ public interface AudioSink {
|
||||
/** Sets the auxiliary effect. */
|
||||
void setAuxEffectInfo(AuxEffectInfo auxEffectInfo);
|
||||
|
||||
/**
|
||||
* Sets the preferred audio device.
|
||||
*
|
||||
* @param audioDeviceInfo The preferred {@linkplain AudioDeviceInfo audio device}, or null to
|
||||
* restore the default.
|
||||
*/
|
||||
@RequiresApi(23)
|
||||
default void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {}
|
||||
|
||||
/**
|
||||
* Enables tunneling, if possible. The sink is reset if tunneling was previously disabled.
|
||||
* Enabling tunneling is only possible if the sink is based on a platform {@link AudioTrack}, and
|
||||
|
@ -23,11 +23,14 @@ import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.DoNotInline;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
import androidx.media3.common.C;
|
||||
@ -623,6 +626,11 @@ public abstract class DecoderAudioRenderer<
|
||||
case MSG_SET_AUDIO_SESSION_ID:
|
||||
audioSink.setAudioSessionId((Integer) message);
|
||||
break;
|
||||
case MSG_SET_PREFERRED_AUDIO_DEVICE:
|
||||
if (Util.SDK_INT >= 23) {
|
||||
Api23.setAudioSinkPreferredDevice(audioSink, message);
|
||||
}
|
||||
break;
|
||||
case MSG_SET_CAMERA_MOTION_LISTENER:
|
||||
case MSG_SET_CHANGE_FRAME_RATE_STRATEGY:
|
||||
case MSG_SET_SCALING_MODE:
|
||||
@ -795,4 +803,16 @@ public abstract class DecoderAudioRenderer<
|
||||
eventDispatcher.audioSinkError(audioSinkError);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
private static final class Api23 {
|
||||
private Api23() {}
|
||||
|
||||
@DoNotInline
|
||||
public static void setAudioSinkPreferredDevice(
|
||||
AudioSink audioSink, @Nullable Object messagePayload) {
|
||||
@Nullable AudioDeviceInfo audioDeviceInfo = (AudioDeviceInfo) messagePayload;
|
||||
audioSink.setPreferredDevice(audioDeviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import static java.lang.Math.min;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
@ -565,6 +566,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
private boolean externalAudioSessionIdProvided;
|
||||
private int audioSessionId;
|
||||
private AuxEffectInfo auxEffectInfo;
|
||||
@Nullable private AudioDeviceInfoApi23 preferredDevice;
|
||||
private boolean tunneling;
|
||||
private long lastFeedElapsedRealtimeMs;
|
||||
private boolean offloadDisabledUntilNextConfiguration;
|
||||
@ -913,6 +915,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
audioTrack.attachAuxEffect(auxEffectInfo.effectId);
|
||||
audioTrack.setAuxEffectSendLevel(auxEffectInfo.sendLevel);
|
||||
}
|
||||
if (preferredDevice != null && Util.SDK_INT >= 23) {
|
||||
Api23.setPreferredDeviceOnAudioTrack(audioTrack, preferredDevice);
|
||||
}
|
||||
|
||||
startMediaTimeUsNeedsInit = true;
|
||||
return true;
|
||||
@ -1413,6 +1418,16 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
this.auxEffectInfo = auxEffectInfo;
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
@Override
|
||||
public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
|
||||
this.preferredDevice =
|
||||
audioDeviceInfo == null ? null : new AudioDeviceInfoApi23(audioDeviceInfo);
|
||||
if (audioTrack != null) {
|
||||
Api23.setPreferredDeviceOnAudioTrack(audioTrack, this.preferredDevice);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableTunnelingV21() {
|
||||
Assertions.checkState(Util.SDK_INT >= 21);
|
||||
@ -2309,6 +2324,28 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
private static final class AudioDeviceInfoApi23 {
|
||||
|
||||
public final AudioDeviceInfo audioDeviceInfo;
|
||||
|
||||
public AudioDeviceInfoApi23(AudioDeviceInfo audioDeviceInfo) {
|
||||
this.audioDeviceInfo = audioDeviceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
private static final class Api23 {
|
||||
private Api23() {}
|
||||
|
||||
@DoNotInline
|
||||
public static void setPreferredDeviceOnAudioTrack(
|
||||
AudioTrack audioTrack, @Nullable AudioDeviceInfoApi23 audioDeviceInfo) {
|
||||
audioTrack.setPreferredDevice(
|
||||
audioDeviceInfo == null ? null : audioDeviceInfo.audioDeviceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(31)
|
||||
private static final class Api31 {
|
||||
private Api31() {}
|
||||
|
@ -15,7 +15,9 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.audio;
|
||||
|
||||
import android.media.AudioDeviceInfo;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
import androidx.media3.common.Format;
|
||||
@ -138,6 +140,12 @@ public class ForwardingAudioSink implements AudioSink {
|
||||
sink.setAuxEffectInfo(auxEffectInfo);
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
@Override
|
||||
public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
|
||||
sink.setPreferredDevice(audioDeviceInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableTunnelingV21() {
|
||||
sink.enableTunnelingV21();
|
||||
|
@ -23,13 +23,16 @@ import static java.lang.Math.max;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.DoNotInline;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
import androidx.media3.common.C;
|
||||
@ -749,6 +752,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
AuxEffectInfo auxEffectInfo = (AuxEffectInfo) message;
|
||||
audioSink.setAuxEffectInfo(auxEffectInfo);
|
||||
break;
|
||||
case MSG_SET_PREFERRED_AUDIO_DEVICE:
|
||||
if (Util.SDK_INT >= 23) {
|
||||
Api23.setAudioSinkPreferredDevice(audioSink, message);
|
||||
}
|
||||
break;
|
||||
case MSG_SET_SKIP_SILENCE_ENABLED:
|
||||
audioSink.setSkipSilenceEnabled((Boolean) message);
|
||||
break;
|
||||
@ -942,4 +950,16 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
eventDispatcher.audioSinkError(audioSinkError);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
private static final class Api23 {
|
||||
private Api23() {}
|
||||
|
||||
@DoNotInline
|
||||
public static void setAudioSinkPreferredDevice(
|
||||
AudioSink audioSink, @Nullable Object messagePayload) {
|
||||
@Nullable AudioDeviceInfo audioDeviceInfo = (AudioDeviceInfo) messagePayload;
|
||||
audioSink.setPreferredDevice(audioDeviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package androidx.media3.test.utils;
|
||||
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
@ -236,6 +237,11 @@ public class StubExoPlayer extends StubPlayer implements ExoPlayer {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferredAudioDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkipSilenceEnabled(boolean skipSilenceEnabled) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
Loading…
x
Reference in New Issue
Block a user