about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2014-12-28 00:43:07 +0000
committerEric Wong <e@80x24.org>2014-12-28 01:49:06 +0000
commita462961df2088af99e2e815ad60b8d838c9d062d (patch)
treef60f5b89c44dd2bf33739c4653d815b1bcf254ba
parent949dbe07c02919f8f17d7880bc69c3ee683daca4 (diff)
downloaddtas-a462961df2088af99e2e815ad60b8d838c9d062d.tar.gz
Since splitfx YAML files are intended to be frequently edited and
modified by the user, we'll support automatically restarting the
source when the user saves changes via their favorite $EDITOR

This change is only for Linux users.  However, sleepy_penguin
supports kqueue nowadays so a patch to support such functionality
would be appreciated.
-rw-r--r--lib/dtas/player.rb7
-rw-r--r--lib/dtas/source/splitfx.rb2
-rw-r--r--lib/dtas/source/watchable.rb54
3 files changed, 63 insertions, 0 deletions
diff --git a/lib/dtas/player.rb b/lib/dtas/player.rb
index 0ae8cef..ea48926 100644
--- a/lib/dtas/player.rb
+++ b/lib/dtas/player.rb
@@ -385,6 +385,7 @@ class DTAS::Player # :nodoc:
   end
 
   def next_source(source_spec)
+    @current.respond_to?(:watch_end) and @current.watch_end(@srv)
     @current = nil
     if source_spec
       case source_spec
@@ -413,6 +414,12 @@ class DTAS::Player # :nodoc:
       dst = @sink_buf
       pending.dst_assoc(dst)
       pending.spawn(@format, @rg, out: dst.wr, in: "/dev/null")
+
+      # watch and restart on modifications
+      pending.respond_to?(:watch_begin) and
+        @srv.wait_ctl(pending.watch_begin(method(:__current_requeue)),
+                      :wait_readable)
+
       @current = pending
       @srv.wait_ctl(dst, :wait_readable)
       wall(msg)
diff --git a/lib/dtas/source/splitfx.rb b/lib/dtas/source/splitfx.rb
index ad9e7c1..a0899f3 100644
--- a/lib/dtas/source/splitfx.rb
+++ b/lib/dtas/source/splitfx.rb
@@ -3,10 +3,12 @@
 require 'yaml'
 require_relative 'sox'
 require_relative '../splitfx'
+require_relative 'watchable'
 
 class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc:
   MAX_YAML_SIZE = 512 * 1024
   attr_writer :sox
+  include DTAS::Source::Watchable if defined?(DTAS::Source::Watchable)
 
   SPLITFX_DEFAULTS = SOX_DEFAULTS.merge("tryorder" => 3)
 
diff --git a/lib/dtas/source/watchable.rb b/lib/dtas/source/watchable.rb
new file mode 100644
index 0000000..3ff9ef8
--- /dev/null
+++ b/lib/dtas/source/watchable.rb
@@ -0,0 +1,54 @@
+# Copyright (C) 2014, all contributors <dtas-all@nongnu.org>
+# License: GPLv3 or later <https://www.gnu.org/licenses/gpl-3.0.txt>
+begin
+  require 'sleepy_penguin'
+rescue LoadError
+end
+
+# used to restart DTAS::Source::SplitFX processing in dtas-player
+# if the YAML file is edited
+module DTAS::Source::Watchable
+  class InotifyReadableIter < SleepyPenguin::Inotify
+    def self.new
+      super(:CLOEXEC)
+    end
+
+    FLAGS = CLOSE_WRITE | MOVED_TO
+
+    def readable_iter
+      or_call = false
+      while event = take(true) # drain the buffer
+        if (event.mask & FLAGS) != 0 && @watching[1] == event.name
+          or_call = true
+        end
+      end
+      if or_call && @on_readable
+        @on_readable.call
+        :delete
+      else
+        :wait_readable
+      end
+    end
+
+    # we must watch the directory, since
+    def watch_file(path, blk)
+      @on_readable = blk
+      @watching = File.split(File.expand_path(path))
+      add_watch(@watching[0], FLAGS)
+    end
+  end
+
+  def watch_begin(blk)
+    @ino = InotifyReadableIter.new
+    @ino.watch_file(@infile, blk)
+    @ino
+  end
+
+  # Closing the inotify descriptor (instead of using inotify_rm_watch)
+  # is cleaner because it avoids EINVAL on race conditions in case
+  # a directory is deleted: https://lkml.org/lkml/2007/7/9/3
+  def watch_end(srv)
+    srv.wait_ctl(@ino, :delete)
+    @ino = @ino.close
+  end
+end if defined?(SleepyPenguin::Inotify)