yoz pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=307f0831ce0be4d8dd075c14d020dc6106f7aa0f

commit 307f0831ce0be4d8dd075c14d020dc6106f7aa0f
Author: MichaĆ«l Bouchaud (yoz) <[email protected]>
Date:   Fri Oct 14 12:30:57 2016 +0200

    mixer: use the new e_client api to export volume control by app.
    
    We use the pulseaudio backend to export volume control by app.
    This commit introduce 3 news shortcuts to control the volume with the 
current
    focused window.
    
    @features
---
 src/modules/mixer/e_mod_main.c                    | 219 ++++++++++++++++++++++
 src/modules/mixer/emixer.c                        |  20 --
 src/modules/mixer/lib/backends/pulseaudio/pulse.c |  11 ++
 src/modules/mixer/lib/emix.h                      |  21 +++
 4 files changed, 251 insertions(+), 20 deletions(-)

diff --git a/src/modules/mixer/e_mod_main.c b/src/modules/mixer/e_mod_main.c
index ef53d2e..8c7efb1 100644
--- a/src/modules/mixer/e_mod_main.c
+++ b/src/modules/mixer/e_mod_main.c
@@ -14,6 +14,7 @@
 
 int _e_emix_log_domain;
 static Eina_Bool init;
+static Eina_List *_client_sinks = NULL;
 
 /* module requirements */
 E_API E_Module_Api e_modapi =
@@ -62,6 +63,9 @@ struct _Context
       E_Action *incr;
       E_Action *decr;
       E_Action *mute;
+      E_Action *incr_app;
+      E_Action *decr_app;
+      E_Action *mute_app;
    } actions;
 };
 
@@ -242,6 +246,42 @@ _volume_mute_cb(E_Object *obj EINA_UNUSED, const char 
*params EINA_UNUSED)
 }
 
 static void
+_volume_increase_app_cb(E_Object *obj EINA_UNUSED, const char *params 
EINA_UNUSED)
+{
+   E_Client *ec;
+
+   ec = e_client_focused_get();
+   if (ec && ec->volume_control_enabled)
+     {
+        e_client_volume_set(ec, ec->volume + VOLUME_STEP);
+     }
+}
+
+static void
+_volume_decrease_app_cb(E_Object *obj EINA_UNUSED, const char *params 
EINA_UNUSED)
+{
+   E_Client *ec;
+
+   ec = e_client_focused_get();
+   if (ec && ec->volume_control_enabled)
+     {
+        e_client_volume_set(ec, ec->volume - VOLUME_STEP);
+     }
+}
+
+static void
+_volume_mute_app_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
+{
+   E_Client *ec;
+
+   ec = e_client_focused_get();
+   if (ec && ec->volume_control_enabled)
+     {
+        e_client_volume_mute_set(ec, !ec->mute);
+     }
+}
+
+static void
 _actions_register(void)
 {
    mixer_context->actions.incr = e_action_add("volume_increase");
@@ -267,6 +307,30 @@ _actions_register(void)
         e_action_predef_name_set("Mixer", _("Mute volume"), "volume_mute",
                                  NULL, NULL, 0);
      }
+   mixer_context->actions.incr_app = e_action_add("volume_increase_app");
+   if (mixer_context->actions.incr_app)
+     {
+        mixer_context->actions.incr_app->func.go = _volume_increase_app_cb;
+        e_action_predef_name_set("Mixer",
+                                 _("Increase Volume of Focused Application"),
+                                 "volume_increase_app", NULL, NULL, 0);
+     }
+   mixer_context->actions.decr_app = e_action_add("volume_decrease_app");
+   if (mixer_context->actions.decr_app)
+     {
+        mixer_context->actions.decr_app->func.go = _volume_decrease_app_cb;
+        e_action_predef_name_set("Mixer",
+                                 _("Decrease Volume of Focused Application"),
+                                 "volume_decrease_app", NULL, NULL, 0);
+     }
+   mixer_context->actions.mute_app = e_action_add("volume_mute_app");
+   if (mixer_context->actions.mute_app)
+     {
+        mixer_context->actions.mute_app->func.go = _volume_mute_app_cb;
+        e_action_predef_name_set("Mixer",
+                                 _("Mute Volume of Focused Application"),
+                                 "volume_mute_app", NULL, NULL, 0);
+     }
 
    e_comp_canvas_keys_ungrab();
    e_comp_canvas_keys_grab();
@@ -296,6 +360,30 @@ _actions_unregister(void)
         mixer_context->actions.mute = NULL;
      }
 
