1/* 2 * Copyright 2018 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 */ 16package androidx.media; 17 18import static org.junit.Assert.assertEquals; 19import static org.junit.Assert.assertFalse; 20import static org.junit.Assert.assertNotNull; 21import static org.junit.Assert.assertTrue; 22import static org.junit.Assert.fail; 23 24import android.content.pm.PackageManager; 25import android.content.res.AssetFileDescriptor; 26import android.hardware.Camera; 27import android.media.AudioManager; 28import android.media.MediaMetadataRetriever; 29import android.media.MediaRecorder; 30import android.media.MediaTimestamp; 31import android.media.PlaybackParams; 32import android.media.SubtitleData; 33import android.media.SyncParams; 34import android.media.audiofx.AudioEffect; 35import android.media.audiofx.Visualizer; 36import android.net.Uri; 37import android.os.Build; 38import android.os.Environment; 39import android.support.test.filters.LargeTest; 40import android.support.test.filters.MediumTest; 41import android.support.test.filters.SdkSuppress; 42import android.support.test.filters.SmallTest; 43import android.support.test.runner.AndroidJUnit4; 44import android.util.Log; 45 46import androidx.media.MediaPlayerInterface.PlayerEventCallback; 47import androidx.media.test.R; 48 49import org.junit.After; 50import org.junit.Before; 51import org.junit.Test; 52import org.junit.runner.RunWith; 53 54import java.io.BufferedReader; 55import java.io.File; 56import java.io.IOException; 57import java.io.InputStream; 58import java.io.InputStreamReader; 59import java.util.ArrayDeque; 60import java.util.ArrayList; 61import java.util.List; 62import java.util.Vector; 63import java.util.concurrent.BlockingDeque; 64import java.util.concurrent.CountDownLatch; 65import java.util.concurrent.ExecutorService; 66import java.util.concurrent.Executors; 67import java.util.concurrent.LinkedBlockingDeque; 68import java.util.concurrent.atomic.AtomicInteger; 69import java.util.concurrent.atomic.AtomicReference; 70 71@RunWith(AndroidJUnit4.class) 72@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P) 73public class MediaPlayer2Test extends MediaPlayer2TestBase { 74 75 private static final String LOG_TAG = "MediaPlayer2Test"; 76 77 private static final int RECORDED_VIDEO_WIDTH = 176; 78 private static final int RECORDED_VIDEO_HEIGHT = 144; 79 private static final long RECORDED_DURATION_MS = 3000; 80 private static final float FLOAT_TOLERANCE = .0001f; 81 82 private String mRecordedFilePath; 83 private final Vector<Integer> mSubtitleTrackIndex = new Vector<>(); 84 private final Monitor mOnSubtitleDataCalled = new Monitor(); 85 private int mSelectedSubtitleIndex; 86 87 private File mOutFile; 88 private Camera mCamera; 89 90 @Before 91 @Override 92 public void setUp() throws Throwable { 93 super.setUp(); 94 mRecordedFilePath = new File(Environment.getExternalStorageDirectory(), 95 "mediaplayer_record.out").getAbsolutePath(); 96 mOutFile = new File(mRecordedFilePath); 97 } 98 99 @After 100 @Override 101 public void tearDown() throws Exception { 102 super.tearDown(); 103 if (mOutFile != null && mOutFile.exists()) { 104 mOutFile.delete(); 105 } 106 } 107 108 @Test 109 @MediumTest 110 public void testPlayNullSourcePath() throws Exception { 111 final Monitor onSetDataSourceCalled = new Monitor(); 112 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 113 @Override 114 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 115 if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { 116 assertTrue(status != MediaPlayer2.CALL_STATUS_NO_ERROR); 117 onSetDataSourceCalled.signal(); 118 } 119 } 120 }; 121 synchronized (mEventCbLock) { 122 mEventCallbacks.add(ecb); 123 } 124 125 onSetDataSourceCalled.reset(); 126 mPlayer.setDataSource((DataSourceDesc) null); 127 onSetDataSourceCalled.waitForSignal(); 128 } 129 130 @Test 131 @LargeTest 132 public void testPlayAudioFromDataURI() throws Exception { 133 final int mp3Duration = 34909; 134 final int tolerance = 70; 135 final int seekDuration = 100; 136 137 // This is "R.raw.testmp3_2", base64-encoded. 138 final int resid = R.raw.testmp3_3; 139 140 InputStream is = mContext.getResources().openRawResource(resid); 141 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 142 143 StringBuilder builder = new StringBuilder(); 144 builder.append("data:;base64,"); 145 builder.append(reader.readLine()); 146 Uri uri = Uri.parse(builder.toString()); 147 148 MediaPlayer2 mp = createMediaPlayer2(mContext, uri); 149 150 final Monitor onPrepareCalled = new Monitor(); 151 final Monitor onPlayCalled = new Monitor(); 152 final Monitor onSeekToCalled = new Monitor(); 153 final Monitor onLoopCurrentCalled = new Monitor(); 154 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 155 @Override 156 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 157 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 158 onPrepareCalled.signal(); 159 } 160 } 161 162 @Override 163 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 164 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 165 onPlayCalled.signal(); 166 } else if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { 167 onLoopCurrentCalled.signal(); 168 } else if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 169 onSeekToCalled.signal(); 170 } 171 } 172 }; 173 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 174 175 try { 176 AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() 177 .setLegacyStreamType(AudioManager.STREAM_MUSIC) 178 .build(); 179 mp.setAudioAttributes(attributes); 180 181 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 182 onPlayCalled.reset(); 183 mp.play(); 184 onPlayCalled.waitForSignal(); 185 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 186 187 /* FIXME: what's API for checking loop state? 188 assertFalse(mp.isLooping()); 189 */ 190 onLoopCurrentCalled.reset(); 191 mp.loopCurrent(true); 192 onLoopCurrentCalled.waitForSignal(); 193 /* FIXME: what's API for checking loop state? 194 assertTrue(mp.isLooping()); 195 */ 196 197 assertEquals(mp3Duration, mp.getDuration(), tolerance); 198 long pos = mp.getCurrentPosition(); 199 assertTrue(pos >= 0); 200 assertTrue(pos < mp3Duration - seekDuration); 201 202 onSeekToCalled.reset(); 203 mp.seekTo(pos + seekDuration, MediaPlayer2.SEEK_PREVIOUS_SYNC); 204 onSeekToCalled.waitForSignal(); 205 assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); 206 207 // test pause and restart 208 mp.pause(); 209 Thread.sleep(SLEEP_TIME); 210 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 211 onPlayCalled.reset(); 212 mp.play(); 213 onPlayCalled.waitForSignal(); 214 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 215 216 // test stop and restart 217 mp.reset(); 218 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 219 mp.setDataSource(new DataSourceDesc.Builder() 220 .setDataSource(mContext, uri) 221 .build()); 222 onPrepareCalled.reset(); 223 mp.prepare(); 224 onPrepareCalled.waitForSignal(); 225 226 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 227 onPlayCalled.reset(); 228 mp.play(); 229 onPlayCalled.waitForSignal(); 230 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 231 232 // waiting to complete 233 while (mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING) { 234 Thread.sleep(SLEEP_TIME); 235 } 236 } finally { 237 mp.close(); 238 } 239 } 240 241 @Test 242 @LargeTest 243 public void testPlayAudio() throws Exception { 244 final int resid = R.raw.testmp3_2; 245 final int mp3Duration = 34909; 246 final int tolerance = 70; 247 final int seekDuration = 100; 248 249 MediaPlayer2 mp = createMediaPlayer2(mContext, resid); 250 251 final Monitor onPrepareCalled = new Monitor(); 252 final Monitor onPlayCalled = new Monitor(); 253 final Monitor onSeekToCalled = new Monitor(); 254 final Monitor onLoopCurrentCalled = new Monitor(); 255 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 256 @Override 257 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 258 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 259 onPrepareCalled.signal(); 260 } 261 } 262 263 @Override 264 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 265 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 266 onPlayCalled.signal(); 267 } else if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { 268 onLoopCurrentCalled.signal(); 269 } else if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 270 onSeekToCalled.signal(); 271 } 272 } 273 }; 274 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 275 276 try { 277 AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() 278 .setLegacyStreamType(AudioManager.STREAM_MUSIC) 279 .build(); 280 mp.setAudioAttributes(attributes); 281 282 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 283 onPlayCalled.reset(); 284 mp.play(); 285 onPlayCalled.waitForSignal(); 286 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 287 288 //assertFalse(mp.isLooping()); 289 onLoopCurrentCalled.reset(); 290 mp.loopCurrent(true); 291 onLoopCurrentCalled.waitForSignal(); 292 //assertTrue(mp.isLooping()); 293 294 assertEquals(mp3Duration, mp.getDuration(), tolerance); 295 long pos = mp.getCurrentPosition(); 296 assertTrue(pos >= 0); 297 assertTrue(pos < mp3Duration - seekDuration); 298 299 onSeekToCalled.reset(); 300 mp.seekTo(pos + seekDuration, MediaPlayer2.SEEK_PREVIOUS_SYNC); 301 onSeekToCalled.waitForSignal(); 302 assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); 303 304 // test pause and restart 305 mp.pause(); 306 Thread.sleep(SLEEP_TIME); 307 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 308 onPlayCalled.reset(); 309 mp.play(); 310 onPlayCalled.waitForSignal(); 311 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 312 313 // test stop and restart 314 mp.reset(); 315 AssetFileDescriptor afd = mResources.openRawResourceFd(resid); 316 mp.setDataSource(new DataSourceDesc.Builder() 317 .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) 318 .build()); 319 320 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 321 onPrepareCalled.reset(); 322 mp.prepare(); 323 onPrepareCalled.waitForSignal(); 324 afd.close(); 325 326 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 327 onPlayCalled.reset(); 328 mp.play(); 329 onPlayCalled.waitForSignal(); 330 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 331 332 // waiting to complete 333 while (mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING) { 334 Thread.sleep(SLEEP_TIME); 335 } 336 } catch (Exception e) { 337 throw e; 338 } finally { 339 mp.close(); 340 } 341 } 342 343 /* 344 public void testConcurentPlayAudio() throws Exception { 345 final int resid = R.raw.test1m1s; // MP3 longer than 1m are usualy offloaded 346 final int tolerance = 70; 347 348 List<MediaPlayer2> mps = Stream.generate(() -> createMediaPlayer2(mContext, resid)) 349 .limit(5).collect(Collectors.toList()); 350 351 try { 352 for (MediaPlayer2 mp : mps) { 353 Monitor onPlayCalled = new Monitor(); 354 Monitor onLoopCurrentCalled = new Monitor(); 355 MediaPlayer2.MediaPlayer2EventCallback ecb = 356 new MediaPlayer2.MediaPlayer2EventCallback() { 357 @Override 358 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, 359 int what, int status) { 360 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 361 onPlayCalled.signal(); 362 } else if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { 363 onLoopCurrentCalled.signal(); 364 } 365 } 366 }; 367 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 368 369 AudioAttributes attributes = new AudioAttributes.Builder() 370 .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) 371 .build(); 372 mp.setAudioAttributes(attributes); 373 374 assertFalse(mp.isPlaying()); 375 onPlayCalled.reset(); 376 mp.play(); 377 onPlayCalled.waitForSignal(); 378 assertTrue(mp.isPlaying()); 379 380 assertFalse(mp.isLooping()); 381 onLoopCurrentCalled.reset(); 382 mp.loopCurrent(true); 383 onLoopCurrentCalled.waitForSignal(); 384 assertTrue(mp.isLooping()); 385 386 long pos = mp.getCurrentPosition(); 387 assertTrue(pos >= 0); 388 389 Thread.sleep(SLEEP_TIME); // Delay each track to be able to ear them 390 } 391 // Check that all mp3 are playing concurrently here 392 for (MediaPlayer2 mp : mps) { 393 long pos = mp.getCurrentPosition(); 394 Thread.sleep(SLEEP_TIME); 395 assertEquals(pos + SLEEP_TIME, mp.getCurrentPosition(), tolerance); 396 } 397 } finally { 398 mps.forEach(MediaPlayer2::close); 399 } 400 } 401 */ 402 403 @Test 404 @LargeTest 405 public void testPlayAudioLooping() throws Exception { 406 final int resid = R.raw.testmp3; 407 408 MediaPlayer2 mp = createMediaPlayer2(mContext, resid); 409 try { 410 AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() 411 .setLegacyStreamType(AudioManager.STREAM_MUSIC) 412 .build(); 413 mp.setAudioAttributes(attributes); 414 mp.loopCurrent(true); 415 final Monitor onCompletionCalled = new Monitor(); 416 final Monitor onPlayCalled = new Monitor(); 417 MediaPlayer2.MediaPlayer2EventCallback ecb = 418 new MediaPlayer2.MediaPlayer2EventCallback() { 419 @Override 420 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, 421 int what, int extra) { 422 if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { 423 Log.i("@@@", "got oncompletion"); 424 onCompletionCalled.signal(); 425 } 426 } 427 428 @Override 429 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, 430 int what, int status) { 431 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 432 onPlayCalled.signal(); 433 } 434 } 435 }; 436 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 437 438 assertFalse(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 439 onPlayCalled.reset(); 440 mp.play(); 441 onPlayCalled.waitForSignal(); 442 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 443 444 long duration = mp.getDuration(); 445 Thread.sleep(duration * 4); // allow for several loops 446 assertTrue(mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 447 assertEquals("wrong number of completion signals", 0, 448 onCompletionCalled.getNumSignal()); 449 mp.loopCurrent(false); 450 451 // wait for playback to finish 452 while (mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING) { 453 Thread.sleep(SLEEP_TIME); 454 } 455 assertEquals("wrong number of completion signals", 1, 456 onCompletionCalled.getNumSignal()); 457 } finally { 458 mp.close(); 459 } 460 } 461 462 @Test 463 @LargeTest 464 public void testPlayMidi() throws Exception { 465 final int resid = R.raw.midi8sec; 466 final int midiDuration = 8000; 467 final int tolerance = 70; 468 final int seekDuration = 1000; 469 470 MediaPlayer2 mp = createMediaPlayer2(mContext, resid); 471 472 final Monitor onPrepareCalled = new Monitor(); 473 final Monitor onSeekToCalled = new Monitor(); 474 final Monitor onLoopCurrentCalled = new Monitor(); 475 MediaPlayer2.MediaPlayer2EventCallback ecb = 476 new MediaPlayer2.MediaPlayer2EventCallback() { 477 @Override 478 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 479 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 480 onPrepareCalled.signal(); 481 } 482 } 483 484 @Override 485 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, 486 int what, int status) { 487 if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { 488 onLoopCurrentCalled.signal(); 489 } else if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 490 onSeekToCalled.signal(); 491 } 492 } 493 }; 494 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 495 496 try { 497 AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() 498 .setLegacyStreamType(AudioManager.STREAM_MUSIC) 499 .build(); 500 mp.setAudioAttributes(attributes); 501 502 mp.play(); 503 504 /* FIXME: what's API for checking loop state? 505 assertFalse(mp.isLooping()); 506 */ 507 onLoopCurrentCalled.reset(); 508 mp.loopCurrent(true); 509 onLoopCurrentCalled.waitForSignal(); 510 /* FIXME: what's API for checking loop state? 511 assertTrue(mp.isLooping()); 512 */ 513 514 assertEquals(midiDuration, mp.getDuration(), tolerance); 515 long pos = mp.getCurrentPosition(); 516 assertTrue(pos >= 0); 517 assertTrue(pos < midiDuration - seekDuration); 518 519 onSeekToCalled.reset(); 520 mp.seekTo(pos + seekDuration, MediaPlayer2.SEEK_PREVIOUS_SYNC); 521 onSeekToCalled.waitForSignal(); 522 assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); 523 524 // test stop and restart 525 mp.reset(); 526 AssetFileDescriptor afd = mResources.openRawResourceFd(resid); 527 mp.setDataSource(new DataSourceDesc.Builder() 528 .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) 529 .build()); 530 531 mp.setMediaPlayer2EventCallback(mExecutor, ecb); 532 onPrepareCalled.reset(); 533 mp.prepare(); 534 onPrepareCalled.waitForSignal(); 535 afd.close(); 536 537 mp.play(); 538 539 Thread.sleep(SLEEP_TIME); 540 } finally { 541 mp.close(); 542 } 543 } 544 545 static class OutputListener { 546 int mSession; 547 AudioEffect mVc; 548 Visualizer mVis; 549 byte [] mVisData; 550 boolean mSoundDetected; 551 OutputListener(int session) { 552 mSession = session; 553 /* FIXME: find out a public API for replacing AudioEffect contructor. 554 // creating a volume controller on output mix ensures that ro.audio.silent mutes 555 // audio after the effects and not before 556 mVc = new AudioEffect( 557 AudioEffect.EFFECT_TYPE_NULL, 558 UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"), 559 0, 560 session); 561 mVc.setEnabled(true); 562 */ 563 mVis = new Visualizer(session); 564 int size = 256; 565 int[] range = Visualizer.getCaptureSizeRange(); 566 if (size < range[0]) { 567 size = range[0]; 568 } 569 if (size > range[1]) { 570 size = range[1]; 571 } 572 assertTrue(mVis.setCaptureSize(size) == Visualizer.SUCCESS); 573 574 mVis.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { 575 @Override 576 public void onWaveFormDataCapture(Visualizer visualizer, 577 byte[] waveform, int samplingRate) { 578 if (!mSoundDetected) { 579 for (int i = 0; i < waveform.length; i++) { 580 // 8 bit unsigned PCM, zero level is at 128, which is -128 when 581 // seen as a signed byte 582 if (waveform[i] != -128) { 583 mSoundDetected = true; 584 break; 585 } 586 } 587 } 588 } 589 590 @Override 591 public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) { 592 } 593 }, 10000 /* milliHertz */, true /* PCM */, false /* FFT */); 594 assertTrue(mVis.setEnabled(true) == Visualizer.SUCCESS); 595 } 596 597 void reset() { 598 mSoundDetected = false; 599 } 600 601 boolean heardSound() { 602 return mSoundDetected; 603 } 604 605 void release() { 606 mVis.release(); 607 /* FIXME: find out a public API for replacing AudioEffect contructor. 608 mVc.release(); 609 */ 610 } 611 } 612 613 public void testPlayAudioTwice() throws Exception { 614 615 final int resid = R.raw.camera_click; 616 617 MediaPlayer2 mp = createMediaPlayer2(mContext, resid); 618 try { 619 AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() 620 .setLegacyStreamType(AudioManager.STREAM_MUSIC) 621 .build(); 622 mp.setAudioAttributes(attributes); 623 624 OutputListener listener = new OutputListener(mp.getAudioSessionId()); 625 626 Thread.sleep(SLEEP_TIME); 627 assertFalse("noise heard before test started", listener.heardSound()); 628 629 mp.play(); 630 Thread.sleep(SLEEP_TIME); 631 assertFalse("player was still playing after " + SLEEP_TIME + " ms", 632 mp.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 633 assertTrue("nothing heard while test ran", listener.heardSound()); 634 listener.reset(); 635 mp.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); 636 mp.play(); 637 Thread.sleep(SLEEP_TIME); 638 assertTrue("nothing heard when sound was replayed", listener.heardSound()); 639 listener.release(); 640 } finally { 641 mp.close(); 642 } 643 } 644 645 @Test 646 @LargeTest 647 public void testPlayVideo() throws Exception { 648 playVideoTest(R.raw.testvideo, 352, 288); 649 } 650 651 /** 652 * Test for reseting a surface during video playback 653 * After reseting, the video should continue playing 654 * from the time setDisplay() was called 655 */ 656 @Test 657 @LargeTest 658 public void testVideoSurfaceResetting() throws Exception { 659 final int tolerance = 150; 660 final int audioLatencyTolerance = 1000; /* covers audio path latency variability */ 661 final int seekPos = 4760; // This is the I-frame position 662 663 final CountDownLatch seekDone = new CountDownLatch(1); 664 665 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 666 @Override 667 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 668 if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 669 seekDone.countDown(); 670 } 671 } 672 }; 673 synchronized (mEventCbLock) { 674 mEventCallbacks.add(ecb); 675 } 676 677 if (!checkLoadResource(R.raw.testvideo)) { 678 return; // skip; 679 } 680 playLoadedVideo(352, 288, -1); 681 682 Thread.sleep(SLEEP_TIME); 683 684 long posBefore = mPlayer.getCurrentPosition(); 685 mPlayer.setSurface(mActivity.getSurfaceHolder2().getSurface()); 686 long posAfter = mPlayer.getCurrentPosition(); 687 688 /* temporarily disable timestamp checking because MediaPlayer2 now seeks to I-frame 689 * position, instead of requested position. setDisplay invovles a seek operation 690 * internally. 691 */ 692 // TODO: uncomment out line below when MediaPlayer2 can seek to requested position. 693 // assertEquals(posAfter, posBefore, tolerance); 694 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 695 696 Thread.sleep(SLEEP_TIME); 697 698 mPlayer.seekTo(seekPos, MediaPlayer2.SEEK_PREVIOUS_SYNC); 699 seekDone.await(); 700 posAfter = mPlayer.getCurrentPosition(); 701 assertEquals(seekPos, posAfter, tolerance + audioLatencyTolerance); 702 703 Thread.sleep(SLEEP_TIME / 2); 704 posBefore = mPlayer.getCurrentPosition(); 705 mPlayer.setSurface(null); 706 posAfter = mPlayer.getCurrentPosition(); 707 // TODO: uncomment out line below when MediaPlayer2 can seek to requested position. 708 // assertEquals(posAfter, posBefore, tolerance); 709 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 710 711 Thread.sleep(SLEEP_TIME); 712 713 posBefore = mPlayer.getCurrentPosition(); 714 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 715 posAfter = mPlayer.getCurrentPosition(); 716 717 // TODO: uncomment out line below when MediaPlayer2 can seek to requested position. 718 // assertEquals(posAfter, posBefore, tolerance); 719 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 720 721 Thread.sleep(SLEEP_TIME); 722 } 723 724 public void testRecordedVideoPlayback0() throws Exception { 725 testRecordedVideoPlaybackWithAngle(0); 726 } 727 728 public void testRecordedVideoPlayback90() throws Exception { 729 testRecordedVideoPlaybackWithAngle(90); 730 } 731 732 public void testRecordedVideoPlayback180() throws Exception { 733 testRecordedVideoPlaybackWithAngle(180); 734 } 735 736 public void testRecordedVideoPlayback270() throws Exception { 737 testRecordedVideoPlaybackWithAngle(270); 738 } 739 740 private boolean hasCamera() { 741 return mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); 742 } 743 744 private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception { 745 int width = RECORDED_VIDEO_WIDTH; 746 int height = RECORDED_VIDEO_HEIGHT; 747 final String file = mRecordedFilePath; 748 final long durationMs = RECORDED_DURATION_MS; 749 750 if (!hasCamera()) { 751 return; 752 } 753 754 boolean isSupported = false; 755 mCamera = Camera.open(0); 756 Camera.Parameters parameters = mCamera.getParameters(); 757 List<Camera.Size> videoSizes = parameters.getSupportedVideoSizes(); 758 // getSupportedVideoSizes returns null when separate video/preview size 759 // is not supported. 760 if (videoSizes == null) { 761 videoSizes = parameters.getSupportedPreviewSizes(); 762 } 763 for (Camera.Size size : videoSizes) { 764 if (size.width == width && size.height == height) { 765 isSupported = true; 766 break; 767 } 768 } 769 mCamera.release(); 770 mCamera = null; 771 if (!isSupported) { 772 width = videoSizes.get(0).width; 773 height = videoSizes.get(0).height; 774 } 775 checkOrientation(angle); 776 recordVideo(width, height, angle, file, durationMs); 777 checkDisplayedVideoSize(width, height, angle, file); 778 checkVideoRotationAngle(angle, file); 779 } 780 781 private void checkOrientation(int angle) throws Exception { 782 assertTrue(angle >= 0); 783 assertTrue(angle < 360); 784 assertTrue((angle % 90) == 0); 785 } 786 787 private void recordVideo( 788 int w, int h, int angle, String file, long durationMs) throws Exception { 789 790 MediaRecorder recorder = new MediaRecorder(); 791 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 792 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 793 recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); 794 recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); 795 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); 796 recorder.setOutputFile(file); 797 recorder.setOrientationHint(angle); 798 recorder.setVideoSize(w, h); 799 recorder.setPreviewDisplay(mActivity.getSurfaceHolder2().getSurface()); 800 recorder.prepare(); 801 recorder.start(); 802 Thread.sleep(durationMs); 803 recorder.stop(); 804 recorder.release(); 805 recorder = null; 806 } 807 808 private void checkDisplayedVideoSize( 809 int w, int h, int angle, String file) throws Exception { 810 811 int displayWidth = w; 812 int displayHeight = h; 813 if ((angle % 180) != 0) { 814 displayWidth = h; 815 displayHeight = w; 816 } 817 playVideoTest(file, displayWidth, displayHeight); 818 } 819 820 private void checkVideoRotationAngle(int angle, String file) { 821 MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 822 retriever.setDataSource(file); 823 String rotation = retriever.extractMetadata( 824 MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); 825 retriever.release(); 826 retriever = null; 827 assertNotNull(rotation); 828 assertEquals(Integer.parseInt(rotation), angle); 829 } 830 831 @Test 832 @LargeTest 833 public void testSkipToNext() throws Exception { 834 testPlaylist(true); 835 } 836 837 @Test 838 @LargeTest 839 public void testPlaylist() throws Exception { 840 testPlaylist(false); 841 } 842 843 private void testPlaylist(boolean skip) throws Exception { 844 if (!checkLoadResource( 845 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { 846 return; // skip 847 } 848 final DataSourceDesc dsd1 = createDataSourceDesc( 849 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz); 850 final DataSourceDesc dsd2 = createDataSourceDesc( 851 R.raw.testvideo); 852 ArrayList<DataSourceDesc> nextDSDs = new ArrayList<DataSourceDesc>(2); 853 nextDSDs.add(dsd2); 854 nextDSDs.add(dsd1); 855 856 mPlayer.setNextDataSources(nextDSDs); 857 858 final Monitor onCompletion1Called = new Monitor(); 859 final Monitor onCompletion2Called = new Monitor(); 860 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 861 @Override 862 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 863 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 864 Log.i(LOG_TAG, "testPlaylist: prepared dsd MediaId=" + dsd.getMediaId()); 865 mOnPrepareCalled.signal(); 866 } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { 867 if (dsd == dsd1) { 868 onCompletion1Called.signal(); 869 } else if (dsd == dsd2) { 870 onCompletion2Called.signal(); 871 } else { 872 mOnCompletionCalled.signal(); 873 } 874 } 875 } 876 }; 877 synchronized (mEventCbLock) { 878 mEventCallbacks.add(ecb); 879 } 880 881 mOnCompletionCalled.reset(); 882 onCompletion1Called.reset(); 883 onCompletion2Called.reset(); 884 885 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 886 887 mPlayer.prepare(); 888 889 mPlayer.play(); 890 891 if (skip) { 892 mPlayer.skipToNext(); 893 mPlayer.skipToNext(); 894 } else { 895 mOnCompletionCalled.waitForSignal(); 896 onCompletion2Called.waitForSignal(); 897 } 898 onCompletion1Called.waitForSignal(); 899 if (skip) { 900 assertFalse("first dsd completed", mOnCompletionCalled.isSignalled()); 901 assertFalse("second dsd completed", onCompletion2Called.isSignalled()); 902 } 903 904 mPlayer.reset(); 905 } 906 907 // setPlaybackParams() with non-zero speed should NOT start playback. 908 // TODO: enable this test when MediaPlayer2.setPlaybackParams() is fixed 909 /* 910 public void testSetPlaybackParamsPositiveSpeed() throws Exception { 911 if (!checkLoadResource( 912 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { 913 return; // skip 914 } 915 916 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 917 @Override 918 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 919 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 920 mOnPrepareCalled.signal(); 921 } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { 922 mOnCompletionCalled.signal(); 923 } 924 } 925 926 @Override 927 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 928 if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 929 mOnSeekCompleteCalled.signal(); 930 } 931 } 932 }; 933 synchronized (mEventCbLock) { 934 mEventCallbacks.add(ecb); 935 } 936 937 mOnCompletionCalled.reset(); 938 mPlayer.setDisplay(mActivity.getSurfaceHolder()); 939 940 mOnPrepareCalled.reset(); 941 mPlayer.prepare(); 942 mOnPrepareCalled.waitForSignal(); 943 944 mOnSeekCompleteCalled.reset(); 945 mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); 946 mOnSeekCompleteCalled.waitForSignal(); 947 948 final float playbackRate = 1.0f; 949 950 int playTime = 2000; // The testing clip is about 10 second long. 951 mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); 952 assertTrue("MediaPlayer2 should be playing", mPlayer.isPlaying()); 953 Thread.sleep(playTime); 954 assertTrue("MediaPlayer2 should still be playing", 955 mPlayer.getCurrentPosition() > 0); 956 957 long duration = mPlayer.getDuration(); 958 mOnSeekCompleteCalled.reset(); 959 mPlayer.seekTo(duration - 1000, MediaPlayer2.SEEK_PREVIOUS_SYNC); 960 mOnSeekCompleteCalled.waitForSignal(); 961 962 mOnCompletionCalled.waitForSignal(); 963 assertFalse("MediaPlayer2 should not be playing", mPlayer.isPlaying()); 964 long eosPosition = mPlayer.getCurrentPosition(); 965 966 mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); 967 assertTrue("MediaPlayer2 should be playing after EOS", mPlayer.isPlaying()); 968 Thread.sleep(playTime); 969 long position = mPlayer.getCurrentPosition(); 970 assertTrue("MediaPlayer2 should still be playing after EOS", 971 position > 0 && position < eosPosition); 972 973 mPlayer.reset(); 974 } 975 */ 976 977 @Test 978 @LargeTest 979 public void testPlaybackRate() throws Exception { 980 final int toleranceMs = 1000; 981 if (!checkLoadResource( 982 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { 983 return; // skip 984 } 985 986 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 987 @Override 988 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 989 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 990 mOnPrepareCalled.signal(); 991 } 992 } 993 }; 994 synchronized (mEventCbLock) { 995 mEventCallbacks.add(ecb); 996 } 997 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 998 999 mOnPrepareCalled.reset(); 1000 mPlayer.prepare(); 1001 mOnPrepareCalled.waitForSignal(); 1002 1003 SyncParams sync = new SyncParams().allowDefaults(); 1004 mPlayer.setSyncParams(sync); 1005 sync = mPlayer.getSyncParams(); 1006 1007 float[] rates = { 0.25f, 0.5f, 1.0f, 2.0f }; 1008 for (float playbackRate : rates) { 1009 mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); 1010 Thread.sleep(1000); 1011 int playTime = 4000; // The testing clip is about 10 second long. 1012 mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); 1013 mPlayer.play(); 1014 Thread.sleep(playTime); 1015 PlaybackParams pbp = mPlayer.getPlaybackParams(); 1016 assertEquals( 1017 playbackRate, pbp.getSpeed(), 1018 FLOAT_TOLERANCE + playbackRate * sync.getTolerance()); 1019 assertTrue("MediaPlayer2 should still be playing", 1020 mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 1021 1022 long playedMediaDurationMs = mPlayer.getCurrentPosition(); 1023 int diff = Math.abs((int) (playedMediaDurationMs / playbackRate) - playTime); 1024 if (diff > toleranceMs) { 1025 fail("Media player had error in playback rate " + playbackRate 1026 + ", play time is " + playTime + " vs expected " + playedMediaDurationMs); 1027 } 1028 mPlayer.pause(); 1029 pbp = mPlayer.getPlaybackParams(); 1030 // TODO: pause() should NOT change PlaybackParams. 1031 // assertEquals(0.f, pbp.getSpeed(), FLOAT_TOLERANCE); 1032 } 1033 mPlayer.reset(); 1034 } 1035 1036 @Test 1037 @LargeTest 1038 public void testSeekModes() throws Exception { 1039 // This clip has 2 I frames at 66687us and 4299687us. 1040 if (!checkLoadResource( 1041 R.raw.bbb_s1_320x240_mp4_h264_mp2_800kbps_30fps_aac_lc_5ch_240kbps_44100hz)) { 1042 return; // skip 1043 } 1044 1045 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1046 @Override 1047 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1048 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1049 mOnPrepareCalled.signal(); 1050 } 1051 } 1052 1053 @Override 1054 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1055 if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 1056 mOnSeekCompleteCalled.signal(); 1057 } 1058 } 1059 }; 1060 synchronized (mEventCbLock) { 1061 mEventCallbacks.add(ecb); 1062 } 1063 1064 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1065 1066 mOnPrepareCalled.reset(); 1067 mPlayer.prepare(); 1068 mOnPrepareCalled.waitForSignal(); 1069 1070 mOnSeekCompleteCalled.reset(); 1071 mPlayer.play(); 1072 1073 final long seekPosMs = 3000; 1074 final long timeToleranceMs = 100; 1075 final long syncTime1Ms = 67; 1076 final long syncTime2Ms = 4300; 1077 1078 // TODO: tighten checking range. For now, ensure mediaplayer doesn't 1079 // seek to previous sync or next sync. 1080 long cp = runSeekMode(MediaPlayer2.SEEK_CLOSEST, seekPosMs); 1081 assertTrue("MediaPlayer2 did not seek to closest position", 1082 cp > seekPosMs && cp < syncTime2Ms); 1083 1084 // TODO: tighten checking range. For now, ensure mediaplayer doesn't 1085 // seek to closest position or next sync. 1086 cp = runSeekMode(MediaPlayer2.SEEK_PREVIOUS_SYNC, seekPosMs); 1087 assertTrue("MediaPlayer2 did not seek to preivous sync position", 1088 cp < seekPosMs - timeToleranceMs); 1089 1090 // TODO: tighten checking range. For now, ensure mediaplayer doesn't 1091 // seek to closest position or previous sync. 1092 cp = runSeekMode(MediaPlayer2.SEEK_NEXT_SYNC, seekPosMs); 1093 assertTrue("MediaPlayer2 did not seek to next sync position", 1094 cp > syncTime2Ms - timeToleranceMs); 1095 1096 // TODO: tighten checking range. For now, ensure mediaplayer doesn't 1097 // seek to closest position or previous sync. 1098 cp = runSeekMode(MediaPlayer2.SEEK_CLOSEST_SYNC, seekPosMs); 1099 assertTrue("MediaPlayer2 did not seek to closest sync position", 1100 cp > syncTime2Ms - timeToleranceMs); 1101 1102 mPlayer.reset(); 1103 } 1104 1105 private long runSeekMode(int seekMode, long seekPosMs) throws Exception { 1106 final int sleepIntervalMs = 100; 1107 int timeRemainedMs = 10000; // total time for testing 1108 final int timeToleranceMs = 100; 1109 1110 mPlayer.seekTo(seekPosMs, seekMode); 1111 mOnSeekCompleteCalled.waitForSignal(); 1112 mOnSeekCompleteCalled.reset(); 1113 long cp = -seekPosMs; 1114 while (timeRemainedMs > 0) { 1115 cp = mPlayer.getCurrentPosition(); 1116 // Wait till MediaPlayer2 starts rendering since MediaPlayer2 caches 1117 // seek position as current position. 1118 if (cp < seekPosMs - timeToleranceMs || cp > seekPosMs + timeToleranceMs) { 1119 break; 1120 } 1121 timeRemainedMs -= sleepIntervalMs; 1122 Thread.sleep(sleepIntervalMs); 1123 } 1124 assertTrue("MediaPlayer2 did not finish seeking in time for mode " + seekMode, 1125 timeRemainedMs > 0); 1126 return cp; 1127 } 1128 1129 @Test 1130 @LargeTest 1131 public void testGetTimestamp() throws Exception { 1132 final int toleranceUs = 100000; 1133 final float playbackRate = 1.0f; 1134 if (!checkLoadResource( 1135 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { 1136 return; // skip 1137 } 1138 1139 final Monitor onPauseCalled = new Monitor(); 1140 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1141 @Override 1142 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1143 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1144 mOnPrepareCalled.signal(); 1145 } 1146 } 1147 1148 @Override 1149 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1150 if (what == MediaPlayer2.CALL_COMPLETED_PAUSE) { 1151 onPauseCalled.signal(); 1152 } 1153 } 1154 }; 1155 synchronized (mEventCbLock) { 1156 mEventCallbacks.add(ecb); 1157 } 1158 1159 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1160 1161 mOnPrepareCalled.reset(); 1162 mPlayer.prepare(); 1163 mOnPrepareCalled.waitForSignal(); 1164 1165 mPlayer.play(); 1166 mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); 1167 Thread.sleep(SLEEP_TIME); // let player get into stable state. 1168 long nt1 = System.nanoTime(); 1169 MediaTimestamp ts1 = mPlayer.getTimestamp(); 1170 long nt2 = System.nanoTime(); 1171 assertTrue("Media player should return a valid time stamp", ts1 != null); 1172 assertEquals("MediaPlayer2 had error in clockRate " + ts1.getMediaClockRate(), 1173 playbackRate, ts1.getMediaClockRate(), 0.001f); 1174 assertTrue("The nanoTime of Media timestamp should be taken when getTimestamp is called.", 1175 nt1 <= ts1.getAnchorSytemNanoTime() && ts1.getAnchorSytemNanoTime() <= nt2); 1176 1177 onPauseCalled.reset(); 1178 mPlayer.pause(); 1179 onPauseCalled.waitForSignal(); 1180 ts1 = mPlayer.getTimestamp(); 1181 assertTrue("Media player should return a valid time stamp", ts1 != null); 1182 assertTrue("Media player should have play rate of 0.0f when paused", 1183 ts1.getMediaClockRate() == 0.0f); 1184 1185 mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); 1186 mPlayer.play(); 1187 Thread.sleep(SLEEP_TIME); // let player get into stable state. 1188 int playTime = 4000; // The testing clip is about 10 second long. 1189 ts1 = mPlayer.getTimestamp(); 1190 assertTrue("Media player should return a valid time stamp", ts1 != null); 1191 Thread.sleep(playTime); 1192 MediaTimestamp ts2 = mPlayer.getTimestamp(); 1193 assertTrue("Media player should return a valid time stamp", ts2 != null); 1194 assertTrue("The clockRate should not be changed.", 1195 ts1.getMediaClockRate() == ts2.getMediaClockRate()); 1196 assertEquals("MediaPlayer2 had error in timestamp.", 1197 ts1.getAnchorMediaTimeUs() + (long) (playTime * ts1.getMediaClockRate() * 1000), 1198 ts2.getAnchorMediaTimeUs(), toleranceUs); 1199 1200 mPlayer.reset(); 1201 } 1202 1203 public void testLocalVideo_MKV_H265_1280x720_500kbps_25fps_AAC_Stereo_128kbps_44100Hz() 1204 throws Exception { 1205 playVideoTest( 1206 R.raw.video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz, 1280, 720); 1207 } 1208 1209 public void testLocalVideo_MP4_H264_480x360_500kbps_25fps_AAC_Stereo_128kbps_44110Hz() 1210 throws Exception { 1211 playVideoTest( 1212 R.raw.video_480x360_mp4_h264_500kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); 1213 } 1214 1215 public void testLocalVideo_MP4_H264_480x360_500kbps_30fps_AAC_Stereo_128kbps_44110Hz() 1216 throws Exception { 1217 playVideoTest( 1218 R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); 1219 } 1220 1221 public void testLocalVideo_MP4_H264_480x360_1000kbps_25fps_AAC_Stereo_128kbps_44110Hz() 1222 throws Exception { 1223 playVideoTest( 1224 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); 1225 } 1226 1227 public void testLocalVideo_MP4_H264_480x360_1000kbps_30fps_AAC_Stereo_128kbps_44110Hz() 1228 throws Exception { 1229 playVideoTest( 1230 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); 1231 } 1232 1233 public void testLocalVideo_MP4_H264_480x360_1350kbps_25fps_AAC_Stereo_128kbps_44110Hz() 1234 throws Exception { 1235 playVideoTest( 1236 R.raw.video_480x360_mp4_h264_1350kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); 1237 } 1238 1239 public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz() 1240 throws Exception { 1241 playVideoTest( 1242 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); 1243 } 1244 1245 public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz_frag() 1246 throws Exception { 1247 playVideoTest( 1248 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz_fragmented, 1249 480, 360); 1250 } 1251 1252 public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_192kbps_44110Hz() 1253 throws Exception { 1254 playVideoTest( 1255 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz, 480, 360); 1256 } 1257 1258 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_11025Hz() 1259 throws Exception { 1260 playVideoTest( 1261 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_11025hz, 176, 144); 1262 } 1263 1264 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_22050Hz() 1265 throws Exception { 1266 playVideoTest( 1267 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_22050hz, 176, 144); 1268 } 1269 1270 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_11025Hz() 1271 throws Exception { 1272 playVideoTest( 1273 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 1274 } 1275 1276 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_22050Hz() 1277 throws Exception { 1278 playVideoTest( 1279 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 1280 } 1281 1282 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_11025Hz() 1283 throws Exception { 1284 playVideoTest( 1285 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 1286 } 1287 1288 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_22050Hz() 1289 throws Exception { 1290 playVideoTest( 1291 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 1292 } 1293 1294 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_11025Hz() 1295 throws Exception { 1296 playVideoTest( 1297 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_11025hz, 176, 144); 1298 } 1299 1300 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_22050Hz() 1301 throws Exception { 1302 playVideoTest( 1303 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_22050hz, 176, 144); 1304 } 1305 1306 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_11025Hz() 1307 throws Exception { 1308 playVideoTest( 1309 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 1310 } 1311 1312 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_22050Hz() 1313 throws Exception { 1314 playVideoTest( 1315 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 1316 } 1317 1318 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_11025Hz() 1319 throws Exception { 1320 playVideoTest( 1321 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); 1322 } 1323 1324 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_22050Hz() 1325 throws Exception { 1326 playVideoTest( 1327 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); 1328 } 1329 1330 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_11025Hz() 1331 throws Exception { 1332 playVideoTest( 1333 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz, 176, 144); 1334 } 1335 1336 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_22050Hz() 1337 throws Exception { 1338 playVideoTest( 1339 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_22050hz, 176, 144); 1340 } 1341 1342 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_11025Hz() 1343 throws Exception { 1344 playVideoTest( 1345 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 1346 } 1347 1348 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_22050Hz() 1349 throws Exception { 1350 playVideoTest( 1351 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 1352 } 1353 1354 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_11025Hz() 1355 throws Exception { 1356 playVideoTest( 1357 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 1358 } 1359 1360 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_22050Hz() 1361 throws Exception { 1362 playVideoTest( 1363 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 1364 } 1365 1366 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_11025Hz() 1367 throws Exception { 1368 playVideoTest( 1369 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_11025hz, 176, 144); 1370 } 1371 1372 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_22050Hz() 1373 throws Exception { 1374 playVideoTest( 1375 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_22050hz, 176, 144); 1376 } 1377 1378 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_11025Hz() 1379 throws Exception { 1380 playVideoTest( 1381 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 1382 } 1383 1384 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_22050Hz() 1385 throws Exception { 1386 playVideoTest( 1387 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 1388 } 1389 1390 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_11025Hz() 1391 throws Exception { 1392 playVideoTest( 1393 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); 1394 } 1395 1396 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_22050Hz() 1397 throws Exception { 1398 playVideoTest( 1399 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_22050hz, 176, 144); 1400 } 1401 1402 private void readSubtitleTracks() throws Exception { 1403 mSubtitleTrackIndex.clear(); 1404 List<MediaPlayer2.TrackInfo> trackInfos = mPlayer.getTrackInfo(); 1405 if (trackInfos == null || trackInfos.size() == 0) { 1406 return; 1407 } 1408 1409 Vector<Integer> subtitleTrackIndex = new Vector<>(); 1410 for (int i = 0; i < trackInfos.size(); ++i) { 1411 assertTrue(trackInfos.get(i) != null); 1412 if (trackInfos.get(i).getTrackType() 1413 == MediaPlayer2.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) { 1414 subtitleTrackIndex.add(i); 1415 } 1416 } 1417 1418 mSubtitleTrackIndex.addAll(subtitleTrackIndex); 1419 } 1420 1421 private void selectSubtitleTrack(int index) throws Exception { 1422 int trackIndex = mSubtitleTrackIndex.get(index); 1423 mPlayer.selectTrack(trackIndex); 1424 mSelectedSubtitleIndex = index; 1425 } 1426 1427 private void deselectSubtitleTrack(int index) throws Exception { 1428 int trackIndex = mSubtitleTrackIndex.get(index); 1429 mOnDeselectTrackCalled.reset(); 1430 mPlayer.deselectTrack(trackIndex); 1431 mOnDeselectTrackCalled.waitForSignal(); 1432 if (mSelectedSubtitleIndex == index) { 1433 mSelectedSubtitleIndex = -1; 1434 } 1435 } 1436 1437 @Test 1438 @LargeTest 1439 public void testDeselectTrackForSubtitleTracks() throws Throwable { 1440 if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) { 1441 return; // skip; 1442 } 1443 1444 mInstrumentation.waitForIdleSync(); 1445 1446 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1447 @Override 1448 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1449 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1450 mOnPrepareCalled.signal(); 1451 } else if (what == MediaPlayer2.MEDIA_INFO_METADATA_UPDATE) { 1452 mOnInfoCalled.signal(); 1453 } 1454 } 1455 1456 @Override 1457 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1458 if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 1459 mOnSeekCompleteCalled.signal(); 1460 } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 1461 mOnPlayCalled.signal(); 1462 } else if (what == MediaPlayer2.CALL_COMPLETED_DESELECT_TRACK) { 1463 mCallStatus = status; 1464 mOnDeselectTrackCalled.signal(); 1465 } 1466 } 1467 1468 @Override 1469 public void onSubtitleData( 1470 MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) { 1471 if (data != null && data.getData() != null) { 1472 mOnSubtitleDataCalled.signal(); 1473 } 1474 } 1475 }; 1476 synchronized (mEventCbLock) { 1477 mEventCallbacks.add(ecb); 1478 } 1479 1480 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1481 1482 mOnPrepareCalled.reset(); 1483 mPlayer.prepare(); 1484 mOnPrepareCalled.waitForSignal(); 1485 1486 mOnPlayCalled.reset(); 1487 mPlayer.play(); 1488 mOnPlayCalled.waitForSignal(); 1489 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 1490 1491 // Closed caption tracks are in-band. 1492 // So, those tracks will be found after processing a number of frames. 1493 mOnInfoCalled.waitForSignal(1500); 1494 1495 mOnInfoCalled.reset(); 1496 mOnInfoCalled.waitForSignal(1500); 1497 1498 readSubtitleTracks(); 1499 1500 // Run twice to check if repeated selection-deselection on the same track works well. 1501 for (int i = 0; i < 2; i++) { 1502 // Waits until at least one subtitle is fired. Timeout is 2.5 seconds. 1503 selectSubtitleTrack(i); 1504 mOnSubtitleDataCalled.reset(); 1505 assertTrue(mOnSubtitleDataCalled.waitForSignal(2500)); 1506 1507 // Try deselecting track. 1508 deselectSubtitleTrack(i); 1509 mOnSubtitleDataCalled.reset(); 1510 assertFalse(mOnSubtitleDataCalled.waitForSignal(1500)); 1511 } 1512 1513 // Deselecting unselected track: expected error status 1514 mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; 1515 deselectSubtitleTrack(0); 1516 assertTrue(mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR); 1517 1518 mPlayer.reset(); 1519 } 1520 1521 @Test 1522 @LargeTest 1523 public void testChangeSubtitleTrack() throws Throwable { 1524 if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) { 1525 return; // skip; 1526 } 1527 1528 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1529 @Override 1530 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1531 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1532 mOnPrepareCalled.signal(); 1533 } else if (what == MediaPlayer2.MEDIA_INFO_METADATA_UPDATE) { 1534 mOnInfoCalled.signal(); 1535 } 1536 } 1537 1538 @Override 1539 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1540 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 1541 mOnPlayCalled.signal(); 1542 } 1543 } 1544 1545 @Override 1546 public void onSubtitleData( 1547 MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) { 1548 if (data != null && data.getData() != null) { 1549 mOnSubtitleDataCalled.signal(); 1550 } 1551 } 1552 }; 1553 synchronized (mEventCbLock) { 1554 mEventCallbacks.add(ecb); 1555 } 1556 1557 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1558 1559 mOnPrepareCalled.reset(); 1560 mPlayer.prepare(); 1561 mOnPrepareCalled.waitForSignal(); 1562 1563 mOnPlayCalled.reset(); 1564 mPlayer.play(); 1565 mOnPlayCalled.waitForSignal(); 1566 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 1567 1568 // Closed caption tracks are in-band. 1569 // So, those tracks will be found after processing a number of frames. 1570 mOnInfoCalled.waitForSignal(1500); 1571 1572 mOnInfoCalled.reset(); 1573 mOnInfoCalled.waitForSignal(1500); 1574 1575 readSubtitleTracks(); 1576 1577 // Waits until at least two captions are fired. Timeout is 2.5 sec. 1578 selectSubtitleTrack(0); 1579 assertTrue(mOnSubtitleDataCalled.waitForCountedSignals(2, 2500) >= 2); 1580 1581 mOnSubtitleDataCalled.reset(); 1582 selectSubtitleTrack(1); 1583 assertTrue(mOnSubtitleDataCalled.waitForCountedSignals(2, 2500) >= 2); 1584 1585 mPlayer.reset(); 1586 } 1587 1588 @Test 1589 @LargeTest 1590 public void testGetTrackInfoForVideoWithSubtitleTracks() throws Throwable { 1591 if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) { 1592 return; // skip; 1593 } 1594 1595 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1596 @Override 1597 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1598 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1599 mOnPrepareCalled.signal(); 1600 } else if (what == MediaPlayer2.MEDIA_INFO_METADATA_UPDATE) { 1601 mOnInfoCalled.signal(); 1602 } 1603 } 1604 1605 @Override 1606 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1607 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 1608 mOnPlayCalled.signal(); 1609 } 1610 } 1611 }; 1612 synchronized (mEventCbLock) { 1613 mEventCallbacks.add(ecb); 1614 } 1615 1616 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1617 1618 mOnPrepareCalled.reset(); 1619 mPlayer.prepare(); 1620 mOnPrepareCalled.waitForSignal(); 1621 1622 mOnPlayCalled.reset(); 1623 mPlayer.play(); 1624 mOnPlayCalled.waitForSignal(); 1625 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 1626 1627 // The media metadata will be changed while playing since closed caption tracks are in-band 1628 // and those tracks will be found after processing a number of frames. These tracks will be 1629 // found within one second. 1630 mOnInfoCalled.waitForSignal(1500); 1631 1632 mOnInfoCalled.reset(); 1633 mOnInfoCalled.waitForSignal(1500); 1634 1635 readSubtitleTracks(); 1636 assertEquals(2, mSubtitleTrackIndex.size()); 1637 1638 mPlayer.reset(); 1639 } 1640 1641 @Test 1642 @LargeTest 1643 public void testMediaTimeDiscontinuity() throws Exception { 1644 if (!checkLoadResource( 1645 R.raw.bbb_s1_320x240_mp4_h264_mp2_800kbps_30fps_aac_lc_5ch_240kbps_44100hz)) { 1646 return; // skip 1647 } 1648 1649 final BlockingDeque<MediaTimestamp> timestamps = new LinkedBlockingDeque<>(); 1650 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1651 @Override 1652 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1653 if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 1654 mOnSeekCompleteCalled.signal(); 1655 } 1656 } 1657 @Override 1658 public void onMediaTimeDiscontinuity( 1659 MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { 1660 timestamps.add(timestamp); 1661 mOnMediaTimeDiscontinuityCalled.signal(); 1662 } 1663 }; 1664 synchronized (mEventCbLock) { 1665 mEventCallbacks.add(ecb); 1666 } 1667 1668 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1669 mPlayer.prepare(); 1670 1671 // Timestamp needs to be reported when playback starts. 1672 mOnMediaTimeDiscontinuityCalled.reset(); 1673 mPlayer.play(); 1674 do { 1675 assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000)); 1676 } while (Math.abs(timestamps.getLast().getMediaClockRate() - 1.0f) > 0.01f); 1677 1678 // Timestamp needs to be reported when seeking is done. 1679 mOnSeekCompleteCalled.reset(); 1680 mOnMediaTimeDiscontinuityCalled.reset(); 1681 mPlayer.seekTo(3000); 1682 mOnSeekCompleteCalled.waitForSignal(); 1683 do { 1684 assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000)); 1685 } while (Math.abs(timestamps.getLast().getMediaClockRate() - 1.0f) > 0.01f); 1686 1687 // Timestamp needs to be updated when playback rate changes. 1688 mOnMediaTimeDiscontinuityCalled.reset(); 1689 mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(0.5f)); 1690 mOnMediaTimeDiscontinuityCalled.waitForSignal(); 1691 do { 1692 assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000)); 1693 } while (Math.abs(timestamps.getLast().getMediaClockRate() - 0.5f) > 0.01f); 1694 1695 // Timestamp needs to be updated when player is paused. 1696 mOnMediaTimeDiscontinuityCalled.reset(); 1697 mPlayer.pause(); 1698 mOnMediaTimeDiscontinuityCalled.waitForSignal(); 1699 do { 1700 assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000)); 1701 } while (Math.abs(timestamps.getLast().getMediaClockRate() - 0.0f) > 0.01f); 1702 1703 mPlayer.reset(); 1704 } 1705 1706 /* 1707 * This test assumes the resources being tested are between 8 and 14 seconds long 1708 * The ones being used here are 10 seconds long. 1709 */ 1710 @Test 1711 @LargeTest 1712 public void testResumeAtEnd() throws Throwable { 1713 int testsRun = testResumeAtEnd(R.raw.loudsoftmp3) 1714 + testResumeAtEnd(R.raw.loudsoftwav) 1715 + testResumeAtEnd(R.raw.loudsoftogg) 1716 + testResumeAtEnd(R.raw.loudsoftitunes) 1717 + testResumeAtEnd(R.raw.loudsoftfaac) 1718 + testResumeAtEnd(R.raw.loudsoftaac); 1719 } 1720 1721 // returns 1 if test was run, 0 otherwise 1722 private int testResumeAtEnd(int res) throws Throwable { 1723 if (!loadResource(res)) { 1724 Log.i(LOG_TAG, "testResumeAtEnd: No decoder found for " 1725 + mContext.getResources().getResourceEntryName(res) + " --- skipping."); 1726 return 0; // skip 1727 } 1728 mOnCompletionCalled.reset(); 1729 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1730 @Override 1731 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1732 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1733 mOnPrepareCalled.signal(); 1734 } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { 1735 mOnCompletionCalled.signal(); 1736 mPlayer.play(); 1737 } 1738 } 1739 }; 1740 mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); 1741 1742 mOnPrepareCalled.reset(); 1743 mPlayer.prepare(); 1744 mOnPrepareCalled.waitForSignal(); 1745 1746 // skip the first part of the file so we reach EOF sooner 1747 mPlayer.seekTo(5000, MediaPlayer2.SEEK_PREVIOUS_SYNC); 1748 mPlayer.play(); 1749 // sleep long enough that we restart playback at least once, but no more 1750 Thread.sleep(10000); 1751 assertTrue("MediaPlayer2 should still be playing", 1752 mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 1753 mPlayer.reset(); 1754 assertEquals("wrong number of repetitions", 1, mOnCompletionCalled.getNumSignal()); 1755 return 1; 1756 } 1757 1758 @Test 1759 @LargeTest 1760 public void testPositionAtEnd() throws Throwable { 1761 int testsRun = testPositionAtEnd(R.raw.test1m1shighstereo) 1762 + testPositionAtEnd(R.raw.loudsoftmp3) 1763 + testPositionAtEnd(R.raw.loudsoftwav) 1764 + testPositionAtEnd(R.raw.loudsoftogg) 1765 + testPositionAtEnd(R.raw.loudsoftitunes) 1766 + testPositionAtEnd(R.raw.loudsoftfaac) 1767 + testPositionAtEnd(R.raw.loudsoftaac); 1768 } 1769 1770 private int testPositionAtEnd(int res) throws Throwable { 1771 if (!loadResource(res)) { 1772 Log.i(LOG_TAG, "testPositionAtEnd: No decoder found for " 1773 + mContext.getResources().getResourceEntryName(res) + " --- skipping."); 1774 return 0; // skip 1775 } 1776 AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() 1777 .setLegacyStreamType(AudioManager.STREAM_MUSIC) 1778 .build(); 1779 mPlayer.setAudioAttributes(attributes); 1780 1781 mOnCompletionCalled.reset(); 1782 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1783 @Override 1784 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1785 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1786 mOnPrepareCalled.signal(); 1787 } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { 1788 mOnCompletionCalled.signal(); 1789 } 1790 } 1791 1792 @Override 1793 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1794 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 1795 mOnPlayCalled.signal(); 1796 } 1797 } 1798 }; 1799 mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); 1800 1801 mOnPrepareCalled.reset(); 1802 mPlayer.prepare(); 1803 mOnPrepareCalled.waitForSignal(); 1804 1805 long duration = mPlayer.getDuration(); 1806 assertTrue("resource too short", duration > 6000); 1807 mPlayer.seekTo(duration - 5000, MediaPlayer2.SEEK_PREVIOUS_SYNC); 1808 mOnPlayCalled.reset(); 1809 mPlayer.play(); 1810 mOnPlayCalled.waitForSignal(); 1811 while (mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING) { 1812 Log.i("@@@@", "position: " + mPlayer.getCurrentPosition()); 1813 Thread.sleep(500); 1814 } 1815 Log.i("@@@@", "final position: " + mPlayer.getCurrentPosition()); 1816 assertTrue(mPlayer.getCurrentPosition() > duration - 1000); 1817 mPlayer.reset(); 1818 return 1; 1819 } 1820 1821 @Test 1822 @LargeTest 1823 public void testMediaPlayer2Callback() throws Throwable { 1824 final int mp4Duration = 8484; 1825 1826 if (!checkLoadResource(R.raw.testvideo)) { 1827 return; // skip; 1828 } 1829 1830 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1831 1832 mOnCompletionCalled.reset(); 1833 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1834 @Override 1835 public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, 1836 int width, int height) { 1837 mOnVideoSizeChangedCalled.signal(); 1838 } 1839 1840 @Override 1841 public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1842 mOnErrorCalled.signal(); 1843 } 1844 1845 @Override 1846 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 1847 mOnInfoCalled.signal(); 1848 1849 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 1850 mOnPrepareCalled.signal(); 1851 } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { 1852 mOnCompletionCalled.signal(); 1853 } 1854 } 1855 1856 @Override 1857 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1858 if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { 1859 mOnSeekCompleteCalled.signal(); 1860 } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 1861 mOnPlayCalled.signal(); 1862 } 1863 } 1864 }; 1865 synchronized (mEventCbLock) { 1866 mEventCallbacks.add(ecb); 1867 } 1868 1869 assertFalse(mOnPrepareCalled.isSignalled()); 1870 assertFalse(mOnVideoSizeChangedCalled.isSignalled()); 1871 mPlayer.prepare(); 1872 mOnPrepareCalled.waitForSignal(); 1873 mOnVideoSizeChangedCalled.waitForSignal(); 1874 1875 mOnSeekCompleteCalled.reset(); 1876 mPlayer.seekTo(mp4Duration >> 1, MediaPlayer2.SEEK_PREVIOUS_SYNC); 1877 mOnSeekCompleteCalled.waitForSignal(); 1878 1879 assertFalse(mOnCompletionCalled.isSignalled()); 1880 mPlayer.play(); 1881 mOnPlayCalled.waitForSignal(); 1882 while (mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING) { 1883 Thread.sleep(SLEEP_TIME); 1884 } 1885 assertFalse(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 1886 mOnCompletionCalled.waitForSignal(); 1887 assertFalse(mOnErrorCalled.isSignalled()); 1888 mPlayer.reset(); 1889 } 1890 1891 @Test 1892 @LargeTest 1893 public void testPlayerStates() throws Throwable { 1894 final int mp4Duration = 8484; 1895 1896 if (!checkLoadResource(R.raw.testvideo)) { 1897 return; // skip; 1898 } 1899 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1900 1901 final Monitor prepareCompleted = new Monitor(); 1902 final Monitor playCompleted = new Monitor(); 1903 final Monitor pauseCompleted = new Monitor(); 1904 1905 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 1906 @Override 1907 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 1908 if (what == MediaPlayer2.CALL_COMPLETED_PREPARE) { 1909 prepareCompleted.signal(); 1910 } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 1911 playCompleted.signal(); 1912 } else if (what == MediaPlayer2.CALL_COMPLETED_PAUSE) { 1913 pauseCompleted.signal(); 1914 } 1915 } 1916 }; 1917 synchronized (mEventCbLock) { 1918 mEventCallbacks.add(ecb); 1919 } 1920 1921 MediaPlayerInterface playerBase = mPlayer.getMediaPlayerInterface(); 1922 assertEquals(MediaPlayerInterface.BUFFERING_STATE_UNKNOWN, playerBase.getBufferingState()); 1923 assertEquals(MediaPlayerInterface.PLAYER_STATE_IDLE, playerBase.getPlayerState()); 1924 prepareCompleted.reset(); 1925 playerBase.prepare(); 1926 prepareCompleted.waitForSignal(); 1927 assertEquals(MediaPlayerInterface.BUFFERING_STATE_BUFFERING_AND_PLAYABLE, 1928 playerBase.getBufferingState()); 1929 assertEquals(MediaPlayerInterface.PLAYER_STATE_PAUSED, playerBase.getPlayerState()); 1930 assertEquals(MediaPlayer2.MEDIAPLAYER2_STATE_PREPARED, mPlayer.getMediaPlayer2State()); 1931 1932 playCompleted.reset(); 1933 playerBase.play(); 1934 playCompleted.waitForSignal(); 1935 assertEquals(MediaPlayerInterface.BUFFERING_STATE_BUFFERING_AND_PLAYABLE, 1936 playerBase.getBufferingState()); 1937 assertEquals(MediaPlayerInterface.PLAYER_STATE_PLAYING, playerBase.getPlayerState()); 1938 1939 pauseCompleted.reset(); 1940 playerBase.pause(); 1941 pauseCompleted.waitForSignal(); 1942 assertEquals(MediaPlayerInterface.BUFFERING_STATE_BUFFERING_AND_PLAYABLE, 1943 playerBase.getBufferingState()); 1944 assertEquals(MediaPlayerInterface.PLAYER_STATE_PAUSED, playerBase.getPlayerState()); 1945 1946 playerBase.reset(); 1947 assertEquals(MediaPlayerInterface.BUFFERING_STATE_UNKNOWN, playerBase.getBufferingState()); 1948 assertEquals(MediaPlayerInterface.PLAYER_STATE_IDLE, playerBase.getPlayerState()); 1949 } 1950 1951 @Test 1952 @LargeTest 1953 public void testPlayerEventCallback() throws Throwable { 1954 final int mp4Duration = 8484; 1955 1956 if (!checkLoadResource(R.raw.testvideo)) { 1957 return; // skip; 1958 } 1959 final DataSourceDesc dsd2 = createDataSourceDesc( 1960 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz); 1961 mPlayer.setNextDataSource(dsd2); 1962 1963 mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface()); 1964 1965 final Monitor onDsdChangedCalled = new Monitor(); 1966 final Monitor onPrepareCalled = new Monitor(); 1967 final Monitor onSeekCompleteCalled = new Monitor(); 1968 final Monitor onPlayerStateChangedCalled = new Monitor(); 1969 final AtomicInteger playerState = new AtomicInteger(); 1970 final Monitor onBufferingStateChangedCalled = new Monitor(); 1971 final AtomicInteger bufferingState = new AtomicInteger(); 1972 final Monitor onPlaybackSpeedChanged = new Monitor(); 1973 final AtomicReference<Float> playbackSpeed = new AtomicReference<>(); 1974 1975 PlayerEventCallback callback = new PlayerEventCallback() { 1976 @Override 1977 public void onCurrentDataSourceChanged(MediaPlayerInterface mpb, DataSourceDesc dsd) { 1978 onDsdChangedCalled.signal(); 1979 } 1980 1981 @Override 1982 public void onMediaPrepared(MediaPlayerInterface mpb, DataSourceDesc dsd) { 1983 onPrepareCalled.signal(); 1984 } 1985 1986 @Override 1987 public void onPlayerStateChanged(MediaPlayerInterface mpb, int state) { 1988 playerState.set(state); 1989 onPlayerStateChangedCalled.signal(); 1990 } 1991 1992 @Override 1993 public void onBufferingStateChanged(MediaPlayerInterface mpb, DataSourceDesc dsd, 1994 int state) { 1995 bufferingState.set(state); 1996 onBufferingStateChangedCalled.signal(); 1997 } 1998 1999 @Override 2000 public void onPlaybackSpeedChanged(MediaPlayerInterface mpb, float speed) { 2001 playbackSpeed.set(speed); 2002 onPlaybackSpeedChanged.signal(); 2003 } 2004 2005 @Override 2006 public void onSeekCompleted(MediaPlayerInterface mpb, long position) { 2007 onSeekCompleteCalled.signal(); 2008 } 2009 }; 2010 MediaPlayerInterface basePlayer = mPlayer.getMediaPlayerInterface(); 2011 ExecutorService executor = Executors.newFixedThreadPool(1); 2012 basePlayer.registerPlayerEventCallback(executor, callback); 2013 2014 onPrepareCalled.reset(); 2015 onPlayerStateChangedCalled.reset(); 2016 onBufferingStateChangedCalled.reset(); 2017 basePlayer.prepare(); 2018 do { 2019 assertTrue(onBufferingStateChangedCalled.waitForSignal(1000)); 2020 } while (bufferingState.get() 2021 != MediaPlayerInterface.BUFFERING_STATE_BUFFERING_AND_STARVED); 2022 2023 assertTrue(onPrepareCalled.waitForSignal(1000)); 2024 do { 2025 assertTrue(onPlayerStateChangedCalled.waitForSignal(1000)); 2026 } while (playerState.get() != MediaPlayerInterface.PLAYER_STATE_PAUSED); 2027 do { 2028 assertTrue(onBufferingStateChangedCalled.waitForSignal(1000)); 2029 } while (bufferingState.get() 2030 != MediaPlayerInterface.BUFFERING_STATE_BUFFERING_AND_PLAYABLE); 2031 2032 onSeekCompleteCalled.reset(); 2033 basePlayer.seekTo(mp4Duration >> 1); 2034 onSeekCompleteCalled.waitForSignal(); 2035 2036 onPlaybackSpeedChanged.reset(); 2037 basePlayer.setPlaybackSpeed(0.5f); 2038 do { 2039 assertTrue(onPlaybackSpeedChanged.waitForSignal(1000)); 2040 } while (Math.abs(playbackSpeed.get() - 0.5f) > FLOAT_TOLERANCE); 2041 2042 basePlayer.skipToNext(); 2043 assertTrue(onDsdChangedCalled.waitForSignal(1000)); 2044 2045 basePlayer.reset(); 2046 2047 basePlayer.unregisterPlayerEventCallback(callback); 2048 executor.shutdown(); 2049 } 2050 2051 public void testRecordAndPlay() throws Exception { 2052 if (!hasMicrophone()) { 2053 return; 2054 } 2055 /* FIXME: check the codec exists. 2056 if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_AUDIO_AMR_NB) 2057 || !MediaUtils.checkEncoder(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { 2058 return; // skip 2059 } 2060 */ 2061 File outputFile = new File(Environment.getExternalStorageDirectory(), 2062 "record_and_play.3gp"); 2063 String outputFileLocation = outputFile.getAbsolutePath(); 2064 try { 2065 recordMedia(outputFileLocation); 2066 2067 Uri uri = Uri.parse(outputFileLocation); 2068 MediaPlayer2 mp = MediaPlayer2.create(); 2069 try { 2070 mp.setDataSource(new DataSourceDesc.Builder() 2071 .setDataSource(mContext, uri) 2072 .build()); 2073 mp.prepare(); 2074 Thread.sleep(SLEEP_TIME); 2075 playAndStop(mp); 2076 } finally { 2077 mp.close(); 2078 } 2079 2080 try { 2081 mp = createMediaPlayer2(mContext, uri); 2082 playAndStop(mp); 2083 } finally { 2084 if (mp != null) { 2085 mp.close(); 2086 } 2087 } 2088 2089 try { 2090 mp = createMediaPlayer2(mContext, uri, mActivity.getSurfaceHolder()); 2091 playAndStop(mp); 2092 } finally { 2093 if (mp != null) { 2094 mp.close(); 2095 } 2096 } 2097 } finally { 2098 outputFile.delete(); 2099 } 2100 } 2101 2102 private void playAndStop(MediaPlayer2 mp) throws Exception { 2103 mp.play(); 2104 Thread.sleep(SLEEP_TIME); 2105 mp.reset(); 2106 } 2107 2108 private void recordMedia(String outputFile) throws Exception { 2109 MediaRecorder mr = new MediaRecorder(); 2110 try { 2111 mr.setAudioSource(MediaRecorder.AudioSource.MIC); 2112 mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 2113 mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 2114 mr.setOutputFile(outputFile); 2115 2116 mr.prepare(); 2117 mr.start(); 2118 Thread.sleep(SLEEP_TIME); 2119 mr.stop(); 2120 } finally { 2121 mr.release(); 2122 } 2123 } 2124 2125 private boolean hasMicrophone() { 2126 return mActivity.getPackageManager().hasSystemFeature( 2127 PackageManager.FEATURE_MICROPHONE); 2128 } 2129 2130 // Smoke test playback from a Media2DataSource. 2131 @Test 2132 @LargeTest 2133 public void testPlaybackFromAMedia2DataSource() throws Exception { 2134 final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz; 2135 final int duration = 10000; 2136 2137 /* FIXME: check the codec exists. 2138 if (!MediaUtils.hasCodecsForResource(mContext, resid)) { 2139 return; 2140 } 2141 */ 2142 2143 TestMedia2DataSource dataSource = 2144 TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid)); 2145 // Test returning -1 from getSize() to indicate unknown size. 2146 dataSource.returnFromGetSize(-1); 2147 mPlayer.setDataSource(new DataSourceDesc.Builder() 2148 .setDataSource(dataSource) 2149 .build()); 2150 playLoadedVideo(null, null, -1); 2151 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 2152 2153 // Test pause and restart. 2154 mPlayer.pause(); 2155 Thread.sleep(SLEEP_TIME); 2156 assertFalse(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 2157 2158 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 2159 @Override 2160 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 2161 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 2162 mOnPrepareCalled.signal(); 2163 } 2164 } 2165 2166 @Override 2167 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 2168 if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { 2169 mOnPlayCalled.signal(); 2170 } 2171 } 2172 }; 2173 mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); 2174 2175 mOnPlayCalled.reset(); 2176 mPlayer.play(); 2177 mOnPlayCalled.waitForSignal(); 2178 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 2179 2180 // Test reset. 2181 mPlayer.reset(); 2182 mPlayer.setDataSource(new DataSourceDesc.Builder() 2183 .setDataSource(dataSource) 2184 .build()); 2185 2186 mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); 2187 2188 mOnPrepareCalled.reset(); 2189 mPlayer.prepare(); 2190 mOnPrepareCalled.waitForSignal(); 2191 2192 mOnPlayCalled.reset(); 2193 mPlayer.play(); 2194 mOnPlayCalled.waitForSignal(); 2195 assertTrue(mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING); 2196 2197 // Test seek. Note: the seek position is cached and returned as the 2198 // current position so there's no point in comparing them. 2199 mPlayer.seekTo(duration - SLEEP_TIME, MediaPlayer2.SEEK_PREVIOUS_SYNC); 2200 while (mPlayer.getMediaPlayer2State() == MediaPlayer2.MEDIAPLAYER2_STATE_PLAYING) { 2201 Thread.sleep(SLEEP_TIME); 2202 } 2203 } 2204 2205 @Test 2206 @LargeTest 2207 public void testNullMedia2DataSourceIsRejected() throws Exception { 2208 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 2209 @Override 2210 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 2211 if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { 2212 mCallStatus = status; 2213 mOnPlayCalled.signal(); 2214 } 2215 } 2216 }; 2217 mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); 2218 2219 mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; 2220 mPlayer.setDataSource((DataSourceDesc) null); 2221 mOnPlayCalled.waitForSignal(); 2222 assertTrue(mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR); 2223 } 2224 2225 @Test 2226 @LargeTest 2227 public void testMedia2DataSourceIsClosedOnReset() throws Exception { 2228 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 2229 @Override 2230 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 2231 if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { 2232 mCallStatus = status; 2233 mOnPlayCalled.signal(); 2234 } 2235 } 2236 }; 2237 mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); 2238 2239 TestMedia2DataSource dataSource = new TestMedia2DataSource(new byte[0]); 2240 mPlayer.setDataSource(new DataSourceDesc.Builder() 2241 .setDataSource(dataSource) 2242 .build()); 2243 mOnPlayCalled.waitForSignal(); 2244 mPlayer.reset(); 2245 assertTrue(dataSource.isClosed()); 2246 } 2247 2248 @Test 2249 @LargeTest 2250 public void testPlaybackFailsIfMedia2DataSourceThrows() throws Exception { 2251 final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz; 2252 /* FIXME: check the codec exists. 2253 if (!MediaUtils.hasCodecsForResource(mContext, resid)) { 2254 return; 2255 } 2256 */ 2257 2258 setOnErrorListener(); 2259 TestMedia2DataSource dataSource = 2260 TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid)); 2261 mPlayer.setDataSource(new DataSourceDesc.Builder() 2262 .setDataSource(dataSource) 2263 .build()); 2264 2265 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 2266 @Override 2267 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 2268 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 2269 mOnPrepareCalled.signal(); 2270 } 2271 } 2272 }; 2273 synchronized (mEventCbLock) { 2274 mEventCallbacks.add(ecb); 2275 } 2276 2277 mOnPrepareCalled.reset(); 2278 mPlayer.prepare(); 2279 mOnPrepareCalled.waitForSignal(); 2280 2281 dataSource.throwFromReadAt(); 2282 mPlayer.play(); 2283 assertTrue(mOnErrorCalled.waitForSignal()); 2284 } 2285 2286 @Test 2287 @LargeTest 2288 public void testPlaybackFailsIfMedia2DataSourceReturnsAnError() throws Exception { 2289 final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz; 2290 /* FIXME: check the codec exists. 2291 if (!MediaUtils.hasCodecsForResource(mContext, resid)) { 2292 return; 2293 } 2294 */ 2295 2296 TestMedia2DataSource dataSource = 2297 TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid)); 2298 mPlayer.setDataSource(new DataSourceDesc.Builder() 2299 .setDataSource(dataSource) 2300 .build()); 2301 2302 setOnErrorListener(); 2303 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 2304 @Override 2305 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 2306 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 2307 mOnPrepareCalled.signal(); 2308 } 2309 } 2310 }; 2311 synchronized (mEventCbLock) { 2312 mEventCallbacks.add(ecb); 2313 } 2314 2315 mOnPrepareCalled.reset(); 2316 mPlayer.prepare(); 2317 mOnPrepareCalled.waitForSignal(); 2318 2319 dataSource.returnFromReadAt(-2); 2320 mPlayer.play(); 2321 assertTrue(mOnErrorCalled.waitForSignal()); 2322 } 2323 2324 @Test 2325 @SmallTest 2326 public void testClearPendingCommands() throws Exception { 2327 final Monitor readAllowed = new Monitor(); 2328 Media2DataSource dataSource = new Media2DataSource() { 2329 @Override 2330 public int readAt(long position, byte[] buffer, int offset, int size) 2331 throws IOException { 2332 try { 2333 readAllowed.waitForSignal(); 2334 } catch (InterruptedException e) { 2335 fail(); 2336 } 2337 return -1; 2338 } 2339 2340 @Override 2341 public long getSize() throws IOException { 2342 return -1; // Unknown size 2343 } 2344 2345 @Override 2346 public void close() throws IOException {} 2347 }; 2348 final ArrayDeque<Integer> commandsCompleted = new ArrayDeque<>(); 2349 setOnErrorListener(); 2350 MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { 2351 @Override 2352 public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 2353 if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { 2354 mOnPrepareCalled.signal(); 2355 } 2356 } 2357 2358 @Override 2359 public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { 2360 commandsCompleted.add(what); 2361 } 2362 2363 @Override 2364 public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { 2365 mOnErrorCalled.signal(); 2366 } 2367 }; 2368 synchronized (mEventCbLock) { 2369 mEventCallbacks.add(ecb); 2370 } 2371 2372 mOnPrepareCalled.reset(); 2373 mOnErrorCalled.reset(); 2374 2375 mPlayer.setDataSource(new DataSourceDesc.Builder() 2376 .setDataSource(dataSource) 2377 .build()); 2378 2379 // prepare() will be pending until readAllowed is signaled. 2380 mPlayer.prepare(); 2381 2382 mPlayer.play(); 2383 mPlayer.pause(); 2384 mPlayer.play(); 2385 mPlayer.pause(); 2386 mPlayer.play(); 2387 mPlayer.seekTo(1000); 2388 2389 // Cause a failure on the pending prepare operation. 2390 readAllowed.signal(); 2391 mOnErrorCalled.waitForSignal(); 2392 assertEquals(0, mOnPrepareCalled.getNumSignal()); 2393 assertEquals(1, commandsCompleted.size()); 2394 assertEquals(MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE, 2395 (int) commandsCompleted.peekFirst()); 2396 } 2397} 2398