diff --git a/src/modules/mixer/backend.c b/src/modules/mixer/backend.c index 7fcb2c73c..e705b964a 100644 --- a/src/modules/mixer/backend.c +++ b/src/modules/mixer/backend.c @@ -358,6 +358,10 @@ _sink_event(int type, void *info) } else if (type == EMIX_SINK_CHANGED_EVENT) { + /* If pulseaudio changed the default sink, swap the UI to display it + instead of previously selected sink */ + if (sink->default_sink) + _sink_default = sink; if (_sink_default == sink) { static int prev_vol = -1; diff --git a/src/modules/mixer/e_mod_config.c b/src/modules/mixer/e_mod_config.c index e426c3ca1..445bb3a21 100644 --- a/src/modules/mixer/e_mod_config.c +++ b/src/modules/mixer/e_mod_config.c @@ -25,6 +25,7 @@ typedef struct _Emix_Config_Sink Eina_List *ports; int mute; int volume; + int default_sink; } Emix_Config_Sink; typedef struct _Emix_Config_Source @@ -32,6 +33,7 @@ typedef struct _Emix_Config_Source const char *name; int mute; int volume; + int default_source; } Emix_Config_Source; typedef struct _Emix_Config_Port @@ -63,11 +65,13 @@ _emix_config_dd_new(void) E_CONFIG_LIST(c_sinkd, Emix_Config_Sink, ports, c_portd); E_CONFIG_VAL(c_sinkd, Emix_Config_Sink, mute, INT); E_CONFIG_VAL(c_sinkd, Emix_Config_Sink, volume, INT); + E_CONFIG_VAL(c_sinkd, Emix_Config_Sink, default_sink, INT); c_sourced = E_CONFIG_DD_NEW("Emix_Config_Source", Emix_Config_Source); E_CONFIG_VAL(c_sourced, Emix_Config_Source, name, STR); E_CONFIG_VAL(c_sourced, Emix_Config_Source, mute, INT); E_CONFIG_VAL(c_sourced, Emix_Config_Source, volume, INT); + E_CONFIG_VAL(c_sourced, Emix_Config_Source, default_source, INT); cd = E_CONFIG_DD_NEW("Emix_Config", Emix_Config); @@ -260,6 +264,7 @@ emix_config_save_state_get(void) if (emsink->volume.channel_count > 0) sink->volume = emsink->volume.volumes[0]; sink->mute = emsink->mute; + sink->default_sink = emsink->default_sink; _config->sinks = eina_list_append(_config->sinks, sink); } } @@ -274,6 +279,7 @@ emix_config_save_state_get(void) if (emsource->volume.channel_count > 0) source->volume = emsource->volume.volumes[0]; source->mute = emsource->mute; + source->default_source = emsource->default_source; _config->sources = eina_list_append(_config->sources, source); } } @@ -351,6 +357,8 @@ emix_config_save_state_restore(void) free(v.volumes); } emix_sink_mute_set(emsink, sink->mute); + if (sink->default_sink) + emix_sink_default_set(emsink); EINA_LIST_FOREACH(sink->ports, ll, port) { if (!port->name) continue; @@ -377,6 +385,8 @@ emix_config_save_state_restore(void) free(v.volumes); } emix_source_mute_set(emsource, source->mute); + if (source->default_source) + emix_source_default_set(emsource); } } diff --git a/src/modules/mixer/emixer.c b/src/modules/mixer/emixer.c index 322d5398f..fa5bc2a8c 100644 --- a/src/modules/mixer/emixer.c +++ b/src/modules/mixer/emixer.c @@ -121,6 +121,20 @@ _cb_sink_lock_change(void *data, _emix_sink_volume_fill(sink, fr, bx, lock); } +static void +_cb_sink_default_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *fr = data; + Emix_Sink *sink = evas_object_data_get(fr, "sink"); + Eina_Bool is_default = elm_check_state_get(obj); + if (is_default) { + emix_sink_default_set(sink); + elm_object_disabled_set(obj, EINA_TRUE); + } +} + static void _emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *fr, Evas_Object *bx, Eina_Bool locked) { @@ -195,6 +209,14 @@ _emix_sink_volume_fill(Emix_Sink *sink, Evas_Object *fr, Evas_Object *bx, Eina_B elm_box_pack_end(bx, bxhv); evas_object_show(bxhv); + ck = elm_check_add(bx); + evas_object_data_set(fr, "default", ck); + elm_object_text_set(ck, "Default"); + elm_check_state_set(ck, sink->default_sink); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", _cb_sink_default_change, fr); + ck = elm_check_add(bx); evas_object_data_set(fr, "mute", ck); elm_object_text_set(ck, "Mute"); @@ -368,6 +390,9 @@ _emix_sink_change(Emix_Sink *sink) elm_object_disabled_set(sl, sink->mute); } + ck = evas_object_data_get(fr, "default"); + elm_check_state_set(ck, sink->default_sink); + elm_object_disabled_set(ck, sink->default_sink); } ////////////////////////////////////////////////////////////////////////////// @@ -845,6 +870,20 @@ _cb_source_lock_change(void *data, _emix_source_volume_fill(source, fr, bx, lock); } +static void +_cb_source_default_change(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Evas_Object *fr = data; + Emix_Source *source = evas_object_data_get(fr, "source"); + Eina_Bool is_default = elm_check_state_get(obj); + if (is_default) { + emix_source_default_set(source); + elm_object_disabled_set(obj, EINA_TRUE); + } +} + static void _emix_source_volume_fill(Emix_Source *source, Evas_Object *fr, Evas_Object *bx, Eina_Bool locked) { @@ -925,6 +964,14 @@ _emix_source_volume_fill(Emix_Source *source, Evas_Object *fr, Evas_Object *bx, elm_box_pack_end(bx, bxhv); evas_object_show(bxhv); + ck = elm_check_add(bx); + evas_object_data_set(fr, "default", ck); + elm_object_text_set(ck, "Default"); + elm_check_state_set(ck, source->default_source); + elm_box_pack_end(bxhv, ck); + evas_object_show(ck); + evas_object_smart_callback_add(ck, "changed", _cb_source_default_change, fr); + ck = elm_check_add(bx); evas_object_data_set(fr, "mute", ck); elm_object_text_set(ck, "Mute"); @@ -1071,6 +1118,10 @@ _emix_source_change(Emix_Source *source) elm_slider_value_set(sl, source->volume.volumes[0]); elm_object_disabled_set(sl, source->mute); } + + ck = evas_object_data_get(fr, "default"); + elm_check_state_set(ck, source->default_source); + elm_object_disabled_set(ck, source->default_source); } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/modules/mixer/lib/backends/alsa/alsa.c b/src/modules/mixer/lib/backends/alsa/alsa.c index 0d12d03a9..894b1115e 100644 --- a/src/modules/mixer/lib/backends/alsa/alsa.c +++ b/src/modules/mixer/lib/backends/alsa/alsa.c @@ -518,7 +518,7 @@ _alsa_backend = _alsa_shutdown, _max_volume, _alsa_sinks_get, - _alsa_support, /*default support*/ + _alsa_support, /*sink default support*/ NULL, /*get*/ NULL, /*set*/ _alsa_sink_mute_set, /*mute_set*/ @@ -530,6 +530,9 @@ _alsa_backend = NULL,/*sink input volume set*/ NULL,/*sink input sink change*/ _alsa_sources_get,/*source*/ + _alsa_support, /* source default support*/ + NULL, /*get*/ + NULL, /*set*/ _alsa_sources_mute_set,/* source mute set */ _alsa_sources_volume_set, /* source volume set */ NULL, /* advanced options */ diff --git a/src/modules/mixer/lib/backends/pulseaudio/pulse.c b/src/modules/mixer/lib/backends/pulseaudio/pulse.c index fc5b17346..23d446feb 100644 --- a/src/modules/mixer/lib/backends/pulseaudio/pulse.c +++ b/src/modules/mixer/lib/backends/pulseaudio/pulse.c @@ -25,7 +25,6 @@ typedef struct _Context Emix_Event_Cb cb; const void *userdata; Ecore_Timer *connect; - int default_sink; Eina_List *sinks, *sources, *inputs, *cards; Eina_Bool connected; @@ -35,6 +34,7 @@ typedef struct _Sink { Emix_Sink base; int idx; + const char *pulse_name; } Sink; typedef struct _Sink_Input @@ -47,6 +47,7 @@ typedef struct _Source { Emix_Source base; int idx; + const char *pulse_name; } Source; typedef struct _Profile @@ -114,6 +115,7 @@ _sink_del(Sink *sink) eina_stringshare_del(sink->base.volume.channel_names[i]); free(sink->base.volume.channel_names); eina_stringshare_del(sink->base.name); + eina_stringshare_del(sink->pulse_name); free(sink); } @@ -143,6 +145,7 @@ _source_del(Source *source) eina_stringshare_del(source->base.volume.channel_names[i]); free(source->base.volume.channel_names); eina_stringshare_del(source->base.name); + eina_stringshare_del(source->pulse_name); free(source); } @@ -187,6 +190,7 @@ _sink_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol, sink = calloc(1, sizeof(Sink)); sink->idx = info->index; + sink->pulse_name = eina_stringshare_add(info->name); 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)); @@ -543,7 +547,8 @@ _source_cb(pa_context *c EINA_UNUSED, const pa_source_info *info, EINA_SAFETY_ON_NULL_RETURN(source); source->idx = info->index; - source->base.name = eina_stringshare_add(info->name); + source->pulse_name = eina_stringshare_add(info->name); + source->base.name = eina_stringshare_add(info->description); _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) @@ -642,6 +647,9 @@ static void _sink_default_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol, void *userdata EINA_UNUSED) { + Sink *sink; + Eina_List *l; + if (eol < 0) { if (pa_context_errno(c) == PA_ERR_NOENTITY) @@ -657,7 +665,50 @@ _sink_default_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol, DBG("sink index: %d\nsink name: %s", info->index, info->name); - ctx->default_sink = info->index; + EINA_LIST_FOREACH(ctx->sinks, l, sink) + { + Eina_Bool prev_default = sink->base.default_sink; + sink->base.default_sink = (uint32_t)sink->idx == info->index; + if (ctx->cb && prev_default != sink->base.default_sink) + ctx->cb((void *)ctx->userdata, EMIX_SINK_CHANGED_EVENT, + (Emix_Sink *)sink); + } + + if (ctx->cb) + ctx->cb((void *)ctx->userdata, EMIX_READY_EVENT, NULL); +} + +static void +_source_default_cb(pa_context *c EINA_UNUSED, const pa_source_info *info, int eol, + void *userdata EINA_UNUSED) +{ + Source *source; + Eina_List *l; + + if (eol < 0) + { + if (pa_context_errno(c) == PA_ERR_NOENTITY) + return; + + ERR("Source callback failure"); + return; + } + + if (eol > 0) + return; + + DBG("source index: %d\nsource name: %s", info->index, + info->name); + + EINA_LIST_FOREACH(ctx->sources, l, source) + { + Eina_Bool prev_default = source->base.default_source; + source->base.default_source = (uint32_t)source->idx == info->index; + if (ctx->cb && prev_default != source->base.default_source) + ctx->cb((void *)ctx->userdata, EMIX_SOURCE_CHANGED_EVENT, + (Emix_Source *)source); + } + if (ctx->cb) ctx->cb((void *)ctx->userdata, EMIX_READY_EVENT, NULL); } @@ -683,6 +734,14 @@ _server_info_cb(pa_context *c, const pa_server_info *info, return; } pa_operation_unref(o); + + if (!(o = pa_context_get_source_info_by_name(c, info->default_source_name, + _source_default_cb, userdata))) + { + ERR("pa_context_get_source_info_by_name() failed"); + return; + } + pa_operation_unref(o); } static int @@ -1369,12 +1428,60 @@ _sink_default_get(void) EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); EINA_LIST_FOREACH(ctx->sinks, l, s) - if (s->idx == ctx->default_sink) + if (s->base.default_sink) return (Emix_Sink *)s; return NULL; } +static void +_sink_default_set(Emix_Sink *sink) +{ + Sink *s = (Sink *)sink; + pa_operation* o; + + DBG("Set default sink: %s", sink->name); + if (!(o = pa_context_set_default_sink(ctx->context, s->pulse_name, NULL, NULL))) { + ERR("pa_context_set_default_sink() failed"); + return; + } + pa_operation_unref(o); +} + +static Eina_Bool +_source_default_support(void) +{ + return EINA_TRUE; +} + +static const Emix_Source * +_source_default_get(void) +{ + Source *s; + Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); + EINA_LIST_FOREACH(ctx->sources, l, s) + if (s->base.default_source) + return (Emix_Source *)s; + + return NULL; +} + +static void +_source_default_set(Emix_Source *source) +{ + Source *s = (Source *)source; + pa_operation* o; + + DBG("Set default sink: %s", source->name); + if (!(o = pa_context_set_default_source(ctx->context, s->pulse_name, NULL, NULL))) { + ERR("pa_context_set_default_source() failed"); + return; + } + pa_operation_unref(o); +} + static Eina_Bool _sink_change_support(void) { @@ -1424,7 +1531,7 @@ _pulseaudio_backend = _sinks_get, _sink_default_support, _sink_default_get, - NULL, + _sink_default_set, _sink_mute_set, _sink_volume_set, _sink_port_set, @@ -1434,6 +1541,9 @@ _pulseaudio_backend = _sink_input_volume_set, _sink_input_move, _sources_get, + _source_default_support, + _source_default_get, + _source_default_set, _source_mute_set, _source_volume_set, NULL, diff --git a/src/modules/mixer/lib/emix.c b/src/modules/mixer/lib/emix.c index ba2436d55..962e7e535 100644 --- a/src/modules/mixer/lib/emix.c +++ b/src/modules/mixer/lib/emix.c @@ -347,6 +347,34 @@ emix_sources_get(void) return ctx->loaded->ebackend_sources_get(); } +Eina_Bool +emix_source_default_support(void) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded && + ctx->loaded->ebackend_source_default_support), + EINA_FALSE); + return ctx->loaded->ebackend_source_default_support(); +} + +const Emix_Source* +emix_source_default_get(void) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded && + ctx->loaded->ebackend_source_default_get), + NULL); + return ctx->loaded->ebackend_source_default_get(); +} + +void +emix_source_default_set(Emix_Source *source) +{ + EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded && + ctx->loaded->ebackend_source_default_set && + source)); + + ctx->loaded->ebackend_source_default_set(source); +} + void emix_source_mute_set(Emix_Source *source, Eina_Bool mute) { @@ -428,5 +456,3 @@ emix_card_profile_set(Emix_Card *card, Emix_Profile *profile) return ctx->loaded->ebackend_card_profile_set(card, profile); } - - diff --git a/src/modules/mixer/lib/emix.h b/src/modules/mixer/lib/emix.h index 6b1e67094..5f2512310 100644 --- a/src/modules/mixer/lib/emix.h +++ b/src/modules/mixer/lib/emix.h @@ -62,6 +62,7 @@ typedef struct _Emix_Sink { const char *name; Emix_Volume volume; Eina_Bool mute; + Eina_Bool default_sink; Eina_List *ports; } Emix_Sink; @@ -78,6 +79,7 @@ typedef struct _Emix_Source { const char *name; Emix_Volume volume; Eina_Bool mute; + Eina_Bool default_source; } Emix_Source; typedef struct _Emix_Profile { @@ -122,6 +124,9 @@ typedef struct _Emix_Backend { Emix_Sink_Input *input, Emix_Sink *sink); const Eina_List* (*ebackend_sources_get)(void); + Eina_Bool (*ebackend_source_default_support)(void); + const Emix_Source* (*ebackend_source_default_get)(void); + void (*ebackend_source_default_set)(Emix_Source *source); void (*ebackend_source_mute_set)(Emix_Source *source, Eina_Bool mute); void (*ebackend_source_volume_set)(Emix_Source *source, @@ -179,6 +184,9 @@ E_API void emix_sink_input_sink_change(Emix_Sink_Input *input, Emix_Sink *sink); E_API const Eina_List* emix_sources_get(void); +E_API Eina_Bool emix_source_default_support(void); +E_API const Emix_Source* emix_source_default_get(void); +E_API void emix_source_default_set(Emix_Source *source); E_API void emix_source_mute_set(Emix_Source *source, Eina_Bool mute); E_API void emix_source_volume_set(Emix_Source *source,