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