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// Reverb parameters for output mix
73SLuint16 mixPresetNumber = ~0;
74char *mixEnvName = NULL;
75SLEnvironmentalReverbSettings mixEnvSettings;
76
77// Reverb parameters for audio player
78SLuint16 playerPresetNumber = ~0;
79char *playerEnvName = NULL;
80SLEnvironmentalReverbSettings playerEnvSettings;
81
82// Compare two environmental reverb settings structures.
83// Returns true if the settings are identical, or false if they are different.
84
85bool slesutCompareEnvronmentalReverbSettings(
86        const SLEnvironmentalReverbSettings *settings1,
87        const SLEnvironmentalReverbSettings *settings2)
88{
89    return
90        (settings1->roomLevel == settings2->roomLevel) &&
91        (settings1->roomHFLevel == settings2->roomHFLevel) &&
92        (settings1->decayTime == settings2->decayTime) &&
93        (settings1->decayHFRatio == settings2->decayHFRatio) &&
94        (settings1->reflectionsLevel == settings2->reflectionsLevel) &&
95        (settings1->reflectionsDelay == settings2->reflectionsDelay) &&
96        (settings1->reverbLevel == settings2->reverbLevel) &&
97        (settings1->reverbDelay == settings2->reverbDelay) &&
98        (settings1->diffusion == settings2->diffusion) &&
99        (settings1->density == settings2->density);
100}
101
102// Print an environmental reverb settings structure.
103
104void slesutPrintEnvironmentalReverbSettings(const SLEnvironmentalReverbSettings *settings)
105{
106    printf("roomLevel: %u\n", settings->roomLevel);
107    printf("roomHFLevel: %u\n", settings->roomHFLevel);
108    printf("decayTime: %lu\n", settings->decayTime);
109    printf("decayHFRatio: %u\n", settings->decayHFRatio);
110    printf("reflectionsLevel: %u\n", settings->reflectionsLevel);
111    printf("reflectionsDelay: %lu\n", settings->reflectionsDelay);
112    printf("reverbLevel: %u\n", settings->reverbLevel);
113    printf("reverbDelay: %lu\n", settings->reverbDelay);
114    printf("diffusion: %u\n", settings->diffusion);
115    printf("density: %u\n", settings->density);
116}
117
118// Lookup environmental reverb settings by name
119
120const SLEnvironmentalReverbSettings *lookupEnvName(const char *name)
121{
122    unsigned j;
123    for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) {
124        if (!strcasecmp(name, pairs[j].mName)) {
125            return &pairs[j].mSettings;
126        }
127    }
128    return NULL;
129}
130
131// Print all available environmental reverb names
132
133void printEnvNames(void)
134{
135    unsigned j;
136    bool needSpace = false;
137    bool needNewline = false;
138    unsigned lineLen = 0;
139    for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) {
140        const char *name = pairs[j].mName;
141        unsigned nameLen = strlen(name);
142        if (lineLen + (needSpace ? 1 : 0) + nameLen > 72) {
143            putchar('\n');
144            needSpace = false;
145            needNewline = false;
146            lineLen = 0;
147        }
148        if (needSpace) {
149            putchar(' ');
150            ++lineLen;
151        }
152        fputs(name, stdout);
153        lineLen += nameLen;
154        needSpace = true;
155        needNewline = true;
156    }
157    if (needNewline) {
158        putchar('\n');
159    }
160}
161
162// Main program
163
164int main(int argc, char **argv)
165{
166    SLresult result;
167
168    // process command line parameters
169    char *prog = argv[0];
170    int i;
171    for (i = 1; i < argc; ++i) {
172        char *arg = argv[i];
173        if (arg[0] != '-')
174            break;
175        if (!strncmp(arg, "--mix-preset=", 13)) {
176            mixPresetNumber = atoi(&arg[13]);
177        } else if (!strncmp(arg, "--mix-name=", 11)) {
178            mixEnvName = &arg[11];
179        } else if (!strncmp(arg, "--player-preset=", 16)) {
180            playerPresetNumber = atoi(&arg[16]);
181        } else if (!strncmp(arg, "--player-name=", 14)) {
182            playerEnvName = &arg[14];
183        } else {
184            fprintf(stderr, "%s: unknown option %s ignored\n", prog, arg);
185        }
186    }
187    if (argc - i != 1) {
188        fprintf(stderr, "usage: %s --mix-preset=# --mix-name=I3DL2 --player-preset=# "
189                "--player-name=I3DL2 filename\n", prog);
190        return EXIT_FAILURE;
191    }
192    char *pathname = argv[i];
193
194    const SLEnvironmentalReverbSettings *envSettings;
195    if (NULL != mixEnvName) {
196        envSettings = lookupEnvName(mixEnvName);
197        if (NULL == envSettings) {
198            fprintf(stderr, "%s: mix environmental reverb name %s not found, "
199                    "available names are:\n", prog, mixEnvName);
200            printEnvNames();
201            return EXIT_FAILURE;
202        }
203        mixEnvSettings = *envSettings;
204    }
205    if (NULL != playerEnvName) {
206        envSettings = lookupEnvName(playerEnvName);
207        if (NULL == envSettings) {
208            fprintf(stderr, "%s: player environmental reverb name %s not found, "
209                    "available names are:\n", prog, playerEnvName);
210            printEnvNames();
211            return EXIT_FAILURE;
212        }
213        playerEnvSettings = *envSettings;
214    }
215
216    // create engine
217    SLObjectItf engineObject;
218    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
219    assert(SL_RESULT_SUCCESS == result);
220    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
221    assert(SL_RESULT_SUCCESS == result);
222    SLEngineItf engineEngine;
223    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
224    assert(SL_RESULT_SUCCESS == result);
225
226    // create output mix
227    SLInterfaceID mix_ids[2];
228    SLboolean mix_req[2];
229    SLuint32 count = 0;
230    if (mixPresetNumber != ((SLuint16) ~0)) {
231        mix_req[count] = SL_BOOLEAN_TRUE;
232        mix_ids[count++] = SL_IID_PRESETREVERB;
233    }
234    if (mixEnvName != NULL) {
235        mix_req[count] = SL_BOOLEAN_TRUE;
236        mix_ids[count++] = SL_IID_ENVIRONMENTALREVERB;
237    }
238    SLObjectItf mixObject;
239    result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, count, mix_ids, mix_req);
240    assert(SL_RESULT_SUCCESS == result);
241    result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
242    assert(SL_RESULT_SUCCESS == result);
243
244    // configure preset reverb on output mix
245    SLPresetReverbItf mixPresetReverb;
246    if (mixPresetNumber != ((SLuint16) ~0)) {
247        result = (*mixObject)->GetInterface(mixObject, SL_IID_PRESETREVERB, &mixPresetReverb);
248        assert(SL_RESULT_SUCCESS == result);
249        SLuint16 getPresetReverb = 12345;
250        result = (*mixPresetReverb)->GetPreset(mixPresetReverb, &getPresetReverb);
251        assert(SL_RESULT_SUCCESS == result);
252        printf("Output mix default preset reverb %u\n", getPresetReverb);
253        result = (*mixPresetReverb)->SetPreset(mixPresetReverb, mixPresetNumber);
254        if (SL_RESULT_SUCCESS == result) {
255            result = (*mixPresetReverb)->GetPreset(mixPresetReverb, &getPresetReverb);
256            assert(SL_RESULT_SUCCESS == result);
257            assert(getPresetReverb == mixPresetNumber);
258            printf("Output mix preset reverb successfully changed to %u\n", mixPresetNumber);
259        } else
260            printf("Unable to set output mix preset reverb to %u, result=%lu\n", mixPresetNumber,
261                    result);
262    }
263
264    // configure environmental reverb on output mix
265    SLEnvironmentalReverbItf mixEnvironmentalReverb;
266    if (mixEnvName != NULL) {
267        result = (*mixObject)->GetInterface(mixObject, SL_IID_ENVIRONMENTALREVERB,
268                &mixEnvironmentalReverb);
269        assert(SL_RESULT_SUCCESS == result);
270        SLEnvironmentalReverbSettings getSettings;
271        result = (*mixEnvironmentalReverb)->GetEnvironmentalReverbProperties(mixEnvironmentalReverb,
272                &getSettings);
273        assert(SL_RESULT_SUCCESS == result);
274        printf("Output mix default environmental reverb settings\n");
275        printf("------------------------------------------------\n");
276        slesutPrintEnvironmentalReverbSettings(&getSettings);
277        printf("\n");
278        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
279                &mixEnvSettings);
280        assert(SL_RESULT_SUCCESS == result);
281        printf("Output mix new environmental reverb settings\n");
282        printf("--------------------------------------------\n");
283        slesutPrintEnvironmentalReverbSettings(&mixEnvSettings);
284        printf("\n");
285        result = (*mixEnvironmentalReverb)->GetEnvironmentalReverbProperties(mixEnvironmentalReverb,
286                &getSettings);
287        assert(SL_RESULT_SUCCESS == result);
288        printf("Output mix read environmental reverb settings\n");
289        printf("--------------------------------------------\n");
290        slesutPrintEnvironmentalReverbSettings(&getSettings);
291        printf("\n");
292        if (!slesutCompareEnvronmentalReverbSettings(&getSettings, &mixEnvSettings)) {
293            printf("Warning: new and read are different; check details above\n");
294        } else {
295            printf("New and read match, life is good\n");
296        }
297    }
298
299    // create audio player
300    SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathname};
301    SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
302    SLDataSource audioSrc = {&locURI, &dfMIME};
303    SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
304    SLDataSink audioSnk = {&locOutputMix, NULL};
305    SLInterfaceID player_ids[4];
306    SLboolean player_req[4];
307    count = 0;
308    if (playerPresetNumber != ((SLuint16) ~0)) {
309        player_req[count] = SL_BOOLEAN_TRUE;
310        player_ids[count++] = SL_IID_PRESETREVERB;
311    }
312    if (playerEnvName != NULL) {
313        player_req[count] = SL_BOOLEAN_TRUE;
314        player_ids[count++] = SL_IID_ENVIRONMENTALREVERB;
315    }
316    if (mixPresetNumber != ((SLuint16) ~0) || mixEnvName != NULL) {
317        player_req[count] = SL_BOOLEAN_TRUE;
318        player_ids[count++] = SL_IID_EFFECTSEND;
319    }
320    player_req[count] = SL_BOOLEAN_TRUE;
321    player_ids[count++] = SL_IID_PREFETCHSTATUS;
322    SLObjectItf playerObject;
323    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
324        &audioSnk, count, player_ids, player_req);
325    assert(SL_RESULT_SUCCESS == result);
326
327    // realize audio player
328    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
329    assert(SL_RESULT_SUCCESS == result);
330
331    // if reverb is on output mix (aux effect), then enable it for this player
332    if (mixPresetNumber != ((SLuint16) ~0) || mixEnvName != NULL) {
333        SLEffectSendItf playerEffectSend;
334        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
335        assert(SL_RESULT_SUCCESS == result);
336        if (mixPresetNumber != ((SLuint16) ~0)) {
337            result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixPresetReverb,
338                    SL_BOOLEAN_TRUE, (SLmillibel) 0);
339            assert(SL_RESULT_SUCCESS == result);
340        }
341        if (mixEnvName != NULL) {
342            result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
343                    SL_BOOLEAN_TRUE, (SLmillibel) 0);
344            assert(SL_RESULT_SUCCESS == result);
345        }
346    }
347
348    // configure preset reverb on player
349    SLPresetReverbItf playerPresetReverb;
350    if (playerPresetNumber != ((SLuint16) ~0)) {
351        result = (*playerObject)->GetInterface(playerObject, SL_IID_PRESETREVERB,
352                &playerPresetReverb);
353        assert(SL_RESULT_SUCCESS == result);
354        SLuint16 getPresetReverb = 12345;
355        result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb);
356        assert(SL_RESULT_SUCCESS == result);
357        printf("Player default preset reverb %u\n", getPresetReverb);
358        result = (*playerPresetReverb)->SetPreset(playerPresetReverb, playerPresetNumber);
359        if (SL_RESULT_SUCCESS == result) {
360            result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb);
361            assert(SL_RESULT_SUCCESS == result);
362            assert(getPresetReverb == playerPresetNumber);
363            printf("Player preset reverb successfully changed to %u\n", playerPresetNumber);
364        } else
365            printf("Unable to set player preset reverb to %u, result=%lu\n", playerPresetNumber,
366                    result);
367    }
368
369    // configure environmental reverb on player
370    SLEnvironmentalReverbItf playerEnvironmentalReverb;
371    if (playerEnvName != NULL) {
372        result = (*playerObject)->GetInterface(playerObject, SL_IID_ENVIRONMENTALREVERB,
373                &playerEnvironmentalReverb);
374        assert(SL_RESULT_SUCCESS == result);
375        SLEnvironmentalReverbSettings getSettings;
376        memset(&getSettings, 0, sizeof(getSettings));
377        result = (*playerEnvironmentalReverb)->GetEnvironmentalReverbProperties(
378                playerEnvironmentalReverb, &getSettings);
379        assert(SL_RESULT_SUCCESS == result);
380        printf("Player default environmental reverb settings\n");
381        printf("--------------------------------------------\n");
382        slesutPrintEnvironmentalReverbSettings(&getSettings);
383        printf("\n");
384        result = (*playerEnvironmentalReverb)->SetEnvironmentalReverbProperties(
385                playerEnvironmentalReverb, &playerEnvSettings);
386        assert(SL_RESULT_SUCCESS == result);
387        printf("Player new environmental reverb settings\n");
388        printf("----------------------------------------\n");
389        slesutPrintEnvironmentalReverbSettings(&playerEnvSettings);
390        printf("\n");
391        result = (*playerEnvironmentalReverb)->GetEnvironmentalReverbProperties(
392                playerEnvironmentalReverb, &getSettings);
393        assert(SL_RESULT_SUCCESS == result);
394        printf("Player read environmental reverb settings\n");
395        printf("-----------------------------------------\n");
396        slesutPrintEnvironmentalReverbSettings(&getSettings);
397        printf("\n");
398        if (!slesutCompareEnvronmentalReverbSettings(&getSettings, &playerEnvSettings)) {
399            printf("Warning: new and read are different; check details above\n");
400        } else {
401            printf("New and read match, life is good\n");
402        }
403    }
404
405    // get the play interface
406    SLPlayItf playerPlay;
407    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
408    assert(SL_RESULT_SUCCESS == result);
409
410    // set play state to paused to enable pre-fetch so we can get a more reliable duration
411    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED);
412    assert(SL_RESULT_SUCCESS == result);
413
414    // get the prefetch status interface
415    SLPrefetchStatusItf playerPrefetchStatus;
416    result = (*playerObject)->GetInterface(playerObject, SL_IID_PREFETCHSTATUS,
417            &playerPrefetchStatus);
418    assert(SL_RESULT_SUCCESS == result);
419
420    // poll prefetch status to detect when it completes
421    SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
422    SLuint32 timeOutIndex = 100; // 10s
423    while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
424        usleep(100 * 1000);
425        (*playerPrefetchStatus)->GetPrefetchStatus(playerPrefetchStatus, &prefetchStatus);
426        timeOutIndex--;
427    }
428    if (timeOutIndex == 0) {
429        fprintf(stderr, "\nWe\'re done waiting, failed to prefetch data in time, exiting\n");
430        goto destroyRes;
431    }
432
433    // get the duration
434    SLmillisecond duration;
435    result = (*playerPlay)->GetDuration(playerPlay, &duration);
436    assert(SL_RESULT_SUCCESS == result);
437    if (SL_TIME_UNKNOWN == duration) {
438        printf("duration: unknown\n");
439    } else {
440        printf("duration: %.1f seconds\n", duration / 1000.0);
441    }
442
443    // start audio playing
444    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
445    assert(SL_RESULT_SUCCESS == result);
446
447    // wait for audio to finish playing
448    SLuint32 state;
449    for (;;) {
450        result = (*playerPlay)->GetPlayState(playerPlay, &state);
451        assert(SL_RESULT_SUCCESS == result);
452        if (SL_PLAYSTATE_PLAYING != state)
453            break;
454        usleep(1000000);
455     }
456    assert(SL_PLAYSTATE_PAUSED == state);
457
458destroyRes:
459    // cleanup objects
460    (*playerObject)->Destroy(playerObject);
461    (*mixObject)->Destroy(mixObject);
462    (*engineObject)->Destroy(engineObject);
463
464    return EXIT_SUCCESS;
465}
466