alsa-backup 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|