Add support for resetting the AudioTrack stream type.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=139797714
This commit is contained in:
andrewlewis 2016-11-21 09:55:55 -08:00 committed by Oliver Woodman
parent 060ca4aecc
commit ae0ac55b8d
8 changed files with 144 additions and 46 deletions

View File

@ -20,7 +20,6 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.MimeTypes;
@ -54,11 +53,10 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public FfmpegAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
AudioCapabilities audioCapabilities, int streamType) {
super(eventHandler, eventListener, audioCapabilities, streamType);
AudioCapabilities audioCapabilities) {
super(eventHandler, eventListener, audioCapabilities);
}
@Override

View File

@ -19,7 +19,6 @@ import android.os.Handler;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.MimeTypes;
@ -50,11 +49,10 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public LibflacAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
AudioCapabilities audioCapabilities, int streamType) {
super(eventHandler, eventListener, audioCapabilities, streamType);
AudioCapabilities audioCapabilities) {
super(eventHandler, eventListener, audioCapabilities);
}
@Override

View File

@ -19,7 +19,6 @@ import android.os.Handler;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
@ -52,11 +51,10 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public LibopusAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
AudioCapabilities audioCapabilities, int streamType) {
super(eventHandler, eventListener, audioCapabilities, streamType);
AudioCapabilities audioCapabilities) {
super(eventHandler, eventListener, audioCapabilities);
}
/**
@ -65,12 +63,11 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public LibopusAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
AudioCapabilities audioCapabilities, int streamType,
DrmSessionManager<ExoMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys) {
super(eventHandler, eventListener, audioCapabilities, streamType, drmSessionManager,
AudioCapabilities audioCapabilities, DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys) {
super(eventHandler, eventListener, audioCapabilities, drmSessionManager,
playClearSamplesWithoutKeys);
}

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.support.annotation.IntDef;
import android.view.Surface;
@ -159,6 +160,42 @@ public final class C {
public static final int CHANNEL_OUT_7POINT1_SURROUND = Util.SDK_INT < 23
? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
/**
* Stream types for an {@link android.media.AudioTrack}.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({STREAM_TYPE_ALARM, STREAM_TYPE_MUSIC, STREAM_TYPE_NOTIFICATION, STREAM_TYPE_RING,
STREAM_TYPE_SYSTEM, STREAM_TYPE_VOICE_CALL})
public @interface StreamType {}
/**
* @see AudioManager#STREAM_ALARM
*/
public static final int STREAM_TYPE_ALARM = AudioManager.STREAM_ALARM;
/**
* @see AudioManager#STREAM_MUSIC
*/
public static final int STREAM_TYPE_MUSIC = AudioManager.STREAM_MUSIC;
/**
* @see AudioManager#STREAM_NOTIFICATION
*/
public static final int STREAM_TYPE_NOTIFICATION = AudioManager.STREAM_NOTIFICATION;
/**
* @see AudioManager#STREAM_RING
*/
public static final int STREAM_TYPE_RING = AudioManager.STREAM_RING;
/**
* @see AudioManager#STREAM_SYSTEM
*/
public static final int STREAM_TYPE_SYSTEM = AudioManager.STREAM_SYSTEM;
/**
* @see AudioManager#STREAM_VOICE_CALL
*/
public static final int STREAM_TYPE_VOICE_CALL = AudioManager.STREAM_VOICE_CALL;
/**
* The default stream type used by audio renderers.
*/
public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC;
/**
* Flags which can apply to a buffer containing a media sample.
*/
@ -397,21 +434,35 @@ public final class C {
public static final int MSG_SET_SURFACE = 1;
/**
* The type of a message that can be passed to an audio {@link Renderer} via
* A type of a message that can be passed to an audio {@link Renderer} via
* {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object
* should be a {@link Float} with 0 being silence and 1 being unity gain.
*/
public static final int MSG_SET_VOLUME = 2;
/**
* The type of a message that can be passed to an audio {@link Renderer} via
* A type of a message that can be passed to an audio {@link Renderer} via
* {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object
* should be a {@link android.media.PlaybackParams}, which will be used to configure the
* should be a {@link android.media.PlaybackParams}, or null, which will be used to configure the
* underlying {@link android.media.AudioTrack}. The message object should not be modified by the
* caller after it has been passed
*/
public static final int MSG_SET_PLAYBACK_PARAMS = 3;
/**
* A type of a message that can be passed to an audio {@link Renderer} via
* {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object
* should be one of the integer stream types in {@link C.StreamType}, and will specify the stream
* type of the underlying {@link android.media.AudioTrack}. See also
* {@link android.media.AudioTrack#AudioTrack(int, int, int, int, int, int)}. If the stream type
* is not set, audio renderers use {@link #STREAM_TYPE_DEFAULT}.
* <p>
* Note that when the stream type changes, the AudioTrack must be reinitialized, which can
* introduce a brief gap in audio output. Note also that tracks in the same audio session must
* share the same routing, so a new audio session id will be generated.
*/
public static final int MSG_SET_STREAM_TYPE = 4;
/**
* Applications or extensions may define custom {@code MSG_*} constants greater than or equal to
* this value.

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.PlaybackParams;
import android.os.Handler;
@ -114,6 +113,8 @@ public final class SimpleExoPlayer implements ExoPlayer {
private DecoderCounters videoDecoderCounters;
private DecoderCounters audioDecoderCounters;
private int audioSessionId;
@C.StreamType
private int audioStreamType;
private float volume;
private PlaybackParamsHolder playbackParamsHolder;
@ -152,6 +153,7 @@ public final class SimpleExoPlayer implements ExoPlayer {
// Set initial values.
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioStreamType = C.STREAM_TYPE_DEFAULT;
volume = 1;
// Build the player and associated objects.
@ -232,6 +234,36 @@ public final class SimpleExoPlayer implements ExoPlayer {
}
}
/**
* Sets the stream type for audio playback (see {@link C.StreamType} and
* {@link android.media.AudioTrack#AudioTrack(int, int, int, int, int, int)}). If the stream type
* is not set, audio renderers use {@link C#STREAM_TYPE_DEFAULT}.
* <p>
* Note that when the stream type changes, the AudioTrack must be reinitialized, which can
* introduce a brief gap in audio output. Note also that tracks in the same audio session must
* share the same routing, so a new audio session id will be generated.
*
* @param audioStreamType The stream type for audio playback.
*/
public void setAudioStreamType(@C.StreamType int audioStreamType) {
this.audioStreamType = audioStreamType;
ExoPlayerMessage[] messages = new ExoPlayerMessage[audioRendererCount];
int count = 0;
for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_STREAM_TYPE, audioStreamType);
}
}
player.sendMessages(messages);
}
/**
* Returns the stream type for audio playback.
*/
public @C.StreamType int getAudioStreamType() {
return audioStreamType;
}
/**
* Sets the audio volume, with 0 being silence and 1 being unity gain.
*
@ -543,7 +575,7 @@ public final class SimpleExoPlayer implements ExoPlayer {
Renderer audioRenderer = new MediaCodecAudioRenderer(MediaCodecSelector.DEFAULT,
drmSessionManager, true, mainHandler, componentListener,
AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);
AudioCapabilities.getCapabilities(context));
renderersList.add(audioRenderer);
Renderer textRenderer = new TextRenderer(componentListener, mainHandler.getLooper());

View File

@ -249,7 +249,6 @@ public final class AudioTrack {
public static boolean failOnSpuriousAudioTimestamp = false;
private final AudioCapabilities audioCapabilities;
private final int streamType;
private final Listener listener;
private final ConditionVariable releasingConditionVariable;
private final long[] playheadOffsets;
@ -263,6 +262,8 @@ public final class AudioTrack {
private android.media.AudioTrack audioTrack;
private int sampleRate;
private int channelConfig;
@C.StreamType
private int streamType;
@C.Encoding
private int sourceEncoding;
@C.Encoding
@ -301,12 +302,10 @@ public final class AudioTrack {
/**
* @param audioCapabilities The current audio capabilities.
* @param streamType The type of audio stream for the underlying {@link android.media.AudioTrack}.
* @param listener Listener for audio track events.
*/
public AudioTrack(AudioCapabilities audioCapabilities, int streamType, Listener listener) {
public AudioTrack(AudioCapabilities audioCapabilities, Listener listener) {
this.audioCapabilities = audioCapabilities;
this.streamType = streamType;
this.listener = listener;
releasingConditionVariable = new ConditionVariable(true);
if (Util.SDK_INT >= 18) {
@ -327,6 +326,7 @@ public final class AudioTrack {
playheadOffsets = new long[MAX_PLAYHEAD_OFFSET_COUNT];
volume = 1.0f;
startMediaTimeState = START_NOT_SET;
streamType = C.STREAM_TYPE_DEFAULT;
}
/**
@ -742,6 +742,24 @@ public final class AudioTrack {
audioTrackUtil.setPlaybackParams(playbackParams);
}
/**
* Sets the stream type for audio track. If the stream type has changed, {@link #isInitialized()}
* will return {@code false} and the caller must re-{@link #initialize(int)} the audio track
* before writing more data. The caller must not reuse the audio session identifier when
* re-initializing with a new stream type.
*
* @param streamType The {@link C.StreamType} to use for audio output.
* @return Whether the stream type changed.
*/
public boolean setStreamType(@C.StreamType int streamType) {
if (this.streamType == streamType) {
return false;
}
this.streamType = streamType;
reset();
return true;
}
/**
* Sets the playback volume.
*

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer2.audio;
import android.annotation.TargetApi;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
@ -107,7 +106,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
boolean playClearSamplesWithoutKeys, Handler eventHandler,
AudioRendererEventListener eventListener) {
this(mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler,
eventListener, null, AudioManager.STREAM_MUSIC);
eventListener, null);
}
/**
@ -124,16 +123,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public MediaCodecAudioRenderer(MediaCodecSelector mediaCodecSelector,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys, Handler eventHandler,
AudioRendererEventListener eventListener, AudioCapabilities audioCapabilities,
int streamType) {
AudioRendererEventListener eventListener, AudioCapabilities audioCapabilities) {
super(C.TRACK_TYPE_AUDIO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys);
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioTrack = new AudioTrack(audioCapabilities, streamType, this);
audioTrack = new AudioTrack(audioCapabilities, this);
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
}
@ -387,6 +384,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
case C.MSG_SET_PLAYBACK_PARAMS:
audioTrack.setPlaybackParams((PlaybackParams) message);
break;
case C.MSG_SET_STREAM_TYPE:
@C.StreamType int streamType = (Integer) message;
if (audioTrack.setStreamType(streamType)) {
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
}
break;
default:
super.handleMessage(messageType, message);
break;

View File

@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.audio;
import android.media.AudioManager;
import android.media.PlaybackParams;
import android.os.Handler;
import android.os.Looper;
@ -47,8 +46,9 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
private final boolean playClearSamplesWithoutKeys;
private final EventDispatcher eventDispatcher;
private final FormatHolder formatHolder;
private final AudioTrack audioTrack;
private final DrmSessionManager<ExoMediaCrypto> drmSessionManager;
private final FormatHolder formatHolder;
private DecoderCounters decoderCounters;
private Format inputFormat;
@ -65,7 +65,6 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
private boolean outputStreamEnded;
private boolean waitingForKeys;
private final AudioTrack audioTrack;
private int audioSessionId;
public SimpleDecoderAudioRenderer() {
@ -79,7 +78,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
*/
public SimpleDecoderAudioRenderer(Handler eventHandler,
AudioRendererEventListener eventListener) {
this(eventHandler, eventListener, null, AudioManager.STREAM_MUSIC);
this(eventHandler, eventListener, null);
}
/**
@ -88,12 +87,10 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public SimpleDecoderAudioRenderer(Handler eventHandler,
AudioRendererEventListener eventListener, AudioCapabilities audioCapabilities,
int streamType) {
this(eventHandler, eventListener, audioCapabilities, streamType, null, false);
AudioRendererEventListener eventListener, AudioCapabilities audioCapabilities) {
this(eventHandler, eventListener, audioCapabilities, null, false);
}
/**
@ -102,7 +99,6 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
* @param drmSessionManager For use with encrypted media. May be null if support for encrypted
* media is not required.
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
@ -113,15 +109,14 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
*/
public SimpleDecoderAudioRenderer(Handler eventHandler,
AudioRendererEventListener eventListener, AudioCapabilities audioCapabilities,
int streamType, DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys) {
DrmSessionManager<ExoMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys) {
super(C.TRACK_TYPE_AUDIO);
this.drmSessionManager = drmSessionManager;
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioTrack = new AudioTrack(audioCapabilities, streamType, this);
audioTrack = new AudioTrack(audioCapabilities, this);
this.drmSessionManager = drmSessionManager;
formatHolder = new FormatHolder();
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
}
@Override
@ -473,6 +468,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
case C.MSG_SET_PLAYBACK_PARAMS:
audioTrack.setPlaybackParams((PlaybackParams) message);
break;
case C.MSG_SET_STREAM_TYPE:
@C.StreamType int streamType = (Integer) message;
if (audioTrack.setStreamType(streamType)) {
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
}
break;
default:
super.handleMessage(messageType, message);
break;