mediaplayer: add buffering settings API
Test: compiles, ensured that params is passed all the way to source
Bug:32524218
Change-Id: I90d65e10012ecc1a78989eba80d025d513ceaadf
diff --git a/api/current.txt b/api/current.txt
index bca65ee..6faf179 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20711,6 +20711,40 @@
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public final class BufferingParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getInitialBufferingMode();
+ method public int getInitialBufferingWatermarkKB();
+ method public int getInitialBufferingWatermarkMs();
+ method public int getRebufferingMode();
+ method public int getRebufferingWatermarkHighKB();
+ method public int getRebufferingWatermarkHighMs();
+ method public int getRebufferingWatermarkLowKB();
+ method public int getRebufferingWatermarkLowMs();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+ field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+ field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+ field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+ }
+
+ public static class BufferingParams.Builder {
+ ctor public BufferingParams.Builder();
+ ctor public BufferingParams.Builder(android.media.BufferingParams);
+ method public android.media.BufferingParams build();
+ method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingMode(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -21883,7 +21917,9 @@
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
+ method public android.media.BufferingParams getBufferingParams();
method public int getCurrentPosition();
+ method public android.media.BufferingParams getDefaultBufferingParams();
method public int getDuration();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -21906,6 +21942,7 @@
method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public deprecated void setAudioStreamType(int);
method public void setAuxEffectSendLevel(float);
+ method public void setBufferingParams(android.media.BufferingParams);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
diff --git a/api/system-current.txt b/api/system-current.txt
index cf4db76..34c22d1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -22296,6 +22296,40 @@
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public final class BufferingParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getInitialBufferingMode();
+ method public int getInitialBufferingWatermarkKB();
+ method public int getInitialBufferingWatermarkMs();
+ method public int getRebufferingMode();
+ method public int getRebufferingWatermarkHighKB();
+ method public int getRebufferingWatermarkHighMs();
+ method public int getRebufferingWatermarkLowKB();
+ method public int getRebufferingWatermarkLowMs();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+ field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+ field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+ field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+ }
+
+ public static class BufferingParams.Builder {
+ ctor public BufferingParams.Builder();
+ ctor public BufferingParams.Builder(android.media.BufferingParams);
+ method public android.media.BufferingParams build();
+ method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingMode(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -23468,7 +23502,9 @@
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
+ method public android.media.BufferingParams getBufferingParams();
method public int getCurrentPosition();
+ method public android.media.BufferingParams getDefaultBufferingParams();
method public int getDuration();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -23491,6 +23527,7 @@
method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public deprecated void setAudioStreamType(int);
method public void setAuxEffectSendLevel(float);
+ method public void setBufferingParams(android.media.BufferingParams);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
diff --git a/api/test-current.txt b/api/test-current.txt
index d18af4c..db3b244 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -20801,6 +20801,40 @@
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public final class BufferingParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getInitialBufferingMode();
+ method public int getInitialBufferingWatermarkKB();
+ method public int getInitialBufferingWatermarkMs();
+ method public int getRebufferingMode();
+ method public int getRebufferingWatermarkHighKB();
+ method public int getRebufferingWatermarkHighMs();
+ method public int getRebufferingWatermarkLowKB();
+ method public int getRebufferingWatermarkLowMs();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+ field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+ field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+ field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+ }
+
+ public static class BufferingParams.Builder {
+ ctor public BufferingParams.Builder();
+ ctor public BufferingParams.Builder(android.media.BufferingParams);
+ method public android.media.BufferingParams build();
+ method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingMode(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -21973,7 +22007,9 @@
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
+ method public android.media.BufferingParams getBufferingParams();
method public int getCurrentPosition();
+ method public android.media.BufferingParams getDefaultBufferingParams();
method public int getDuration();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -21996,6 +22032,7 @@
method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public deprecated void setAudioStreamType(int);
method public void setAuxEffectSendLevel(float);
+ method public void setBufferingParams(android.media.BufferingParams);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
diff --git a/media/java/android/media/BufferingParams.aidl b/media/java/android/media/BufferingParams.aidl
new file mode 100644
index 0000000..d156d44
--- /dev/null
+++ b/media/java/android/media/BufferingParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable BufferingParams;
diff --git a/media/java/android/media/BufferingParams.java b/media/java/android/media/BufferingParams.java
new file mode 100644
index 0000000..fdcd6ba
--- /dev/null
+++ b/media/java/android/media/BufferingParams.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Structure for source buffering management params.
+ *
+ * Used by {@link MediaPlayer#getDefaultBufferingParams()},
+ * {@link MediaPlayer#getBufferingParams()} and
+ * {@link MediaPlayer#setBufferingParams(BufferingParams)}
+ * to control source buffering behavior.
+ *
+ * <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering
+ * (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer}
+ * is playing back source). {@link BufferingParams} includes mode and corresponding
+ * watermarks for each stage of source buffering. The watermarks could be either size
+ * based (in milliseconds), or time based (in kilobytes) or both, depending on the mode.
+ *
+ * <p>There are 4 buffering modes: {@link #BUFFERING_MODE_NONE},
+ * {@link #BUFFERING_MODE_TIME_ONLY}, {@link #BUFFERING_MODE_SIZE_ONLY} and
+ * {@link #BUFFERING_MODE_TIME_THEN_SIZE}.
+ * {@link MediaPlayer} source component has default buffering modes which can be queried
+ * by calling {@link MediaPlayer#getDefaultBufferingParams()}.
+ * Users should always use those default modes or their downsized version when trying to
+ * change buffering params. For example, {@link #BUFFERING_MODE_TIME_THEN_SIZE} can be
+ * downsized to {@link #BUFFERING_MODE_NONE}, {@link #BUFFERING_MODE_TIME_ONLY} or
+ * {@link #BUFFERING_MODE_SIZE_ONLY}. But {@link #BUFFERING_MODE_TIME_ONLY} can not be
+ * downsized to {@link #BUFFERING_MODE_SIZE_ONLY}.
+ * <ul>
+ * <li><strong>initial buffering stage:</strong> has one watermark which is used when
+ * {@link MediaPlayer} is being prepared. When cached data amount exceeds this watermark,
+ * {@link MediaPlayer} is prepared.</li>
+ * <li><strong>rebuffering stage:</strong> has two watermarks, low and high, which are
+ * used when {@link MediaPlayer} is playing back content.
+ * <ul>
+ * <li> When cached data amount exceeds high watermark, {@link MediaPlayer} will pause
+ * buffering. Buffering will resume when cache runs below some limit which could be low
+ * watermark or some intermediate value decided by the source component.</li>
+ * <li> When cached data amount runs below low watermark, {@link MediaPlayer} will paused
+ * playback. Playback will resume when cached data amount exceeds high watermark
+ * or reaches end of stream.</li>
+ * </ul>
+ * </ul>
+ * <p>Users should use {@link Builder} to change {@link BufferingParams}.
+ */
+public final class BufferingParams implements Parcelable {
+ /**
+ * This mode indicates that source buffering is not supported.
+ */
+ public static final int BUFFERING_MODE_NONE = 0;
+ /**
+ * This mode indicates that only time based source buffering is supported. This means
+ * the watermark(s) are time based.
+ */
+ public static final int BUFFERING_MODE_TIME_ONLY = 1;
+ /**
+ * This mode indicates that only size based source buffering is supported. This means
+ * the watermark(s) are size based.
+ */
+ public static final int BUFFERING_MODE_SIZE_ONLY = 2;
+ /**
+ * This mode indicates that both time and size based source buffering are supported,
+ * and time based calculation precedes size based. Size based calculation will be used
+ * only when time information is not available from the source.
+ */
+ public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3;
+
+ /** @hide */
+ @IntDef(
+ value = {
+ BUFFERING_MODE_NONE,
+ BUFFERING_MODE_TIME_ONLY,
+ BUFFERING_MODE_SIZE_ONLY,
+ BUFFERING_MODE_TIME_THEN_SIZE,
+ }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BufferingMode {}
+
+ private static final int BUFFERING_NO_WATERMARK = -1;
+
+ // params
+ private int mInitialBufferingMode = BUFFERING_MODE_NONE;
+ private int mRebufferingMode = BUFFERING_MODE_NONE;
+
+ private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
+ private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+
+ private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+
+ private BufferingParams() {
+ }
+
+ /**
+ * Return the initial buffering mode used when {@link MediaPlayer} is being prepared.
+ * @return one of the values that can be set in {@link Builder#setInitialBufferingMode(int)}
+ */
+ public int getInitialBufferingMode() {
+ return mInitialBufferingMode;
+ }
+
+ /**
+ * Return the rebuffering mode used when {@link MediaPlayer} is playing back source.
+ * @return one of the values that can be set in {@link Builder#setRebufferingMode(int)}
+ */
+ public int getRebufferingMode() {
+ return mRebufferingMode;
+ }
+
+ /**
+ * Return the time based initial buffering watermark in milliseconds.
+ * It is meaningful only when initial buffering mode obatined from
+ * {@link #getInitialBufferingMode()} is time based.
+ * @return time based initial buffering watermark in milliseconds
+ */
+ public int getInitialBufferingWatermarkMs() {
+ return mInitialWatermarkMs;
+ }
+
+ /**
+ * Return the size based initial buffering watermark in kilobytes.
+ * It is meaningful only when initial buffering mode obatined from
+ * {@link #getInitialBufferingMode()} is size based.
+ * @return size based initial buffering watermark in kilobytes
+ */
+ public int getInitialBufferingWatermarkKB() {
+ return mInitialWatermarkKB;
+ }
+
+ /**
+ * Return the time based low watermark in milliseconds for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is time based.
+ * @return time based low watermark for rebuffering in milliseconds
+ */
+ public int getRebufferingWatermarkLowMs() {
+ return mRebufferingWatermarkLowMs;
+ }
+
+ /**
+ * Return the time based high watermark in milliseconds for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is time based.
+ * @return time based high watermark for rebuffering in milliseconds
+ */
+ public int getRebufferingWatermarkHighMs() {
+ return mRebufferingWatermarkHighMs;
+ }
+
+ /**
+ * Return the size based low watermark in kilobytes for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is size based.
+ * @return size based low watermark for rebuffering in kilobytes
+ */
+ public int getRebufferingWatermarkLowKB() {
+ return mRebufferingWatermarkLowKB;
+ }
+
+ /**
+ * Return the size based high watermark in kilobytes for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is size based.
+ * @return size based high watermark for rebuffering in kilobytes
+ */
+ public int getRebufferingWatermarkHighKB() {
+ return mRebufferingWatermarkHighKB;
+ }
+
+ /**
+ * Builder class for {@link BufferingParams} objects.
+ * <p> Here is an example where <code>Builder</code> is used to define the
+ * {@link BufferingParams} to be used by a {@link MediaPlayer} instance:
+ *
+ * <pre class="prettyprint">
+ * BufferingParams myParams = mediaplayer.getDefaultBufferingParams();
+ * myParams = new BufferingParams.Builder(myParams)
+ * .setInitialBufferingWatermarkMs(10000)
+ * .build();
+ * mediaplayer.setBufferingParams(myParams);
+ * </pre>
+ */
+ public static class Builder {
+ private int mInitialBufferingMode = BUFFERING_MODE_NONE;
+ private int mRebufferingMode = BUFFERING_MODE_NONE;
+
+ private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
+ private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+
+ private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+
+ /**
+ * Constructs a new Builder with the defaults.
+ * By default, both initial buffering mode and rebuffering mode are
+ * {@link BufferingParams#BUFFERING_MODE_NONE}, and all watermarks are -1.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link BufferingParams} instance
+ * @param bp the {@link BufferingParams} object whose data will be reused
+ * in the new Builder.
+ */
+ public Builder(BufferingParams bp) {
+ mInitialBufferingMode = bp.mInitialBufferingMode;
+ mRebufferingMode = bp.mRebufferingMode;
+
+ mInitialWatermarkMs = bp.mInitialWatermarkMs;
+ mInitialWatermarkKB = bp.mInitialWatermarkKB;
+
+ mRebufferingWatermarkLowMs = bp.mRebufferingWatermarkLowMs;
+ mRebufferingWatermarkHighMs = bp.mRebufferingWatermarkHighMs;
+ mRebufferingWatermarkLowKB = bp.mRebufferingWatermarkLowKB;
+ mRebufferingWatermarkHighKB = bp.mRebufferingWatermarkHighKB;
+ }
+
+ /**
+ * Combines all of the fields that have been set and return a new
+ * {@link BufferingParams} object. <code>IllegalStateException</code> will be
+ * thrown if there is conflict between fields.
+ * @return a new {@link BufferingParams} object
+ */
+ public BufferingParams build() {
+ if (isTimeBasedMode(mRebufferingMode)
+ && mRebufferingWatermarkLowMs > mRebufferingWatermarkHighMs) {
+ throw new IllegalStateException("Illegal watermark:"
+ + mRebufferingWatermarkLowMs + " : " + mRebufferingWatermarkHighMs);
+ }
+ if (isSizeBasedMode(mRebufferingMode)
+ && mRebufferingWatermarkLowKB > mRebufferingWatermarkHighKB) {
+ throw new IllegalStateException("Illegal watermark:"
+ + mRebufferingWatermarkLowKB + " : " + mRebufferingWatermarkHighKB);
+ }
+
+ BufferingParams bp = new BufferingParams();
+ bp.mInitialBufferingMode = mInitialBufferingMode;
+ bp.mRebufferingMode = mRebufferingMode;
+
+ bp.mInitialWatermarkMs = mInitialWatermarkMs;
+ bp.mInitialWatermarkKB = mInitialWatermarkKB;
+
+ bp.mRebufferingWatermarkLowMs = mRebufferingWatermarkLowMs;
+ bp.mRebufferingWatermarkHighMs = mRebufferingWatermarkHighMs;
+ bp.mRebufferingWatermarkLowKB = mRebufferingWatermarkLowKB;
+ bp.mRebufferingWatermarkHighKB = mRebufferingWatermarkHighKB;
+ return bp;
+ }
+
+ private boolean isTimeBasedMode(int mode) {
+ return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+ }
+
+ private boolean isSizeBasedMode(int mode) {
+ return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+ }
+
+ /**
+ * Sets the initial buffering mode.
+ * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+ * @return the same Builder instance.
+ */
+ public Builder setInitialBufferingMode(@BufferingMode int mode) {
+ switch (mode) {
+ case BUFFERING_MODE_NONE:
+ case BUFFERING_MODE_TIME_ONLY:
+ case BUFFERING_MODE_SIZE_ONLY:
+ case BUFFERING_MODE_TIME_THEN_SIZE:
+ mInitialBufferingMode = mode;
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal buffering mode " + mode);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the rebuffering mode.
+ * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingMode(@BufferingMode int mode) {
+ switch (mode) {
+ case BUFFERING_MODE_NONE:
+ case BUFFERING_MODE_TIME_ONLY:
+ case BUFFERING_MODE_SIZE_ONLY:
+ case BUFFERING_MODE_TIME_THEN_SIZE:
+ mRebufferingMode = mode;
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal buffering mode " + mode);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the time based watermark in milliseconds for initial buffering.
+ * @param watermarkMs time based watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setInitialBufferingWatermarkMs(int watermarkMs) {
+ mInitialWatermarkMs = watermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the size based watermark in kilobytes for initial buffering.
+ * @param watermarkKB size based watermark in kilobytes
+ * @return the same Builder instance.
+ */
+ public Builder setInitialBufferingWatermarkKB(int watermarkKB) {
+ mInitialWatermarkKB = watermarkKB;
+ return this;
+ }
+
+ /**
+ * Sets the time based low watermark in milliseconds for rebuffering.
+ * @param watermarkMs time based low watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkLowMs(int watermarkMs) {
+ mRebufferingWatermarkLowMs = watermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the time based high watermark in milliseconds for rebuffering.
+ * @param watermarkMs time based high watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkHighMs(int watermarkMs) {
+ mRebufferingWatermarkHighMs = watermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the size based low watermark in milliseconds for rebuffering.
+ * @param watermarkKB size based low watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkLowKB(int watermarkKB) {
+ mRebufferingWatermarkLowKB = watermarkKB;
+ return this;
+ }
+
+ /**
+ * Sets the size based high watermark in milliseconds for rebuffering.
+ * @param watermarkKB size based high watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkHighKB(int watermarkKB) {
+ mRebufferingWatermarkHighKB = watermarkKB;
+ return this;
+ }
+
+ /**
+ * Sets the time based low and high watermarks in milliseconds for rebuffering.
+ * @param lowWatermarkMs time based low watermark in milliseconds
+ * @param highWatermarkMs time based high watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarksMs(int lowWatermarkMs, int highWatermarkMs) {
+ mRebufferingWatermarkLowMs = lowWatermarkMs;
+ mRebufferingWatermarkHighMs = highWatermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the size based low and high watermarks in kilobytes for rebuffering.
+ * @param lowWatermarkKB size based low watermark in kilobytes
+ * @param highWatermarkKB size based high watermark in kilobytes
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarksKB(int lowWatermarkKB, int highWatermarkKB) {
+ mRebufferingWatermarkLowKB = lowWatermarkKB;
+ mRebufferingWatermarkHighKB = highWatermarkKB;
+ return this;
+ }
+ }
+
+ private BufferingParams(Parcel in) {
+ mInitialBufferingMode = in.readInt();
+ mRebufferingMode = in.readInt();
+
+ mInitialWatermarkMs = in.readInt();
+ mInitialWatermarkKB = in.readInt();
+
+ mRebufferingWatermarkLowMs = in.readInt();
+ mRebufferingWatermarkHighMs = in.readInt();
+ mRebufferingWatermarkLowKB = in.readInt();
+ mRebufferingWatermarkHighKB = in.readInt();
+ }
+
+ public static final Parcelable.Creator<BufferingParams> CREATOR =
+ new Parcelable.Creator<BufferingParams>() {
+ @Override
+ public BufferingParams createFromParcel(Parcel in) {
+ return new BufferingParams(in);
+ }
+
+ @Override
+ public BufferingParams[] newArray(int size) {
+ return new BufferingParams[size];
+ }
+ };
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mInitialBufferingMode);
+ dest.writeInt(mRebufferingMode);
+
+ dest.writeInt(mInitialWatermarkMs);
+ dest.writeInt(mInitialWatermarkKB);
+
+ dest.writeInt(mRebufferingWatermarkLowMs);
+ dest.writeInt(mRebufferingWatermarkHighMs);
+ dest.writeInt(mRebufferingWatermarkLowKB);
+ dest.writeInt(mRebufferingWatermarkHighKB);
+ }
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e3a0f25..4023400 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -45,6 +45,7 @@
import android.widget.VideoView;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
+import android.media.BufferingParams;
import android.media.MediaFormat;
import android.media.MediaTimeProvider;
import android.media.PlaybackParams;
@@ -479,6 +480,11 @@
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
+ * <tr><td>setBufferingParams</p></td>
+ * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error}</p></td>
+ * <td>{Idle} </p></td>
+ * <td>This method does not change the object state.
+ * </p></td></tr>
* <tr><td>setPlaybackParams</p></td>
* <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
* <td>{Idle, Stopped} </p></td>
@@ -1390,6 +1396,45 @@
public native boolean isPlaying();
/**
+ * Gets the default buffering management params.
+ * Calling it only after {@code setDataSource} has been called.
+ * Each type of data source might have different set of default params.
+ *
+ * @return the default buffering management params supported by the source component.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized, or {@code setDataSource} has not been called.
+ */
+ @NonNull
+ public native BufferingParams getDefaultBufferingParams();
+
+ /**
+ * Gets the current buffering management params used by the source component.
+ * Calling it only after {@code setDataSource} has been called.
+ *
+ * @return the current buffering management params used by the source component.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized, or {@code setDataSource} has not been called.
+ */
+ @NonNull
+ public native BufferingParams getBufferingParams();
+
+ /**
+ * Sets buffering management params.
+ * The object sets its internal BufferingParams to the input, except that the input is
+ * invalid or not supported.
+ * Call it only after {@code setDataSource} has been called.
+ * Users should only use supported mode returned by {@link #getDefaultBufferingParams()}
+ * or its downsized version as described in {@link BufferingParams}.
+ *
+ * @param params the buffering management params.
+ *
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized or has been released, or {@code setDataSource} has not been called.
+ * @throws IllegalArgumentException if params is invalid or not supported.
+ */
+ public native void setBufferingParams(@NonNull BufferingParams params);
+
+ /**
* Change playback speed of audio by resampling the audio.
* <p>
* Specifies resampling as audio mode for variable rate playback, i.e.,
diff --git a/media/jni/android_media_BufferingParams.h b/media/jni/android_media_BufferingParams.h
new file mode 100644
index 0000000..24c51f5
--- /dev/null
+++ b/media/jni/android_media_BufferingParams.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_BUFFERING_PARAMS_H_
+#define _ANDROID_MEDIA_BUFFERING_PARAMS_H_
+
+#include <media/BufferingSettings.h>
+
+namespace android {
+
+// This entire class is inline
+struct BufferingParams {
+ BufferingSettings settings;
+
+ struct fields_t {
+ jclass clazz;
+ jmethodID constructID;
+
+ jfieldID initial_buffering_mode;
+ jfieldID rebuffering_mode;
+ jfieldID initial_watermark_ms;
+ jfieldID initial_watermark_kb;
+ jfieldID rebuffering_watermark_low_ms;
+ jfieldID rebuffering_watermark_high_ms;
+ jfieldID rebuffering_watermark_low_kb;
+ jfieldID rebuffering_watermark_high_kb;
+
+ void init(JNIEnv *env) {
+ jclass lclazz = env->FindClass("android/media/BufferingParams");
+ if (lclazz == NULL) {
+ return;
+ }
+
+ clazz = (jclass)env->NewGlobalRef(lclazz);
+ if (clazz == NULL) {
+ return;
+ }
+
+ constructID = env->GetMethodID(clazz, "<init>", "()V");
+
+ initial_buffering_mode = env->GetFieldID(clazz, "mInitialBufferingMode", "I");
+ rebuffering_mode = env->GetFieldID(clazz, "mRebufferingMode", "I");
+ initial_watermark_ms = env->GetFieldID(clazz, "mInitialWatermarkMs", "I");
+ initial_watermark_kb = env->GetFieldID(clazz, "mInitialWatermarkKB", "I");
+ rebuffering_watermark_low_ms = env->GetFieldID(clazz, "mRebufferingWatermarkLowMs", "I");
+ rebuffering_watermark_high_ms = env->GetFieldID(clazz, "mRebufferingWatermarkHighMs", "I");
+ rebuffering_watermark_low_kb = env->GetFieldID(clazz, "mRebufferingWatermarkLowKB", "I");
+ rebuffering_watermark_high_kb = env->GetFieldID(clazz, "mRebufferingWatermarkHighKB", "I");
+
+ env->DeleteLocalRef(lclazz);
+ }
+
+ void exit(JNIEnv *env) {
+ env->DeleteGlobalRef(clazz);
+ clazz = NULL;
+ }
+ };
+
+ void fillFromJobject(JNIEnv *env, const fields_t& fields, jobject params) {
+ settings.mInitialBufferingMode =
+ (BufferingMode)env->GetIntField(params, fields.initial_buffering_mode);
+ settings.mRebufferingMode =
+ (BufferingMode)env->GetIntField(params, fields.rebuffering_mode);
+ settings.mInitialWatermarkMs =
+ env->GetIntField(params, fields.initial_watermark_ms);
+ settings.mInitialWatermarkKB =
+ env->GetIntField(params, fields.initial_watermark_kb);
+ settings.mRebufferingWatermarkLowMs =
+ env->GetIntField(params, fields.rebuffering_watermark_low_ms);
+ settings.mRebufferingWatermarkHighMs =
+ env->GetIntField(params, fields.rebuffering_watermark_high_ms);
+ settings.mRebufferingWatermarkLowKB =
+ env->GetIntField(params, fields.rebuffering_watermark_low_kb);
+ settings.mRebufferingWatermarkHighKB =
+ env->GetIntField(params, fields.rebuffering_watermark_high_kb);
+ }
+
+ jobject asJobject(JNIEnv *env, const fields_t& fields) {
+ jobject params = env->NewObject(fields.clazz, fields.constructID);
+ if (params == NULL) {
+ return NULL;
+ }
+ env->SetIntField(params, fields.initial_buffering_mode, (jint)settings.mInitialBufferingMode);
+ env->SetIntField(params, fields.rebuffering_mode, (jint)settings.mRebufferingMode);
+ env->SetIntField(params, fields.initial_watermark_ms, (jint)settings.mInitialWatermarkMs);
+ env->SetIntField(params, fields.initial_watermark_kb, (jint)settings.mInitialWatermarkKB);
+ env->SetIntField(params, fields.rebuffering_watermark_low_ms, (jint)settings.mRebufferingWatermarkLowMs);
+ env->SetIntField(params, fields.rebuffering_watermark_high_ms, (jint)settings.mRebufferingWatermarkHighMs);
+ env->SetIntField(params, fields.rebuffering_watermark_low_kb, (jint)settings.mRebufferingWatermarkLowKB);
+ env->SetIntField(params, fields.rebuffering_watermark_high_kb, (jint)settings.mRebufferingWatermarkHighKB);
+
+ return params;
+ }
+};
+
+} // namespace android
+
+#endif // _ANDROID_MEDIA_BUFFERING_PARAMS_H_
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c52ed94..8225052 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -37,6 +37,7 @@
#include "utils/Errors.h" // for status_t
#include "utils/KeyedVector.h"
#include "utils/String8.h"
+#include "android_media_BufferingParams.h"
#include "android_media_MediaDataSource.h"
#include "android_media_PlaybackParams.h"
#include "android_media_SyncParams.h"
@@ -69,6 +70,7 @@
};
static fields_t fields;
+static BufferingParams::fields_t gBufferingParamsFields;
static PlaybackParams::fields_t gPlaybackParamsFields;
static SyncParams::fields_t gSyncParamsFields;
@@ -343,6 +345,66 @@
setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
}
+static jobject
+android_media_MediaPlayer_getDefaultBufferingParams(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ BufferingParams bp;
+ BufferingSettings &settings = bp.settings;
+ process_media_player_call(
+ env, thiz, mp->getDefaultBufferingSettings(&settings),
+ "java/lang/IllegalStateException", "unexpected error");
+ ALOGV("getDefaultBufferingSettings:{%s}", settings.toString().string());
+
+ return bp.asJobject(env, gBufferingParamsFields);
+}
+
+static jobject
+android_media_MediaPlayer_getBufferingParams(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ BufferingParams bp;
+ BufferingSettings &settings = bp.settings;
+ process_media_player_call(
+ env, thiz, mp->getBufferingSettings(&settings),
+ "java/lang/IllegalStateException", "unexpected error");
+ ALOGV("getBufferingSettings:{%s}", settings.toString().string());
+
+ return bp.asJobject(env, gBufferingParamsFields);
+}
+
+static void
+android_media_MediaPlayer_setBufferingParams(JNIEnv *env, jobject thiz, jobject params)
+{
+ if (params == NULL) {
+ return;
+ }
+
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ BufferingParams bp;
+ bp.fillFromJobject(env, gBufferingParamsFields, params);
+ ALOGV("setBufferingParams:{%s}", bp.settings.toString().string());
+
+ process_media_player_call(
+ env, thiz, mp->setBufferingSettings(bp.settings),
+ "java/lang/IllegalStateException", "unexpected error");
+}
+
static void
android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
{
@@ -860,6 +922,7 @@
env->DeleteLocalRef(clazz);
+ gBufferingParamsFields.init(env);
gPlaybackParamsFields.init(env);
gSyncParamsFields.init(env);
}
@@ -1046,6 +1109,9 @@
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
+ {"getDefaultBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getDefaultBufferingParams},
+ {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getBufferingParams},
+ {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer_setBufferingParams},
{"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer_start},