Class: DTAS::Sink

Inherits:
Object
  • Object
show all
Includes:
Command, Process, Serialize
Defined in:
lib/dtas/sink.rb

Overview

this is a sink (endpoint, audio enters but never leaves)

Constant Summary collapse

SINK_DEFAULTS =
COMMAND_DEFAULTS.merge({
  "name" => nil, # order matters, this is first
  "command" => "exec play -q $SOXFMT -",
  "prio" => 0,
  "nonblock" => false,
  "pipe_size" => nil,
  "active" => false,
})
DEVFD_RE =
%r{/dev/fd/([a-zA-Z]\w*)\b}
SIVS =

order matters for Ruby 1.9+, this defines to_hsh serialization so we can make the state file human-friendly

%w(name env command prio nonblock pipe_size active)

Constants included from Process

Process::PIDS

Constants included from Command

Command::COMMAND_DEFAULTS

Instance Attribute Summary collapse

Attributes included from Command

#command, #env, #pid, #spawn_at, #to_io

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Serialize

#ivars_to_hash

Methods included from Process

#dtas_spawn, #env_expand, #qx, reaper

Methods included from XS

#xs

Methods included from Command

#command_init, #command_string

Constructor Details

#initializeSink

Returns a new instance of Sink.



38
39
40
41
# File 'lib/dtas/sink.rb', line 38

def initialize
  command_init(SINK_DEFAULTS)
  @sink = self
end

Instance Attribute Details

#activeObject

boolean



14
15
16
# File 'lib/dtas/sink.rb', line 14

def active
  @active
end

#nameObject

Returns the value of attribute name.



15
16
17
# File 'lib/dtas/sink.rb', line 15

def name
  @name
end

#nonblockObject

Returns the value of attribute nonblock.



17
18
19
# File 'lib/dtas/sink.rb', line 17

def nonblock
  @nonblock
end

#pipe_sizeObject

Returns the value of attribute pipe_size.



16
17
18
# File 'lib/dtas/sink.rb', line 16

def pipe_size
  @pipe_size
end

#prioObject

:nodoc:



13
14
15
# File 'lib/dtas/sink.rb', line 13

def prio
  @prio
end

Class Method Details

.load(hash) ⇒ Object



49
50
51
52
53
54
55
56
57
# File 'lib/dtas/sink.rb', line 49

def self.load(hash)
  sink = new
  return sink unless hash
  (SIVS & hash.keys).each do |k|
    sink.instance_variable_set("@#{k}", hash[k])
  end
  sink.valid_name?(sink.name) or raise ArgumentError, "invalid sink name"
  sink
end

Instance Method Details

#on_death(status) ⇒ Object



65
66
67
# File 'lib/dtas/sink.rb', line 65

def on_death(status)
  super
end

#parse(str) ⇒ Object



59
60
61
62
63
# File 'lib/dtas/sink.rb', line 59

def parse(str)
  inputs = {}
  str.scan(DEVFD_RE) { |w| inputs[w[0]] = nil }
  inputs
end

#spawn(format, opts = {}) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/dtas/sink.rb', line 69

def spawn(format, opts = {})
  raise "BUG: #{self.inspect}#spawn called twice" if @pid
  rv = []

  pclass = @nonblock ? DTAS::PipeNB : DTAS::Pipe

  cmd = command_string
  inputs = parse(cmd)

  if inputs.empty?
    # /dev/fd/* not specified in the command, assume one input for stdin
    r, w = pclass.new
    w.pipe_size = @pipe_size if @pipe_size
    inputs[:in] = opts[:in] = r
    w.sink = self
    rv << w
  else
    # multiple inputs, fun!, we'll tee to them
    inputs.each_key do |name|
      r, w = pclass.new
      w.pipe_size = @pipe_size if @pipe_size
      inputs[name] = r
      w.sink = self
      rv << w
    end
    opts[:in] = "/dev/null"

    # map to real /dev/fd/* values and setup proper redirects
    cmd = cmd.gsub(DEVFD_RE) do
      read_fd = inputs[$1].fileno
      opts[read_fd] = read_fd # do not close-on-exec
      "/dev/fd/#{read_fd}"
    end
  end

  @pid = dtas_spawn(format.to_env.merge!(@env), cmd, opts)
  inputs.each_value(&:close)
  rv
end

#to_hashObject



109
110
111
# File 'lib/dtas/sink.rb', line 109

def to_hash
  ivars_to_hash(SIVS)
end

#to_hshObject



113
114
115
# File 'lib/dtas/sink.rb', line 113

def to_hsh
  to_hash.delete_if { |k,v| v == SINK_DEFAULTS[k] }
end

#valid_name?(s) ⇒ Boolean

allow things that look like audio device names (“hw:1,0” , “/dev/dsp”) or variable names.

Returns:

  • (Boolean)


45
46
47
# File 'lib/dtas/sink.rb', line 45

def valid_name?(s)
  !!(s =~ %r{\A[\w:,/-]+\z})
end