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