reverb.c revision 14463a8e53e2a5185a395e2045fd33ad4a63050d
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
33typedef struct {
34    const char *mName;
35    SLEnvironmentalReverbSettings mSettings;
36} Pair;
37
38#define _(name) {#name, SL_I3DL2_ENVIRONMENT_PRESET_##name},
39
40Pair 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
74bool outputMixPresetItfRequested = false;
75SLuint16 outputMixPresetNumber = ~0;
76
77// Parameters for environmental reverb on output mix
78bool outputMixEnvironmentalItfRequested = false;
79char *outputMixEnvironmentalName = NULL;
80SLEnvironmentalReverbSettings outputMixEnvironmentalSettings;
81
82// Parameters for preset reverb on audio player (not supported)
83bool playerPresetItfRequested = false;
84SLuint16 playerPresetNumber = ~0;
85
86// Parameters for environmental reverb on audio player (not supported)
87bool playerEnvironmentalItfRequested = false;
88char *playerEnvironmentalName = NULL;
89SLEnvironmentalReverbSettings playerEnvironmentalSettings;
90
91// Compare two environmental reverb settings structures.
92// Returns true if the settings are identical, or false if they are different.
93
94bool 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
113void 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
129const 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
142void 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
178static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
179static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
180SLuint32 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
190void 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
222int 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
657destroyRes:
658    // cleanup objects
659    (*playerObject)->Destroy(playerObject);
660    (*mixObject)->Destroy(mixObject);
661    (*engineObject)->Destroy(engineObject);
662
663    return EXIT_SUCCESS;
664}
665