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