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