Start cleaning up buffering.
- Always continue loading if we've got less than the minimum amount of media in the buffer. - Use LoadControl in ExtractorSampleSource. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=125679669
This commit is contained in:
parent
5055a4aa91
commit
a8883baa69
@ -58,8 +58,6 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
|
|
||||||
public static final int DEFAULT_LOW_WATERMARK_MS = 15000;
|
public static final int DEFAULT_LOW_WATERMARK_MS = 15000;
|
||||||
public static final int DEFAULT_HIGH_WATERMARK_MS = 30000;
|
public static final int DEFAULT_HIGH_WATERMARK_MS = 30000;
|
||||||
public static final float DEFAULT_LOW_BUFFER_LOAD = 0.2f;
|
|
||||||
public static final float DEFAULT_HIGH_BUFFER_LOAD = 0.8f;
|
|
||||||
|
|
||||||
private static final int ABOVE_HIGH_WATERMARK = 0;
|
private static final int ABOVE_HIGH_WATERMARK = 0;
|
||||||
private static final int BETWEEN_WATERMARKS = 1;
|
private static final int BETWEEN_WATERMARKS = 1;
|
||||||
@ -73,12 +71,10 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
|
|
||||||
private final long lowWatermarkUs;
|
private final long lowWatermarkUs;
|
||||||
private final long highWatermarkUs;
|
private final long highWatermarkUs;
|
||||||
private final float lowBufferLoad;
|
|
||||||
private final float highBufferLoad;
|
|
||||||
|
|
||||||
private int targetBufferSize;
|
|
||||||
private long maxLoadStartPositionUs;
|
private long maxLoadStartPositionUs;
|
||||||
private int bufferState;
|
private int targetBufferSize;
|
||||||
|
private boolean targetBufferSizeReached;
|
||||||
private boolean fillingBuffers;
|
private boolean fillingBuffers;
|
||||||
private boolean streamingPrioritySet;
|
private boolean streamingPrioritySet;
|
||||||
|
|
||||||
@ -102,7 +98,7 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
public DefaultLoadControl(DefaultAllocator allocator, Handler eventHandler,
|
public DefaultLoadControl(DefaultAllocator allocator, Handler eventHandler,
|
||||||
EventListener eventListener) {
|
EventListener eventListener) {
|
||||||
this(allocator, eventHandler, eventListener, DEFAULT_LOW_WATERMARK_MS,
|
this(allocator, eventHandler, eventListener, DEFAULT_LOW_WATERMARK_MS,
|
||||||
DEFAULT_HIGH_WATERMARK_MS, DEFAULT_LOW_BUFFER_LOAD, DEFAULT_HIGH_BUFFER_LOAD);
|
DEFAULT_HIGH_WATERMARK_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,15 +113,9 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
* the filling state.
|
* the filling state.
|
||||||
* @param highWatermarkMs The minimum duration of media that can be buffered for the control to
|
* @param highWatermarkMs The minimum duration of media that can be buffered for the control to
|
||||||
* transition from filling to draining.
|
* transition from filling to draining.
|
||||||
* @param lowBufferLoad The minimum fraction of the buffer that must be utilized for the control
|
|
||||||
* to be in the draining state. If the utilization is lower, then the control will transition
|
|
||||||
* to the filling state.
|
|
||||||
* @param highBufferLoad The minimum fraction of the buffer that must be utilized for the control
|
|
||||||
* to transition from the loading state to the draining state.
|
|
||||||
*/
|
*/
|
||||||
public DefaultLoadControl(DefaultAllocator allocator, Handler eventHandler,
|
public DefaultLoadControl(DefaultAllocator allocator, Handler eventHandler,
|
||||||
EventListener eventListener, int lowWatermarkMs, int highWatermarkMs, float lowBufferLoad,
|
EventListener eventListener, int lowWatermarkMs, int highWatermarkMs) {
|
||||||
float highBufferLoad) {
|
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
@ -133,8 +123,6 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
this.loaderStates = new HashMap<>();
|
this.loaderStates = new HashMap<>();
|
||||||
this.lowWatermarkUs = lowWatermarkMs * 1000L;
|
this.lowWatermarkUs = lowWatermarkMs * 1000L;
|
||||||
this.highWatermarkUs = highWatermarkMs * 1000L;
|
this.highWatermarkUs = highWatermarkMs * 1000L;
|
||||||
this.lowBufferLoad = lowBufferLoad;
|
|
||||||
this.highBufferLoad = highBufferLoad;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -151,6 +139,7 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
LoaderState state = loaderStates.remove(loader);
|
LoaderState state = loaderStates.remove(loader);
|
||||||
targetBufferSize -= state.bufferSizeContribution;
|
targetBufferSize -= state.bufferSizeContribution;
|
||||||
allocator.setTargetBufferSize(targetBufferSize);
|
allocator.setTargetBufferSize(targetBufferSize);
|
||||||
|
targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
||||||
updateControlState();
|
updateControlState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,11 +163,10 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the buffer state.
|
// Update the buffer state.
|
||||||
int currentBufferSize = allocator.getTotalBytesAllocated();
|
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
||||||
int bufferState = getBufferState(currentBufferSize);
|
boolean bufferStateChanged = this.targetBufferSizeReached != targetBufferSizeReached;
|
||||||
boolean bufferStateChanged = this.bufferState != bufferState;
|
|
||||||
if (bufferStateChanged) {
|
if (bufferStateChanged) {
|
||||||
this.bufferState = bufferState;
|
this.targetBufferSizeReached = targetBufferSizeReached;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If either of the individual states have changed, update the shared control state.
|
// If either of the individual states have changed, update the shared control state.
|
||||||
@ -186,8 +174,7 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
updateControlState();
|
updateControlState();
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentBufferSize < targetBufferSize && nextLoadPositionUs != C.UNSET_TIME_US
|
return nextLoadPositionUs != C.UNSET_TIME_US && nextLoadPositionUs <= maxLoadStartPositionUs;
|
||||||
&& nextLoadPositionUs <= maxLoadStartPositionUs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getLoaderBufferState(long playbackPositionUs, long nextLoadPositionUs) {
|
private int getLoaderBufferState(long playbackPositionUs, long nextLoadPositionUs) {
|
||||||
@ -201,27 +188,20 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getBufferState(int currentBufferSize) {
|
|
||||||
float bufferLoad = (float) currentBufferSize / targetBufferSize;
|
|
||||||
return bufferLoad > highBufferLoad ? ABOVE_HIGH_WATERMARK
|
|
||||||
: bufferLoad < lowBufferLoad ? BELOW_LOW_WATERMARK
|
|
||||||
: BETWEEN_WATERMARKS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateControlState() {
|
private void updateControlState() {
|
||||||
boolean loading = false;
|
boolean loading = false;
|
||||||
boolean haveNextLoadPosition = false;
|
boolean haveNextLoadPosition = false;
|
||||||
int highestState = bufferState;
|
int worstLoaderState = ABOVE_HIGH_WATERMARK;
|
||||||
for (int i = 0; i < loaders.size(); i++) {
|
for (int i = 0; i < loaders.size(); i++) {
|
||||||
LoaderState loaderState = loaderStates.get(loaders.get(i));
|
LoaderState loaderState = loaderStates.get(loaders.get(i));
|
||||||
loading |= loaderState.loading;
|
loading |= loaderState.loading;
|
||||||
haveNextLoadPosition |= loaderState.nextLoadPositionUs != C.UNSET_TIME_US;
|
haveNextLoadPosition |= loaderState.nextLoadPositionUs != C.UNSET_TIME_US;
|
||||||
highestState = Math.max(highestState, loaderState.bufferState);
|
worstLoaderState = Math.max(worstLoaderState, loaderState.bufferState);
|
||||||
}
|
}
|
||||||
|
|
||||||
fillingBuffers = !loaders.isEmpty() && (loading || haveNextLoadPosition)
|
fillingBuffers = !loaders.isEmpty() && (loading || haveNextLoadPosition)
|
||||||
&& (highestState == BELOW_LOW_WATERMARK
|
&& (worstLoaderState == BELOW_LOW_WATERMARK
|
||||||
|| (highestState == BETWEEN_WATERMARKS && fillingBuffers));
|
|| (worstLoaderState == BETWEEN_WATERMARKS && fillingBuffers && !targetBufferSizeReached));
|
||||||
if (fillingBuffers && !streamingPrioritySet) {
|
if (fillingBuffers && !streamingPrioritySet) {
|
||||||
NetworkLock.instance.add(NetworkLock.STREAMING_PRIORITY);
|
NetworkLock.instance.add(NetworkLock.STREAMING_PRIORITY);
|
||||||
streamingPrioritySet = true;
|
streamingPrioritySet = true;
|
||||||
|
@ -17,14 +17,15 @@ package com.google.android.exoplayer.extractor;
|
|||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.DecoderInputBuffer;
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
|
import com.google.android.exoplayer.DefaultLoadControl;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
|
import com.google.android.exoplayer.LoadControl;
|
||||||
import com.google.android.exoplayer.ParserException;
|
import com.google.android.exoplayer.ParserException;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
import com.google.android.exoplayer.TrackSelection;
|
import com.google.android.exoplayer.TrackSelection;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
import com.google.android.exoplayer.upstream.Allocator;
|
|
||||||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
||||||
@ -36,6 +37,7 @@ import com.google.android.exoplayer.util.Assertions;
|
|||||||
import com.google.android.exoplayer.util.Util;
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.ConditionVariable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
@ -125,7 +127,8 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final EventListener eventListener;
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final Allocator allocator;
|
private final ConditionVariable loadCondition;
|
||||||
|
private final LoadControl loadControl;
|
||||||
private final Loader loader;
|
private final Loader loader;
|
||||||
private final ExtractorHolder extractorHolder;
|
private final ExtractorHolder extractorHolder;
|
||||||
|
|
||||||
@ -186,7 +189,8 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
||||||
allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
loadCondition = new ConditionVariable();
|
||||||
|
loadControl = new DefaultLoadControl(new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE));
|
||||||
loader = new Loader("Loader:ExtractorSampleSource");
|
loader = new Loader("Loader:ExtractorSampleSource");
|
||||||
extractorHolder = new ExtractorHolder(extractors, this);
|
extractorHolder = new ExtractorHolder(extractors, this);
|
||||||
pendingResetPositionUs = C.UNSET_TIME_US;
|
pendingResetPositionUs = C.UNSET_TIME_US;
|
||||||
@ -308,6 +312,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (seekMap != null && tracksBuilt && haveFormatsForAllTracks()) {
|
if (seekMap != null && tracksBuilt && haveFormatsForAllTracks()) {
|
||||||
|
loadCondition.close();
|
||||||
int trackCount = sampleQueues.length;
|
int trackCount = sampleQueues.length;
|
||||||
TrackGroup[] trackArray = new TrackGroup[trackCount];
|
TrackGroup[] trackArray = new TrackGroup[trackCount];
|
||||||
trackEnabledStates = new boolean[trackCount];
|
trackEnabledStates = new boolean[trackCount];
|
||||||
@ -322,6 +327,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
// We're not prepared.
|
// We're not prepared.
|
||||||
maybeThrowError();
|
maybeThrowError();
|
||||||
if (!loader.isLoading()) {
|
if (!loader.isLoading()) {
|
||||||
|
loadCondition.open();
|
||||||
startLoading();
|
startLoading();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -341,6 +347,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
||||||
List<TrackSelection> newSelections, long positionUs) {
|
List<TrackSelection> newSelections, long positionUs) {
|
||||||
Assertions.checkState(prepared);
|
Assertions.checkState(prepared);
|
||||||
|
boolean tracksWereEnabled = enabledTrackCount > 0;
|
||||||
// Unselect old tracks.
|
// Unselect old tracks.
|
||||||
for (int i = 0; i < oldStreams.size(); i++) {
|
for (int i = 0; i < oldStreams.size(); i++) {
|
||||||
int track = ((TrackStreamImpl) oldStreams.get(i)).track;
|
int track = ((TrackStreamImpl) oldStreams.get(i)).track;
|
||||||
@ -372,19 +379,33 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
}
|
}
|
||||||
// Cancel or start requests as necessary.
|
// Cancel or start requests as necessary.
|
||||||
if (enabledTrackCount == 0) {
|
if (enabledTrackCount == 0) {
|
||||||
|
if (tracksWereEnabled) {
|
||||||
|
loadControl.unregister(this);
|
||||||
|
loadCondition.close();
|
||||||
|
}
|
||||||
if (loader.isLoading()) {
|
if (loader.isLoading()) {
|
||||||
loader.cancelLoading();
|
loader.cancelLoading();
|
||||||
}
|
}
|
||||||
} else if (seenFirstTrackSelection ? newStreams.length > 0 : positionUs != 0) {
|
} else {
|
||||||
|
if (!tracksWereEnabled) {
|
||||||
|
loadControl.register(this, C.DEFAULT_MUXED_BUFFER_SIZE);
|
||||||
|
loadCondition.open();
|
||||||
|
}
|
||||||
|
if (seenFirstTrackSelection ? newStreams.length > 0 : positionUs != 0) {
|
||||||
seekToUs(positionUs);
|
seekToUs(positionUs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
seenFirstTrackSelection = true;
|
seenFirstTrackSelection = true;
|
||||||
return newStreams;
|
return newStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void continueBuffering(long playbackPositionUs) {
|
public void continueBuffering(long playbackPositionUs) {
|
||||||
// Do nothing.
|
if (loadControl.update(this, playbackPositionUs, getBufferedPositionUs(), loader.isLoading())) {
|
||||||
|
loadCondition.open();
|
||||||
|
} else {
|
||||||
|
loadCondition.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -434,6 +455,9 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
||||||
sampleQueue.disable();
|
sampleQueue.disable();
|
||||||
}
|
}
|
||||||
|
if (enabledTrackCount > 0) {
|
||||||
|
loadControl.unregister(this);
|
||||||
|
}
|
||||||
loader.release();
|
loader.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,7 +522,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
@Override
|
@Override
|
||||||
public TrackOutput track(int id) {
|
public TrackOutput track(int id) {
|
||||||
sampleQueues = Arrays.copyOf(sampleQueues, sampleQueues.length + 1);
|
sampleQueues = Arrays.copyOf(sampleQueues, sampleQueues.length + 1);
|
||||||
DefaultTrackOutput sampleQueue = new DefaultTrackOutput(allocator);
|
DefaultTrackOutput sampleQueue = new DefaultTrackOutput(loadControl.getAllocator());
|
||||||
sampleQueues[sampleQueues.length - 1] = sampleQueue;
|
sampleQueues[sampleQueues.length - 1] = sampleQueue;
|
||||||
return sampleQueue;
|
return sampleQueue;
|
||||||
}
|
}
|
||||||
@ -536,7 +560,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
|
|
||||||
private void startLoading() {
|
private void startLoading() {
|
||||||
ExtractingLoadable loadable = new ExtractingLoadable(uri, dataSource, extractorHolder,
|
ExtractingLoadable loadable = new ExtractingLoadable(uri, dataSource, extractorHolder,
|
||||||
allocator, C.DEFAULT_MUXED_BUFFER_SIZE);
|
loadCondition);
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
Assertions.checkState(isPendingReset());
|
Assertions.checkState(isPendingReset());
|
||||||
if (durationUs != C.UNSET_TIME_US && pendingResetPositionUs >= durationUs) {
|
if (durationUs != C.UNSET_TIME_US && pendingResetPositionUs >= durationUs) {
|
||||||
@ -657,8 +681,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
private final Uri uri;
|
private final Uri uri;
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final ExtractorHolder extractorHolder;
|
private final ExtractorHolder extractorHolder;
|
||||||
private final Allocator allocator;
|
private final ConditionVariable loadCondition;
|
||||||
private final int requestedBufferSize;
|
|
||||||
private final PositionHolder positionHolder;
|
private final PositionHolder positionHolder;
|
||||||
|
|
||||||
private volatile boolean loadCanceled;
|
private volatile boolean loadCanceled;
|
||||||
@ -667,12 +690,11 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
private long length;
|
private long length;
|
||||||
|
|
||||||
public ExtractingLoadable(Uri uri, DataSource dataSource, ExtractorHolder extractorHolder,
|
public ExtractingLoadable(Uri uri, DataSource dataSource, ExtractorHolder extractorHolder,
|
||||||
Allocator allocator, int requestedBufferSize) {
|
ConditionVariable loadCondition) {
|
||||||
this.uri = Assertions.checkNotNull(uri);
|
this.uri = Assertions.checkNotNull(uri);
|
||||||
this.dataSource = Assertions.checkNotNull(dataSource);
|
this.dataSource = Assertions.checkNotNull(dataSource);
|
||||||
this.extractorHolder = Assertions.checkNotNull(extractorHolder);
|
this.extractorHolder = Assertions.checkNotNull(extractorHolder);
|
||||||
this.allocator = Assertions.checkNotNull(allocator);
|
this.loadCondition = loadCondition;
|
||||||
this.requestedBufferSize = requestedBufferSize;
|
|
||||||
this.positionHolder = new PositionHolder();
|
this.positionHolder = new PositionHolder();
|
||||||
this.pendingExtractorSeek = true;
|
this.pendingExtractorSeek = true;
|
||||||
this.length = C.LENGTH_UNBOUNDED;
|
this.length = C.LENGTH_UNBOUNDED;
|
||||||
@ -711,11 +733,10 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
pendingExtractorSeek = false;
|
pendingExtractorSeek = false;
|
||||||
}
|
}
|
||||||
while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
|
while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
|
||||||
allocator.blockWhileTotalBytesAllocatedExceeds(requestedBufferSize);
|
// TODO: Prevent the loader from loading too much data between evaluations of the
|
||||||
|
// buffering condition.
|
||||||
|
loadCondition.block();
|
||||||
result = extractor.read(input, positionHolder);
|
result = extractor.read(input, positionHolder);
|
||||||
// TODO: Implement throttling to stop us from buffering data too often.
|
|
||||||
// TODO: Block buffering between the point at which we have sufficient data for
|
|
||||||
// preparation to complete and the first call to endTrackSelection.
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (result == Extractor.RESULT_SEEK) {
|
if (result == Extractor.RESULT_SEEK) {
|
||||||
|
@ -39,19 +39,10 @@ public interface Allocator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hints to the {@link Allocator} that it should make a best effort to release any memory that it
|
* Hints to the {@link Allocator} that it should make a best effort to release any memory that it
|
||||||
* has allocated that it no longer requires.
|
* has allocated beyond the target buffer size.
|
||||||
*/
|
*/
|
||||||
void trim();
|
void trim();
|
||||||
|
|
||||||
/**
|
|
||||||
* Blocks execution until the number of bytes allocated is not greater than the limit, or the
|
|
||||||
* thread is interrupted.
|
|
||||||
*
|
|
||||||
* @param limit The limit in bytes.
|
|
||||||
* @throws InterruptedException If the thread is interrupted.
|
|
||||||
*/
|
|
||||||
void blockWhileTotalBytesAllocatedExceeds(int limit) throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total number of bytes currently allocated.
|
* Returns the total number of bytes currently allocated.
|
||||||
*/
|
*/
|
||||||
|
@ -47,7 +47,7 @@ public final class DefaultAllocator implements Allocator {
|
|||||||
/**
|
/**
|
||||||
* Constructs a pool with some {@link Allocation}s created up front.
|
* Constructs a pool with some {@link Allocation}s created up front.
|
||||||
* <p>
|
* <p>
|
||||||
* Note: Initial {@link Allocation}s will never be discarded by {@link #trim(int)}.
|
* Note: Initial {@link Allocation}s will never be discarded by {@link #trim()}.
|
||||||
*
|
*
|
||||||
* @param individualAllocationSize The length of each individual allocation.
|
* @param individualAllocationSize The length of each individual allocation.
|
||||||
* @param initialAllocationCount The number of allocations to create up front.
|
* @param initialAllocationCount The number of allocations to create up front.
|
||||||
@ -70,7 +70,11 @@ public final class DefaultAllocator implements Allocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void setTargetBufferSize(int targetBufferSize) {
|
public synchronized void setTargetBufferSize(int targetBufferSize) {
|
||||||
|
boolean targetBufferSizeReduced = targetBufferSize < this.targetBufferSize;
|
||||||
this.targetBufferSize = targetBufferSize;
|
this.targetBufferSize = targetBufferSize;
|
||||||
|
if (targetBufferSizeReduced) {
|
||||||
|
trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -147,14 +151,6 @@ public final class DefaultAllocator implements Allocator {
|
|||||||
return allocatedCount * individualAllocationSize;
|
return allocatedCount * individualAllocationSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void blockWhileTotalBytesAllocatedExceeds(int limit)
|
|
||||||
throws InterruptedException {
|
|
||||||
while (getTotalBytesAllocated() > limit) {
|
|
||||||
wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIndividualAllocationLength() {
|
public int getIndividualAllocationLength() {
|
||||||
return individualAllocationSize;
|
return individualAllocationSize;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user