Merge pull request #226 from google/dev

Refine logic for determining AudioTrack size.
This commit is contained in:
ojw28 2015-01-06 20:15:42 +00:00
commit a6e94af267
3 changed files with 32 additions and 98 deletions

View File

@ -73,9 +73,6 @@ public final class Ac3PassthroughAudioTrackRenderer extends TrackRenderer {
/** Default buffer size for AC-3 packets from the sample source */
private static final int DEFAULT_BUFFER_SIZE = 16384 * 2;
/** Multiplication factor for the audio track's buffer size. */
private static final int MIN_BUFFER_MULTIPLICATION_FACTOR = 3;
private final Handler eventHandler;
private final EventListener eventListener;
@ -103,15 +100,15 @@ public final class Ac3PassthroughAudioTrackRenderer extends TrackRenderer {
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public Ac3PassthroughAudioTrackRenderer(
SampleSource source, Handler eventHandler, EventListener eventListener) {
public Ac3PassthroughAudioTrackRenderer(SampleSource source, Handler eventHandler,
EventListener eventListener) {
this.source = Assertions.checkNotNull(source);
this.eventHandler = eventHandler;
this.eventListener = eventListener;
sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
sampleHolder.data = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE);
formatHolder = new MediaFormatHolder();
audioTrack = new AudioTrack(MIN_BUFFER_MULTIPLICATION_FACTOR);
audioTrack = new AudioTrack();
shouldReadInputBuffer = true;
}

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer;
import com.google.android.exoplayer.audio.AudioTrack;
import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
import android.annotation.TargetApi;
@ -64,10 +63,9 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
public static final int MSG_SET_VOLUME = 1;
private final EventListener eventListener;
private final AudioTrack audioTrack;
private int audioSessionId;
private int audioSessionId;
private long currentPositionUs;
/**
@ -118,72 +116,10 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
*/
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) {
this(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener,
new AudioTrack());
}
/**
* @param source The upstream source from which the renderer obtains samples.
* @param minBufferMultiplicationFactor When instantiating an underlying
* {@link android.media.AudioTrack}, the size of the track is calculated as this value
* multiplied by the minimum buffer size obtained from
* {@link android.media.AudioTrack#getMinBufferSize(int, int, int)}. The multiplication
* factor must be greater than or equal to 1.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public MediaCodecAudioTrackRenderer(SampleSource source, float minBufferMultiplicationFactor,
Handler eventHandler, EventListener eventListener) {
this(source, null, true, minBufferMultiplicationFactor, eventHandler, eventListener);
}
/**
* @param source The upstream source from which the renderer obtains samples.
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
* content is not required.
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
* For example a media file may start with a short clear region so as to allow playback to
* begin in parallel with key acquisision. This parameter specifies whether the renderer is
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
* has obtained the keys necessary to decrypt encrypted regions of the media.
* @param minBufferMultiplicationFactor When instantiating an underlying
* {@link android.media.AudioTrack}, the size of the track is calculated as this value
* multiplied by the minimum buffer size obtained from
* {@link android.media.AudioTrack#getMinBufferSize(int, int, int)}. The multiplication
* factor must be greater than or equal to 1.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
boolean playClearSamplesWithoutKeys, float minBufferMultiplicationFactor,
Handler eventHandler, EventListener eventListener) {
this(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener,
new AudioTrack(minBufferMultiplicationFactor));
}
/**
* @param source The upstream source from which the renderer obtains samples.
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
* content is not required.
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
* For example a media file may start with a short clear region so as to allow playback to
* begin in parallel with key acquisision. This parameter specifies whether the renderer is
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
* has obtained the keys necessary to decrypt encrypted regions of the media.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioTrack Used for playing back decoded audio samples.
*/
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener,
AudioTrack audioTrack) {
super(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener);
this.eventListener = eventListener;
this.audioTrack = Assertions.checkNotNull(audioTrack);
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
this.audioTrack = new AudioTrack();
}
@Override

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer.audio;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
import android.annotation.SuppressLint;
@ -89,12 +88,19 @@ public final class AudioTrack {
/** Represents an unset {@link android.media.AudioTrack} session identifier. */
public static final int SESSION_ID_NOT_SET = 0;
/** The default multiplication factor used when determining the size of the track's buffer. */
public static final float DEFAULT_MIN_BUFFER_MULTIPLICATION_FACTOR = 4;
/** Returned by {@link #getCurrentPositionUs} when the position is not set. */
public static final long CURRENT_POSITION_NOT_SET = Long.MIN_VALUE;
/** A minimum length for the {@link android.media.AudioTrack} buffer, in microseconds. */
private static final long MIN_BUFFER_DURATION_US = 250000;
/** A maximum length for the {@link android.media.AudioTrack} buffer, in microseconds. */
private static final long MAX_BUFFER_DURATION_US = 750000;
/**
* A multiplication factor to apply to the minimum buffer size requested by the underlying
* {@link android.media.AudioTrack}.
*/
private static final int BUFFER_MULTIPLICATION_FACTOR = 4;
private static final String TAG = "AudioTrack";
/**
@ -126,7 +132,6 @@ public final class AudioTrack {
private final ConditionVariable releasingConditionVariable;
private final AudioTimestampCompat audioTimestampCompat;
private final long[] playheadOffsets;
private final float minBufferMultiplicationFactor;
private android.media.AudioTrack audioTrack;
private int sampleRate;
@ -162,15 +167,7 @@ public final class AudioTrack {
/** Bitrate measured in kilobits per second, if {@link #isAc3} is true. */
private int ac3Bitrate;
/** Constructs an audio track using the default minimum buffer size multiplier. */
public AudioTrack() {
this(DEFAULT_MIN_BUFFER_MULTIPLICATION_FACTOR);
}
/** Constructs an audio track using the specified minimum buffer size multiplier. */
public AudioTrack(float minBufferMultiplicationFactor) {
Assertions.checkArgument(minBufferMultiplicationFactor >= 1);
this.minBufferMultiplicationFactor = minBufferMultiplicationFactor;
releasingConditionVariable = new ConditionVariable(true);
if (Util.SDK_INT >= 19) {
audioTimestampCompat = new AudioTimestampCompatV19();
@ -297,11 +294,11 @@ public final class AudioTrack {
*
* @param format Specifies the channel count and sample rate to play back.
* @param encoding The format in which audio is represented.
* @param bufferSize The total size of the playback buffer in bytes. Specify 0 to use a buffer
* size based on the minimum for format.
* @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to use a
* size inferred from the format.
*/
@SuppressLint("InlinedApi")
public void reconfigure(MediaFormat format, int encoding, int bufferSize) {
public void reconfigure(MediaFormat format, int encoding, int specifiedBufferSize) {
int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
int channelConfig;
switch (channelCount) {
@ -333,16 +330,25 @@ public final class AudioTrack {
reset();
minBufferSize = android.media.AudioTrack.getMinBufferSize(sampleRate, channelConfig, encoding);
this.encoding = encoding;
this.bufferSize =
bufferSize == 0 ? (int) (minBufferMultiplicationFactor * minBufferSize) : bufferSize;
this.sampleRate = sampleRate;
this.channelConfig = channelConfig;
this.isAc3 = isAc3;
ac3Bitrate = UNKNOWN_AC3_BITRATE; // Calculated on receiving the first buffer if isAc3 is true.
frameSize = 2 * channelCount; // 2 bytes per 16 bit sample * number of channels.
minBufferSize = android.media.AudioTrack.getMinBufferSize(sampleRate, channelConfig, encoding);
if (specifiedBufferSize != 0) {
bufferSize = specifiedBufferSize;
} else {
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * frameSize;
int maxAppBufferSize = (int) Math.max(minBufferSize,
durationUsToFrames(MAX_BUFFER_DURATION_US) * frameSize);
bufferSize = multipliedBufferSize < minAppBufferSize ? minAppBufferSize
: multipliedBufferSize > maxAppBufferSize ? maxAppBufferSize
: multipliedBufferSize;
}
}
/** Starts/resumes playing audio if the audio track has been initialized. */
@ -434,7 +440,7 @@ public final class AudioTrack {
int bytesWritten = 0;
if (Util.SDK_INT < 21) {
// Work out how many bytes we can write without the risk of blocking.
int bytesPending = (int) (submittedBytes - framesToBytes(getPlaybackPositionFrames()));
int bytesPending = (int) (submittedBytes - (getPlaybackPositionFrames() * frameSize));
int bytesToWrite = bufferSize - bytesPending;
if (bytesToWrite > 0) {
bytesToWrite = Math.min(temporaryBufferSize, bytesToWrite);
@ -651,11 +657,6 @@ public final class AudioTrack {
return framesToDurationUs(getPlaybackPositionFrames());
}
private long framesToBytes(long frameCount) {
// This method is unused on SDK >= 21.
return frameCount * frameSize;
}
private long bytesToFrames(long byteCount) {
if (isAc3) {
return