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), used by -player

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, #env_expand_ary, #env_expand_i, #qx, reaper

Methods included from SpawnFix

#spawn

Methods included from XS

#xs

Methods included from Command

#command_init, #command_string

Constructor Details

#initializeSink

Returns a new instance of Sink.


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

def initialize
  command_init(SINK_DEFAULTS)
  @sink = self
end

Instance Attribute Details

#activeObject

boolean


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

def active
  @active
end

#nameObject

Returns the value of attribute name.


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

def name
  @name
end

#nonblockObject

Returns the value of attribute nonblock.


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

def nonblock
  @nonblock
end

#pipe_sizeObject

Returns the value of attribute pipe_size.


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

def pipe_size
  @pipe_size
end

#prioObject

:nodoc:


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

def prio
  @prio
end

Class Method Details

.load(hash) ⇒ Object


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

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


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

def on_death(status)
  super
end

#parse(str) ⇒ Object


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

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

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


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
108
# File 'lib/dtas/sink.rb', line 70

def sink_spawn(format, opts = {})
  raise "BUG: #{self.inspect}#sink_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] = DTAS.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


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

def to_hash
  ivars_to_hash(SIVS)
end

#to_hshObject


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

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)

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

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