From 5aedf54042e3af234b4dd35d6ba0961ae5023739 Mon Sep 17 00:00:00 2001 From: "Michael Bouchaud (yoz)" Date: Tue, 21 May 2019 14:40:43 +0100 Subject: [PATCH] emixer: Add volume channels control on emixer Summary: This commit allow the user to control each volumes channels in emixer. A lock flag is introduced to manage volume as before. @feature Reviewers: zmike!, devilhorns, raster Subscribers: cedric Tags: #enlightenment-git Differential Revision: https://phab.enlightenment.org/D7639 --- src/modules/mixer/e_mod_config.c | 4 +- src/modules/mixer/emixer.c | 705 +++++++++++++++--- src/modules/mixer/gadget/backend.c | 4 +- src/modules/mixer/lib/backends/alsa/alsa.c | 24 +- .../mixer/lib/backends/pulseaudio/pulse.c | 79 +- src/modules/mixer/lib/emix.c | 6 +- src/modules/mixer/lib/emix.h | 25 +- 7 files changed, 702 insertions(+), 145 deletions(-) diff --git a/src/modules/mixer/e_mod_config.c b/src/modules/mixer/e_mod_config.c index 1dad09389..9f93e7972 100644 --- a/src/modules/mixer/e_mod_config.c +++ b/src/modules/mixer/e_mod_config.c @@ -347,7 +347,7 @@ emix_config_save_state_restore(void) v.channel_count = emsink->volume.channel_count; for (i = 0; i < v.channel_count; i++) v.volumes[i] = sink->volume; - emix_sink_volume_set(emsink, v); + emix_sink_volume_set(emsink, &v); free(v.volumes); } emix_sink_mute_set(emsink, sink->mute); @@ -373,7 +373,7 @@ emix_config_save_state_restore(void) v.channel_count = emsource->volume.channel_count; for (i = 0; i < v.channel_count; i++) v.volumes[i] = source->volume; - emix_source_volume_set(emsource, v); + emix_source_volume_set(emsource, &v); free(v.volumes); } emix_source_mute_set(emsource, source->mute); diff --git a/src/modules/mixer/emixer.c b/src/modules/mixer/emixer.c index 9b3644013..ae1719c25 100644 --- a/src/modules/mixer/emixer.c +++ b/src/modules/mixer/emixer.c @@ -9,6 +9,8 @@ Eina_List *source_list = NULL, *sink_input_list = NULL, *sink_list = NULL, *card ////////////////////////////////////////////////////////////////////////////// +static void _emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked); + static Eina_Bool _backend_init(const char *back) { @@ -48,6 +50,20 @@ _cb_sink_volume_change(void *data, elm_slider_value_set(obj, vol); } +static void +_cb_sink_volume_channel_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Sink *sink = evas_object_data_get(bxv, "sink"); + double vol = elm_slider_value_get(obj); + sink->volume.volumes[(uintptr_t)evas_object_data_get(obj, "channel")] = vol; + elm_slider_value_set(obj, vol); + emix_sink_volume_set(sink, &sink->volume); +} + + static void _cb_sink_mute_change(void *data, Evas_Object *obj, @@ -55,18 +71,147 @@ _cb_sink_mute_change(void *data, { Evas_Object *bxv = data; Emix_Sink *sink = evas_object_data_get(bxv, "sink"); - Evas_Object *sl = evas_object_data_get(bxv, "volume"); + Evas_Object *lock = evas_object_data_get(bxv, "lock"); Eina_Bool mute = elm_check_state_get(obj); - elm_object_disabled_set(sl, mute); + Eina_List *l; + Evas_Object *o; + + if (lock && !elm_check_state_get(lock)) + { + EINA_LIST_FOREACH(evas_object_data_get(bxv, "volumes"), l, o) + { + elm_object_disabled_set(o, mute); + o = evas_object_data_get(o, "lb"); + elm_object_disabled_set(o, mute); + } + } + else + { + o = evas_object_data_get(bxv, "volume"); + elm_object_disabled_set(o, mute); + } emix_sink_mute_set(sink, mute); } +static void +_cb_sink_lock_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Sink *sink = evas_object_data_get(bxv, "sink"); + Evas_Object *bx = evas_object_data_get(bxv, "volume_bx"); + Eina_Bool lock = elm_check_state_get(obj); + if (lock) + VOLSET(sink->volume.volumes[0], sink->volume, + sink, emix_sink_volume_set); + _emix_sink_volume_fill(sink, bxv, bx, lock); +} + +static void +_emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked) +{ + Evas_Object *bxhv, *sl, *ck, *lb; + Eina_List *sls = NULL; + unsigned int i; + + eina_list_free(evas_object_data_get(bxv, "volumes")); + elm_box_clear(bx); + + bxhv = elm_box_add(bx); + evas_object_size_hint_weight_set(bxhv, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(bxhv, EVAS_HINT_FILL, 0.5); + elm_box_pack_end(bx, bxhv); + evas_object_show(bxhv); + + if (locked) + { + sl = elm_slider_add(bx); + evas_object_data_set(bxv, "volume", sl); + elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); + elm_slider_span_size_set(sl, emix_max_volume_get() * elm_config_scale_get()); + elm_slider_unit_format_set(sl, "%1.0f"); + elm_slider_indicator_format_set(sl, "%1.0f"); + evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_slider_value_set(sl, sink->volume.volumes[0]); + elm_box_pack_end(bxhv, sl); + evas_object_show(sl); + evas_object_smart_callback_add(sl, "changed", _cb_sink_volume_change, bxv); + elm_object_disabled_set(sl, sink->mute); + } + else + { + for (i = 0; i < sink->volume.channel_count; ++i) + { + lb = elm_label_add(bx); + if (!sink->volume.channel_names) + { + char buf[1024]; + snprintf(buf, sizeof(buf), "Channel %d", i); + elm_object_text_set(lb, buf); + } + else + elm_object_text_set(lb, sink->volume.channel_names[i]); + evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.5); + evas_object_size_hint_align_set(lb, 0.0, 0.5); + elm_box_pack_end(bxhv, lb); + elm_object_disabled_set(lb, sink->mute); + evas_object_show(lb); + + sl = elm_slider_add(bx); + evas_object_data_set(sl, "lb", lb); + evas_object_data_set(sl, "channel", (uintptr_t *)(uintptr_t)i); + elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); + elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); + elm_slider_unit_format_set(sl, "%1.0f"); + elm_slider_indicator_format_set(sl, "%1.0f"); + evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_slider_value_set(sl, sink->volume.volumes[i]); + elm_box_pack_end(bxhv, sl); + evas_object_show(sl); + evas_object_smart_callback_add(sl, "changed", _cb_sink_volume_channel_change, bxv); + elm_object_disabled_set(sl, sink->mute); + sls = eina_list_append(sls, sl); + } + } + evas_object_data_set(bxv, "volumes", sls); + + bxhv = elm_box_add(bx); + elm_box_pack_end(bx, bxhv); + evas_object_show(bxhv); + + ck = elm_check_add(bx); + evas_object_data_set(bxv, "mute", ck); + elm_object_text_set(ck, "Mute"); + elm_check_state_set(ck, sink->mute); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", _cb_sink_mute_change, bxv); + + if (sink->volume.channel_count > 1) + { + ck = elm_check_add(bx); + elm_object_text_set(ck, "Lock"); + evas_object_data_set(bxv, "lock", ck); + elm_check_state_set(ck, locked); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", _cb_sink_lock_change, bxv); + } +} + + + static void _emix_sink_add(Emix_Sink *sink) { - Evas_Object *bxv, *bx, *lb, *ck, *sl, *hv, *sep; + Evas_Object *bxv, *bx, *lb, *hv, *sep; const Eina_List *l; Emix_Port *port; + Eina_Bool locked = EINA_TRUE; + unsigned int i; bxv = elm_box_add(win); sink_list = eina_list_append(sink_list, bxv); @@ -104,34 +249,27 @@ _emix_sink_add(Emix_Sink *sink) elm_box_pack_end(bx, hv); evas_object_show(hv); - bx = elm_box_add(win); + /* Compare each volume level and check if they differ. If they differ unlock + the volume control and let user set each channel volume level */ + for (i = 1; i < sink->volume.channel_count; ++i) + { + if (sink->volume.volumes[i - 1] != sink->volume.volumes[i]) + { + locked = EINA_FALSE; + break; + } + } + + bx = elm_box_add(bxv); + evas_object_data_set(bxv, "volume_bx", bx); elm_box_horizontal_set(bx, EINA_TRUE); evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); - evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.0); + evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.5); elm_box_pack_end(bxv, bx); evas_object_show(bx); - sl = elm_slider_add(win); - evas_object_data_set(bxv, "volume", sl); - elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); - elm_slider_span_size_set(sl, emix_max_volume_get() * elm_config_scale_get()); - elm_slider_unit_format_set(sl, "%1.0f"); - elm_slider_indicator_format_set(sl, "%1.0f"); - evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.5); - evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5); - elm_slider_value_set(sl, sink->volume.volumes[0]); - elm_box_pack_end(bx, sl); - evas_object_show(sl); - evas_object_smart_callback_add(sl, "changed", _cb_sink_volume_change, bxv); - ck = elm_check_add(win); - evas_object_data_set(bxv, "mute", ck); - elm_object_text_set(ck, "Mute"); - elm_check_state_set(ck, sink->mute); - elm_object_disabled_set(sl, sink->mute); - elm_box_pack_end(bx, ck); - evas_object_show(ck); - evas_object_smart_callback_add(ck, "changed", _cb_sink_mute_change, bxv); + _emix_sink_volume_fill(sink, bxv, bx, locked); sep = elm_separator_add(win); elm_separator_horizontal_set(sep, EINA_TRUE); @@ -164,7 +302,8 @@ static void _emix_sink_change(Emix_Sink *sink) { const Eina_List *l; - Evas_Object *bxv, *hv, *ck, *sl; + Eina_List *ll; + Evas_Object *bxv, *hv, *ck, *sl, *lb; Emix_Port *port; EINA_LIST_FOREACH(sink_list, l, bxv) @@ -181,15 +320,35 @@ _emix_sink_change(Emix_Sink *sink) _cb_sink_port_change, port); if (port->active) elm_object_text_set(hv, port->description); } - sl = evas_object_data_get(bxv, "volume"); - elm_slider_value_set(sl, sink->volume.volumes[0]); + ck = evas_object_data_get(bxv, "lock"); + + if (ck && !elm_check_state_get(ck)) + { + ck = evas_object_data_get(bxv, "mute"); + elm_check_state_set(ck, sink->mute); + EINA_LIST_FOREACH(evas_object_data_get(bxv, "volumes"), ll, sl) + { + elm_slider_value_set(sl, + sink->volume.volumes[(uintptr_t)evas_object_data_get(sl, "channel")]); + elm_object_disabled_set(sl, sink->mute); + lb = evas_object_data_get(sl, "lb"); + elm_object_disabled_set(lb, sink->mute); + } + } + else + { + ck = evas_object_data_get(bxv, "mute"); + elm_check_state_set(ck, sink->mute); + + sl = evas_object_data_get(bxv, "volume"); + elm_slider_value_set(sl, sink->volume.volumes[0]); + elm_object_disabled_set(sl, sink->mute); + } - ck = evas_object_data_get(bxv, "mute"); - elm_check_state_set(ck, sink->mute); - elm_object_disabled_set(sl, sink->mute); } ////////////////////////////////////////////////////////////////////////////// +static void _emix_sink_input_volume_fill(Emix_Sink_Input *input, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked); static void _cb_sink_input_port_change(void *data, @@ -215,6 +374,19 @@ _cb_sink_input_volume_change(void *data, elm_slider_value_set(obj, vol); } +static void +_cb_sink_input_volume_channel_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Sink_Input *input = evas_object_data_get(bxv, "input"); + double vol = elm_slider_value_get(obj); + input->volume.volumes[(uintptr_t)evas_object_data_get(obj, "channel")] = vol; + elm_slider_value_set(obj, vol); + emix_sink_input_volume_set(input, &input->volume); +} + static void _cb_sink_input_volume_drag_stop(void *data, Evas_Object *obj, @@ -226,6 +398,17 @@ _cb_sink_input_volume_drag_stop(void *data, elm_slider_value_set(obj, vol); } +static void +_cb_sink_input_volume_channel_drag_stop(void *data, + Evas_Object *obj, + void *event EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Sink_Input *input = evas_object_data_get(bxv, "input"); + int vol = input->volume.volumes[(uintptr_t)evas_object_data_get(obj, "channel")]; + elm_slider_value_set(obj, vol); +} + static void _cb_sink_input_mute_change(void *data, Evas_Object *obj, @@ -233,18 +416,156 @@ _cb_sink_input_mute_change(void *data, { Evas_Object *bxv = data; Emix_Sink_Input *input = evas_object_data_get(bxv, "input"); - Evas_Object *sl = evas_object_data_get(bxv, "volume"); + Evas_Object *sl; + Evas_Object *lock = evas_object_data_get(bxv, "lock"); Eina_Bool mute = elm_check_state_get(obj); - elm_object_disabled_set(sl, mute); + Evas_Object *lb; + Eina_List *l; + + if (lock && !elm_check_state_get(lock)) + { + EINA_LIST_FOREACH(evas_object_data_get(bxv, "volumes"), l, sl) + { + elm_object_disabled_set(sl, mute); + lb = evas_object_data_get(sl, "lb"); + elm_object_disabled_set(lb, mute); + } + } + else + { + sl = evas_object_data_get(bxv, "volume"); + elm_object_disabled_set(sl, mute); + } emix_sink_input_mute_set(input, mute); } +static void +_cb_sink_input_lock_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Sink_Input *input = evas_object_data_get(bxv, "input"); + Evas_Object *bx = evas_object_data_get(bxv, "volume_bx"); + Eina_Bool lock = elm_check_state_get(obj); + if (lock) + VOLSET(input->volume.volumes[0], input->volume, + input, emix_sink_input_volume_set); + _emix_sink_input_volume_fill(input, bxv, bx, lock); +} + +static void +_emix_sink_input_volume_fill(Emix_Sink_Input *input, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked) +{ + Evas_Object *bxhv, *lb, *sl, *ck; + unsigned int i; + Eina_List *sls = NULL; + + eina_list_free(evas_object_data_get(bxv, "volumes")); + elm_box_clear(bx); + + bxhv = elm_box_add(bx); + evas_object_size_hint_weight_set(bxhv, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(bxhv, EVAS_HINT_FILL, 0.5); + elm_box_pack_end(bx, bxhv); + evas_object_show(bxhv); + + if (locked) + { + sl = elm_slider_add(bx); + evas_object_data_set(bxv, "volume", sl); + elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); + elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); + elm_slider_unit_format_set(sl, "%1.0f"); + elm_slider_indicator_format_set(sl, "%1.0f"); + evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5); + elm_slider_value_set(sl, input->volume.volumes[0]); + elm_box_pack_end(bxhv, sl); + evas_object_show(sl); + evas_object_smart_callback_add(sl, "changed", + _cb_sink_input_volume_change, bxv); + evas_object_smart_callback_add(sl, "slider,drag,stop", + _cb_sink_input_volume_drag_stop, bxv); + + } + else + { + for (i = 0; i < input->volume.channel_count; ++i) + { + lb = elm_label_add(bx); + if (!input->volume.channel_names) + { + char buf[1024]; + snprintf(buf, sizeof(buf), "Channel %d", i); + elm_object_text_set(lb, buf); + } + else + elm_object_text_set(lb, input->volume.channel_names[i]); + evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.5); + evas_object_size_hint_align_set(lb, 0.0, 0.5); + elm_box_pack_end(bxhv, lb); + elm_object_disabled_set(lb, input->mute); + evas_object_show(lb); + + sl = elm_slider_add(bx); + evas_object_data_set(sl, "lb", lb); + evas_object_data_set(sl, "channel", (uintptr_t *)(uintptr_t)i); + elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); + elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); + elm_slider_unit_format_set(sl, "%1.0f"); + elm_slider_indicator_format_set(sl, "%1.0f"); + evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_slider_value_set(sl, input->volume.volumes[i]); + elm_box_pack_end(bxhv, sl); + evas_object_show(sl); + evas_object_smart_callback_add(sl, "changed", + _cb_sink_input_volume_channel_change, bxv); + evas_object_smart_callback_add(sl, "slider,drag,stop", + _cb_sink_input_volume_channel_drag_stop, bxv); + elm_object_disabled_set(sl, input->mute); + sls = eina_list_append(sls, sl); + } + } + evas_object_data_set(bxv, "volumes", sls); + + bxhv = elm_box_add(bx); + elm_box_pack_end(bx, bxhv); + evas_object_show(bxhv); + + ck = elm_check_add(bx); + evas_object_data_set(bxv, "mute", ck); + elm_object_text_set(ck, "Mute"); + elm_check_state_set(ck, input->mute); + elm_object_disabled_set(sl, input->mute); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", + _cb_sink_input_mute_change, bxv); + + if (input->volume.channel_count > 1) + { + ck = elm_check_add(bx); + evas_object_data_set(bxv, "lock", ck); + elm_object_text_set(ck, "Lock"); + elm_check_state_set(ck, locked); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", + _cb_sink_input_lock_change, bxv); + } +} + + static void _emix_sink_input_add(Emix_Sink_Input *input) { - Evas_Object *bxv, *bx, *lb, *ck, *sl, *hv, *sep; + Evas_Object *bxv, *bx, *lb, *hv, *sep; const Eina_List *l; Emix_Sink *sink; + Eina_Bool locked = EINA_TRUE; + unsigned int i; bxv = elm_box_add(win); sink_input_list = eina_list_append(sink_input_list, bxv); @@ -255,13 +576,13 @@ _emix_sink_input_add(Emix_Sink_Input *input) bx = elm_box_add(win); elm_box_horizontal_set(bx, EINA_TRUE); evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); - evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.0); + evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.5); elm_box_pack_end(bxv, bx); evas_object_show(bx); lb = elm_label_add(win); elm_object_text_set(lb, input->name); - evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.5); + evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.0); evas_object_size_hint_align_set(lb, 0.0, 0.5); elm_box_pack_end(bx, lb); evas_object_show(lb); @@ -283,37 +604,25 @@ _emix_sink_input_add(Emix_Sink_Input *input) evas_object_show(hv); bx = elm_box_add(win); + evas_object_data_set(bxv, "volume_bx", bx); elm_box_horizontal_set(bx, EINA_TRUE); evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); - evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.0); + evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.5); elm_box_pack_end(bxv, bx); evas_object_show(bx); - sl = elm_slider_add(win); - evas_object_data_set(bxv, "volume", sl); - elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); - elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); - elm_slider_unit_format_set(sl, "%1.0f"); - elm_slider_indicator_format_set(sl, "%1.0f"); - evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.5); - evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5); - elm_slider_value_set(sl, input->volume.volumes[0]); - elm_box_pack_end(bx, sl); - evas_object_show(sl); - evas_object_smart_callback_add(sl, "changed", - _cb_sink_input_volume_change, bxv); - evas_object_smart_callback_add(sl, "slider,drag,stop", - _cb_sink_input_volume_drag_stop, bxv); + /* Compare each volume level and check if they differ. If they differ unlock + the volume control and let user set each channel volume level */ + for (i = 1; i < input->volume.channel_count; ++i) + { + if (input->volume.volumes[i - 1] != input->volume.volumes[i]) + { + locked = EINA_FALSE; + break; + } + } - ck = elm_check_add(win); - evas_object_data_set(bxv, "mute", ck); - elm_object_text_set(ck, "Mute"); - elm_check_state_set(ck, input->mute); - elm_object_disabled_set(sl, input->mute); - elm_box_pack_end(bx, ck); - evas_object_show(ck); - evas_object_smart_callback_add(ck, "changed", - _cb_sink_input_mute_change, bxv); + _emix_sink_input_volume_fill(input, bxv, bx, locked); sep = elm_separator_add(win); elm_separator_horizontal_set(sep, EINA_TRUE); @@ -346,7 +655,8 @@ static void _emix_sink_input_change(Emix_Sink_Input *input) { const Eina_List *l; - Evas_Object *bxv, *hv, *ck, *sl; + Eina_List *ll; + Evas_Object *bxv, *hv, *ck, *sl, *lb; Emix_Sink *sink; EINA_LIST_FOREACH(sink_input_list, l, bxv) @@ -363,15 +673,35 @@ _emix_sink_input_change(Emix_Sink_Input *input) _cb_sink_input_port_change, sink); if (input->sink == sink) elm_object_text_set(hv, sink->name); } - sl = evas_object_data_get(bxv, "volume"); - elm_slider_value_set(sl, input->volume.volumes[0]); - ck = evas_object_data_get(bxv, "mute"); - elm_check_state_set(ck, input->mute); - elm_object_disabled_set(sl, input->mute); + ck = evas_object_data_get(bxv, "lock"); + + if (ck && !elm_check_state_get(ck)) + { + ck = evas_object_data_get(bxv, "mute"); + elm_check_state_set(ck, input->mute); + EINA_LIST_FOREACH(evas_object_data_get(bxv, "volumes"), ll, sl) + { + elm_slider_value_set(sl, + input->volume.volumes[(uintptr_t)evas_object_data_get(sl, "channel")]); + elm_object_disabled_set(sl, input->mute); + lb = evas_object_data_get(sl, "lb"); + elm_object_disabled_set(lb, input->mute); + } + } + else + { + ck = evas_object_data_get(bxv, "mute"); + elm_check_state_set(ck, input->mute); + + sl = evas_object_data_get(bxv, "volume"); + elm_slider_value_set(sl, input->volume.volumes[0]); + elm_object_disabled_set(sl, input->mute); + } } ////////////////////////////////////////////////////////////////////////////// +static void _emix_source_volume_fill(Emix_Source *source, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked); static void _cb_source_volume_change(void *data, @@ -385,6 +715,20 @@ _cb_source_volume_change(void *data, elm_slider_value_set(obj, vol); } +static void +_cb_source_volume_channel_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Source *source = evas_object_data_get(bxv, "source"); + double vol = elm_slider_value_get(obj); + source->volume.volumes[(uintptr_t)evas_object_data_get(obj, "channel")] = vol; + elm_slider_value_set(obj, vol); + emix_source_volume_set(source, &source->volume); +} + + static void _cb_source_volume_drag_stop(void *data, Evas_Object *obj, @@ -396,6 +740,17 @@ _cb_source_volume_drag_stop(void *data, elm_slider_value_set(obj, vol); } +static void +_cb_source_volume_channel_drag_stop(void *data, + Evas_Object *obj, + void *event EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Source *source = evas_object_data_get(bxv, "source"); + int vol = source->volume.volumes[(uintptr_t)evas_object_data_get(obj, "channel")]; + elm_slider_value_set(obj, vol); +} + static void _cb_source_mute_change(void *data, Evas_Object *obj, @@ -403,16 +758,153 @@ _cb_source_mute_change(void *data, { Evas_Object *bxv = data; Emix_Source *source = evas_object_data_get(bxv, "source"); - Evas_Object *sl = evas_object_data_get(bxv, "volume"); + Evas_Object *sl; + Evas_Object *lock = evas_object_data_get(bxv, "lock"); Eina_Bool mute = elm_check_state_get(obj); - elm_object_disabled_set(sl, mute); + Evas_Object *lb; + Eina_List *l; + + if (lock && !elm_check_state_get(lock)) + { + EINA_LIST_FOREACH(evas_object_data_get(bxv, "volumes"), l, sl) + { + elm_object_disabled_set(sl, mute); + lb = evas_object_data_get(sl, "lb"); + elm_object_disabled_set(lb, mute); + } + } + else + { + sl = evas_object_data_get(bxv, "volume"); + elm_object_disabled_set(sl, mute); + } emix_source_mute_set(source, mute); } +static void +_cb_source_lock_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *bxv = data; + Emix_Source *source = evas_object_data_get(bxv, "source"); + Evas_Object *bx = evas_object_data_get(bxv, "volume_bx"); + Eina_Bool lock = elm_check_state_get(obj); + if (lock) + VOLSET(source->volume.volumes[0], source->volume, + source, emix_source_volume_set); + _emix_source_volume_fill(source, bxv, bx, lock); +} + +static void +_emix_source_volume_fill(Emix_Source *source, Evas_Object *bxv, Evas_Object *bx, Eina_Bool locked) +{ + Evas_Object *bxhv, *lb, *sl, *ck; + Eina_List *sls = NULL; + unsigned int i; + + eina_list_free(evas_object_data_get(bxv, "volumes")); + elm_box_clear(bx); + + bxhv = elm_box_add(bx); + evas_object_size_hint_weight_set(bxhv, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(bxhv, EVAS_HINT_FILL, 0.5); + elm_box_pack_end(bx, bxhv); + evas_object_show(bxhv); + + if (locked) + { + sl = elm_slider_add(bx); + evas_object_data_set(bxv, "volume", sl); + elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); + elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); + elm_slider_unit_format_set(sl, "%1.0f"); + elm_slider_indicator_format_set(sl, "%1.0f"); + evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_slider_value_set(sl, source->volume.volumes[0]); + elm_box_pack_end(bxhv, sl); + evas_object_show(sl); + evas_object_smart_callback_add(sl, "changed", + _cb_source_volume_change, bxv); + evas_object_smart_callback_add(sl, "slider,drag,stop", + _cb_source_volume_drag_stop, bxv); + elm_object_disabled_set(sl, source->mute); + } + else + { + for (i = 0; i < source->volume.channel_count; ++i) + { + lb = elm_label_add(bx); + if (!source->volume.channel_names) + { + char buf[1024]; + snprintf(buf, sizeof(buf), "Channel %d", i); + elm_object_text_set(lb, buf); + } + else + elm_object_text_set(lb, source->volume.channel_names[i]); + evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.5); + evas_object_size_hint_align_set(lb, 0.0, 0.5); + elm_box_pack_end(bxhv, lb); + elm_object_disabled_set(lb, source->mute); + evas_object_show(lb); + + sl = elm_slider_add(bx); + evas_object_data_set(sl, "lb", lb); + evas_object_data_set(sl, "channel", (uintptr_t *)(uintptr_t)i); + elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); + elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); + elm_slider_unit_format_set(sl, "%1.0f"); + elm_slider_indicator_format_set(sl, "%1.0f"); + evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_slider_value_set(sl, source->volume.volumes[i]); + elm_box_pack_end(bxhv, sl); + evas_object_show(sl); + evas_object_smart_callback_add(sl, "changed", + _cb_source_volume_channel_change, bxv); + evas_object_smart_callback_add(sl, "slider,drag,stop", + _cb_source_volume_channel_drag_stop, bxv); + elm_object_disabled_set(sl, source->mute); + sls = eina_list_append(sls, sl); + } + } + evas_object_data_set(bxv, "volumes", sls); + + bxhv = elm_box_add(bx); + elm_box_pack_end(bx, bxhv); + evas_object_show(bxhv); + + ck = elm_check_add(bx); + evas_object_data_set(bxv, "mute", ck); + elm_object_text_set(ck, "Mute"); + elm_check_state_set(ck, source->mute); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", + _cb_source_mute_change, bxv); + + if (source->volume.channel_count > 1) + { + ck = elm_check_add(bx); + evas_object_data_set(bxv, "lock", ck); + elm_object_text_set(ck, "Lock"); + elm_check_state_set(ck, locked); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", + _cb_source_lock_change, bxv); + } +} + + static void _emix_source_add(Emix_Source *source) { - Evas_Object *bxv, *bx, *lb, *ck, *sl, *sep; + Evas_Object *bxv, *bx, *lb, *sep; + unsigned int i; + Eina_Bool locked = EINA_TRUE; bxv = elm_box_add(win); source_list = eina_list_append(source_list, bxv); @@ -429,43 +921,32 @@ _emix_source_add(Emix_Source *source) lb = elm_label_add(win); elm_object_text_set(lb, source->name); - evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.5); + evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.0); evas_object_size_hint_align_set(lb, 0.0, 0.5); elm_box_pack_end(bx, lb); evas_object_show(lb); bx = elm_box_add(win); + evas_object_data_set(bxv, "volume_bx", bx); elm_box_horizontal_set(bx, EINA_TRUE); evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); - evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.0); + evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.5); elm_box_pack_end(bxv, bx); evas_object_show(bx); - sl = elm_slider_add(win); - evas_object_data_set(bxv, "volume", sl); - elm_slider_min_max_set(sl, 0.0, emix_max_volume_get()); - elm_slider_span_size_set(sl, (emix_max_volume_get()) * elm_config_scale_get()); - elm_slider_unit_format_set(sl, "%1.0f"); - elm_slider_indicator_format_set(sl, "%1.0f"); - evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.5); - evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5); - elm_slider_value_set(sl, source->volume.volumes[0]); - elm_box_pack_end(bx, sl); - evas_object_show(sl); - evas_object_smart_callback_add(sl, "changed", - _cb_source_volume_change, bxv); - evas_object_smart_callback_add(sl, "slider,drag,stop", - _cb_source_volume_drag_stop, bxv); + /* Compare each volume level and check if they differ. If they differ unlock + the volume control and let user set each channel volume level */ + for (i = 1; i < source->volume.channel_count; ++i) + { + if (source->volume.volumes[i - 1] != source->volume.volumes[i]) + { + locked = EINA_FALSE; + break; + } + } + + _emix_source_volume_fill(source, bxv, bx, locked); - ck = elm_check_add(win); - evas_object_data_set(bxv, "mute", ck); - elm_object_text_set(ck, "Mute"); - elm_check_state_set(ck, source->mute); - elm_object_disabled_set(sl, source->mute); - elm_box_pack_end(bx, ck); - evas_object_show(ck); - evas_object_smart_callback_add(ck, "changed", - _cb_source_mute_change, bxv); sep = elm_separator_add(win); elm_separator_horizontal_set(sep, EINA_TRUE); @@ -498,19 +979,39 @@ static void _emix_source_change(Emix_Source *source) { const Eina_List *l; - Evas_Object *bxv, *ck, *sl; + Eina_List *ll; + Evas_Object *bxv, *ck, *sl, *lb; EINA_LIST_FOREACH(source_list, l, bxv) { if (evas_object_data_get(bxv, "source") == source) break; } if (!l) return; - sl = evas_object_data_get(bxv, "volume"); - elm_slider_value_set(sl, source->volume.volumes[0]); - ck = evas_object_data_get(bxv, "mute"); - elm_check_state_set(ck, source->mute); - elm_object_disabled_set(sl, source->mute); + ck = evas_object_data_get(bxv, "lock"); + + if (ck && !elm_check_state_get(ck)) + { + ck = evas_object_data_get(bxv, "mute"); + elm_check_state_set(ck, source->mute); + EINA_LIST_FOREACH(evas_object_data_get(bxv, "volumes"), ll, sl) + { + elm_slider_value_set(sl, + source->volume.volumes[(uintptr_t)evas_object_data_get(sl, "channel")]); + elm_object_disabled_set(sl, source->mute); + lb = evas_object_data_get(sl, "lb"); + elm_object_disabled_set(lb, source->mute); + } + } + else + { + ck = evas_object_data_get(bxv, "mute"); + elm_check_state_set(ck, source->mute); + + sl = evas_object_data_get(bxv, "volume"); + elm_slider_value_set(sl, source->volume.volumes[0]); + elm_object_disabled_set(sl, source->mute); + } } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/modules/mixer/gadget/backend.c b/src/modules/mixer/gadget/backend.c index 0f9b469c1..59e7d7acb 100644 --- a/src/modules/mixer/gadget/backend.c +++ b/src/modules/mixer/gadget/backend.c @@ -158,7 +158,7 @@ _volume_increase_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) volume.volumes[i] = s->volume.volumes[i]; } - emix_sink_volume_set(s, volume); + emix_sink_volume_set(s, &volume); emix_config_save_state_get(); if (emix_config_save_get()) e_config_save_queue(); free(volume.volumes); @@ -184,7 +184,7 @@ _volume_decrease_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) volume.volumes[i] = s->volume.volumes[i]; } - emix_sink_volume_set((Emix_Sink *)_sink_default, volume); + emix_sink_volume_set((Emix_Sink *)_sink_default, &volume); emix_config_save_state_get(); if (emix_config_save_get()) e_config_save_queue(); free(volume.volumes); diff --git a/src/modules/mixer/lib/backends/alsa/alsa.c b/src/modules/mixer/lib/backends/alsa/alsa.c index e09227db6..0d12d03a9 100644 --- a/src/modules/mixer/lib/backends/alsa/alsa.c +++ b/src/modules/mixer/lib/backends/alsa/alsa.c @@ -408,25 +408,25 @@ _alsa_sources_mute_set(Emix_Source *source, Eina_Bool mute) } static void -_alsa_sources_volume_set(Emix_Source *source, Emix_Volume v) +_alsa_sources_volume_set(Emix_Source *source, Emix_Volume *v) { Alsa_Emix_Source *s = (Alsa_Emix_Source*) source; unsigned int i; snd_mixer_elem_t *elem; - EINA_SAFETY_ON_FALSE_RETURN((ctx && source)); + EINA_SAFETY_ON_FALSE_RETURN((ctx && source && v)); - if (v.channel_count != eina_list_count(s->channels)) + if (v->channel_count != eina_list_count(s->channels)) { ERR("Volume struct doesn't have the same length than the channels"); return; } - for (i = 0; i < v.channel_count; i++ ) + for (i = 0; i < v->channel_count; i++ ) { elem = eina_list_nth(s->channels, i); - _alsa_channel_volume_set(elem, v.volumes[i], EINA_FALSE); - s->source.volume.volumes[i] = v.volumes[i]; + _alsa_channel_volume_set(elem, v->volumes[i], EINA_FALSE); + s->source.volume.volumes[i] = v->volumes[i]; } if (ctx->cb) ctx->cb((void *)ctx->userdata, EMIX_SOURCE_CHANGED_EVENT, @@ -480,25 +480,25 @@ _alsa_sink_mute_set(Emix_Sink *sink, Eina_Bool mute) } static void -_alsa_sink_volume_set(Emix_Sink *sink, Emix_Volume v) +_alsa_sink_volume_set(Emix_Sink *sink, Emix_Volume *v) { Alsa_Emix_Sink *s = (Alsa_Emix_Sink *)sink; unsigned int i; snd_mixer_elem_t *elem; - EINA_SAFETY_ON_FALSE_RETURN((ctx && sink)); + EINA_SAFETY_ON_FALSE_RETURN((ctx && sink && v)); - if (v.channel_count != eina_list_count(s->channels)) + if (v->channel_count != eina_list_count(s->channels)) { ERR("Volume struct doesn't have the same length than the channels"); return; } - for (i = 0; i < v.channel_count; i++ ) + for (i = 0; i < v->channel_count; i++ ) { elem = eina_list_nth(s->channels, i); - _alsa_channel_volume_set(elem, v.volumes[i], EINA_FALSE); - s->sink.volume.volumes[i] = v.volumes[i]; + _alsa_channel_volume_set(elem, v->volumes[i], EINA_FALSE); + s->sink.volume.volumes[i] = v->volumes[i]; } if (ctx->cb) ctx->cb((void *)ctx->userdata, EMIX_SINK_CHANGED_EVENT, diff --git a/src/modules/mixer/lib/backends/pulseaudio/pulse.c b/src/modules/mixer/lib/backends/pulseaudio/pulse.c index 5c58749d1..8cbb1f4f9 100644 --- a/src/modules/mixer/lib/backends/pulseaudio/pulse.c +++ b/src/modules/mixer/lib/backends/pulseaudio/pulse.c @@ -66,14 +66,14 @@ static Context *ctx = NULL; extern pa_mainloop_api functable; static pa_cvolume -_emix_volume_convert(const Emix_Volume volume) +_emix_volume_convert(const Emix_Volume *volume) { pa_cvolume vol; unsigned int i; - vol.channels = volume.channel_count; - for (i = 0; i < volume.channel_count; i++) - vol.values[i] = INT_TO_PA_VOLUME(volume.volumes[i]); + vol.channels = volume->channel_count; + for (i = 0; i < volume->channel_count; i++) + vol.values[i] = INT_TO_PA_VOLUME(volume->volumes[i]); return vol; } @@ -98,6 +98,7 @@ _pa_cvolume_convert(const pa_cvolume *volume, Emix_Volume *vol) static void _sink_del(Sink *sink) { + unsigned int i; Emix_Port *port; EINA_SAFETY_ON_NULL_RETURN(sink); @@ -109,6 +110,9 @@ _sink_del(Sink *sink) } free(sink->base.volume.volumes); + for(i = 0; i < sink->base.volume.channel_count; ++i) + eina_stringshare_del(sink->base.volume.channel_names[i]); + free(sink->base.volume.channel_names); eina_stringshare_del(sink->base.name); free(sink); } @@ -116,9 +120,13 @@ _sink_del(Sink *sink) static void _sink_input_del(Sink_Input *input) { + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(input); free(input->base.volume.volumes); + for(i = 0; i < input->base.volume.channel_count; ++i) + eina_stringshare_del(input->base.volume.channel_names[i]); + free(input->base.volume.channel_names); eina_stringshare_del(input->base.name); eina_stringshare_del(input->icon); free(input); @@ -127,9 +135,13 @@ _sink_input_del(Sink_Input *input) static void _source_del(Source *source) { + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(source); free(source->base.volume.volumes); + for(i = 0; i < source->base.volume.channel_count; ++i) + eina_stringshare_del(source->base.volume.channel_names[i]); + free(source->base.volume.channel_names); eina_stringshare_del(source->base.name); free(source); } @@ -177,6 +189,9 @@ _sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol, sink->idx = info->index; sink->base.name = eina_stringshare_add(info->description); _pa_cvolume_convert(&info->volume, &sink->base.volume); + sink->base.volume.channel_names = calloc(sink->base.volume.channel_count, sizeof(Emix_Channel)); + 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.mute = !!info->mute; for (i = 0; i < info->n_ports; i++) @@ -238,7 +253,18 @@ _sink_changed_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol, EINA_SAFETY_ON_NULL_RETURN(sink); eina_stringshare_replace(&sink->base.name, info->description); + + if (sink->base.volume.channel_count != info->volume.channels) + { + for (i = 0; i < sink->base.volume.channel_count; ++i) + eina_stringshare_del(sink->base.volume.channel_names[i]); + free(sink->base.volume.channel_names); + sink->base.volume.channel_names = calloc(info->volume.channels, sizeof(Emix_Channel)); + } _pa_cvolume_convert(&info->volume, &sink->base.volume); + for (i = 0; i < sink->base.volume.channel_count; ++i) + eina_stringshare_replace(&sink->base.volume.channel_names[i], + pa_channel_position_to_pretty_string(info->channel_map.map[i])); sink->base.mute = !!info->mute; if (sink->base.ports) @@ -335,6 +361,7 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info, Eina_List *l; Sink *s; const char *t; + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(ctx); if (eol < 0) @@ -374,6 +401,9 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info, input->base.name = eina_stringshare_add(eina_strbuf_string_get(input_name)); eina_strbuf_free(input_name); _pa_cvolume_convert(&info->volume, &input->base.volume); + input->base.volume.channel_names = calloc(input->base.volume.channel_count, sizeof(Emix_Channel)); + for (i = 0; i < input->base.volume.channel_count; ++i) + input->base.volume.channel_names[i] = eina_stringshare_add(pa_channel_position_to_pretty_string(info->channel_map.map[i])); input->base.mute = !!info->mute; EINA_LIST_FOREACH(ctx->sinks, l, s) { @@ -398,10 +428,11 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info, int eol, void *userdata EINA_UNUSED) { - Sink_Input *input = NULL, *i; + Sink_Input *input = NULL, *si; Sink *s = NULL; Eina_List *l; const char *t; + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(ctx); if (eol < 0) @@ -416,11 +447,11 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED, if (eol > 0) return; - EINA_LIST_FOREACH(ctx->inputs, l, i) + EINA_LIST_FOREACH(ctx->inputs, l, si) { - if (i->idx == (int)info->index) + if (si->idx == (int)info->index) { - input = i; + input = si; break; } } @@ -434,7 +465,18 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED, ctx->inputs = eina_list_append(ctx->inputs, input); } input->idx = info->index; + if (input->base.volume.channel_count != info->volume.channels) + { + for (i = 0; i < input->base.volume.channel_count; ++i) + eina_stringshare_del(input->base.volume.channel_names[i]); + free(input->base.volume.channel_names); + input->base.volume.channel_names = calloc(info->volume.channels, sizeof(Emix_Channel)); + } _pa_cvolume_convert(&info->volume, &input->base.volume); + for (i = 0; i < input->base.volume.channel_count; ++i) + eina_stringshare_replace(&input->base.volume.channel_names[i], + pa_channel_position_to_pretty_string(info->channel_map.map[i])); + input->base.mute = !!info->mute; EINA_LIST_FOREACH(ctx->sinks, l, s) @@ -482,6 +524,7 @@ _source_cb(pa_context *c EINA_UNUSED, const pa_source_info *info, int eol, void *userdata EINA_UNUSED) { Source *source; + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(ctx); if (eol < 0) @@ -502,6 +545,9 @@ _source_cb(pa_context *c EINA_UNUSED, const pa_source_info *info, source->idx = info->index; source->base.name = eina_stringshare_add(info->name); _pa_cvolume_convert(&info->volume, &source->base.volume); + source->base.volume.channel_names = calloc(source->base.volume.channel_count, sizeof(Emix_Channel)); + for (i = 0; i < source->base.volume.channel_count; ++i) + source->base.volume.channel_names[i] = eina_stringshare_add(pa_channel_position_to_pretty_string(info->channel_map.map[i])); source->base.mute = !!info->mute; ctx->sources = eina_list_append(ctx->sources, source); @@ -517,6 +563,7 @@ _source_changed_cb(pa_context *c EINA_UNUSED, { Source *source = NULL, *s; Eina_List *l; + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(ctx); if (eol < 0) @@ -549,7 +596,17 @@ _source_changed_cb(pa_context *c EINA_UNUSED, ctx->sources = eina_list_append(ctx->sources, source); } source->idx= info->index; + if (source->base.volume.channel_count != info->volume.channels) + { + for (i = 0; i < source->base.volume.channel_count; ++i) + eina_stringshare_del(source->base.volume.channel_names[i]); + free(source->base.volume.channel_names); + source->base.volume.channel_names = calloc(info->volume.channels, sizeof(Emix_Channel)); + } _pa_cvolume_convert(&info->volume, &source->base.volume); + for (i = 0; i < source->base.volume.channel_count; ++i) + eina_stringshare_replace(&source->base.volume.channel_names[i], + pa_channel_position_to_pretty_string(info->channel_map.map[i])); source->base.mute = !!info->mute; if (ctx->cb) @@ -1164,7 +1221,7 @@ _disconnect_cb() } static void -_source_volume_set(Emix_Source *source, Emix_Volume volume) +_source_volume_set(Emix_Source *source, Emix_Volume *volume) { pa_operation* o; pa_cvolume vol = _emix_volume_convert(volume); @@ -1211,7 +1268,7 @@ _sink_inputs_get(void) } static void -_sink_volume_set(Emix_Sink *sink, Emix_Volume volume) +_sink_volume_set(Emix_Sink *sink, Emix_Volume *volume) { pa_operation* o; Sink *s = (Sink *)sink; @@ -1236,7 +1293,7 @@ _sink_mute_set(Emix_Sink *sink, Eina_Bool mute) } static void -_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume volume) +_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume *volume) { pa_operation* o; Sink_Input *sink_input = (Sink_Input *)input; diff --git a/src/modules/mixer/lib/emix.c b/src/modules/mixer/lib/emix.c index 4d22fb509..65f9cb33f 100644 --- a/src/modules/mixer/lib/emix.c +++ b/src/modules/mixer/lib/emix.c @@ -282,7 +282,7 @@ emix_sink_mute_set(Emix_Sink *sink, Eina_Bool mute) } void -emix_sink_volume_set(Emix_Sink *sink, Emix_Volume volume) +emix_sink_volume_set(Emix_Sink *sink, Emix_Volume *volume) { EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded && ctx->loaded->ebackend_sink_volume_set && @@ -320,7 +320,7 @@ emix_sink_input_mute_set(Emix_Sink_Input *input, Eina_Bool mute) } void -emix_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume volume) +emix_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume *volume) { EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded && ctx->loaded->ebackend_sink_input_volume_set && @@ -359,7 +359,7 @@ emix_source_mute_set(Emix_Source *source, Eina_Bool mute) } void -emix_source_volume_set(Emix_Source *source, Emix_Volume volume) +emix_source_volume_set(Emix_Source *source, Emix_Volume *volume) { EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded && ctx->loaded->ebackend_source_volume_set && diff --git a/src/modules/mixer/lib/emix.h b/src/modules/mixer/lib/emix.h index 94bfb89ed..6725a96c7 100644 --- a/src/modules/mixer/lib/emix.h +++ b/src/modules/mixer/lib/emix.h @@ -42,10 +42,13 @@ enum Emix_Event { EMIX_CARD_CHANGED_EVENT }; +typedef const char * Emix_Channel; + typedef struct _Emix_Volume { unsigned int channel_count; // the index of the field is the id of the channel, the value the volume int *volumes; + Emix_Channel *channel_names; } Emix_Volume; typedef struct _Emix_Port { @@ -104,7 +107,7 @@ typedef struct _Emix_Backend { void (*ebackend_sink_mute_set)(Emix_Sink *sink, Eina_Bool mute); void (*ebackend_sink_volume_set)(Emix_Sink *sink, - Emix_Volume volume); + Emix_Volume *volume); Eina_Bool (*ebackend_sink_port_set)(Emix_Sink *sink, const Emix_Port *port); Eina_Bool (*ebackend_sink_change_support)(void); @@ -113,7 +116,7 @@ typedef struct _Emix_Backend { void (*ebackend_sink_input_mute_set)( Emix_Sink_Input *input, Eina_Bool mute); void (*ebackend_sink_input_volume_set)( - Emix_Sink_Input *input, Emix_Volume volume); + Emix_Sink_Input *input, Emix_Volume *volume); void (*ebackend_sink_input_sink_change)( Emix_Sink_Input *input, Emix_Sink *sink); @@ -121,7 +124,7 @@ typedef struct _Emix_Backend { void (*ebackend_source_mute_set)(Emix_Source *source, Eina_Bool mute); void (*ebackend_source_volume_set)(Emix_Source *source, - Emix_Volume volume); + Emix_Volume *volume); Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent); const Eina_List* (*ebackend_cards_get)(void); @@ -132,17 +135,13 @@ typedef struct _Emix_Backend { #define VOLSET(vol, srcvol, target, func) \ do { \ - Emix_Volume _v; \ int _pvol = srcvol.volumes[0]; \ if ((_pvol > 80) && (_pvol <= 100) && \ (vol > 100) && (vol < 120)) vol = 100; \ - _v.channel_count = srcvol.channel_count; \ - _v.volumes = calloc(srcvol.channel_count, sizeof(int)); \ - if (_v.volumes) { \ + if (srcvol.volumes) { \ unsigned int _i; \ - for (_i = 0; _i < _v.channel_count; _i++) _v.volumes[_i] = vol; \ - func(target, _v); \ - free(_v.volumes); \ + for (_i = 0; _i < srcvol.channel_count; _i++) srcvol.volumes[_i] = vol; \ + func(target, &srcvol); \ } \ } while (0) @@ -167,14 +166,14 @@ E_API Eina_Bool emix_sink_port_set(Emix_Sink *sink, Emix_Port *port); E_API void emix_sink_default_set(Emix_Sink *sink); E_API void emix_sink_mute_set(Emix_Sink *sink, Eina_Bool mute); E_API void emix_sink_volume_set(Emix_Sink *sink, - Emix_Volume volume); + Emix_Volume *volume); E_API Eina_Bool emix_sink_change_support(void); E_API const Eina_List* emix_sink_inputs_get(void); E_API void emix_sink_input_mute_set(Emix_Sink_Input *input, Eina_Bool mute); E_API void emix_sink_input_volume_set(Emix_Sink_Input *input, - Emix_Volume volume); + Emix_Volume *volume); E_API void emix_sink_input_sink_change(Emix_Sink_Input *input, Emix_Sink *sink); @@ -182,7 +181,7 @@ E_API const Eina_List* emix_sources_get(void); E_API void emix_source_mute_set(Emix_Source *source, Eina_Bool mute); E_API void emix_source_volume_set(Emix_Source *source, - Emix_Volume volume); + Emix_Volume *volume); E_API Evas_Object* emix_advanced_options_add(Evas_Object *parent); E_API const Eina_List* emix_cards_get(void);