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 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 #include <fcntl.h>
23 
24 #include <SLES/OpenSLES.h>
25 #include <SLES/OpenSLES_Android.h>
26 
27 
28 #define MAX_NUMBER_INTERFACES 3
29 
30 #define TEST_MUTE 0
31 #define TEST_SOLO 1
32 
33 #define PREFETCHEVENT_ERROR_CANDIDATE \
34             (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
35 
36 //-----------------------------------------------------------------
37 /* Exits the application if an error is encountered */
38 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
39 
ExitOnErrorFunc(SLresult result,int line)40 void ExitOnErrorFunc( SLresult result , int line)
41 {
42     if (SL_RESULT_SUCCESS != result) {
43         fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line);
44         exit(EXIT_FAILURE);
45     }
46 }
47 
48 //-----------------------------------------------------------------
49 bool prefetchError = false;
50 
51 /* Callback for "prefetch" events, here used to detect audio resource opening errors */
PrefetchEventCallback(SLPrefetchStatusItf caller,void * pContext __unused,SLuint32 event)52 void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext __unused, SLuint32 event)
53 {
54     SLpermille level = 0;
55     SLresult result;
56     result = (*caller)->GetFillLevel(caller, &level);
57     ExitOnError(result);
58     SLuint32 status;
59     result = (*caller)->GetPrefetchStatus(caller, &status);
60     ExitOnError(result);
61     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
62             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
63         fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n");
64         prefetchError = true;
65     }
66 }
67 
68 //-----------------------------------------------------------------
69 
70 /* Play an audio path by opening a file descriptor on that path  */
TestPlayPathFromFD(SLObjectItf sl,const char * path,SLAint64 offset,SLAint64 size)71 void TestPlayPathFromFD( SLObjectItf sl, const char* path, SLAint64 offset, SLAint64 size)
72 {
73     SLresult  result;
74     SLEngineItf EngineItf;
75 
76     /* Objects this application uses: one player and an ouput mix */
77     SLObjectItf  player, outputMix;
78 
79     /* Source of audio data to play */
80     SLDataSource            audioSource;
81     SLDataLocator_AndroidFD locatorFd;
82     SLDataFormat_MIME       mime;
83 
84     /* Data sinks for the audio player */
85     SLDataSink               audioSink;
86     SLDataLocator_OutputMix  locator_outputmix;
87 
88     /* Play and PrefetchStatus interfaces for the audio player */
89     SLPlayItf              playItf;
90     SLPrefetchStatusItf    prefetchItf;
91 
92     SLboolean required[MAX_NUMBER_INTERFACES];
93     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
94 
95     /* Get the SL Engine Interface which is implicit */
96     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
97     ExitOnError(result);
98 
99     /* Initialize arrays required[] and iidArray[] */
100     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
101         required[i] = SL_BOOLEAN_FALSE;
102         iidArray[i] = SL_IID_NULL;
103     }
104 
105     /* ------------------------------------------------------ */
106     /* Configuration of the output mix  */
107 
108     /* Create Output Mix object to be used by the player */
109      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required);
110      ExitOnError(result);
111 
112     /* Realize the Output Mix object in synchronous mode */
113     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
114     ExitOnError(result);
115 
116     /* Setup the data sink structure */
117     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
118     locator_outputmix.outputMix   = outputMix;
119     audioSink.pLocator            = (void*)&locator_outputmix;
120     audioSink.pFormat             = NULL;
121 
122     /* ------------------------------------------------------ */
123     /* Configuration of the player  */
124 
125     /* Set arrays required[] and iidArray[] for SLPrefetchStatusItf interfaces */
126     /*  (SLPlayItf is implicit) */
127     required[0] = SL_BOOLEAN_TRUE;
128     iidArray[0] = SL_IID_PREFETCHSTATUS;
129 
130     /* Setup the data source structure for the URI */
131     locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD;
132     int fd = open(path, O_RDONLY);
133     if (fd == -1) {
134         perror(path);
135         exit(EXIT_FAILURE);
136     }
137     locatorFd.fd = (SLint32) fd;
138     locatorFd.length = size;
139     locatorFd.offset = offset;
140 
141     mime.formatType = SL_DATAFORMAT_MIME;
142     /*     this is how ignored mime information is specified, according to OpenSL ES spec
143      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
144     mime.mimeType      = (SLchar*)NULL;
145     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
146 
147     audioSource.pFormat  = (void*)&mime;
148     audioSource.pLocator = (void*)&locatorFd;
149 
150     /* Create the audio player */
151     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 1,
152             iidArray, required);
153     ExitOnError(result);
154 
155     /* Realize the player in synchronous mode. */
156     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
157     fprintf(stdout, "URI example: after Realize\n");
158 
159     /* Get the SLPlayItf, SLPrefetchStatusItf and SLAndroidStreamTypeItf interfaces for the player*/
160     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
161     ExitOnError(result);
162 
163     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
164     ExitOnError(result);
165 
166     /* Set up prefetching callback.*/
167     result = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf);
168     ExitOnError(result);
169     result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE);
170     ExitOnError(result);
171 
172     fprintf(stdout, "Player configured\n");
173 
174     /* ------------------------------------------------------ */
175     /* Playback and test */
176 
177     /* Start the data prefetching by setting the player to the paused state */
178     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
179     ExitOnError(result);
180 
181     /* Wait until there's data to play */
182     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
183     while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
184         usleep(100 * 1000);
185         result = (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
186         ExitOnError(result);
187         if (prefetchError) {
188             fprintf(stderr, "Failure to prefetch data, exiting\n");
189             ExitOnError(SL_RESULT_CONTENT_NOT_FOUND);
190         }
191     }
192 
193     /* Get duration */
194     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
195     result = (*playItf)->GetDuration(playItf, &durationInMsec);
196     ExitOnError(result);
197     if (durationInMsec == SL_TIME_UNKNOWN) {
198         durationInMsec = 5000;
199     }
200 
201     /* Start playback */
202     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
203     ExitOnError(result);
204 
205     usleep(durationInMsec * 1000);
206 
207     /* Make sure player is stopped */
208     fprintf(stdout, "Stopping playback\n");
209     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
210     ExitOnError(result);
211 
212     /* Destroy the player */
213     (*player)->Destroy(player);
214 
215     /* Destroy Output Mix object */
216     (*outputMix)->Destroy(outputMix);
217 
218     close(fd);
219 }
220 
221 //-----------------------------------------------------------------
main(int argc,char * const argv[])222 int main(int argc, char* const argv[])
223 {
224     SLresult    result;
225     SLObjectItf sl;
226 
227     fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf ", argv[0]);
228     fprintf(stdout, "and AudioPlayer with SLDataLocator_AndroidFD source / OutputMix sink\n");
229     fprintf(stdout, "Plays the sound file designated by the given path, ");
230     fprintf(stdout, "starting at the specified offset, and using the specified length.\n");
231     fprintf(stdout, "Omit the length of the file for it to be computed by the system.\n");
232 
233     if (argc < 3) {
234         fprintf(stdout, "Usage: \t%s path offsetInBytes [sizeInBytes]\n", argv[0]);
235         fprintf(stdout, "Example: \"%s /sdcard/my.mp3 0 344460\" \n", argv[0]);
236         exit(EXIT_FAILURE);
237     }
238 
239     SLEngineOption EngineOption[] = {
240             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
241     };
242 
243     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
244     ExitOnError(result);
245 
246     /* Realizing the SL Engine in synchronous mode. */
247     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
248     ExitOnError(result);
249 
250     if (argc == 3) {
251         fprintf(stdout, "no file size given, using SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE\n");
252         TestPlayPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]),
253                 SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE);
254     } else {
255         TestPlayPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]), (SLAint64)atoi(argv[3]));
256     }
257 
258     /* Shutdown OpenSL ES */
259     (*sl)->Destroy(sl);
260 
261     return EXIT_SUCCESS;
262 }
263