/* * 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 <pthread.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) }; // Parameters for preset reverb on output mix bool outputMixPresetItfRequested = false; SLuint16 outputMixPresetNumber = ~0; // Parameters for environmental reverb on output mix bool outputMixEnvironmentalItfRequested = false; char *outputMixEnvironmentalName = NULL; SLEnvironmentalReverbSettings outputMixEnvironmentalSettings; // Parameters for preset reverb on audio player (not supported) bool playerPresetItfRequested = false; SLuint16 playerPresetNumber = ~0; // Parameters for environmental reverb on audio player (not supported) bool playerEnvironmentalItfRequested = false; char *playerEnvironmentalName = NULL; SLEnvironmentalReverbSettings playerEnvironmentalSettings; // Compare two environmental reverb settings structures. // Returns true if the settings are identical, or false if they are different. bool slesutCompareEnvironmentalReverbSettings( 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: %d\n", settings->roomLevel); printf("roomHFLevel: %d\n", settings->roomHFLevel); printf("decayTime: %d\n", settings->decayTime); printf("decayHFRatio: %d\n", settings->decayHFRatio); printf("reflectionsLevel: %d\n", settings->reflectionsLevel); printf("reflectionsDelay: %d\n", settings->reflectionsDelay); printf("reverbLevel: %d\n", settings->reverbLevel); printf("reverbDelay: %d\n", settings->reverbDelay); printf("diffusion: %d\n", settings->diffusion); printf("density: %d\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'); } } // These are extensions to OpenSL ES 1.0.1 values #define SL_PREFETCHSTATUS_UNKNOWN ((SLuint32) 0) #define SL_PREFETCHSTATUS_ERROR ((SLuint32) -1) // Mutex and condition shared with main program to protect prefetch_status static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; SLuint32 prefetch_status = SL_PREFETCHSTATUS_UNKNOWN; /* used to detect errors likely to have occured when the OpenSL ES framework fails to open * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. */ #define PREFETCHEVENT_ERROR_CANDIDATE \ (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) // Prefetch status callback void prefetch_callback(SLPrefetchStatusItf caller, void *context, SLuint32 event) { SLresult result; assert(context == NULL); SLpermille level; result = (*caller)->GetFillLevel(caller, &level); assert(SL_RESULT_SUCCESS == result); SLuint32 status; result = (*caller)->GetPrefetchStatus(caller, &status); assert(SL_RESULT_SUCCESS == result); SLuint32 new_prefetch_status; if ((event & PREFETCHEVENT_ERROR_CANDIDATE) == PREFETCHEVENT_ERROR_CANDIDATE && level == 0 && status == SL_PREFETCHSTATUS_UNDERFLOW) { new_prefetch_status = SL_PREFETCHSTATUS_ERROR; } else if (event == SL_PREFETCHEVENT_STATUSCHANGE && status == SL_PREFETCHSTATUS_SUFFICIENTDATA) { new_prefetch_status = status; } else { return; } int ok; ok = pthread_mutex_lock(&mutex); assert(ok == 0); prefetch_status = new_prefetch_status; ok = pthread_cond_signal(&cond); assert(ok == 0); ok = pthread_mutex_unlock(&mutex); assert(ok == 0); } // Main program int main(int argc, char **argv) { SLresult result; bool loop = false; // process command line parameters char *prog = argv[0]; int i; for (i = 1; i < argc; ++i) { char *arg = argv[i]; if (arg[0] != '-') break; bool bad = false; // whether the option string is invalid if (!strncmp(arg, "--mix-preset", 12)) { if ('\0' == arg[12]) { outputMixPresetItfRequested = true; } else if ('=' == arg[12]) { outputMixPresetNumber = atoi(&arg[13]); outputMixPresetItfRequested = true; } else { bad = true; } } else if (!strncmp(arg, "--mix-name", 10)) { if ('\0' == arg[10]) { outputMixEnvironmentalItfRequested = true; } else if ('=' == arg[10]) { outputMixEnvironmentalName = &arg[11]; outputMixEnvironmentalItfRequested = true; } else { bad = true; } } else if (!strncmp(arg, "--player-preset", 15)) { if ('\0' == arg[15]) { playerPresetItfRequested = true; } else if ('=' == arg[15]) { playerPresetNumber = atoi(&arg[16]); playerPresetItfRequested = true; } else { bad = true; } } else if (!strncmp(arg, "--player-name", 13)) { if ('\0' == arg[13]) { playerEnvironmentalItfRequested = true; } else if ('=' == arg[13]) { playerEnvironmentalName = &arg[14]; playerEnvironmentalItfRequested = true; } else { bad = true; } } else if (!strcmp(arg, "--loop")) { loop = true; } else { bad = true; } if (bad) { 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 --loop filename\n", prog); return EXIT_FAILURE; } char *pathname = argv[i]; const SLEnvironmentalReverbSettings *envSettings; if (NULL != outputMixEnvironmentalName) { envSettings = lookupEnvName(outputMixEnvironmentalName); if (NULL == envSettings) { fprintf(stderr, "%s: output mix environmental reverb name %s not found, " "available names are:\n", prog, outputMixEnvironmentalName); printEnvNames(); return EXIT_FAILURE; } outputMixEnvironmentalSettings = *envSettings; } if (NULL != playerEnvironmentalName) { envSettings = lookupEnvName(playerEnvironmentalName); if (NULL == envSettings) { fprintf(stderr, "%s: player environmental reverb name %s not found, " "available names are:\n", prog, playerEnvironmentalName); printEnvNames(); return EXIT_FAILURE; } playerEnvironmentalSettings = *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 (outputMixPresetItfRequested) { mix_req[count] = SL_BOOLEAN_TRUE; mix_ids[count++] = SL_IID_PRESETREVERB; } if (outputMixEnvironmentalItfRequested) { 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 outputMixPresetReverb; if (outputMixPresetItfRequested) { result = (*mixObject)->GetInterface(mixObject, SL_IID_PRESETREVERB, &outputMixPresetReverb); assert(SL_RESULT_SUCCESS == result); SLuint16 getPresetReverb = 12345; result = (*outputMixPresetReverb)->GetPreset(outputMixPresetReverb, &getPresetReverb); assert(SL_RESULT_SUCCESS == result); printf("Output mix default preset reverb number = %u\n", getPresetReverb); if (outputMixPresetNumber != ((SLuint16) ~0)) { result = (*outputMixPresetReverb)->SetPreset(outputMixPresetReverb, outputMixPresetNumber); if (SL_RESULT_SUCCESS == result) { result = (*outputMixPresetReverb)->GetPreset(outputMixPresetReverb, &getPresetReverb); assert(SL_RESULT_SUCCESS == result); assert(getPresetReverb == outputMixPresetNumber); printf("Output mix preset reverb successfully changed to %u\n", outputMixPresetNumber); } else { printf("Unable to set output mix preset reverb to %u, result=%u\n", outputMixPresetNumber, result); } } } // configure environmental reverb on output mix SLEnvironmentalReverbItf outputMixEnvironmentalReverb; if (outputMixEnvironmentalItfRequested) { result = (*mixObject)->GetInterface(mixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb); assert(SL_RESULT_SUCCESS == result); SLEnvironmentalReverbSettings getSettings; result = (*outputMixEnvironmentalReverb)->GetEnvironmentalReverbProperties( outputMixEnvironmentalReverb, &getSettings); assert(SL_RESULT_SUCCESS == result); printf("Output mix default environmental reverb settings\n"); printf("------------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); if (outputMixEnvironmentalName != NULL) { result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties( outputMixEnvironmentalReverb, &outputMixEnvironmentalSettings); assert(SL_RESULT_SUCCESS == result); printf("Output mix new environmental reverb settings\n"); printf("--------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&outputMixEnvironmentalSettings); printf("\n"); result = (*outputMixEnvironmentalReverb)->GetEnvironmentalReverbProperties( outputMixEnvironmentalReverb, &getSettings); assert(SL_RESULT_SUCCESS == result); printf("Output mix read environmental reverb settings\n"); printf("--------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); if (!slesutCompareEnvironmentalReverbSettings(&getSettings, &outputMixEnvironmentalSettings)) { 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[5]; SLboolean player_req[5]; count = 0; if (playerPresetItfRequested) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_PRESETREVERB; } if (playerEnvironmentalItfRequested) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_ENVIRONMENTALREVERB; } if (outputMixPresetItfRequested || outputMixEnvironmentalItfRequested) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_EFFECTSEND; } if (loop) { player_req[count] = SL_BOOLEAN_TRUE; player_ids[count++] = SL_IID_SEEK; } 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 (outputMixPresetItfRequested || outputMixEnvironmentalItfRequested) { SLEffectSendItf playerEffectSend; result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); assert(SL_RESULT_SUCCESS == result); SLboolean enabled; SLmillibel directLevel; SLmillibel sendLevel; if (outputMixPresetItfRequested) { result = (*playerEffectSend)->IsEnabled(playerEffectSend, outputMixPresetReverb, &enabled); assert(SL_RESULT_SUCCESS == result); printf("Output mix preset reverb: player effect send default enabled = %s\n", enabled ? "true" : "false"); directLevel = 12345; result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel); assert(SL_RESULT_SUCCESS == result); printf("Output mix preset reverb: player effect send default direct level = %d\n", directLevel); sendLevel = 12345; result = (*playerEffectSend)->GetSendLevel(playerEffectSend, outputMixPresetReverb, &sendLevel); assert(SL_RESULT_SUCCESS == result); printf("Output mix preset reverb: player effect send default send level = %d\n", sendLevel); if (outputMixPresetNumber != ((SLuint16) ~0)) { result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, outputMixPresetReverb, SL_BOOLEAN_TRUE, (SLmillibel) 0); assert(SL_RESULT_SUCCESS == result); result = (*playerEffectSend)->IsEnabled(playerEffectSend, outputMixPresetReverb, &enabled); assert(SL_RESULT_SUCCESS == result); directLevel = 12345; result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel); assert(SL_RESULT_SUCCESS == result); sendLevel = 12345; result = (*playerEffectSend)->GetSendLevel(playerEffectSend, outputMixPresetReverb, &sendLevel); assert(SL_RESULT_SUCCESS == result); printf("Output mix preset reverb: player effect send new enabled = %s, direct level" " = %d, send level = %d\n", enabled ? "true" : "false", directLevel, sendLevel); } } if (outputMixEnvironmentalItfRequested) { if (outputMixEnvironmentalName != NULL) { result = (*playerEffectSend)->IsEnabled(playerEffectSend, outputMixEnvironmentalReverb, &enabled); assert(SL_RESULT_SUCCESS == result); printf("Output mix environmental reverb: player effect send default enabled = %s\n", enabled ? "true" : "false"); directLevel = 12345; result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel); assert(SL_RESULT_SUCCESS == result); printf("Output mix environmental reverb: player effect send default direct level" " = %d\n", directLevel); sendLevel = 12345; result = (*playerEffectSend)->GetSendLevel(playerEffectSend, outputMixEnvironmentalReverb, &sendLevel); assert(SL_RESULT_SUCCESS == result); printf("Output mix environmental reverb: player effect send default send level" " = %d\n", sendLevel); result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, outputMixEnvironmentalReverb, SL_BOOLEAN_TRUE, (SLmillibel) 0); assert(SL_RESULT_SUCCESS == result); result = (*playerEffectSend)->IsEnabled(playerEffectSend, outputMixEnvironmentalReverb, &enabled); assert(SL_RESULT_SUCCESS == result); directLevel = 12345; result = (*playerEffectSend)->GetDirectLevel(playerEffectSend, &directLevel); assert(SL_RESULT_SUCCESS == result); sendLevel = 12345; result = (*playerEffectSend)->GetSendLevel(playerEffectSend, outputMixEnvironmentalReverb, &sendLevel); assert(SL_RESULT_SUCCESS == result); printf("Output mix environmental reverb: player effect send new enabled = %s, " "direct level = %d, send level = %d\n", enabled ? "true" : "false", directLevel, sendLevel); } } } // configure preset reverb on player SLPresetReverbItf playerPresetReverb; if (playerPresetItfRequested) { result = (*playerObject)->GetInterface(playerObject, SL_IID_PRESETREVERB, &playerPresetReverb); assert(SL_RESULT_SUCCESS == result); SLuint16 getPresetReverb = 12345; result = (*playerPresetReverb)->GetPreset(playerPresetReverb, &getPresetReverb); if (SL_RESULT_SUCCESS == result) { printf("Player default preset reverb %u\n", getPresetReverb); if (playerPresetNumber != ((SLuint16) ~0)) { 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=%u\n", playerPresetNumber, result); } } } else { printf("Unable to get player default preset reverb, result=%u\n", result); } } // configure environmental reverb on player SLEnvironmentalReverbItf playerEnvironmentalReverb; if (playerEnvironmentalItfRequested) { 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); if (SL_RESULT_SUCCESS == result) { printf("Player default environmental reverb settings\n"); printf("--------------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&getSettings); printf("\n"); if (playerEnvironmentalName != NULL) { result = (*playerEnvironmentalReverb)->SetEnvironmentalReverbProperties( playerEnvironmentalReverb, &playerEnvironmentalSettings); assert(SL_RESULT_SUCCESS == result); printf("Player new environmental reverb settings\n"); printf("----------------------------------------\n"); slesutPrintEnvironmentalReverbSettings(&playerEnvironmentalSettings); 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 (!slesutCompareEnvironmentalReverbSettings(&getSettings, &playerEnvironmentalSettings)) { printf("Warning: new and read are different; check details above\n"); } else { printf("New and read match, life is good\n"); } } } else { printf("Unable to get player default environmental reverb properties, result=%u\n", result); } } // get the play interface SLPlayItf playerPlay; result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 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); // enable prefetch status callbacks result = (*playerPrefetchStatus)->RegisterCallback(playerPrefetchStatus, prefetch_callback, NULL); assert(SL_RESULT_SUCCESS == result); result = (*playerPrefetchStatus)->SetCallbackEventsMask(playerPrefetchStatus, SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE); 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); // wait for prefetch status callback to indicate either sufficient data or error pthread_mutex_lock(&mutex); while (prefetch_status == SL_PREFETCHSTATUS_UNKNOWN) { pthread_cond_wait(&cond, &mutex); } pthread_mutex_unlock(&mutex); if (prefetch_status == SL_PREFETCHSTATUS_ERROR) { fprintf(stderr, "Error during prefetch, 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); } // enable looping if (loop) { SLSeekItf playerSeek; result = (*playerObject)->GetInterface(playerObject, SL_IID_SEEK, &playerSeek); assert(SL_RESULT_SUCCESS == result); result = (*playerSeek)->SetLoop(playerSeek, SL_BOOLEAN_TRUE, (SLmillisecond) 0, SL_TIME_UNKNOWN); assert(SL_RESULT_SUCCESS == result); } // 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; }