Imported Upstream version 1.7.1
[platform/upstream/edje.git] / src / lib / edje_multisense.c
1 #include "edje_private.h"
2
3 typedef struct _Multisense_Data
4 {
5    Edje_Multisense_Env *msenv;
6 #ifdef HAVE_LIBREMIX
7    RemixDeck *deck;
8    RemixTrack *track;
9    RemixLayer *snd_layer, *player_layer;
10    RemixBase *player;
11    RemixBase *player_snd;
12    int remaining;
13    int offset;
14    Eina_List *snd_src_list;
15
16    MULTISENSE_SOUND_PLAYER_GET_FUNC multisense_sound_player_get;
17 #endif
18 }Multisense_Data;
19
20 #define BUF_LEN 64
21 #define SND_PROCESS_LENGTH 2048
22
23 #ifdef HAVE_LIBREMIX
24 static Ecore_Thread *player_thread = NULL;
25 static int command_pipe[2];
26 static Eina_Bool pipe_initialized = EINA_FALSE;
27 #endif
28
29 typedef enum _Edje_Sound_Action_Type
30 {
31    EDJE_PLAY_SAMPLE = 0,
32    EDJE_PLAY_TONE,
33    /*
34    EDJE_PLAY_PATTERN,
35    EDJE_PLAY_INSTRUMENT,
36    EDJE_PLAY_SONG,
37    */
38    EDJE_SOUND_LAST
39 } Edje_Sound_Action_Type;
40
41 typedef struct _Edje_Sample_Action Edje_Sample_Action;
42 typedef struct _Edje_Tone_Action Edje_Tone_Action;
43 typedef struct _Edje_Multisense_Sound_Action Edje_Multisense_Sound_Action;
44
45 struct _Edje_Sample_Action
46 {
47    char sample_name[BUF_LEN];
48    double speed;
49 };
50
51 struct _Edje_Tone_Action
52 {
53    char tone_name[BUF_LEN];
54    double duration;
55 };
56
57 struct _Edje_Multisense_Sound_Action
58 {
59    Edje *ed;
60    Edje_Sound_Action_Type action;
61    union {
62       Edje_Sample_Action sample;
63       Edje_Tone_Action tone;
64    } type;
65 };
66
67 #ifdef HAVE_LIBREMIX
68 static Multisense_Data *
69 init_multisense_environment(void)
70 {
71    Multisense_Data *msdata;
72    char ms_factory[BUF_LEN];
73    char *ms_factory_env;
74    Eina_Module *m = NULL;
75    MULTISENSE_FACTORY_INIT_FUNC multisense_factory_init;
76
77    msdata = calloc(1, sizeof(Multisense_Data));
78    if (!msdata) goto err;
79
80    msdata->msenv = calloc(1, sizeof(Edje_Multisense_Env));
81    if (!msdata->msenv) goto err;
82
83    ms_factory_env = getenv("MULTISENSE_FACTORY");
84    if (ms_factory_env)
85      strncpy(ms_factory, ms_factory_env, BUF_LEN);
86    else
87      strcpy(ms_factory, "multisense_factory");
88
89    m = _edje_module_handle_load(ms_factory);
90    if (!m) goto err;
91
92    msdata->msenv->remixenv = remix_init();
93
94    multisense_factory_init =
95      eina_module_symbol_get(m, "multisense_factory_init");
96    if (multisense_factory_init) multisense_factory_init(msdata->msenv);
97
98    msdata->multisense_sound_player_get =
99      eina_module_symbol_get(m, "multisense_sound_player_get");
100    if (!msdata->multisense_sound_player_get) goto err;
101
102    msdata->deck = remix_deck_new(msdata->msenv->remixenv);
103    msdata->track = remix_track_new(msdata->msenv->remixenv, msdata->deck);
104    msdata->snd_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
105                                              msdata->track,
106                                              REMIX_TIME_SAMPLES);
107    msdata->player_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
108                                                 msdata->track,
109                                                 REMIX_TIME_SAMPLES);
110    msdata->player = msdata->multisense_sound_player_get(msdata->msenv);
111    if (!msdata->player) goto err;
112    msdata->player_snd = remix_sound_new(msdata->msenv->remixenv,
113                                         msdata->player, msdata->player_layer,
114                                         REMIX_SAMPLES(0),
115                                         REMIX_SAMPLES(REMIX_COUNT_INFINITE));
116    return msdata;
117
118 err:
119    if (msdata)
120      {
121         if (msdata->deck) remix_destroy(msdata->msenv->remixenv, msdata->deck);
122         if (msdata->msenv->remixenv) remix_purge(msdata->msenv->remixenv);
123         if (msdata->msenv) free(msdata->msenv);
124         free(msdata);
125      }
126    return NULL;
127 }
128 #endif
129
130 #ifdef HAVE_LIBREMIX
131 static RemixBase *
132 eet_sound_reader_get(Edje_Multisense_Env *msenv, const char *path, const char *sound_id, const double speed)
133 {
134    RemixPlugin *sf_plugin = NULL;
135    RemixBase * eet_snd_reader = NULL;
136    int sf_path_key = 0;
137    int sf_sound_id_key = 0;
138    int sf_speed_key = 0;
139    CDSet *sf_parms = NULL;
140    RemixEnv *env = msenv->remixenv;
141
142    if (sf_plugin == NULL)
143      {
144         sf_plugin = remix_find_plugin(env, "eet_sndfile_reader");
145         if (sf_plugin == NULL)
146           {
147              ERR ("Multisense EET Sound reader plugin NULL\n");
148              return NULL;
149           }
150
151         sf_path_key = remix_get_init_parameter_key(env, sf_plugin, "path");
152         sf_sound_id_key = remix_get_init_parameter_key(env, sf_plugin, "sound_id");
153         sf_speed_key = remix_get_init_parameter_key(env, sf_plugin, "speed");
154      }
155    sf_parms = cd_set_replace(env, sf_parms, sf_path_key, CD_STRING(path));
156    sf_parms = cd_set_replace(env, sf_parms, sf_sound_id_key, CD_STRING(sound_id));
157    sf_parms = cd_set_replace(env, sf_parms, sf_speed_key, CD_DOUBLE(speed));
158    eet_snd_reader = remix_new(env, sf_plugin, sf_parms);
159
160    return eet_snd_reader;
161 }
162
163
164 static RemixBase *
165 edje_remix_sample_create(Multisense_Data *msdata, Edje*ed, Edje_Sample_Action *action)
166 {
167    RemixBase *remix_snd = NULL;
168    Edje_Sound_Sample *sample;
169    int i;
170    char snd_id_str[16];
171
172    if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
173      return NULL;
174
175    for (i = 0; i < (int)ed->file->sound_dir->samples_count; i++)
176      {
177         sample = &ed->file->sound_dir->samples[i];
178         if (!strcmp(sample->name, action->sample_name))
179           {
180              snprintf(snd_id_str, sizeof(snd_id_str), "edje/sounds/%i", sample->id);
181              remix_snd = eet_sound_reader_get(msdata->msenv, ed->file->path,
182                                               snd_id_str, action->speed);
183              break;
184           }
185      }
186    return remix_snd;
187 }
188
189 static RemixBase *
190 edje_remix_tone_create(Multisense_Data *msdata, Edje*ed, Edje_Tone_Action *action)
191 {
192    Edje_Sound_Tone *tone;
193    RemixSquareTone *square = NULL;
194    unsigned int i;
195
196    if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
197      return NULL;
198
199    for (i = 0; i < ed->file->sound_dir->tones_count; i++)
200      {
201         tone = &ed->file->sound_dir->tones[i];
202         if (!strcmp(tone->name, action->tone_name))
203           {
204              square = remix_squaretone_new (msdata->msenv->remixenv, tone->value);
205              break;
206           }
207      }
208    return square;
209 }
210
211 static void
212 sound_command_handler(Multisense_Data *msdata)
213 {
214    RemixCount length;
215    Edje_Multisense_Sound_Action command;
216    RemixBase *base = NULL;
217    RemixBase *sound;
218
219    if (read(command_pipe[0], &command, sizeof(command)) <= 0) return;
220    switch (command.action)
221      {
222       case EDJE_PLAY_SAMPLE:
223         base = edje_remix_sample_create(msdata, command.ed,
224                                         &command.type.sample);
225         length = remix_length(msdata->msenv->remixenv, base);
226         break;
227       case EDJE_PLAY_TONE:
228         base = edje_remix_tone_create(msdata, command.ed, &command.type.tone);
229         length = (command.type.tone.duration *
230                               remix_get_samplerate(msdata->msenv->remixenv));
231         break;
232       default:
233         ERR("Invalid Sound Play Command\n");
234         break;
235      }
236    if (base)
237      {
238         sound = remix_sound_new(msdata->msenv->remixenv, base, msdata->snd_layer,
239                                 REMIX_SAMPLES(msdata->offset),
240                                 REMIX_SAMPLES(length));
241         if (msdata->remaining < length) msdata->remaining = length;
242         msdata->snd_src_list = eina_list_append(msdata->snd_src_list, sound);
243         msdata->snd_src_list = eina_list_append(msdata->snd_src_list, base);
244      }
245 }
246 #endif
247
248 #ifdef HAVE_LIBREMIX
249 // msdata outside of thread due to thread issues in dlsym etc.
250 static Multisense_Data *msdata = NULL;
251
252 static void
253 _msdata_free(void)
254 {
255    // cleanup msdata outside of thread due to thread issues in dlsym etc.
256    if (!msdata) return;
257    //cleanup Remix stuffs
258    remix_destroy(msdata->msenv->remixenv, msdata->player);
259    remix_destroy(msdata->msenv->remixenv, msdata->deck);
260    remix_purge(msdata->msenv->remixenv);
261
262    free(msdata->msenv);
263    free(msdata);
264    msdata = NULL;
265 }
266
267 static void
268 _player_job(void *data __UNUSED__, Ecore_Thread *th)
269 {
270    fd_set wait_fds;
271    RemixBase *sound;
272    RemixCount process_len;
273 // disable and move outside of thread due to dlsym etc. thread issues
274 //   Multisense_Data * msdata = init_multisense_environment();
275
276    if (!msdata) return;
277
278    fcntl(command_pipe[0], F_SETFL, O_NONBLOCK);
279    FD_ZERO(&wait_fds);
280    FD_SET(command_pipe[0], &wait_fds);
281
282    while (!ecore_thread_check(th))
283      {
284         if (!msdata->remaining)
285           {
286              int err;
287              
288              //Cleanup already played sound sources
289              EINA_LIST_FREE(msdata->snd_src_list, sound)
290                {
291                   remix_destroy(msdata->msenv->remixenv, sound);
292                }
293              //wait for new sound
294              err = select(command_pipe[0] + 1, &wait_fds, NULL, NULL, 0);
295              if (ecore_thread_check(th))
296                break;
297           }
298         //read sound command , if any
299         sound_command_handler(msdata);
300         process_len = MIN(msdata->remaining, SND_PROCESS_LENGTH);
301         remix_process(msdata->msenv->remixenv, msdata->deck, process_len,
302                       RemixNone, RemixNone);
303         msdata->offset += process_len;
304         msdata->remaining -= process_len;
305      }
306
307    //Cleanup last played sound sources
308    EINA_LIST_FREE(msdata->snd_src_list, sound)
309      {
310         remix_destroy(msdata->msenv->remixenv, sound);
311      }
312 }
313 #endif
314
315 #ifdef HAVE_LIBREMIX
316 static void
317 _player_cancel(void *data __UNUSED__, Ecore_Thread *th __UNUSED__)
318 {
319    // cleanup msdata outside of thread due to thread issues in dlsym etc.
320    _msdata_free();
321    player_thread = NULL;
322 }
323 #endif
324
325 #ifdef HAVE_LIBREMIX
326 static void
327 _player_end(void *data __UNUSED__, Ecore_Thread *th __UNUSED__)
328 {
329    // cleanup msdata outside of thread due to thread issues in dlsym etc.
330    _msdata_free();
331    player_thread = NULL;
332 }
333 #endif
334
335 Eina_Bool
336 _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed)
337 {
338    ssize_t size = 0;
339 #ifdef ENABLE_MULTISENSE
340    Edje_Multisense_Sound_Action command;
341
342    if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
343    if (!sample_name)
344      {
345         ERR("Given Sample Name is NULL\n");
346         return EINA_FALSE;
347      }
348
349    command.action = EDJE_PLAY_SAMPLE;
350    command.ed = ed;
351    strncpy(command.type.sample.sample_name, sample_name, BUF_LEN);
352    command.type.sample.speed = speed;
353    size = write(command_pipe[1], &command, sizeof(command));
354 #else
355    // warning shh
356    (void) ed;
357    (void) sample_name;
358    (void) speed;
359 #endif
360    return (size == sizeof(Edje_Multisense_Sound_Action));
361 }
362
363 Eina_Bool
364 _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration)
365 {
366    ssize_t size = 0;
367 #ifdef ENABLE_MULTISENSE
368    Edje_Multisense_Sound_Action command;
369
370    if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
371    if (!tone_name)
372      {
373         ERR("Given Tone Name is NULL\n");
374         return EINA_FALSE;
375      }
376
377    command.action = EDJE_PLAY_TONE;
378    command.ed = ed;
379    strncpy(command.type.tone.tone_name, tone_name, BUF_LEN);
380    command.type.tone.duration = duration;
381    size = write(command_pipe[1], &command, sizeof(command));
382 #else
383    // warning shh
384    (void) ed;
385    (void) duration;
386    (void) tone_name;
387 #endif
388    return (size == sizeof(Edje_Multisense_Sound_Action));
389
390 }
391
392 /* Initialize the modules in main thread. to avoid dlopen issue in the Threads */
393 void
394 _edje_multisense_init(void)
395 {
396 #ifdef ENABLE_MULTISENSE
397    if (!pipe_initialized && (pipe(command_pipe) != -1))
398      pipe_initialized = EINA_TRUE;
399
400    // init msdata outside of thread due to thread issues in dlsym etc.
401    if (!msdata) msdata = init_multisense_environment();
402
403    if (!player_thread)
404      player_thread = ecore_thread_feedback_run(_player_job, NULL, _player_end, _player_cancel, NULL, EINA_TRUE);
405 #endif
406 }
407
408 void
409 _edje_multisense_shutdown(void)
410 {
411 #ifdef ENABLE_MULTISENSE
412    if (player_thread) ecore_thread_cancel(player_thread);
413    if (pipe_initialized)
414      {
415         int i = 42;
416
417         write(command_pipe[1], &i, sizeof (int));
418         close(command_pipe[1]);
419         close(command_pipe[0]);
420      }
421 #endif
422 }