Commit 15a2f47f by andrewlewis Committed by Oliver Woodman

Add support for float output in DefaultAudioSink

Also switch from using MIME types to C.ENCODING_* encodings in DefaultAudioSink.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175936872
parent 8537376a
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
position, for fast backward seeking. The back-buffer can be configured by position, for fast backward seeking. The back-buffer can be configured by
custom `LoadControl` implementations. custom `LoadControl` implementations.
* New Cast extension: Simplifies toggling between local and Cast playbacks. * New Cast extension: Simplifies toggling between local and Cast playbacks.
* Support 32-bit PCM float output from `DefaultAudioSink`.
### 2.6.0 ### ### 2.6.0 ###
......
...@@ -127,8 +127,8 @@ public final class C { ...@@ -127,8 +127,8 @@ public final class C {
*/ */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, @IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_AC3, ENCODING_E_AC3, ENCODING_DTS, ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT, ENCODING_AC3, ENCODING_E_AC3,
ENCODING_DTS_HD}) ENCODING_DTS, ENCODING_DTS_HD})
public @interface Encoding {} public @interface Encoding {}
/** /**
...@@ -136,7 +136,7 @@ public final class C { ...@@ -136,7 +136,7 @@ public final class C {
*/ */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, @IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT}) ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT})
public @interface PcmEncoding {} public @interface PcmEncoding {}
/** /**
* @see AudioFormat#ENCODING_INVALID * @see AudioFormat#ENCODING_INVALID
...@@ -159,6 +159,10 @@ public final class C { ...@@ -159,6 +159,10 @@ public final class C {
*/ */
public static final int ENCODING_PCM_32BIT = 0x40000000; public static final int ENCODING_PCM_32BIT = 0x40000000;
/** /**
* @see AudioFormat#ENCODING_PCM_FLOAT
*/
public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT;
/**
* @see AudioFormat#ENCODING_AC3 * @see AudioFormat#ENCODING_AC3
*/ */
public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3;
......
...@@ -25,14 +25,13 @@ import java.nio.ByteBuffer; ...@@ -25,14 +25,13 @@ import java.nio.ByteBuffer;
* A sink that consumes audio data. * A sink that consumes audio data.
* <p> * <p>
* Before starting playback, specify the input audio format by calling * Before starting playback, specify the input audio format by calling
* {@link #configure(String, int, int, int, int, int[], int, int)}. * {@link #configure(int, int, int, int, int[], int, int)}.
* <p> * <p>
* Call {@link #handleBuffer(ByteBuffer, long)} to write data, and {@link #handleDiscontinuity()} * 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. * when the data being fed is discontinuous. Call {@link #play()} to start playing the written data.
* <p> * <p>
* Call {@link #configure(String, int, int, int, int, int[], int, int)} whenever the input format * Call {@link #configure(int, int, int, int, int[], int, int)} whenever the input format changes.
* changes. The sink will be reinitialized on the next call to * The sink will be reinitialized on the next call to {@link #handleBuffer(ByteBuffer, long)}.
* {@link #handleBuffer(ByteBuffer, long)}.
* <p> * <p>
* Call {@link #reset()} to prepare the sink to receive audio data from a new playback position. * Call {@link #reset()} to prepare the sink to receive audio data from a new playback position.
* <p> * <p>
...@@ -166,13 +165,12 @@ public interface AudioSink { ...@@ -166,13 +165,12 @@ public interface AudioSink {
void setListener(Listener listener); void setListener(Listener listener);
/** /**
* Returns whether it's possible to play audio in the specified format using encoded audio * Returns whether it's possible to play audio in the specified encoding using passthrough.
* passthrough.
* *
* @param mimeType The format mime type. * @param encoding The audio encoding.
* @return Whether it's possible to play audio in the format using encoded audio passthrough. * @return Whether it's possible to play audio in the specified encoding using passthrough.
*/ */
boolean isPassthroughSupported(String mimeType); boolean isPassthroughSupported(@C.Encoding int encoding);
/** /**
* Returns the playback position in the stream starting at zero, in microseconds, or * Returns the playback position in the stream starting at zero, in microseconds, or
...@@ -186,12 +184,9 @@ public interface AudioSink { ...@@ -186,12 +184,9 @@ public interface AudioSink {
/** /**
* Configures (or reconfigures) the sink. * Configures (or reconfigures) the sink.
* *
* @param inputMimeType The MIME type of audio data provided in the input buffers. * @param inputEncoding The encoding of audio data provided in the input buffers.
* @param inputChannelCount The number of channels. * @param inputChannelCount The number of channels.
* @param inputSampleRate The sample rate in Hz. * @param inputSampleRate The sample rate in Hz.
* @param inputPcmEncoding For PCM formats, the encoding used. One of
* {@link C#ENCODING_PCM_16BIT}, {@link C#ENCODING_PCM_16BIT}, {@link C#ENCODING_PCM_24BIT}
* and {@link C#ENCODING_PCM_32BIT}.
* @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to infer a * @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to infer a
* suitable buffer size. * suitable buffer size.
* @param outputChannels A mapping from input to output channels that is applied to this sink's * @param outputChannels A mapping from input to output channels that is applied to this sink's
...@@ -205,9 +200,9 @@ public interface AudioSink { ...@@ -205,9 +200,9 @@ public interface AudioSink {
* immediately preceding the next call to {@link #reset()} or this method. * immediately preceding the next call to {@link #reset()} or this method.
* @throws ConfigurationException If an error occurs configuring the sink. * @throws ConfigurationException If an error occurs configuring the sink.
*/ */
void configure(String inputMimeType, int inputChannelCount, int inputSampleRate, void configure(@C.Encoding int inputEncoding, int inputChannelCount, int inputSampleRate,
@C.PcmEncoding int inputPcmEncoding, int specifiedBufferSize, @Nullable int[] outputChannels, int specifiedBufferSize, @Nullable int[] outputChannels, int trimStartSamples,
int trimStartSamples, int trimEndSamples) throws ConfigurationException; int trimEndSamples) throws ConfigurationException;
/** /**
* Starts or resumes consuming audio if initialized. * Starts or resumes consuming audio if initialized.
...@@ -228,8 +223,7 @@ public interface AudioSink { ...@@ -228,8 +223,7 @@ public interface AudioSink {
* Returns whether the data was handled in full. If the data was not handled in full then the same * Returns whether the data was handled in full. If the data was not handled in full then the same
* {@link ByteBuffer} must be provided to subsequent calls until it has been fully consumed, * {@link ByteBuffer} must be provided to subsequent calls until it has been fully consumed,
* except in the case of an intervening call to {@link #reset()} (or to * except in the case of an intervening call to {@link #reset()} (or to
* {@link #configure(String, int, int, int, int, int[], int, int)} that causes the sink to be * {@link #configure(int, int, int, int, int[], int, int)} that causes the sink to be reset).
* reset).
* *
* @param buffer The buffer containing audio data. * @param buffer The buffer containing audio data.
* @param presentationTimeUs The presentation timestamp of the buffer in microseconds. * @param presentationTimeUs The presentation timestamp of the buffer in microseconds.
......
...@@ -29,7 +29,6 @@ import android.util.Log; ...@@ -29,7 +29,6 @@ import android.util.Log;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
...@@ -182,13 +181,13 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -182,13 +181,13 @@ public final class DefaultAudioSink implements AudioSink {
*/ */
private AudioTrack keepSessionIdAudioTrack; private AudioTrack keepSessionIdAudioTrack;
private AudioTrack audioTrack; private AudioTrack audioTrack;
private boolean isInputPcm;
private int inputSampleRate; private int inputSampleRate;
private int sampleRate; private int sampleRate;
private int channelConfig; private int channelConfig;
private @C.Encoding int encoding;
private @C.Encoding int outputEncoding; private @C.Encoding int outputEncoding;
private AudioAttributes audioAttributes; private AudioAttributes audioAttributes;
private boolean passthrough; private boolean processingEnabled;
private int bufferSize; private int bufferSize;
private long bufferSizeUs; private long bufferSizeUs;
...@@ -286,9 +285,8 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -286,9 +285,8 @@ public final class DefaultAudioSink implements AudioSink {
} }
@Override @Override
public boolean isPassthroughSupported(String mimeType) { public boolean isPassthroughSupported(@C.Encoding int encoding) {
return audioCapabilities != null return audioCapabilities != null && audioCapabilities.supportsEncoding(encoding);
&& audioCapabilities.supportsEncoding(getEncodingForMimeType(mimeType));
} }
@Override @Override
...@@ -331,18 +329,20 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -331,18 +329,20 @@ public final class DefaultAudioSink implements AudioSink {
} }
@Override @Override
public void configure(String inputMimeType, int inputChannelCount, int inputSampleRate, public void configure(@C.Encoding int inputEncoding, int inputChannelCount, int inputSampleRate,
@C.PcmEncoding int inputPcmEncoding, int specifiedBufferSize, @Nullable int[] outputChannels, int specifiedBufferSize, @Nullable int[] outputChannels, int trimStartSamples,
int trimStartSamples, int trimEndSamples) throws ConfigurationException { int trimEndSamples) throws ConfigurationException {
boolean flush = false;
this.inputSampleRate = inputSampleRate; this.inputSampleRate = inputSampleRate;
int channelCount = inputChannelCount; int channelCount = inputChannelCount;
int sampleRate = inputSampleRate; int sampleRate = inputSampleRate;
@C.Encoding int encoding; isInputPcm = isEncodingPcm(inputEncoding);
boolean passthrough = !MimeTypes.AUDIO_RAW.equals(inputMimeType); if (isInputPcm) {
boolean flush = false; pcmFrameSize = Util.getPcmFrameSize(inputEncoding, channelCount);
if (!passthrough) { }
encoding = inputPcmEncoding; @C.Encoding int encoding = inputEncoding;
pcmFrameSize = Util.getPcmFrameSize(inputPcmEncoding, channelCount); boolean processingEnabled = isInputPcm && inputEncoding != C.ENCODING_PCM_FLOAT;
if (processingEnabled) {
trimmingAudioProcessor.setTrimSampleCount(trimStartSamples, trimEndSamples); trimmingAudioProcessor.setTrimSampleCount(trimStartSamples, trimEndSamples);
channelMappingAudioProcessor.setChannelMap(outputChannels); channelMappingAudioProcessor.setChannelMap(outputChannels);
for (AudioProcessor audioProcessor : availableAudioProcessors) { for (AudioProcessor audioProcessor : availableAudioProcessors) {
...@@ -360,8 +360,6 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -360,8 +360,6 @@ public final class DefaultAudioSink implements AudioSink {
if (flush) { if (flush) {
resetAudioProcessors(); resetAudioProcessors();
} }
} else {
encoding = getEncodingForMimeType(inputMimeType);
} }
int channelConfig; int channelConfig;
...@@ -411,11 +409,11 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -411,11 +409,11 @@ public final class DefaultAudioSink implements AudioSink {
// Workaround for Nexus Player not reporting support for mono passthrough. // Workaround for Nexus Player not reporting support for mono passthrough.
// (See [Internal: b/34268671].) // (See [Internal: b/34268671].)
if (Util.SDK_INT <= 25 && "fugu".equals(Util.DEVICE) && passthrough && channelCount == 1) { if (Util.SDK_INT <= 25 && "fugu".equals(Util.DEVICE) && !isInputPcm && channelCount == 1) {
channelConfig = AudioFormat.CHANNEL_OUT_STEREO; channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
} }
if (!flush && isInitialized() && this.encoding == encoding && this.sampleRate == sampleRate if (!flush && isInitialized() && outputEncoding == encoding && this.sampleRate == sampleRate
&& this.channelConfig == channelConfig) { && this.channelConfig == channelConfig) {
// We already have an audio track with the correct sample rate, channel config and encoding. // We already have an audio track with the correct sample rate, channel config and encoding.
return; return;
...@@ -423,16 +421,24 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -423,16 +421,24 @@ public final class DefaultAudioSink implements AudioSink {
reset(); reset();
this.encoding = encoding; this.processingEnabled = processingEnabled;
this.passthrough = passthrough;
this.sampleRate = sampleRate; this.sampleRate = sampleRate;
this.channelConfig = channelConfig; this.channelConfig = channelConfig;
outputEncoding = passthrough ? encoding : C.ENCODING_PCM_16BIT; outputEncoding = encoding;
outputPcmFrameSize = Util.getPcmFrameSize(C.ENCODING_PCM_16BIT, channelCount); if (isInputPcm) {
outputPcmFrameSize = Util.getPcmFrameSize(outputEncoding, channelCount);
}
if (specifiedBufferSize != 0) { if (specifiedBufferSize != 0) {
bufferSize = specifiedBufferSize; bufferSize = specifiedBufferSize;
} else if (passthrough) { } else if (isInputPcm) {
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, outputEncoding);
Assertions.checkState(minBufferSize != ERROR_BAD_VALUE);
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize;
int maxAppBufferSize = (int) Math.max(minBufferSize,
durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize);
bufferSize = Util.constrainValue(multipliedBufferSize, minAppBufferSize, maxAppBufferSize);
} else {
// TODO: Set the minimum buffer size using getMinBufferSize when it takes the encoding into // TODO: Set the minimum buffer size using getMinBufferSize when it takes the encoding into
// account. [Internal: b/25181305] // account. [Internal: b/25181305]
if (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3) { if (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3) {
...@@ -442,21 +448,9 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -442,21 +448,9 @@ public final class DefaultAudioSink implements AudioSink {
// DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s. // DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s.
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND); bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND);
} }
} else {
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, outputEncoding);
Assertions.checkState(minBufferSize != ERROR_BAD_VALUE);
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize;
int maxAppBufferSize = (int) Math.max(minBufferSize,
durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize);
bufferSize = multipliedBufferSize < minAppBufferSize ? minAppBufferSize
: multipliedBufferSize > maxAppBufferSize ? maxAppBufferSize
: multipliedBufferSize;
} }
bufferSizeUs = passthrough ? C.TIME_UNSET : framesToDurationUs(bufferSize / outputPcmFrameSize); bufferSizeUs =
isInputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
// The old playback parameters may no longer be applicable so try to reset them now.
setPlaybackParameters(playbackParameters);
} }
private void resetAudioProcessors() { private void resetAudioProcessors() {
...@@ -487,6 +481,10 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -487,6 +481,10 @@ public final class DefaultAudioSink implements AudioSink {
releasingConditionVariable.block(); releasingConditionVariable.block();
audioTrack = initializeAudioTrack(); audioTrack = initializeAudioTrack();
// The old playback parameters may no longer be applicable so try to reset them now.
setPlaybackParameters(playbackParameters);
int audioSessionId = audioTrack.getAudioSessionId(); int audioSessionId = audioTrack.getAudioSessionId();
if (enablePreV21AudioSessionWorkaround) { if (enablePreV21AudioSessionWorkaround) {
if (Util.SDK_INT < 21) { if (Util.SDK_INT < 21) {
...@@ -574,7 +572,7 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -574,7 +572,7 @@ public final class DefaultAudioSink implements AudioSink {
return true; return true;
} }
if (passthrough && framesPerEncodedSample == 0) { if (!isInputPcm && framesPerEncodedSample == 0) {
// If this is the first encoded sample, calculate the sample size in frames. // If this is the first encoded sample, calculate the sample size in frames.
framesPerEncodedSample = getFramesPerEncodedSample(outputEncoding, buffer); framesPerEncodedSample = getFramesPerEncodedSample(outputEncoding, buffer);
} }
...@@ -618,20 +616,19 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -618,20 +616,19 @@ public final class DefaultAudioSink implements AudioSink {
} }
} }
if (passthrough) { if (isInputPcm) {
submittedEncodedFrames += framesPerEncodedSample;
} else {
submittedPcmBytes += buffer.remaining(); submittedPcmBytes += buffer.remaining();
} else {
submittedEncodedFrames += framesPerEncodedSample;
} }
inputBuffer = buffer; inputBuffer = buffer;
} }
if (passthrough) { if (processingEnabled) {
// Passthrough buffers are not processed.
writeBuffer(inputBuffer, presentationTimeUs);
} else {
processBuffers(presentationTimeUs); processBuffers(presentationTimeUs);
} else {
writeBuffer(inputBuffer, presentationTimeUs);
} }
if (!inputBuffer.hasRemaining()) { if (!inputBuffer.hasRemaining()) {
...@@ -679,10 +676,9 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -679,10 +676,9 @@ public final class DefaultAudioSink implements AudioSink {
} }
@SuppressWarnings("ReferenceEquality") @SuppressWarnings("ReferenceEquality")
private boolean writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs) private void writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs) throws WriteException {
throws WriteException {
if (!buffer.hasRemaining()) { if (!buffer.hasRemaining()) {
return true; return;
} }
if (outputBuffer != null) { if (outputBuffer != null) {
Assertions.checkArgument(outputBuffer == buffer); Assertions.checkArgument(outputBuffer == buffer);
...@@ -701,7 +697,7 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -701,7 +697,7 @@ public final class DefaultAudioSink implements AudioSink {
} }
int bytesRemaining = buffer.remaining(); int bytesRemaining = buffer.remaining();
int bytesWritten = 0; int bytesWritten = 0;
if (Util.SDK_INT < 21) { // passthrough == false if (Util.SDK_INT < 21) { // isInputPcm == true
// Work out how many bytes we can write without the risk of blocking. // Work out how many bytes we can write without the risk of blocking.
int bytesPending = int bytesPending =
(int) (writtenPcmBytes - (audioTrackUtil.getPlaybackHeadPosition() * outputPcmFrameSize)); (int) (writtenPcmBytes - (audioTrackUtil.getPlaybackHeadPosition() * outputPcmFrameSize));
...@@ -728,17 +724,15 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -728,17 +724,15 @@ public final class DefaultAudioSink implements AudioSink {
throw new WriteException(bytesWritten); throw new WriteException(bytesWritten);
} }
if (!passthrough) { if (isInputPcm) {
writtenPcmBytes += bytesWritten; writtenPcmBytes += bytesWritten;
} }
if (bytesWritten == bytesRemaining) { if (bytesWritten == bytesRemaining) {
if (passthrough) { if (!isInputPcm) {
writtenEncodedFrames += framesPerEncodedSample; writtenEncodedFrames += framesPerEncodedSample;
} }
outputBuffer = null; outputBuffer = null;
return true;
} }
return false;
} }
@Override @Override
...@@ -758,7 +752,7 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -758,7 +752,7 @@ public final class DefaultAudioSink implements AudioSink {
private boolean drainAudioProcessorsToEndOfStream() throws WriteException { private boolean drainAudioProcessorsToEndOfStream() throws WriteException {
boolean audioProcessorNeedsEndOfStream = false; boolean audioProcessorNeedsEndOfStream = false;
if (drainingAudioProcessorIndex == C.INDEX_UNSET) { if (drainingAudioProcessorIndex == C.INDEX_UNSET) {
drainingAudioProcessorIndex = passthrough ? audioProcessors.length : 0; drainingAudioProcessorIndex = processingEnabled ? 0 : audioProcessors.length;
audioProcessorNeedsEndOfStream = true; audioProcessorNeedsEndOfStream = true;
} }
while (drainingAudioProcessorIndex < audioProcessors.length) { while (drainingAudioProcessorIndex < audioProcessors.length) {
...@@ -799,8 +793,8 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -799,8 +793,8 @@ public final class DefaultAudioSink implements AudioSink {
@Override @Override
public PlaybackParameters setPlaybackParameters(PlaybackParameters playbackParameters) { public PlaybackParameters setPlaybackParameters(PlaybackParameters playbackParameters) {
if (passthrough) { if (isInitialized() && !processingEnabled) {
// The playback parameters are always the default in passthrough mode. // The playback parameters are always the default if processing is disabled.
this.playbackParameters = PlaybackParameters.DEFAULT; this.playbackParameters = PlaybackParameters.DEFAULT;
return this.playbackParameters; return this.playbackParameters;
} }
...@@ -1076,7 +1070,7 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -1076,7 +1070,7 @@ public final class DefaultAudioSink implements AudioSink {
audioTimestampSet = false; audioTimestampSet = false;
} }
} }
if (getLatencyMethod != null && !passthrough) { if (getLatencyMethod != null && isInputPcm) {
try { try {
// Compute the audio track latency, excluding the latency due to the buffer (leaving // Compute the audio track latency, excluding the latency due to the buffer (leaving
// latency due to the mixer and audio hardware driver). // latency due to the mixer and audio hardware driver).
...@@ -1115,11 +1109,11 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -1115,11 +1109,11 @@ public final class DefaultAudioSink implements AudioSink {
} }
private long getSubmittedFrames() { private long getSubmittedFrames() {
return passthrough ? submittedEncodedFrames : (submittedPcmBytes / pcmFrameSize); return isInputPcm ? (submittedPcmBytes / pcmFrameSize) : submittedEncodedFrames;
} }
private long getWrittenFrames() { private long getWrittenFrames() {
return passthrough ? writtenEncodedFrames : (writtenPcmBytes / outputPcmFrameSize); return isInputPcm ? (writtenPcmBytes / outputPcmFrameSize) : writtenEncodedFrames;
} }
private void resetSyncParams() { private void resetSyncParams() {
...@@ -1212,20 +1206,10 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -1212,20 +1206,10 @@ public final class DefaultAudioSink implements AudioSink {
MODE_STATIC, audioSessionId); MODE_STATIC, audioSessionId);
} }
@C.Encoding private static boolean isEncodingPcm(@C.Encoding int encoding) {
private static int getEncodingForMimeType(String mimeType) { return encoding == C.ENCODING_PCM_8BIT || encoding == C.ENCODING_PCM_16BIT
switch (mimeType) { || encoding == C.ENCODING_PCM_24BIT || encoding == C.ENCODING_PCM_32BIT
case MimeTypes.AUDIO_AC3: || encoding == C.ENCODING_PCM_FLOAT;
return C.ENCODING_AC3;
case MimeTypes.AUDIO_E_AC3:
return C.ENCODING_E_AC3;
case MimeTypes.AUDIO_DTS:
return C.ENCODING_DTS;
case MimeTypes.AUDIO_DTS_HD:
return C.ENCODING_DTS_HD;
default:
return C.ENCODING_INVALID;
}
} }
private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) { private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) {
......
...@@ -51,6 +51,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -51,6 +51,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private boolean passthroughEnabled; private boolean passthroughEnabled;
private boolean codecNeedsDiscardChannelsWorkaround; private boolean codecNeedsDiscardChannelsWorkaround;
private android.media.MediaFormat passthroughMediaFormat; private android.media.MediaFormat passthroughMediaFormat;
@C.Encoding
private int pcmEncoding; private int pcmEncoding;
private int channelCount; private int channelCount;
private int encoderDelay; private int encoderDelay;
...@@ -226,7 +227,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -226,7 +227,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* @return Whether passthrough playback is supported. * @return Whether passthrough playback is supported.
*/ */
protected boolean allowPassthrough(String mimeType) { protected boolean allowPassthrough(String mimeType) {
return audioSink.isPassthroughSupported(mimeType); return audioSink.isPassthroughSupported(MimeTypes.getEncoding(mimeType));
} }
@Override @Override
...@@ -272,10 +273,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -272,10 +273,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override @Override
protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat) protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat)
throws ExoPlaybackException { throws ExoPlaybackException {
boolean passthrough = passthroughMediaFormat != null; @C.Encoding int encoding;
String mimeType = passthrough ? passthroughMediaFormat.getString(MediaFormat.KEY_MIME) MediaFormat format;
: MimeTypes.AUDIO_RAW; if (passthroughMediaFormat != null) {
MediaFormat format = passthrough ? passthroughMediaFormat : outputFormat; encoding = MimeTypes.getEncoding(passthroughMediaFormat.getString(MediaFormat.KEY_MIME));
format = passthroughMediaFormat;
} else {
encoding = pcmEncoding;
format = outputFormat;
}
int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
int[] channelMap; int[] channelMap;
...@@ -289,8 +295,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -289,8 +295,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
try { try {
audioSink.configure(mimeType, channelCount, sampleRate, pcmEncoding, 0, channelMap, audioSink.configure(encoding, channelCount, sampleRate, 0, channelMap, encoderDelay,
encoderDelay, encoderPadding); encoderPadding);
} catch (AudioSink.ConfigurationException e) { } catch (AudioSink.ConfigurationException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw ExoPlaybackException.createForRenderer(e, getIndex());
} }
......
...@@ -329,8 +329,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements ...@@ -329,8 +329,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
if (audioTrackNeedsConfigure) { if (audioTrackNeedsConfigure) {
Format outputFormat = getOutputFormat(); Format outputFormat = getOutputFormat();
audioSink.configure(outputFormat.sampleMimeType, outputFormat.channelCount, audioSink.configure(outputFormat.pcmEncoding, outputFormat.channelCount,
outputFormat.sampleRate, outputFormat.pcmEncoding, 0, null, encoderDelay, encoderPadding); outputFormat.sampleRate, 0, null, encoderDelay, encoderPadding);
audioTrackNeedsConfigure = false; audioTrackNeedsConfigure = false;
} }
......
...@@ -208,12 +208,12 @@ public final class MimeTypes { ...@@ -208,12 +208,12 @@ public final class MimeTypes {
} }
/** /**
* Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified mime type. * Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
* {@link C#TRACK_TYPE_UNKNOWN} if the mime type is not known or the mapping cannot be * {@link C#TRACK_TYPE_UNKNOWN} if the MIME type is not known or the mapping cannot be
* established. * established.
* *
* @param mimeType The mimeType. * @param mimeType The MIME type.
* @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified mime type. * @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
*/ */
public static int getTrackType(String mimeType) { public static int getTrackType(String mimeType) {
if (TextUtils.isEmpty(mimeType)) { if (TextUtils.isEmpty(mimeType)) {
...@@ -240,6 +240,28 @@ public final class MimeTypes { ...@@ -240,6 +240,28 @@ public final class MimeTypes {
} }
/** /**
* Returns the {@link C}{@code .ENCODING_*} constant that corresponds to a specified MIME type, or
* {@link C#ENCODING_INVALID} if the mapping cannot be established.
*
* @param mimeType The MIME type.
* @return The {@link C}{@code .ENCODING_*} constant that corresponds to a specified MIME type.
*/
public static @C.Encoding int getEncoding(String mimeType) {
switch (mimeType) {
case MimeTypes.AUDIO_AC3:
return C.ENCODING_AC3;
case MimeTypes.AUDIO_E_AC3:
return C.ENCODING_E_AC3;
case MimeTypes.AUDIO_DTS:
return C.ENCODING_DTS;
case MimeTypes.AUDIO_DTS_HD:
return C.ENCODING_DTS_HD;
default:
return C.ENCODING_INVALID;
}
}
/**
* Equivalent to {@code getTrackType(getMediaMimeType(codec))}. * Equivalent to {@code getTrackType(getMediaMimeType(codec))}.
* *
* @param codec The codec. * @param codec The codec.
......
...@@ -826,6 +826,7 @@ public final class Util { ...@@ -826,6 +826,7 @@ public final class Util {
case C.ENCODING_PCM_24BIT: case C.ENCODING_PCM_24BIT:
return channelCount * 3; return channelCount * 3;
case C.ENCODING_PCM_32BIT: case C.ENCODING_PCM_32BIT:
case C.ENCODING_PCM_FLOAT:
return channelCount * 4; return channelCount * 4;
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment