#include #include #include #include #include #include "common/timing.h" #include "slplay.h" SLEngineItf engineInterface = NULL; SLObjectItf outputMix = NULL; SLObjectItf engine = NULL; uri_player players[32] = {{NULL, NULL, NULL}}; uint64_t loop_start = 0; uint64_t loop_start_ctx = 0; uri_player* get_player_by_uri(const char* uri) { for (uri_player *s = players; s->uri != NULL; s++) { if (strcmp(s->uri, uri) == 0) { return s; } } return NULL; } uri_player* slplay_create_player_for_uri(const char* uri, char **error) { uri_player player = { uri, NULL, NULL }; SLresult result; SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *) uri}; SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; SLDataSource audioSrc = {&locUri, &formatMime}; SLDataLocator_OutputMix outMix = {SL_DATALOCATOR_OUTPUTMIX, outputMix}; SLDataSink audioSnk = {&outMix, NULL}; result = (*engineInterface)->CreateAudioPlayer(engineInterface, &player.player, &audioSrc, &audioSnk, 0, NULL, NULL); if (result != SL_RESULT_SUCCESS) { *error = "Failed to create audio player"; return NULL; } result = (*(player.player))->Realize(player.player, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS) { *error = "Failed to realize audio player"; return NULL; } result = (*(player.player))->GetInterface(player.player, SL_IID_PLAY, &(player.playInterface)); if (result != SL_RESULT_SUCCESS) { *error = "Failed to get player interface"; return NULL; } result = (*(player.playInterface))->SetPlayState(player.playInterface, SL_PLAYSTATE_PAUSED); if (result != SL_RESULT_SUCCESS) { *error = "Failed to initialize playstate to SL_PLAYSTATE_PAUSED"; return NULL; } uri_player *p = players; while (p->uri != NULL) { p++; } *p = player; return p; } void slplay_setup(char **error) { SLresult result; SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}}; result = slCreateEngine(&engine, 1, engineOptions, 0, NULL, NULL); if (result != SL_RESULT_SUCCESS) { *error = "Failed to create OpenSL engine"; } result = (*engine)->Realize(engine, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS) { *error = "Failed to realize OpenSL engine"; } result = (*engine)->GetInterface(engine, SL_IID_ENGINE, &engineInterface); if (result != SL_RESULT_SUCCESS) { *error = "Failed to realize OpenSL engine"; } const SLInterfaceID ids[1] = {SL_IID_VOLUME}; const SLboolean req[1] = {SL_BOOLEAN_FALSE}; result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMix, 1, ids, req); if (result != SL_RESULT_SUCCESS) { *error = "Failed to create output mix"; } result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS) { *error = "Failed to realize output mix"; } } void slplay_destroy() { for (uri_player *player = players; player->uri != NULL; player++) { if (player->player) { (*(player->player))->Destroy(player->player); } } (*outputMix)->Destroy(outputMix); (*engine)->Destroy(engine); } void slplay_stop(uri_player* player, char **error) { SLPlayItf playInterface = player->playInterface; SLresult result; // stop a loop loop_start = 0; result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PAUSED); if (result != SL_RESULT_SUCCESS) { *error = "Failed to set SL_PLAYSTATE_STOPPED"; return; } } void slplay_stop_uri(const char* uri, char **error) { uri_player* player = get_player_by_uri(uri); slplay_stop(player, error); } void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) { uint64_t cb_loop_start = *((uint64_t*)context); if (event == SL_PLAYEVENT_HEADATEND && cb_loop_start == loop_start) { (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); (*playItf)->SetMarkerPosition(playItf, 0); (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); } } void slplay_play (const char *uri, bool loop, char **error) { SLresult result; uri_player* player = get_player_by_uri(uri); if (player == NULL) { player = slplay_create_player_for_uri(uri, error); if (*error) { return; } } SLPlayItf playInterface = player->playInterface; if (loop) { loop_start = nanos_since_boot(); loop_start_ctx = loop_start; result = (*playInterface)->RegisterCallback(playInterface, slplay_callback, &loop_start_ctx); if (result != SL_RESULT_SUCCESS) { char error[64]; snprintf(error, sizeof(error), "Failed to register callback. %d", result); *error = error[0]; return; } result = (*playInterface)->SetCallbackEventsMask(playInterface, SL_PLAYEVENT_HEADATEND); if (result != SL_RESULT_SUCCESS) { *error = "Failed to set callback event mask"; return; } } // Reset the audio player result = (*playInterface)->ClearMarkerPosition(playInterface); if (result != SL_RESULT_SUCCESS) { *error = "Failed to clear marker position"; return; } result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PAUSED); result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_STOPPED); result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PLAYING); if (result != SL_RESULT_SUCCESS) { *error = "Failed to set SL_PLAYSTATE_PLAYING"; } }