1 /*
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>
51 #include <SLES/OpenSLES.h>
52 
53 
54 #define MAX_NUMBER_INTERFACES 3
55 #define MAX_NUMBER_OUTPUT_DEVICES 6
56 
57 //The expected playback duration
58 const int MP3_DURATION = 71030; //71 secs
59 
60 
61 //-----------------------------------------------------------------
62 /* Checks for error. If any errors exit the application! */
CheckErr(SLresult res)63 void CheckErr( SLresult res )
64 {
65     if ( res != SL_RESULT_SUCCESS )  {
66         fprintf(stderr, "%u SL failure, exiting\n", res);
67         //Fail the test case
68         ASSERT_TRUE(false);
69     }
70 }
71 
72 //-----------------------------------------------------------------
73 /* PrefetchStatusItf callback for an audio player */
PrefetchEventCallback(SLPrefetchStatusItf caller,void * pContext __unused,SLuint32 event)74 void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext __unused, SLuint32 event)
75 {
76     SLpermille level = 0;
77     (*caller)->GetFillLevel(caller, &level);
78     SLuint32 status;
79     fprintf(stdout, "\t\tPrefetchEventCallback: received event %u\n", event);
80     (*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) {
87         fprintf(stdout, "\t\tPrefetchEventCallback: Buffer fill level is = %d\n", level);
88     }
89     if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
90         fprintf(stdout, "\t\tPrefetchEventCallback: Prefetch Status is = %u\n", status);
91     }
92 
93 }
94 
95 
96 //-----------------------------------------------------------------
97 
98 /* Play some music from a URI  */
TestPlayUri(SLObjectItf sl,const char * path)99 void 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
141     res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
142             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,
166             &audioSource, &audioSink, 2, iidArray, required); CheckErr(res);
167 
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);
189 
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 */
196     res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
197     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) {
210         fprintf(stderr, "Error: Failed to prefetch data in time, exiting\n");
211         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) {
219         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);
227         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) {
241       fprintf(stderr, "Error: GetPosition returns SL_TIME_UNKNOWN after expected duration\n");
242       ASSERT_TRUE(false);
243     } else if ( currentPositionInMsec <= 0 ||
244         currentPositionInMsec > (MP3_DURATION * 1.1) ){
245         fprintf(stderr, "Error: GetPosition returns %i, should be expected duration for test\n",
246                 (int) currentPositionInMsec);
247         ASSERT_TRUE(false);
248     }
249 
250     /* Make sure player is stopped */
251     res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
252     CheckErr(res);
253 
254 destroyRes:
255 
256     /* Destroy the player */
257     (*player)->Destroy(player);
258 
259     /* Destroy Output Mix object */
260     (*OutputMix)->Destroy(OutputMix);
261 
262     fprintf(stdout, "End of test reached\n");
263 }
264 
265 
266 // The fixture for testing class MimeUri
267 class MimeUri: public ::testing::Test {
268 public:
269     SLresult res;
270     SLObjectItf sl;
271 
272 protected:
MimeUri()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 
~MimeUri()286     virtual ~MimeUri() {
287         // You can do clean-up work that doesn't throw exceptions here.
288         (*sl)->Destroy(sl);
289     }
290 
SetUp()291     virtual void SetUp() {
292         // Code here will be called immediately after the constructor (right
293         // before each test).
294 
295     }
296 
TearDown()297     virtual void TearDown() {
298         // Code here will be called immediately after each test (right
299         // before the destructor).
300 
301     }
302 };
303 
TEST_F(MimeUri,testPlayAbsPath)304 TEST_F(MimeUri, testPlayAbsPath){
305     TestPlayUri(sl, "/sdcard/media_api/music/MP3_256kbps_2ch.mp3");
306 }
307 
TEST_F(MimeUri,testPlayfilePath)308 TEST_F(MimeUri, testPlayfilePath){
309     TestPlayUri(sl, "file:///sdcard/media_api/music/MP3_256kbps_2ch.mp3");
310 }
311 
312 //-----------------------------------------------------------------
main(int argc,char ** argv)313 int main(int argc, char **argv)
314 {
315     testing::InitGoogleTest(&argc, argv);
316     return RUN_ALL_TESTS();
317 }
318