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