forked from enlightenment/enlightenment
mixer - show a mic/recording slider if someothing is and icons
so now display icons for clients/apps that are playing anything back right now next to the vu meter. also if some app is recording something, display a slider for mic/input source volume and a list of icons that are recording too and a vu meter too for this (95% of the time things wont record so hide it then and only show when something does).
This commit is contained in:
parent
c5c994658d
commit
9376490ba8
|
@ -43,7 +43,6 @@ static void _sink_input_set(int volume, Eina_Bool muted, void *data);
|
|||
static int _sink_input_min_get(void *data);
|
||||
static int _sink_input_max_get(void *data);
|
||||
static const char *_sink_input_name_get(void *data);
|
||||
static pid_t _get_ppid(pid_t pid);
|
||||
static void _sink_input_event(int type, Emix_Sink_Input *input);
|
||||
static void _events_cb(void *data, enum Emix_Event type, void *event_info);
|
||||
static Eina_Bool _desklock_cb(void *data, int type, void *info);
|
||||
|
@ -85,6 +84,8 @@ static int _notification_id = 0;
|
|||
static Ecore_Exe *_emixer_exe = NULL;
|
||||
static Ecore_Event_Handler *_emix_exe_event_del_handler = NULL;
|
||||
|
||||
static const Emix_Source *_source_default = NULL;
|
||||
|
||||
static E_Action *_action_incr = NULL;
|
||||
static E_Action *_action_decr = NULL;
|
||||
static E_Action *_action_mute = NULL;
|
||||
|
@ -133,7 +134,7 @@ _notify(const int val)
|
|||
}
|
||||
|
||||
static void
|
||||
_volume_increase_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||
_volume_adjust(int step)
|
||||
{
|
||||
unsigned int i;
|
||||
Emix_Volume volume;
|
||||
|
@ -143,19 +144,21 @@ _volume_increase_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
|||
|
||||
if (!s->volume.channel_count) return;
|
||||
|
||||
if (BARRIER_CHECK(s->volume.volumes[0], s->volume.volumes[0] + VOLUME_STEP))
|
||||
return;
|
||||
if (step > 0)
|
||||
{
|
||||
if (BARRIER_CHECK(s->volume.volumes[0], s->volume.volumes[0] + step))
|
||||
return;
|
||||
}
|
||||
|
||||
volume.channel_count = s->volume.channel_count;
|
||||
volume.volumes = calloc(s->volume.channel_count, sizeof(int));
|
||||
for (i = 0; i < volume.channel_count; i++)
|
||||
{
|
||||
if (s->volume.volumes[i] < (emix_max_volume_get()) - VOLUME_STEP)
|
||||
volume.volumes[i] = s->volume.volumes[i] + VOLUME_STEP;
|
||||
else if (s->volume.volumes[i] < emix_max_volume_get())
|
||||
volume.volumes[i] = s->volume.volumes[i] + step;
|
||||
if (volume.volumes[i] < 0)
|
||||
volume.volumes[i] = 0;
|
||||
else if (volume.volumes[i] > emix_max_volume_get())
|
||||
volume.volumes[i] = emix_max_volume_get();
|
||||
else
|
||||
volume.volumes[i] = s->volume.volumes[i];
|
||||
}
|
||||
|
||||
emix_sink_volume_set(s, &volume);
|
||||
|
@ -164,27 +167,47 @@ _volume_increase_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
|||
free(volume.volumes);
|
||||
}
|
||||
|
||||
static void
|
||||
_volume_increase_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||
{
|
||||
_volume_adjust(VOLUME_STEP);
|
||||
}
|
||||
|
||||
static void
|
||||
_volume_decrease_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||
{
|
||||
_volume_adjust(-VOLUME_STEP);
|
||||
}
|
||||
|
||||
static void
|
||||
_volume_source_adjust(int step)
|
||||
{
|
||||
unsigned int i;
|
||||
Emix_Volume volume;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN(_sink_default);
|
||||
Emix_Sink *s = (Emix_Sink *)_sink_default;
|
||||
Emix_Source *s = (Emix_Source *)_source_default;
|
||||
|
||||
if (!s->volume.channel_count) return;
|
||||
|
||||
if (step > 0)
|
||||
{
|
||||
if (BARRIER_CHECK(s->volume.volumes[0], s->volume.volumes[0] + step))
|
||||
return;
|
||||
}
|
||||
|
||||
volume.channel_count = s->volume.channel_count;
|
||||
volume.volumes = calloc(s->volume.channel_count, sizeof(int));
|
||||
for (i = 0; i < volume.channel_count; i++)
|
||||
{
|
||||
if (s->volume.volumes[i] > VOLUME_STEP)
|
||||
volume.volumes[i] = s->volume.volumes[i] - VOLUME_STEP;
|
||||
else if (s->volume.volumes[i] < VOLUME_STEP)
|
||||
volume.volumes[i] = s->volume.volumes[i] + step;
|
||||
if (volume.volumes[i] < 0)
|
||||
volume.volumes[i] = 0;
|
||||
else
|
||||
volume.volumes[i] = s->volume.volumes[i];
|
||||
else if (volume.volumes[i] > emix_max_volume_get())
|
||||
volume.volumes[i] = emix_max_volume_get();
|
||||
}
|
||||
|
||||
emix_sink_volume_set((Emix_Sink *)_sink_default, &volume);
|
||||
emix_source_volume_set(s, &volume);
|
||||
emix_config_save_state_get();
|
||||
if (emix_config_save_get()) e_config_save_queue();
|
||||
free(volume.volumes);
|
||||
|
@ -497,8 +520,8 @@ _sink_input_name_get(void *data)
|
|||
return input->name;
|
||||
}
|
||||
|
||||
static pid_t
|
||||
_get_ppid(pid_t pid)
|
||||
EINTERN pid_t
|
||||
backend_util_get_ppid(pid_t pid)
|
||||
{
|
||||
int fd;
|
||||
char buf[128];
|
||||
|
@ -564,7 +587,7 @@ _sink_input_event(int type, Emix_Sink_Input *input)
|
|||
}
|
||||
}
|
||||
if (found) break;
|
||||
pid = _get_ppid(pid);
|
||||
pid = backend_util_get_ppid(pid);
|
||||
}
|
||||
break;
|
||||
case EMIX_SINK_INPUT_REMOVED_EVENT:
|
||||
|
@ -589,6 +612,75 @@ _sink_input_event(int type, Emix_Sink_Input *input)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_source_event(int type, Emix_Source *source)
|
||||
{
|
||||
const Eina_List *l;
|
||||
|
||||
if (type == EMIX_SOURCE_REMOVED_EVENT)
|
||||
{
|
||||
if (source == _source_default)
|
||||
{
|
||||
l = emix_sources_get();
|
||||
if (l) _source_default = l->data;
|
||||
else _source_default = NULL;
|
||||
if (emix_config_save_get()) e_config_save_queue();
|
||||
_backend_changed();
|
||||
}
|
||||
}
|
||||
else if (type == EMIX_SOURCE_CHANGED_EVENT)
|
||||
{
|
||||
/* If pulseaudio changed the default sink, swap the UI to display it
|
||||
instead of previously selected sink */
|
||||
if (source->default_source)
|
||||
_source_default = source;
|
||||
if (_source_default == source)
|
||||
{
|
||||
static int prev_vol = -1;
|
||||
int vol;
|
||||
|
||||
_backend_changed();
|
||||
if (source->mute || !source->volume.channel_count) vol = 0;
|
||||
else vol = source->volume.volumes[0];
|
||||
if (vol != prev_vol)
|
||||
{
|
||||
// _notify(vol);
|
||||
prev_vol = vol;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Source added");
|
||||
}
|
||||
/*
|
||||
Only safe the state if we are not in init mode,
|
||||
If we are in init mode, this is a result of the restore call.
|
||||
Restore iterates over a list of sinks which would get deleted in the
|
||||
save_state_get call.
|
||||
*/
|
||||
if (!_backend_init_flag)
|
||||
{
|
||||
emix_config_save_state_get();
|
||||
if (emix_config_save_get()) e_config_save_queue();
|
||||
// ecore_event_add(E_EVENT_MIXER_SINKS_CHANGED, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_event(int type, Emix_Source_Output *output EINA_UNUSED)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EMIX_SOURCE_OUTPUT_ADDED_EVENT:
|
||||
break;
|
||||
case EMIX_SOURCE_OUTPUT_REMOVED_EVENT:
|
||||
break;
|
||||
case EMIX_SOURCE_OUTPUT_CHANGED_EVENT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info)
|
||||
{
|
||||
|
@ -610,6 +702,16 @@ _events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info)
|
|||
case EMIX_SINK_INPUT_CHANGED_EVENT:
|
||||
_sink_input_event(type, event_info);
|
||||
break;
|
||||
case EMIX_SOURCE_ADDED_EVENT:
|
||||
case EMIX_SOURCE_CHANGED_EVENT:
|
||||
case EMIX_SOURCE_REMOVED_EVENT:
|
||||
_source_event(type, event_info);
|
||||
break;
|
||||
case EMIX_SOURCE_OUTPUT_ADDED_EVENT:
|
||||
case EMIX_SOURCE_OUTPUT_CHANGED_EVENT:
|
||||
case EMIX_SOURCE_OUTPUT_REMOVED_EVENT:
|
||||
_source_output_event(type, event_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -988,7 +1090,7 @@ _e_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
|||
_client_sinks = eina_list_append(_client_sinks, sink);
|
||||
return ECORE_CALLBACK_PASS_ON;
|
||||
}
|
||||
pid = _get_ppid(pid);
|
||||
pid = backend_util_get_ppid(pid);
|
||||
}
|
||||
}
|
||||
return ECORE_CALLBACK_PASS_ON;
|
||||
|
@ -1186,6 +1288,9 @@ backend_init(void)
|
|||
if (emix_sink_default_support())
|
||||
_sink_default = emix_sink_default_get();
|
||||
|
||||
if (emix_source_default_support())
|
||||
_source_default = emix_source_default_get();
|
||||
|
||||
_actions_register();
|
||||
|
||||
_border_hook = e_int_client_menu_hook_add(_bd_hook, NULL);
|
||||
|
@ -1348,3 +1453,77 @@ backend_sink_default_get(void)
|
|||
return _sink_default;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EINTERN Eina_Bool
|
||||
backend_source_active_get(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(_source_default, EINA_FALSE);
|
||||
if (emix_source_outputs_get()) return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
backend_source_volume_decrease(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(_source_default);
|
||||
_volume_source_adjust(-VOLUME_STEP);
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
backend_source_volume_increase(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(_source_default);
|
||||
_volume_source_adjust(VOLUME_STEP);
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
backend_source_mute_set(Eina_Bool mute)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(_source_default);
|
||||
|
||||
DBG("Source default mute set %d", mute);
|
||||
emix_source_mute_set((Emix_Source *)_source_default, mute);
|
||||
emix_config_save_state_get();
|
||||
if (emix_config_save_get()) e_config_save_queue();
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
backend_source_mute_get(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(_source_default, EINA_FALSE);
|
||||
return _source_default->mute;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
backend_source_volume_set(unsigned int volume)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(_source_default);
|
||||
DBG("Sink default mute set %d", volume);
|
||||
|
||||
VOLSET(volume, ((Emix_Source *)_source_default)->volume,
|
||||
(Emix_Source *)_source_default, emix_source_volume_set);
|
||||
emix_config_save_state_get();
|
||||
if (emix_config_save_get()) e_config_save_queue();
|
||||
}
|
||||
|
||||
EINTERN unsigned int
|
||||
backend_source_volume_get(void)
|
||||
{
|
||||
unsigned int volume = 0, i;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(_source_default, 0);
|
||||
for (i = 0; i < _source_default->volume.channel_count; i++)
|
||||
volume += _source_default->volume.volumes[i];
|
||||
if (_source_default->volume.channel_count)
|
||||
volume = volume / _source_default->volume.channel_count;
|
||||
|
||||
DBG("Source default volume get %d", volume);
|
||||
return volume;
|
||||
}
|
||||
|
||||
EINTERN const Emix_Source *
|
||||
backend_source_default_get(void)
|
||||
{
|
||||
return _source_default;
|
||||
}
|
||||
|
|
|
@ -21,4 +21,15 @@ EINTERN Eina_Bool backend_mute_get(void);
|
|||
EINTERN void backend_sink_default_set(const Emix_Sink *s);
|
||||
EINTERN const Emix_Sink *backend_sink_default_get(void);
|
||||
|
||||
EINTERN Eina_Bool backend_source_active_get(void);
|
||||
EINTERN void backend_source_volume_decrease(void);
|
||||
EINTERN void backend_source_volume_increase(void);
|
||||
EINTERN void backend_source_mute_set(Eina_Bool mute);
|
||||
EINTERN Eina_Bool backend_source_mute_get(void);
|
||||
EINTERN void backend_source_volume_set(unsigned int volume);
|
||||
EINTERN unsigned int backend_source_volume_get(void);
|
||||
EINTERN const Emix_Source *backend_source_default_get(void);
|
||||
|
||||
EINTERN pid_t backend_util_get_ppid(pid_t pid);
|
||||
|
||||
#endif /* MIXER_GADGET_BACKEND */
|
||||
|
|
|
@ -51,6 +51,7 @@ typedef struct _Mon_Data Mon_Data;
|
|||
struct _Mon_Data
|
||||
{
|
||||
Emix_Sink *sink;
|
||||
Emix_Source *source;
|
||||
Evas_Object *vu;
|
||||
Ecore_Animator *animator;
|
||||
float samp_max;
|
||||
|
@ -70,9 +71,19 @@ struct _Instance
|
|||
Evas_Object *gadget;
|
||||
Evas_Object *list;
|
||||
Evas_Object *slider;
|
||||
Evas_Object *slider_ic;
|
||||
Evas_Object *check;
|
||||
Evas_Object *vu;
|
||||
Evas_Object *playback_box;
|
||||
Evas_Object *recbox;
|
||||
Evas_Object *recslider;
|
||||
Evas_Object *reccheck;
|
||||
Evas_Object *recbx;
|
||||
Evas_Object *recic;
|
||||
Evas_Object *recvu;
|
||||
Evas_Object *recording_box;
|
||||
Mon_Data mon_data;
|
||||
Mon_Data recmon_data;
|
||||
};
|
||||
|
||||
static Context *mixer_context = NULL;
|
||||
|
@ -122,6 +133,29 @@ _sink_icon_find(const char *name)
|
|||
static void _sink_unmonitor(Instance *inst, Emix_Sink *s);
|
||||
static void _sink_monitor(Instance *inst, Emix_Sink *s);
|
||||
|
||||
static void _source_unmonitor(Instance *inst, Emix_Source *s);
|
||||
static void _source_monitor(Instance *inst, Emix_Source *s);
|
||||
|
||||
static void _popup_playback_box_refill(Instance *inst);
|
||||
static void _popup_recording_fill(Instance *inst);
|
||||
|
||||
static void
|
||||
_cb_emix_event(void *data, enum Emix_Event event, void *event_info EINA_UNUSED)
|
||||
{
|
||||
Instance *inst = data;
|
||||
|
||||
if ((event == EMIX_SINK_INPUT_ADDED_EVENT) ||
|
||||
(event == EMIX_SINK_INPUT_REMOVED_EVENT))
|
||||
{
|
||||
_popup_playback_box_refill(inst);
|
||||
}
|
||||
else if ((event == EMIX_SOURCE_OUTPUT_ADDED_EVENT) ||
|
||||
(event == EMIX_SOURCE_OUTPUT_REMOVED_EVENT))
|
||||
{
|
||||
_popup_recording_fill(inst);
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_emix_monitor_update(void *data)
|
||||
{
|
||||
|
@ -171,9 +205,70 @@ _cb_emix_sink_monitor_event(void *data, enum Emix_Event event, void *event_info)
|
|||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_emix_source_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_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_source_monitor_update, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_mixer_popup_update(Instance *inst, int mute, int vol)
|
||||
{
|
||||
Emix_Sink *s;
|
||||
char *icname = NULL;
|
||||
|
||||
s = (Emix_Sink *)backend_sink_default_get();
|
||||
if (s)
|
||||
{
|
||||
if (s->name) icname = _sink_icon_find(s->name);
|
||||
if (!icname) icname = strdup("audio-volume");
|
||||
|
||||
elm_icon_standard_set(inst->slider_ic, icname);
|
||||
free(icname);
|
||||
}
|
||||
elm_check_state_set(inst->check, !!mute);
|
||||
elm_slider_value_set(inst->slider, vol);
|
||||
}
|
||||
|
@ -235,9 +330,18 @@ static void
|
|||
_popup_del(Instance *inst)
|
||||
{
|
||||
inst->slider = NULL;
|
||||
inst->slider_ic = NULL;
|
||||
inst->check = NULL;
|
||||
inst->list = NULL;
|
||||
inst->vu = NULL;
|
||||
inst->playback_box = NULL;
|
||||
inst->recbox = NULL;
|
||||
inst->recslider = NULL;
|
||||
inst->reccheck = NULL;
|
||||
inst->recbx = NULL;
|
||||
inst->recvu = NULL;
|
||||
inst->recording_box = NULL;
|
||||
emix_event_callback_del(_cb_emix_event, inst);
|
||||
if (inst->mon_data.sink) _sink_unmonitor(inst, inst->mon_data.sink);
|
||||
E_FREE_FUNC(inst->popup, e_object_del);
|
||||
}
|
||||
|
@ -321,6 +425,39 @@ _sink_monitor(Instance *inst, Emix_Sink *s)
|
|||
emix_sink_monitor(md->sink, EINA_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
_source_unmonitor(Instance *inst, Emix_Source *s)
|
||||
{
|
||||
Mon_Data *md = &(inst->recmon_data);
|
||||
if (md->source != s) return;
|
||||
emix_event_callback_del(_cb_emix_source_monitor_event, md);
|
||||
if (md->animator)
|
||||
{
|
||||
ecore_animator_del(md->animator);
|
||||
md->animator = NULL;
|
||||
}
|
||||
emix_source_monitor(md->source, EINA_FALSE);
|
||||
md->source = NULL;
|
||||
md->vu = NULL;
|
||||
md->mon_update = 0;
|
||||
md->samp_max = 0;
|
||||
md->mon_skips = 0;
|
||||
md->mon_samps = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_source_monitor(Instance *inst, Emix_Source *s)
|
||||
{
|
||||
Mon_Data *md = &(inst->recmon_data);
|
||||
if (md->source == s) return;
|
||||
|
||||
if (md->source) _source_unmonitor(inst, md->source);
|
||||
md->source = s;
|
||||
md->vu = inst->recvu;
|
||||
emix_event_callback_add(_cb_emix_source_monitor_event, md);
|
||||
emix_source_monitor(md->source, EINA_TRUE);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_mixer_sinks_changed(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
|
||||
{
|
||||
|
@ -372,13 +509,260 @@ _cb_vu_format_cb(double v EINA_UNUSED)
|
|||
return "";
|
||||
}
|
||||
|
||||
static void
|
||||
_popup_playback_box_refill(Instance *inst)
|
||||
{
|
||||
Evas_Object *ic;
|
||||
Eina_List *children, *l, *del_list = NULL;
|
||||
Eina_List *playbacks;
|
||||
Evas_Object *o;
|
||||
Emix_Sink_Input *s;
|
||||
int num = 0;
|
||||
|
||||
children = elm_box_children_get(inst->playback_box);
|
||||
EINA_LIST_FOREACH(children, l, o)
|
||||
{
|
||||
// skip first item - it's the rect spacer
|
||||
if (l->prev) del_list = eina_list_append(del_list, o);
|
||||
}
|
||||
EINA_LIST_FREE(del_list, o) evas_object_del(o);
|
||||
playbacks = (Eina_List *)emix_sink_inputs_get();
|
||||
printf("MX: playbacks %p\n", playbacks);
|
||||
EINA_LIST_FOREACH(playbacks, l, s)
|
||||
{
|
||||
E_Client *ec = NULL;
|
||||
Eina_List *clients, *ll;
|
||||
pid_t pid;
|
||||
|
||||
ic = NULL;
|
||||
pid = s->pid;
|
||||
printf("MX: + PID %i\n", pid);
|
||||
for (;;)
|
||||
{
|
||||
if ((pid <= 1) || (pid == getpid())) return;
|
||||
|
||||
clients = e_client_focus_stack_get();
|
||||
EINA_LIST_FOREACH(clients, ll, ec)
|
||||
{
|
||||
if ((ec->netwm.pid == pid) && (!ec->parent))
|
||||
{
|
||||
ic = e_client_icon_add(ec, e_comp->evas);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pid = backend_util_get_ppid(pid);
|
||||
if (ic) break;
|
||||
}
|
||||
if (!ic)
|
||||
{
|
||||
if (s->icon)
|
||||
{
|
||||
ic = elm_icon_add(e_comp->elm);
|
||||
elm_icon_standard_set(ic, s->icon);
|
||||
}
|
||||
}
|
||||
if (ic)
|
||||
{
|
||||
printf("MX: + %p\n", ic);
|
||||
evas_object_size_hint_min_set(ic, 20 * e_scale, 20 * e_scale);
|
||||
elm_box_pack_end(inst->playback_box, ic);
|
||||
evas_object_show(ic);
|
||||
}
|
||||
|
||||
// max 8 app icons
|
||||
num++;
|
||||
if (num > 8) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_reccheck_changed_cb(void *data EINA_UNUSED, Evas_Object *obj,
|
||||
void *event EINA_UNUSED)
|
||||
{
|
||||
backend_source_mute_set(elm_check_state_get(obj));
|
||||
}
|
||||
|
||||
static void
|
||||
_recslider_changed_cb(void *data EINA_UNUSED, Evas_Object *obj,
|
||||
void *event EINA_UNUSED)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = (int)elm_slider_value_get(obj);
|
||||
backend_source_volume_set(val);
|
||||
}
|
||||
|
||||
static void
|
||||
_popup_recording_box_refill(Instance *inst)
|
||||
{
|
||||
Evas_Object *ic;
|
||||
Eina_List *children, *l, *del_list = NULL;
|
||||
Eina_List *recordings;
|
||||
Evas_Object *o;
|
||||
Emix_Source_Output *s;
|
||||
int num = 0;
|
||||
|
||||
children = elm_box_children_get(inst->recording_box);
|
||||
EINA_LIST_FOREACH(children, l, o)
|
||||
{
|
||||
// skip first item - it's the rect spacer
|
||||
if (l->prev) del_list = eina_list_append(del_list, o);
|
||||
}
|
||||
EINA_LIST_FREE(del_list, o) evas_object_del(o);
|
||||
recordings = (Eina_List *)emix_source_outputs_get();
|
||||
EINA_LIST_FOREACH(recordings, l, s)
|
||||
{
|
||||
E_Client *ec = NULL;
|
||||
Eina_List *clients, *ll;
|
||||
pid_t pid;
|
||||
|
||||
ic = NULL;
|
||||
pid = s->pid;
|
||||
for (;;)
|
||||
{
|
||||
if ((pid <= 1) || (pid == getpid())) return;
|
||||
|
||||
clients = e_client_focus_stack_get();
|
||||
EINA_LIST_FOREACH(clients, ll, ec)
|
||||
{
|
||||
if ((ec->netwm.pid == pid) && (!ec->parent))
|
||||
{
|
||||
ic = e_client_icon_add(ec, e_comp->evas);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pid = backend_util_get_ppid(pid);
|
||||
if (ic) break;
|
||||
}
|
||||
if (!ic)
|
||||
{
|
||||
if (s->icon)
|
||||
{
|
||||
ic = elm_icon_add(e_comp->elm);
|
||||
elm_icon_standard_set(ic, s->icon);
|
||||
}
|
||||
}
|
||||
if (ic)
|
||||
{
|
||||
evas_object_size_hint_min_set(ic, 20 * e_scale, 20 * e_scale);
|
||||
elm_box_pack_end(inst->recording_box, ic);
|
||||
evas_object_show(ic);
|
||||
}
|
||||
|
||||
// max 8 app icons
|
||||
num++;
|
||||
if (num > 8) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_popup_recording_fill(Instance *inst)
|
||||
{
|
||||
Emix_Source *ss;
|
||||
|
||||
if (inst->recording_box) evas_object_del(inst->recording_box);
|
||||
if (inst->recvu) evas_object_del(inst->recvu);
|
||||
if (inst->recic) evas_object_del(inst->recic);
|
||||
if (inst->recbx) evas_object_del(inst->recbx);
|
||||
if (inst->reccheck) evas_object_del(inst->reccheck);
|
||||
if (inst->recslider) evas_object_del(inst->recslider);
|
||||
|
||||
inst->recslider = NULL;
|
||||
inst->reccheck = NULL;
|
||||
inst->recbx = NULL;
|
||||
inst->recvu = NULL;
|
||||
inst->recording_box = NULL;
|
||||
|
||||
ss = (Emix_Source *)backend_source_default_get();
|
||||
if (ss) _source_unmonitor(inst, ss);
|
||||
|
||||
if (backend_source_active_get())
|
||||
{
|
||||
Evas_Object *bx, *r, *slider, *ic;
|
||||
|
||||
bx = elm_box_add(e_comp->elm);
|
||||
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.5);
|
||||
elm_box_pack_end(inst->recbox, bx);
|
||||
evas_object_show(bx);
|
||||
|
||||
inst->recvu = elm_progressbar_add(e_comp->elm);
|
||||
elm_progressbar_unit_format_function_set(inst->recvu, _cb_vu_format_cb, NULL);
|
||||
evas_object_size_hint_weight_set(inst->recvu, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(inst->recvu, EVAS_HINT_FILL, 0.5);
|
||||
elm_box_pack_end(bx, inst->recvu);
|
||||
evas_object_show(inst->recvu);
|
||||
|
||||
inst->recording_box = elm_box_add(e_comp->elm);
|
||||
elm_box_horizontal_set(inst->recording_box, EINA_TRUE);
|
||||
evas_object_size_hint_weight_set(inst->recording_box, 0.0, 0.0);
|
||||
evas_object_size_hint_align_set(inst->recording_box, 1.0, 0.5);
|
||||
elm_box_pack_end(bx, inst->recording_box);
|
||||
evas_object_show(inst->recording_box);
|
||||
|
||||
r = evas_object_rectangle_add(evas_object_evas_get(e_comp->elm));
|
||||
evas_object_size_hint_min_set(r, 0, 20 * e_scale);
|
||||
evas_object_color_set(r, 0, 0, 0, 0);
|
||||
elm_box_pack_end(inst->recording_box, r);
|
||||
|
||||
_popup_recording_box_refill(inst);
|
||||
|
||||
bx = elm_box_add(e_comp->elm);
|
||||
inst->recbx = 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);
|
||||
elm_box_pack_end(inst->recbox, bx);
|
||||
evas_object_show(bx);
|
||||
|
||||
ss = (Emix_Source *)backend_source_default_get();
|
||||
if (ss)
|
||||
{
|
||||
ic = elm_icon_add(e_comp->elm);
|
||||
inst->recic = ic;
|
||||
evas_object_size_hint_min_set(ic, 20 * e_scale, 20 * e_scale);
|
||||
elm_icon_standard_set(ic, "audio-input-microphone");
|
||||
elm_box_pack_end(bx, ic);
|
||||
evas_object_show(ic);
|
||||
}
|
||||
|
||||
slider = elm_slider_add(e_comp->elm);
|
||||
inst->recslider = slider;
|
||||
elm_slider_span_size_set(slider, 128 * elm_config_scale_get());
|
||||
elm_slider_unit_format_set(slider, "%1.0f");
|
||||
elm_slider_indicator_format_set(slider, "%1.0f");
|
||||
evas_object_size_hint_align_set(slider, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
evas_object_size_hint_weight_set(slider, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_show(slider);
|
||||
elm_slider_min_max_set(slider, 0.0, emix_max_volume_get());
|
||||
evas_object_smart_callback_add(slider, "changed", _recslider_changed_cb, NULL);
|
||||
elm_slider_value_set(slider, backend_source_volume_get());
|
||||
elm_box_pack_end(bx, slider);
|
||||
evas_object_show(slider);
|
||||
|
||||
inst->reccheck = elm_check_add(e_comp->elm);
|
||||
evas_object_size_hint_align_set(inst->reccheck, 0.5, EVAS_HINT_FILL);
|
||||
elm_object_text_set(inst->reccheck, _("Mute"));
|
||||
elm_check_state_set(inst->reccheck, backend_source_mute_get());
|
||||
evas_object_smart_callback_add(inst->reccheck, "changed", _reccheck_changed_cb, NULL);
|
||||
elm_box_pack_end(bx, inst->reccheck);
|
||||
evas_object_show(inst->reccheck);
|
||||
|
||||
if (ss) _source_monitor(inst, ss);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_popup_new(Instance *inst)
|
||||
{
|
||||
Evas_Object *button, *list, *slider, *bx, *ic;
|
||||
Evas_Object *button, *list, *slider, *bx, *ic, *r;
|
||||
Emix_Sink *s;
|
||||
Eina_List *l;
|
||||
Elm_Object_Item *default_it = NULL;
|
||||
char *icname = NULL;
|
||||
|
||||
emix_event_callback_add(_cb_emix_event, inst);
|
||||
|
||||
inst->popup = e_gadcon_popup_new(inst->gcc, 0);
|
||||
list = elm_box_add(e_comp->elm);
|
||||
|
@ -391,19 +775,55 @@ _popup_new(Instance *inst)
|
|||
elm_box_pack_end(list, inst->list);
|
||||
|
||||
bx = elm_box_add(e_comp->elm);
|
||||
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.5);
|
||||
elm_box_pack_end(list, bx);
|
||||
evas_object_show(bx);
|
||||
|
||||
inst->vu = elm_progressbar_add(e_comp->elm);
|
||||
elm_progressbar_unit_format_function_set(inst->vu, _cb_vu_format_cb, NULL);
|
||||
evas_object_size_hint_weight_set(inst->vu, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(inst->vu, EVAS_HINT_FILL, 0.0);
|
||||
elm_box_pack_end(list, inst->vu);
|
||||
evas_object_size_hint_align_set(inst->vu, EVAS_HINT_FILL, 0.5);
|
||||
elm_box_pack_end(bx, inst->vu);
|
||||
evas_object_show(inst->vu);
|
||||
|
||||
inst->playback_box = elm_box_add(e_comp->elm);
|
||||
elm_box_horizontal_set(inst->playback_box, EINA_TRUE);
|
||||
evas_object_size_hint_weight_set(inst->playback_box, 0.0, 0.0);
|
||||
evas_object_size_hint_align_set(inst->playback_box, 1.0, 0.5);
|
||||
elm_box_pack_end(bx, inst->playback_box);
|
||||
evas_object_show(inst->playback_box);
|
||||
|
||||
r = evas_object_rectangle_add(evas_object_evas_get(e_comp->elm));
|
||||
evas_object_size_hint_min_set(r, 0, 20 * e_scale);
|
||||
evas_object_color_set(r, 0, 0, 0, 0);
|
||||
elm_box_pack_end(inst->playback_box, r);
|
||||
|
||||
_popup_playback_box_refill(inst);
|
||||
|
||||
bx = elm_box_add(e_comp->elm);
|
||||
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);
|
||||
elm_box_pack_end(list, bx);
|
||||
evas_object_show(bx);
|
||||
|
||||
s = (Emix_Sink *)backend_sink_default_get();
|
||||
if (s)
|
||||
{
|
||||
if (s->name) icname = _sink_icon_find(s->name);
|
||||
if (!icname) icname = strdup("audio-volume");
|
||||
|
||||
ic = elm_icon_add(e_comp->elm);
|
||||
evas_object_size_hint_min_set(ic, 20 * e_scale, 20 * e_scale);
|
||||
elm_icon_standard_set(ic, icname);
|
||||
free(icname);
|
||||
elm_box_pack_end(bx, ic);
|
||||
evas_object_show(ic);
|
||||
inst->slider_ic = ic;
|
||||
}
|
||||
|
||||
slider = elm_slider_add(e_comp->elm);
|
||||
inst->slider = slider;
|
||||
elm_slider_span_size_set(slider, 128 * elm_config_scale_get());
|
||||
|
@ -427,6 +847,14 @@ _popup_new(Instance *inst)
|
|||
elm_box_pack_end(bx, inst->check);
|
||||
evas_object_show(inst->check);
|
||||
|
||||
inst->recbox = elm_box_add(e_comp->elm);
|
||||
evas_object_size_hint_align_set(inst->recbox, EVAS_HINT_FILL, 0.5);
|
||||
evas_object_size_hint_weight_set(inst->recbox, EVAS_HINT_EXPAND, 0.0);
|
||||
elm_box_pack_end(list, inst->recbox);
|
||||
evas_object_show(inst->recbox);
|
||||
|
||||
_popup_recording_fill(inst);
|
||||
|
||||
button = elm_button_add(e_comp->elm);
|
||||
evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0.0);
|
||||
|
@ -438,7 +866,6 @@ _popup_new(Instance *inst)
|
|||
EINA_LIST_FOREACH((Eina_List *)emix_sinks_get(), l, s)
|
||||
{
|
||||
Elm_Object_Item *it;
|
||||
char *icname = NULL;
|
||||
|
||||
if (s->name) icname = _sink_icon_find(s->name);
|
||||
if (!icname) icname = strdup("audio-volume");
|
||||
|
@ -456,7 +883,7 @@ _popup_new(Instance *inst)
|
|||
}
|
||||
elm_list_go(inst->list);
|
||||
|
||||
evas_object_size_hint_min_set(list, 240 * e_scale, 240 * e_scale);
|
||||
evas_object_size_hint_min_set(list, 240 * e_scale, 280 * e_scale);
|
||||
|
||||
e_gadcon_popup_content_set(inst->popup, list);
|
||||
e_comp_object_util_autoclose(inst->popup->comp_object,
|
||||
|
|
|
@ -525,22 +525,26 @@ _alsa_backend =
|
|||
_alsa_sink_volume_set, /*volume_set*/
|
||||
NULL, /* port set */
|
||||
_alsa_support, /*change support*/
|
||||
NULL, /*sink input get*/
|
||||
NULL,/*sink input mute set*/
|
||||
NULL,/*sink input volume set*/
|
||||
NULL,/*sink input sink change*/
|
||||
NULL, /*sink inputs get*/
|
||||
NULL, /*sink input mute set*/
|
||||
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, /*source outputs get*/
|
||||
NULL, /*source output mute set*/
|
||||
NULL, /*source output volume set*/
|
||||
NULL, /*source output source change*/
|
||||
NULL, /* advanced options */
|
||||
NULL, /* card list */
|
||||
NULL, /* card profile set */
|
||||
NULL, /* sink monitor set */
|
||||
NULL, /* sink input monitor set */
|
||||
NULL /* ssource monitor set */
|
||||
NULL /* source monitor set */
|
||||
};
|
||||
|
||||
E_API Emix_Backend *
|
||||
|
|
|
@ -26,7 +26,7 @@ typedef struct _Context
|
|||
const void *userdata;
|
||||
Ecore_Timer *connect;
|
||||
|
||||
Eina_List *sinks, *sources, *inputs, *cards;
|
||||
Eina_List *sinks, *sources, *inputs, *outputs, *cards;
|
||||
Eina_Bool connected;
|
||||
} Context;
|
||||
|
||||
|
@ -59,6 +59,13 @@ typedef struct _Source
|
|||
pa_stream *mon_stream;
|
||||
} Source;
|
||||
|
||||
typedef struct _Source_Output
|
||||
{
|
||||
Emix_Source_Output base;
|
||||
int idx, source_idx;
|
||||
Eina_Bool running : 1;
|
||||
} Source_Output;
|
||||
|
||||
typedef struct _Profile
|
||||
{
|
||||
Emix_Profile base;
|
||||
|
@ -168,6 +175,21 @@ _source_del(Source *source)
|
|||
free(source);
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_del(Source_Output *output)
|
||||
{
|
||||
unsigned int i;
|
||||
EINA_SAFETY_ON_NULL_RETURN(output);
|
||||
|
||||
free(output->base.volume.volumes);
|
||||
for(i = 0; i < output->base.volume.channel_count; ++i)
|
||||
eina_stringshare_del(output->base.volume.channel_names[i]);
|
||||
free(output->base.volume.channel_names);
|
||||
eina_stringshare_del(output->base.name);
|
||||
eina_stringshare_del(output->base.icon);
|
||||
free(output);
|
||||
}
|
||||
|
||||
static void
|
||||
_card_del(Card *card)
|
||||
{
|
||||
|
@ -728,6 +750,189 @@ _source_remove_cb(int index, void *data EINA_UNUSED)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_state_running_set(Source_Output *output, Eina_Bool running)
|
||||
{
|
||||
output->running = running;
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_cb(pa_context *c EINA_UNUSED, const pa_source_output_info *info,
|
||||
int eol, void *userdata EINA_UNUSED)
|
||||
{
|
||||
Source_Output *output;
|
||||
Eina_List *l;
|
||||
Source *s;
|
||||
const char *t;
|
||||
unsigned int i;
|
||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||
|
||||
if (eol < 0)
|
||||
{
|
||||
if (pa_context_errno(c) == PA_ERR_NOENTITY)
|
||||
return;
|
||||
|
||||
ERR("Source output callback failure");
|
||||
return;
|
||||
}
|
||||
|
||||
if (eol > 0)
|
||||
return;
|
||||
|
||||
if ((info->name) && (!strcmp(info->name, "__e_mon"))) return;
|
||||
|
||||
output = calloc(1, sizeof(Source_Output));
|
||||
EINA_SAFETY_ON_NULL_RETURN(output);
|
||||
|
||||
DBG("source output index: %d\nsink input name: %s", info->index,
|
||||
info->name);
|
||||
|
||||
output->idx = info->index;
|
||||
output->source_idx = info->source;
|
||||
|
||||
Eina_Strbuf *output_name;
|
||||
|
||||
output_name = eina_strbuf_new();
|
||||
const char *application = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_NAME);
|
||||
if (application)
|
||||
{
|
||||
eina_strbuf_append(output_name, application);
|
||||
eina_strbuf_append(output_name, ":");
|
||||
eina_strbuf_append(output_name, info->name);
|
||||
}
|
||||
else if (info->name)
|
||||
{
|
||||
eina_strbuf_append(output_name, info->name);
|
||||
}
|
||||
output->base.name = eina_stringshare_add(eina_strbuf_string_get(output_name));
|
||||
eina_strbuf_free(output_name);
|
||||
_pa_cvolume_convert(&info->volume, &output->base.volume);
|
||||
output->base.volume.channel_names = calloc(output->base.volume.channel_count, sizeof(Emix_Channel));
|
||||
for (i = 0; i < output->base.volume.channel_count; ++i)
|
||||
output->base.volume.channel_names[i] = eina_stringshare_add(pa_channel_position_to_pretty_string(info->channel_map.map[i]));
|
||||
output->base.mute = !!info->mute;
|
||||
EINA_LIST_FOREACH(ctx->sources, l, s)
|
||||
{
|
||||
if (s->idx == (int)info->source)
|
||||
output->base.source = (Emix_Source *)s;
|
||||
}
|
||||
output->base.icon = eina_stringshare_add(_icon_from_properties(info->proplist));
|
||||
ctx->outputs = eina_list_append(ctx->outputs, output);
|
||||
|
||||
if ((t = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_PROCESS_ID)))
|
||||
{
|
||||
output->base.pid = atoi(t);
|
||||
}
|
||||
if (!info->corked) _source_output_state_running_set(output, EINA_TRUE);
|
||||
else _source_output_state_running_set(output, EINA_FALSE);
|
||||
|
||||
if (ctx->cb)
|
||||
ctx->cb((void *)ctx->userdata, EMIX_SOURCE_OUTPUT_ADDED_EVENT,
|
||||
(Emix_Source_Output *)output);
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_changed_cb(pa_context *c EINA_UNUSED,
|
||||
const pa_source_output_info *info, int eol,
|
||||
void *userdata EINA_UNUSED)
|
||||
{
|
||||
Source_Output *output = NULL, *so;
|
||||
Source *s = NULL;
|
||||
Eina_List *l;
|
||||
const char *t;
|
||||
unsigned int i;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||
if (eol < 0)
|
||||
{
|
||||
if (pa_context_errno(c) == PA_ERR_NOENTITY)
|
||||
return;
|
||||
|
||||
ERR("Source output changed callback failure");
|
||||
return;
|
||||
}
|
||||
|
||||
if (eol > 0)
|
||||
return;
|
||||
|
||||
if ((info->name) && (!strcmp(info->name, "__e_mon"))) return;
|
||||
|
||||
EINA_LIST_FOREACH(ctx->outputs, l, so)
|
||||
{
|
||||
if (so->idx == (int)info->index)
|
||||
{
|
||||
output = so;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("source output changed index: %d\n", info->index);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
output = calloc(1, sizeof(Source_Output));
|
||||
EINA_SAFETY_ON_NULL_RETURN(output);
|
||||
ctx->outputs = eina_list_append(ctx->outputs, output);
|
||||
}
|
||||
output->idx = info->index;
|
||||
output->source_idx = info->source;
|
||||
if (output->base.volume.channel_count != info->volume.channels)
|
||||
{
|
||||
for (i = 0; i < output->base.volume.channel_count; ++i)
|
||||
eina_stringshare_del(output->base.volume.channel_names[i]);
|
||||
free(output->base.volume.channel_names);
|
||||
output->base.volume.channel_names = calloc(info->volume.channels, sizeof(Emix_Channel));
|
||||
}
|
||||
_pa_cvolume_convert(&info->volume, &output->base.volume);
|
||||
for (i = 0; i < output->base.volume.channel_count; ++i)
|
||||
eina_stringshare_replace(&output->base.volume.channel_names[i],
|
||||
pa_channel_position_to_pretty_string(info->channel_map.map[i]));
|
||||
|
||||
output->base.mute = !!info->mute;
|
||||
|
||||
EINA_LIST_FOREACH(ctx->sources, l, s)
|
||||
{
|
||||
if (s->idx == (int)info->source)
|
||||
output->base.source = (Emix_Source *)s;
|
||||
}
|
||||
if ((t = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_PROCESS_ID)))
|
||||
{
|
||||
output->base.pid = atoi(t);
|
||||
}
|
||||
|
||||
if (!info->corked) _source_output_state_running_set(output, EINA_TRUE);
|
||||
else _source_output_state_running_set(output, EINA_FALSE);
|
||||
|
||||
if (ctx->cb)
|
||||
ctx->cb((void *)ctx->userdata, EMIX_SOURCE_OUTPUT_CHANGED_EVENT,
|
||||
(Emix_Source_Output *)output);
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_remove_cb(int index, void *data EINA_UNUSED)
|
||||
{
|
||||
Source_Output *output;
|
||||
Eina_List *l;
|
||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||
|
||||
DBG("Removing source output: %d", index);
|
||||
|
||||
EINA_LIST_FOREACH(ctx->outputs, l, output)
|
||||
{
|
||||
if (output->idx == index)
|
||||
{
|
||||
ctx->outputs = eina_list_remove_list(ctx->outputs, l);
|
||||
if (ctx->cb)
|
||||
ctx->cb((void *)ctx->userdata,
|
||||
EMIX_SOURCE_OUTPUT_REMOVED_EVENT,
|
||||
(Emix_Source_Output *)output);
|
||||
_source_output_del(output);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_sink_default_cb(pa_context *c EINA_UNUSED, const pa_sink_info *info, int eol,
|
||||
void *userdata EINA_UNUSED)
|
||||
|
@ -1093,6 +1298,33 @@ _subscribe_cb(pa_context *c, pa_subscription_event_type_t t,
|
|||
pa_operation_unref(o);
|
||||
}
|
||||
break;
|
||||
case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
|
||||
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) ==
|
||||
PA_SUBSCRIPTION_EVENT_REMOVE)
|
||||
_source_output_remove_cb(index, data);
|
||||
else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) ==
|
||||
PA_SUBSCRIPTION_EVENT_NEW)
|
||||
{
|
||||
if (!(o = pa_context_get_source_output_info(c, index,
|
||||
_source_output_cb, data)))
|
||||
{
|
||||
ERR("pa_context_get_source_info() failed");
|
||||
return;
|
||||
}
|
||||
pa_operation_unref(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(o = pa_context_get_source_output_info(c, index,
|
||||
_source_output_changed_cb,
|
||||
data)))
|
||||
{
|
||||
ERR("pa_context_get_source_info() failed");
|
||||
return;
|
||||
}
|
||||
pa_operation_unref(o);
|
||||
}
|
||||
break;
|
||||
case PA_SUBSCRIPTION_EVENT_SERVER:
|
||||
if (!(o = pa_context_get_server_info(c, _server_info_cb,
|
||||
data)))
|
||||
|
@ -1195,6 +1427,14 @@ _pulse_pa_state_cb(pa_context *context, void *data)
|
|||
}
|
||||
pa_operation_unref(o);
|
||||
|
||||
if (!(o = pa_context_get_source_output_info_list(context, _source_output_cb,
|
||||
ctx)))
|
||||
{
|
||||
ERR("pa_context_get_source_output_info_list() failed");
|
||||
return;
|
||||
}
|
||||
pa_operation_unref(o);
|
||||
|
||||
if (!(o = pa_context_get_server_info(context, _server_info_cb,
|
||||
ctx)))
|
||||
{
|
||||
|
@ -1405,13 +1645,6 @@ _sources_get(void)
|
|||
return ctx->sources;
|
||||
}
|
||||
|
||||
static const Eina_List *
|
||||
_sink_inputs_get(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
||||
return ctx->inputs;
|
||||
}
|
||||
|
||||
static void
|
||||
_sink_volume_set(Emix_Sink *sink, Emix_Volume *volume)
|
||||
{
|
||||
|
@ -1437,6 +1670,13 @@ _sink_mute_set(Emix_Sink *sink, Eina_Bool mute)
|
|||
ERR("pa_context_set_sink_mute() failed");
|
||||
}
|
||||
|
||||
static const Eina_List *
|
||||
_sink_inputs_get(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
||||
return ctx->inputs;
|
||||
}
|
||||
|
||||
static void
|
||||
_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume *volume)
|
||||
{
|
||||
|
@ -1479,6 +1719,55 @@ _sink_input_move(Emix_Sink_Input *input, Emix_Sink *sink)
|
|||
ERR("pa_context_move_sink_input_by_index() failed");
|
||||
}
|
||||
|
||||
static const Eina_List *
|
||||
_source_outputs_get(void)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
||||
return ctx->outputs;
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_volume_set(Emix_Source_Output *output, Emix_Volume *volume)
|
||||
{
|
||||
pa_operation* o;
|
||||
Source_Output *source_output = (Source_Output *)output;
|
||||
pa_cvolume vol = _emix_volume_convert(volume);
|
||||
EINA_SAFETY_ON_FALSE_RETURN(ctx && ctx->context && output != NULL);
|
||||
|
||||
if (!(o = pa_context_set_source_output_volume(ctx->context,
|
||||
source_output->idx, &vol,
|
||||
NULL, NULL)))
|
||||
ERR("pa_context_set_source_output_volume_by_index() failed");
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_mute_set(Emix_Source_Output *output, Eina_Bool mute)
|
||||
{
|
||||
pa_operation* o;
|
||||
Source_Output *source_output = (Source_Output *)output;
|
||||
EINA_SAFETY_ON_FALSE_RETURN(ctx && ctx->context && output != NULL);
|
||||
|
||||
if (!(o = pa_context_set_source_output_mute(ctx->context,
|
||||
source_output->idx, mute,
|
||||
NULL, NULL)))
|
||||
ERR("pa_context_set_source_output_mute() failed");
|
||||
}
|
||||
|
||||
static void
|
||||
_source_output_move(Emix_Source_Output *output, Emix_Source *source)
|
||||
{
|
||||
pa_operation* o;
|
||||
Source *s = (Source *)source;
|
||||
Source_Output *i = (Source_Output *)output;
|
||||
EINA_SAFETY_ON_FALSE_RETURN(ctx && ctx->context && output != NULL
|
||||
&& source != NULL);
|
||||
|
||||
if (!(o = pa_context_move_source_output_by_index(ctx->context,
|
||||
i->idx, s->idx, NULL,
|
||||
NULL)))
|
||||
ERR("pa_context_move_source_output_by_index() failed");
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_sink_port_set(Emix_Sink *sink, const Emix_Port *port)
|
||||
{
|
||||
|
@ -1868,6 +2157,10 @@ _pulseaudio_backend =
|
|||
_source_default_set,
|
||||
_source_mute_set,
|
||||
_source_volume_set,
|
||||
_source_outputs_get,
|
||||
_source_output_mute_set,
|
||||
_source_output_volume_set,
|
||||
_source_output_move,
|
||||
NULL,
|
||||
_cards_get,
|
||||
_card_profile_set,
|
||||
|
|
|
@ -395,6 +395,45 @@ emix_source_volume_set(Emix_Source *source, Emix_Volume *volume)
|
|||
ctx->loaded->ebackend_source_volume_set(source, volume);
|
||||
}
|
||||
|
||||
const Eina_List*
|
||||
emix_source_outputs_get(void)
|
||||
{
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
||||
ctx->loaded->ebackend_source_outputs_get),
|
||||
NULL);
|
||||
return ctx->loaded->ebackend_source_outputs_get();
|
||||
}
|
||||
|
||||
void
|
||||
emix_source_output_mute_set(Emix_Source_Output *output, Eina_Bool mute)
|
||||
{
|
||||
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
||||
ctx->loaded->ebackend_source_output_mute_set &&
|
||||
output));
|
||||
|
||||
ctx->loaded->ebackend_source_output_mute_set(output, mute);
|
||||
}
|
||||
|
||||
void
|
||||
emix_source_output_volume_set(Emix_Source_Output *output, Emix_Volume *volume)
|
||||
{
|
||||
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
||||
ctx->loaded->ebackend_source_output_volume_set &&
|
||||
output));
|
||||
|
||||
ctx->loaded->ebackend_source_output_volume_set(output, volume);
|
||||
}
|
||||
|
||||
void
|
||||
emix_source_output_sink_change(Emix_Source_Output *output, Emix_Source *source)
|
||||
{
|
||||
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
||||
ctx->loaded->ebackend_source_output_source_change &&
|
||||
output && source));
|
||||
|
||||
ctx->loaded->ebackend_source_output_source_change(output, source);
|
||||
}
|
||||
|
||||
Evas_Object *
|
||||
emix_advanced_options_add(Evas_Object *parent)
|
||||
{
|
||||
|
|
|
@ -37,6 +37,9 @@ enum Emix_Event {
|
|||
EMIX_SOURCE_ADDED_EVENT,
|
||||
EMIX_SOURCE_REMOVED_EVENT,
|
||||
EMIX_SOURCE_CHANGED_EVENT,
|
||||
EMIX_SOURCE_OUTPUT_ADDED_EVENT,
|
||||
EMIX_SOURCE_OUTPUT_REMOVED_EVENT,
|
||||
EMIX_SOURCE_OUTPUT_CHANGED_EVENT,
|
||||
EMIX_CARD_ADDED_EVENT,
|
||||
EMIX_CARD_REMOVED_EVENT,
|
||||
EMIX_CARD_CHANGED_EVENT,
|
||||
|
@ -91,6 +94,15 @@ typedef struct _Emix_Source {
|
|||
const float *mon_buf; // LRLRLR unsigned char samples
|
||||
} Emix_Source;
|
||||
|
||||
typedef struct _Emix_Source_Output {
|
||||
const char *name;
|
||||
Emix_Volume volume;
|
||||
Eina_Bool mute;
|
||||
Emix_Source *source;
|
||||
pid_t pid;
|
||||
const char *icon;
|
||||
} Emix_Source_Output;
|
||||
|
||||
typedef struct _Emix_Profile {
|
||||
const char *name;
|
||||
const char *description;
|
||||
|
@ -141,6 +153,14 @@ typedef struct _Emix_Backend {
|
|||
void (*ebackend_source_volume_set)(Emix_Source *source,
|
||||
Emix_Volume *volume);
|
||||
|
||||
const Eina_List* (*ebackend_source_outputs_get)(void);
|
||||
void (*ebackend_source_output_mute_set)(
|
||||
Emix_Source_Output *output, Eina_Bool mute);
|
||||
void (*ebackend_source_output_volume_set)(
|
||||
Emix_Source_Output *output, Emix_Volume *volume);
|
||||
void (*ebackend_source_output_source_change)(
|
||||
Emix_Source_Output *output, Emix_Source *source);
|
||||
|
||||
Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent);
|
||||
const Eina_List* (*ebackend_cards_get)(void);
|
||||
Eina_Bool (*ebackend_card_profile_set)(Emix_Card *card, const Emix_Profile *profile);
|
||||
|
@ -208,6 +228,15 @@ 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);
|
||||
|
||||
E_API const Eina_List* emix_source_outputs_get(void);
|
||||
E_API void emix_source_output_mute_set(Emix_Source_Output *output,
|
||||
Eina_Bool mute);
|
||||
E_API void emix_source_output_volume_set(Emix_Source_Output *output,
|
||||
Emix_Volume *volume);
|
||||
E_API void emix_source_output_sink_change(Emix_Source_Output *output,
|
||||
Emix_Source *source);
|
||||
|
||||
E_API Evas_Object* emix_advanced_options_add(Evas_Object *parent);
|
||||
|
||||
E_API const Eina_List* emix_cards_get(void);
|
||||
|
|
Loading…
Reference in New Issue