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 #ifdef ANDROID
26 #include <SLES/OpenSLES_Android.h>
27 #endif
28 
29 
30 #define MAX_NUMBER_INTERFACES 3
31 
32 #define TIME_S_BETWEEN_EQ_ON_OFF 3
33 
34 //-----------------------------------------------------------------
35 /* Exits the application if an error is encountered */
36 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
37 
ExitOnErrorFunc(SLresult result,int line)38 void ExitOnErrorFunc( SLresult result , int line)
39 {
40     if (SL_RESULT_SUCCESS != result) {
41         fprintf(stderr, "%u error code encountered at line %d, exiting\n", result, line);
42         exit(EXIT_FAILURE);
43     }
44 }
45 
46 
47 //-----------------------------------------------------------------
48 
49 /* Play an audio path by opening a file descriptor on that path  */
TestEQPathFromFD(SLObjectItf sl,const char * path,SLAint64 offset,SLAint64 size,bool alwaysOn)50 void TestEQPathFromFD( SLObjectItf sl, const char* path
51 #ifdef ANDROID
52     , SLAint64 offset, SLAint64 size
53 #endif
54     , bool alwaysOn
55     )
56 {
57     SLresult  result;
58     SLEngineItf EngineItf;
59 
60     /* Objects this application uses: one player and an ouput mix */
61     SLObjectItf  player, outputMix;
62 
63     /* Source of audio data to play */
64     SLDataSource            audioSource;
65 #ifdef ANDROID
66     SLDataLocator_AndroidFD locatorFd;
67 #else
68     SLDataLocator_URI       locatorUri;
69 #endif
70     SLDataFormat_MIME       mime;
71 
72     /* Data sinks for the audio player */
73     SLDataSink               audioSink;
74     SLDataLocator_OutputMix  locator_outputmix;
75 
76     /* Play and PrefetchStatus interfaces for the audio player */
77     SLPlayItf              playItf;
78     SLPrefetchStatusItf    prefetchItf;
79     SLEqualizerItf         eqItf;
80 
81     SLboolean required[MAX_NUMBER_INTERFACES];
82     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
83 
84     /* Get the SL Engine Interface which is implicit */
85     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
86     ExitOnError(result);
87 
88     /* Initialize arrays required[] and iidArray[] */
89     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
90         required[i] = SL_BOOLEAN_FALSE;
91         iidArray[i] = SL_IID_NULL;
92     }
93 
94     /* ------------------------------------------------------ */
95     /* Configuration of the output mix  */
96 
97     /* Create Output Mix object to be used by the player */
98      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 1, iidArray, required);
99      ExitOnError(result);
100 
101     /* Realize the Output Mix object in synchronous mode */
102     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
103     ExitOnError(result);
104 
105     /* Setup the data sink structure */
106     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
107     locator_outputmix.outputMix   = outputMix;
108     audioSink.pLocator            = (void*)&locator_outputmix;
109     audioSink.pFormat             = NULL;
110 
111     /* ------------------------------------------------------ */
112     /* Configuration of the player  */
113 
114     /* Set arrays required[] and iidArray[] for SLPrefetchStatusItf interfaces */
115     /*  (SLPlayItf is implicit) */
116     required[0] = SL_BOOLEAN_TRUE;
117     iidArray[0] = SL_IID_PREFETCHSTATUS;
118     required[1] = SL_BOOLEAN_TRUE;
119     iidArray[1] = SL_IID_EQUALIZER;
120 
121     /* Setup the data source structure for the URI */
122 #ifdef ANDROID
123     locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD;
124     int fd = open(path, O_RDONLY);
125     if (fd == -1) {
126         ExitOnError(SL_RESULT_RESOURCE_ERROR);
127     }
128     locatorFd.fd = (SLint32) fd;
129     locatorFd.length = size;
130     locatorFd.offset = offset;
131 #else
132     locatorUri.locatorType = SL_DATALOCATOR_URI;
133     locatorUri.URI = (SLchar *) path;
134 #endif
135 
136     mime.formatType = SL_DATAFORMAT_MIME;
137     /*     this is how ignored mime information is specified, according to OpenSL ES spec
138      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
139     mime.mimeType      = (SLchar*)NULL;
140     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
141 
142     audioSource.pFormat  = (void*)&mime;
143 #ifdef ANDROID
144     audioSource.pLocator = (void*)&locatorFd;
145 #else
146     audioSource.pLocator = (void*)&locatorUri;
147 #endif
148 
149     /* Create the audio player */
150     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2,
151             iidArray, required);
152     ExitOnError(result);
153 
154     /* Realize the player in synchronous mode. */
155     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
156     fprintf(stdout, "URI example: after Realize\n");
157 
158     /* Get the SLPlayItf, SLPrefetchStatusItf and SLAndroidStreamTypeItf interfaces for the player*/
159     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
160     ExitOnError(result);
161 
162     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
163     ExitOnError(result);
164 
165     result = (*player)->GetInterface(player, SL_IID_EQUALIZER, (void*)&eqItf);
166     ExitOnError(result);
167 
168     fprintf(stdout, "Player configured\n");
169 
170     /* ------------------------------------------------------ */
171     /* Playback and test */
172 
173     /* Start the data prefetching by setting the player to the paused state */
174     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
175     ExitOnError(result);
176 
177     /* Wait until there's data to play */
178     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
179     while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
180         usleep(100 * 1000);
181         (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
182         ExitOnError(result);
183     }
184 
185     /* Get duration */
186     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
187     result = (*playItf)->GetDuration(playItf, &durationInMsec);
188     ExitOnError(result);
189     if (durationInMsec == SL_TIME_UNKNOWN) {
190         durationInMsec = 5000;
191     }
192 
193     /* Start playback */
194     fprintf(stdout, "Starting to play\n");
195     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING );
196     ExitOnError(result);
197 
198     /* Configure EQ */
199     SLuint16 nbPresets, preset, nbBands = 0;
200     result = (*eqItf)->GetNumberOfBands(eqItf, &nbBands);
201     ExitOnError(result);
202     result = (*eqItf)->GetNumberOfPresets(eqItf, &nbPresets);
203     ExitOnError(result);
204     /*    Start from a preset  */
205     preset = nbPresets > 2 ?  2 : 0;
206     result = (*eqItf)->UsePreset(eqItf, preset);
207 
208     preset = 1977;
209     result = (*eqItf)->GetCurrentPreset(eqItf, &preset);
210     ExitOnError(result);
211     if (SL_EQUALIZER_UNDEFINED == preset) {
212         fprintf(stderr, "Using SL_EQUALIZER_UNDEFINED preset, unexpected here!\n");
213     } else {
214         fprintf(stdout, "Using preset %d\n", preset);
215     }
216 
217     /*    Tweak it so it's obvious it gets turned on/off later */
218     SLmillibel minLevel, maxLevel = 0;
219     result = (*eqItf)->GetBandLevelRange(eqItf, &minLevel, &maxLevel);
220     ExitOnError(result);
221     fprintf(stdout, "Band level range = %dmB to %dmB\n", minLevel, maxLevel);
222 
223     SLuint16 b = 0;
224     for(b = 0 ; b < nbBands/2 ; b++) {
225         result = (*eqItf)->SetBandLevel(eqItf, b, minLevel);
226         ExitOnError(result);
227     }
228     for(b = nbBands/2 ; b < nbBands ; b++) {
229         result = (*eqItf)->SetBandLevel(eqItf, b, maxLevel);
230         ExitOnError(result);
231     }
232 
233     SLmillibel level = 0;
234     for(b = 0 ; b < nbBands ; b++) {
235         result = (*eqItf)->GetBandLevel(eqItf, b, &level);
236         ExitOnError(result);
237         fprintf(stdout, "Band %d level = %dmB\n", b, level);
238     }
239 
240     /* Switch EQ on/off every TIME_S_BETWEEN_EQ_ON_OFF seconds unless always on */
241     SLboolean previousEnabled = SL_BOOLEAN_FALSE;
242     for(unsigned int j=0 ; j<(durationInMsec/(1000*TIME_S_BETWEEN_EQ_ON_OFF)) ; j++) {
243         SLboolean enabled;
244         result = (*eqItf)->IsEnabled(eqItf, &enabled);
245         ExitOnError(result);
246         enabled = alwaysOn || !enabled;
247         if (enabled != previousEnabled) {
248             result = (*eqItf)->SetEnabled(eqItf, enabled);
249             ExitOnError(result);
250             previousEnabled = enabled;
251             if (SL_BOOLEAN_TRUE == enabled) {
252                 fprintf(stdout, "EQ on\n");
253             } else {
254                 fprintf(stdout, "EQ off\n");
255             }
256         }
257         usleep(TIME_S_BETWEEN_EQ_ON_OFF * 1000 * 1000);
258     }
259 
260     /* Make sure player is stopped */
261     fprintf(stdout, "Stopping playback\n");
262     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
263     ExitOnError(result);
264 
265     /* Destroy the player */
266     (*player)->Destroy(player);
267 
268     /* Destroy Output Mix object */
269     (*outputMix)->Destroy(outputMix);
270 
271 #ifdef ANDROID
272     close(fd);
273 #endif
274 }
275 
276 //-----------------------------------------------------------------
main(int argc,char * const argv[])277 int main(int argc, char* const argv[])
278 {
279     const char *programName = argv[0];
280     SLresult    result;
281     SLObjectItf sl;
282 
283     fprintf(stdout, "OpenSL ES test %s: exercises SLEqualizerItf ", programName);
284     fprintf(stdout, "and AudioPlayer with SLDataLocator_AndroidFD source / OutputMix sink\n");
285     fprintf(stdout, "Plays the sound file designated by the given path, ");
286     fprintf(stdout, "starting at the specified offset, and using the specified length.\n");
287     fprintf(stdout, "Omit the length of the file for it to be computed by the system.\n");
288     fprintf(stdout, "Every %d seconds, the EQ will be turned on and off,\n",
289             TIME_S_BETWEEN_EQ_ON_OFF);
290     fprintf(stdout, "unless the --always-on option is specified before the path.\n");
291 
292     bool alwaysOn = false;
293     if (argc >= 2 && !strcmp(argv[1], "--always-on")) {
294         alwaysOn = true;
295         --argc;
296         ++argv;
297     }
298 
299 #ifdef ANDROID
300     if (argc < 3)
301 #else
302     if (argc < 1)
303 #endif
304     {
305         fprintf(stdout, "Usage: \t%s [--always-on] path offsetInBytes [sizeInBytes]\n",
306                 programName);
307         fprintf(stdout, "Example: \"%s /sdcard/my.mp3 0 344460\" \n", programName);
308         exit(EXIT_FAILURE);
309     }
310 
311     SLEngineOption EngineOption[] = {
312             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
313     };
314 
315     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
316     ExitOnError(result);
317 
318     /* Realizing the SL Engine in synchronous mode. */
319     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
320     ExitOnError(result);
321 
322 #ifdef ANDROID
323     if (argc == 3) {
324         fprintf(stdout, "\nno file size given, using SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE\n\n");
325         TestEQPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]),
326                 SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE, alwaysOn);
327     } else {
328         TestEQPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]), (SLAint64)atoi(argv[3]), alwaysOn);
329     }
330 #else
331     TestEQPathFromFD(sl, argv[1]);
332 #endif
333 
334     /* Shutdown OpenSL ES */
335     (*sl)->Destroy(sl);
336 
337     return EXIT_SUCCESS;
338 }
339