Merge pull request #226 from google/dev
Refine logic for determining AudioTrack size.
This commit is contained in:
commit
a6e94af267
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user