[vlc-devel] [PATCH] Add dpms module to switch it off while playing

Olivier Brunel jjk at jjacky.com
Fri Oct 25 19:43:41 CEST 2013


Assumes it was on before/should be on again after. Point is to switch it off
when starting to play, and (back) on when pausing/stopping.

Signed-off-by: Olivier Brunel <jjk at jjacky.com>
---
Hi,

It was suggested to me to send this here, so here we go. A few things I feel I
should say about this:

- As I explained in a blog post[1], the main reason I wrote this is because I
  wanted DPMS to be turned back on when pausing a video (and off on resume),
  which VLC doesn't do. The inhibit in VLC only works on play/stop and that's
  not good enough for me (I'll often pause and go AFK, for a while). This is why
  it uses the "interface" capability.

- The right thing to do might have been to call xdg-screensaver suspend/resume,
  and instead I'm calling `xset +/-dpms` directly, which means on pause/stop
  DPMS will be turned back on, whereas it would have otherwise maybe not been
  done because another app had called xdg-screensaver suspend.
  It's a known "flaw" because I don't use a session manager myself, so the call
  to xdg-screensaver would have been one to xset anyways, plus I have no idea
  how to get the window ID from VLC.

- I'm not familiar at all with the VLC codebase, so this was very much inspired
  from previous similar modules. (Any horrible bug in there is most likely my
  doing though :p)

-jjacky

[1] http://jjacky.com/2013-09-30-automatically-switch-dpms-off-in-vlc-2.1/


 modules/misc/Modules.am |   4 +-
 modules/misc/dpms.c     | 228 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 231 insertions(+), 1 deletion(-)
 create mode 100644 modules/misc/dpms.c

diff --git a/modules/misc/Modules.am b/modules/misc/Modules.am
index d2d6a22..2a123da 100644
--- a/modules/misc/Modules.am
+++ b/modules/misc/Modules.am
@@ -5,6 +5,7 @@ SOURCES_fingerprinter = fingerprinter.c \
 	webservices/acoustid.h \
 	webservices/json.c \
 	webservices/json.h
+SOURCES_dpms = dpms.c
 
 SOURCES_xml = xml/libxml.c
 
@@ -55,7 +56,8 @@ libstats_plugin_la_LIBADD = $(AM_LIBADD)
 libvlc_LTLIBRARIES += \
 	libaudioscrobbler_plugin.la \
 	liblogger_plugin.la \
-	libstats_plugin.la
+	libstats_plugin.la \
+	libdpms_plugin.la
 
 if ENABLE_SOUT
 libvlc_LTLIBRARIES += \
diff --git a/modules/misc/dpms.c b/modules/misc/dpms.c
new file mode 100644
index 0000000..12b3b1d
--- /dev/null
+++ b/modules/misc/dpms.c
@@ -0,0 +1,228 @@
+/**
+ * dpms.c               Copyright (C) 2013 Olivier Brunel       GPL 3+
+ * based on inhibit.c   Copyright © 2007 Rafaël Carré           GPL 2+
+ * based on xdg.c       Copyright (C) 2008 Rémi Denis-Courmont  LGPL 2.1+
+ * */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_input.h>
+#include <vlc_interface.h>
+#include <vlc_playlist.h>
+#include <assert.h>
+#include <signal.h>
+#include <spawn.h>
+#include <sys/wait.h>
+
+static int  Activate    (vlc_object_t *p_this);
+static void Deactivate  (vlc_object_t *p_this);
+
+static void Inhibit     (intf_thread_t *p_intf, bool suspend);
+
+static int StateChange  (vlc_object_t *p_input, const char *var,
+                         vlc_value_t prev, vlc_value_t value, void *data);
+static int ItemChange   (vlc_object_t *p_playlist, const char *var,
+                         vlc_value_t prev, vlc_value_t value, void *data);
+static void *Thread     (void *data);
+
+struct intf_sys_t
+{
+    playlist_t         *p_playlist;
+    vlc_thread_t        thread;
+    vlc_cond_t          update;
+    vlc_cond_t          inactive;
+    vlc_mutex_t         lock;
+    posix_spawnattr_t   attr;
+    bool                suspend;
+    bool                suspended;
+    bool                has_callback;
+};
+
+vlc_module_begin ()
+    set_shortname (N_("dpms"))
+    set_description (N_("Switch DPMS off while playing"))
+    set_capability ("interface", 10)
+    set_callbacks (Activate, Deactivate)
+vlc_module_end ()
+
+/*****************************************************************************
+ * Activate: initialize and create stuff
+ *****************************************************************************/
+static int Activate (vlc_object_t *p_this)
+{
+    intf_thread_t   *p_intf = (intf_thread_t *) p_this;
+    intf_sys_t      *p_sys;
+
+    p_sys = p_intf->p_sys = (intf_sys_t *) calloc (1, sizeof (intf_sys_t));
+    if (!p_sys)
+        return VLC_ENOMEM;
+
+    vlc_mutex_init (&p_sys->lock);
+    vlc_cond_init (&p_sys->update);
+    vlc_cond_init (&p_sys->inactive);
+    posix_spawnattr_init (&p_sys->attr);
+    /* Reset signal handlers to default and clear mask in the child process */
+    {
+        sigset_t set;
+
+        sigemptyset (&set);
+        posix_spawnattr_setsigmask (&p_sys->attr, &set);
+        sigaddset (&set, SIGPIPE);
+        posix_spawnattr_setsigdefault (&p_sys->attr, &set);
+        posix_spawnattr_setflags (&p_sys->attr, POSIX_SPAWN_SETSIGDEF
+                                              | POSIX_SPAWN_SETSIGMASK);
+    }
+
+    if (vlc_clone (&p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW))
+    {
+        vlc_cond_destroy (&p_sys->inactive);
+        vlc_cond_destroy (&p_sys->update);
+        vlc_mutex_destroy (&p_sys->lock);
+        free (p_sys);
+        return VLC_ENOMEM;
+    }
+    p_sys->p_playlist = pl_Get (p_intf);
+    var_AddCallback (p_sys->p_playlist, "activity", ItemChange, p_intf);
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Deactivate: uninitialize and cleanup
+ *****************************************************************************/
+static void Deactivate (vlc_object_t *p_this)
+{
+    intf_thread_t *p_intf = (intf_thread_t*)p_this;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    input_thread_t *p_input;
+
+    var_DelCallback (p_sys->p_playlist, "activity", ItemChange, p_intf);
+
+    p_input = playlist_CurrentInput (p_sys->p_playlist);
+    if (p_input)
+    {
+        if (p_sys->has_callback)
+            var_DelCallback (p_input, "intf-event", StateChange, p_intf);
+        vlc_object_release (p_input);
+    }
+
+    Inhibit (p_intf, false);
+
+    /* Make sure xset is gone for good */
+    vlc_mutex_lock (&p_sys->lock);
+    while (p_sys->suspended)
+        vlc_cond_wait (&p_sys->inactive, &p_sys->lock);
+    vlc_mutex_unlock (&p_sys->lock);
+
+    vlc_cancel (p_sys->thread);
+    vlc_join (p_sys->thread, NULL);
+    posix_spawnattr_destroy (&p_sys->attr);
+    vlc_cond_destroy (&p_sys->inactive);
+    vlc_cond_destroy (&p_sys->update);
+    vlc_mutex_destroy (&p_sys->lock);
+
+    free (p_sys);
+}
+
+static void Inhibit (intf_thread_t *p_intf, bool suspend)
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    /* in case xset take a little while to start up (e.g. 1 second), avoid
+     * waiting for it unless we really need to (clean up). */
+    vlc_mutex_lock (&p_sys->lock);
+    p_sys->suspend = suspend;
+    vlc_cond_signal (&p_sys->update);
+    vlc_mutex_unlock (&p_sys->lock);
+}
+
+static int StateChange (vlc_object_t *p_input, const char *var,
+                        vlc_value_t prev, vlc_value_t value, void *data)
+{
+    intf_thread_t *p_intf = data;
+    int state;
+
+    if (value.i_int != INPUT_EVENT_STATE)
+        return VLC_SUCCESS;
+
+    state = var_GetInteger (p_input, "state");
+
+    if ((state == PLAYING_S) == p_intf->p_sys->suspended)
+        return VLC_SUCCESS;
+
+    Inhibit (p_intf, state == PLAYING_S);
+
+    (void)var; (void)prev;
+    return VLC_SUCCESS;
+}
+
+static int ItemChange (vlc_object_t *p_playlist, const char *var,
+                       vlc_value_t prev, vlc_value_t value, void *data)
+{
+    intf_thread_t *p_intf = data;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    input_thread_t *p_input;
+
+    p_input = playlist_CurrentInput (p_sys->p_playlist);
+    if (!p_input || p_input->b_dead)
+        return VLC_SUCCESS;
+
+    Inhibit (p_intf, true);
+    var_AddCallback (p_input, "intf-event", StateChange, p_intf);
+    p_sys->has_callback = true;
+    vlc_object_release (p_input);
+
+    (void)var; (void)prev; (void)value; (void)p_playlist;
+    return VLC_SUCCESS;
+}
+
+
+extern char **environ;
+
+VLC_NORETURN
+static void *Thread (void *data)
+{
+    intf_thread_t *p_intf = data;
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    vlc_mutex_lock (&p_sys->lock);
+    mutex_cleanup_push (&p_sys->lock);
+    for (;;)
+    {
+        while (p_sys->suspended == p_sys->suspend)
+            vlc_cond_wait (&p_sys->update, &p_sys->lock);
+
+        int canc = vlc_savecancel ();
+        char *argv[3] = {
+            (char *) "xset",
+            (char *) ((p_sys->suspend) ? "-dpms" : "+dpms"),
+            NULL,
+        };
+        pid_t pid;
+
+        vlc_mutex_unlock (&p_sys->lock);
+        if (!posix_spawnp (&pid, argv[0], NULL, &p_sys->attr,
+                           argv, environ))
+        {
+            int status;
+
+            /* Wait for command to complete */
+            while (waitpid (pid, &status, 0) == -1);
+        }
+        else
+            /* We don't handle the error, but busy looping would be worse :( */
+            msg_Warn (p_intf, "Failed to start xset");
+
+        vlc_mutex_lock (&p_sys->lock);
+        p_sys->suspended = p_sys->suspend;
+        if (!p_sys->suspended)
+            vlc_cond_signal (&p_sys->inactive);
+        vlc_restorecancel (canc);
+    }
+
+    vlc_cleanup_pop ();
+    assert (0);
+}
-- 
1.8.4




More information about the vlc-devel mailing list