mimeUri_test.cpp revision 791b3c0bb7bef1fd930a1b91274b972989f6a715
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 "OpenSLES.h"
52
53
54#define MAX_NUMBER_INTERFACES 3
55#define MAX_NUMBER_OUTPUT_DEVICES 6
56
57//The expected playback duration
58const int MP3_DURATION = 75000; //75 secs
59
60
61//-----------------------------------------------------------------
62/* Checks for error. If any errors exit the application! */
63void CheckErr( SLresult res )
64{
65    if ( res != SL_RESULT_SUCCESS )  {
66        fprintf(stdout, "%lu 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 */
74void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext, SLuint32 event)
75{
76    SLpermille level = 0;
77    (*caller)->GetFillLevel(caller, &level);
78    SLuint32 status;
79    fprintf(stderr, "\t\tPrefetchEventCallback: received event %lu\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(stderr, "\t\tPrefetchEventCallback: Buffer fill level is = %d\n", level);
88        ASSERT_TRUE(false);
89    }
90    if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
91        fprintf(stderr, "\t\tPrefetchEventCallback: Prefetch Status is = %lu\n", status);
92        ASSERT_TRUE(false);
93    }
94
95}
96
97
98//-----------------------------------------------------------------
99
100/* Play some music from a URI  */
101void TestPlayUri( SLObjectItf sl, const char* path)
102{
103    SLEngineItf                EngineItf;
104
105    SLint32                    numOutputs = 0;
106    SLuint32                   deviceID = 0;
107
108    SLresult                   res;
109
110    SLDataSource               audioSource;
111    SLDataLocator_URI          uri;
112    SLDataFormat_MIME          mime;
113
114    SLDataSink                 audioSink;
115    SLDataLocator_OutputMix    locator_outputmix;
116
117    SLObjectItf                player;
118    SLPlayItf                  playItf;
119    SLVolumeItf                volItf;
120    SLPrefetchStatusItf        prefetchItf;
121
122    SLObjectItf                OutputMix;
123
124    SLboolean required[MAX_NUMBER_INTERFACES];
125    SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
126
127    /* Get the SL Engine Interface which is implicit */
128    res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
129    CheckErr(res);
130
131    /* Initialize arrays required[] and iidArray[] */
132    for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
133        required[i] = SL_BOOLEAN_FALSE;
134        iidArray[i] = SL_IID_NULL;
135    }
136
137    // Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface
138    required[0] = SL_BOOLEAN_TRUE;
139    iidArray[0] = SL_IID_VOLUME;
140    required[1] = SL_BOOLEAN_TRUE;
141    iidArray[1] = SL_IID_PREFETCHSTATUS;
142    // Create Output Mix object to be used by player
143    res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 1,
144            iidArray, required); CheckErr(res);
145
146    // Realizing the Output Mix object in synchronous mode.
147    res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
148    CheckErr(res);
149
150    /* Setup the data source structure for the URI */
151    uri.locatorType = SL_DATALOCATOR_URI;
152    uri.URI         =  (SLchar*) path;
153    mime.formatType    = SL_DATAFORMAT_MIME;
154    mime.mimeType      = (SLchar*)NULL;
155    mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
156
157    audioSource.pFormat      = (void *)&mime;
158    audioSource.pLocator     = (void *)&uri;
159
160    /* Setup the data sink structure */
161    locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
162    locator_outputmix.outputMix    = OutputMix;
163    audioSink.pLocator           = (void *)&locator_outputmix;
164    audioSink.pFormat            = NULL;
165
166    /* Create the audio player */
167    res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
168            &audioSource, &audioSink, 1, iidArray, required); CheckErr(res);
169
170    /* Realizing the player in synchronous mode. */
171    res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
172
173    /* Get interfaces */
174    res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
175    CheckErr(res);
176
177    res = (*player)->GetInterface(player, SL_IID_VOLUME,  (void*)&volItf);
178    CheckErr(res);
179
180    res = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
181    CheckErr(res);
182    res = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf);
183    CheckErr(res);
184    res = (*prefetchItf)->SetCallbackEventsMask(prefetchItf,
185            SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
186
187    /* Display duration */
188    SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
189    res = (*playItf)->GetDuration(playItf, &durationInMsec);
190    CheckErr(res);
191    if (durationInMsec == SL_TIME_UNKNOWN) {
192        fprintf(stdout, "Content duration is unknown (before starting to prefetch)\n");
193        ASSERT_TRUE(false);
194    }
195
196    /* Set the player volume */
197    res = (*volItf)->SetVolumeLevel( volItf, -300);
198    CheckErr(res);
199
200    /* Play the URI */
201    /*     first cause the player to prefetch the data */
202    fprintf(stderr, "\nbefore set to PAUSED\n\n");
203    res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
204    fprintf(stderr, "\nafter set to PAUSED\n\n");
205    CheckErr(res);
206
207    /*     wait until there's data to play */
208    //SLpermille fillLevel = 0;
209    SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
210    SLuint32 timeOutIndex = 100; // 10s
211    while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
212        usleep(100 * 1000);
213        (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
214        timeOutIndex--;
215    }
216
217    if (timeOutIndex == 0) {
218        fprintf(stderr, "We\'re done here, failed to prefetch data in time, exiting\n");
219        ASSERT_TRUE(false);
220       // goto destroyRes;
221    }
222
223    /* Display duration again, */
224    res = (*playItf)->GetDuration(playItf, &durationInMsec);
225    CheckErr(res);
226    if (durationInMsec == SL_TIME_UNKNOWN) {
227        fprintf(stdout, "Content duration is unknown (after prefetch completed)\n");
228        ASSERT_TRUE(false);
229    }
230
231    res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
232    CheckErr(res);
233
234    /* Play for the song duration*/
235    usleep(MP3_DURATION * 1000);
236
237    /* Validate the play position*/
238    SLmillisecond currentPositionInMsec = SL_TIME_UNKNOWN;
239           res = (*playItf)->GetPosition(playItf, &currentPositionInMsec);
240           CheckErr(res);
241    if (currentPositionInMsec == SL_TIME_UNKNOWN) {
242      fprintf(stdout, "GetPosition returns UNKNOWN\n");
243      ASSERT_TRUE(false);
244    } else if ( currentPositionInMsec <= 0 ||
245        currentPositionInMsec > (MP3_DURATION * 1.1) ){
246        fprintf(stdout, "Current play position is %i : beyond the duration\n",
247                (int) currentPositionInMsec);
248        ASSERT_TRUE(false);
249    }
250
251    /* Make sure player is stopped */
252    fprintf(stdout, "URI example: stopping playback\n");
253    res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
254    CheckErr(res);
255
256destroyRes:
257
258    /* Destroy the player */
259    (*player)->Destroy(player);
260
261    /* Destroy Output Mix object */
262    (*OutputMix)->Destroy(OutputMix);
263}
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}
318