1 #include "edje_private.h"
3 typedef struct _Multisense_Data
5 Edje_Multisense_Env *msenv;
9 RemixLayer *snd_layer, *player_layer;
11 RemixBase *player_snd;
14 Eina_List *snd_src_list;
16 MULTISENSE_SOUND_PLAYER_GET_FUNC multisense_sound_player_get;
21 #define SND_PROCESS_LENGTH 2048
22 #define TIMEOUT_FOR_MM_HANDLER 10
24 #ifdef ENABLE_MULTISENSE
25 static Ecore_Thread *player_thread = NULL;
26 static int command_pipe[2];
27 static Eina_Bool pipe_initialized = EINA_FALSE;
28 static Ecore_Timer *idletimer = NULL;
29 static Eina_Condition eina_player_cond;
30 static Eina_Lock eina_player_mutex;
33 typedef enum _Edje_Sound_Action_Type
44 } Edje_Sound_Action_Type;
46 typedef struct _Edje_Sample_Action Edje_Sample_Action;
47 typedef struct _Edje_Tone_Action Edje_Tone_Action;
48 typedef struct _Edje_Multisense_Sound_Action Edje_Multisense_Sound_Action;
50 struct _Edje_Sample_Action
52 char sample_name[BUF_LEN];
56 struct _Edje_Tone_Action
58 char tone_name[BUF_LEN];
62 struct _Edje_Multisense_Sound_Action
65 Edje_Sound_Action_Type action;
67 Edje_Sample_Action sample;
68 Edje_Tone_Action tone;
72 #ifdef ENABLE_MULTISENSE
73 static Eina_Module *m = NULL;
74 static Eina_Bool _edje_multisense_Timer_Callback(void *data);
77 edje_multisense_create_timer(void)
79 ecore_thread_main_loop_begin();
80 if (idletimer) ecore_timer_del(idletimer);
81 idletimer = ecore_timer_add(TIMEOUT_FOR_MM_HANDLER,
82 _edje_multisense_Timer_Callback, NULL);
84 ecore_thread_main_loop_end();
89 edje_multisense_kill_timer(void)
91 ecore_thread_main_loop_begin();
92 if (idletimer) ecore_timer_del(idletimer);
94 ecore_thread_main_loop_end();
99 _edje_multisense_Timer_Callback(void *data)
101 #if defined(ENABLE_MULTISENSE) && defined(HAVE_LIBREMIX)
103 Edje_Multisense_Sound_Action command = {0,};
105 if ((!pipe_initialized) && (!player_thread)) return ECORE_CALLBACK_CANCEL;
107 //post a command to handle mm sound cleanup
108 command.action = EDJE_CLOSE_HANDLE;
109 size = write(command_pipe[1], &command, sizeof(command));
112 return ECORE_CALLBACK_CANCEL;
115 static Multisense_Data *
116 init_multisense_environment(void)
118 Multisense_Data *msdata;
119 char ms_factory[BUF_LEN];
120 char *ms_factory_env;
121 MULTISENSE_FACTORY_INIT_FUNC multisense_factory_init;
123 msdata = calloc(1, sizeof(Multisense_Data));
124 if (!msdata) goto err;
126 msdata->msenv = calloc(1, sizeof(Edje_Multisense_Env));
127 if (!msdata->msenv) goto err;
129 ms_factory_env = getenv("MULTISENSE_FACTORY");
131 strncpy(ms_factory, ms_factory_env, BUF_LEN);
133 strcpy(ms_factory, "multisense_factory");
135 m = _edje_module_handle_load(ms_factory);
138 msdata->msenv->remixenv = remix_init();
140 multisense_factory_init =
141 eina_module_symbol_get(m, "multisense_factory_init");
142 if (multisense_factory_init) multisense_factory_init(msdata->msenv);
144 msdata->multisense_sound_player_get =
145 eina_module_symbol_get(m, "multisense_sound_player_get");
146 if (!msdata->multisense_sound_player_get) goto err;
148 msdata->deck = remix_deck_new(msdata->msenv->remixenv);
149 msdata->track = remix_track_new(msdata->msenv->remixenv, msdata->deck);
150 msdata->snd_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
153 msdata->player_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
156 msdata->player = msdata->multisense_sound_player_get(msdata->msenv);
157 if (!msdata->player) goto err;
158 msdata->player_snd = remix_sound_new(msdata->msenv->remixenv,
159 msdata->player, msdata->player_layer,
161 REMIX_SAMPLES(REMIX_COUNT_INFINITE));
169 if (msdata->deck) remix_destroy(msdata->msenv->remixenv, msdata->deck);
170 if (msdata->msenv->remixenv) remix_purge(msdata->msenv->remixenv);
172 if (msdata->msenv) free(msdata->msenv);
179 #if defined(ENABLE_MULTISENSE) && defined(HAVE_LIBREMIX)
181 eet_sound_reader_get(Edje_Multisense_Env *msenv, const char *path,
182 const char *sound_id, const double speed)
184 RemixPlugin *sf_plugin = NULL;
185 RemixBase * eet_snd_reader = NULL;
187 int sf_sound_id_key = 0;
188 int sf_speed_key = 0;
189 CDSet *sf_parms = NULL;
190 RemixEnv *env = msenv->remixenv;
192 if (sf_plugin == NULL)
194 sf_plugin = remix_find_plugin(env, "eet_sndfile_reader");
195 if (sf_plugin == NULL)
197 ERR ("Multisense EET Sound reader plugin NULL\n");
201 sf_path_key = remix_get_init_parameter_key(env, sf_plugin, "path");
202 sf_sound_id_key = remix_get_init_parameter_key(env, sf_plugin, "sound_id");
203 sf_speed_key = remix_get_init_parameter_key(env, sf_plugin, "speed");
205 sf_parms = cd_set_replace(env, sf_parms, sf_path_key, CD_STRING(path));
206 sf_parms = cd_set_replace(env, sf_parms, sf_sound_id_key, CD_STRING(sound_id));
207 sf_parms = cd_set_replace(env, sf_parms, sf_speed_key, CD_DOUBLE(speed));
208 eet_snd_reader = remix_new(env, sf_plugin, sf_parms);
210 //free the sf_parms as it is no more needed.
211 cd_set_free(env, sf_parms);
213 return eet_snd_reader;
217 edje_remix_sample_create(Multisense_Data *msdata, Edje_File *file, Edje_Sample_Action *action)
219 RemixBase *remix_snd = NULL;
220 Edje_Sound_Sample *sample;
224 if ((!file) || (!file->sound_dir))
227 for (i = 0; i < (int)file->sound_dir->samples_count; i++)
229 sample = &file->sound_dir->samples[i];
230 if (sample && !strcmp(sample->name, action->sample_name))
232 snprintf(snd_id_str, sizeof(snd_id_str), "edje/sounds/%i", sample->id);
233 remix_snd = eet_sound_reader_get(msdata->msenv, file->path,
234 snd_id_str, action->speed);
242 edje_remix_tone_create(Multisense_Data *msdata, Edje_File *file, Edje_Tone_Action *action)
244 Edje_Sound_Tone *tone;
245 RemixSquareTone *square = NULL;
248 if ((!file) || (!file->sound_dir))
251 for (i = 0; i < file->sound_dir->tones_count; i++)
253 tone = &file->sound_dir->tones[i];
254 if (tone && !strcmp(tone->name, action->tone_name))
256 square = remix_squaretone_new (msdata->msenv->remixenv, tone->value);
264 sound_command_handler(Multisense_Data *msdata)
267 Edje_Multisense_Sound_Action command = {0,};
268 RemixBase *base = NULL;
270 int read_len = sizeof(command);
272 //read and handle all samples to avoid queue effect
273 while(read(command_pipe[0], &command, sizeof(command)) == read_len)
275 switch (command.action)
277 case EDJE_PLAY_SAMPLE:
278 base = edje_remix_sample_create(msdata, command.snd_file,
279 &command.type.sample);
280 length = remix_length(msdata->msenv->remixenv, base);
281 edje_multisense_create_timer();
284 base = edje_remix_tone_create(msdata, command.snd_file, &command.type.tone);
285 length = (command.type.tone.duration *
286 remix_get_samplerate(msdata->msenv->remixenv));
288 case EDJE_CLOSE_HANDLE:
289 remix_reset(msdata->msenv->remixenv, msdata->player);
292 case EDJE_SOUND_LAST:
295 ERR("Invalid Sound Play Command\n");
300 sound = remix_sound_new(msdata->msenv->remixenv, base, msdata->snd_layer,
301 REMIX_SAMPLES(msdata->offset),
302 REMIX_SAMPLES(length));
303 if (msdata->remaining < length) msdata->remaining = length;
304 msdata->snd_src_list = eina_list_append(msdata->snd_src_list, sound);
305 msdata->snd_src_list = eina_list_append(msdata->snd_src_list, base);
312 #ifdef ENABLE_MULTISENSE
313 // msdata outside of thread due to thread issues in dlsym etc.
314 static Multisense_Data *msdata = NULL;
319 // cleanup msdata outside of thread due to thread issues in dlsym etc.
323 //cleanup Remix stuffs
324 remix_destroy(msdata->msenv->remixenv, msdata->player);
325 remix_destroy(msdata->msenv->remixenv, msdata->deck);
326 remix_purge(msdata->msenv->remixenv);
334 _player_job(void *data __UNUSED__, Ecore_Thread *th)
339 RemixCount process_len;
341 // disable and move outside of thread due to dlsym etc. thread issues
342 // Multisense_Data * msdata = init_multisense_environment();
346 fcntl(command_pipe[0], F_SETFL, O_NONBLOCK);
348 FD_SET(command_pipe[0], &wait_fds);
350 while (!ecore_thread_check(th))
353 if (!msdata->remaining)
356 //Cleanup already played sound sources
357 EINA_LIST_FREE(msdata->snd_src_list, sound)
359 remix_destroy(msdata->msenv->remixenv, sound);
362 err = select(command_pipe[0] + 1, &wait_fds, NULL, NULL, 0);
364 //read sound command , if any
365 if (!sound_command_handler(msdata)) break;
366 process_len = MIN(msdata->remaining, SND_PROCESS_LENGTH);
367 remix_process(msdata->msenv->remixenv, msdata->deck, process_len,
368 RemixNone, RemixNone);
369 msdata->offset += process_len;
370 msdata->remaining -= process_len;
375 //Cleanup last played sound sources
376 EINA_LIST_FREE(msdata->snd_src_list, sound)
378 remix_destroy(msdata->msenv->remixenv, sound);
382 player_thread = NULL;
383 close(command_pipe[0]);
384 close(command_pipe[1]);
386 /* Lock mutex and signal the main thread to resume shutdown */
387 eina_lock_take(&eina_player_mutex);
388 eina_condition_signal(&eina_player_cond);
389 eina_lock_release(&eina_player_mutex);
394 _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed)
397 #if defined(ENABLE_MULTISENSE) && defined(HAVE_LIBREMIX)
398 Edje_Multisense_Sound_Action command = {0,};
400 if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
403 ERR("Given Sample Name is NULL\n");
407 command.action = EDJE_PLAY_SAMPLE;
408 command.snd_file = ed->file;
409 strncpy(command.type.sample.sample_name, sample_name, BUF_LEN);
410 command.type.sample.speed = speed;
411 size = write(command_pipe[1], &command, sizeof(command));
418 return (size == sizeof(Edje_Multisense_Sound_Action));
422 _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration)
425 #if defined(ENABLE_MULTISENSE) && defined(HAVE_LIBREMIX)
426 Edje_Multisense_Sound_Action command = {0,};
428 if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
431 ERR("Given Tone Name is NULL\n");
435 command.action = EDJE_PLAY_TONE;
436 command.snd_file = ed->file;
437 strncpy(command.type.tone.tone_name, tone_name, BUF_LEN);
438 command.type.tone.duration = duration;
439 size = write(command_pipe[1], &command, sizeof(command));
446 return (size == sizeof(Edje_Multisense_Sound_Action));
450 /* Initialize the modules in main thread. to avoid dlopen issue in the Threads */
452 _edje_multisense_init(void)
454 #ifdef ENABLE_MULTISENSE
455 if (!pipe_initialized && (pipe(command_pipe) != -1))
456 pipe_initialized = EINA_TRUE;
457 multisense_init = EINA_TRUE;
459 // init msdata outside of thread due to thread issues in dlsym etc.
460 if (!msdata) msdata = init_multisense_environment();
462 // Initialize the synchronisation elements with main thread.
463 eina_lock_new(&eina_player_mutex);
464 eina_condition_new(&eina_player_cond, &eina_player_mutex);
467 player_thread = ecore_thread_feedback_run(_player_job, NULL, NULL, NULL,
473 _edje_multisense_shutdown(void)
475 #ifdef ENABLE_MULTISENSE
476 Edje_Multisense_Sound_Action command = {0,};
477 MULTISENSE_FACTORY_SHUTDOWN_FUNC multisense_factory_shutdown;
479 // lock the synchronisation mutex and hold it.
480 eina_lock_take(&eina_player_mutex);
482 if (m) multisense_factory_shutdown
483 = eina_module_symbol_get(m,"multisense_factory_shutdown");
484 if (multisense_factory_shutdown && msdata)
485 multisense_factory_shutdown(msdata->msenv);
486 /* Disable cancel call and exit thread function on recieving EDJE_SOUND_LAST
487 at other end of pipe */
488 //if (player_thread) ecore_thread_cancel(player_thread);
489 if (pipe_initialized)
491 //unblock the select() in player worker thread
492 command.action = EDJE_SOUND_LAST;
493 write(command_pipe[1], &command, sizeof(command));
496 // kill the timer if alive still.
497 edje_multisense_kill_timer();
499 // wait for edje multisense player to quit.
500 eina_condition_wait(&eina_player_cond);
501 eina_lock_release(&eina_player_mutex);
503 // cleanup the synchronisation elements.
504 eina_condition_free(&eina_player_cond);
505 eina_lock_free(&eina_player_mutex);