/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Demonstrate environmental reverb and preset reverb on an output mix and audio player #include "SLES/OpenSLES.h" #include <assert.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define bool int #define false 0 #define true 1 // Table of I3DL2 named environmental reverb settings typedef struct { const char *mName; SLEnvironmentalReverbSettings mSettings; } Pair; #define _(name) {#name, SL_I3DL2_ENVIRONMENT_PRESET_##name}, Pair pairs[] = { _(DEFAULT) _(GENERIC) _(PADDEDCELL) _(ROOM) _(BATHROOM) _(LIVINGROOM) _(STONEROOM) _(AUDITORIUM) _(CONCERTHALL) _(CAVE) _(ARENA) _(HANGAR) _(CARPETEDHALLWAY) _(HALLWAY) _(STONECORRIDOR) _(ALLEY) _(FOREST) _(CITY) _(MOUNTAINS) _(QUARRY) _(PLAIN) _(PARKINGLOT) _(SEWERPIPE) _(UNDERWATER) _(SMALLROOM) _(MEDIUMROOM) _(LARGEROOM) _(MEDIUMHALL) _(LARGEHALL) _(PLATE) }; // Reverb parameters for output mix SLuint16 mixPresetNumber = ~0; char *mixEnvName = NULL; SLEnvironmentalReverbSettings mixEnvSettings; // Reverb parameters for audio player SLuint16 playerPresetNumber = ~0; char *playerEnvName = NULL; SLEnvironmentalReverbSettings playerEnvSettings; // Compare two environmental reverb settings structures. // Returns true if the settings are identical, or false if they are different. bool slesutCompareEnvronmentalReverbSettings( const SLEnvironmentalReverbSettings *settings1, const SLEnvironmentalReverbSettings *settings2) { return (settings1->roomLevel == settings2->roomLevel) && (settings1->roomHFLevel == settings2->roomHFLevel) && (settings1->decayTime == settings2->decayTime) && (settings1->decayHFRatio == settings2->decayHFRatio) && (settings1->reflectionsLevel == settings2->reflectionsLevel) && (settings1->reflectionsDelay == settings2->reflectionsDelay) && (settings1->reverbLevel == settings2->reverbLevel) && (settings1->reverbDelay == settings2->reverbDelay) && (settings1->diffusion == settings2->diffusion) && (settings1->density == settings2->density); } // Print an environmental reverb settings structure. void slesutPrintEnvironmentalReverbSettings(const SLEnvironmentalReverbSettings *settings) { printf("roomLevel: %u\n", settings->roomLevel); printf("roomHFLevel: %u\n", settings->roomHFLevel); printf("decayTime: %lu\n", settings->decayTime); printf("decayHFRatio: %u\n", settings->decayHFRatio); printf("reflectionsLevel: %u\n", settings->reflectionsLevel); printf("reflectionsDelay: %lu\n", settings->reflectionsDelay); printf("reverbLevel: %u\n", settings->reverbLevel); printf("reverbDelay: %lu\n", settings->reverbDelay); printf("diffusion: %u\n", settings->diffusion); printf("density: %u\n", settings->density); } // Lookup environmental reverb settings by name const SLEnvironmentalReverbSettings *lookupEnvName(const char *name) { unsigned j; for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) { if (!strcasecmp(name, pairs[j].mName)) { return &pairs[j].mSettings; } } return NULL; } // Print all available environmental reverb names void printEnvNames(void) { unsigned j; bool needSpace = false; bool needNewline = false; unsigned lineLen = 0; for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) { const char *name = pairs[j].mName; unsigned nameLen = strlen(name); if (lineLen + (needSpace ? 1 : 0) + nameLen > 72) { putchar('\n'); needSpace = false; needNewline = false; lineLen = 0; } if (needSpace) { putchar(' '); ++lineLen; } fputs(name, stdout); lineLen += nameLen; needSpace = true; needNewline = true; } if (needNewline) { putchar('\n'); } } // Main program int main(int argc, char **argv) { SLresult result; // process command line parameters char *prog = argv[0]; int i; for (i = 1; i < argc; ++i) { char *arg = argv[i]; if (arg[0] != '-') break; if (!strncmp(arg, "--mix-preset=", 13)) { mixPresetNumber = atoi(&arg[13]); } else if (!strncmp(arg, "--mix-name=", 11)) { mixEnvName = &arg[11]; } else if (!strncmp(arg, "--player-preset=", 16)) { playerPresetNumber = atoi(&arg[16]); } else if (!strncmp(arg, "--player-name=", 14)) { playerEnvName = &arg[14]; } else { fprintf(stderr, "%s: unknown option %s ignored\n", prog, arg); } } if (argc - i != 1) { fprintf(stderr, "usage: %s --mix-preset=# --mix-name=I3DL2 --player-preset=# " "--player-name=I3DL2 filename\n", prog); return EXIT_FAILURE; } char *pathname = argv[i]; const SLEnvironmentalReverbSettings *envSettings; if (NULL != mixEnvName) { envSettings = lookupEnvName(mixEnvName); if (NULL == envSettings) { fprintf(stderr, "%s: mix environmental reverb name %s not found, " "available names are:\n", prog, mixEnvName); printEnvNames(); return EXIT_FAILURE; } mixEnvSettings = *envSettings; } if (NULL != playerEnvName) { envSettings = lookupEnvName(playerEnvName); if (NULL == envSettings) { fprintf(stderr, "%s: player environmental reverb name %s not found, " "available names are:\n", prog, playerEnvName); printEnvNames(); return EXIT_FAILURE; } playerEnvSettings = *envSettings; } // create engine SLObjectItf engineObject; result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); assert(SL_RESULT_SUCCESS == result); result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); SLEngineItf engineEngine; result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); assert(SL_RESULT_SUCCESS == result); // create output mix SLInterfaceID mix_ids[2]; SLboolean mix_req[2]; SLuint32 count = 0; if (mixPresetNumber != ((SLuint16) ~0)) { mix_req[count] = SL_BOOLEAN_TRUE; mix_ids[count++] = SL_IID_PRESETREVERB; } if (mixEnvName != NULL) { mix_req[count] = SL_BOOLEAN_TRUE; mix_ids[count++] = SL_IID_ENVIRONMENTALREVERB; } SLObjectItf mixObject; result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, count, mix_ids, mix_req); assert(SL_RESULT_SUCCESS == result); result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // configure preset reverb on output mix SLPresetReverbItf mixPresetReverb; if (mixPresetNumber != ((SLuint16) ~0)) { result = (*mixObject)->GetInterface(mixObject, SL_IID_PRESETREVERB, &mixPresetReverb); assert(SL_RESULT_SUCCESS == result); SLuint16 getPresetReverb = 12345; result = (*mixPresetReverb)->GetPreset(mixPresetReverb, &getPresetReverb); assert(SL_RESULT_SUCCESS == result); printf("Output mix default preset reverb %u\n", getPresetReverb); result = (*mixPresetReverb)->SetPreset(mixPresetReverb, mixPresetNumber); if (SL_RESULT_SUCCESS == result) { result = (*mixPresetReverb)->GetPreset(mixPresetReverb, &getPresetReverb); assert(SL_RESULT_SUCCESS == result); assert(getPresetReverb == mixPresetNumber); printf("Output mix preset reverb successfully changed to %u\n", mixPresetNumber); } else printf("Unable to set output mix preset reverb to %u, result=%lu\n", mixPresetNumber, result); } // configure environmental reverb on output mix SLEnvironmentalReverbItf mixEnvironmentalReverb; if (mixEnvName != NULL) { result = (*mixObject)->GetInterface(mixObject, SL_IID_ENVIRONMENTALREVERB, &mixEnvironmentalReverb); assert(SL_RESULT_SUCCESS == result); SLEnvironmentalReverbSettings getSettings; result = (*mixEnvironmentalReverb)->GetEnvironmentalReverbProperties(mixEnvironmentalReverb, &getSettings); assert(SL_RESULT_SUCCESS == result); printf("Output mix default environmental reverb settings\n"); printf("------------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, &mixEnvSettings); assert(SL_RESULT_SUCCESS == result); printf("Output mix new environmental reverb settings\n"); printf("--------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&mixEnvSettings); printf("\n"); result = (*mixEnvironmentalReverb)->GetEnvironmentalReverbProperties(mixEnvironmentalReverb, &getSettings); assert(SL_RESULT_SUCCESS == result); printf("Output mix read environmental reverb settings\n"); printf("--------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); if (!slesutCompareEnvronmentalReverbSettings(&getSettings, &mixEnvSettings)) { printf("Warning: new and read are different; check details above\n"); } else { printf("New and read match, life is good\n"); } } // create audio player SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathname}; SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; SLDataSource audioSrc = {&locURI, &dfMIME}; SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject}; SLDataSink audioSnk = {&locOutputMix, NULL}; SLInterfaceID player_ids[4]; SLboolean player_req[4]; count = 0; if (playerPresetNumber != ((SLuint16) ~0)) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_PRESETREVERB; } if (playerEnvName != NULL) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_ENVIRONMENTALREVERB; } if (mixPresetNumber != ((SLuint16) ~0) || mixEnvName != NULL) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_EFFECTSEND; } player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_PREFETCHSTATUS; SLObjectItf playerObject; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, &audioSnk, count, player_ids, player_req); assert(SL_RESULT_SUCCESS == result); // realize audio player result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // if reverb is on output mix (aux effect), then enable it for this player if (mixPresetNumber != ((SLuint16) ~0) || mixEnvName != NULL) { SLEffectSendItf playerEffectSend; result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); assert(SL_RESULT_SUCCESS == result); if (mixPresetNumber != ((SLuint16) ~0)) { result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixPresetReverb, SL_BOOLEAN_TRUE, (SLmillibel) 0); assert(SL_RESULT_SUCCESS == result); } if (mixEnvName != NULL) { result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, SL_BOOLEAN_TRUE, (SLmillibel) 0); assert(SL_RESULT_SUCCESS == result); } } // configure preset reverb on player SLPresetReverbItf playerPresetReverb; if (playerPresetNumber != ((SLuint16) ~0)) { result = (*playerObject)->GetInterface(playerObject, SL_IID_PRESETREVERB, &playerPresetReverb); assert(SL_RESULT_SUCCESS == result); SLuint16 getPresetReverb = 12345; result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb); assert(SL_RESULT_SUCCESS == result); printf("Player default preset reverb %u\n", getPresetReverb); result = (*playerPresetReverb)->SetPreset(playerPresetReverb, playerPresetNumber); if (SL_RESULT_SUCCESS == result) { result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb); assert(SL_RESULT_SUCCESS == result); assert(getPresetReverb == playerPresetNumber); printf("Player preset reverb successfully changed to %u\n", playerPresetNumber); } else printf("Unable to set player preset reverb to %u, result=%lu\n", playerPresetNumber, result); } // configure environmental reverb on player SLEnvironmentalReverbItf playerEnvironmentalReverb; if (playerEnvName != NULL) { result = (*playerObject)->GetInterface(playerObject, SL_IID_ENVIRONMENTALREVERB, &playerEnvironmentalReverb); assert(SL_RESULT_SUCCESS == result); SLEnvironmentalReverbSettings getSettings; memset(&getSettings, 0, sizeof(getSettings)); result = (*playerEnvironmentalReverb)->GetEnvironmentalReverbProperties( playerEnvironmentalReverb, &getSettings); assert(SL_RESULT_SUCCESS == result); printf("Player default environmental reverb settings\n"); printf("--------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); result = (*playerEnvironmentalReverb)->SetEnvironmentalReverbProperties( playerEnvironmentalReverb, &playerEnvSettings); assert(SL_RESULT_SUCCESS == result); printf("Player new environmental reverb settings\n"); printf("----------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&playerEnvSettings); printf("\n"); result = (*playerEnvironmentalReverb)->GetEnvironmentalReverbProperties( playerEnvironmentalReverb, &getSettings); assert(SL_RESULT_SUCCESS == result); printf("Player read environmental reverb settings\n"); printf("-----------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); if (!slesutCompareEnvronmentalReverbSettings(&getSettings, &playerEnvSettings)) { printf("Warning: new and read are different; check details above\n"); } else { printf("New and read match, life is good\n"); } } // get the play interface SLPlayItf playerPlay; result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); assert(SL_RESULT_SUCCESS == result); // set play state to paused to enable pre-fetch so we can get a more reliable duration result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED); assert(SL_RESULT_SUCCESS == result); // get the prefetch status interface SLPrefetchStatusItf playerPrefetchStatus; result = (*playerObject)->GetInterface(playerObject, SL_IID_PREFETCHSTATUS, &playerPrefetchStatus); assert(SL_RESULT_SUCCESS == result); // poll prefetch status to detect when it completes SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; SLuint32 timeOutIndex = 100; // 10s while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) { usleep(100 * 1000); (*playerPrefetchStatus)->GetPrefetchStatus(playerPrefetchStatus, &prefetchStatus); timeOutIndex--; } if (timeOutIndex == 0) { fprintf(stderr, "\nWe\'re done waiting, failed to prefetch data in time, exiting\n"); goto destroyRes; } // get the duration SLmillisecond duration; result = (*playerPlay)->GetDuration(playerPlay, &duration); assert(SL_RESULT_SUCCESS == result); if (SL_TIME_UNKNOWN == duration) { printf("duration: unknown\n"); } else { printf("duration: %.1f seconds\n", duration / 1000.0); } // start audio playing result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); assert(SL_RESULT_SUCCESS == result); // wait for audio to finish playing SLuint32 state; for (;;) { result = (*playerPlay)->GetPlayState(playerPlay, &state); assert(SL_RESULT_SUCCESS == result); if (SL_PLAYSTATE_PLAYING != state) break; usleep(1000000); } assert(SL_PLAYSTATE_PAUSED == state); destroyRes: // cleanup objects (*playerObject)->Destroy(playerObject); (*mixObject)->Destroy(mixObject); (*engineObject)->Destroy(engineObject); return EXIT_SUCCESS; }