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