alsa-backup 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +4 -0
- data/History.txt +32 -0
- data/Manifest.txt +32 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +106 -0
- data/Rakefile +65 -0
- data/TODO +3 -0
- data/alsa-backup.gemspec +47 -0
- data/bin/alsa-backup +9 -0
- data/config.sample +91 -0
- data/lib/alsa.rb +299 -0
- data/lib/alsa_backup.rb +37 -0
- data/lib/alsa_backup/cli.rb +56 -0
- data/lib/alsa_backup/core_ext.rb +34 -0
- data/lib/alsa_backup/length_controller.rb +21 -0
- data/lib/alsa_backup/recorder.rb +91 -0
- data/lib/alsa_backup/writer.rb +124 -0
- data/lib/sndfile.rb +138 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/alsa/pcm_spec.rb +7 -0
- data/spec/alsa_backup/cli_spec.rb +78 -0
- data/spec/alsa_backup/core_ext_spec.rb +42 -0
- data/spec/alsa_backup/recorder_spec.rb +145 -0
- data/spec/alsa_backup/writer_spec.rb +130 -0
- data/spec/alsa_backup_spec.rb +11 -0
- data/spec/fixtures/config_test.rb +3 -0
- data/spec/sndfile/info_spec.rb +38 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +30 -0
- data/tasks/rspec.rake +35 -0
- metadata +139 -0
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/alsa_backup.rb'}"
|
9
|
+
puts "Loading alsa_backup gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'alsa_backup/cli'
|
4
|
+
|
5
|
+
describe AlsaBackup::CLI, "execute" do
|
6
|
+
before(:each) do
|
7
|
+
@stdout_io = StringIO.new
|
8
|
+
@file = test_file
|
9
|
+
|
10
|
+
@recorder = AlsaBackup::Recorder.new(@file)
|
11
|
+
@recorder.stub!(:start)
|
12
|
+
AlsaBackup.stub!(:recorder).and_return(@recorder)
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute_cli(options = {})
|
16
|
+
options = { :file => @file, :length => 2 }.update(options)
|
17
|
+
arguments = options.collect do |key,value|
|
18
|
+
if value
|
19
|
+
returning "--#{key}" do |argument|
|
20
|
+
argument << "=#{value}" unless value == true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end.compact
|
24
|
+
|
25
|
+
AlsaBackup::CLI.execute(@stdout_io, *arguments)
|
26
|
+
@stdout_io.rewind
|
27
|
+
@stdout = @stdout_io.read
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should use AlsaBackup.recorder" do
|
31
|
+
AlsaBackup.should_receive(:recorder).and_return(@recorder)
|
32
|
+
execute_cli
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set the record file with specified one" do
|
36
|
+
@recorder.should_receive(:file=).with(file = "dummy")
|
37
|
+
execute_cli :file => file
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should start the AlsaBackup.recorder" do
|
41
|
+
@recorder.should_receive(:start)
|
42
|
+
execute_cli
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should start the recorder with specified length" do
|
46
|
+
@recorder.should_receive(:start).with(length = 60)
|
47
|
+
execute_cli :length => length
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should start the record without length if not specified" do
|
51
|
+
@recorder.should_receive(:start).with(nil)
|
52
|
+
execute_cli :length => nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should execute specified config file" do
|
56
|
+
execute_cli :config => fixture_file('config_test.rb'), :file => nil
|
57
|
+
AlsaBackup.recorder.file.should == "config_test_ok"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should override config file values with command line arguments" do
|
61
|
+
argument_file = "dummy"
|
62
|
+
execute_cli :config => fixture_file('config_test.rb'), :file => argument_file
|
63
|
+
AlsaBackup.recorder.file.should == argument_file
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should write pid in specified file" do
|
67
|
+
pid_file = test_file("pid")
|
68
|
+
execute_cli :pid => pid_file
|
69
|
+
|
70
|
+
IO.read(pid_file).strip.should == $$.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should daemonize the process with option background" do
|
74
|
+
Daemonize.should_receive(:daemonize)
|
75
|
+
execute_cli :background => true
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Time do
|
4
|
+
|
5
|
+
describe "floor" do
|
6
|
+
|
7
|
+
it "should change xh41 on xh49 for min with a modulo of 10" do
|
8
|
+
time = Time.now.change(:min => 49)
|
9
|
+
time.floor(:min, 10).should == time.change(:min => 40)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe File do
|
17
|
+
|
18
|
+
describe "suffix_basename" do
|
19
|
+
|
20
|
+
def take_this_form(expected_file)
|
21
|
+
simple_matcher("have this #{expected_file}") do |actual|
|
22
|
+
File.suffix_basename(actual,'<prefix>') == expected_file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it { 'test.rb'.should take_this_form('test<prefix>.rb') }
|
27
|
+
|
28
|
+
it "should return test<prefix> for test" do
|
29
|
+
File.suffix_basename('test','<prefix>').should == 'test<prefix>'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return /path/test<prefix>.rb for /patest" do
|
33
|
+
File.suffix_basename('/path/test.rb','<prefix>').should == '/path/test<prefix>.rb'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return /test<prefix>.rb for /test.rb" do
|
37
|
+
File.suffix_basename('/path/test.rb','<prefix>').should == '/path/test<prefix>.rb'
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'alsa_backup/recorder'
|
4
|
+
|
5
|
+
describe AlsaBackup::Recorder do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@file = test_file
|
9
|
+
@recorder = AlsaBackup::Recorder.new(@file)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not raise an error on start" do
|
13
|
+
@recorder.start(2)
|
14
|
+
lambda { @recorder.start(2) }.should_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should use the specified alsa device" do
|
18
|
+
@recorder.device = alsa_device = "dummy"
|
19
|
+
ALSA::PCM::Capture.should_receive(:open).with(alsa_device, anything)
|
20
|
+
@recorder.open_capture
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should use the specified sample rate" do
|
24
|
+
@recorder.sample_rate = 48000
|
25
|
+
@recorder.format[:sample_rate].should == @recorder.sample_rate
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should use the specified channels" do
|
29
|
+
@recorder.channels = 4
|
30
|
+
@recorder.format[:channels].should == @recorder.channels
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should use 44100 as default sample rate" do
|
34
|
+
@recorder.sample_rate.should == 44100
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should use 2 as default channels" do
|
38
|
+
@recorder.channels.should == 2
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should use hw:0 as default device" do
|
42
|
+
@recorder.device.should == "hw:0"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should stop the recording on Interrupt error" do
|
46
|
+
@recorder.stub!(:open_writer).and_raise(Interrupt)
|
47
|
+
@recorder.start
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "error handler" do
|
51
|
+
|
52
|
+
class TestErrorHandler
|
53
|
+
|
54
|
+
def initialize(proc)
|
55
|
+
proc = Proc.new { |e| proc } unless Proc == proc
|
56
|
+
@proc = proc
|
57
|
+
end
|
58
|
+
|
59
|
+
def call(e)
|
60
|
+
if @proc
|
61
|
+
response = @proc.call(e)
|
62
|
+
@proc = nil
|
63
|
+
response
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
before(:each) do
|
70
|
+
AlsaBackup::Writer.stub!(:open).and_raise("dummy")
|
71
|
+
@recorder.stub!(:sleep)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should raise error when error handler is nil" do
|
75
|
+
@recorder.error_handler = nil
|
76
|
+
lambda { @recorder.start }.should raise_error
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise error when error handler returns nil or false" do
|
80
|
+
@recorder.error_handler = TestErrorHandler.new(nil)
|
81
|
+
lambda { @recorder.start }.should raise_error
|
82
|
+
end
|
83
|
+
|
84
|
+
def start_recorder(limit = nil)
|
85
|
+
@recorder.start(limit)
|
86
|
+
rescue RuntimeError
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should retry when error handler returns something (not false or nil)" do
|
91
|
+
@recorder.error_handler = TestErrorHandler.new(true)
|
92
|
+
AlsaBackup::Writer.should_receive(:open).twice().and_raise("dummy")
|
93
|
+
|
94
|
+
start_recorder
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should use the error handler response as sleep time if numerical" do
|
98
|
+
@recorder.error_handler = TestErrorHandler.new(error_handler_response = 5)
|
99
|
+
@recorder.should_receive(:sleep).with(error_handler_response)
|
100
|
+
start_recorder
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should sleep 5 seconds when the error handler response is a number" do
|
104
|
+
@recorder.error_handler = TestErrorHandler.new(true)
|
105
|
+
@recorder.should_receive(:sleep).with(5)
|
106
|
+
start_recorder
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not use error handler when recorder is started with a time length" do
|
110
|
+
@recorder.error_handler = mock("error_handler")
|
111
|
+
@recorder.error_handler.should_not_receive(:call)
|
112
|
+
|
113
|
+
start_recorder(2)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "open_writer" do
|
119
|
+
|
120
|
+
it "should use the given on_close block" do
|
121
|
+
on_close_block = Proc.new {}
|
122
|
+
@recorder.on_close &on_close_block
|
123
|
+
|
124
|
+
AlsaBackup::Writer.should_receive(:open).with(hash_including(:on_close => on_close_block))
|
125
|
+
@recorder.open_writer {}
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should use the directory" do
|
129
|
+
AlsaBackup::Writer.should_receive(:open).with(hash_including(:directory => @recorder.directory))
|
130
|
+
@recorder.open_writer {}
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should use the file" do
|
134
|
+
AlsaBackup::Writer.should_receive(:open).with(hash_including(:file => @recorder.file))
|
135
|
+
@recorder.open_writer {}
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should use the format wav pcm_16 with wanted sample_rate and channels" do
|
139
|
+
AlsaBackup::Writer.should_receive(:open).with(hash_including(:format => @recorder.format(:format => "wav pcm_16")))
|
140
|
+
@recorder.open_writer {}
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe AlsaBackup::Writer do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@file = "test.wav"
|
7
|
+
@directory = test_directory
|
8
|
+
@writer = AlsaBackup::Writer.new :directory => @directory, :file => @file
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "when created" do
|
12
|
+
|
13
|
+
it "should use the :directory option as directory" do
|
14
|
+
AlsaBackup::Writer.new(:directory => @directory).directory.should == @directory
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should use the :file option as file" do
|
18
|
+
AlsaBackup::Writer.new(:file => @file).file.should == @file
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should use the :format option as format" do
|
22
|
+
format = {:format => "test"}
|
23
|
+
AlsaBackup::Writer.new(:format => format).format.should == format
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should use default_format when no specified" do
|
27
|
+
AlsaBackup::Writer.new.format.should == AlsaBackup::Writer.default_format
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should include the given :on_close proc in on_close_callbacks" do
|
31
|
+
on_close_proc = Proc.new {}
|
32
|
+
AlsaBackup::Writer.new(:on_close => on_close_proc).on_close_callbacks.should include(on_close_proc)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "on_close" do
|
38
|
+
|
39
|
+
it "should include a callback which delete empty file" do
|
40
|
+
AlsaBackup::Writer.should_receive(:delete_empty_file).with(@file)
|
41
|
+
@writer.on_close(@file)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should invoke all on_close_callbacks" do
|
45
|
+
file_given_to_proc = nil
|
46
|
+
|
47
|
+
@writer.on_close_callbacks << Proc.new do |file|
|
48
|
+
file_given_to_proc = file
|
49
|
+
end
|
50
|
+
@writer.on_close(@file)
|
51
|
+
|
52
|
+
file_given_to_proc.should == @file
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should ignore exception from callbacks" do
|
56
|
+
@writer.on_close_callbacks << Proc.new do |file|
|
57
|
+
raise "Error"
|
58
|
+
end
|
59
|
+
lambda { @writer.on_close(@file) }.should_not raise_error
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "file" do
|
65
|
+
|
66
|
+
it "should accept file as string" do
|
67
|
+
@writer.file = file_name = "dummy"
|
68
|
+
@writer.file.should == file_name
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should accept file as Proc" do
|
72
|
+
file_name = "dummy"
|
73
|
+
@writer.file = Proc.new { file_name }
|
74
|
+
@writer.file.should == file_name
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "rename_existing_file" do
|
80
|
+
|
81
|
+
it "should keep file if not exists" do
|
82
|
+
File.should_receive(:exists?).with(@file).and_return(false)
|
83
|
+
File.should_not_receive(:rename)
|
84
|
+
AlsaBackup::Writer.rename_existing_file(@file)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should try to suffix with '-n' to find a free name" do
|
88
|
+
File.stub!(:exists?).and_return(true)
|
89
|
+
|
90
|
+
free_file = File.suffix_basename(@file, "-99")
|
91
|
+
File.should_receive(:exists?).with(free_file).and_return(false)
|
92
|
+
|
93
|
+
File.should_receive(:rename).with(@file, free_file)
|
94
|
+
AlsaBackup::Writer.rename_existing_file(@file)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should raise an error when no free file is found" do
|
98
|
+
File.stub!(:exists?).and_return(true)
|
99
|
+
lambda do
|
100
|
+
AlsaBackup::Writer.rename_existing_file(@file)
|
101
|
+
end.should raise_error
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "close" do
|
107
|
+
|
108
|
+
it "should close file (via close_file method)" do
|
109
|
+
@writer.should_receive(:close_file)
|
110
|
+
@writer.close
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "close_file" do
|
116
|
+
|
117
|
+
it "should close current sndfile" do
|
118
|
+
sndfile = @writer.sndfile
|
119
|
+
sndfile.should_receive(:close)
|
120
|
+
@writer.close_file
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should notify on_close callbacks (via on_close method)" do
|
124
|
+
@writer.should_receive(:on_close).with(@writer.sndfile.path)
|
125
|
+
@writer.close_file
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|