blob: ded5d5c96bee512c349140caae0905db432d14f0 [file] [log] [blame]
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -07001/*
2 * Copyright (C) 2010 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
17/*
18 * Copyright (c) 2009 The Khronos Group Inc.
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
21 * software and /or associated documentation files (the "Materials "), to deal in the
22 * Materials without restriction, including without limitation the rights to use, copy,
23 * modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials,
24 * and to permit persons to whom the Materials are furnished to do so, subject to
25 * the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be included
28 * in all copies or substantial portions of the Materials.
29 *
30 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36 * CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
37 * MATERIALS.
38 */
39
40#define LOG_NDEBUG 0
41#define LOG_TAG "slesTestPlayUri"
42
43#include <utils/Log.h>
44#include <getopt.h>
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <unistd.h>
49#include <sys/time.h>
50#include <gtest/gtest.h>
Glenn Kastenc6853892011-07-19 11:16:07 -070051#include <SLES/OpenSLES.h>
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -070052
53
54#define MAX_NUMBER_INTERFACES 3
55#define MAX_NUMBER_OUTPUT_DEVICES 6
56
57//The expected playback duration
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -070058const int MP3_DURATION = 71030; //71 secs
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -070059
60
61//-----------------------------------------------------------------
62/* Checks for error. If any errors exit the application! */
63void CheckErr( SLresult res )
64{
65 if ( res != SL_RESULT_SUCCESS ) {
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -070066 fprintf(stderr, "%u SL failure, exiting\n", res);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -070067 //Fail the test case
68 ASSERT_TRUE(false);
69 }
70}
71
72//-----------------------------------------------------------------
73/* PrefetchStatusItf callback for an audio player */
74void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext, SLuint32 event)
75{
76 SLpermille level = 0;
77 (*caller)->GetFillLevel(caller, &level);
78 SLuint32 status;
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -070079 fprintf(stdout, "\t\tPrefetchEventCallback: received event %u\n", event);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -070080 (*caller)->GetPrefetchStatus(caller, &status);
81 if ((event & (SL_PREFETCHEVENT_STATUSCHANGE|SL_PREFETCHEVENT_FILLLEVELCHANGE))
82 && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
83 fprintf(stderr, "\t\tPrefetchEventCallback: Error while prefetching data, exiting\n");
84 ASSERT_TRUE(false);
85 }
86 if (event & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
Jean-Michel Trivi5940f262010-08-17 11:41:22 -070087 fprintf(stdout, "\t\tPrefetchEventCallback: Buffer fill level is = %d\n", level);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -070088 }
89 if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -070090 fprintf(stdout, "\t\tPrefetchEventCallback: Prefetch Status is = %u\n", status);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -070091 }
92
93}
94
95
96//-----------------------------------------------------------------
97
98/* Play some music from a URI */
99void TestPlayUri( SLObjectItf sl, const char* path)
100{
101 SLEngineItf EngineItf;
102
103 SLint32 numOutputs = 0;
104 SLuint32 deviceID = 0;
105
106 SLresult res;
107
108 SLDataSource audioSource;
109 SLDataLocator_URI uri;
110 SLDataFormat_MIME mime;
111
112 SLDataSink audioSink;
113 SLDataLocator_OutputMix locator_outputmix;
114
115 SLObjectItf player;
116 SLPlayItf playItf;
117 SLVolumeItf volItf;
118 SLPrefetchStatusItf prefetchItf;
119
120 SLObjectItf OutputMix;
121
122 SLboolean required[MAX_NUMBER_INTERFACES];
123 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
124
125 /* Get the SL Engine Interface which is implicit */
126 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
127 CheckErr(res);
128
129 /* Initialize arrays required[] and iidArray[] */
130 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
131 required[i] = SL_BOOLEAN_FALSE;
132 iidArray[i] = SL_IID_NULL;
133 }
134
135 // Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface
136 required[0] = SL_BOOLEAN_TRUE;
137 iidArray[0] = SL_IID_VOLUME;
138 required[1] = SL_BOOLEAN_TRUE;
139 iidArray[1] = SL_IID_PREFETCHSTATUS;
140 // Create Output Mix object to be used by player
Glenn Kastenc2303eb2010-10-10 15:04:20 -0700141 res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700142 iidArray, required); CheckErr(res);
143
144 // Realizing the Output Mix object in synchronous mode.
145 res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
146 CheckErr(res);
147
148 /* Setup the data source structure for the URI */
149 uri.locatorType = SL_DATALOCATOR_URI;
150 uri.URI = (SLchar*) path;
151 mime.formatType = SL_DATAFORMAT_MIME;
152 mime.mimeType = (SLchar*)NULL;
153 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
154
155 audioSource.pFormat = (void *)&mime;
156 audioSource.pLocator = (void *)&uri;
157
158 /* Setup the data sink structure */
159 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
160 locator_outputmix.outputMix = OutputMix;
161 audioSink.pLocator = (void *)&locator_outputmix;
162 audioSink.pFormat = NULL;
163
164 /* Create the audio player */
165 res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
Jean-Michel Trivi5940f262010-08-17 11:41:22 -0700166 &audioSource, &audioSink, 2, iidArray, required); CheckErr(res);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700167
168 /* Realizing the player in synchronous mode. */
169 res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
170
171 /* Get interfaces */
172 res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
173 CheckErr(res);
174
175 res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volItf);
176 CheckErr(res);
177
178 res = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
179 CheckErr(res);
180 res = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf);
181 CheckErr(res);
182 res = (*prefetchItf)->SetCallbackEventsMask(prefetchItf,
183 SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
184
185 /* Display duration */
186 SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
187 res = (*playItf)->GetDuration(playItf, &durationInMsec);
188 CheckErr(res);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700189
190 /* Set the player volume */
191 res = (*volItf)->SetVolumeLevel( volItf, -300);
192 CheckErr(res);
193
194 /* Play the URI */
195 /* first cause the player to prefetch the data */
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700196 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700197 CheckErr(res);
198
199 /* wait until there's data to play */
200 //SLpermille fillLevel = 0;
201 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
202 SLuint32 timeOutIndex = 100; // 10s
203 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
204 usleep(100 * 1000);
205 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
206 timeOutIndex--;
207 }
208
209 if (timeOutIndex == 0) {
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -0700210 fprintf(stderr, "Error: Failed to prefetch data in time, exiting\n");
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700211 ASSERT_TRUE(false);
212 // goto destroyRes;
213 }
214
215 /* Display duration again, */
216 res = (*playItf)->GetDuration(playItf, &durationInMsec);
217 CheckErr(res);
218 if (durationInMsec == SL_TIME_UNKNOWN) {
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -0700219 fprintf(stderr, "Error: GetDuration returned SL_TIME_UNKNOWN (after prefetch completed)\n");
220 ASSERT_TRUE(false);
221 }
222 SLint32 durationDiffMsec = durationInMsec - MP3_DURATION;
223 if (durationDiffMsec < 0) { durationDiffMsec *= -1; }
224 if (durationDiffMsec > (MP3_DURATION/20)) {
225 fprintf(stderr, "Error: GetDuration returned %d, more than 5percent off from expected %d\n",
226 durationInMsec, MP3_DURATION);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700227 ASSERT_TRUE(false);
228 }
229
230 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
231 CheckErr(res);
232
233 /* Play for the song duration*/
234 usleep(MP3_DURATION * 1000);
235
236 /* Validate the play position*/
237 SLmillisecond currentPositionInMsec = SL_TIME_UNKNOWN;
238 res = (*playItf)->GetPosition(playItf, &currentPositionInMsec);
239 CheckErr(res);
240 if (currentPositionInMsec == SL_TIME_UNKNOWN) {
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -0700241 fprintf(stderr, "Error: GetPosition returns SL_TIME_UNKNOWN after expected duration\n");
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700242 ASSERT_TRUE(false);
243 } else if ( currentPositionInMsec <= 0 ||
244 currentPositionInMsec > (MP3_DURATION * 1.1) ){
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -0700245 fprintf(stderr, "Error: GetPosition returns %i, should be expected duration for test\n",
Yu Shan Emily Lau791b3c02010-07-07 19:13:54 -0700246 (int) currentPositionInMsec);
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700247 ASSERT_TRUE(false);
248 }
249
250 /* Make sure player is stopped */
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700251 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
252 CheckErr(res);
253
254destroyRes:
255
256 /* Destroy the player */
257 (*player)->Destroy(player);
258
259 /* Destroy Output Mix object */
260 (*OutputMix)->Destroy(OutputMix);
Jean-Michel Triviebbc7dd2011-05-11 11:12:13 -0700261
262 fprintf(stdout, "End of test reached\n");
Yu Shan Emily Lau95ba4632010-06-29 15:50:44 -0700263}
264
265
266// The fixture for testing class MimeUri
267class MimeUri: public ::testing::Test {
268public:
269 SLresult res;
270 SLObjectItf sl;
271
272protected:
273 MimeUri() {
274 // You can do set-up work for each test here.
275 SLEngineOption EngineOption[] = { { (SLuint32) SL_ENGINEOPTION_THREADSAFE,
276 (SLuint32) SL_BOOLEAN_TRUE } };
277
278 res = slCreateEngine(&sl, 1, EngineOption, 0, NULL, NULL);
279 CheckErr(res);
280
281 /* Realizing the SL Engine in synchronous mode. */
282 res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
283 CheckErr(res);
284 }
285
286 virtual ~MimeUri() {
287 // You can do clean-up work that doesn't throw exceptions here.
288 (*sl)->Destroy(sl);
289 }
290
291 virtual void SetUp() {
292 // Code here will be called immediately after the constructor (right
293 // before each test).
294
295 }
296
297 virtual void TearDown() {
298 // Code here will be called immediately after each test (right
299 // before the destructor).
300
301 }
302};
303
304TEST_F(MimeUri, testPlayAbsPath){
305 TestPlayUri(sl, "/sdcard/media_api/music/MP3_256kbps_2ch.mp3");
306}
307
308TEST_F(MimeUri, testPlayfilePath){
309 TestPlayUri(sl, "file:///sdcard/media_api/music/MP3_256kbps_2ch.mp3");
310}
311
312//-----------------------------------------------------------------
313int main(int argc, char **argv)
314{
315 testing::InitGoogleTest(&argc, argv);
316 return RUN_ALL_TESTS();
317}