forked from enlightenment/enlightenment
e mixer - add ability to monitor streams with vu meters too
it's generic infra where you can get a general waveform (44.1khz stereo floats per strea) for playback (sink inputs), output (sinks) and inputs (sources). the emix gui will put a vu meter (actually it's not a vbu meter - it's a peak sample measure over any frame period) with a progress bar there. very useful now. @feat
This commit is contained in:
parent
0564846adb
commit
9444e5d55d
|
@ -1248,7 +1248,7 @@ backend_shutdown(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
emix_event_callback_del(_events_cb);
|
emix_event_callback_del(_events_cb, NULL);
|
||||||
emix_shutdown();
|
emix_shutdown();
|
||||||
emix_config_shutdown();
|
emix_config_shutdown();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,123 @@ Eina_List *source_list = NULL, *sink_input_list = NULL, *sink_list = NULL, *card
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct _Mon_Data
|
||||||
|
{
|
||||||
|
Emix_Sink *sink;
|
||||||
|
Emix_Sink_Input *input;
|
||||||
|
Emix_Source *source;
|
||||||
|
Evas_Object *fr;
|
||||||
|
Evas_Object *vu;
|
||||||
|
Ecore_Animator *animator;
|
||||||
|
float samp_max;
|
||||||
|
int mon_skips;
|
||||||
|
int mon_update;
|
||||||
|
int mon_samps;
|
||||||
|
} Mon_Data;
|
||||||
|
|
||||||
|
static Eina_List *_monitor_data_list = NULL;
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_cb_emix_monitor_update(void *data)
|
||||||
|
{
|
||||||
|
Mon_Data *md = data;
|
||||||
|
|
||||||
|
if (md->mon_update == 0)
|
||||||
|
{
|
||||||
|
md->mon_skips++;
|
||||||
|
if (md->mon_skips > 5)
|
||||||
|
{
|
||||||
|
elm_progressbar_value_set(md->vu, 0.0);
|
||||||
|
md->animator = NULL;
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
elm_progressbar_value_set(md->vu, md->samp_max);
|
||||||
|
md->mon_update = 0;
|
||||||
|
md->samp_max = 0;
|
||||||
|
md->mon_skips = 0;
|
||||||
|
md->mon_samps = 0;
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cb_emix_sink_monitor_event(void *data, enum Emix_Event event, void *event_info)
|
||||||
|
{
|
||||||
|
Mon_Data *md = data;
|
||||||
|
Emix_Sink *sink = event_info;
|
||||||
|
|
||||||
|
if (sink != md->sink) return;
|
||||||
|
if (event == EMIX_SINK_MONITOR_EVENT)
|
||||||
|
{
|
||||||
|
unsigned int i, num = sink->mon_num * 2;
|
||||||
|
float samp, max = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
samp = fabs(sink->mon_buf[i]);
|
||||||
|
if (samp > max) max = samp;
|
||||||
|
}
|
||||||
|
md->mon_samps += num;
|
||||||
|
if (md->samp_max < max) md->samp_max = max;
|
||||||
|
md->mon_update++;
|
||||||
|
if (!md->animator)
|
||||||
|
md->animator = ecore_animator_add(_cb_emix_monitor_update, md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cb_emix_sink_input_monitor_event(void *data, enum Emix_Event event, void *event_info)
|
||||||
|
{
|
||||||
|
Mon_Data *md = data;
|
||||||
|
Emix_Sink_Input *input = event_info;
|
||||||
|
|
||||||
|
if (input != md->input) return;
|
||||||
|
if (event == EMIX_SINK_INPUT_MONITOR_EVENT)
|
||||||
|
{
|
||||||
|
unsigned int i, num = input->mon_num * 2;
|
||||||
|
float samp, max = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
samp = fabs(input->mon_buf[i]);
|
||||||
|
if (samp > max) max = samp;
|
||||||
|
}
|
||||||
|
md->mon_samps += num;
|
||||||
|
if (md->samp_max < max) md->samp_max = max;
|
||||||
|
md->mon_update++;
|
||||||
|
if (!md->animator)
|
||||||
|
md->animator = ecore_animator_add(_cb_emix_monitor_update, md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cb_emix_source_monitor_event(void *data, enum Emix_Event event, void *event_info)
|
||||||
|
{
|
||||||
|
Mon_Data *md = data;
|
||||||
|
Emix_Source *source = event_info;
|
||||||
|
|
||||||
|
if (source != md->source) return;
|
||||||
|
if (event == EMIX_SOURCE_MONITOR_EVENT)
|
||||||
|
{
|
||||||
|
unsigned int i, num = source->mon_num * 2;
|
||||||
|
float samp, max = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
samp = fabs(source->mon_buf[i]);
|
||||||
|
if (samp > max) max = samp;
|
||||||
|
}
|
||||||
|
md->mon_samps += num;
|
||||||
|
if (md->samp_max < max) md->samp_max = max;
|
||||||
|
md->mon_update++;
|
||||||
|
if (!md->animator)
|
||||||
|
md->animator = ecore_animator_add(_cb_emix_monitor_update, md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void _emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked);
|
static void _emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked);
|
||||||
static Evas_Object *_icon(Evas_Object *base, const char *name);
|
static Evas_Object *_icon(Evas_Object *base, const char *name);
|
||||||
|
|
||||||
|
@ -40,6 +157,12 @@ _backend_init(const char *back)
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
_cb_vu_format_cb(double v EINA_UNUSED)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_cb_sink_port_change(void *data,
|
_cb_sink_port_change(void *data,
|
||||||
Evas_Object *obj,
|
Evas_Object *obj,
|
||||||
|
@ -250,10 +373,11 @@ _emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *fr, Evas_Object *bx, Eina_B
|
||||||
static void
|
static void
|
||||||
_emix_sink_add(Emix_Sink *sink)
|
_emix_sink_add(Emix_Sink *sink)
|
||||||
{
|
{
|
||||||
Evas_Object *bxv, *bx, *lb, *hv, *fr, *sep;
|
Evas_Object *bxv, *bx, *lb, *hv, *fr, *sep, *vu;
|
||||||
const Eina_List *l;
|
const Eina_List *l;
|
||||||
Emix_Port *port;
|
Emix_Port *port;
|
||||||
Eina_Bool locked = EINA_TRUE;
|
Eina_Bool locked = EINA_TRUE;
|
||||||
|
Mon_Data *md;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
fr = elm_frame_add(win);
|
fr = elm_frame_add(win);
|
||||||
|
@ -323,6 +447,14 @@ _emix_sink_add(Emix_Sink *sink)
|
||||||
elm_box_pack_end(sink_box, fr);
|
elm_box_pack_end(sink_box, fr);
|
||||||
evas_object_show(fr);
|
evas_object_show(fr);
|
||||||
|
|
||||||
|
vu = elm_progressbar_add(win);
|
||||||
|
elm_progressbar_unit_format_function_set(vu, _cb_vu_format_cb, NULL);
|
||||||
|
evas_object_data_set(fr, "vu", vu);
|
||||||
|
evas_object_size_hint_weight_set(vu, EVAS_HINT_EXPAND, 0.0);
|
||||||
|
evas_object_size_hint_align_set(vu, EVAS_HINT_FILL, 0.0);
|
||||||
|
elm_box_pack_end(sink_box, vu);
|
||||||
|
evas_object_show(vu);
|
||||||
|
|
||||||
sep = elm_separator_add(win);
|
sep = elm_separator_add(win);
|
||||||
evas_object_data_set(fr, "extra", sep);
|
evas_object_data_set(fr, "extra", sep);
|
||||||
elm_separator_horizontal_set(sep, EINA_TRUE);
|
elm_separator_horizontal_set(sep, EINA_TRUE);
|
||||||
|
@ -330,19 +462,44 @@ _emix_sink_add(Emix_Sink *sink)
|
||||||
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0);
|
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0);
|
||||||
elm_box_pack_end(sink_box, sep);
|
elm_box_pack_end(sink_box, sep);
|
||||||
evas_object_show(sep);
|
evas_object_show(sep);
|
||||||
|
|
||||||
|
md = calloc(1, sizeof(Mon_Data));
|
||||||
|
if (md)
|
||||||
|
{
|
||||||
|
md->sink = sink;
|
||||||
|
md->fr = fr;
|
||||||
|
md->vu = vu;
|
||||||
|
emix_event_callback_add(_cb_emix_sink_monitor_event, md);
|
||||||
|
_monitor_data_list = eina_list_append(_monitor_data_list, md);
|
||||||
|
}
|
||||||
|
emix_sink_monitor(sink, EINA_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_emix_sink_del(Emix_Sink *sink)
|
_emix_sink_del(Emix_Sink *sink)
|
||||||
{
|
{
|
||||||
Eina_List *l;
|
Eina_List *l, *ll;
|
||||||
Evas_Object *fr;
|
Evas_Object *fr;
|
||||||
|
Mon_Data *md;
|
||||||
|
|
||||||
|
emix_sink_monitor(sink, EINA_FALSE);
|
||||||
|
EINA_LIST_FOREACH_SAFE(_monitor_data_list, l, ll, md)
|
||||||
|
{
|
||||||
|
if (md->sink == sink)
|
||||||
|
{
|
||||||
|
emix_event_callback_del(_cb_emix_sink_monitor_event, md);
|
||||||
|
_monitor_data_list = eina_list_remove_list(_monitor_data_list, l);
|
||||||
|
if (md->animator) ecore_animator_del(md->animator);
|
||||||
|
free(md);
|
||||||
|
}
|
||||||
|
}
|
||||||
EINA_LIST_FOREACH(sink_list, l, fr)
|
EINA_LIST_FOREACH(sink_list, l, fr)
|
||||||
{
|
{
|
||||||
if (evas_object_data_get(fr, "sink") == sink)
|
if (evas_object_data_get(fr, "sink") == sink)
|
||||||
{
|
{
|
||||||
sink_list = eina_list_remove_list(sink_list, l);
|
sink_list = eina_list_remove_list(sink_list, l);
|
||||||
evas_object_del(evas_object_data_get(fr, "extra"));
|
evas_object_del(evas_object_data_get(fr, "extra"));
|
||||||
|
evas_object_del(evas_object_data_get(fr, "vu"));
|
||||||
evas_object_del(fr);
|
evas_object_del(fr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -626,10 +783,11 @@ _emix_sink_input_volume_fill(Emix_Sink_Input *input, Evas_Object *fr, Evas_Objec
|
||||||
static void
|
static void
|
||||||
_emix_sink_input_add(Emix_Sink_Input *input)
|
_emix_sink_input_add(Emix_Sink_Input *input)
|
||||||
{
|
{
|
||||||
Evas_Object *bxv, *bx, *lb, *hv, *ic, *fr, *sep;
|
Evas_Object *bxv, *bx, *lb, *hv, *ic, *fr, *sep, *vu;
|
||||||
const Eina_List *l;
|
const Eina_List *l;
|
||||||
Emix_Sink *sink;
|
Emix_Sink *sink;
|
||||||
Eina_Bool locked = EINA_TRUE;
|
Eina_Bool locked = EINA_TRUE;
|
||||||
|
Mon_Data *md;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (!input->sink) return;
|
if (!input->sink) return;
|
||||||
|
@ -717,6 +875,14 @@ _emix_sink_input_add(Emix_Sink_Input *input)
|
||||||
elm_box_pack_end(sink_input_box, fr);
|
elm_box_pack_end(sink_input_box, fr);
|
||||||
evas_object_show(fr);
|
evas_object_show(fr);
|
||||||
|
|
||||||
|
vu = elm_progressbar_add(win);
|
||||||
|
elm_progressbar_unit_format_function_set(vu, _cb_vu_format_cb, NULL);
|
||||||
|
evas_object_data_set(fr, "vu", vu);
|
||||||
|
evas_object_size_hint_weight_set(vu, EVAS_HINT_EXPAND, 0.0);
|
||||||
|
evas_object_size_hint_align_set(vu, EVAS_HINT_FILL, 0.0);
|
||||||
|
elm_box_pack_end(sink_input_box, vu);
|
||||||
|
evas_object_show(vu);
|
||||||
|
|
||||||
sep = elm_separator_add(win);
|
sep = elm_separator_add(win);
|
||||||
evas_object_data_set(fr, "extra", sep);
|
evas_object_data_set(fr, "extra", sep);
|
||||||
elm_separator_horizontal_set(sep, EINA_TRUE);
|
elm_separator_horizontal_set(sep, EINA_TRUE);
|
||||||
|
@ -724,19 +890,44 @@ _emix_sink_input_add(Emix_Sink_Input *input)
|
||||||
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0);
|
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0);
|
||||||
elm_box_pack_end(sink_input_box, sep);
|
elm_box_pack_end(sink_input_box, sep);
|
||||||
evas_object_show(sep);
|
evas_object_show(sep);
|
||||||
|
|
||||||
|
md = calloc(1, sizeof(Mon_Data));
|
||||||
|
if (md)
|
||||||
|
{
|
||||||
|
md->input = input;
|
||||||
|
md->fr = fr;
|
||||||
|
md->vu = vu;
|
||||||
|
emix_event_callback_add(_cb_emix_sink_input_monitor_event, md);
|
||||||
|
_monitor_data_list = eina_list_append(_monitor_data_list, md);
|
||||||
|
}
|
||||||
|
emix_sink_input_monitor(input, EINA_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_emix_sink_input_del(Emix_Sink_Input *input)
|
_emix_sink_input_del(Emix_Sink_Input *input)
|
||||||
{
|
{
|
||||||
Eina_List *l;
|
Eina_List *l, *ll;
|
||||||
Evas_Object *fr;
|
Evas_Object *fr;
|
||||||
|
Mon_Data *md;
|
||||||
|
|
||||||
|
emix_sink_input_monitor(input, EINA_FALSE);
|
||||||
|
EINA_LIST_FOREACH_SAFE(_monitor_data_list, l, ll, md)
|
||||||
|
{
|
||||||
|
if (md->input == input)
|
||||||
|
{
|
||||||
|
emix_event_callback_del(_cb_emix_sink_input_monitor_event, md);
|
||||||
|
_monitor_data_list = eina_list_remove_list(_monitor_data_list, l);
|
||||||
|
if (md->animator) ecore_animator_del(md->animator);
|
||||||
|
free(md);
|
||||||
|
}
|
||||||
|
}
|
||||||
EINA_LIST_FOREACH(sink_input_list, l, fr)
|
EINA_LIST_FOREACH(sink_input_list, l, fr)
|
||||||
{
|
{
|
||||||
if (evas_object_data_get(fr, "input") == input)
|
if (evas_object_data_get(fr, "input") == input)
|
||||||
{
|
{
|
||||||
sink_input_list = eina_list_remove_list(sink_input_list, l);
|
sink_input_list = eina_list_remove_list(sink_input_list, l);
|
||||||
evas_object_del(evas_object_data_get(fr, "extra"));
|
evas_object_del(evas_object_data_get(fr, "extra"));
|
||||||
|
evas_object_del(evas_object_data_get(fr, "vu"));
|
||||||
evas_object_del(fr);
|
evas_object_del(fr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1026,9 +1217,10 @@ _emix_source_volume_fill(Emix_Source *source, Evas_Object *fr, Evas_Object *bx,
|
||||||
static void
|
static void
|
||||||
_emix_source_add(Emix_Source *source)
|
_emix_source_add(Emix_Source *source)
|
||||||
{
|
{
|
||||||
Evas_Object *bxv, *bx, *fr, *lb, *sep;
|
Evas_Object *bxv, *bx, *fr, *lb, *sep, *vu;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
Eina_Bool locked = EINA_TRUE;
|
Eina_Bool locked = EINA_TRUE;
|
||||||
|
Mon_Data *md;
|
||||||
|
|
||||||
fr = elm_frame_add(win);
|
fr = elm_frame_add(win);
|
||||||
evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 1.0);
|
evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 1.0);
|
||||||
|
@ -1081,6 +1273,14 @@ _emix_source_add(Emix_Source *source)
|
||||||
elm_box_pack_end(source_box, fr);
|
elm_box_pack_end(source_box, fr);
|
||||||
evas_object_show(fr);
|
evas_object_show(fr);
|
||||||
|
|
||||||
|
vu = elm_progressbar_add(win);
|
||||||
|
elm_progressbar_unit_format_function_set(vu, _cb_vu_format_cb, NULL);
|
||||||
|
evas_object_data_set(fr, "vu", vu);
|
||||||
|
evas_object_size_hint_weight_set(vu, EVAS_HINT_EXPAND, 0.0);
|
||||||
|
evas_object_size_hint_align_set(vu, EVAS_HINT_FILL, 0.0);
|
||||||
|
elm_box_pack_end(source_box, vu);
|
||||||
|
evas_object_show(vu);
|
||||||
|
|
||||||
sep = elm_separator_add(win);
|
sep = elm_separator_add(win);
|
||||||
evas_object_data_set(fr, "extra", sep);
|
evas_object_data_set(fr, "extra", sep);
|
||||||
elm_separator_horizontal_set(sep, EINA_TRUE);
|
elm_separator_horizontal_set(sep, EINA_TRUE);
|
||||||
|
@ -1088,6 +1288,17 @@ _emix_source_add(Emix_Source *source)
|
||||||
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0);
|
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0);
|
||||||
elm_box_pack_end(source_box, sep);
|
elm_box_pack_end(source_box, sep);
|
||||||
evas_object_show(sep);
|
evas_object_show(sep);
|
||||||
|
|
||||||
|
md = calloc(1, sizeof(Mon_Data));
|
||||||
|
if (md)
|
||||||
|
{
|
||||||
|
md->source = source;
|
||||||
|
md->fr = fr;
|
||||||
|
md->vu = vu;
|
||||||
|
emix_event_callback_add(_cb_emix_source_monitor_event, md);
|
||||||
|
_monitor_data_list = eina_list_append(_monitor_data_list, md);
|
||||||
|
}
|
||||||
|
emix_source_monitor(source, EINA_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1101,6 +1312,7 @@ _emix_source_del(Emix_Source *source)
|
||||||
{
|
{
|
||||||
source_list = eina_list_remove_list(source_list, l);
|
source_list = eina_list_remove_list(source_list, l);
|
||||||
evas_object_del(evas_object_data_get(fr, "extra"));
|
evas_object_del(evas_object_data_get(fr, "extra"));
|
||||||
|
evas_object_del(evas_object_data_get(fr, "vu"));
|
||||||
evas_object_del(fr);
|
evas_object_del(fr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1322,6 +1534,12 @@ _cb_emix_event(void *data EINA_UNUSED, enum Emix_Event event, void *event_info)
|
||||||
case EMIX_CARD_CHANGED_EVENT:
|
case EMIX_CARD_CHANGED_EVENT:
|
||||||
_emix_card_change(event_info);
|
_emix_card_change(event_info);
|
||||||
break;
|
break;
|
||||||
|
case EMIX_SINK_MONITOR_EVENT:
|
||||||
|
break;
|
||||||
|
case EMIX_SINK_INPUT_MONITOR_EVENT:
|
||||||
|
break;
|
||||||
|
case EMIX_SOURCE_MONITOR_EVENT:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -537,7 +537,10 @@ _alsa_backend =
|
||||||
_alsa_sources_volume_set, /* source volume set */
|
_alsa_sources_volume_set, /* source volume set */
|
||||||
NULL, /* advanced options */
|
NULL, /* advanced options */
|
||||||
NULL, /* card list */
|
NULL, /* card list */
|
||||||
NULL /* card profile set */
|
NULL, /* card profile set */
|
||||||
|
NULL, /* sink monitor set */
|
||||||
|
NULL, /* sink input monitor set */
|
||||||
|
NULL /* ssource monitor set */
|
||||||
};
|
};
|
||||||
|
|
||||||
E_API Emix_Backend *
|
E_API Emix_Backend *
|
||||||
|
|
|
@ -33,14 +33,21 @@ typedef struct _Context
|
||||||
typedef struct _Sink
|
typedef struct _Sink
|
||||||
{
|
{
|
||||||
Emix_Sink base;
|
Emix_Sink base;
|
||||||
int idx;
|
int idx, monitor_idx;
|
||||||
const char *pulse_name;
|
const char *pulse_name;
|
||||||
|
const char *monitor_source_name;
|
||||||
|
int mon_count;
|
||||||
|
pa_stream *mon_stream;
|
||||||
|
Eina_Bool running : 1;
|
||||||
} Sink;
|
} Sink;
|
||||||
|
|
||||||
typedef struct _Sink_Input
|
typedef struct _Sink_Input
|
||||||
{
|
{
|
||||||
Emix_Sink_Input base;
|
Emix_Sink_Input base;
|
||||||
int idx;
|
int idx, sink_idx;
|
||||||
|
int mon_count;
|
||||||
|
pa_stream *mon_stream;
|
||||||
|
Eina_Bool running : 1;
|
||||||
} Sink_Input;
|
} Sink_Input;
|
||||||
|
|
||||||
typedef struct _Source
|
typedef struct _Source
|
||||||
|
@ -48,6 +55,8 @@ typedef struct _Source
|
||||||
Emix_Source base;
|
Emix_Source base;
|
||||||
int idx;
|
int idx;
|
||||||
const char *pulse_name;
|
const char *pulse_name;
|
||||||
|
int mon_count;
|
||||||
|
pa_stream *mon_stream;
|
||||||
} Source;
|
} Source;
|
||||||
|
|
||||||
typedef struct _Profile
|
typedef struct _Profile
|
||||||
|
@ -65,6 +74,13 @@ typedef struct _Card
|
||||||
static Context *ctx = NULL;
|
static Context *ctx = NULL;
|
||||||
extern pa_mainloop_api functable;
|
extern pa_mainloop_api functable;
|
||||||
|
|
||||||
|
static void _sink_monitor_begin(Sink *sink);
|
||||||
|
static void _sink_monitor_end(Sink *sink);
|
||||||
|
static void _sink_input_monitor_begin(Sink_Input *i);
|
||||||
|
static void _sink_input_monitor_end(Sink_Input *i);
|
||||||
|
static void _source_monitor_begin(Source *s);
|
||||||
|
static void _source_monitor_end(Source *s);
|
||||||
|
|
||||||
static pa_cvolume
|
static pa_cvolume
|
||||||
_emix_volume_convert(const Emix_Volume *volume)
|
_emix_volume_convert(const Emix_Volume *volume)
|
||||||
{
|
{
|
||||||
|
@ -116,6 +132,8 @@ _sink_del(Sink *sink)
|
||||||
free(sink->base.volume.channel_names);
|
free(sink->base.volume.channel_names);
|
||||||
eina_stringshare_del(sink->base.name);
|
eina_stringshare_del(sink->base.name);
|
||||||
eina_stringshare_del(sink->pulse_name);
|
eina_stringshare_del(sink->pulse_name);
|
||||||
|
eina_stringshare_del(sink->monitor_source_name);
|
||||||
|
if (sink->mon_stream) pa_stream_disconnect(sink->mon_stream);
|
||||||
free(sink);
|
free(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +149,7 @@ _sink_input_del(Sink_Input *input)
|
||||||
free(input->base.volume.channel_names);
|
free(input->base.volume.channel_names);
|
||||||
eina_stringshare_del(input->base.name);
|
eina_stringshare_del(input->base.name);
|
||||||
eina_stringshare_del(input->base.icon);
|
eina_stringshare_del(input->base.icon);
|
||||||
|
if (input->mon_stream) pa_stream_disconnect(input->mon_stream);
|
||||||
free(input);
|
free(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +184,30 @@ _card_del(Card *card)
|
||||||
free(card);
|
free(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_state_running_set(Sink *sink, Eina_Bool running)
|
||||||
|
{
|
||||||
|
if (running)
|
||||||
|
{
|
||||||
|
if ((!sink->running) && (sink->mon_count > 0))
|
||||||
|
{
|
||||||
|
sink->running = running;
|
||||||
|
_sink_monitor_begin(sink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((sink->running) && (sink->mon_count > 0))
|
||||||
|
{
|
||||||
|
sink->running = running;
|
||||||
|
_sink_monitor_end(sink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sink->running = running;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
_sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
||||||
void *userdata EINA_UNUSED)
|
void *userdata EINA_UNUSED)
|
||||||
|
@ -190,6 +233,7 @@ _sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
||||||
|
|
||||||
sink = calloc(1, sizeof(Sink));
|
sink = calloc(1, sizeof(Sink));
|
||||||
sink->idx = info->index;
|
sink->idx = info->index;
|
||||||
|
sink->monitor_idx = info->monitor_source;
|
||||||
sink->pulse_name = eina_stringshare_add(info->name);
|
sink->pulse_name = eina_stringshare_add(info->name);
|
||||||
sink->base.name = eina_stringshare_add(info->description);
|
sink->base.name = eina_stringshare_add(info->description);
|
||||||
_pa_cvolume_convert(&info->volume, &sink->base.volume);
|
_pa_cvolume_convert(&info->volume, &sink->base.volume);
|
||||||
|
@ -197,6 +241,7 @@ _sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
||||||
for (i = 0; i < sink->base.volume.channel_count; ++i)
|
for (i = 0; i < sink->base.volume.channel_count; ++i)
|
||||||
sink->base.volume.channel_names[i] = eina_stringshare_add(pa_channel_position_to_pretty_string(info->channel_map.map[i]));
|
sink->base.volume.channel_names[i] = eina_stringshare_add(pa_channel_position_to_pretty_string(info->channel_map.map[i]));
|
||||||
sink->base.mute = !!info->mute;
|
sink->base.mute = !!info->mute;
|
||||||
|
sink->monitor_source_name = eina_stringshare_add(info->monitor_source_name);
|
||||||
|
|
||||||
for (i = 0; i < info->n_ports; i++)
|
for (i = 0; i < info->n_ports; i++)
|
||||||
{
|
{
|
||||||
|
@ -214,7 +259,8 @@ _sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
||||||
if (info->ports[i]->name == info->active_port->name)
|
if (info->ports[i]->name == info->active_port->name)
|
||||||
port->active = EINA_TRUE;
|
port->active = EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
if (info->state == PA_SINK_RUNNING) _sink_state_running_set(sink, EINA_TRUE);
|
||||||
|
else _sink_state_running_set(sink, EINA_FALSE);
|
||||||
ctx->sinks = eina_list_append(ctx->sinks, sink);
|
ctx->sinks = eina_list_append(ctx->sinks, sink);
|
||||||
if (ctx->cb)
|
if (ctx->cb)
|
||||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_ADDED_EVENT,
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_ADDED_EVENT,
|
||||||
|
@ -297,6 +343,11 @@ _sink_changed_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
||||||
port->active = EINA_TRUE;
|
port->active = EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sink->monitor_idx = info->monitor_source;
|
||||||
|
|
||||||
|
if (info->state == PA_SINK_RUNNING) _sink_state_running_set(sink, EINA_TRUE);
|
||||||
|
else _sink_state_running_set(sink, EINA_FALSE);
|
||||||
|
|
||||||
if (ctx->cb)
|
if (ctx->cb)
|
||||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_CHANGED_EVENT,
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_CHANGED_EVENT,
|
||||||
(Emix_Sink *)sink);
|
(Emix_Sink *)sink);
|
||||||
|
@ -357,6 +408,30 @@ _icon_from_properties(pa_proplist *l)
|
||||||
return "audio-card";
|
return "audio-card";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_state_running_set(Sink_Input *input, Eina_Bool running)
|
||||||
|
{
|
||||||
|
if (running)
|
||||||
|
{
|
||||||
|
if ((!input->running) && (input->mon_count > 0))
|
||||||
|
{
|
||||||
|
input->running = running;
|
||||||
|
_sink_input_monitor_begin(input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((input->running) && (input->mon_count > 0))
|
||||||
|
{
|
||||||
|
input->running = running;
|
||||||
|
_sink_input_monitor_end(input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input->running = running;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
_sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
||||||
int eol, void *userdata EINA_UNUSED)
|
int eol, void *userdata EINA_UNUSED)
|
||||||
|
@ -387,6 +462,7 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
||||||
info->name);
|
info->name);
|
||||||
|
|
||||||
input->idx = info->index;
|
input->idx = info->index;
|
||||||
|
input->sink_idx = info->sink;
|
||||||
|
|
||||||
Eina_Strbuf *input_name;
|
Eina_Strbuf *input_name;
|
||||||
|
|
||||||
|
@ -421,6 +497,8 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
||||||
{
|
{
|
||||||
input->base.pid = atoi(t);
|
input->base.pid = atoi(t);
|
||||||
}
|
}
|
||||||
|
if (!info->corked) _sink_input_state_running_set(input, EINA_TRUE);
|
||||||
|
else _sink_input_state_running_set(input, EINA_FALSE);
|
||||||
|
|
||||||
if (ctx->cb)
|
if (ctx->cb)
|
||||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_ADDED_EVENT,
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_ADDED_EVENT,
|
||||||
|
@ -469,6 +547,7 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
|
||||||
ctx->inputs = eina_list_append(ctx->inputs, input);
|
ctx->inputs = eina_list_append(ctx->inputs, input);
|
||||||
}
|
}
|
||||||
input->idx = info->index;
|
input->idx = info->index;
|
||||||
|
input->sink_idx = info->sink;
|
||||||
if (input->base.volume.channel_count != info->volume.channels)
|
if (input->base.volume.channel_count != info->volume.channels)
|
||||||
{
|
{
|
||||||
for (i = 0; i < input->base.volume.channel_count; ++i)
|
for (i = 0; i < input->base.volume.channel_count; ++i)
|
||||||
|
@ -493,6 +572,9 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
|
||||||
input->base.pid = atoi(t);
|
input->base.pid = atoi(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!info->corked) _sink_input_state_running_set(input, EINA_TRUE);
|
||||||
|
else _sink_input_state_running_set(input, EINA_FALSE);
|
||||||
|
|
||||||
if (ctx->cb)
|
if (ctx->cb)
|
||||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_CHANGED_EVENT,
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_CHANGED_EVENT,
|
||||||
(Emix_Sink_Input *)input);
|
(Emix_Sink_Input *)input);
|
||||||
|
@ -529,6 +611,7 @@ _source_cb(pa_context *c EINA_UNUSED, const pa_source_info *info,
|
||||||
{
|
{
|
||||||
Source *source;
|
Source *source;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
size_t len;
|
||||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||||
|
|
||||||
if (eol < 0)
|
if (eol < 0)
|
||||||
|
@ -543,6 +626,13 @@ _source_cb(pa_context *c EINA_UNUSED, const pa_source_info *info,
|
||||||
if (eol > 0)
|
if (eol > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
len = strlen(info->name);
|
||||||
|
if (len > 8)
|
||||||
|
{
|
||||||
|
const char *s = info->name + len - 8;
|
||||||
|
if (!strcmp(s, ".monitor")) return;
|
||||||
|
}
|
||||||
|
|
||||||
source = calloc(1, sizeof(Source));
|
source = calloc(1, sizeof(Source));
|
||||||
EINA_SAFETY_ON_NULL_RETURN(source);
|
EINA_SAFETY_ON_NULL_RETURN(source);
|
||||||
|
|
||||||
|
@ -1522,6 +1612,241 @@ _card_profile_set(Emix_Card *card, const Emix_Profile *profile)
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_mon_read(pa_stream *stream, size_t bytes EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Sink *s = data;
|
||||||
|
size_t rbytes;
|
||||||
|
const void *buf = NULL;
|
||||||
|
|
||||||
|
if (pa_stream_peek(stream, &buf, &rbytes) == 0)
|
||||||
|
{
|
||||||
|
if ((!buf) && (rbytes))
|
||||||
|
{
|
||||||
|
pa_stream_drop(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->base.mon_num = (unsigned int)((rbytes / sizeof(float)) / 2);
|
||||||
|
s->base.mon_buf = buf;
|
||||||
|
if (ctx->cb)
|
||||||
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_MONITOR_EVENT, s);
|
||||||
|
pa_stream_drop(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_monitor_begin(Sink *s)
|
||||||
|
{
|
||||||
|
pa_sample_spec samp;
|
||||||
|
pa_buffer_attr attr;
|
||||||
|
|
||||||
|
if (pa_context_get_server_protocol_version(ctx->context) < 13) return;
|
||||||
|
|
||||||
|
pa_sample_spec_init(&samp);
|
||||||
|
samp.format = PA_SAMPLE_FLOAT32;
|
||||||
|
samp.rate = 44100;
|
||||||
|
samp.channels = 2;
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
attr.fragsize = sizeof(float) * 4096;
|
||||||
|
attr.maxlength = (uint32_t) -1;
|
||||||
|
|
||||||
|
s->mon_stream = pa_stream_new(ctx->context, "__e_mon", &samp, NULL);
|
||||||
|
pa_stream_set_read_callback(s->mon_stream, _sink_mon_read, s);
|
||||||
|
pa_stream_connect_record(s->mon_stream, s->monitor_source_name,
|
||||||
|
&attr,
|
||||||
|
PA_STREAM_NOFLAGS
|
||||||
|
| PA_STREAM_DONT_MOVE
|
||||||
|
| PA_STREAM_ADJUST_LATENCY
|
||||||
|
| PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_monitor_end(Sink *s)
|
||||||
|
{
|
||||||
|
if (s->mon_stream)
|
||||||
|
{
|
||||||
|
if (s->mon_stream) pa_stream_disconnect(s->mon_stream);
|
||||||
|
s->mon_stream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_monitor_set(Emix_Sink *sink, Eina_Bool monitor)
|
||||||
|
{
|
||||||
|
Sink *s = (Sink *)sink;
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||||
|
if (monitor) s->mon_count++;
|
||||||
|
else s->mon_count--;
|
||||||
|
if (s->mon_count < 0) s->mon_count = 0;
|
||||||
|
if (s->mon_count == 1)
|
||||||
|
{
|
||||||
|
if (s->running) _sink_monitor_begin(s);
|
||||||
|
}
|
||||||
|
else if (s->mon_count == 0) _sink_monitor_end(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_mon_read(pa_stream *stream, size_t bytes EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Sink_Input *i = data;
|
||||||
|
size_t rbytes;
|
||||||
|
const void *buf = NULL;
|
||||||
|
|
||||||
|
if (pa_stream_peek(stream, &buf, &rbytes) == 0)
|
||||||
|
{
|
||||||
|
if ((!buf) && (rbytes))
|
||||||
|
{
|
||||||
|
pa_stream_drop(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i->base.mon_num = (unsigned int)((rbytes / sizeof(float)) / 2);
|
||||||
|
i->base.mon_buf = buf;
|
||||||
|
if (ctx->cb)
|
||||||
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_MONITOR_EVENT, i);
|
||||||
|
pa_stream_drop(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_monitor_begin(Sink_Input *i)
|
||||||
|
{
|
||||||
|
pa_sample_spec samp;
|
||||||
|
pa_buffer_attr attr;
|
||||||
|
char buf[16];
|
||||||
|
Eina_List *l;
|
||||||
|
Sink *s;
|
||||||
|
unsigned int mon_idx = 0;
|
||||||
|
|
||||||
|
if (pa_context_get_server_protocol_version(ctx->context) < 13) return;
|
||||||
|
|
||||||
|
pa_sample_spec_init(&samp);
|
||||||
|
samp.format = PA_SAMPLE_FLOAT32;
|
||||||
|
samp.rate = 44100;
|
||||||
|
samp.channels = 2;
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
attr.fragsize = sizeof(float) * 4096;
|
||||||
|
attr.maxlength = (uint32_t) -1;
|
||||||
|
|
||||||
|
i->mon_stream = pa_stream_new(ctx->context, "__e_mon", &samp, NULL);
|
||||||
|
pa_stream_set_monitor_stream(i->mon_stream, i->idx);
|
||||||
|
pa_stream_set_read_callback(i->mon_stream, _sink_input_mon_read, i);
|
||||||
|
EINA_LIST_FOREACH(ctx->sinks, l, s)
|
||||||
|
{
|
||||||
|
if (i->sink_idx == s->idx)
|
||||||
|
{
|
||||||
|
mon_idx = s->monitor_idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!l) return;
|
||||||
|
snprintf(buf, sizeof(buf), "%i", mon_idx);
|
||||||
|
pa_stream_connect_record(i->mon_stream, buf,
|
||||||
|
&attr,
|
||||||
|
PA_STREAM_NOFLAGS
|
||||||
|
| PA_STREAM_DONT_MOVE
|
||||||
|
| PA_STREAM_ADJUST_LATENCY
|
||||||
|
| PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_monitor_end(Sink_Input *i)
|
||||||
|
{
|
||||||
|
if (i->mon_stream)
|
||||||
|
{
|
||||||
|
if (i->mon_stream) pa_stream_disconnect(i->mon_stream);
|
||||||
|
i->mon_stream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_monitor_set(Emix_Sink_Input *input, Eina_Bool monitor)
|
||||||
|
{
|
||||||
|
Sink_Input *i = (Sink_Input *)input;
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||||
|
if (monitor) i->mon_count++;
|
||||||
|
else i->mon_count--;
|
||||||
|
if (i->mon_count < 0) i->mon_count = 0;
|
||||||
|
if (i->mon_count == 1)
|
||||||
|
{
|
||||||
|
if (i->running) _sink_input_monitor_begin(i);
|
||||||
|
}
|
||||||
|
else if (i->mon_count == 0) _sink_input_monitor_end(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_source_mon_read(pa_stream *stream, size_t bytes EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Source *s = data;
|
||||||
|
size_t rbytes;
|
||||||
|
const void *buf = NULL;
|
||||||
|
|
||||||
|
if (pa_stream_peek(stream, &buf, &rbytes) == 0)
|
||||||
|
{
|
||||||
|
if ((!buf) && (rbytes))
|
||||||
|
{
|
||||||
|
pa_stream_drop(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->base.mon_num = (unsigned int)((rbytes / sizeof(float)) / 2);
|
||||||
|
s->base.mon_buf = buf;
|
||||||
|
if (ctx->cb)
|
||||||
|
ctx->cb((void *)ctx->userdata, EMIX_SOURCE_MONITOR_EVENT, s);
|
||||||
|
pa_stream_drop(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_source_monitor_begin(Source *s)
|
||||||
|
{
|
||||||
|
pa_sample_spec samp;
|
||||||
|
pa_buffer_attr attr;
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
if (pa_context_get_server_protocol_version(ctx->context) < 13) return;
|
||||||
|
|
||||||
|
pa_sample_spec_init(&samp);
|
||||||
|
samp.format = PA_SAMPLE_FLOAT32;
|
||||||
|
samp.rate = 44100;
|
||||||
|
samp.channels = 2;
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
attr.fragsize = sizeof(float) * 4096;
|
||||||
|
attr.maxlength = (uint32_t) -1;
|
||||||
|
|
||||||
|
s->mon_stream = pa_stream_new(ctx->context, "__e_mon", &samp, NULL);
|
||||||
|
pa_stream_set_read_callback(s->mon_stream, _source_mon_read, s);
|
||||||
|
snprintf(buf, sizeof(buf), "%i", s->idx);
|
||||||
|
pa_stream_connect_record(s->mon_stream, buf,
|
||||||
|
&attr,
|
||||||
|
PA_STREAM_NOFLAGS
|
||||||
|
| PA_STREAM_DONT_MOVE
|
||||||
|
| PA_STREAM_ADJUST_LATENCY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_source_monitor_end(Source *s)
|
||||||
|
{
|
||||||
|
if (s->mon_stream)
|
||||||
|
{
|
||||||
|
if (s->mon_stream) pa_stream_disconnect(s->mon_stream);
|
||||||
|
s->mon_stream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_source_monitor_set(Emix_Source *source, Eina_Bool monitor)
|
||||||
|
{
|
||||||
|
Source *s = (Source *)source;
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||||
|
if (monitor) s->mon_count++;
|
||||||
|
else s->mon_count--;
|
||||||
|
if (s->mon_count < 0) s->mon_count = 0;
|
||||||
|
if (s->mon_count == 1) _source_monitor_begin(s);
|
||||||
|
else if (s->mon_count == 0) _source_monitor_end(s);
|
||||||
|
}
|
||||||
|
|
||||||
static Emix_Backend
|
static Emix_Backend
|
||||||
_pulseaudio_backend =
|
_pulseaudio_backend =
|
||||||
{
|
{
|
||||||
|
@ -1548,7 +1873,10 @@ _pulseaudio_backend =
|
||||||
_source_volume_set,
|
_source_volume_set,
|
||||||
NULL,
|
NULL,
|
||||||
_cards_get,
|
_cards_get,
|
||||||
_card_profile_set
|
_card_profile_set,
|
||||||
|
_sink_monitor_set,
|
||||||
|
_sink_input_monitor_set,
|
||||||
|
_source_monitor_set
|
||||||
};
|
};
|
||||||
|
|
||||||
E_API Emix_Backend *
|
E_API Emix_Backend *
|
||||||
|
|
|
@ -419,7 +419,7 @@ emix_event_callback_add(Emix_Event_Cb cb, const void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
Eina_Bool
|
Eina_Bool
|
||||||
emix_event_callback_del(Emix_Event_Cb cb)
|
emix_event_callback_del(Emix_Event_Cb cb, const void *data)
|
||||||
{
|
{
|
||||||
struct Callback_Data *callback;
|
struct Callback_Data *callback;
|
||||||
Eina_List *l;
|
Eina_List *l;
|
||||||
|
@ -427,7 +427,7 @@ emix_event_callback_del(Emix_Event_Cb cb)
|
||||||
|
|
||||||
EINA_LIST_FOREACH(ctx->callbacks, l, callback)
|
EINA_LIST_FOREACH(ctx->callbacks, l, callback)
|
||||||
{
|
{
|
||||||
if (callback->cb == cb)
|
if ((callback->cb == cb) && (callback->data == data))
|
||||||
{
|
{
|
||||||
ctx->callbacks = eina_list_remove_list(ctx->callbacks, l);
|
ctx->callbacks = eina_list_remove_list(ctx->callbacks, l);
|
||||||
free(callback);
|
free(callback);
|
||||||
|
@ -456,3 +456,37 @@ emix_card_profile_set(Emix_Card *card, Emix_Profile *profile)
|
||||||
|
|
||||||
return ctx->loaded->ebackend_card_profile_set(card, profile);
|
return ctx->loaded->ebackend_card_profile_set(card, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
emix_sink_monitor(Emix_Sink *sink, Eina_Bool monitor)
|
||||||
|
{
|
||||||
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
||||||
|
ctx->loaded->ebackend_sink_mute_set &&
|
||||||
|
sink));
|
||||||
|
if (!ctx->loaded->ebackend_sink_monitor_set) return;
|
||||||
|
ctx->loaded->ebackend_sink_monitor_set(sink, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
emix_sink_input_monitor(Emix_Sink_Input *input, Eina_Bool monitor)
|
||||||
|
{
|
||||||
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
||||||
|
ctx->loaded->ebackend_sink_mute_set &&
|
||||||
|
input));
|
||||||
|
|
||||||
|
if (!ctx->loaded->ebackend_sink_input_monitor_set) return;
|
||||||
|
ctx->loaded->ebackend_sink_input_monitor_set(input, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
emix_source_monitor(Emix_Source *source, Eina_Bool monitor)
|
||||||
|
{
|
||||||
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
||||||
|
ctx->loaded->ebackend_sink_mute_set &&
|
||||||
|
source));
|
||||||
|
|
||||||
|
if (!ctx->loaded->ebackend_source_monitor_set) return;
|
||||||
|
ctx->loaded->ebackend_source_monitor_set(source, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,10 @@ enum Emix_Event {
|
||||||
EMIX_SOURCE_CHANGED_EVENT,
|
EMIX_SOURCE_CHANGED_EVENT,
|
||||||
EMIX_CARD_ADDED_EVENT,
|
EMIX_CARD_ADDED_EVENT,
|
||||||
EMIX_CARD_REMOVED_EVENT,
|
EMIX_CARD_REMOVED_EVENT,
|
||||||
EMIX_CARD_CHANGED_EVENT
|
EMIX_CARD_CHANGED_EVENT,
|
||||||
|
EMIX_SINK_MONITOR_EVENT,
|
||||||
|
EMIX_SINK_INPUT_MONITOR_EVENT,
|
||||||
|
EMIX_SOURCE_MONITOR_EVENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef const char * Emix_Channel;
|
typedef const char * Emix_Channel;
|
||||||
|
@ -64,6 +67,8 @@ typedef struct _Emix_Sink {
|
||||||
Eina_Bool mute;
|
Eina_Bool mute;
|
||||||
Eina_Bool default_sink;
|
Eina_Bool default_sink;
|
||||||
Eina_List *ports;
|
Eina_List *ports;
|
||||||
|
unsigned int mon_num; // number of left + right sample pairs
|
||||||
|
const float *mon_buf; // LRLRLR unsigned char samples
|
||||||
} Emix_Sink;
|
} Emix_Sink;
|
||||||
|
|
||||||
typedef struct _Emix_Sink_Input {
|
typedef struct _Emix_Sink_Input {
|
||||||
|
@ -73,6 +78,8 @@ typedef struct _Emix_Sink_Input {
|
||||||
Emix_Sink *sink;
|
Emix_Sink *sink;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
const char *icon;
|
const char *icon;
|
||||||
|
unsigned int mon_num; // number of left + right sample pairs
|
||||||
|
const float *mon_buf; // LRLRLR unsigned char samples
|
||||||
} Emix_Sink_Input;
|
} Emix_Sink_Input;
|
||||||
|
|
||||||
typedef struct _Emix_Source {
|
typedef struct _Emix_Source {
|
||||||
|
@ -80,6 +87,8 @@ typedef struct _Emix_Source {
|
||||||
Emix_Volume volume;
|
Emix_Volume volume;
|
||||||
Eina_Bool mute;
|
Eina_Bool mute;
|
||||||
Eina_Bool default_source;
|
Eina_Bool default_source;
|
||||||
|
unsigned int mon_num; // number of left + right sample pairs
|
||||||
|
const float *mon_buf; // LRLRLR unsigned char samples
|
||||||
} Emix_Source;
|
} Emix_Source;
|
||||||
|
|
||||||
typedef struct _Emix_Profile {
|
typedef struct _Emix_Profile {
|
||||||
|
@ -135,6 +144,13 @@ typedef struct _Emix_Backend {
|
||||||
Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent);
|
Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent);
|
||||||
const Eina_List* (*ebackend_cards_get)(void);
|
const Eina_List* (*ebackend_cards_get)(void);
|
||||||
Eina_Bool (*ebackend_card_profile_set)(Emix_Card *card, const Emix_Profile *profile);
|
Eina_Bool (*ebackend_card_profile_set)(Emix_Card *card, const Emix_Profile *profile);
|
||||||
|
|
||||||
|
void (*ebackend_sink_monitor_set)(Emix_Sink *sink,
|
||||||
|
Eina_Bool monitor);
|
||||||
|
void (*ebackend_sink_input_monitor_set)(Emix_Sink_Input *input,
|
||||||
|
Eina_Bool monitor);
|
||||||
|
void (*ebackend_source_monitor_set)(Emix_Source *source,
|
||||||
|
Eina_Bool monitor);
|
||||||
} Emix_Backend;
|
} Emix_Backend;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -161,7 +177,8 @@ E_API Eina_Bool emix_backend_set(const char *backend);
|
||||||
|
|
||||||
E_API Eina_Bool emix_event_callback_add(Emix_Event_Cb cb,
|
E_API Eina_Bool emix_event_callback_add(Emix_Event_Cb cb,
|
||||||
const void *data);
|
const void *data);
|
||||||
E_API Eina_Bool emix_event_callback_del(Emix_Event_Cb cb);
|
E_API Eina_Bool emix_event_callback_del(Emix_Event_Cb cb,
|
||||||
|
const void *data);
|
||||||
|
|
||||||
E_API int emix_max_volume_get(void);
|
E_API int emix_max_volume_get(void);
|
||||||
|
|
||||||
|
@ -196,4 +213,8 @@ E_API Evas_Object* emix_advanced_options_add(Evas_Object *parent);
|
||||||
E_API const Eina_List* emix_cards_get(void);
|
E_API const Eina_List* emix_cards_get(void);
|
||||||
E_API Eina_Bool emix_card_profile_set(Emix_Card *card, Emix_Profile *profile);
|
E_API Eina_Bool emix_card_profile_set(Emix_Card *card, Emix_Profile *profile);
|
||||||
|
|
||||||
|
E_API void emix_sink_monitor(Emix_Sink *sink, Eina_Bool monitor);
|
||||||
|
E_API void emix_sink_input_monitor(Emix_Sink_Input *input, Eina_Bool monitor);
|
||||||
|
E_API void emix_source_monitor(Emix_Source *source, Eina_Bool monitor);
|
||||||
|
|
||||||
#endif /* EMIX_H */
|
#endif /* EMIX_H */
|
||||||
|
|
Loading…
Reference in New Issue