1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media; 18 19 import android.annotation.IntDef; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import java.lang.annotation.Retention; 24 import java.lang.annotation.RetentionPolicy; 25 26 /** 27 * Structure for source buffering management params. 28 * 29 * Used by {@link MediaPlayer#getDefaultBufferingParams()}, 30 * {@link MediaPlayer#getBufferingParams()} and 31 * {@link MediaPlayer#setBufferingParams(BufferingParams)} 32 * to control source buffering behavior. 33 * 34 * <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering 35 * (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer} 36 * is playing back source). {@link BufferingParams} includes mode and corresponding 37 * watermarks for each stage of source buffering. The watermarks could be either size 38 * based (in milliseconds), or time based (in kilobytes) or both, depending on the mode. 39 * 40 * <p>There are 4 buffering modes: {@link #BUFFERING_MODE_NONE}, 41 * {@link #BUFFERING_MODE_TIME_ONLY}, {@link #BUFFERING_MODE_SIZE_ONLY} and 42 * {@link #BUFFERING_MODE_TIME_THEN_SIZE}. 43 * {@link MediaPlayer} source component has default buffering modes which can be queried 44 * by calling {@link MediaPlayer#getDefaultBufferingParams()}. 45 * Users should always use those default modes or their downsized version when trying to 46 * change buffering params. For example, {@link #BUFFERING_MODE_TIME_THEN_SIZE} can be 47 * downsized to {@link #BUFFERING_MODE_NONE}, {@link #BUFFERING_MODE_TIME_ONLY} or 48 * {@link #BUFFERING_MODE_SIZE_ONLY}. But {@link #BUFFERING_MODE_TIME_ONLY} can not be 49 * downsized to {@link #BUFFERING_MODE_SIZE_ONLY}. 50 * <ul> 51 * <li><strong>initial buffering stage:</strong> has one watermark which is used when 52 * {@link MediaPlayer} is being prepared. When cached data amount exceeds this watermark, 53 * {@link MediaPlayer} is prepared.</li> 54 * <li><strong>rebuffering stage:</strong> has two watermarks, low and high, which are 55 * used when {@link MediaPlayer} is playing back content. 56 * <ul> 57 * <li> When cached data amount exceeds high watermark, {@link MediaPlayer} will pause 58 * buffering. Buffering will resume when cache runs below some limit which could be low 59 * watermark or some intermediate value decided by the source component.</li> 60 * <li> When cached data amount runs below low watermark, {@link MediaPlayer} will paused 61 * playback. Playback will resume when cached data amount exceeds high watermark 62 * or reaches end of stream.</li> 63 * </ul> 64 * </ul> 65 * <p>Users should use {@link Builder} to change {@link BufferingParams}. 66 * @hide 67 */ 68 public final class BufferingParams implements Parcelable { 69 /** 70 * This mode indicates that source buffering is not supported. 71 */ 72 public static final int BUFFERING_MODE_NONE = 0; 73 /** 74 * This mode indicates that only time based source buffering is supported. This means 75 * the watermark(s) are time based. 76 */ 77 public static final int BUFFERING_MODE_TIME_ONLY = 1; 78 /** 79 * This mode indicates that only size based source buffering is supported. This means 80 * the watermark(s) are size based. 81 */ 82 public static final int BUFFERING_MODE_SIZE_ONLY = 2; 83 /** 84 * This mode indicates that both time and size based source buffering are supported, 85 * and time based calculation precedes size based. Size based calculation will be used 86 * only when time information is not available from the source. 87 */ 88 public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; 89 90 /** @hide */ 91 @IntDef( 92 value = { 93 BUFFERING_MODE_NONE, 94 BUFFERING_MODE_TIME_ONLY, 95 BUFFERING_MODE_SIZE_ONLY, 96 BUFFERING_MODE_TIME_THEN_SIZE, 97 } 98 ) 99 @Retention(RetentionPolicy.SOURCE) 100 public @interface BufferingMode {} 101 102 private static final int BUFFERING_NO_WATERMARK = -1; 103 104 // params 105 private int mInitialBufferingMode = BUFFERING_MODE_NONE; 106 private int mRebufferingMode = BUFFERING_MODE_NONE; 107 108 private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK; 109 private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK; 110 111 private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK; 112 private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK; 113 private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK; 114 private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK; 115 116 private BufferingParams() { 117 } 118 119 /** 120 * Return the initial buffering mode used when {@link MediaPlayer} is being prepared. 121 * @return one of the values that can be set in {@link Builder#setInitialBufferingMode(int)} 122 */ 123 public int getInitialBufferingMode() { 124 return mInitialBufferingMode; 125 } 126 127 /** 128 * Return the rebuffering mode used when {@link MediaPlayer} is playing back source. 129 * @return one of the values that can be set in {@link Builder#setRebufferingMode(int)} 130 */ 131 public int getRebufferingMode() { 132 return mRebufferingMode; 133 } 134 135 /** 136 * Return the time based initial buffering watermark in milliseconds. 137 * It is meaningful only when initial buffering mode obatined from 138 * {@link #getInitialBufferingMode()} is time based. 139 * @return time based initial buffering watermark in milliseconds 140 */ 141 public int getInitialBufferingWatermarkMs() { 142 return mInitialWatermarkMs; 143 } 144 145 /** 146 * Return the size based initial buffering watermark in kilobytes. 147 * It is meaningful only when initial buffering mode obatined from 148 * {@link #getInitialBufferingMode()} is size based. 149 * @return size based initial buffering watermark in kilobytes 150 */ 151 public int getInitialBufferingWatermarkKB() { 152 return mInitialWatermarkKB; 153 } 154 155 /** 156 * Return the time based low watermark in milliseconds for rebuffering. 157 * It is meaningful only when rebuffering mode obatined from 158 * {@link #getRebufferingMode()} is time based. 159 * @return time based low watermark for rebuffering in milliseconds 160 */ 161 public int getRebufferingWatermarkLowMs() { 162 return mRebufferingWatermarkLowMs; 163 } 164 165 /** 166 * Return the time based high watermark in milliseconds for rebuffering. 167 * It is meaningful only when rebuffering mode obatined from 168 * {@link #getRebufferingMode()} is time based. 169 * @return time based high watermark for rebuffering in milliseconds 170 */ 171 public int getRebufferingWatermarkHighMs() { 172 return mRebufferingWatermarkHighMs; 173 } 174 175 /** 176 * Return the size based low watermark in kilobytes for rebuffering. 177 * It is meaningful only when rebuffering mode obatined from 178 * {@link #getRebufferingMode()} is size based. 179 * @return size based low watermark for rebuffering in kilobytes 180 */ 181 public int getRebufferingWatermarkLowKB() { 182 return mRebufferingWatermarkLowKB; 183 } 184 185 /** 186 * Return the size based high watermark in kilobytes for rebuffering. 187 * It is meaningful only when rebuffering mode obatined from 188 * {@link #getRebufferingMode()} is size based. 189 * @return size based high watermark for rebuffering in kilobytes 190 */ 191 public int getRebufferingWatermarkHighKB() { 192 return mRebufferingWatermarkHighKB; 193 } 194 195 /** 196 * Builder class for {@link BufferingParams} objects. 197 * <p> Here is an example where <code>Builder</code> is used to define the 198 * {@link BufferingParams} to be used by a {@link MediaPlayer} instance: 199 * 200 * <pre class="prettyprint"> 201 * BufferingParams myParams = mediaplayer.getDefaultBufferingParams(); 202 * myParams = new BufferingParams.Builder(myParams) 203 * .setInitialBufferingWatermarkMs(10000) 204 * .build(); 205 * mediaplayer.setBufferingParams(myParams); 206 * </pre> 207 */ 208 public static class Builder { 209 private int mInitialBufferingMode = BUFFERING_MODE_NONE; 210 private int mRebufferingMode = BUFFERING_MODE_NONE; 211 212 private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK; 213 private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK; 214 215 private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK; 216 private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK; 217 private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK; 218 private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK; 219 220 /** 221 * Constructs a new Builder with the defaults. 222 * By default, both initial buffering mode and rebuffering mode are 223 * {@link BufferingParams#BUFFERING_MODE_NONE}, and all watermarks are -1. 224 */ 225 public Builder() { 226 } 227 228 /** 229 * Constructs a new Builder from a given {@link BufferingParams} instance 230 * @param bp the {@link BufferingParams} object whose data will be reused 231 * in the new Builder. 232 */ 233 public Builder(BufferingParams bp) { 234 mInitialBufferingMode = bp.mInitialBufferingMode; 235 mRebufferingMode = bp.mRebufferingMode; 236 237 mInitialWatermarkMs = bp.mInitialWatermarkMs; 238 mInitialWatermarkKB = bp.mInitialWatermarkKB; 239 240 mRebufferingWatermarkLowMs = bp.mRebufferingWatermarkLowMs; 241 mRebufferingWatermarkHighMs = bp.mRebufferingWatermarkHighMs; 242 mRebufferingWatermarkLowKB = bp.mRebufferingWatermarkLowKB; 243 mRebufferingWatermarkHighKB = bp.mRebufferingWatermarkHighKB; 244 } 245 246 /** 247 * Combines all of the fields that have been set and return a new 248 * {@link BufferingParams} object. <code>IllegalStateException</code> will be 249 * thrown if there is conflict between fields. 250 * @return a new {@link BufferingParams} object 251 */ 252 public BufferingParams build() { 253 if (isTimeBasedMode(mRebufferingMode) 254 && mRebufferingWatermarkLowMs > mRebufferingWatermarkHighMs) { 255 throw new IllegalStateException("Illegal watermark:" 256 + mRebufferingWatermarkLowMs + " : " + mRebufferingWatermarkHighMs); 257 } 258 if (isSizeBasedMode(mRebufferingMode) 259 && mRebufferingWatermarkLowKB > mRebufferingWatermarkHighKB) { 260 throw new IllegalStateException("Illegal watermark:" 261 + mRebufferingWatermarkLowKB + " : " + mRebufferingWatermarkHighKB); 262 } 263 264 BufferingParams bp = new BufferingParams(); 265 bp.mInitialBufferingMode = mInitialBufferingMode; 266 bp.mRebufferingMode = mRebufferingMode; 267 268 bp.mInitialWatermarkMs = mInitialWatermarkMs; 269 bp.mInitialWatermarkKB = mInitialWatermarkKB; 270 271 bp.mRebufferingWatermarkLowMs = mRebufferingWatermarkLowMs; 272 bp.mRebufferingWatermarkHighMs = mRebufferingWatermarkHighMs; 273 bp.mRebufferingWatermarkLowKB = mRebufferingWatermarkLowKB; 274 bp.mRebufferingWatermarkHighKB = mRebufferingWatermarkHighKB; 275 return bp; 276 } 277 278 private boolean isTimeBasedMode(int mode) { 279 return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE); 280 } 281 282 private boolean isSizeBasedMode(int mode) { 283 return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE); 284 } 285 286 /** 287 * Sets the initial buffering mode. 288 * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE}, 289 * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY}, 290 * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY}, 291 * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE}, 292 * @return the same Builder instance. 293 */ 294 public Builder setInitialBufferingMode(@BufferingMode int mode) { 295 switch (mode) { 296 case BUFFERING_MODE_NONE: 297 case BUFFERING_MODE_TIME_ONLY: 298 case BUFFERING_MODE_SIZE_ONLY: 299 case BUFFERING_MODE_TIME_THEN_SIZE: 300 mInitialBufferingMode = mode; 301 break; 302 default: 303 throw new IllegalArgumentException("Illegal buffering mode " + mode); 304 } 305 return this; 306 } 307 308 /** 309 * Sets the rebuffering mode. 310 * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE}, 311 * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY}, 312 * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY}, 313 * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE}, 314 * @return the same Builder instance. 315 */ 316 public Builder setRebufferingMode(@BufferingMode int mode) { 317 switch (mode) { 318 case BUFFERING_MODE_NONE: 319 case BUFFERING_MODE_TIME_ONLY: 320 case BUFFERING_MODE_SIZE_ONLY: 321 case BUFFERING_MODE_TIME_THEN_SIZE: 322 mRebufferingMode = mode; 323 break; 324 default: 325 throw new IllegalArgumentException("Illegal buffering mode " + mode); 326 } 327 return this; 328 } 329 330 /** 331 * Sets the time based watermark in milliseconds for initial buffering. 332 * @param watermarkMs time based watermark in milliseconds 333 * @return the same Builder instance. 334 */ 335 public Builder setInitialBufferingWatermarkMs(int watermarkMs) { 336 mInitialWatermarkMs = watermarkMs; 337 return this; 338 } 339 340 /** 341 * Sets the size based watermark in kilobytes for initial buffering. 342 * @param watermarkKB size based watermark in kilobytes 343 * @return the same Builder instance. 344 */ 345 public Builder setInitialBufferingWatermarkKB(int watermarkKB) { 346 mInitialWatermarkKB = watermarkKB; 347 return this; 348 } 349 350 /** 351 * Sets the time based low watermark in milliseconds for rebuffering. 352 * @param watermarkMs time based low watermark in milliseconds 353 * @return the same Builder instance. 354 */ 355 public Builder setRebufferingWatermarkLowMs(int watermarkMs) { 356 mRebufferingWatermarkLowMs = watermarkMs; 357 return this; 358 } 359 360 /** 361 * Sets the time based high watermark in milliseconds for rebuffering. 362 * @param watermarkMs time based high watermark in milliseconds 363 * @return the same Builder instance. 364 */ 365 public Builder setRebufferingWatermarkHighMs(int watermarkMs) { 366 mRebufferingWatermarkHighMs = watermarkMs; 367 return this; 368 } 369 370 /** 371 * Sets the size based low watermark in milliseconds for rebuffering. 372 * @param watermarkKB size based low watermark in milliseconds 373 * @return the same Builder instance. 374 */ 375 public Builder setRebufferingWatermarkLowKB(int watermarkKB) { 376 mRebufferingWatermarkLowKB = watermarkKB; 377 return this; 378 } 379 380 /** 381 * Sets the size based high watermark in milliseconds for rebuffering. 382 * @param watermarkKB size based high watermark in milliseconds 383 * @return the same Builder instance. 384 */ 385 public Builder setRebufferingWatermarkHighKB(int watermarkKB) { 386 mRebufferingWatermarkHighKB = watermarkKB; 387 return this; 388 } 389 390 /** 391 * Sets the time based low and high watermarks in milliseconds for rebuffering. 392 * @param lowWatermarkMs time based low watermark in milliseconds 393 * @param highWatermarkMs time based high watermark in milliseconds 394 * @return the same Builder instance. 395 */ 396 public Builder setRebufferingWatermarksMs(int lowWatermarkMs, int highWatermarkMs) { 397 mRebufferingWatermarkLowMs = lowWatermarkMs; 398 mRebufferingWatermarkHighMs = highWatermarkMs; 399 return this; 400 } 401 402 /** 403 * Sets the size based low and high watermarks in kilobytes for rebuffering. 404 * @param lowWatermarkKB size based low watermark in kilobytes 405 * @param highWatermarkKB size based high watermark in kilobytes 406 * @return the same Builder instance. 407 */ 408 public Builder setRebufferingWatermarksKB(int lowWatermarkKB, int highWatermarkKB) { 409 mRebufferingWatermarkLowKB = lowWatermarkKB; 410 mRebufferingWatermarkHighKB = highWatermarkKB; 411 return this; 412 } 413 } 414 415 private BufferingParams(Parcel in) { 416 mInitialBufferingMode = in.readInt(); 417 mRebufferingMode = in.readInt(); 418 419 mInitialWatermarkMs = in.readInt(); 420 mInitialWatermarkKB = in.readInt(); 421 422 mRebufferingWatermarkLowMs = in.readInt(); 423 mRebufferingWatermarkHighMs = in.readInt(); 424 mRebufferingWatermarkLowKB = in.readInt(); 425 mRebufferingWatermarkHighKB = in.readInt(); 426 } 427 428 public static final Parcelable.Creator<BufferingParams> CREATOR = 429 new Parcelable.Creator<BufferingParams>() { 430 @Override 431 public BufferingParams createFromParcel(Parcel in) { 432 return new BufferingParams(in); 433 } 434 435 @Override 436 public BufferingParams[] newArray(int size) { 437 return new BufferingParams[size]; 438 } 439 }; 440 441 442 @Override 443 public int describeContents() { 444 return 0; 445 } 446 447 @Override 448 public void writeToParcel(Parcel dest, int flags) { 449 dest.writeInt(mInitialBufferingMode); 450 dest.writeInt(mRebufferingMode); 451 452 dest.writeInt(mInitialWatermarkMs); 453 dest.writeInt(mInitialWatermarkKB); 454 455 dest.writeInt(mRebufferingWatermarkLowMs); 456 dest.writeInt(mRebufferingWatermarkHighMs); 457 dest.writeInt(mRebufferingWatermarkLowKB); 458 dest.writeInt(mRebufferingWatermarkHighKB); 459 } 460 } 461