about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/dtas/player.rb45
-rw-r--r--lib/dtas/player/client_handler.rb33
-rw-r--r--lib/dtas/source/av.rb8
-rw-r--r--lib/dtas/source/file.rb27
-rw-r--r--lib/dtas/source/sox.rb9
5 files changed, 90 insertions, 32 deletions
diff --git a/lib/dtas/player.rb b/lib/dtas/player.rb
index f1d3507..5cc95c7 100644
--- a/lib/dtas/player.rb
+++ b/lib/dtas/player.rb
@@ -29,8 +29,6 @@ class DTAS::Player # :nodoc:
     @queue = [] # files for sources, or commands
     @paused = false
     @format = DTAS::Format.new
-    @srccmd = nil
-    @srcenv = {}
 
     @sinks = {} # { user-defined name => sink }
     @targets = [] # order matters
@@ -40,7 +38,15 @@ class DTAS::Player # :nodoc:
     @sink_buf = DTAS::Buffer.new
     @current = nil
     @watchers = {}
-    @sources = [ DTAS::Source::Sox.new, DTAS::Source::Av.new ]
+    @source_map = {
+      "sox" => DTAS::Source::Sox.new,
+      "av" => DTAS::Source::Av.new,
+    }
+    source_map_reload
+  end
+
+  def source_map_reload
+    @sources = @source_map.values.sort_by { |src| src.tryorder }
   end
 
   def echo(msg)
@@ -60,13 +66,16 @@ class DTAS::Player # :nodoc:
     $stdout.write(msg << "\n")
   end
 
+  # used for state file
   def to_hsh
     rv = {}
     rv["socket"] = @socket
     rv["paused"] = @paused if @paused
-    src = rv["source"] = {}
-    src["command"] = @srccmd if @srccmd
-    src["env"] = @srcenv if @srcenv.size > 0
+    src_map = rv["source"] = {}
+    @source_map.each do |name, src|
+      src_hsh = src.to_state_hash
+      src_map[name] = src_hsh unless src_hsh.empty?
+    end
 
     # Arrays
     rv["queue"] = @queue
@@ -109,8 +118,22 @@ class DTAS::Player # :nodoc:
         instance_variable_set("@#{k}", v)
       end
       if v = hash["source"]
-        @srccmd = v["command"]
-        e = v["env"] and @srcenv = e
+        # compatibility with 0.0.0, which was sox-only
+        # we'll drop this after 1.0.0, or when we support a source decoder
+        # named "command" or "env" :P
+        sox_cmd, sox_env = v["command"], v["env"]
+        if sox_cmd || sox_env
+          sox = @source_map["sox"]
+          sox.command = sox_cmd if sox_cmd
+          sox.env = sox_env if sox_env
+        end
+
+        # new style: name = "av" or "sox" or whatever else we may support
+        @source_map.each do |name, src|
+          src_hsh = v[name] or next
+          src.load!(src_hsh)
+        end
+        source_map_reload
       end
 
       if v = hash["format"]
