? rubyecasound-27-11-2003-22-45.patch ? stresstest.rb Index: Makefile.am =================================================================== RCS file: /home/cvspsrv/cvsroot/sound/ecasound/rubyecasound/Makefile.am,v retrieving revision 1.1 diff -u -p -r1.1 Makefile.am --- Makefile.am 27 Nov 2003 01:04:59 -0000 1.1 +++ Makefile.am 27 Nov 2003 22:15:57 -0000 @@ -1,17 +1,14 @@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = README \ - ecasound.rb \ - control-interface.rb + ecasound.rb # ---------------------------------------------------------------------- # defines # ---------------------------------------------------------------------- if ECA_AM_RUBYECASOUND_INSTALL -rubyecasound_install_list1 = $(srcdir)/ecasound.rb \ - $(srcdir)/control-interface.rb -rubyecasound_uninstall_list1 = $(DESTDIR)$(ECA_S_RUBY_SITEDIR)/ecasound.rb \ - $(DESTDIR)$(ECA_S_RUBY_SITEDIR)/control-interface.rb +rubyecasound_install_list1 = $(srcdir)/ecasound.rb +rubyecasound_uninstall_list1 = $(DESTDIR)$(ECA_S_RUBY_SITEDIR)/ecasound.rb endif if ECA_AM_RUBYECASOUND_INSTALL Index: README =================================================================== RCS file: /home/cvspsrv/cvsroot/sound/ecasound/rubyecasound/README,v retrieving revision 1.1 diff -u -p -r1.1 README --- README 27 Nov 2003 01:04:59 -0000 1.1 +++ README 27 Nov 2003 22:15:57 -0000 @@ -9,15 +9,8 @@ Ruby 1.6.8. The first step was to implement a native control interface like the one for Python (ecacontrol.py) which should work by now. -So if you would like to play with ecasound iam from Ruby: - -cp -r ecasound* some_dir/ -cd some_dir - -If you dare to install this system-wide (not yet recommended): - -ruby setup.rb config -su -c 'ruby setup.rb install' +So for now just copy ecasound.rb somewhere if you would like to play with +ecasound iam from Ruby. An example (cut to my_test.rb) -----8<-----------8<--------- Index: ecasound.rb =================================================================== RCS file: /home/cvspsrv/cvsroot/sound/ecasound/rubyecasound/ecasound.rb,v retrieving revision 1.1 diff -u -p -r1.1 ecasound.rb --- ecasound.rb 27 Nov 2003 01:04:59 -0000 1.1 +++ ecasound.rb 27 Nov 2003 22:15:57 -0000 @@ -1,7 +1,10 @@ =begin = ruby-ecasound -require this file to get access to Ecasound::ControlInterface -There will be more (see README) +'require' this file to get access to Ecasound::ControlInterface. +Eventually, there will be more (see README). + +TODO +Is there a chance that the ecasound process gets zombified? = copyright Copyright (C) 2003 Jan Weil @@ -21,11 +24,135 @@ along with this program; if not, write t Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =end +require "timeout" + +# File::which +# just a utility +class File + + def self::which(prog, path=ENV['PATH']) + path.split(File::PATH_SEPARATOR).each do |dir| + f = File::join(dir, prog) + if File::executable?(f) && ! File::directory?(f) + return f + end + end + end + +end # File + +class VersionString < String + def initialize(str) + if str.split(".").length() != 3 + raise("VersionString must be like a.b.c") + end + super(str) + end + + def <=>(comp_str) + comp_ints = comp_str.split(".") + my_ints = self.split(".") + my_ints.each_index do |index| + if my_ints[index].to_i() < comp_ints[index].to_i() + return -1 + elsif my_ints[index].to_i() > comp_ints[index].to_i() + return 1 + elsif index < 2 + next + end + end + return 0 + end +end module Ecasound class EcasoundError < RuntimeError; end -end # Ecasound:: +class ControlInterface + + REQUIRED_VERSION = VersionString.new("2.2.0") + + @@ecasound = ENV['ECASOUND'] || File::which("ecasound") + + if not File::executable?(@@ecasound) + raise(EcasoundError, "ecasound executable not found") + else + @@version = VersionString.new(`#{@@ecasound} --version`.split("\n")[0][/\d\.\d\.\d/]) + if @@version < REQUIRED_VERSION + raise(EcasoundError, "ecasound version #{REQUIRED_VERSION} or newer required, found: #{@@version}") + end + end + + @@timeout = 5 # seconds before sync is called 'lost' + + def initialize(args = "") + @ecapipe = IO.popen("-", "r+") # fork! + + if @ecapipe.nil? + # child + # stderr has to be redirected to avoid buffering problems + $stderr.reopen(open("/dev/null", "w")) + exec("#{@@ecasound} -c -D " + args) + else + # parent + @command = nil + @response = {} + @last_type = nil + + command("int-output-mode-wellformed") + end + end + + def command(cmd, f=nil) + @command = cmd.strip() + @ecapipe.write(@command + "\n") + + response = "" + + # TimeoutError is raised unless response is complete + begin + timeout(@@timeout) do + loop do + response += read_eca() + if response =~ /256 ([0-9]{1,5}) (.+)\r\n(.*)\r\n\r\n/m + # we have a valid response + break + end + end + end + rescue TimeoutError + msg = "lost synchronisation to ecasound subprocess" + raise(EcasoundError, msg) + end + + @last_type = $~[2] + case @last_type + when "e" + # an error occured! + raise(EcasoundError, "command failed: '#{@command}'") + when "S" + @response["S"] = $~[3].split(",") + when "f" + @response["f"] = $~[3].to_f() + when "i", "li" + @response[@last_type] = $~[3].to_i() + else + @response[@last_type] = $~[3] + end + @response[@last_type] + end + + private + + def read_eca() + buffer = "" + while select([@ecapipe], nil, nil, 0) + buffer = buffer + @ecapipe.read(1) + end + buffer + end -require "control-interface" +end # ControlInterface + +end # Ecasound::