diff --git a/library/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java b/library/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java index 711ef521e7f..fc1ee567aa8 100644 --- a/library/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java +++ b/library/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java @@ -39,9 +39,9 @@ *

* Before starting playback, specify the input format by calling * {@link #configure(String, int, int, int, int)}. Optionally call {@link #setAudioSessionId(int)}, - * {@link #setTunnelingEnabledV21(boolean)} and {@link #setStreamType(int)} to configure audio - * playback. These methods may be called after writing data to the track, in which case it will be - * reinitialized as required. + * {@link #setStreamType(int)}, {@link #enableTunnelingV21(int)} and {@link #disableTunneling()} + * to configure audio playback. These methods may be called after writing data to the track, in + * which case it will be reinitialized as required. *

* Call {@link #handleBuffer(ByteBuffer, long)} to write data, and {@link #handleDiscontinuity()} * when the data being fed is discontinuous. Call {@link #play()} to start playing the written data. @@ -64,9 +64,9 @@ public final class AudioTrack { public interface Listener { /** - * Called when the audio track has been initialized with the specified {@code audioSessionId}. + * Called when the audio track has been initialized with a newly generated audio session id. * - * @param audioSessionId The audio session id. + * @param audioSessionId The newly generated audio session id. */ void onAudioSessionId(int audioSessionId); @@ -275,7 +275,6 @@ public InvalidAudioTrackTimestampException(String detailMessage) { private int bufferSize; private long bufferSizeUs; - private boolean useHwAvSync; private ByteBuffer avSyncHeader; private int bytesUntilNextAvSync; @@ -520,8 +519,7 @@ private void initialize() throws InitializationException { // initialization of the audio track to fail. releasingConditionVariable.block(); - useHwAvSync = tunneling; - if (useHwAvSync) { + if (tunneling) { audioTrack = createHwAvSyncAudioTrackV21(sampleRate, channelConfig, targetEncoding, bufferSize, audioSessionId); } else if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) { @@ -716,7 +714,7 @@ private boolean writeBuffer(ByteBuffer buffer, long presentationTimeUs) throws W buffer.position(buffer.position() + bytesWritten); } } else { - bytesWritten = useHwAvSync + bytesWritten = tunneling ? writeNonBlockingWithAvSyncV21(audioTrack, buffer, bytesRemaining, presentationTimeUs) : writeNonBlockingV21(audioTrack, buffer, bytesRemaining); } @@ -771,13 +769,12 @@ public void setPlaybackParams(PlaybackParams playbackParams) { /** * Sets the stream type for audio track. If the stream type has changed and if the audio track - * is not configured for use with video tunneling, then the audio track is reset and will be - * reinitialized on the next call to {@link #handleBuffer(ByteBuffer, long)}. An audio session - * cannot be reused after a change of stream type, so the audio session identifier will be reset. + * is not configured for use with tunneling, then the audio track is reset and the audio session + * id is cleared. *

- * If the audio track is configured for use with video tunneling then the stream type is ignored - * and the audio track is not reset. The passed stream type will be used if the audio track is - * later re-configured into non-tunneled mode. + * If the audio track is configured for use with tunneling then the stream type is ignored, the + * audio track is not reset and the audio session id is not cleared. The passed stream type will + * be used if the audio track is later re-configured into non-tunneled mode. * * @param streamType The {@link C.StreamType} to use for audio output. */ @@ -786,7 +783,7 @@ public void setStreamType(@C.StreamType int streamType) { return; } this.streamType = streamType; - if (useHwAvSync) { + if (tunneling) { // The stream type is ignored in tunneling mode, so no need to reset. return; } @@ -795,7 +792,7 @@ public void setStreamType(@C.StreamType int streamType) { } /** - * Sets the audio session id, and resets the audio track if the audio session id has changed. + * Sets the audio session id. The audio track is reset if the audio session id has changed. */ public void setAudioSessionId(int audioSessionId) { if (this.audioSessionId != audioSessionId) { @@ -805,16 +802,29 @@ public void setAudioSessionId(int audioSessionId) { } /** - * Sets whether tunneling is enabled. Enabling tunneling requires platform API version 21 onwards. - * Resets the audio track if tunneling was enabled/disabled. + * Enables tunneling. The audio track is reset if tunneling was previously disabled or if the + * audio session id has changed. Enabling tunneling requires platform API version 21 onwards. * - * @param tunneling Whether the audio track will be used with tunneling video playback. + * @param tunnelingAudioSessionId The audio session id to use. * @throws IllegalStateException Thrown if enabling tunneling on platform API version < 21. */ - public void setTunnelingEnabledV21(boolean tunneling) { - if (this.tunneling != tunneling) { - Assertions.checkState(Util.SDK_INT >= 21); - this.tunneling = tunneling; + public void enableTunnelingV21(int tunnelingAudioSessionId) { + Assertions.checkState(Util.SDK_INT >= 21); + if (!tunneling || audioSessionId != tunnelingAudioSessionId) { + tunneling = true; + audioSessionId = tunnelingAudioSessionId; + reset(); + } + } + + /** + * Disables tunneling. If tunneling was previously enabled then the audio track is reset and the + * audio session id is cleared. + */ + public void disableTunneling() { + if (tunneling) { + tunneling = false; + audioSessionId = C.AUDIO_SESSION_ID_UNSET; reset(); } } diff --git a/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 308ee7773b3..ac2501c0fd9 100644 --- a/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -258,6 +258,13 @@ protected void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, protected void onEnabled(boolean joining) throws ExoPlaybackException { super.onEnabled(joining); eventDispatcher.enabled(decoderCounters); + // TODO: Allow this to be set. + int tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET; + if (tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET) { + audioTrack.enableTunnelingV21(tunnelingAudioSessionId); + } else { + audioTrack.disableTunneling(); + } } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index ee305ca59f8..28635d5449a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -406,6 +406,13 @@ public long getPositionUs() { protected void onEnabled(boolean joining) throws ExoPlaybackException { decoderCounters = new DecoderCounters(); eventDispatcher.enabled(decoderCounters); + // TODO: Allow this to be set. + int tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET; + if (tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET) { + audioTrack.enableTunnelingV21(tunnelingAudioSessionId); + } else { + audioTrack.disableTunneling(); + } } @Override