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