1
# This is a native implementation of Ecasound's control interface for Ruby.
2
# Copyright (C) 2003 - 2004 Jan Weil <jan.weil@web.de>
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# ---------------------------------------------------------------------------
24
eci = Ecasound::ControlInterface.new(ecasound_args)
25
ecasound-response = eci.command("iam-command-here")
29
Is there a chance that the ecasound process gets zombified?
37
def self::which(prog, path=ENV['PATH'])
38
path.split(File::PATH_SEPARATOR).each do |dir|
39
f = File::join(dir, prog)
40
if File::executable?(f) && ! File::directory?(f)
47
class VersionString < String
51
if str.split(".").length() != 3
52
raise("Versioning scheme must be major.minor.micro")
56
str.split(".").each {|s| @numbers.push(s.to_i())}
60
numbers.each_index do |i|
61
if numbers[i] < other.numbers[i]
63
elsif numbers[i] > other.numbers[i]
75
REQUIRED_VERSION = VersionString.new("2.2.0")
76
TIMEOUT = 15 # seconds before sync is called 'lost'
78
class EcasoundError < RuntimeError; end
79
class EcasoundCommandError < EcasoundError
80
attr_accessor :command, :error
81
def initialize(command, error)
87
class ControlInterface
88
@@ecasound = ENV['ECASOUND'] || File::which("ecasound")
90
if not File::executable?(@@ecasound.to_s)
91
raise("ecasound executable not found")
93
@@version = VersionString.new(`#{@@ecasound} --version`.split("\n")[0][/\d\.\d\.\d/])
94
if @@version < REQUIRED_VERSION
95
raise("ecasound version #{REQUIRED_VERSION} or newer required, found: #{@@version}")
99
def initialize(args = nil)
101
@ecapipe = IO.popen("-", "r+") # fork!
105
$stderr.reopen(open("/dev/null", "w"))
106
exec("#{@@ecasound} #{args.to_s} -c -D -d:256 ")
110
command("int-output-mode-wellformed")
119
@mutex.synchronize do
121
#puts "command: #{cmd}"
123
@ecapipe.write(cmd + "\n")
125
# ugly hack but the process gets stuck otherwise -kvehmanen
132
# TimeoutError is raised unless response is complete
136
break if response =~ /256 ([0-9]{1,5}) (\-|i|li|f|s|S|e)\r\n(.*)\r\n\r\n/m
140
raise(EcasoundError, "lost synchronisation to ecasound subprocess\nlast command was: '#{cmd}'")
143
content = $3[0, $1.to_i()]
145
#puts "type: '#{$2}'"
146
#puts "length: #{$1}"
147
#puts "content: #{content}"
151
raise(EcasoundCommandError.new(cmd, content))
157
return content.split(",")
159
return content.to_f()
161
return content.to_i()
163
raise(EcasoundError, "parsing of ecasound's output produced an unknown return type")
172
while select([@ecapipe], nil, nil, 0)
173
buffer += @ecapipe.read(1) || ""
177
end # ControlInterface