@@ -331,12 +354,6 @@ class DTAS::Player # :nodoc:
         echo(%W(command #{@current.command_string}))
       end
 
-      # FIXME, support Av overrides
-      if DTAS::Source::Sox === @current
-        @current.command = @srccmd if @srccmd
-        @current.env = @srcenv.dup unless @srcenv.empty?
-      end
-
       dst = @sink_buf
       @current.dst_assoc(dst)
       @current.spawn(@format, @rg, out: dst.wr, in: "/dev/null")
diff --git a/lib/dtas/player/client_handler.rb b/lib/dtas/player/client_handler.rb
index e08d9a3..d580695 100644
--- a/lib/dtas/player/client_handler.rb
+++ b/lib/dtas/player/client_handler.rb
@@ -419,28 +419,39 @@ module DTAS::Player::ClientHandler # :nodoc:
   end
 
   def source_handler(io, msg)
-    case msg.shift
+    map = @source_map
+    op = msg.shift
+    if op == "ls"
+      s = map.keys.sort { |a,b| map[a].tryorder <=> map[b].tryorder }
+      return io.emit(s.join(' '))
+    end
+
+    name = msg.shift
+    src = map[name] or return io.emit("ERR non-existent source name")
+    case op
     when "cat"
-      io.emit({
-        "command" => @srccmd || DTAS::Source::Sox::SOX_DEFAULTS["command"],
-        "env" => @srcenv,
-      }.to_yaml)
+      io.emit(src.to_source_cat.to_yaml)
     when "ed"
-      before = [ @srccmd, @srcenv ].inspect
+      before = src.to_state_hash
+      sd = src.source_defaults
       msg.each do |kv|
         k, v = kv.split(/=/, 2)
         case k
         when "command"
-          @srccmd = v.empty? ? nil : v
+          src.command = v.empty? ? sd[k] : v
         when %r{\Aenv\.([^=]+)\z}
-          @srcenv[$1] = v
+          src.env[$1] = v
         when %r{\Aenv#([^=]+)\z}
           v == nil or return io.emit("ERR unset env has no value")
-          @srcenv.delete($1)
+          src.env.delete($1)
+        when "tryorder"
+          rv = set_int(io, kv, v, true) { |i| src.tryorder = i || sd[k] }
+          rv == true or return rv
+          source_map_reload
         end
       end
-      after = [ @srccmd, @srcenv ].inspect
-      __current_requeue if before != after
+      after = src.to_state_hash
+      __current_requeue if before != after && @current.class == before.class
       io.emit("OK")
     else
       io.emit("ERR unknown source op")
diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb
index a6a0e3a..61d88b2 100644
--- a/lib/dtas/source/av.rb
+++ b/lib/dtas/source/av.rb
@@ -17,6 +17,7 @@ class DTAS::Source::Av # :nodoc:
     "command" =>
       'avconv -v error $SSPOS -i "$INFILE" $AMAP -f sox - |' \
       'sox -p $SOXFMT - $RGFX',
+    "tryorder" => 1,
   )
 
   attr_reader :precision # always 32
@@ -28,8 +29,7 @@ class DTAS::Source::Av # :nodoc:
   end
 
   def try(infile, offset = nil)
-    rv = dup
-    rv.source_file_init(infile, offset)
+    rv = source_file_dup(infile, offset)
     rv.av_ok? or return
     rv
   end
@@ -133,4 +133,8 @@ class DTAS::Source::Av # :nodoc:
   def to_hsh
     to_hash.delete_if { |k,v| v == AV_DEFAULTS[k] }
   end
+
+  def source_defaults
+    AV_DEFAULTS
+  end
 end
diff --git a/lib/dtas/source/file.rb b/lib/dtas/source/file.rb
index a66308b..3663d8d 100644
--- a/lib/dtas/source/file.rb
+++ b/lib/dtas/source/file.rb
@@ -10,6 +10,7 @@ require_relative '../process'
 module DTAS::Source::File # :nodoc:
   attr_reader :infile
   attr_reader :offset
+  attr_accessor :tryorder
   require_relative 'common' # dtas/source/common
   require_relative 'mp3gain'
   include DTAS::Command
@@ -17,9 +18,17 @@ module DTAS::Source::File # :nodoc:
   include DTAS::Source::Common
   include DTAS::Source::Mp3gain
 
-  FILE_SIVS = %w(infile comments command env)
+  FILE_SIVS = %w(infile comments command env) # for the "current" command
+  SRC_SIVS = %w(command env tryorder)
 
-  def source_file_init(infile, offset)
+  def source_file_dup(infile, offset)
+    rv = dup
+    rv.__file_init(infile, offset)
+    rv
+  end
+
+  def __file_init(infile, offset)
+    @env = @env.dup
     @format = nil
     @infile = infile
     @offset = offset
@@ -68,4 +77,18 @@ module DTAS::Source::File # :nodoc:
             DTAS::ReplayGain.new(mp3gain_comments)
   end
 
+  def to_source_cat
+    ivars_to_hash(SRC_SIVS)
+  end
+
+  def load!(src_hsh)
+    SRC_SIVS.each do |field|
+      val = src_hsh[field] and instance_variable_set("@#{field}", val)
+    end
+  end
+
+  def to_state_hash
+    defaults = source_defaults # see dtas/source/{av,sox}.rb
+    to_source_cat.delete_if { |k,v| v == defaults[k] }
+  end
 end
diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb
index fa6192d..e1baee9 100644
--- a/lib/dtas/source/sox.rb
+++ b/lib/dtas/source/sox.rb
@@ -13,6 +13,7 @@ class DTAS::Source::Sox # :nodoc:
 
   SOX_DEFAULTS = COMMAND_DEFAULTS.merge(
     "command" => 'exec sox "$INFILE" $SOXFMT - $TRIMFX $RGFX',
+    "tryorder" => 0,
   )
 
   def initialize
@@ -23,9 +24,7 @@ class DTAS::Source::Sox # :nodoc:
     err = ""
     qx(@env, %W(soxi #{infile}), err_str: err, no_raise: true)
     return if err =~ /soxi FAIL formats:/
-    rv = dup
-    rv.source_file_init(infile, offset)
-    rv
+    source_file_dup(infile, offset)
   end
 
   def precision
@@ -100,4 +99,8 @@ class DTAS::Source::Sox # :nodoc:
   def to_hsh
     to_hash.delete_if { |k,v| v == SOX_DEFAULTS[k] }
   end
+
+  def source_defaults
+    SOX_DEFAULTS
+  end
 end