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