+   if (mixer_context->actions.incr_app)
+     {
+        e_action_predef_name_del("Mixer",
+                                 _("Increase Volume of Focuse Application"));
+        e_action_del("volume_increase_app");
+        mixer_context->actions.incr_app = NULL;
+     }
+
+   if (mixer_context->actions.decr_app)
+     {
+        e_action_predef_name_del("Mixer",
+                                 _("Decrease Volume of Focuse Application"));
+        e_action_del("volume_decrease_app");
+        mixer_context->actions.decr_app = NULL;
+     }
+
+   if (mixer_context->actions.incr_app)
+     {
+        e_action_predef_name_del("Mixer",
+                                 _("Mute Volume of Focuse Application"));
+        e_action_del("volume_mute_app");
+        mixer_context->actions.mute_app = NULL;
+     }
+
    e_comp_canvas_keys_ungrab();
    e_comp_canvas_keys_grab();
 }
@@ -759,6 +847,126 @@ _ready(void)
 }
 
 static void
+_sink_input_get(int *volume, Eina_Bool *muted, void *data)
+{
+   Emix_Sink_Input *input;
+
+   input = data;
+
+   if (volume) *volume = input->volume.volumes[0];
+   if (muted) *muted = input->mute;
+}
+
+static void
+_sink_input_set(int volume, Eina_Bool muted, void *data)
+{
+   Emix_Sink_Input *input;
+
+   input = data;
+
+   VOLSET(volume, input->volume, input, emix_sink_input_volume_set);
+   emix_sink_input_mute_set(input, muted);
+}
+
+static int
+_sink_input_min_get(void *data)
+{
+   return 0;
+}
+
+static int
+_sink_input_max_get(void *data)
+{
+   return emix_max_volume_get();
+}
+
+static pid_t
+_get_ppid(pid_t pid)
+{
+   int fd;
+   char buf[128];
+   char *s;
+   pid_t ppid;
+
+   /* Open the status info process file provided by kernel to get the parent
+    * process id. 'man 5 proc' and go to /proc/[pid]/stat to get information
+    * about the content of this file.
+    */
+   snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+   fd = open(buf, O_RDONLY);
+   if (fd == -1)
+     {
+        ERR("Can't open %s, maybee the process exited.", buf);
+        return -1;
+     }
+   read(fd, buf, sizeof(buf));
+   buf[sizeof(buf) - 1] = '0';
+   s = strrchr(buf, ')');
+   s += 3;
+   ppid = atoi(s);
+   close(fd);
+   return ppid;
+}
+
+static void
+_sink_input_event(int type, Emix_Sink_Input *input)
+{
+   Eina_List *clients, *l, *ll;
+   E_Client *ec;
+   E_Client_Volume_Sink *sink;
+   pid_t pid;
+
+   switch (type)
+     {
+      case EMIX_SINK_INPUT_ADDED_EVENT:
+         pid = input->pid;
+         while (42)
+           {
+              if (pid <= 1 || pid == getpid()) return;
+              clients = e_client_focus_stack_get();
+              EINA_LIST_FOREACH(clients, l, ec)
+                {
+                   if ((ec->netwm.pid == pid) && (!ec->parent))
+                     {
+                        DBG("Sink found the client %s",
+                            e_client_util_name_get(ec));
+                        sink = e_client_volume_sink_new(_sink_input_get,
+                                                 _sink_input_set,
+                                                 _sink_input_min_get,
+                                                 _sink_input_max_get,
+                                                 input);
+                        e_client_volume_sink_append(ec, sink);
+                        _client_sinks = eina_list_append(_client_sinks, sink);
+                        return;
+                     }
+                }
+              pid = _get_ppid(pid);
+           }
+         break;
+      case EMIX_SINK_INPUT_REMOVED_EVENT:
+         EINA_LIST_FOREACH(_client_sinks, l, sink)
+           {
+              if (sink->data == input)
+                {
+                   e_client_volume_sink_del(sink);
+                   _client_sinks = eina_list_remove_list(_client_sinks, l);
+                   break;
+                }
+           }
+         break;
+      case EMIX_SINK_INPUT_CHANGED_EVENT:
+         EINA_LIST_FOREACH(_client_sinks, l, sink)
+           {
+              if (sink->data == input)
+                {
+                   e_client_volume_sink_update(sink);
+                }
+           }
+         break;
+     }
+}
+
+static void
 _events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info)
 {
    switch (type)
@@ -774,6 +982,12 @@ _events_cb(void *data EINA_UNUSED, enum Emix_Event type, 
void *event_info)
       case EMIX_READY_EVENT:
          _ready();
          break;
+      case EMIX_SINK_INPUT_ADDED_EVENT:
+      case EMIX_SINK_INPUT_REMOVED_EVENT:
+      case EMIX_SINK_INPUT_CHANGED_EVENT:
+         _sink_input_event(type, event_info);
+         break;
+
       default:
          break;
      }
