efl/src/lib/edje/edje_multisense.c

423 lines
12 KiB
C

#include "edje_private.h"
typedef struct _Multisense_Data
{
Edje_Multisense_Env *msenv;
#ifdef HAVE_LIBREMIX
RemixDeck *deck;
RemixTrack *track;
RemixLayer *snd_layer, *player_layer;
RemixBase *player;
RemixBase *player_snd;
int remaining;
int offset;
Eina_List *snd_src_list;
MULTISENSE_SOUND_PLAYER_GET_FUNC multisense_sound_player_get;
#endif
}Multisense_Data;
#define BUF_LEN 64
#define SND_PROCESS_LENGTH 2048
#ifdef HAVE_LIBREMIX
static Ecore_Thread *player_thread = NULL;
static int command_pipe[2];
static Eina_Bool pipe_initialized = EINA_FALSE;
#endif
typedef enum _Edje_Sound_Action_Type
{
EDJE_PLAY_SAMPLE = 0,
EDJE_PLAY_TONE,
/*
EDJE_PLAY_PATTERN,
EDJE_PLAY_INSTRUMENT,
EDJE_PLAY_SONG,
*/
EDJE_SOUND_LAST
} Edje_Sound_Action_Type;
typedef struct _Edje_Sample_Action Edje_Sample_Action;
typedef struct _Edje_Tone_Action Edje_Tone_Action;
typedef struct _Edje_Multisense_Sound_Action Edje_Multisense_Sound_Action;
struct _Edje_Sample_Action
{
char sample_name[BUF_LEN];
double speed;
};
struct _Edje_Tone_Action
{
char tone_name[BUF_LEN];
double duration;
};
struct _Edje_Multisense_Sound_Action
{
Edje *ed;
Edje_Sound_Action_Type action;
union {
Edje_Sample_Action sample;
Edje_Tone_Action tone;
} type;
};
#ifdef HAVE_LIBREMIX
static Multisense_Data *
init_multisense_environment(void)
{
Multisense_Data *msdata;
char ms_factory[BUF_LEN];
char *ms_factory_env;
Eina_Module *m = NULL;
MULTISENSE_FACTORY_INIT_FUNC multisense_factory_init;
msdata = calloc(1, sizeof(Multisense_Data));
if (!msdata) goto err;
msdata->msenv = calloc(1, sizeof(Edje_Multisense_Env));
if (!msdata->msenv) goto err;
ms_factory_env = getenv("MULTISENSE_FACTORY");
if (ms_factory_env)
strncpy(ms_factory, ms_factory_env, BUF_LEN);
else
strcpy(ms_factory, "multisense_factory");
m = _edje_module_handle_load(ms_factory);
if (!m) goto err;
msdata->msenv->remixenv = remix_init();
multisense_factory_init =
eina_module_symbol_get(m, "multisense_factory_init");
if (multisense_factory_init) multisense_factory_init(msdata->msenv);
msdata->multisense_sound_player_get =
eina_module_symbol_get(m, "multisense_sound_player_get");
if (!msdata->multisense_sound_player_get) goto err;
msdata->deck = remix_deck_new(msdata->msenv->remixenv);
msdata->track = remix_track_new(msdata->msenv->remixenv, msdata->deck);
msdata->snd_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
msdata->track,
REMIX_TIME_SAMPLES);
msdata->player_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
msdata->track,
REMIX_TIME_SAMPLES);
msdata->player = msdata->multisense_sound_player_get(msdata->msenv);
if (!msdata->player) goto err;
msdata->player_snd = remix_sound_new(msdata->msenv->remixenv,
msdata->player, msdata->player_layer,
REMIX_SAMPLES(0),
REMIX_SAMPLES(REMIX_COUNT_INFINITE));
return msdata;
err:
if (msdata)
{
if (msdata->deck) remix_destroy(msdata->msenv->remixenv, msdata->deck);
if (msdata->msenv->remixenv) remix_purge(msdata->msenv->remixenv);
if (msdata->msenv) free(msdata->msenv);
free(msdata);
}
return NULL;
}
#endif
#ifdef HAVE_LIBREMIX
static RemixBase *
eet_sound_reader_get(Edje_Multisense_Env *msenv, const char *path, const char *sound_id, const double speed)
{
RemixPlugin *sf_plugin = NULL;
RemixBase * eet_snd_reader = NULL;
int sf_path_key = 0;
int sf_sound_id_key = 0;
int sf_speed_key = 0;
CDSet *sf_parms = NULL;
RemixEnv *env = msenv->remixenv;
if (sf_plugin == NULL)
{
sf_plugin = remix_find_plugin(env, "eet_sndfile_reader");
if (sf_plugin == NULL)
{
ERR ("Multisense EET Sound reader plugin NULL\n");
return NULL;
}
sf_path_key = remix_get_init_parameter_key(env, sf_plugin, "path");
sf_sound_id_key = remix_get_init_parameter_key(env, sf_plugin, "sound_id");
sf_speed_key = remix_get_init_parameter_key(env, sf_plugin, "speed");
}
sf_parms = cd_set_replace(env, sf_parms, sf_path_key, CD_STRING(path));
sf_parms = cd_set_replace(env, sf_parms, sf_sound_id_key, CD_STRING(sound_id));
sf_parms = cd_set_replace(env, sf_parms, sf_speed_key, CD_DOUBLE(speed));
eet_snd_reader = remix_new(env, sf_plugin, sf_parms);
return eet_snd_reader;
}
static RemixBase *
edje_remix_sample_create(Multisense_Data *msdata, Edje*ed, Edje_Sample_Action *action)
{
RemixBase *remix_snd = NULL;
Edje_Sound_Sample *sample;
int i;
char snd_id_str[16];
if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
return NULL;
for (i = 0; i < (int)ed->file->sound_dir->samples_count; i++)
{
sample = &ed->file->sound_dir->samples[i];
if (!strcmp(sample->name, action->sample_name))
{
snprintf(snd_id_str, sizeof(snd_id_str), "edje/sounds/%i", sample->id);
remix_snd = eet_sound_reader_get(msdata->msenv, ed->file->path,
snd_id_str, action->speed);
break;
}
}
return remix_snd;
}
static RemixBase *
edje_remix_tone_create(Multisense_Data *msdata, Edje*ed, Edje_Tone_Action *action)
{
Edje_Sound_Tone *tone;
RemixSquareTone *square = NULL;
unsigned int i;
if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
return NULL;
for (i = 0; i < ed->file->sound_dir->tones_count; i++)
{
tone = &ed->file->sound_dir->tones[i];
if (!strcmp(tone->name, action->tone_name))
{
square = remix_squaretone_new (msdata->msenv->remixenv, tone->value);
break;
}
}
return square;
}
static void
sound_command_handler(Multisense_Data *msdata)
{
RemixCount length;
Edje_Multisense_Sound_Action command;
RemixBase *base = NULL;
RemixBase *sound;
if (read(command_pipe[0], &command, sizeof(command)) <= 0) return;
switch (command.action)
{
case EDJE_PLAY_SAMPLE:
base = edje_remix_sample_create(msdata, command.ed,
&command.type.sample);
length = remix_length(msdata->msenv->remixenv, base);
break;
case EDJE_PLAY_TONE:
base = edje_remix_tone_create(msdata, command.ed, &command.type.tone);
length = (command.type.tone.duration *
remix_get_samplerate(msdata->msenv->remixenv));
break;
default:
ERR("Invalid Sound Play Command\n");
break;
}
if (base)
{
sound = remix_sound_new(msdata->msenv->remixenv, base, msdata->snd_layer,
REMIX_SAMPLES(msdata->offset),
REMIX_SAMPLES(length));
if (msdata->remaining < length) msdata->remaining = length;
msdata->snd_src_list = eina_list_append(msdata->snd_src_list, sound);
msdata->snd_src_list = eina_list_append(msdata->snd_src_list, base);
}
}
#endif
#ifdef HAVE_LIBREMIX
// msdata outside of thread due to thread issues in dlsym etc.
static Multisense_Data *msdata = NULL;
static void
_msdata_free(void)
{
// cleanup msdata outside of thread due to thread issues in dlsym etc.
if (!msdata) return;
//cleanup Remix stuffs
remix_destroy(msdata->msenv->remixenv, msdata->player);
remix_destroy(msdata->msenv->remixenv, msdata->deck);
remix_purge(msdata->msenv->remixenv);
free(msdata->msenv);
free(msdata);
msdata = NULL;
}
static void
_player_job(void *data EINA_UNUSED, Ecore_Thread *th)
{
fd_set wait_fds;
RemixBase *sound;
RemixCount process_len;
// disable and move outside of thread due to dlsym etc. thread issues
// Multisense_Data * msdata = init_multisense_environment();
if (!msdata) return;
fcntl(command_pipe[0], F_SETFL, O_NONBLOCK);
FD_ZERO(&wait_fds);
FD_SET(command_pipe[0], &wait_fds);
while (!ecore_thread_check(th))
{
if (!msdata->remaining)
{
int err;
//Cleanup already played sound sources
EINA_LIST_FREE(msdata->snd_src_list, sound)
{
remix_destroy(msdata->msenv->remixenv, sound);
}
//wait for new sound
err = select(command_pipe[0] + 1, &wait_fds, NULL, NULL, 0);
if (ecore_thread_check(th))
break;
}
//read sound command , if any
sound_command_handler(msdata);
process_len = MIN(msdata->remaining, SND_PROCESS_LENGTH);
remix_process(msdata->msenv->remixenv, msdata->deck, process_len,
RemixNone, RemixNone);
msdata->offset += process_len;
msdata->remaining -= process_len;
}
//Cleanup last played sound sources
EINA_LIST_FREE(msdata->snd_src_list, sound)
{
remix_destroy(msdata->msenv->remixenv, sound);
}
}
#endif
#ifdef HAVE_LIBREMIX
static void
_player_cancel(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
// cleanup msdata outside of thread due to thread issues in dlsym etc.
_msdata_free();
player_thread = NULL;
}
#endif
#ifdef HAVE_LIBREMIX
static void
_player_end(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
// cleanup msdata outside of thread due to thread issues in dlsym etc.
_msdata_free();
player_thread = NULL;
}
#endif
Eina_Bool
_edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed)
{
ssize_t size = 0;
#ifdef ENABLE_MULTISENSE
Edje_Multisense_Sound_Action command;
if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
if (!sample_name)
{
ERR("Given Sample Name is NULL\n");
return EINA_FALSE;
}
command.action = EDJE_PLAY_SAMPLE;
command.ed = ed;
strncpy(command.type.sample.sample_name, sample_name, BUF_LEN);
command.type.sample.speed = speed;
size = write(command_pipe[1], &command, sizeof(command));
#else
// warning shh
(void) ed;
(void) sample_name;
(void) speed;
#endif
return (size == sizeof(Edje_Multisense_Sound_Action));
}
Eina_Bool
_edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration)
{
ssize_t size = 0;
#ifdef ENABLE_MULTISENSE
Edje_Multisense_Sound_Action command;
if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
if (!tone_name)
{
ERR("Given Tone Name is NULL\n");
return EINA_FALSE;
}
command.action = EDJE_PLAY_TONE;
command.ed = ed;
strncpy(command.type.tone.tone_name, tone_name, BUF_LEN);
command.type.tone.duration = duration;
size = write(command_pipe[1], &command, sizeof(command));
#else
// warning shh
(void) ed;
(void) duration;
(void) tone_name;
#endif
return (size == sizeof(Edje_Multisense_Sound_Action));
}
/* Initialize the modules in main thread. to avoid dlopen issue in the Threads */
void
_edje_multisense_init(void)
{
#ifdef ENABLE_MULTISENSE
if (!pipe_initialized && (pipe(command_pipe) != -1))
pipe_initialized = EINA_TRUE;
// init msdata outside of thread due to thread issues in dlsym etc.
if (!msdata) msdata = init_multisense_environment();
if (!player_thread)
player_thread = ecore_thread_feedback_run(_player_job, NULL, _player_end, _player_cancel, NULL, EINA_TRUE);
#endif
}
void
_edje_multisense_shutdown(void)
{
#ifdef ENABLE_MULTISENSE
if (player_thread) ecore_thread_cancel(player_thread);
if (pipe_initialized)
{
int i = 42;
write(command_pipe[1], &i, sizeof (int));
close(command_pipe[1]);
close(command_pipe[0]);
}
#endif
}