Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.media.cts;
     17 
     18 import android.content.Context;
     19 import android.content.pm.PackageManager;
     20 import android.content.res.AssetFileDescriptor;
     21 import android.content.res.Resources;
     22 import android.cts.util.MediaUtils;
     23 import android.media.MediaPlayer;
     24 import android.test.ActivityInstrumentationTestCase2;
     25 
     26 import java.io.IOException;
     27 import java.util.logging.Logger;
     28 
     29 /**
     30  * Base class for tests which use MediaPlayer to play audio or video.
     31  */
     32 public class MediaPlayerTestBase extends ActivityInstrumentationTestCase2<MediaStubActivity> {
     33     private static final Logger LOG = Logger.getLogger(MediaPlayerTestBase.class.getName());
     34 
     35     protected static final int SLEEP_TIME = 1000;
     36     protected static final int LONG_SLEEP_TIME = 6000;
     37     protected static final int STREAM_RETRIES = 20;
     38     protected static boolean sUseScaleToFitMode = false;
     39 
     40     public static class Monitor {
     41         private int numSignal;
     42 
     43         public synchronized void reset() {
     44             numSignal = 0;
     45         }
     46 
     47         public synchronized void signal() {
     48             numSignal++;
     49             notifyAll();
     50         }
     51 
     52         public synchronized boolean waitForSignal() throws InterruptedException {
     53             return waitForCountedSignals(1) > 0;
     54         }
     55 
     56         public synchronized int waitForCountedSignals(int targetCount) throws InterruptedException {
     57             while (numSignal < targetCount) {
     58                 wait();
     59             }
     60             return numSignal;
     61         }
     62 
     63         public synchronized boolean waitForSignal(long timeoutMs) throws InterruptedException {
     64             return waitForCountedSignals(1, timeoutMs) > 0;
     65         }
     66 
     67         public synchronized int waitForCountedSignals(int targetCount, long timeoutMs)
     68                 throws InterruptedException {
     69             if (timeoutMs == 0) {
     70                 return waitForCountedSignals(targetCount);
     71             }
     72             long deadline = System.currentTimeMillis() + timeoutMs;
     73             while (numSignal < targetCount) {
     74                 long delay = deadline - System.currentTimeMillis();
     75                 if (delay <= 0) {
     76                     break;
     77                 }
     78                 wait(delay);
     79             }
     80             return numSignal;
     81         }
     82 
     83         public synchronized boolean isSignalled() {
     84             return numSignal >= 1;
     85         }
     86 
     87         public synchronized int getNumSignal() {
     88             return numSignal;
     89         }
     90     }
     91 
     92     protected Monitor mOnVideoSizeChangedCalled = new Monitor();
     93     protected Monitor mOnVideoRenderingStartCalled = new Monitor();
     94     protected Monitor mOnBufferingUpdateCalled = new Monitor();
     95     protected Monitor mOnPrepareCalled = new Monitor();
     96     protected Monitor mOnSeekCompleteCalled = new Monitor();
     97     protected Monitor mOnCompletionCalled = new Monitor();
     98     protected Monitor mOnInfoCalled = new Monitor();
     99     protected Monitor mOnErrorCalled = new Monitor();
    100 
    101     protected Context mContext;
    102     protected Resources mResources;
    103 
    104 
    105     protected MediaPlayer mMediaPlayer = null;
    106     protected MediaPlayer mMediaPlayer2 = null;
    107     protected MediaStubActivity mActivity;
    108 
    109     public MediaPlayerTestBase() {
    110         super(MediaStubActivity.class);
    111     }
    112 
    113     @Override
    114     protected void setUp() throws Exception {
    115         super.setUp();
    116         mActivity = getActivity();
    117         getInstrumentation().waitForIdleSync();
    118         try {
    119             runTestOnUiThread(new Runnable() {
    120                 public void run() {
    121                     mMediaPlayer = new MediaPlayer();
    122                     mMediaPlayer2 = new MediaPlayer();
    123                 }
    124             });
    125         } catch (Throwable e) {
    126             e.printStackTrace();
    127             fail();
    128         }
    129         mContext = getInstrumentation().getTargetContext();
    130         mResources = mContext.getResources();
    131     }
    132 
    133     @Override
    134     protected void tearDown() throws Exception {
    135         if (mMediaPlayer != null) {
    136             mMediaPlayer.release();
    137             mMediaPlayer = null;
    138         }
    139         if (mMediaPlayer2 != null) {
    140             mMediaPlayer2.release();
    141             mMediaPlayer2 = null;
    142         }
    143         mActivity = null;
    144         super.tearDown();
    145     }
    146 
    147     // returns true on success
    148     protected boolean loadResource(int resid) throws Exception {
    149         if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
    150             return false;
    151         }
    152 
    153         AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
    154         try {
    155             mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
    156                     afd.getLength());
    157 
    158             // Although it is only meant for video playback, it should not
    159             // cause issues for audio-only playback.
    160             int videoScalingMode = sUseScaleToFitMode?
    161                                     MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT
    162                                   : MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING;
    163 
    164             mMediaPlayer.setVideoScalingMode(videoScalingMode);
    165         } finally {
    166             afd.close();
    167         }
    168         sUseScaleToFitMode = !sUseScaleToFitMode;  // Alternate the scaling mode
    169         return true;
    170     }
    171 
    172     protected boolean checkLoadResource(int resid) throws Exception {
    173         return MediaUtils.check(loadResource(resid), "no decoder found");
    174     }
    175 
    176     protected void loadSubtitleSource(int resid) throws Exception {
    177         AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
    178         try {
    179             mMediaPlayer.addTimedTextSource(afd.getFileDescriptor(), afd.getStartOffset(),
    180                       afd.getLength(), MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP);
    181         } finally {
    182             afd.close();
    183         }
    184     }
    185 
    186     protected void playLiveVideoTest(String path, int playTime) throws Exception {
    187         playVideoWithRetries(path, null, null, playTime);
    188     }
    189 
    190     protected void playVideoTest(String path, int width, int height) throws Exception {
    191         playVideoWithRetries(path, width, height, 0);
    192     }
    193 
    194     protected void playVideoWithRetries(String path, Integer width, Integer height, int playTime)
    195             throws Exception {
    196         boolean playedSuccessfully = false;
    197         for (int i = 0; i < STREAM_RETRIES; i++) {
    198           try {
    199             mMediaPlayer.setDataSource(path);
    200             playLoadedVideo(width, height, playTime);
    201             playedSuccessfully = true;
    202             break;
    203           } catch (PrepareFailedException e) {
    204             // prepare() can fail because of network issues, so try again
    205             LOG.warning("prepare() failed on try " + i + ", trying playback again");
    206           }
    207         }
    208         assertTrue("Stream did not play successfully after all attempts", playedSuccessfully);
    209     }
    210 
    211     protected void playVideoTest(int resid, int width, int height) throws Exception {
    212         if (!checkLoadResource(resid)) {
    213             return; // skip
    214         }
    215 
    216         playLoadedVideo(width, height, 0);
    217     }
    218 
    219     /**
    220      * Play a video which has already been loaded with setDataSource().
    221      *
    222      * @param width width of the video to verify, or null to skip verification
    223      * @param height height of the video to verify, or null to skip verification
    224      * @param playTime length of time to play video, or 0 to play entire video.
    225      * with a non-negative value, this method stops the playback after the length of
    226      * time or the duration the video is elapsed. With a value of -1,
    227      * this method simply starts the video and returns immediately without
    228      * stoping the video playback.
    229      */
    230     protected void playLoadedVideo(final Integer width, final Integer height, int playTime)
    231             throws Exception {
    232         final float leftVolume = 0.5f;
    233         final float rightVolume = 0.5f;
    234 
    235         mMediaPlayer.setDisplay(mActivity.getSurfaceHolder());
    236         mMediaPlayer.setScreenOnWhilePlaying(true);
    237         mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
    238             @Override
    239             public void onVideoSizeChanged(MediaPlayer mp, int w, int h) {
    240                 if (w == 0 && h == 0) {
    241                     // A size of 0x0 can be sent initially one time when using NuPlayer.
    242                     assertFalse(mOnVideoSizeChangedCalled.isSignalled());
    243                     return;
    244                 }
    245                 mOnVideoSizeChangedCalled.signal();
    246                 if (width != null) {
    247                     assertEquals(width.intValue(), w);
    248                 }
    249                 if (height != null) {
    250                     assertEquals(height.intValue(), h);
    251                 }
    252             }
    253         });
    254         mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    255             @Override
    256             public boolean onError(MediaPlayer mp, int what, int extra) {
    257                 fail("Media player had error " + what + " playing video");
    258                 return true;
    259             }
    260         });
    261         mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
    262             @Override
    263             public boolean onInfo(MediaPlayer mp, int what, int extra) {
    264                 if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
    265                     mOnVideoRenderingStartCalled.signal();
    266                 }
    267                 return true;
    268             }
    269         });
    270         try {
    271           mMediaPlayer.prepare();
    272         } catch (IOException e) {
    273           mMediaPlayer.reset();
    274           throw new PrepareFailedException();
    275         }
    276 
    277         mMediaPlayer.start();
    278         mOnVideoSizeChangedCalled.waitForSignal();
    279         mOnVideoRenderingStartCalled.waitForSignal();
    280         mMediaPlayer.setVolume(leftVolume, rightVolume);
    281 
    282         // waiting to complete
    283         if (playTime == -1) {
    284             return;
    285         } else if (playTime == 0) {
    286             while (mMediaPlayer.isPlaying()) {
    287                 Thread.sleep(SLEEP_TIME);
    288             }
    289         } else {
    290             Thread.sleep(playTime);
    291         }
    292         mMediaPlayer.stop();
    293     }
    294 
    295     private static class PrepareFailedException extends Exception {}
    296 
    297     public boolean isTv() {
    298         PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
    299         return pm.hasSystemFeature(pm.FEATURE_TELEVISION)
    300                 && pm.hasSystemFeature(pm.FEATURE_LEANBACK);
    301     }
    302 
    303     public boolean checkTv() {
    304         return MediaUtils.check(isTv(), "not a TV");
    305     }
    306 
    307     protected void setOnErrorListener() {
    308         mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    309             @Override
    310             public boolean onError(MediaPlayer mp, int what, int extra) {
    311                 mOnErrorCalled.signal();
    312                 return false;
    313             }
    314         });
    315     }
    316 }
    317