From 12981b168e9fc094cc47bdd8c5eebfc5bbdc4001 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Tue, 27 Aug 2013 23:42:24 +0900 Subject: [PATCH] ecore-audio - expose ready and fail events so multisense can avoid leaks well well well. i WASN'T crazy. there WAS a leak. it was ecore-audio+multisense. if a pulse audio output doesn't connect... NO ONE KNOWS. all audio streams keep being appended to it forever just consuming more memory indefinitely. there is no way to handle it. expose events so it CAN be handled. --- .../ecore_audio/ecore_audio_obj_out_pulse.c | 34 +++++++++++++++++-- .../ecore_audio/ecore_audio_obj_out_pulse.h | 22 ++++++++++++ src/lib/edje/edje_multisense.c | 33 ++++++++++++++---- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c index 5c413050b7..80f7fb0227 100644 --- a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c +++ b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c @@ -25,13 +25,19 @@ EAPI Eo_Op ECORE_AUDIO_OBJ_OUT_PULSE_BASE_ID = EO_NOOP; #define MY_CLASS ECORE_AUDIO_OBJ_OUT_PULSE_CLASS #define MY_CLASS_NAME "ecore_audio_obj_out_pulse" -const Eo_Event_Description _ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY; +EAPI const Eo_Event_Description _ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY = + EO_EVENT_DESCRIPTION("context,ready", "Called when the output is ready for playback."); #define ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY (&(_ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY)) +EAPI const Eo_Event_Description _ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL = + EO_EVENT_DESCRIPTION("context,fail", "Called when context fails."); +#define ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL (&(_ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL)) + struct _Ecore_Audio_Pulse_Class { pa_mainloop_api *api; pa_context *context; pa_context_state_t state; + Ecore_Job *state_job; Eina_List *outputs; }; @@ -213,17 +219,38 @@ static void _state_cb(pa_context *context, void *data EINA_UNUSED) pa_context_state_t state; state = pa_context_get_state(context); + class_vars.state = state; if (state == PA_CONTEXT_READY) { DBG("PA context ready."); EINA_LIST_FOREACH(class_vars.outputs, out, eo_obj) { eo_do(eo_obj, eo_event_callback_call(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY, NULL, NULL)); } + } else if ((state == PA_CONTEXT_FAILED) || (state == PA_CONTEXT_TERMINATED)) { + DBG("PA context fail."); + EINA_LIST_FOREACH(class_vars.outputs, out, eo_obj) { + eo_do(eo_obj, eo_event_callback_call(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL, NULL, NULL)); + } } else { DBG("Connection state %i", state); } - class_vars.state = state; +} + +static void _state_job(void *data EINA_UNUSED) +{ + if ((class_vars.state == PA_CONTEXT_FAILED) || + (class_vars.state == PA_CONTEXT_TERMINATED)) + { + Eo *eo_obj; + Eina_List *out; + + DBG("PA context fail."); + EINA_LIST_FOREACH(class_vars.outputs, out, eo_obj) { + eo_do(eo_obj, eo_event_callback_call(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL, NULL, NULL)); + } + } + class_vars.state_job = NULL; } static void _constructor(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) @@ -249,6 +276,8 @@ static void _constructor(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list EINA_U } class_vars.outputs = eina_list_append(class_vars.outputs, eo_obj); + if (class_vars.state_job) eo_del(class_vars.state_job); + class_vars.state_job = ecore_job_add(_state_job, NULL); } static void _destructor(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) @@ -281,6 +310,7 @@ static const Eo_Op_Description op_desc[] = { static const Eo_Event_Description *event_desc[] = { ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY, + ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL, NULL }; diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h index b12526cc3c..a0318316d1 100644 --- a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h +++ b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h @@ -52,6 +52,28 @@ enum _Ecore_Audio_Obj_Out_Pulse_Sub_Ids #define ECORE_AUDIO_OBJ_OUT_PULSE_ID(sub_id) (ECORE_AUDIO_OBJ_OUT_PULSE_BASE_ID + EO_TYPECHECK(enum _Ecore_Audio_Obj_Out_Pulse_Sub_Ids, sub_id)) +extern EAPI const Eo_Event_Description _ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY; + +/** + * @brief The output context is ready + * + * @since 1.8 + * + * Emitted when the outout context is ready for playback + */ +#define ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY (&(_ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY)) + +extern EAPI const Eo_Event_Description _ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL; + +/** + * @brief The output context has failed + * + * @since 1.8 + * + * Emitted when the outout context has failed. At this point the output is unusable and will never work, so it is advisable to delete it. + */ +#define ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL (&(_ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL)) + /** * @} */ diff --git a/src/lib/edje/edje_multisense.c b/src/lib/edje/edje_multisense.c index b321e75e25..daa878ea0c 100644 --- a/src/lib/edje/edje_multisense.c +++ b/src/lib/edje/edje_multisense.c @@ -6,6 +6,7 @@ static Eo *out = NULL; static int outs = 0; +static Eina_Bool outfail = EINA_FALSE; static Eina_Bool _play_finished(void *data EINA_UNUSED, Eo *in, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) { @@ -14,6 +15,14 @@ static Eina_Bool _play_finished(void *data EINA_UNUSED, Eo *in, const Eo_Event_D return EINA_TRUE; } +static Eina_Bool _out_fail(void *data EINA_UNUSED, Eo *output EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +{ + outfail = EINA_TRUE; + eo_del(out); + out = NULL; + return EINA_TRUE; +} + struct _edje_multisense_eet_data { sf_count_t offset, length; @@ -93,11 +102,13 @@ _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, c int i; Eina_Bool ret; - if (!sample_name) - { - ERR("Given Sample Name is NULL\n"); - return EINA_FALSE; - } + if (outfail) return EINA_FALSE; + + if (!sample_name) + { + ERR("Given Sample Name is NULL\n"); + return EINA_FALSE; + } if ((!ed) || (!ed->file) || (!ed->file->sound_dir)) return EINA_FALSE; @@ -153,7 +164,8 @@ _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, c eo_event_callback_add(ECORE_AUDIO_EV_IN_STOPPED, _play_finished, NULL)); if (!out) { - out = eo_add(ECORE_AUDIO_OBJ_OUT_PULSE_CLASS, NULL); + out = eo_add(ECORE_AUDIO_OBJ_OUT_PULSE_CLASS, NULL, + eo_event_callback_add(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL, _out_fail, NULL)); if (out) outs++; } if (!out) @@ -195,6 +207,9 @@ _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const ERR("Given Tone Name is NULL"); return EINA_FALSE; } + + if (outfail) return EINA_FALSE; + if ((!ed) || (!ed->file) || (!ed->file->sound_dir)) return EINA_FALSE; @@ -210,7 +225,11 @@ _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const eo_do(in, eo_event_callback_add(ECORE_AUDIO_EV_IN_STOPPED, _play_finished, NULL)); if (!out) - out = eo_add(ECORE_AUDIO_OBJ_OUT_PULSE_CLASS, NULL); + { + out = eo_add(ECORE_AUDIO_OBJ_OUT_PULSE_CLASS, NULL, + eo_event_callback_add(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_FAIL, _out_fail, NULL)); + if (out) outs++; + } eo_do(out, ecore_audio_obj_out_input_attach(in, &ret)); if (!ret) {