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 */ 16package android.media.cts; 17 18import com.android.cts.media.R; 19 20import android.content.Context; 21import android.content.pm.PackageManager; 22import android.content.res.AssetFileDescriptor; 23import android.media.AudioManager; 24import android.media.MediaPlayer; 25import android.media.MediaRecorder; 26import android.media.MediaMetadataRetriever; 27import android.media.TimedText; 28import android.media.audiofx.AudioEffect; 29import android.media.audiofx.Visualizer; 30import android.media.cts.MediaPlayerTestBase.Monitor; 31import android.net.Uri; 32import android.os.Environment; 33import android.os.PowerManager; 34import android.os.SystemClock; 35import android.util.Log; 36 37import java.io.File; 38import java.util.StringTokenizer; 39import java.util.UUID; 40import java.util.Vector; 41import java.util.concurrent.CountDownLatch; 42 43/** 44 * Tests for the MediaPlayer API and local video/audio playback. 45 * 46 * The files in res/raw used by testLocalVideo* are (c) copyright 2008, 47 * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons 48 * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/. 49 */ 50public class MediaPlayerTest extends MediaPlayerTestBase { 51 52 private String RECORDED_FILE; 53 private static final String LOG_TAG = "MediaPlayerTest"; 54 55 private static final int RECORDED_VIDEO_WIDTH = 176; 56 private static final int RECORDED_VIDEO_HEIGHT = 144; 57 private static final long RECORDED_DURATION_MS = 3000; 58 private Vector<Integer> mTimedTextTrackIndex = new Vector<Integer>(); 59 private int mSelectedTimedTextIndex; 60 private Monitor mOnTimedTextCalled = new Monitor(); 61 62 private File mOutFile; 63 64 @Override 65 protected void setUp() throws Exception { 66 super.setUp(); 67 RECORDED_FILE = new File(Environment.getExternalStorageDirectory(), 68 "mediaplayer_record.out").getAbsolutePath(); 69 mOutFile = new File(RECORDED_FILE); 70 } 71 72 @Override 73 protected void tearDown() throws Exception { 74 super.tearDown(); 75 if (mOutFile != null && mOutFile.exists()) { 76 mOutFile.delete(); 77 } 78 } 79 public void testPlayNullSource() throws Exception { 80 try { 81 mMediaPlayer.setDataSource((String) null); 82 fail("Null URI was accepted"); 83 } catch (RuntimeException e) { 84 // expected 85 } 86 } 87 88 public void testPlayAudio() throws Exception { 89 final int mp3Duration = 34909; 90 final int tolerance = 70; 91 final int seekDuration = 100; 92 final int resid = R.raw.testmp3_2; 93 94 MediaPlayer mp = MediaPlayer.create(mContext, resid); 95 try { 96 mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 97 mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); 98 99 assertFalse(mp.isPlaying()); 100 mp.start(); 101 assertTrue(mp.isPlaying()); 102 103 assertFalse(mp.isLooping()); 104 mp.setLooping(true); 105 assertTrue(mp.isLooping()); 106 107 assertEquals(mp3Duration, mp.getDuration(), tolerance); 108 int pos = mp.getCurrentPosition(); 109 assertTrue(pos >= 0); 110 assertTrue(pos < mp3Duration - seekDuration); 111 112 mp.seekTo(pos + seekDuration); 113 assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); 114 115 // test pause and restart 116 mp.pause(); 117 Thread.sleep(SLEEP_TIME); 118 assertFalse(mp.isPlaying()); 119 mp.start(); 120 assertTrue(mp.isPlaying()); 121 122 // test stop and restart 123 mp.stop(); 124 mp.reset(); 125 AssetFileDescriptor afd = mResources.openRawResourceFd(resid); 126 mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); 127 afd.close(); 128 mp.prepare(); 129 assertFalse(mp.isPlaying()); 130 mp.start(); 131 assertTrue(mp.isPlaying()); 132 133 // waiting to complete 134 while(mp.isPlaying()) { 135 Thread.sleep(SLEEP_TIME); 136 } 137 } finally { 138 mp.release(); 139 } 140 } 141 142 public void testPlayVideo() throws Exception { 143 playVideoTest(R.raw.testvideo, 352, 288); 144 } 145 146 private void initMediaPlayer(MediaPlayer player) throws Exception { 147 AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.test1m1s); 148 try { 149 player.reset(); 150 player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); 151 player.prepare(); 152 player.seekTo(56000); 153 } finally { 154 afd.close(); 155 } 156 } 157 158 public void testSetNextMediaPlayerWithReset() throws Exception { 159 160 initMediaPlayer(mMediaPlayer); 161 162 try { 163 initMediaPlayer(mMediaPlayer2); 164 mMediaPlayer2.reset(); 165 mMediaPlayer.setNextMediaPlayer(mMediaPlayer2); 166 fail("setNextMediaPlayer() succeeded with unprepared player"); 167 } catch (RuntimeException e) { 168 // expected 169 } finally { 170 mMediaPlayer.reset(); 171 } 172 } 173 174 public void testSetNextMediaPlayerWithRelease() throws Exception { 175 176 initMediaPlayer(mMediaPlayer); 177 178 try { 179 initMediaPlayer(mMediaPlayer2); 180 mMediaPlayer2.release(); 181 mMediaPlayer.setNextMediaPlayer(mMediaPlayer2); 182 fail("setNextMediaPlayer() succeeded with unprepared player"); 183 } catch (RuntimeException e) { 184 // expected 185 } finally { 186 mMediaPlayer.reset(); 187 } 188 } 189 190 public void testSetNextMediaPlayer() throws Exception { 191 initMediaPlayer(mMediaPlayer); 192 193 final Monitor mTestCompleted = new Monitor(); 194 195 Thread timer = new Thread(new Runnable() { 196 197 @Override 198 public void run() { 199 long startTime = SystemClock.elapsedRealtime(); 200 while(true) { 201 SystemClock.sleep(SLEEP_TIME); 202 if (mTestCompleted.isSignalled()) { 203 // done 204 return; 205 } 206 long now = SystemClock.elapsedRealtime(); 207 if ((now - startTime) > 25000) { 208 // We've been running for 25 seconds and still aren't done, so we're stuck 209 // somewhere. Signal ourselves to dump the thread stacks. 210 android.os.Process.sendSignal(android.os.Process.myPid(), 3); 211 SystemClock.sleep(2000); 212 fail("Test is stuck, see ANR stack trace for more info. You may need to" + 213 " create /data/anr first"); 214 return; 215 } 216 } 217 } 218 }); 219 220 timer.start(); 221 222 try { 223 for (int i = 0; i < 3; i++) { 224 225 initMediaPlayer(mMediaPlayer2); 226 mOnCompletionCalled.reset(); 227 mOnInfoCalled.reset(); 228 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 229 @Override 230 public void onCompletion(MediaPlayer mp) { 231 assertEquals(mMediaPlayer, mp); 232 mOnCompletionCalled.signal(); 233 } 234 }); 235 mMediaPlayer2.setOnInfoListener(new MediaPlayer.OnInfoListener() { 236 @Override 237 public boolean onInfo(MediaPlayer mp, int what, int extra) { 238 assertEquals(mMediaPlayer2, mp); 239 if (what == MediaPlayer.MEDIA_INFO_STARTED_AS_NEXT) { 240 mOnInfoCalled.signal(); 241 } 242 return false; 243 } 244 }); 245 246 mMediaPlayer.setNextMediaPlayer(mMediaPlayer2); 247 mMediaPlayer.start(); 248 assertTrue(mMediaPlayer.isPlaying()); 249 assertFalse(mOnCompletionCalled.isSignalled()); 250 assertFalse(mMediaPlayer2.isPlaying()); 251 assertFalse(mOnInfoCalled.isSignalled()); 252 while(mMediaPlayer.isPlaying()) { 253 Thread.sleep(SLEEP_TIME); 254 } 255 // wait a little longer in case the callbacks haven't quite made it through yet 256 Thread.sleep(100); 257 assertTrue(mMediaPlayer2.isPlaying()); 258 assertTrue(mOnCompletionCalled.isSignalled()); 259 assertTrue(mOnInfoCalled.isSignalled()); 260 261 // At this point the 1st player is done, and the 2nd one is playing. 262 // Now swap them, and go through the loop again. 263 MediaPlayer tmp = mMediaPlayer; 264 mMediaPlayer = mMediaPlayer2; 265 mMediaPlayer2 = tmp; 266 } 267 268 // Now test that setNextMediaPlayer(null) works. 1 is still playing, 2 is done 269 mOnCompletionCalled.reset(); 270 mOnInfoCalled.reset(); 271 initMediaPlayer(mMediaPlayer2); 272 mMediaPlayer.setNextMediaPlayer(mMediaPlayer2); 273 274 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 275 @Override 276 public void onCompletion(MediaPlayer mp) { 277 assertEquals(mMediaPlayer, mp); 278 mOnCompletionCalled.signal(); 279 } 280 }); 281 mMediaPlayer2.setOnInfoListener(new MediaPlayer.OnInfoListener() { 282 @Override 283 public boolean onInfo(MediaPlayer mp, int what, int extra) { 284 assertEquals(mMediaPlayer2, mp); 285 if (what == MediaPlayer.MEDIA_INFO_STARTED_AS_NEXT) { 286 mOnInfoCalled.signal(); 287 } 288 return false; 289 } 290 }); 291 assertTrue(mMediaPlayer.isPlaying()); 292 assertFalse(mOnCompletionCalled.isSignalled()); 293 assertFalse(mMediaPlayer2.isPlaying()); 294 assertFalse(mOnInfoCalled.isSignalled()); 295 Thread.sleep(SLEEP_TIME); 296 mMediaPlayer.setNextMediaPlayer(null); 297 while(mMediaPlayer.isPlaying()) { 298 Thread.sleep(SLEEP_TIME); 299 } 300 // wait a little longer in case the callbacks haven't quite made it through yet 301 Thread.sleep(100); 302 assertFalse(mMediaPlayer.isPlaying()); 303 assertFalse(mMediaPlayer2.isPlaying()); 304 assertTrue(mOnCompletionCalled.isSignalled()); 305 assertFalse(mOnInfoCalled.isSignalled()); 306 307 } finally { 308 mMediaPlayer.reset(); 309 mMediaPlayer2.reset(); 310 } 311 mTestCompleted.signal(); 312 313 } 314 315 // The following tests are all a bit flaky, which is why they're retried a 316 // few times in a loop. 317 318 // This test uses one mp3 that is silent but has a strong positive DC offset, 319 // and a second mp3 that is also silent but has a strong negative DC offset. 320 // If the two are played back overlapped, they will cancel each other out, 321 // and result in zeroes being detected. If there is a gap in playback, that 322 // will also result in zeroes being detected. 323 // Note that this test does NOT guarantee that the correct data is played 324 public void testGapless1() throws Exception { 325 flakyTestWrapper(R.raw.monodcpos, R.raw.monodcneg); 326 } 327 328 // This test is similar, but uses two identical m4a files that have some noise 329 // with a strong positive DC offset. This is used to detect if there is 330 // a gap in playback 331 // Note that this test does NOT guarantee that the correct data is played 332 public void testGapless2() throws Exception { 333 flakyTestWrapper(R.raw.stereonoisedcpos, R.raw.stereonoisedcpos); 334 } 335 336 // same as above, but with a mono file 337 public void testGapless3() throws Exception { 338 flakyTestWrapper(R.raw.mononoisedcpos, R.raw.mononoisedcpos); 339 } 340 341 private void flakyTestWrapper(int resid1, int resid2) throws Exception { 342 boolean success = false; 343 // test usually succeeds within a few tries, but occasionally may fail 344 // many times in a row, so be aggressive and try up to 20 times 345 for (int i = 0; i < 20 && !success; i++) { 346 try { 347 testGapless(resid1, resid2); 348 success = true; 349 } catch (Throwable t) { 350 SystemClock.sleep(1000); 351 } 352 } 353 // Try one more time. If this succeeds, we'll consider the test a success, 354 // otherwise the exception gets thrown 355 if (!success) { 356 testGapless(resid1, resid2); 357 } 358 } 359 360 private void testGapless(int resid1, int resid2) throws Exception { 361 362 MediaPlayer mp1 = new MediaPlayer(); 363 mp1.setAudioStreamType(AudioManager.STREAM_MUSIC); 364 try { 365 AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid1); 366 mp1.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); 367 afd.close(); 368 mp1.prepare(); 369 } catch (Exception e) { 370 assertTrue(false); 371 } 372 int session = mp1.getAudioSessionId(); 373 374 MediaPlayer mp2 = new MediaPlayer(); 375 mp2.setAudioSessionId(session); 376 mp2.setAudioStreamType(AudioManager.STREAM_MUSIC); 377 try { 378 AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid2); 379 mp2.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); 380 afd.close(); 381 mp2.prepare(); 382 } catch (Exception e) { 383 assertTrue(false); 384 } 385 // creating a volume controller on output mix ensures that ro.audio.silent mutes 386 // audio after the effects and not before 387 AudioEffect vc = new AudioEffect( 388 AudioEffect.EFFECT_TYPE_NULL, 389 UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"), 390 0, 391 session); 392 vc.setEnabled(true); 393 int captureintervalms = mp1.getDuration() + mp2.getDuration() - 2000; 394 int size = 256; 395 int[] range = Visualizer.getCaptureSizeRange(); 396 if (size < range[0]) { 397 size = range[0]; 398 } 399 if (size > range[1]) { 400 size = range[1]; 401 } 402 byte [] vizdata = new byte[size]; 403 Visualizer vis = new Visualizer(session); 404 assertTrue(vis.setCaptureSize(vizdata.length) == Visualizer.SUCCESS); 405 assertTrue(vis.setEnabled(true) == Visualizer.SUCCESS); 406 AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 407 int oldRingerMode = am.getRingerMode(); 408 am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); 409 int oldvolume = am.getStreamVolume(AudioManager.STREAM_MUSIC); 410 am.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0); 411 try { 412 mp1.setNextMediaPlayer(mp2); 413 mp1.start(); 414 assertTrue(mp1.isPlaying()); 415 assertFalse(mp2.isPlaying()); 416 // allow playback to get started 417 Thread.sleep(SLEEP_TIME); 418 long start = SystemClock.elapsedRealtime(); 419 // there should be no consecutive zeroes (-128) in the capture buffer 420 // when going to the next file. If silence is detected right away, then 421 // the volume is probably turned all the way down (visualizer data 422 // is captured after volume adjustment). 423 boolean first = true; 424 while((SystemClock.elapsedRealtime() - start) < captureintervalms) { 425 assertTrue(vis.getWaveForm(vizdata) == Visualizer.SUCCESS); 426 for (int i = 0; i < vizdata.length - 1; i++) { 427 if (vizdata[i] == -128 && vizdata[i + 1] == -128) { 428 if (first) { 429 fail("silence detected, please increase volume and rerun test"); 430 } else { 431 fail("gap or overlap detected at t=" + 432 (SLEEP_TIME + SystemClock.elapsedRealtime() - start) + 433 ", offset " + i); 434 } 435 break; 436 } 437 } 438 first = false; 439 } 440 } finally { 441 mp1.release(); 442 mp2.release(); 443 vis.release(); 444 vc.release(); 445 am.setRingerMode(oldRingerMode); 446 am.setStreamVolume(AudioManager.STREAM_MUSIC, oldvolume, 0); 447 } 448 } 449 450 /** 451 * Test for reseting a surface during video playback 452 * After reseting, the video should continue playing 453 * from the time setDisplay() was called 454 */ 455 public void testVideoSurfaceResetting() throws Exception { 456 final int tolerance = 150; 457 final int audioLatencyTolerance = 1000; /* covers audio path latency variability */ 458 final int seekPos = 5000; 459 460 final CountDownLatch seekDone = new CountDownLatch(1); 461 462 mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() { 463 @Override 464 public void onSeekComplete(MediaPlayer mp) { 465 seekDone.countDown(); 466 } 467 }); 468 469 loadResource(R.raw.testvideo); 470 playLoadedVideo(352, 288, -1); 471 472 Thread.sleep(SLEEP_TIME); 473 474 int posBefore = mMediaPlayer.getCurrentPosition(); 475 mMediaPlayer.setDisplay(getActivity().getSurfaceHolder2()); 476 int posAfter = mMediaPlayer.getCurrentPosition(); 477 478 assertEquals(posAfter, posBefore, tolerance); 479 assertTrue(mMediaPlayer.isPlaying()); 480 481 Thread.sleep(SLEEP_TIME); 482 483 mMediaPlayer.seekTo(seekPos); 484 seekDone.await(); 485 posAfter = mMediaPlayer.getCurrentPosition(); 486 assertEquals(seekPos, posAfter, tolerance + audioLatencyTolerance); 487 488 Thread.sleep(SLEEP_TIME / 2); 489 posBefore = mMediaPlayer.getCurrentPosition(); 490 mMediaPlayer.setDisplay(null); 491 posAfter = mMediaPlayer.getCurrentPosition(); 492 assertEquals(posAfter, posBefore, tolerance); 493 assertTrue(mMediaPlayer.isPlaying()); 494 495 Thread.sleep(SLEEP_TIME); 496 497 posBefore = mMediaPlayer.getCurrentPosition(); 498 mMediaPlayer.setDisplay(getActivity().getSurfaceHolder()); 499 posAfter = mMediaPlayer.getCurrentPosition(); 500 501 assertEquals(posAfter, posBefore, tolerance); 502 assertTrue(mMediaPlayer.isPlaying()); 503 504 Thread.sleep(SLEEP_TIME); 505 } 506 507 public void testRecordedVideoPlayback0() throws Exception { 508 testRecordedVideoPlaybackWithAngle(0); 509 } 510 511 public void testRecordedVideoPlayback90() throws Exception { 512 testRecordedVideoPlaybackWithAngle(90); 513 } 514 515 public void testRecordedVideoPlayback180() throws Exception { 516 testRecordedVideoPlaybackWithAngle(180); 517 } 518 519 public void testRecordedVideoPlayback270() throws Exception { 520 testRecordedVideoPlaybackWithAngle(270); 521 } 522 523 private boolean hasCamera() { 524 return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); 525 } 526 527 private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception { 528 final int width = RECORDED_VIDEO_WIDTH; 529 final int height = RECORDED_VIDEO_HEIGHT; 530 final String file = RECORDED_FILE; 531 final long durationMs = RECORDED_DURATION_MS; 532 533 if (!hasCamera()) { 534 return; 535 } 536 checkOrientation(angle); 537 recordVideo(width, height, angle, file, durationMs); 538 checkDisplayedVideoSize(width, height, angle, file); 539 checkVideoRotationAngle(angle, file); 540 } 541 542 private void checkOrientation(int angle) throws Exception { 543 assertTrue(angle >= 0); 544 assertTrue(angle < 360); 545 assertTrue((angle % 90) == 0); 546 } 547 548 private void recordVideo( 549 int w, int h, int angle, String file, long durationMs) throws Exception { 550 551 MediaRecorder recorder = new MediaRecorder(); 552 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 553 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 554 recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); 555 recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); 556 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); 557 recorder.setOutputFile(file); 558 recorder.setOrientationHint(angle); 559 recorder.setVideoSize(w, h); 560 recorder.setPreviewDisplay(getActivity().getSurfaceHolder2().getSurface()); 561 recorder.prepare(); 562 recorder.start(); 563 Thread.sleep(durationMs); 564 recorder.stop(); 565 recorder.release(); 566 recorder = null; 567 } 568 569 private void checkDisplayedVideoSize( 570 int w, int h, int angle, String file) throws Exception { 571 572 int displayWidth = w; 573 int displayHeight = h; 574 if ((angle % 180) != 0) { 575 displayWidth = h; 576 displayHeight = w; 577 } 578 playVideoTest(file, displayWidth, displayHeight); 579 } 580 581 private void checkVideoRotationAngle(int angle, String file) { 582 MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 583 retriever.setDataSource(file); 584 String rotation = retriever.extractMetadata( 585 MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); 586 retriever.release(); 587 retriever = null; 588 assertNotNull(rotation); 589 assertEquals(Integer.parseInt(rotation), angle); 590 } 591 592 public void testLocalVideo_MP4_H264_480x360_500kbps_25fps_AAC_Stereo_128kbps_44110Hz() 593 throws Exception { 594 playVideoTest( 595 R.raw.video_480x360_mp4_h264_500kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); 596 } 597 598 public void testLocalVideo_MP4_H264_480x360_500kbps_30fps_AAC_Stereo_128kbps_44110Hz() 599 throws Exception { 600 playVideoTest( 601 R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); 602 } 603 604 public void testLocalVideo_MP4_H264_480x360_1000kbps_25fps_AAC_Stereo_128kbps_44110Hz() 605 throws Exception { 606 playVideoTest( 607 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); 608 } 609 610 public void testLocalVideo_MP4_H264_480x360_1000kbps_30fps_AAC_Stereo_128kbps_44110Hz() 611 throws Exception { 612 playVideoTest( 613 R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); 614 } 615 616 public void testLocalVideo_MP4_H264_480x360_1350kbps_25fps_AAC_Stereo_128kbps_44110Hz() 617 throws Exception { 618 playVideoTest( 619 R.raw.video_480x360_mp4_h264_1350kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); 620 } 621 622 public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz() 623 throws Exception { 624 playVideoTest( 625 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); 626 } 627 628 public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_192kbps_44110Hz() 629 throws Exception { 630 playVideoTest( 631 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz, 480, 360); 632 } 633 634 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_11025Hz() 635 throws Exception { 636 playVideoTest( 637 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_11025hz, 176, 144); 638 } 639 640 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_22050Hz() 641 throws Exception { 642 playVideoTest( 643 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_22050hz, 176, 144); 644 } 645 646 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_11025Hz() 647 throws Exception { 648 playVideoTest( 649 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 650 } 651 652 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_22050Hz() 653 throws Exception { 654 playVideoTest( 655 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 656 } 657 658 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_11025Hz() 659 throws Exception { 660 playVideoTest( 661 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 662 } 663 664 public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_22050Hz() 665 throws Exception { 666 playVideoTest( 667 R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 668 } 669 670 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_11025Hz() 671 throws Exception { 672 playVideoTest( 673 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_11025hz, 176, 144); 674 } 675 676 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_22050Hz() 677 throws Exception { 678 playVideoTest( 679 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_22050hz, 176, 144); 680 } 681 682 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_11025Hz() 683 throws Exception { 684 playVideoTest( 685 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 686 } 687 688 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_22050Hz() 689 throws Exception { 690 playVideoTest( 691 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 692 } 693 694 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_11025Hz() 695 throws Exception { 696 playVideoTest( 697 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); 698 } 699 700 public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_22050Hz() 701 throws Exception { 702 playVideoTest( 703 R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); 704 } 705 706 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_11025Hz() 707 throws Exception { 708 playVideoTest( 709 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz, 176, 144); 710 } 711 712 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_22050Hz() 713 throws Exception { 714 playVideoTest( 715 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_22050hz, 176, 144); 716 } 717 718 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_11025Hz() 719 throws Exception { 720 playVideoTest( 721 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 722 } 723 724 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_22050Hz() 725 throws Exception { 726 playVideoTest( 727 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); 728 } 729 730 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_11025Hz() 731 throws Exception { 732 playVideoTest( 733 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 734 } 735 736 public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_22050Hz() 737 throws Exception { 738 playVideoTest( 739 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); 740 } 741 742 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_11025Hz() 743 throws Exception { 744 playVideoTest( 745 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_11025hz, 176, 144); 746 } 747 748 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_22050Hz() 749 throws Exception { 750 playVideoTest( 751 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_22050hz, 176, 144); 752 } 753 754 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_11025Hz() 755 throws Exception { 756 playVideoTest( 757 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 758 } 759 760 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_22050Hz() 761 throws Exception { 762 playVideoTest( 763 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); 764 } 765 766 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_11025Hz() 767 throws Exception { 768 playVideoTest( 769 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); 770 } 771 772 public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_22050Hz() 773 throws Exception { 774 playVideoTest( 775 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_22050hz, 176, 144); 776 } 777 778 private void readTimedTextTracks() throws Exception { 779 mTimedTextTrackIndex.clear(); 780 MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo(); 781 if (trackInfos == null || trackInfos.length == 0) { 782 return; 783 } 784 for (int i = 0; i < trackInfos.length; ++i) { 785 assertTrue(trackInfos[i] != null); 786 if (trackInfos[i].getTrackType() == 787 MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) { 788 mTimedTextTrackIndex.add(i); 789 } 790 } 791 } 792 793 private int getTimedTextTrackCount() { 794 return mTimedTextTrackIndex.size(); 795 } 796 797 private void selectSubtitleTrack(int index) throws Exception { 798 int trackIndex = mTimedTextTrackIndex.get(index); 799 mMediaPlayer.selectTrack(trackIndex); 800 mSelectedTimedTextIndex = index; 801 } 802 803 private void deselectSubtitleTrack(int index) throws Exception { 804 int trackIndex = mTimedTextTrackIndex.get(index); 805 mMediaPlayer.deselectTrack(trackIndex); 806 if (mSelectedTimedTextIndex == index) { 807 mSelectedTimedTextIndex = -1; 808 } 809 } 810 811 public void testDeselectTrack() throws Exception { 812 loadResource(R.raw.testvideo_with_2_subtitles); 813 loadSubtitleSource(R.raw.test_subtitle1_srt); 814 readTimedTextTracks(); 815 assertEquals(getTimedTextTrackCount(), 3); 816 817 mMediaPlayer.setDisplay(getActivity().getSurfaceHolder()); 818 mMediaPlayer.setScreenOnWhilePlaying(true); 819 mMediaPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); 820 mMediaPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() { 821 @Override 822 public void onTimedText(MediaPlayer mp, TimedText text) { 823 if (text != null) { 824 String plainText = text.getText(); 825 if (plainText != null) { 826 mOnTimedTextCalled.signal(); 827 Log.d(LOG_TAG, "text: " + plainText.trim()); 828 } 829 } 830 } 831 }); 832 mMediaPlayer.prepare(); 833 mMediaPlayer.start(); 834 assertTrue(mMediaPlayer.isPlaying()); 835 836 // Run twice to check if repeated selection-deselection on the same track works well. 837 for (int i = 0; i < 2; i++) { 838 // Waits until at least one subtitle is fired. Timeout is 1 sec. 839 selectSubtitleTrack(0); 840 mOnTimedTextCalled.reset(); 841 assertTrue(mOnTimedTextCalled.waitForSignal(1000)); 842 843 // Try deselecting track. 844 deselectSubtitleTrack(0); 845 mOnTimedTextCalled.reset(); 846 assertFalse(mOnTimedTextCalled.waitForSignal(1000)); 847 } 848 849 // Run the same test for external subtitle track. 850 for (int i = 0; i < 2; i++) { 851 selectSubtitleTrack(2); 852 mOnTimedTextCalled.reset(); 853 assertTrue(mOnTimedTextCalled.waitForSignal(1000)); 854 855 // Try deselecting track. 856 deselectSubtitleTrack(2); 857 mOnTimedTextCalled.reset(); 858 assertFalse(mOnTimedTextCalled.waitForSignal(1000)); 859 } 860 861 try { 862 deselectSubtitleTrack(0); 863 fail("Deselecting unselected track: expected RuntimeException, " + 864 "but no exception has been triggered."); 865 } catch (RuntimeException e) { 866 // expected 867 } 868 869 mMediaPlayer.stop(); 870 } 871 872 public void testChangeSubtitleTrack() throws Exception { 873 loadResource(R.raw.testvideo_with_2_subtitles); 874 readTimedTextTracks(); 875 assertEquals(getTimedTextTrackCount(), 2); 876 877 // Adds two more external subtitle files. 878 loadSubtitleSource(R.raw.test_subtitle1_srt); 879 loadSubtitleSource(R.raw.test_subtitle2_srt); 880 readTimedTextTracks(); 881 assertEquals(getTimedTextTrackCount(), 4); 882 883 mMediaPlayer.setDisplay(getActivity().getSurfaceHolder()); 884 mMediaPlayer.setScreenOnWhilePlaying(true); 885 mMediaPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); 886 mMediaPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() { 887 @Override 888 public void onTimedText(MediaPlayer mp, TimedText text) { 889 final int toleranceMs = 100; 890 final int durationMs = 500; 891 int posMs = mMediaPlayer.getCurrentPosition(); 892 if (text != null) { 893 String plainText = text.getText(); 894 if (plainText != null) { 895 StringTokenizer tokens = new StringTokenizer(plainText.trim(), ":"); 896 int subtitleTrackIndex = Integer.parseInt(tokens.nextToken()); 897 int startMs = Integer.parseInt(tokens.nextToken()); 898 Log.d(LOG_TAG, "text: " + plainText.trim() + 899 ", trackId: " + subtitleTrackIndex + ", posMs: " + posMs); 900 assertTrue("The diff between subtitle's start time " + startMs + 901 " and current time " + posMs + 902 " is over tolerance " + toleranceMs, 903 (posMs >= startMs - toleranceMs) && 904 (posMs < startMs + durationMs + toleranceMs) ); 905 assertEquals("Expected track: " + mSelectedTimedTextIndex + 906 ", actual track: " + subtitleTrackIndex, 907 mSelectedTimedTextIndex, subtitleTrackIndex); 908 mOnTimedTextCalled.signal(); 909 } 910 } 911 } 912 }); 913 914 mMediaPlayer.prepare(); 915 assertFalse(mMediaPlayer.isPlaying()); 916 917 selectSubtitleTrack(0); 918 mOnTimedTextCalled.reset(); 919 920 mMediaPlayer.start(); 921 assertTrue(mMediaPlayer.isPlaying()); 922 923 // Waits until at least two subtitles are fired. Timeout is 2 sec. 924 // Please refer the test srt files: 925 // test_subtitle1_srt.3gp and test_subtitle2_srt.3gp 926 assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2000) >= 2); 927 928 selectSubtitleTrack(1); 929 mOnTimedTextCalled.reset(); 930 assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2000) >= 2); 931 932 selectSubtitleTrack(2); 933 mOnTimedTextCalled.reset(); 934 assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2000) >= 2); 935 936 selectSubtitleTrack(3); 937 mOnTimedTextCalled.reset(); 938 assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2000) >= 2); 939 mMediaPlayer.stop(); 940 } 941 942 public void testGetTrackInfo() throws Exception { 943 loadResource(R.raw.testvideo_with_2_subtitles); 944 loadSubtitleSource(R.raw.test_subtitle1_srt); 945 loadSubtitleSource(R.raw.test_subtitle2_srt); 946 mMediaPlayer.prepare(); 947 mMediaPlayer.start(); 948 949 readTimedTextTracks(); 950 selectSubtitleTrack(2); 951 952 int count = 0; 953 MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo(); 954 assertTrue(trackInfos != null && trackInfos.length != 0); 955 for (int i = 0; i < trackInfos.length; ++i) { 956 assertTrue(trackInfos[i] != null); 957 if (trackInfos[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) { 958 String trackLanguage = trackInfos[i].getLanguage(); 959 assertTrue(trackLanguage != null); 960 trackLanguage.trim(); 961 Log.d(LOG_TAG, "track info lang: " + trackLanguage); 962 assertTrue("Should not see empty track language with our test data.", 963 trackLanguage.length() > 0); 964 count++; 965 } 966 } 967 // There are 4 subtitle tracks in total in our test data. 968 assertEquals(4, count); 969 } 970 971 public void testCallback() throws Throwable { 972 final int mp4Duration = 8484; 973 974 loadResource(R.raw.testvideo); 975 mMediaPlayer.setDisplay(getActivity().getSurfaceHolder()); 976 mMediaPlayer.setScreenOnWhilePlaying(true); 977 978 mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() { 979 @Override 980 public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 981 mOnVideoSizeChangedCalled.signal(); 982 } 983 }); 984 985 mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 986 @Override 987 public void onPrepared(MediaPlayer mp) { 988 mOnPrepareCalled.signal(); 989 } 990 }); 991 992 mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() { 993 @Override 994 public void onSeekComplete(MediaPlayer mp) { 995 mOnSeekCompleteCalled.signal(); 996 } 997 }); 998 999 mOnCompletionCalled.reset(); 1000 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 1001 @Override 1002 public void onCompletion(MediaPlayer mp) { 1003 mOnCompletionCalled.signal(); 1004 } 1005 }); 1006 1007 mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 1008 @Override 1009 public boolean onError(MediaPlayer mp, int what, int extra) { 1010 mOnErrorCalled.signal(); 1011 return false; 1012 } 1013 }); 1014 1015 mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() { 1016 @Override 1017 public boolean onInfo(MediaPlayer mp, int what, int extra) { 1018 mOnInfoCalled.signal(); 1019 return false; 1020 } 1021 }); 1022 1023 assertFalse(mOnPrepareCalled.isSignalled()); 1024 assertFalse(mOnVideoSizeChangedCalled.isSignalled()); 1025 mMediaPlayer.prepare(); 1026 mOnPrepareCalled.waitForSignal(); 1027 mOnVideoSizeChangedCalled.waitForSignal(); 1028 mOnSeekCompleteCalled.reset(); 1029 mMediaPlayer.seekTo(mp4Duration >> 1); 1030 mOnSeekCompleteCalled.waitForSignal(); 1031 assertFalse(mOnCompletionCalled.isSignalled()); 1032 mMediaPlayer.start(); 1033 while(mMediaPlayer.isPlaying()) { 1034 Thread.sleep(SLEEP_TIME); 1035 } 1036 assertFalse(mMediaPlayer.isPlaying()); 1037 mOnCompletionCalled.waitForSignal(); 1038 assertFalse(mOnErrorCalled.isSignalled()); 1039 mMediaPlayer.stop(); 1040 mMediaPlayer.start(); 1041 mOnErrorCalled.waitForSignal(); 1042 } 1043 1044 public void testRecordAndPlay() throws Exception { 1045 if (!hasMicrophone()) { 1046 return; 1047 } 1048 File outputFile = new File(Environment.getExternalStorageDirectory(), 1049 "record_and_play.3gp"); 1050 String outputFileLocation = outputFile.getAbsolutePath(); 1051 try { 1052 recordMedia(outputFileLocation); 1053 MediaPlayer mp = new MediaPlayer(); 1054 try { 1055 mp.setDataSource(outputFileLocation); 1056 mp.prepareAsync(); 1057 Thread.sleep(SLEEP_TIME); 1058 playAndStop(mp); 1059 } finally { 1060 mp.release(); 1061 } 1062 1063 Uri uri = Uri.parse(outputFileLocation); 1064 mp = new MediaPlayer(); 1065 try { 1066 mp.setDataSource(mContext, uri); 1067 mp.prepareAsync(); 1068 Thread.sleep(SLEEP_TIME); 1069 playAndStop(mp); 1070 } finally { 1071 mp.release(); 1072 } 1073 1074 try { 1075 mp = MediaPlayer.create(mContext, uri); 1076 playAndStop(mp); 1077 } finally { 1078 if (mp != null) { 1079 mp.release(); 1080 } 1081 } 1082 1083 try { 1084 mp = MediaPlayer.create(mContext, uri, getActivity().getSurfaceHolder()); 1085 playAndStop(mp); 1086 } finally { 1087 if (mp != null) { 1088 mp.release(); 1089 } 1090 } 1091 } finally { 1092 outputFile.delete(); 1093 } 1094 } 1095 1096 private void playAndStop(MediaPlayer mp) throws Exception { 1097 mp.start(); 1098 Thread.sleep(SLEEP_TIME); 1099 mp.stop(); 1100 } 1101 1102 private void recordMedia(String outputFile) throws Exception { 1103 MediaRecorder mr = new MediaRecorder(); 1104 try { 1105 mr.setAudioSource(MediaRecorder.AudioSource.MIC); 1106 mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 1107 mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 1108 mr.setOutputFile(outputFile); 1109 1110 mr.prepare(); 1111 mr.start(); 1112 Thread.sleep(SLEEP_TIME); 1113 mr.stop(); 1114 } finally { 1115 mr.release(); 1116 } 1117 } 1118 1119 private boolean hasMicrophone() { 1120 return getActivity().getPackageManager().hasSystemFeature( 1121 PackageManager.FEATURE_MICROPHONE); 1122 } 1123} 1124