From 2907cc6dd0b0d2d80d44ae292a157651d6e05ee7 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 26 Aug 2013 05:25:22 +0000 Subject: player: flesh out multi-source in protocol/sourceedit We should be fully-capable of managing any number of options to try sources in. --- lib/dtas/player.rb | 45 +++++++++++++++++++++++++++------------ lib/dtas/player/client_handler.rb | 33 ++++++++++++++++++---------- lib/dtas/source/av.rb | 8 +++++-- lib/dtas/source/file.rb | 27 +++++++++++++++++++++-- lib/dtas/source/sox.rb | 9 +++++--- 5 files changed, 90 insertions(+), 32 deletions(-) (limited to 'lib') 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 -- cgit v1.2.3-24-ge0c7