Skip to content

Commit

Permalink
Add setPreferredAudioDevice method to ExoPlayer
Browse files Browse the repository at this point in the history
This allows to access the associated functionality of AudioTrack and
fills a feature gap to MediaPlayer, which has a similar method.

Issue: #135
PiperOrigin-RevId: 476398964
  • Loading branch information
tonihei authored and marcbaechinger committed Sep 30, 2022
1 parent 5b3efa8 commit a069ebd
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 0 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Expand Up @@ -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
Expand Down
Expand Up @@ -20,6 +20,7 @@
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;
Expand All @@ -29,6 +30,7 @@
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;
Expand Down Expand Up @@ -1473,6 +1475,16 @@ void setMediaSources(
@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.
*
Expand Down
Expand Up @@ -26,6 +26,7 @@
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;
Expand All @@ -38,6 +39,7 @@
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;
Expand Down Expand Up @@ -1442,6 +1444,13 @@ public void clearAuxEffectInfo() {
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();
Expand Down
Expand Up @@ -198,6 +198,13 @@ interface WakeupListener {
* <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.
Expand Down
Expand Up @@ -16,13 +16,15 @@
package androidx.media3.exoplayer;

import android.content.Context;
import android.media.AudioDeviceInfo;
import android.os.Looper;
import android.view.Surface;
import android.view.SurfaceHolder;
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;
Expand Down Expand Up @@ -628,6 +630,13 @@ public void clearAuxEffectInfo() {
player.clearAuxEffectInfo();
}

@RequiresApi(23)
@Override
public void setPreferredAudioDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
blockUntilConstructorFinished();
player.setPreferredAudioDevice(audioDeviceInfo);
}

@Override
public void setVolume(float volume) {
blockUntilConstructorFinished();
Expand Down
Expand Up @@ -17,9 +17,11 @@

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;
Expand Down Expand Up @@ -420,6 +422,15 @@ boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs, int encodedAcce
/** 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
Expand Down
Expand Up @@ -23,11 +23,14 @@
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;
Expand Down Expand Up @@ -623,6 +626,11 @@ public void handleMessage(@MessageType int messageType, @Nullable Object message
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:
Expand Down Expand Up @@ -795,4 +803,16 @@ public void onAudioSinkError(Exception audioSinkError) {
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);
}
}
}
Expand Up @@ -24,6 +24,7 @@
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;
Expand Down Expand Up @@ -565,6 +566,7 @@ public DefaultAudioSink build() {
private boolean externalAudioSessionIdProvided;
private int audioSessionId;
private AuxEffectInfo auxEffectInfo;
@Nullable private AudioDeviceInfoApi23 preferredDevice;
private boolean tunneling;
private long lastFeedElapsedRealtimeMs;
private boolean offloadDisabledUntilNextConfiguration;
Expand Down Expand Up @@ -913,6 +915,9 @@ private boolean initializeAudioTrack() throws InitializationException {
audioTrack.attachAuxEffect(auxEffectInfo.effectId);
audioTrack.setAuxEffectSendLevel(auxEffectInfo.sendLevel);
}
if (preferredDevice != null && Util.SDK_INT >= 23) {
Api23.setPreferredDeviceOnAudioTrack(audioTrack, preferredDevice);
}

startMediaTimeUsNeedsInit = true;
return true;
Expand Down Expand Up @@ -1413,6 +1418,16 @@ public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) {
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);
Expand Down Expand Up @@ -2309,6 +2324,28 @@ public void clear() {
}
}

@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() {}
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -138,6 +140,12 @@ public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) {
sink.setAuxEffectInfo(auxEffectInfo);
}

@RequiresApi(23)
@Override
public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
sink.setPreferredDevice(audioDeviceInfo);
}

@Override
public void enableTunnelingV21() {
sink.enableTunnelingV21();
Expand Down
Expand Up @@ -23,13 +23,16 @@

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;
Expand Down Expand Up @@ -749,6 +752,11 @@ public void handleMessage(@MessageType int messageType, @Nullable Object message
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;
Expand Down Expand Up @@ -942,4 +950,16 @@ public void onAudioSinkError(Exception audioSinkError) {
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);
}
}
}
Expand Up @@ -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;
Expand Down Expand Up @@ -236,6 +237,11 @@ public void clearAuxEffectInfo() {
throw new UnsupportedOperationException();
}

@Override
public void setPreferredAudioDevice(@Nullable AudioDeviceInfo audioDeviceInfo) {
throw new UnsupportedOperationException();
}

@Override
public void setSkipSilenceEnabled(boolean skipSilenceEnabled) {
throw new UnsupportedOperationException();
Expand Down

0 comments on commit a069ebd

Please sign in to comment.