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.media.MediaPlayer;
     23 import android.media.cts.TestUtils.Monitor;
     24 import android.net.Uri;
     25 import android.os.PersistableBundle;
     26 import android.test.ActivityInstrumentationTestCase2;
     27 
     28 import com.android.compatibility.common.util.MediaUtils;
     29 
     30 import java.io.IOException;
     31 import java.net.HttpCookie;
     32 import java.util.List;
     33 import java.util.logging.Logger;
     34 import java.util.Map;
     35 import java.util.Set;
     36 
     37 /**
     38  * Base class for tests which use MediaPlayer to play audio or video.
     39  */
     40 public class MediaPlayerTestBase extends ActivityInstrumentationTestCase2<MediaStubActivity> {
     41     private static final Logger LOG = Logger.getLogger(MediaPlayerTestBase.class.getName());
     42 
     43     protected static final int SLEEP_TIME = 1000;
     44     protected static final int LONG_SLEEP_TIME = 6000;
     45     protected static final int STREAM_RETRIES = 20;
     46     protected static boolean sUseScaleToFitMode = false;
     47 
     48     protected Monitor mOnVideoSizeChangedCalled = new Monitor();
     49     protected Monitor mOnVideoRenderingStartCalled = new Monitor();
     50     protected Monitor mOnBufferingUpdateCalled = new Monitor();
     51     protected Monitor mOnPrepareCalled = new Monitor();
     52     protected Monitor mOnSeekCompleteCalled = new Monitor();
     53     protected Monitor mOnCompletionCalled = new Monitor();
     54     protected Monitor mOnInfoCalled = new Monitor();
     55     protected Monitor mOnErrorCalled = new Monitor();
     56 
     57     protected Context mContext;
     58     protected Resources mResources;
     59 
     60 
     61     protected MediaPlayer mMediaPlayer = null;
     62     protected MediaPlayer mMediaPlayer2 = null;
     63     protected MediaStubActivity mActivity;
     64 
     65     public MediaPlayerTestBase() {
     66         super(MediaStubActivity.class);
     67     }
     68 
     69     @Override
     70     protected void setUp() throws Exception {
     71         super.setUp();
     72         mActivity = getActivity();
     73         getInstrumentation().waitForIdleSync();
     74         try {
     75             runTestOnUiThread(new Runnable() {
     76                 public void run() {
     77                     mMediaPlayer = new MediaPlayer();
     78                     mMediaPlayer2 = new MediaPlayer();
     79                 }
     80             });
     81         } catch (Throwable e) {
     82             e.printStackTrace();
     83             fail();
     84         }
     85         mContext = getInstrumentation().getTargetContext();
     86         mResources = mContext.getResources();
     87     }
     88 
     89     @Override
     90     protected void tearDown() throws Exception {
     91         if (mMediaPlayer != null) {
     92             mMediaPlayer.release();
     93             mMediaPlayer = null;
     94         }
     95         if (mMediaPlayer2 != null) {
     96             mMediaPlayer2.release();
     97             mMediaPlayer2 = null;
     98         }
     99         mActivity = null;
    100         super.tearDown();
    101     }
    102 
    103     // returns true on success
    104     protected boolean loadResource(int resid) throws Exception {
    105         if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
    106             return false;
    107         }
    108 
    109         AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
    110         try {
    111             mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
    112                     afd.getLength());
    113 
    114             // Although it is only meant for video playback, it should not
    115             // cause issues for audio-only playback.
    116             int videoScalingMode = sUseScaleToFitMode?
    117                                     MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT
    118                                   : MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING;
    119 
    120             mMediaPlayer.setVideoScalingMode(videoScalingMode);
    121         } finally {
    122             afd.close();
    123         }
    124         sUseScaleToFitMode = !sUseScaleToFitMode;  // Alternate the scaling mode
    125         return true;
    126     }
    127 
    128     protected boolean checkLoadResource(int resid) throws Exception {
    129         return MediaUtils.check(loadResource(resid), "no decoder found");
    130     }
    131 
    132     protected void loadSubtitleSource(int resid) throws Exception {
    133         AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
    134         try {
    135             mMediaPlayer.addTimedTextSource(afd.getFileDescriptor(), afd.getStartOffset(),
    136                       afd.getLength(), MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP);
    137         } finally {
    138             afd.close();
    139         }
    140     }
    141 
    142     protected void playLiveVideoTest(String path, int playTime) throws Exception {
    143         playVideoWithRetries(path, null, null, playTime);
    144     }
    145 
    146     protected void playLiveAudioOnlyTest(String path, int playTime) throws Exception {
    147         playVideoWithRetries(path, -1, -1, playTime);
    148     }
    149 
    150     protected void playVideoTest(String path, int width, int height) throws Exception {
    151         playVideoWithRetries(path, width, height, 0);
    152     }
    153 
    154     protected void playVideoWithRetries(String path, Integer width, Integer height, int playTime)
    155             throws Exception {
    156         boolean playedSuccessfully = false;
    157         for (int i = 0; i < STREAM_RETRIES; i++) {
    158           try {
    159             mMediaPlayer.setDataSource(path);
    160             playLoadedVideo(width, height, playTime);
    161             playedSuccessfully = true;
    162             break;
    163           } catch (PrepareFailedException e) {
    164             // prepare() can fail because of network issues, so try again
    165             LOG.warning("prepare() failed on try " + i + ", trying playback again");
    166           }
    167         }
    168         assertTrue("Stream did not play successfully after all attempts", playedSuccessfully);
    169     }
    170 
    171     protected void playVideoTest(int resid, int width, int height) throws Exception {
    172         if (!checkLoadResource(resid)) {
    173             return; // skip
    174         }
    175 
    176         playLoadedVideo(width, height, 0);
    177     }
    178 
    179     protected void playLiveVideoTest(
    180             Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
    181             int playTime) throws Exception {
    182         playVideoWithRetries(uri, headers, cookies, null /* width */, null /* height */, playTime);
    183     }
    184 
    185     protected void playVideoWithRetries(
    186             Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
    187             Integer width, Integer height, int playTime) throws Exception {
    188         boolean playedSuccessfully = false;
    189         for (int i = 0; i < STREAM_RETRIES; i++) {
    190             try {
    191                 mMediaPlayer.setDataSource(getInstrumentation().getTargetContext(),
    192                         uri, headers, cookies);
    193                 playLoadedVideo(width, height, playTime);
    194                 playedSuccessfully = true;
    195                 break;
    196             } catch (PrepareFailedException e) {
    197                 // prepare() can fail because of network issues, so try again
    198                 // playLoadedVideo already has reset the player so we can try again safely.
    199                 LOG.warning("prepare() failed on try " + i + ", trying playback again");
    200             }
    201         }
    202         assertTrue("Stream did not play successfully after all attempts", playedSuccessfully);
    203     }
    204 
    205     /**
    206      * Play a video which has already been loaded with setDataSource().
    207      *
    208      * @param width width of the video to verify, or null to skip verification
    209      * @param height height of the video to verify, or null to skip verification
    210      * @param playTime length of time to play video, or 0 to play entire video.
    211      * with a non-negative value, this method stops the playback after the length of
    212      * time or the duration the video is elapsed. With a value of -1,
    213      * this method simply starts the video and returns immediately without
    214      * stoping the video playback.
    215      */
    216     protected void playLoadedVideo(final Integer width, final Integer height, int playTime)
    217             throws Exception {
    218         final float leftVolume = 0.5f;
    219         final float rightVolume = 0.5f;
    220 
    221         boolean audioOnly = (width != null && width.intValue() == -1) ||
    222                 (height != null && height.intValue() == -1);
    223 
    224         mMediaPlayer.setDisplay(mActivity.getSurfaceHolder());
    225         mMediaPlayer.setScreenOnWhilePlaying(true);
    226         mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
    227             @Override
    228             public void onVideoSizeChanged(MediaPlayer mp, int w, int h) {
    229                 if (w == 0 && h == 0) {
    230                     // A size of 0x0 can be sent initially one time when using NuPlayer.
    231                     assertFalse(mOnVideoSizeChangedCalled.isSignalled());
    232                     return;
    233                 }
    234                 mOnVideoSizeChangedCalled.signal();
    235                 if (width != null) {
    236                     assertEquals(width.intValue(), w);
    237                 }
    238                 if (height != null) {
    239                     assertEquals(height.intValue(), h);
    240                 }
    241             }
    242         });
    243         mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    244             @Override
    245             public boolean onError(MediaPlayer mp, int what, int extra) {
    246                 fail("Media player had error " + what + " playing video");
    247                 return true;
    248             }
    249         });
    250         mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
    251             @Override
    252             public boolean onInfo(MediaPlayer mp, int what, int extra) {
    253                 if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
    254                     mOnVideoRenderingStartCalled.signal();
    255                 }
    256                 return true;
    257             }
    258         });
    259         try {
    260           mMediaPlayer.prepare();
    261         } catch (IOException e) {
    262           mMediaPlayer.reset();
    263           throw new PrepareFailedException();
    264         }
    265 
    266         mMediaPlayer.start();
    267         if (!audioOnly) {
    268             mOnVideoSizeChangedCalled.waitForSignal();
    269             mOnVideoRenderingStartCalled.waitForSignal();
    270         }
    271         mMediaPlayer.setVolume(leftVolume, rightVolume);
    272 
    273         // waiting to complete
    274         if (playTime == -1) {
    275             return;
    276         } else if (playTime == 0) {
    277             while (mMediaPlayer.isPlaying()) {
    278                 Thread.sleep(SLEEP_TIME);
    279             }
    280         } else {
    281             Thread.sleep(playTime);
    282         }
    283 
    284         // validate a few MediaMetrics.
    285         PersistableBundle metrics = mMediaPlayer.getMetrics();
    286         if (metrics == null) {
    287             fail("MediaPlayer.getMetrics() returned null metrics");
    288         } else if (metrics.isEmpty()) {
    289             fail("MediaPlayer.getMetrics() returned empty metrics");
    290         } else {
    291 
    292             int size = metrics.size();
    293             Set<String> keys = metrics.keySet();
    294 
    295             if (keys == null) {
    296                 fail("MediaMetricsSet returned no keys");
    297             } else if (keys.size() != size) {
    298                 fail("MediaMetricsSet.keys().size() mismatch MediaMetricsSet.size()");
    299             }
    300 
    301             // we played something; so one of these should be non-null
    302             String vmime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_VIDEO, null);
    303             String amime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_AUDIO, null);
    304             if (vmime == null && amime == null) {
    305                 fail("getMetrics() returned neither video nor audio mime value");
    306             }
    307 
    308             long duration = metrics.getLong(MediaPlayer.MetricsConstants.DURATION, -2);
    309             if (duration == -2) {
    310                 fail("getMetrics() didn't return a duration");
    311             }
    312             long playing = metrics.getLong(MediaPlayer.MetricsConstants.PLAYING, -2);
    313             if (playing == -2) {
    314                 fail("getMetrics() didn't return a playing time");
    315             }
    316             if (!keys.contains(MediaPlayer.MetricsConstants.PLAYING)) {
    317                 fail("MediaMetricsSet.keys() missing: " + MediaPlayer.MetricsConstants.PLAYING);
    318             }
    319         }
    320 
    321         mMediaPlayer.stop();
    322     }
    323 
    324     private static class PrepareFailedException extends Exception {}
    325 
    326     public boolean isTv() {
    327         PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
    328         return pm.hasSystemFeature(pm.FEATURE_TELEVISION)
    329                 && pm.hasSystemFeature(pm.FEATURE_LEANBACK);
    330     }
    331 
    332     public boolean checkTv() {
    333         return MediaUtils.check(isTv(), "not a TV");
    334     }
    335 
    336     protected void setOnErrorListener() {
    337         mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    338             @Override
    339             public boolean onError(MediaPlayer mp, int what, int extra) {
    340                 mOnErrorCalled.signal();
    341                 return false;
    342             }
    343         });
    344     }
    345 }
    346