• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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.app.Activity;
25 import android.app.Instrumentation;
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 import android.content.res.AssetFileDescriptor;
29 import android.media.MediaPlayer;
30 import android.media.cts.TestUtils.Monitor;
31 import android.net.Uri;
32 import android.os.ConditionVariable;
33 import android.os.ParcelFileDescriptor;
34 import android.os.PersistableBundle;
35 
36 import androidx.annotation.CallSuper;
37 import androidx.test.core.app.ActivityScenario;
38 import androidx.test.platform.app.InstrumentationRegistry;
39 
40 import com.android.compatibility.common.util.MediaUtils;
41 
42 import java.io.File;
43 import java.io.FileNotFoundException;
44 import java.io.IOException;
45 import java.net.HttpCookie;
46 import java.util.List;
47 import java.util.logging.Logger;
48 import java.util.Map;
49 import java.util.Set;
50 
51 import org.junit.After;
52 import org.junit.Before;
53 
54 /**
55  * Base class for tests which use MediaPlayer to play audio or video.
56  */
57 public class MediaPlayerTestBase extends MediaTestBase {
58     private static final Logger LOG = Logger.getLogger(MediaPlayerTestBase.class.getName());
59 
60     protected Monitor mOnVideoSizeChangedCalled = new Monitor();
61     protected Monitor mOnVideoRenderingStartCalled = new Monitor();
62     protected Monitor mOnBufferingUpdateCalled = new Monitor();
63     protected Monitor mOnPrepareCalled = new Monitor();
64     protected Monitor mOnSeekCompleteCalled = new Monitor();
65     protected Monitor mOnCompletionCalled = new Monitor();
66     protected Monitor mOnInfoCalled = new Monitor();
67     protected Monitor mOnErrorCalled = new Monitor();
68 
69     protected MediaPlayer mMediaPlayer = null;
70     protected MediaPlayer mMediaPlayer2 = null;
71 
72     @Before
73     @Override
setUp()74     public void setUp() throws Throwable {
75         super.setUp();
76         runOnUiThread(() -> {
77             mMediaPlayer = new MediaPlayer();
78             mMediaPlayer2 = new MediaPlayer();
79         });
80     }
81     @After
82     @Override
tearDown()83     public void tearDown() {
84         if (mMediaPlayer != null) {
85             mMediaPlayer.release();
86             mMediaPlayer = null;
87         }
88         if (mMediaPlayer2 != null) {
89             mMediaPlayer2.release();
90             mMediaPlayer2 = null;
91         }
92         super.tearDown();
93     }
94 
runOnUiThread(Runnable runnable)95     protected void runOnUiThread(Runnable runnable) throws Throwable {
96         Throwable[] throwableHolder = new Throwable[1];
97         getInstrumentation().runOnMainSync(() -> {
98             try {
99                 runnable.run();
100             } catch (Throwable throwable) {
101                 throwableHolder[0] = throwable;
102             }
103         });
104         if (throwableHolder[0] != null) {
105             throw throwableHolder[0];
106         }
107     }
108 
playLiveVideoTest(String path, int playTime)109     protected void playLiveVideoTest(String path, int playTime) throws Exception {
110         playVideoWithRetries(path, null, null, playTime);
111     }
112 
playLiveAudioOnlyTest(String path, int playTime)113     protected void playLiveAudioOnlyTest(String path, int playTime) throws Exception {
114         playVideoWithRetries(path, -1, -1, playTime);
115     }
116 
playVideoTest(String path, int width, int height)117     protected void playVideoTest(String path, int width, int height) throws Exception {
118         playVideoWithRetries(path, width, height, 0);
119     }
120 
playVideoWithRetries(String path, Integer width, Integer height, int playTime)121     protected void playVideoWithRetries(String path, Integer width, Integer height, int playTime)
122             throws Exception {
123         boolean playedSuccessfully = false;
124         for (int i = 0; i < STREAM_RETRIES; i++) {
125           try {
126             mMediaPlayer.reset();
127             mMediaPlayer.setDataSource(path);
128             playLoadedVideo(width, height, playTime);
129             playedSuccessfully = true;
130             break;
131           } catch (PrepareFailedException e) {
132             // prepare() can fail because of network issues, so try again
133             LOG.warning("prepare() failed on try " + i + ", trying playback again");
134           }
135         }
136         assertTrue("Stream did not play successfully after all attempts", playedSuccessfully);
137     }
138 
playLiveVideoTest( Uri uri, Map<String, String> headers, List<HttpCookie> cookies, int playTime)139     protected void playLiveVideoTest(
140             Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
141             int playTime) throws Exception {
142         playVideoWithRetries(uri, headers, cookies, null /* width */, null /* height */, playTime);
143     }
144 
playLiveAudioOnlyTest( Uri uri, Map<String, String> headers, List<HttpCookie> cookies, int playTime)145     protected void playLiveAudioOnlyTest(
146             Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
147             int playTime) throws Exception {
148         playVideoWithRetries(uri, headers, cookies, -1 /* width */, -1 /* height */, playTime);
149     }
150 
playVideoWithRetries( Uri uri, Map<String, String> headers, List<HttpCookie> cookies, Integer width, Integer height, int playTime)151     protected void playVideoWithRetries(
152             Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
153             Integer width, Integer height, int playTime) throws Exception {
154         boolean playedSuccessfully = false;
155         for (int i = 0; i < STREAM_RETRIES; i++) {
156             try {
157                 mMediaPlayer.reset();
158                 mMediaPlayer.setDataSource(
159                         getInstrumentation().getTargetContext(),
160                         uri,
161                         headers,
162                         cookies);
163                 playLoadedVideo(width, height, playTime);
164                 playedSuccessfully = true;
165                 break;
166             } catch (PrepareFailedException e) {
167                 // prepare() can fail because of network issues, so try again
168                 // playLoadedVideo already has reset the player so we can try again safely.
169                 LOG.warning("prepare() failed on try " + i + ", trying playback again");
170             }
171         }
172         assertTrue("Stream did not play successfully after all attempts", playedSuccessfully);
173     }
174 
175     /**
176      * Play a video which has already been loaded with setDataSource().
177      *
178      * @param width width of the video to verify, or null to skip verification
179      * @param height height of the video to verify, or null to skip verification
180      * @param playTime length of time to play video, or 0 to play entire video.
181      * with a non-negative value, this method stops the playback after the length of
182      * time or the duration the video is elapsed. With a value of -1,
183      * this method simply starts the video and returns immediately without
184      * stoping the video playback.
185      */
playLoadedVideo(final Integer width, final Integer height, int playTime)186     protected void playLoadedVideo(final Integer width, final Integer height, int playTime)
187             throws Exception {
188         final float leftVolume = 0.5f;
189         final float rightVolume = 0.5f;
190 
191         boolean audioOnly = (width != null && width == -1) ||
192                 (height != null && height == -1);
193 
194         mMediaPlayer.setDisplay(mActivity.getSurfaceHolder());
195         mMediaPlayer.setScreenOnWhilePlaying(true);
196         mMediaPlayer.setOnVideoSizeChangedListener((mp, w, h) -> {
197             if (w == 0 && h == 0) {
198                 // A size of 0x0 can be sent initially one time when using NuPlayer.
199                 assertFalse(mOnVideoSizeChangedCalled.isSignalled());
200                 return;
201             }
202             mOnVideoSizeChangedCalled.signal();
203             if (width != null) {
204                 assertEquals(width.intValue(), w);
205             }
206             if (height != null) {
207                 assertEquals(height.intValue(), h);
208             }
209         });
210         mMediaPlayer.setOnErrorListener((mp, what, extra) -> {
211             fail("Media player had error " + what + " playing video");
212             return true;
213         });
214         mMediaPlayer.setOnInfoListener((mp, what, extra) -> {
215             if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
216                 mOnVideoRenderingStartCalled.signal();
217             }
218             return true;
219         });
220         try {
221           mMediaPlayer.prepare();
222         } catch (IOException e) {
223           mMediaPlayer.reset();
224           throw new PrepareFailedException();
225         }
226 
227         mMediaPlayer.start();
228         if (!audioOnly) {
229             mOnVideoSizeChangedCalled.waitForSignal();
230             mOnVideoRenderingStartCalled.waitForSignal();
231         }
232         mMediaPlayer.setVolume(leftVolume, rightVolume);
233 
234         // waiting to complete
235         if (playTime == -1) {
236             return;
237         } else if (playTime == 0) {
238             while (mMediaPlayer.isPlaying()) {
239                 Thread.sleep(SLEEP_TIME);
240             }
241         } else {
242             Thread.sleep(playTime);
243         }
244 
245         // validate a few MediaMetrics.
246         PersistableBundle metrics = mMediaPlayer.getMetrics();
247         if (metrics == null) {
248             fail("MediaPlayer.getMetrics() returned null metrics");
249         } else if (metrics.isEmpty()) {
250             fail("MediaPlayer.getMetrics() returned empty metrics");
251         } else {
252 
253             int size = metrics.size();
254             Set<String> keys = metrics.keySet();
255 
256             if (keys == null) {
257                 fail("MediaMetricsSet returned no keys");
258             } else if (keys.size() != size) {
259                 fail("MediaMetricsSet.keys().size() mismatch MediaMetricsSet.size()");
260             }
261 
262             // we played something; so one of these should be non-null
263             String vmime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_VIDEO, null);
264             String amime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_AUDIO, null);
265             if (vmime == null && amime == null) {
266                 fail("getMetrics() returned neither video nor audio mime value");
267             }
268 
269             long duration = metrics.getLong(MediaPlayer.MetricsConstants.DURATION, -2);
270             if (duration == -2) {
271                 fail("getMetrics() didn't return a duration");
272             }
273             long playing = metrics.getLong(MediaPlayer.MetricsConstants.PLAYING, -2);
274             if (playing == -2) {
275                 fail("getMetrics() didn't return a playing time");
276             }
277             if (!keys.contains(MediaPlayer.MetricsConstants.PLAYING)) {
278                 fail("MediaMetricsSet.keys() missing: " + MediaPlayer.MetricsConstants.PLAYING);
279             }
280         }
281 
282         mMediaPlayer.stop();
283     }
284 
285     private static class PrepareFailedException extends Exception {}
286 
setOnErrorListener()287     protected void setOnErrorListener() {
288         mMediaPlayer.setOnErrorListener((mp, what, extra) -> {
289             mOnErrorCalled.signal();
290             return false;
291         });
292     }
293 }
294