Sound refactor (#1589)
* Soud refactor * remove files from files_common * add timeout to set_volumn * add param volume to init * done * test.cc * fix typo * add repeat param instead of loop * revert submodule * add member function currentSound * remove function create_player from class member * fix build error fix repeat * rename CHECK_RESULT to ReturnOnError * set currentSound_ before posible err * use std::map to initialize sound table cleanup cleanup cleanup fix bug in stop change paramater name * done * remove function CreatePlayer, create player in init() * resolve conflict * remove sound test * rebase * remove whitespace * Apply great review suggestion * use player's SLVolumeItf interface to set volume * use float * leave the volume control the way it ispull/1711/head
parent
10cb6ab87a
commit
8cacc14b31
11 changed files with 159 additions and 377 deletions
@ -1,184 +0,0 @@ |
|||||||
#include <stdio.h> |
|
||||||
#include <assert.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <getopt.h> |
|
||||||
|
|
||||||
#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"; |
|
||||||
} |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
#ifndef SLPLAY_H |
|
||||||
#define SLPLAY_H |
|
||||||
|
|
||||||
#include <SLES/OpenSLES.h> |
|
||||||
#include <SLES/OpenSLES_Android.h> |
|
||||||
#include <stdbool.h> |
|
||||||
|
|
||||||
typedef struct { |
|
||||||
const char* uri; |
|
||||||
SLObjectItf player; |
|
||||||
SLPlayItf playInterface; |
|
||||||
} uri_player; |
|
||||||
|
|
||||||
void slplay_setup(char **error); |
|
||||||
uri_player* slplay_create_player_for_uri(const char* uri, char **error); |
|
||||||
void slplay_play (const char *uri, bool loop, char **error); |
|
||||||
void slplay_stop_uri (const char* uri, char **error); |
|
||||||
void slplay_destroy(); |
|
||||||
|
|
||||||
#endif |
|
||||||
|
|
@ -1,17 +1,33 @@ |
|||||||
#ifndef __SOUND_HPP |
#pragma once |
||||||
#define __SOUND_HPP |
#include <map> |
||||||
|
|
||||||
#include "cereal/gen/cpp/log.capnp.h" |
#include "cereal/gen/cpp/log.capnp.h" |
||||||
|
|
||||||
typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; |
#if defined(QCOM) || defined(QCOM2) |
||||||
|
#include <SLES/OpenSLES.h> |
||||||
void ui_sound_init(); |
#include <SLES/OpenSLES_Android.h> |
||||||
void ui_sound_destroy(); |
#endif |
||||||
|
|
||||||
void set_volume(int volume); |
typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; |
||||||
|
|
||||||
void play_alert_sound(AudibleAlert alert); |
class Sound { |
||||||
void stop_alert_sound(AudibleAlert alert); |
public: |
||||||
|
Sound() = default; |
||||||
|
bool init(int volume); |
||||||
|
bool play(AudibleAlert alert, int repeat = 0); |
||||||
|
void stop(); |
||||||
|
void setVolume(int volume, int timeout_seconds = 5); |
||||||
|
AudibleAlert currentPlaying(); |
||||||
|
~Sound(); |
||||||
|
|
||||||
|
private: |
||||||
|
#if defined(QCOM) || defined(QCOM2) |
||||||
|
SLObjectItf engine_ = nullptr; |
||||||
|
SLObjectItf outputMix_ = nullptr; |
||||||
|
int last_volume_ = 0; |
||||||
|
double last_set_volume_time_ = 0.; |
||||||
|
AudibleAlert currentSound_ = AudibleAlert::NONE; |
||||||
|
struct Player; |
||||||
|
std::map<AudibleAlert, Player *> player_; |
||||||
|
friend void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event); |
||||||
#endif |
#endif |
||||||
|
}; |
||||||
|
@ -1,3 +0,0 @@ |
|||||||
#!/bin/sh |
|
||||||
clang -fPIC -o play_sound play_sound.c ../slplay.c -I ../../ -I ../ -lOpenSLES -Wl,-rpath=/system/lib64 |
|
||||||
|
|
@ -1,37 +0,0 @@ |
|||||||
#include <stdio.h> |
|
||||||
#include "slplay.h" |
|
||||||
|
|
||||||
void play_sound(char *uri, int volume) { |
|
||||||
char **error = NULL; |
|
||||||
printf("call slplay_setup\n"); |
|
||||||
slplay_setup(error); |
|
||||||
if (error) { printf("%s\n", *error); return; } |
|
||||||
|
|
||||||
printf("call slplay_create_player_for_uri\n"); |
|
||||||
slplay_create_player_for_uri(uri, error); |
|
||||||
if (error) { printf("%s\n", *error); return; } |
|
||||||
|
|
||||||
printf("call slplay_play\n"); |
|
||||||
|
|
||||||
while (1) { |
|
||||||
char volume_change_cmd[64]; |
|
||||||
sprintf(volume_change_cmd, "service call audio 3 i32 3 i32 %d i32 1", volume); |
|
||||||
system(volume_change_cmd); |
|
||||||
|
|
||||||
slplay_play(uri, false, error); |
|
||||||
if (error) { printf("%s\n", *error); return; } |
|
||||||
|
|
||||||
sleep(1); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
int main(int argc, char *argv[]) { |
|
||||||
int volume = 10; |
|
||||||
if (argc > 2) { |
|
||||||
volume = atoi(argv[2]); |
|
||||||
} |
|
||||||
printf("setting volume to %d\n", volume); |
|
||||||
|
|
||||||
play_sound(argv[1], volume); |
|
||||||
return 0; |
|
||||||
} |
|
Loading…
Reference in new issue