slesTest_playMuteSolo.cpp revision c6853892c94800e72c0bd676d5d2136d48cea76e
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
23#include <SLES/OpenSLES.h>
24
25
26#define MAX_NUMBER_INTERFACES 3
27
28#define TEST_MUTE 0
29#define TEST_SOLO 1
30
31typedef struct {
32    int testMode;
33    SLPlayItf playItf;
34    SLMuteSoloItf muteSoloItf;
35} Context;
36
37//-----------------------------------------------------------------
38/* Exits the application if an error is encountered */
39#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
40
41void ExitOnErrorFunc( SLresult result , int line)
42{
43    if (SL_RESULT_SUCCESS != result) {
44        fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line);
45        exit(EXIT_FAILURE);
46    }
47}
48
49//-----------------------------------------------------------------
50/* PlayItf callback for an audio player, will be called for every SL_PLAYEVENT_HEADATNEWPOS event */
51void PlayEventCallback( SLPlayItf caller,  void *pContext, SLuint32 event)
52{
53    Context *context = (Context *) pContext;
54    SLPlayItf playItf = context->playItf;
55    SLMuteSoloItf muteSolo = context->muteSoloItf;
56    SLuint8 numChannels = 0;
57    SLresult res = (*muteSolo)->GetNumChannels(muteSolo, &numChannels); ExitOnError(res);
58    //fprintf(stdout, "Content has %d channel(s)\n", numChannels);
59    SLmillisecond position;
60    res = (*playItf)->GetPosition(playItf, &position); ExitOnError(res);
61    printf("position=%u\n", (unsigned) position);
62
63    switch (context->testMode) {
64        case TEST_MUTE: {
65            //---------------------------------------------------
66            if (numChannels > 1) { // SLMuteSoloItf only works if more than one channel
67                SLboolean leftMuted = SL_BOOLEAN_TRUE;
68                res = (*muteSolo)->GetChannelMute(muteSolo, 0, &leftMuted); ExitOnError(res);
69                // swap channel mute
70                res = (*muteSolo)->SetChannelMute(muteSolo, 0,
71                       leftMuted == SL_BOOLEAN_TRUE ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE);
72                ExitOnError(res);
73                res = (*muteSolo)->SetChannelMute(muteSolo, 1,
74                       leftMuted == SL_BOOLEAN_TRUE ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE);
75                ExitOnError(res);
76                if (leftMuted == SL_BOOLEAN_TRUE) { // we've swapped the channel mute above
77                    fprintf(stdout, "channel 0: playing, channel 1: muted\n");
78                } else {
79                    fprintf(stdout, "channel 0: muted, channel 1: playing\n");
80                }
81            }
82            } break;
83
84        case TEST_SOLO: {
85            //---------------------------------------------------
86            if (numChannels > 1) { // SLMuteSoloItf only works if more than one channel
87                SLboolean leftSoloed = SL_BOOLEAN_TRUE;
88                res = (*muteSolo)->GetChannelSolo(muteSolo, 0, &leftSoloed); ExitOnError(res);
89                // swap channel solo
90                res = (*muteSolo)->SetChannelSolo(muteSolo, 0,
91                        leftSoloed == SL_BOOLEAN_TRUE ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE);
92                ExitOnError(res);
93                res = (*muteSolo)->SetChannelSolo(muteSolo, 1,
94                        leftSoloed == SL_BOOLEAN_TRUE ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE);
95                ExitOnError(res);
96                if (leftSoloed == SL_BOOLEAN_TRUE) { // we've swapped the channel solo above
97                    fprintf(stdout, "channel 0: normal, channel 1: soloed\n");
98                } else {
99                    fprintf(stdout, "channel 0: soloed, channel 1: normal\n");
100                }
101            }
102            } break;
103
104        default:
105            break;
106    }
107}
108
109//-----------------------------------------------------------------
110
111/* Play an audio URIs, mute and solo channels  */
112void TestPlayUri( SLObjectItf sl, const char* path)
113{
114    SLresult  result;
115    SLEngineItf EngineItf;
116
117    /* Objects this application uses: one player and an ouput mix */
118    SLObjectItf  player, outputMix;
119
120    /* Source of audio data to play */
121    SLDataSource      audioSource;
122    SLDataLocator_URI uri;
123    SLDataFormat_MIME mime;
124
125    /* Data sinks for the audio player */
126    SLDataSink               audioSink;
127    SLDataLocator_OutputMix  locator_outputmix;
128
129    /* Play, Volume and PrefetchStatus interfaces for the audio player */
130    SLPlayItf           playItf;
131    SLMuteSoloItf       muteSoloItf;
132    SLPrefetchStatusItf prefetchItf;
133
134    SLboolean required[MAX_NUMBER_INTERFACES];
135    SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
136
137    /* Get the SL Engine Interface which is implicit */
138    result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
139    ExitOnError(result);
140
141    /* Initialize arrays required[] and iidArray[] */
142    for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
143        required[i] = SL_BOOLEAN_FALSE;
144        iidArray[i] = SL_IID_NULL;
145    }
146
147    /* ------------------------------------------------------ */
148    /* Configuration of the output mix  */
149
150    /* Create Output Mix object to be used by the player */
151     result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required);
152     ExitOnError(result);
153
154    /* Realize the Output Mix object in synchronous mode */
155    result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
156    ExitOnError(result);
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    /* ------------------------------------------------------ */
165    /* Configuration of the player  */
166
167    /* Set arrays required[] and iidArray[] for SLMuteSoloItf and SLPrefetchStatusItf interfaces */
168    /*  (SLPlayItf is implicit) */
169    required[0] = SL_BOOLEAN_TRUE;
170    iidArray[0] = SL_IID_MUTESOLO;
171    required[1] = SL_BOOLEAN_TRUE;
172    iidArray[1] = SL_IID_PREFETCHSTATUS;
173
174    /* Setup the data source structure for the URI */
175    uri.locatorType = SL_DATALOCATOR_URI;
176    uri.URI         =  (SLchar*) path;
177    mime.formatType = SL_DATAFORMAT_MIME;
178    /*     this is how ignored mime information is specified, according to OpenSL ES spec
179     *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
180    mime.mimeType      = (SLchar*)NULL;
181    mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
182
183    audioSource.pFormat  = (void*)&mime;
184    audioSource.pLocator = (void*)&uri;
185
186    /* Create the audio player */
187    result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2,
188            iidArray, required);
189    ExitOnError(result);
190
191    /* Realize the player in synchronous mode. */
192    result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
193    fprintf(stdout, "URI example: after Realize\n");
194
195    /* Get the SLPlayItf, SLPrefetchStatusItf and SLMuteSoloItf interfaces for the player */
196    result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
197    ExitOnError(result);
198
199    result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
200    ExitOnError(result);
201
202    result = (*player)->GetInterface(player, SL_IID_MUTESOLO, (void*)&muteSoloItf);
203    ExitOnError(result);
204
205    // Attempt to get the channel count before it is necessarily known.
206    // This may fail depending on the platform.
207    SLuint8 numChannels = 123;
208    result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
209    printf("GetNumChannels after Realize but before pre-fetch: result=%u, numChannels=%u\n",
210        result, numChannels);
211
212    /* Initialize a context for use by the callback */
213    Context             context;
214    context.playItf = playItf;
215    context.muteSoloItf = muteSoloItf;
216    context.testMode = TEST_MUTE;
217
218    /*  Setup to receive playback events on position updates */
219    result = (*playItf)->RegisterCallback(playItf, PlayEventCallback, (void *) &context);
220    ExitOnError(result);
221    result = (*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATNEWPOS);
222    ExitOnError(result);
223    result = (*playItf)->SetPositionUpdatePeriod(playItf, 1000);
224    ExitOnError(result);
225
226    fprintf(stdout, "Player configured\n");
227
228    /* ------------------------------------------------------ */
229    /* Playback and test */
230
231    /* Start the data prefetching by setting the player to the paused state */
232    result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
233    ExitOnError(result);
234
235    /* Wait until there's data to play */
236    SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
237    while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
238        usleep(100 * 1000);
239        (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
240    }
241
242    /* Query the number of channels */
243    numChannels = 123;
244    result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
245    ExitOnError(result);
246    fprintf(stdout, "Content has %d channel(s)\n", numChannels);
247
248    if (numChannels == 1) {
249        fprintf(stdout, "SLMuteSolotItf only works one content with more than one channel. Bye\n");
250        goto destroyKillKill;
251    } else {
252        /* Mute left channel */
253        result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_TRUE);
254        ExitOnError(result);
255        result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE);
256        ExitOnError(result);
257    }
258
259    /* Run the test for 10s */
260    /* see PlayEventCallback() for more of the test of the SLMuteSoloItf interface */
261    fprintf(stdout, "\nTesting mute functionality:\n");
262    context.testMode = TEST_MUTE;
263    result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); ExitOnError(result);
264    usleep( 5 * 1000 * 1000);
265    result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_FALSE); ExitOnError(result);
266    result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE); ExitOnError(result);
267    fprintf(stdout, "\nTesting solo functionality:\n");
268    context.testMode = TEST_SOLO;
269    usleep( 5 * 1000 * 1000);
270
271    /* Make sure player is stopped */
272    fprintf(stdout, "Stopping playback\n");
273    result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
274    ExitOnError(result);
275
276destroyKillKill:
277
278    /* Destroy the players */
279    (*player)->Destroy(player);
280
281    /* Destroy Output Mix object */
282    (*outputMix)->Destroy(outputMix);
283}
284
285//-----------------------------------------------------------------
286int main(int argc, char* const argv[])
287{
288    SLresult    result;
289    SLObjectItf sl;
290
291    fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLMuteSoloItf\n",
292            argv[0]);
293    fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n");
294    fprintf(stdout, "Plays a sound and alternates the muting of the channels (for 5s).\n");
295    fprintf(stdout, " and then alternates the solo\'ing of the channels (for 5s).\n");
296    fprintf(stdout, "Stops after 10s\n");
297
298    if (argc == 1) {
299        fprintf(stdout, "Usage: \t%s url\n", argv[0]);
300        fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"\n", argv[0]);
301        exit(EXIT_FAILURE);
302    }
303
304    SLEngineOption EngineOption[] = {
305            {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
306    };
307
308    result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
309    ExitOnError(result);
310
311    /* Realizing the SL Engine in synchronous mode. */
312    result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
313    ExitOnError(result);
314
315    if (argc > 1) {
316        TestPlayUri(sl, argv[1]);
317    }
318
319    /* Shutdown OpenSL ES */
320    (*sl)->Destroy(sl);
321
322    return EXIT_SUCCESS;
323}
324