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 // Demonstrate environmental reverb and preset reverb on an output mix and audio player
18 
19 #include <SLES/OpenSLES.h>
20 #include <assert.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 
27 #define bool int
28 #define false 0
29 #define true 1
30 
31 // Table of I3DL2 named environmental reverb settings
32 
33 typedef struct {
34     const char *mName;
35     SLEnvironmentalReverbSettings mSettings;
36 } Pair;
37 
38 #define _(name) {#name, SL_I3DL2_ENVIRONMENT_PRESET_##name},
39 
40 Pair pairs[] = {
41     _(DEFAULT)
42     _(GENERIC)
43     _(PADDEDCELL)
44     _(ROOM)
45     _(BATHROOM)
46     _(LIVINGROOM)
47     _(STONEROOM)
48     _(AUDITORIUM)
49     _(CONCERTHALL)
50     _(CAVE)
51     _(ARENA)
52     _(HANGAR)
53     _(CARPETEDHALLWAY)
54     _(HALLWAY)
55     _(STONECORRIDOR)
56     _(ALLEY)
57     _(FOREST)
58     _(CITY)
59     _(MOUNTAINS)
60     _(QUARRY)
61     _(PLAIN)
62     _(PARKINGLOT)
63     _(SEWERPIPE)
64     _(UNDERWATER)
65     _(SMALLROOM)
66     _(MEDIUMROOM)
67     _(LARGEROOM)
68     _(MEDIUMHALL)
69     _(LARGEHALL)
70     _(PLATE)
71 };
72 
73 // Parameters for preset reverb on output mix
74 bool outputMixPresetItfRequested = false;
75 SLuint16 outputMixPresetNumber = ~0;
76 
77 // Parameters for environmental reverb on output mix
78 bool outputMixEnvironmentalItfRequested = false;
79 char *outputMixEnvironmentalName = NULL;
80 SLEnvironmentalReverbSettings outputMixEnvironmentalSettings;
81 
82 // Parameters for preset reverb on audio player (not supported)
83 bool playerPresetItfRequested = false;
84 SLuint16 playerPresetNumber = ~0;
85 
86 // Parameters for environmental reverb on audio player (not supported)
87 bool playerEnvironmentalItfRequested = false;
88 char *playerEnvironmentalName = NULL;
89 SLEnvironmentalReverbSettings playerEnvironmentalSettings;
90 
91 // Compare two environmental reverb settings structures.
92 // Returns true if the settings are identical, or false if they are different.
93 
slesutCompareEnvironmentalReverbSettings(const SLEnvironmentalReverbSettings * settings1,const SLEnvironmentalReverbSettings * settings2)94 bool slesutCompareEnvironmentalReverbSettings(
95         const SLEnvironmentalReverbSettings *settings1,
96         const SLEnvironmentalReverbSettings *settings2)
97 {
98     return
99         (settings1->roomLevel == settings2->roomLevel) &&
100         (settings1->roomHFLevel == settings2->roomHFLevel) &&
101         (settings1->decayTime == settings2->decayTime) &&
102         (settings1->decayHFRatio == settings2->decayHFRatio) &&
103         (settings1->reflectionsLevel == settings2->reflectionsLevel) &&
104         (settings1->reflectionsDelay == settings2->reflectionsDelay) &&
105         (settings1->reverbLevel == settings2->reverbLevel) &&
106         (settings1->reverbDelay == settings2->reverbDelay) &&
107         (settings1->diffusion == settings2->diffusion) &&
108         (settings1->density == settings2->density);
109 }
110 
111 // Print an environmental reverb settings structure.
112 
slesutPrintEnvironmentalReverbSettings(const SLEnvironmentalReverbSettings * settings)113 void slesutPrintEnvironmentalReverbSettings(const SLEnvironmentalReverbSettings *settings)
114 {
115     printf("roomLevel: %d\n", settings->roomLevel);
116     printf("roomHFLevel: %d\n", settings->roomHFLevel);
117     printf("decayTime: %d\n", settings->decayTime);
118     printf("decayHFRatio: %d\n", settings->decayHFRatio);
119     printf("reflectionsLevel: %d\n", settings->reflectionsLevel);
120     printf("reflectionsDelay: %d\n", settings->reflectionsDelay);
121     printf("reverbLevel: %d\n", settings->reverbLevel);
122     printf("reverbDelay: %d\n", settings->reverbDelay);
123     printf("diffusion: %d\n", settings->diffusion);
124     printf("density: %d\n", settings->density);
125 }
126 
127 // Lookup environmental reverb settings by name
128 
lookupEnvName(const char * name)129 const SLEnvironmentalReverbSettings *lookupEnvName(const char *name)
130 {
131     unsigned j;
132     for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) {
133         if (!strcasecmp(name, pairs[j].mName)) {
134             return &pairs[j].mSettings;
135         }
136     }
137     return NULL;
138 }
139 
140 // Print all available environmental reverb names
141 
printEnvNames(void)142 void printEnvNames(void)
143 {
144     unsigned j;
145     bool needSpace = false;
146     bool needNewline = false;
147     unsigned lineLen = 0;
148     for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) {
149         const char *name = pairs[j].mName;
150         unsigned nameLen = strlen(name);
151         if (lineLen + (needSpace ? 1 : 0) + nameLen > 72) {
152             putchar('\n');
153             needSpace = false;
154             needNewline = false;
155             lineLen = 0;
156         }
157         if (needSpace) {
158             putchar(' ');
159             ++lineLen;
160         }
161         fputs(name, stdout);
162         lineLen += nameLen;
163         needSpace = true;
164         needNewline = true;
165     }
166     if (needNewline) {
167         putchar('\n');
168     }
169 }
170 
171 // These are extensions to OpenSL ES 1.0.1 values
172 
173 #define SL_PREFETCHSTATUS_UNKNOWN ((SLuint32) 0)
174 #define SL_PREFETCHSTATUS_ERROR   ((SLuint32) -1)
175 
176 // Mutex and condition shared with main program to protect prefetch_status
177 
178 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
179 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
180 SLuint32 prefetch_status = SL_PREFETCHSTATUS_UNKNOWN;
181 
182 /* used to detect errors likely to have occured when the OpenSL ES framework fails to open
183  * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond.
184  */
185 #define PREFETCHEVENT_ERROR_CANDIDATE \
186         (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
187 
188 // Prefetch status callback
189 
prefetch_callback(SLPrefetchStatusItf caller,void * context,SLuint32 event)190 void prefetch_callback(SLPrefetchStatusItf caller, void *context, SLuint32 event)
191 {
192     SLresult result;
193     assert(context == NULL);
194     SLpermille level;
195     result = (*caller)->GetFillLevel(caller, &level);
196     assert(SL_RESULT_SUCCESS == result);
197     SLuint32 status;
198     result = (*caller)->GetPrefetchStatus(caller, &status);
199     assert(SL_RESULT_SUCCESS == result);
200     SLuint32 new_prefetch_status;
201     if ((event & PREFETCHEVENT_ERROR_CANDIDATE) == PREFETCHEVENT_ERROR_CANDIDATE
202             && level == 0 && status == SL_PREFETCHSTATUS_UNDERFLOW) {
203         new_prefetch_status = SL_PREFETCHSTATUS_ERROR;
204     } else if (event == SL_PREFETCHEVENT_STATUSCHANGE &&
205             status == SL_PREFETCHSTATUS_SUFFICIENTDATA) {
206         new_prefetch_status = status;
207     } else {
208         return;
209     }
210     int ok;
211     ok = pthread_mutex_lock(&mutex);
212     assert(ok == 0);
213     prefetch_status = new_prefetch_status;
214     ok = pthread_cond_signal(&cond);
215     assert(ok == 0);
216     ok = pthread_mutex_unlock(&mutex);
217     assert(ok == 0);
218 }
219 
220 // Main program
221 
main(int argc,char ** argv)222 int main(int argc, char **argv)
223 {
224     SLresult result;
225     bool loop = false;
226 
227     // process command line parameters
228     char *prog = argv[0];
229     int i;
230     for (i = 1; i < argc; ++i) {
231         char *arg = argv[i];
232         if (arg[0] != '-')
233             break;
234         bool bad = false;   // whether the option string is invalid
235         if (!strncmp(arg, "--mix-preset", 12)) {
236             if ('\0' == arg[12]) {
237                 outputMixPresetItfRequested = true;
238             } else if ('=' == arg[12]) {
239                 outputMixPresetNumber = atoi(&arg[13]);
240                 outputMixPresetItfRequested = true;
241             } else {
242                 bad = true;
243             }
244         } else if (!strncmp(arg, "--mix-name", 10)) {
245             if ('\0' == arg[10]) {
246                 outputMixEnvironmentalItfRequested = true;
247             } else if ('=' == arg[10]) {
248                 outputMixEnvironmentalName = &arg[11];
249                 outputMixEnvironmentalItfRequested = true;
250             } else {
251                 bad = true;
252             }
253         } else if (!strncmp(arg, "--player-preset", 15)) {
254             if ('\0' == arg[15]) {
255                 playerPresetItfRequested = true;
256             } else if ('=' == arg[15]) {
257                 playerPresetNumber = atoi(&arg[16]);
258                 playerPresetItfRequested = true;
259             } else {
260                 bad = true;
261             }
262         } else if (!strncmp(arg, "--player-name", 13)) {
263             if ('\0' == arg[13]) {
264                 playerEnvironmentalItfRequested = true;
265             } else if ('=' == arg[13]) {
266                 playerEnvironmentalName = &arg[14];
267                 playerEnvironmentalItfRequested = true;
268             } else {
269                 bad = true;
270             }
271         } else if (!strcmp(arg, "--loop")) {
272             loop = true;
273         } else {
274             bad = true;
275         }
276         if (bad) {
277             fprintf(stderr, "%s: unknown option %s ignored\n", prog, arg);
278         }
279     }
280     if (argc - i != 1) {
281         fprintf(stderr, "usage: %s --mix-preset=# --mix-name=I3DL2 --player-preset=# "
282                 "--player-name=I3DL2 --loop filename\n", prog);
283         return EXIT_FAILURE;
284     }
285     char *pathname = argv[i];
286 
287     const SLEnvironmentalReverbSettings *envSettings;
288     if (NULL != outputMixEnvironmentalName) {
289         envSettings = lookupEnvName(outputMixEnvironmentalName);
290         if (NULL == envSettings) {
291             fprintf(stderr, "%s: output mix environmental reverb name %s not found, "
292                     "available names are:\n", prog, outputMixEnvironmentalName);
293             printEnvNames();
294             return EXIT_FAILURE;
295         }
296         outputMixEnvironmentalSettings = *envSettings;
297     }
298     if (NULL != playerEnvironmentalName) {
299         envSettings = lookupEnvName(playerEnvironmentalName);
300         if (NULL == envSettings) {
301             fprintf(stderr, "%s: player environmental reverb name %s not found, "
302                     "available names are:\n", prog, playerEnvironmentalName);
303             printEnvNames();
304             return EXIT_FAILURE;
305         }
306         playerEnvironmentalSettings = *envSettings;
307     }
308 
309     // create engine
310     SLObjectItf engineObject;
311     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
312     assert(SL_RESULT_SUCCESS == result);
313     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
314     assert(SL_RESULT_SUCCESS == result);
315     SLEngineItf engineEngine;
316     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
317     assert(SL_RESULT_SUCCESS == result);
318 
319     // create output mix
320     SLInterfaceID mix_ids[2];
321     SLboolean mix_req[2];
322     SLuint32 count = 0;
323     if (outputMixPresetItfRequested) {
324         mix_req[count] = SL_BOOLEAN_TRUE;
325         mix_ids[count++] = SL_IID_PRESETREVERB;
326     }
327     if (outputMixEnvironmentalItfRequested) {
328         mix_req[count] = SL_BOOLEAN_TRUE;
329         mix_ids[count++] = SL_IID_ENVIRONMENTALREVERB;
330     }
331     SLObjectItf mixObject;
332     result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, count, mix_ids, mix_req);
333     assert(SL_RESULT_SUCCESS == result);
334     result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
335     assert(SL_RESULT_SUCCESS == result);
336 
337     // configure preset reverb on output mix
338     SLPresetReverbItf outputMixPresetReverb;
339     if (outputMixPresetItfRequested) {
340         result = (*mixObject)->GetInterface(mixObject, SL_IID_PRESETREVERB, &outputMixPresetReverb);
341         assert(SL_RESULT_SUCCESS == result);
342         SLuint16 getPresetReverb = 12345;
343         result = (*outputMixPresetReverb)->GetPreset(outputMixPresetReverb, &getPresetReverb);
344         assert(SL_RESULT_SUCCESS == result);
345         printf("Output mix default preset reverb number = %u\n", getPresetReverb);
346         if (outputMixPresetNumber != ((SLuint16) ~0)) {
347             result = (*outputMixPresetReverb)->SetPreset(outputMixPresetReverb,
348                     outputMixPresetNumber);
349             if (SL_RESULT_SUCCESS == result) {
350                 result = (*outputMixPresetReverb)->GetPreset(outputMixPresetReverb,
351                         &getPresetReverb);
352                 assert(SL_RESULT_SUCCESS == result);
353                 assert(getPresetReverb == outputMixPresetNumber);
354                 printf("Output mix preset reverb successfully changed to %u\n",
355                         outputMixPresetNumber);
356             } else {
357                 printf("Unable to set output mix preset reverb to %u, result=%u\n",
358                         outputMixPresetNumber, result);
359             }
360         }
361     }
362 
363     // configure environmental reverb on output mix
364     SLEnvironmentalReverbItf outputMixEnvironmentalReverb;
365     if (outputMixEnvironmentalItfRequested) {
366         result = (*mixObject)->GetInterface(mixObject, SL_IID_ENVIRONMENTALREVERB,
367                 &outputMixEnvironmentalReverb);
368         assert(SL_RESULT_SUCCESS == result);
369         SLEnvironmentalReverbSettings getSettings;
370         result = (*outputMixEnvironmentalReverb)->GetEnvironmentalReverbProperties(
371                 outputMixEnvironmentalReverb, &getSettings);
372         assert(SL_RESULT_SUCCESS == result);
373         printf("Output mix default environmental reverb settings\n");
374         printf("------------------------------------------------\n");
375         slesutPrintEnvironmentalReverbSettings(&getSettings);
376         printf("\n");
377         if (outputMixEnvironmentalName != NULL) {
378             result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
379                     outputMixEnvironmentalReverb, &outputMixEnvironmentalSettings);
380             assert(SL_RESULT_SUCCESS == result);
381             printf("Output mix new environmental reverb settings\n");
382             printf("--------------------------------------------\n");
383             slesutPrintEnvironmentalReverbSettings(&outputMixEnvironmentalSettings);
384             printf("\n");
385             result = (*outputMixEnvironmentalReverb)->GetEnvironmentalReverbProperties(
386                     outputMixEnvironmentalReverb, &getSettings);
387             assert(SL_RESULT_SUCCESS == result);
388             printf("Output mix read environmental reverb settings\n");
389             printf("--------------------------------------------\n");
390             slesutPrintEnvironmentalReverbSettings(&getSettings);
391             printf("\n");
392             if (!slesutCompareEnvironmentalReverbSettings(&getSettings,
393                     &outputMixEnvironmentalSettings)) {
394                 printf("Warning: new and read are different; check details above\n");
395             } else {
396                 printf("New and read match, life is good\n");
397             }
398         }
399     }
400 
401     // create audio player
402     SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathname};
403     SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
404     SLDataSource audioSrc = {&locURI, &dfMIME};
405     SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
406     SLDataSink audioSnk = {&locOutputMix, NULL};
407     SLInterfaceID player_ids[5];
408     SLboolean player_req[5];
409     count = 0;
410     if (playerPresetItfRequested) {
411         player_req[count] = SL_BOOLEAN_TRUE;
412         player_ids[count++] = SL_IID_PRESETREVERB;
413     }
414     if (playerEnvironmentalItfRequested) {
415         player_req[count] = SL_BOOLEAN_TRUE;
416         player_ids[count++] = SL_IID_ENVIRONMENTALREVERB;
417     }
418     if (outputMixPresetItfRequested || outputMixEnvironmentalItfRequested) {
419         player_req[count] = SL_BOOLEAN_TRUE;
420         player_ids[count++] = SL_IID_EFFECTSEND;
421     }
422     if (loop) {
423         player_req[count] = SL_BOOLEAN_TRUE;
424         player_ids[count++] = SL_IID_SEEK;
425     }
426     player_req[count] = SL_BOOLEAN_TRUE;
427     player_ids[count++] = SL_IID_PREFETCHSTATUS;
428     SLObjectItf playerObject;
429     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
430         &audioSnk, count, player_ids, player_req);
431     assert(SL_RESULT_SUCCESS == result);
432 
433     // realize audio player
434     result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
435     assert(SL_RESULT_SUCCESS == result);
436 
437     // if reverb is on output mix (aux effect), then enable it for this player
438     if (outputMixPresetItfRequested || outputMixEnvironmentalItfRequested) {
439         SLEffectSendItf playerEffectSend;
440         result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
441         assert(SL_RESULT_SUCCESS == result);
442         SLboolean enabled;
443         SLmillibel directLevel;
444         SLmillibel sendLevel;
445         if (outputMixPresetItfRequested) {
446             result = (*playerEffectSend)->IsEnabled(playerEffectSend, outputMixPresetReverb,
447                     &enabled);
448             assert(SL_RESULT_SUCCESS == result);
449             printf("Output mix preset reverb: player effect send default enabled = %s\n",
450                     enabled ? "true" : "false");
451             directLevel = 12345;
452             result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel);
453             assert(SL_RESULT_SUCCESS == result);
454             printf("Output mix preset reverb: player effect send default direct level = %d\n",
455                     directLevel);
456             sendLevel = 12345;
457             result = (*playerEffectSend)->GetSendLevel(playerEffectSend, outputMixPresetReverb,
458                     &sendLevel);
459             assert(SL_RESULT_SUCCESS == result);
460             printf("Output mix preset reverb: player effect send default send level = %d\n",
461                     sendLevel);
462             if (outputMixPresetNumber != ((SLuint16) ~0)) {
463                 result = (*playerEffectSend)->EnableEffectSend(playerEffectSend,
464                         outputMixPresetReverb, SL_BOOLEAN_TRUE, (SLmillibel) 0);
465                 assert(SL_RESULT_SUCCESS == result);
466                 result = (*playerEffectSend)->IsEnabled(playerEffectSend, outputMixPresetReverb,
467                         &enabled);
468                 assert(SL_RESULT_SUCCESS == result);
469                 directLevel = 12345;
470                 result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel);
471                 assert(SL_RESULT_SUCCESS == result);
472                 sendLevel = 12345;
473                 result = (*playerEffectSend)->GetSendLevel(playerEffectSend, outputMixPresetReverb,
474                         &sendLevel);
475                 assert(SL_RESULT_SUCCESS == result);
476                 printf("Output mix preset reverb: player effect send new enabled = %s, direct level"
477                     " = %d, send level = %d\n", enabled ? "true" : "false", directLevel, sendLevel);
478             }
479         }
480         if (outputMixEnvironmentalItfRequested) {
481             if (outputMixEnvironmentalName != NULL) {
482                 result = (*playerEffectSend)->IsEnabled(playerEffectSend,
483                         outputMixEnvironmentalReverb, &enabled);
484                 assert(SL_RESULT_SUCCESS == result);
485                 printf("Output mix environmental reverb: player effect send default enabled = %s\n",
486                         enabled ? "true" : "false");
487                 directLevel = 12345;
488                 result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel);
489                 assert(SL_RESULT_SUCCESS == result);
490                 printf("Output mix environmental reverb: player effect send default direct level"
491                         " = %d\n", directLevel);
492                 sendLevel = 12345;
493                 result = (*playerEffectSend)->GetSendLevel(playerEffectSend,
494                         outputMixEnvironmentalReverb, &sendLevel);
495                 assert(SL_RESULT_SUCCESS == result);
496                 printf("Output mix environmental reverb: player effect send default send level"
497                         " = %d\n", sendLevel);
498                 result = (*playerEffectSend)->EnableEffectSend(playerEffectSend,
499                         outputMixEnvironmentalReverb, SL_BOOLEAN_TRUE, (SLmillibel) 0);
500                 assert(SL_RESULT_SUCCESS == result);
501                 result = (*playerEffectSend)->IsEnabled(playerEffectSend,
502                         outputMixEnvironmentalReverb, &enabled);
503                 assert(SL_RESULT_SUCCESS == result);
504                 directLevel = 12345;
505                 result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel);
506                 assert(SL_RESULT_SUCCESS == result);
507                 sendLevel = 12345;
508                 result = (*playerEffectSend)->GetSendLevel(playerEffectSend,
509                         outputMixEnvironmentalReverb, &sendLevel);
510                 assert(SL_RESULT_SUCCESS == result);
511                 printf("Output mix environmental reverb: player effect send new enabled = %s, "
512                     "direct level = %d, send level = %d\n", enabled ? "true" : "false",
513                     directLevel, sendLevel);
514             }
515         }
516     }
517 
518     // configure preset reverb on player
519     SLPresetReverbItf playerPresetReverb;
520     if (playerPresetItfRequested) {
521         result = (*playerObject)->GetInterface(playerObject, SL_IID_PRESETREVERB,
522                 &playerPresetReverb);
523         assert(SL_RESULT_SUCCESS == result);
524         SLuint16 getPresetReverb = 12345;
525         result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb);
526         if (SL_RESULT_SUCCESS == result) {
527             printf("Player default preset reverb %u\n", getPresetReverb);
528             if (playerPresetNumber != ((SLuint16) ~0)) {
529                 result = (*playerPresetReverb)->SetPreset(playerPresetReverb, playerPresetNumber);
530                 if (SL_RESULT_SUCCESS == result) {
531                     result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb);
532                     assert(SL_RESULT_SUCCESS == result);
533                     assert(getPresetReverb == playerPresetNumber);
534                     printf("Player preset reverb successfully changed to %u\n", playerPresetNumber);
535                 } else {
536                     printf("Unable to set player preset reverb to %u, result=%u\n",
537                             playerPresetNumber, result);
538                 }
539             }
540         } else {
541             printf("Unable to get player default preset reverb, result=%u\n", result);
542         }
543     }
544 
545     // configure environmental reverb on player
546     SLEnvironmentalReverbItf playerEnvironmentalReverb;
547     if (playerEnvironmentalItfRequested) {
548         result = (*playerObject)->GetInterface(playerObject, SL_IID_ENVIRONMENTALREVERB,
549                 &playerEnvironmentalReverb);
550         assert(SL_RESULT_SUCCESS == result);
551         SLEnvironmentalReverbSettings getSettings;
552         memset(&getSettings, 0, sizeof(getSettings));
553         result = (*playerEnvironmentalReverb)->GetEnvironmentalReverbProperties(
554                 playerEnvironmentalReverb, &getSettings);
555         if (SL_RESULT_SUCCESS == result) {
556             printf("Player default environmental reverb settings\n");
557             printf("--------------------------------------------\n");
558             slesutPrintEnvironmentalReverbSettings(&getSettings);
559             printf("\n");
560             if (playerEnvironmentalName != NULL) {
561                 result = (*playerEnvironmentalReverb)->SetEnvironmentalReverbProperties(
562                         playerEnvironmentalReverb, &playerEnvironmentalSettings);
563                 assert(SL_RESULT_SUCCESS == result);
564                 printf("Player new environmental reverb settings\n");
565                 printf("----------------------------------------\n");
566                 slesutPrintEnvironmentalReverbSettings(&playerEnvironmentalSettings);
567                 printf("\n");
568                 result = (*playerEnvironmentalReverb)->GetEnvironmentalReverbProperties(
569                         playerEnvironmentalReverb, &getSettings);
570                 assert(SL_RESULT_SUCCESS == result);
571                 printf("Player read environmental reverb settings\n");
572                 printf("-----------------------------------------\n");
573                 slesutPrintEnvironmentalReverbSettings(&getSettings);
574                 printf("\n");
575                 if (!slesutCompareEnvironmentalReverbSettings(&getSettings,
576                         &playerEnvironmentalSettings)) {
577                     printf("Warning: new and read are different; check details above\n");
578                 } else {
579                     printf("New and read match, life is good\n");
580                 }
581             }
582         } else {
583             printf("Unable to get player default environmental reverb properties, result=%u\n",
584                     result);
585         }
586     }
587 
588     // get the play interface
589     SLPlayItf playerPlay;
590     result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
591     assert(SL_RESULT_SUCCESS == result);
592 
593     // get the prefetch status interface
594     SLPrefetchStatusItf playerPrefetchStatus;
595     result = (*playerObject)->GetInterface(playerObject, SL_IID_PREFETCHSTATUS,
596             &playerPrefetchStatus);
597     assert(SL_RESULT_SUCCESS == result);
598 
599     // enable prefetch status callbacks
600     result = (*playerPrefetchStatus)->RegisterCallback(playerPrefetchStatus, prefetch_callback,
601             NULL);
602     assert(SL_RESULT_SUCCESS == result);
603     result = (*playerPrefetchStatus)->SetCallbackEventsMask(playerPrefetchStatus,
604             SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE);
605     assert(SL_RESULT_SUCCESS == result);
606 
607     // set play state to paused to enable pre-fetch so we can get a more reliable duration
608     result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED);
609     assert(SL_RESULT_SUCCESS == result);
610 
611     // wait for prefetch status callback to indicate either sufficient data or error
612     pthread_mutex_lock(&mutex);
613     while (prefetch_status == SL_PREFETCHSTATUS_UNKNOWN) {
614         pthread_cond_wait(&cond, &mutex);
615     }
616     pthread_mutex_unlock(&mutex);
617     if (prefetch_status == SL_PREFETCHSTATUS_ERROR) {
618         fprintf(stderr, "Error during prefetch, exiting\n");
619         goto destroyRes;
620     }
621 
622     // get the duration
623     SLmillisecond duration;
624     result = (*playerPlay)->GetDuration(playerPlay, &duration);
625     assert(SL_RESULT_SUCCESS == result);
626     if (SL_TIME_UNKNOWN == duration) {
627         printf("duration: unknown\n");
628     } else {
629         printf("duration: %.1f seconds\n", duration / 1000.0);
630     }
631 
632     // enable looping
633     if (loop) {
634         SLSeekItf playerSeek;
635         result = (*playerObject)->GetInterface(playerObject, SL_IID_SEEK, &playerSeek);
636         assert(SL_RESULT_SUCCESS == result);
637         result = (*playerSeek)->SetLoop(playerSeek, SL_BOOLEAN_TRUE, (SLmillisecond) 0,
638                 SL_TIME_UNKNOWN);
639         assert(SL_RESULT_SUCCESS == result);
640     }
641 
642     // start audio playing
643     result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
644     assert(SL_RESULT_SUCCESS == result);
645 
646     // wait for audio to finish playing
647     SLuint32 state;
648     for (;;) {
649         result = (*playerPlay)->GetPlayState(playerPlay, &state);
650         assert(SL_RESULT_SUCCESS == result);
651         if (SL_PLAYSTATE_PLAYING != state)
652             break;
653         usleep(1000000);
654      }
655     assert(SL_PLAYSTATE_PAUSED == state);
656 
657 destroyRes:
658     // cleanup objects
659     (*playerObject)->Destroy(playerObject);
660     (*mixObject)->Destroy(mixObject);
661     (*engineObject)->Destroy(engineObject);
662 
663     return EXIT_SUCCESS;
664 }
665