@@ -892,6 +1106,8 @@ err:
 E_API int
 e_modapi_shutdown(E_Module *m EINA_UNUSED)
 {
+   E_Client_Volume_Sink *sink;
+
    _actions_unregister();
    e_gadcon_provider_unregister((const E_Gadcon_Client_Class *)&_gadcon_class);
 
@@ -901,6 +1117,9 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
         E_FREE(mixer_context);
      }
 
+   EINA_LIST_FREE(_client_sinks, sink)
+      e_client_volume_sink_del(sink);
+
    emix_event_callback_del(_events_cb);
    emix_shutdown();
    emix_config_shutdown();
diff --git a/src/modules/mixer/emixer.c b/src/modules/mixer/emixer.c
index 61ae830..5cde881 100644
--- a/src/modules/mixer/emixer.c
+++ b/src/modules/mixer/emixer.c
@@ -24,26 +24,6 @@ _backend_init(const char *back)
    return EINA_FALSE;
 }
 
-//////////////////////////////////////////////////////////////////////////////
-
-#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) { \
-         unsigned int _i; \
-         for (_i = 0; _i < _v.channel_count; _i++) _v.volumes[_i] = vol; \
-         func(target, _v); \
-         free(_v.volumes); \
-      } \
-   } while (0)
-
-
-//////////////////////////////////////////////////////////////////////////////
 static void
 _cb_sink_port_change(void *data,
                      Evas_Object *obj,
diff --git a/src/modules/mixer/lib/backends/pulseaudio/pulse.c 
b/src/modules/mixer/lib/backends/pulseaudio/pulse.c
index 5d7ab71..42f0f93 100644
--- a/src/modules/mixer/lib/backends/pulseaudio/pulse.c
+++ b/src/modules/mixer/lib/backends/pulseaudio/pulse.c
@@ -308,6 +308,7 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const 
pa_sink_input_info *info,
    Sink_Input *input;
    Eina_List *l;
    Sink *s;
+   const char *t;
    EINA_SAFETY_ON_NULL_RETURN(ctx);
 
    if (eol < 0)
@@ -340,6 +341,11 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const 
pa_sink_input_info *info,
    input->icon = eina_stringshare_add(_icon_from_properties(info->proplist));
    ctx->inputs = eina_list_append(ctx->inputs, input);
 
+   if ((t = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_PROCESS_ID)))
+     {
+        input->base.pid = atoi(t);
+     }
+
    if (ctx->cb)
      ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_ADDED_EVENT,
              (Emix_Sink_Input *)input);
@@ -353,6 +359,7 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
    Sink_Input *input = NULL, *i;
    Sink *s = NULL;
    Eina_List *l;
+   const char *t;
 
    EINA_SAFETY_ON_NULL_RETURN(ctx);
    if (eol < 0)
@@ -393,6 +400,10 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
         if (s->idx == (int)info->sink)
           input->base.sink = (Emix_Sink *)s;
      }
+   if ((t = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_PROCESS_ID)))
+     {
+        input->base.pid = atoi(t);
+     }
 
    if (ctx->cb)
      ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_CHANGED_EVENT,
diff --git a/src/modules/mixer/lib/emix.h b/src/modules/mixer/lib/emix.h
index 1f1ee5e..29dc17d 100644
--- a/src/modules/mixer/lib/emix.h
+++ b/src/modules/mixer/lib/emix.h
@@ -64,6 +64,7 @@ typedef struct _Emix_Sink_Input {
    Emix_Volume volume;
    Eina_Bool mute;
    Emix_Sink *sink;
+   pid_t pid;
 } Emix_Sink_Input;
 
 typedef struct _Emix_Source {
@@ -110,6 +111,26 @@ typedef struct _Emix_Backend {
    Evas_Object*          (*ebackend_advanced_options_add)(Evas_Object *parent);
 } 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) { \
+         unsigned int _i; \
+         for (_i = 0; _i < _v.channel_count; _i++) _v.volumes[_i] = vol; \
+         func(target, _v); \
+         free(_v.volumes); \
+      } \
+   } while (0)
+
+//////////////////////////////////////////////////////////////////////////////
+
 
 E_API Eina_Bool           emix_init(void);
 E_API void                emix_shutdown(void);

-- 


Reply via email to