| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.media.cts; |
| |
| import android.content.Context; |
| import android.content.res.AssetFileDescriptor; |
| import android.content.res.Resources; |
| import android.media.MediaPlayer; |
| import android.test.ActivityInstrumentationTestCase2; |
| |
| import java.io.IOException; |
| import java.util.logging.Logger; |
| |
| /** |
| * Base class for tests which use MediaPlayer to play audio or video. |
| */ |
| public class MediaPlayerTestBase extends ActivityInstrumentationTestCase2<MediaStubActivity> { |
| private static final Logger LOG = Logger.getLogger(MediaPlayerTestBase.class.getName()); |
| |
| protected static final int SLEEP_TIME = 1000; |
| protected static final int LONG_SLEEP_TIME = 6000; |
| protected static final int STREAM_RETRIES = 20; |
| |
| public static class Monitor { |
| private boolean signalled; |
| |
| public synchronized void reset() { |
| signalled = false; |
| } |
| |
| public synchronized void signal() { |
| signalled = true; |
| notifyAll(); |
| } |
| |
| public synchronized void waitForSignal() throws InterruptedException { |
| while (!signalled) { |
| wait(); |
| } |
| } |
| |
| public synchronized void waitForSignal(long millis) throws InterruptedException { |
| if (millis == 0) { |
| waitForSignal(); |
| return; |
| } |
| |
| long deadline = System.currentTimeMillis() + millis; |
| while (!signalled) { |
| long delay = deadline - System.currentTimeMillis(); |
| if (delay <= 0) { |
| break; |
| } |
| wait(delay); |
| } |
| } |
| |
| public synchronized boolean isSignalled() { |
| return signalled; |
| } |
| } |
| |
| protected Monitor mOnVideoSizeChangedCalled = new Monitor(); |
| protected Monitor mOnBufferingUpdateCalled = new Monitor(); |
| protected Monitor mOnPrepareCalled = new Monitor(); |
| protected Monitor mOnSeekCompleteCalled = new Monitor(); |
| protected Monitor mOnCompletionCalled = new Monitor(); |
| protected Monitor mOnInfoCalled = new Monitor(); |
| protected Monitor mOnErrorCalled = new Monitor(); |
| |
| protected Context mContext; |
| protected Resources mResources; |
| |
| /* |
| * InstrumentationTestRunner.onStart() calls Looper.prepare(), which creates a looper |
| * for the current thread. However, since we don't actually call loop() in the test, |
| * any messages queued with that looper will never be consumed. We instantiate the player |
| * in the constructor, before setUp(), so that its constructor does not see the |
| * nonfunctional Looper. |
| */ |
| protected MediaPlayer mMediaPlayer = new MediaPlayer(); |
| |
| public MediaPlayerTestBase() { |
| super(MediaStubActivity.class); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| mContext = getInstrumentation().getTargetContext(); |
| mResources = mContext.getResources(); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| if (mMediaPlayer != null) { |
| mMediaPlayer.release(); |
| } |
| super.tearDown(); |
| } |
| |
| protected void loadResource(int resid) throws Exception { |
| AssetFileDescriptor afd = mResources.openRawResourceFd(resid); |
| try { |
| mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), |
| afd.getLength()); |
| } finally { |
| afd.close(); |
| } |
| } |
| |
| protected void playLiveVideoTest(String path, int playTime) throws Exception { |
| playVideoWithRetries(path, null, null, playTime); |
| } |
| |
| protected void playVideoTest(String path, int width, int height) throws Exception { |
| playVideoWithRetries(path, width, height, 0); |
| } |
| |
| protected void playVideoWithRetries(String path, Integer width, Integer height, int playTime) |
| throws Exception { |
| boolean playedSuccessfully = false; |
| for (int i = 0; i < STREAM_RETRIES; i++) { |
| try { |
| mMediaPlayer.setDataSource(path); |
| playLoadedVideo(width, height, playTime); |
| playedSuccessfully = true; |
| break; |
| } catch (PrepareFailedException e) { |
| // prepare() can fail because of network issues, so try again |
| LOG.warning("prepare() failed on try " + i + ", trying playback again"); |
| } |
| } |
| assertTrue("Stream did not play successfully after all attempts", playedSuccessfully); |
| } |
| |
| protected void playVideoTest(int resid, int width, int height) throws Exception { |
| loadResource(resid); |
| playLoadedVideo(width, height, 0); |
| } |
| |
| /** |
| * Play a video which has already been loaded with setDataSource(). |
| * |
| * @param width width of the video to verify, or null to skip verification |
| * @param height height of the video to verify, or null to skip verification |
| * @param playTime length of time to play video, or 0 to play entire video. |
| * with a non-negative value, this method stops the playback after the length of |
| * time or the duration the video is elapsed. With a value of -1, |
| * this method simply starts the video and returns immediately without |
| * stoping the video playback. |
| */ |
| protected void playLoadedVideo(final Integer width, final Integer height, int playTime) |
| throws Exception { |
| final float leftVolume = 0.5f; |
| final float rightVolume = 0.5f; |
| |
| mMediaPlayer.setDisplay(getActivity().getSurfaceHolder()); |
| mMediaPlayer.setScreenOnWhilePlaying(true); |
| mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() { |
| @Override |
| public void onVideoSizeChanged(MediaPlayer mp, int w, int h) { |
| mOnVideoSizeChangedCalled.signal(); |
| if (width != null) { |
| assertEquals(width.intValue(), w); |
| } |
| if (height != null) { |
| assertEquals(height.intValue(), h); |
| } |
| } |
| }); |
| mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { |
| @Override |
| public boolean onError(MediaPlayer mp, int what, int extra) { |
| fail("Media player had error " + what + " playing video"); |
| return true; |
| } |
| }); |
| try { |
| mMediaPlayer.prepare(); |
| } catch (IOException e) { |
| mMediaPlayer.reset(); |
| throw new PrepareFailedException(); |
| } |
| |
| mMediaPlayer.start(); |
| mOnVideoSizeChangedCalled.waitForSignal(); |
| mMediaPlayer.setVolume(leftVolume, rightVolume); |
| |
| // waiting to complete |
| if (playTime == -1) { |
| return; |
| } else if (playTime == 0) { |
| while (mMediaPlayer.isPlaying()) { |
| Thread.sleep(SLEEP_TIME); |
| } |
| } else { |
| Thread.sleep(playTime); |
| } |
| mMediaPlayer.stop(); |
| } |
| |
| private static class PrepareFailedException extends Exception {} |
| } |