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
|
@ -322,9 +322,7 @@ selfdrive/test/test_fingerprints.py
|
|||
selfdrive/test/test_car_models.py
|
||||
|
||||
selfdrive/ui/SConscript
|
||||
selfdrive/ui/*.c
|
||||
selfdrive/ui/*.cc
|
||||
selfdrive/ui/*.h
|
||||
selfdrive/ui/*.hpp
|
||||
selfdrive/ui/ui
|
||||
selfdrive/ui/spinner/Makefile
|
||||
|
|
|
@ -4,7 +4,7 @@ src = ['ui.cc', 'paint.cc', 'sidebar.cc', '#phonelibs/nanovg/nanovg.c']
|
|||
libs = [common, 'zmq', 'czmq', 'capnp', 'kj', 'm', cereal, messaging, gpucommon, visionipc]
|
||||
|
||||
if arch == "aarch64":
|
||||
src += ['sound.cc', 'slplay.c']
|
||||
src += ['sound.cc']
|
||||
libs += ['EGL', 'GLESv3', 'gnustl_shared', 'log', 'utils', 'gui', 'hardware', 'ui', 'CB', 'gsl', 'adreno_utils', 'OpenSLES', 'cutils', 'uuid', 'OpenCL']
|
||||
linkflags = ['-Wl,-rpath=/system/lib64,-rpath=/system/comma/usr/lib']
|
||||
else:
|
||||
|
|
|
@ -82,13 +82,12 @@ int touch_read(TouchState *s, int* out_x, int* out_y) {
|
|||
|
||||
#include "sound.hpp"
|
||||
|
||||
void ui_sound_init() {}
|
||||
void ui_sound_destroy() {}
|
||||
|
||||
void set_volume(int volume) {}
|
||||
|
||||
void play_alert_sound(AudibleAlert alert) {}
|
||||
void stop_alert_sound(AudibleAlert alert) {}
|
||||
bool Sound::init(int volume) { return true; }
|
||||
bool Sound::play(AudibleAlert alert, int repeat) { return true; }
|
||||
void Sound::stop() {}
|
||||
void Sound::setVolume(int volume, int timeout_seconds) {}
|
||||
AudibleAlert Sound::currentPlaying() { return AudibleAlert::NONE; }
|
||||
Sound::~Sound() {}
|
||||
|
||||
#include "common/visionimg.h"
|
||||
#include <sys/mman.h>
|
||||
|
|
|
@ -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,91 +1,137 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "sound.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <atomic>
|
||||
#include "common/swaglog.h"
|
||||
#include "common/timing.h"
|
||||
|
||||
typedef struct {
|
||||
AudibleAlert alert;
|
||||
const char* uri;
|
||||
bool loop;
|
||||
} sound_file;
|
||||
#define LogOnError(func, msg) \
|
||||
if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); }
|
||||
|
||||
extern "C"{
|
||||
#include "slplay.h"
|
||||
}
|
||||
#define ReturnOnError(func, msg) \
|
||||
if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); return false; }
|
||||
|
||||
int last_volume = 0;
|
||||
static std::map<AudibleAlert, const char *> sound_map{
|
||||
{AudibleAlert::CHIME_DISENGAGE, "../assets/sounds/disengaged.wav"},
|
||||
{AudibleAlert::CHIME_ENGAGE, "../assets/sounds/engaged.wav"},
|
||||
{AudibleAlert::CHIME_WARNING1, "../assets/sounds/warning_1.wav"},
|
||||
{AudibleAlert::CHIME_WARNING2, "../assets/sounds/warning_2.wav"},
|
||||
{AudibleAlert::CHIME_WARNING2_REPEAT, "../assets/sounds/warning_2.wav"},
|
||||
{AudibleAlert::CHIME_WARNING_REPEAT, "../assets/sounds/warning_repeat.wav"},
|
||||
{AudibleAlert::CHIME_ERROR, "../assets/sounds/error.wav"},
|
||||
{AudibleAlert::CHIME_PROMPT, "../assets/sounds/error.wav"}};
|
||||
|
||||
void set_volume(int volume) {
|
||||
if (last_volume != volume) {
|
||||
char volume_change_cmd[64];
|
||||
sprintf(volume_change_cmd, "service call audio 3 i32 3 i32 %d i32 1 &", volume);
|
||||
|
||||
// 5 second timeout at 60fps
|
||||
int volume_changed = system(volume_change_cmd);
|
||||
last_volume = volume;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sound_file sound_table[] = {
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_DISENGAGE, "../assets/sounds/disengaged.wav", false },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_ENGAGE, "../assets/sounds/engaged.wav", false },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING1, "../assets/sounds/warning_1.wav", false },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING2, "../assets/sounds/warning_2.wav", false },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING2_REPEAT, "../assets/sounds/warning_2.wav", true },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING_REPEAT, "../assets/sounds/warning_repeat.wav", true },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_ERROR, "../assets/sounds/error.wav", false },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::CHIME_PROMPT, "../assets/sounds/error.wav", false },
|
||||
{ cereal::CarControl::HUDControl::AudibleAlert::NONE, NULL, false },
|
||||
struct Sound::Player {
|
||||
SLObjectItf player;
|
||||
SLPlayItf playItf;
|
||||
// slplay_callback runs on a background thread,use atomic to ensure thread safe.
|
||||
std::atomic<int> repeat;
|
||||
};
|
||||
|
||||
sound_file* get_sound_file(AudibleAlert alert) {
|
||||
for (sound_file *s = sound_table; s->alert != cereal::CarControl::HUDControl::AudibleAlert::NONE; s++) {
|
||||
if (s->alert == alert) {
|
||||
return s;
|
||||
bool Sound::init(int volume) {
|
||||
SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}};
|
||||
const SLInterfaceID ids[1] = {SL_IID_VOLUME};
|
||||
const SLboolean req[1] = {SL_BOOLEAN_FALSE};
|
||||
SLEngineItf engineInterface = NULL;
|
||||
ReturnOnError(slCreateEngine(&engine_, 1, engineOptions, 0, NULL, NULL), "Failed to create OpenSL engine");
|
||||
ReturnOnError((*engine_)->Realize(engine_, SL_BOOLEAN_FALSE), "Failed to realize OpenSL engine");
|
||||
ReturnOnError((*engine_)->GetInterface(engine_, SL_IID_ENGINE, &engineInterface), "Failed to get OpenSL engine interface");
|
||||
ReturnOnError((*engineInterface)->CreateOutputMix(engineInterface, &outputMix_, 1, ids, req), "Failed to create output mix");
|
||||
ReturnOnError((*outputMix_)->Realize(outputMix_, SL_BOOLEAN_FALSE), "Failed to realize output mix");
|
||||
|
||||
for (auto &kv : sound_map) {
|
||||
SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *)kv.second};
|
||||
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};
|
||||
|
||||
SLObjectItf player = NULL;
|
||||
SLPlayItf playItf = NULL;
|
||||
ReturnOnError((*engineInterface)->CreateAudioPlayer(engineInterface, &player, &audioSrc, &audioSnk, 0, NULL, NULL), "Failed to create audio player");
|
||||
ReturnOnError((*player)->Realize(player, SL_BOOLEAN_FALSE), "Failed to realize audio player");
|
||||
ReturnOnError((*player)->GetInterface(player, SL_IID_PLAY, &playItf), "Failed to get player interface");
|
||||
ReturnOnError((*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED), "Failed to initialize playstate to SL_PLAYSTATE_PAUSED");
|
||||
|
||||
player_[kv.first] = new Sound::Player{player, playItf};
|
||||
}
|
||||
|
||||
setVolume(volume);
|
||||
return true;
|
||||
}
|
||||
|
||||
AudibleAlert Sound::currentPlaying() {
|
||||
if (currentSound_ != AudibleAlert::NONE) {
|
||||
auto playItf = player_.at(currentSound_)->playItf;
|
||||
SLuint32 state;
|
||||
if (SL_RESULT_SUCCESS == (*playItf)->GetPlayState(playItf, &state) &&
|
||||
(state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED)) {
|
||||
currentSound_ = AudibleAlert::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return currentSound_;
|
||||
}
|
||||
|
||||
void play_alert_sound(AudibleAlert alert) {
|
||||
sound_file* sound = get_sound_file(alert);
|
||||
char* error = NULL;
|
||||
|
||||
slplay_play(sound->uri, sound->loop, &error);
|
||||
if(error) {
|
||||
LOGW("error playing sound: %s", error);
|
||||
void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) {
|
||||
Sound::Player *s = reinterpret_cast<Sound::Player *>(context);
|
||||
if (event == SL_PLAYEVENT_HEADATEND && s->repeat > 1) {
|
||||
--s->repeat;
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
|
||||
(*playItf)->SetMarkerPosition(playItf, 0);
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
void stop_alert_sound(AudibleAlert alert) {
|
||||
sound_file* sound = get_sound_file(alert);
|
||||
char* error = NULL;
|
||||
bool Sound::play(AudibleAlert alert, int repeat) {
|
||||
if (currentSound_ != AudibleAlert::NONE) {
|
||||
stop();
|
||||
}
|
||||
auto player = player_.at(alert);
|
||||
SLPlayItf playItf = player->playItf;
|
||||
player->repeat = repeat;
|
||||
if (player->repeat > 0) {
|
||||
ReturnOnError((*playItf)->RegisterCallback(playItf, slplay_callback, player), "Failed to register callback");
|
||||
ReturnOnError((*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATEND), "Failed to set callback event mask");
|
||||
}
|
||||
|
||||
slplay_stop_uri(sound->uri, &error);
|
||||
if(error) {
|
||||
LOGW("error stopping sound: %s", error);
|
||||
// Reset the audio player
|
||||
ReturnOnError((*playItf)->ClearMarkerPosition(playItf), "Failed to clear marker position");
|
||||
uint32_t states[] = {SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_STOPPED, SL_PLAYSTATE_PLAYING};
|
||||
for (auto state : states) {
|
||||
ReturnOnError((*playItf)->SetPlayState(playItf, state), "Failed to set SL_PLAYSTATE_PLAYING");
|
||||
}
|
||||
currentSound_ = alert;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sound::stop() {
|
||||
if (currentSound_ != AudibleAlert::NONE) {
|
||||
auto player = player_.at(currentSound_);
|
||||
player->repeat = 0;
|
||||
LogOnError((*(player->playItf))->SetPlayState(player->playItf, SL_PLAYSTATE_PAUSED), "Failed to set SL_PLAYSTATE_PAUSED");
|
||||
currentSound_ = AudibleAlert::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void ui_sound_init() {
|
||||
char *error = NULL;
|
||||
slplay_setup(&error);
|
||||
if (error) goto fail;
|
||||
|
||||
for (sound_file *s = sound_table; s->alert != cereal::CarControl::HUDControl::AudibleAlert::NONE; s++) {
|
||||
slplay_create_player_for_uri(s->uri, &error);
|
||||
if (error) goto fail;
|
||||
void Sound::setVolume(int volume, int timeout_seconds) {
|
||||
if (last_volume_ == volume) return;
|
||||
|
||||
double current_time = nanos_since_boot();
|
||||
if ((current_time - last_set_volume_time_) > (timeout_seconds * (1e+9))) {
|
||||
char volume_change_cmd[64];
|
||||
snprintf(volume_change_cmd, sizeof(volume_change_cmd), "service call audio 3 i32 3 i32 %d i32 1 &", volume);
|
||||
system(volume_change_cmd);
|
||||
last_volume_ = volume;
|
||||
last_set_volume_time_ = current_time;
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
LOGW(error);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void ui_sound_destroy() {
|
||||
slplay_destroy();
|
||||
Sound::~Sound() {
|
||||
for (auto &kv : player_) {
|
||||
(*(kv.second->player))->Destroy(kv.second->player);
|
||||
delete kv.second;
|
||||
}
|
||||
if (outputMix_) (*outputMix_)->Destroy(outputMix_);
|
||||
if (engine_) (*engine_)->Destroy(engine_);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,33 @@
|
|||
#ifndef __SOUND_HPP
|
||||
#define __SOUND_HPP
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include "cereal/gen/cpp/log.capnp.h"
|
||||
|
||||
#if defined(QCOM) || defined(QCOM2)
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
#endif
|
||||
|
||||
typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert;
|
||||
|
||||
void ui_sound_init();
|
||||
void ui_sound_destroy();
|
||||
|
||||
void set_volume(int volume);
|
||||
|
||||
void play_alert_sound(AudibleAlert alert);
|
||||
void stop_alert_sound(AudibleAlert alert);
|
||||
class Sound {
|
||||
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
|
||||
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -308,16 +308,12 @@ void handle_message(UIState *s, SubMaster &sm) {
|
|||
if (!scene.frontview){ s->controls_seen = true; }
|
||||
|
||||
auto alert_sound = scene.controls_state.getAlertSound();
|
||||
const auto sound_none = cereal::CarControl::HUDControl::AudibleAlert::NONE;
|
||||
if (alert_sound != s->alert_sound){
|
||||
if (s->alert_sound != sound_none){
|
||||
stop_alert_sound(s->alert_sound);
|
||||
if (alert_sound != s->sound.currentPlaying()) {
|
||||
if (alert_sound == AudibleAlert::NONE) {
|
||||
s->sound.stop();
|
||||
} else {
|
||||
s->sound.play(alert_sound);
|
||||
}
|
||||
if (alert_sound != sound_none){
|
||||
play_alert_sound(alert_sound);
|
||||
s->alert_type = scene.controls_state.getAlertType();
|
||||
}
|
||||
s->alert_sound = alert_sound;
|
||||
}
|
||||
scene.alert_text1 = scene.controls_state.getAlertText1();
|
||||
scene.alert_text2 = scene.controls_state.getAlertText2();
|
||||
|
@ -411,7 +407,6 @@ void handle_message(UIState *s, SubMaster &sm) {
|
|||
if (!s->started) {
|
||||
if (s->status != STATUS_STOPPED) {
|
||||
update_status(s, STATUS_STOPPED);
|
||||
s->alert_sound_timeout = 0;
|
||||
s->vision_seen = false;
|
||||
s->controls_seen = false;
|
||||
s->active_app = cereal::UiLayoutState::App::HOME;
|
||||
|
@ -754,7 +749,6 @@ int main(int argc, char* argv[]) {
|
|||
TouchState touch = {0};
|
||||
touch_init(&touch);
|
||||
s->touch_fd = touch.fd;
|
||||
ui_sound_init();
|
||||
|
||||
// light sensor scaling params
|
||||
const bool LEON = util::read_file("/proc/cmdline").find("letv") != std::string::npos;
|
||||
|
@ -774,9 +768,8 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
const int MIN_VOLUME = LEON ? 12 : 9;
|
||||
const int MAX_VOLUME = LEON ? 15 : 12;
|
||||
assert(s->sound.init(MIN_VOLUME));
|
||||
|
||||
set_volume(MIN_VOLUME);
|
||||
s->volume_timeout = 5 * UI_FREQ;
|
||||
int draws = 0;
|
||||
|
||||
s->scene.satelliteCount = -1;
|
||||
|
@ -858,13 +851,7 @@ int main(int argc, char* argv[]) {
|
|||
should_swap = true;
|
||||
}
|
||||
|
||||
if (s->volume_timeout > 0) {
|
||||
s->volume_timeout--;
|
||||
} else {
|
||||
int volume = fmin(MAX_VOLUME, MIN_VOLUME + s->scene.controls_state.getVEgo() / 5); // up one notch every 5 m/s
|
||||
set_volume(volume);
|
||||
s->volume_timeout = 5 * UI_FREQ;
|
||||
}
|
||||
s->sound.setVolume(fmin(MAX_VOLUME, MIN_VOLUME + s->scene.controls_state.getVEgo() / 5), 5); // up one notch every 5 m/s
|
||||
|
||||
// If car is started and controlsState times out, display an alert
|
||||
if (s->controls_timeout > 0) {
|
||||
|
@ -877,25 +864,13 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
s->scene.alert_text1 = "TAKE CONTROL IMMEDIATELY";
|
||||
s->scene.alert_text2 = "Controls Unresponsive";
|
||||
|
||||
ui_draw_vision_alert(s, s->scene.alert_size, s->status, s->scene.alert_text1.c_str(), s->scene.alert_text2.c_str());
|
||||
|
||||
s->alert_sound_timeout = 2 * UI_FREQ;
|
||||
s->alert_sound = cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING_REPEAT;
|
||||
play_alert_sound(s->alert_sound);
|
||||
s->sound.play(AudibleAlert::CHIME_WARNING_REPEAT, 3); // loop sound 3 times
|
||||
}
|
||||
|
||||
s->alert_sound_timeout--;
|
||||
s->controls_seen = false;
|
||||
}
|
||||
|
||||
// stop playing alert sound
|
||||
if ((!s->started || (s->started && s->alert_sound_timeout == 0)) &&
|
||||
s->alert_sound != cereal::CarControl::HUDControl::AudibleAlert::NONE) {
|
||||
stop_alert_sound(s->alert_sound);
|
||||
s->alert_sound = cereal::CarControl::HUDControl::AudibleAlert::NONE;
|
||||
}
|
||||
|
||||
read_param_timeout(&s->is_metric, "IsMetric", &s->is_metric_timeout);
|
||||
read_param_timeout(&s->longitudinal_control, "LongitudinalControl", &s->longitudinal_control_timeout);
|
||||
read_param_timeout(&s->limit_set_speed, "LimitSetSpeed", &s->limit_set_speed_timeout);
|
||||
|
@ -928,7 +903,6 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
set_awake(s, true);
|
||||
ui_sound_destroy();
|
||||
|
||||
// wake up bg thread to exit
|
||||
pthread_mutex_lock(&s->lock);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifndef _UI_H
|
||||
#define _UI_H
|
||||
|
||||
#pragma once
|
||||
#include "messaging.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
@ -214,9 +212,7 @@ typedef struct UIState {
|
|||
|
||||
// timeouts
|
||||
int awake_timeout;
|
||||
int volume_timeout;
|
||||
int controls_timeout;
|
||||
int alert_sound_timeout;
|
||||
int speed_lim_off_timeout;
|
||||
int is_metric_timeout;
|
||||
int longitudinal_control_timeout;
|
||||
|
@ -234,8 +230,6 @@ typedef struct UIState {
|
|||
bool limit_set_speed;
|
||||
float speed_lim_off;
|
||||
bool is_ego_over_limit;
|
||||
std::string alert_type;
|
||||
AudibleAlert alert_sound;
|
||||
float alert_blinking_alpha;
|
||||
bool alert_blinked;
|
||||
bool started;
|
||||
|
@ -252,6 +246,8 @@ typedef struct UIState {
|
|||
model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2];
|
||||
|
||||
track_vertices_data track_vertices[2];
|
||||
|
||||
Sound sound;
|
||||
} UIState;
|
||||
|
||||
// API
|
||||
|
@ -263,5 +259,3 @@ void ui_draw_image(NVGcontext *vg, float x, float y, float w, float h, int image
|
|||
void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGcolor color, float r = 0, int width = 0);
|
||||
void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGpaint &paint, float r = 0);
|
||||
void ui_nvg_init(UIState *s);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue