slesTest_playMuteSolo.cpp revision 01e9f5fa4698856f92bcfd88188ee4c8397b22db
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    /* Initialize a context for use by the callback */
216    Context             context;
217    context.playItf = playItf;
218    context.muteSoloItf = muteSoloItf;
219    context.testMode = TEST_MUTE;
220
221    /*  Setup to receive playback events on position updates */
222    result = (*playItf)->RegisterCallback(playItf, PlayEventCallback, (void *) &context);
223    ExitOnError(result);
224    result = (*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATNEWPOS);
225    ExitOnError(result);
226    result = (*playItf)->SetPositionUpdatePeriod(playItf, 1000);
227    ExitOnError(result);
228
229    fprintf(stdout, "Player configured\n");
230
231    /* ------------------------------------------------------ */
232    /* Playback and test */
233
234    /* Start the data prefetching by setting the player to the paused state */
235    result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
236    ExitOnError(result);
237
238    /* Wait until there's data to play */
239    SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
240    while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
241        usleep(100 * 1000);
242        (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
243    }
244
245    /* Query the number of channels */
246    SLuint8 numChannels = 0;
247    result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
248    ExitOnError(result);
249    fprintf(stdout, "Content has %d channel(s)\n", numChannels);
250
251    if (numChannels == 1) {
252        fprintf(stdout, "SLMuteSolotItf only works one content with more than one channel. Bye\n");
253        goto destroyKillKill;
254    } else {
255        /* Mute left channel */
256        result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_TRUE);
257        ExitOnError(result);
258        result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE);
259        ExitOnError(result);
260    }
261
262    /* Run the test for 10s */
263    /* see PlayEventCallback() for more of the test of the SLMuteSoloItf interface */
264    fprintf(stdout, "\nTesting mute functionality:\n");
265    context.testMode = TEST_MUTE;
266    result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); ExitOnError(result);
267    usleep( 5 * 1000 * 1000);
268    result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_FALSE); ExitOnError(result);
269    result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE); ExitOnError(result);
270    fprintf(stdout, "\nTesting solo functionality:\n");
271    context.testMode = TEST_SOLO;
272    usleep( 5 * 1000 * 1000);
273
274    /* Make sure player is stopped */
275    fprintf(stdout, "Stopping playback\n");
276    result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
277    ExitOnError(result);
278
279destroyKillKill:
280
281    /* Destroy the players */
282    (*player)->Destroy(player);
283
284    /* Destroy Output Mix object */
285    (*outputMix)->Destroy(outputMix);
286}
287
288//-----------------------------------------------------------------
289int main(int argc, char* const argv[])
290{
291    LOGV("Starting %s\n", argv[0]);
292
293    SLresult    result;
294    SLObjectItf sl;
295
296    fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLMuteSoloItf\n",
297            argv[0]);
298    fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n");
299    fprintf(stdout, "Plays a sound and alternates the muting of the channels (for 5s).\n");
300    fprintf(stdout, " and then alternates the solo\'ing of the channels (for 5s).\n");
301    fprintf(stdout, "Stops after 10s\n");
302
303    if (argc == 1) {
304        fprintf(stdout, "Usage: \t%s url\n", argv[0]);
305        fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"\n", argv[0]);
306        exit(1);
307    }
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    if (argc > 1) {
321        TestPlayUri(sl, argv[1]);
322    }
323
324    /* Shutdown OpenSL ES */
325    (*sl)->Destroy(sl);
326    exit(0);
327
328    return 0;
329}
330