dtas 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/.gitignore +9 -0
- data/.rsync_doc +3 -0
- data/COPYING +674 -0
- data/Documentation/.gitignore +3 -0
- data/Documentation/GNUmakefile +46 -0
- data/Documentation/dtas-console.txt +42 -0
- data/Documentation/dtas-ctl.txt +64 -0
- data/Documentation/dtas-cueedit.txt +24 -0
- data/Documentation/dtas-enq.txt +29 -0
- data/Documentation/dtas-msinkctl.txt +45 -0
- data/Documentation/dtas-player.txt +110 -0
- data/Documentation/dtas-player_effects.txt +45 -0
- data/Documentation/dtas-player_protocol.txt +181 -0
- data/Documentation/dtas-sinkedit.txt +41 -0
- data/Documentation/dtas-sourceedit.txt +33 -0
- data/Documentation/dtas-xdelay.txt +57 -0
- data/Documentation/troubleshooting.txt +13 -0
- data/GIT-VERSION-GEN +30 -0
- data/GNUmakefile +9 -0
- data/HACKING +12 -0
- data/INSTALL +53 -0
- data/README +103 -0
- data/Rakefile +97 -0
- data/TODO +4 -0
- data/bin/dtas-console +160 -0
- data/bin/dtas-ctl +10 -0
- data/bin/dtas-cueedit +78 -0
- data/bin/dtas-enq +13 -0
- data/bin/dtas-msinkctl +51 -0
- data/bin/dtas-player +34 -0
- data/bin/dtas-sinkedit +58 -0
- data/bin/dtas-sourceedit +48 -0
- data/bin/dtas-xdelay +85 -0
- data/dtas-linux.gemspec +18 -0
- data/dtas-mpris.gemspec +16 -0
- data/examples/dtas_state.yml +18 -0
- data/lib/dtas.rb +7 -0
- data/lib/dtas/buffer.rb +90 -0
- data/lib/dtas/buffer/read_write.rb +102 -0
- data/lib/dtas/buffer/splice.rb +142 -0
- data/lib/dtas/command.rb +43 -0
- data/lib/dtas/compat_onenine.rb +18 -0
- data/lib/dtas/disclaimer.rb +18 -0
- data/lib/dtas/format.rb +151 -0
- data/lib/dtas/pipe.rb +39 -0
- data/lib/dtas/player.rb +393 -0
- data/lib/dtas/player/client_handler.rb +463 -0
- data/lib/dtas/process.rb +87 -0
- data/lib/dtas/replaygain.rb +41 -0
- data/lib/dtas/rg_state.rb +99 -0
- data/lib/dtas/serialize.rb +9 -0
- data/lib/dtas/sigevent.rb +10 -0
- data/lib/dtas/sigevent/efd.rb +20 -0
- data/lib/dtas/sigevent/pipe.rb +28 -0
- data/lib/dtas/sink.rb +121 -0
- data/lib/dtas/source.rb +147 -0
- data/lib/dtas/source/command.rb +40 -0
- data/lib/dtas/source/common.rb +14 -0
- data/lib/dtas/source/mp3.rb +37 -0
- data/lib/dtas/state_file.rb +33 -0
- data/lib/dtas/unix_accepted.rb +76 -0
- data/lib/dtas/unix_client.rb +51 -0
- data/lib/dtas/unix_server.rb +110 -0
- data/lib/dtas/util.rb +15 -0
- data/lib/dtas/writable_iter.rb +22 -0
- data/perl/dtas-graph +129 -0
- data/pkg.mk +26 -0
- data/setup.rb +1586 -0
- data/test/covshow.rb +30 -0
- data/test/helper.rb +76 -0
- data/test/player_integration.rb +121 -0
- data/test/test_buffer.rb +216 -0
- data/test/test_format.rb +61 -0
- data/test/test_format_change.rb +49 -0
- data/test/test_player.rb +47 -0
- data/test/test_player_client_handler.rb +86 -0
- data/test/test_player_integration.rb +220 -0
- data/test/test_rg_integration.rb +117 -0
- data/test/test_rg_state.rb +32 -0
- data/test/test_sink.rb +32 -0
- data/test/test_sink_tee_integration.rb +34 -0
- data/test/test_source.rb +102 -0
- data/test/test_unixserver.rb +66 -0
- data/test/test_util.rb +15 -0
- metadata +208 -0
data/test/covshow.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
3
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
+
#
|
5
|
+
# this works with the __covmerge method in test/helper.rb
|
6
|
+
# run this file after all tests are run
|
7
|
+
|
8
|
+
# load the merged dump data
|
9
|
+
res = Marshal.load(IO.binread("coverage.dump"))
|
10
|
+
|
11
|
+
# Dirty little text formatter. I tried simplecov but the default
|
12
|
+
# HTML+JS is unusable without a GUI (I hate GUIs :P) and it would've
|
13
|
+
# taken me longer to search the Internets to find a plain-text
|
14
|
+
# formatter I like...
|
15
|
+
res.keys.sort.each do |filename|
|
16
|
+
cov = res[filename]
|
17
|
+
puts "==> #{filename} <=="
|
18
|
+
File.readlines(filename).each_with_index do |line, i|
|
19
|
+
n = cov[i]
|
20
|
+
if n == 0 # BAD
|
21
|
+
print(" *** 0 #{line}")
|
22
|
+
elsif n
|
23
|
+
printf("% 7u %s", n, line)
|
24
|
+
elsif line =~ /\S/ # probably a line with just "end" in it
|
25
|
+
print(" #{line}")
|
26
|
+
else # blank line
|
27
|
+
print "\n" # don't output trailing whitespace on blank lines
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
3
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
+
$stdout.sync = $stderr.sync = Thread.abort_on_exception = true
|
5
|
+
|
6
|
+
# fork-aware coverage data gatherer, see also test/covshow.rb
|
7
|
+
if ENV["COVERAGE"]
|
8
|
+
require "coverage"
|
9
|
+
COVMATCH = %r{/lib/dtas\b.*rb\z}
|
10
|
+
COVTMP = File.open("coverage.dump", IO::CREAT|IO::RDWR)
|
11
|
+
COVTMP.binmode
|
12
|
+
COVTMP.sync = true
|
13
|
+
|
14
|
+
def __covmerge
|
15
|
+
res = Coverage.result
|
16
|
+
|
17
|
+
# we own this file (at least until somebody tries to use NFS :x)
|
18
|
+
COVTMP.flock(File::LOCK_EX)
|
19
|
+
|
20
|
+
COVTMP.rewind
|
21
|
+
prev = COVTMP.read
|
22
|
+
prev = prev.empty? ? {} : Marshal.load(prev)
|
23
|
+
res.each do |filename, counts|
|
24
|
+
# filter out stuff that's not in our project
|
25
|
+
COVMATCH =~ filename or next
|
26
|
+
|
27
|
+
merge = prev[filename] || []
|
28
|
+
merge = merge
|
29
|
+
counts.each_with_index do |count, i|
|
30
|
+
count or next
|
31
|
+
merge[i] = (merge[i] || 0) + count
|
32
|
+
end
|
33
|
+
prev[filename] = merge
|
34
|
+
end
|
35
|
+
COVTMP.rewind
|
36
|
+
COVTMP.truncate(0)
|
37
|
+
COVTMP.write(Marshal.dump(prev))
|
38
|
+
ensure
|
39
|
+
COVTMP.flock(File::LOCK_UN)
|
40
|
+
end
|
41
|
+
|
42
|
+
Coverage.start
|
43
|
+
at_exit { __covmerge }
|
44
|
+
end
|
45
|
+
|
46
|
+
gem 'minitest'
|
47
|
+
require 'minitest/autorun'
|
48
|
+
require "tempfile"
|
49
|
+
|
50
|
+
FIFOS = []
|
51
|
+
at_exit { FIFOS.each { |(pid,path)| File.unlink(path) if $$ == pid } }
|
52
|
+
def tmpfifo
|
53
|
+
tmp = Tempfile.new(%w(dtas-test .fifo))
|
54
|
+
path = tmp.path
|
55
|
+
tmp.close!
|
56
|
+
assert system(*%W(mkfifo #{path})), "mkfifo #{path}"
|
57
|
+
FIFOS << [ $$, path ]
|
58
|
+
path
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'tmpdir'
|
62
|
+
class Dir
|
63
|
+
require 'fileutils'
|
64
|
+
def Dir.mktmpdir
|
65
|
+
begin
|
66
|
+
d = "#{Dir.tmpdir}/#$$.#{rand}"
|
67
|
+
Dir.mkdir(d)
|
68
|
+
rescue Errno::EEXIST
|
69
|
+
end while true
|
70
|
+
begin
|
71
|
+
yield d
|
72
|
+
ensure
|
73
|
+
FileUtils.remove_entry(d)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end unless Dir.respond_to?(:mktmpdir)
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
3
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
+
require './test/helper'
|
5
|
+
require 'dtas/player'
|
6
|
+
require 'dtas/state_file'
|
7
|
+
require 'yaml'
|
8
|
+
require 'tempfile'
|
9
|
+
require 'shellwords'
|
10
|
+
require 'timeout'
|
11
|
+
|
12
|
+
module PlayerIntegration
|
13
|
+
def setup
|
14
|
+
sock_tmp = Tempfile.new(%w(dtas-test .sock))
|
15
|
+
@state_tmp = Tempfile.new(%w(dtas-test .yml))
|
16
|
+
@sock_path = sock_tmp.path
|
17
|
+
sock_tmp.close!
|
18
|
+
@player = DTAS::Player.new
|
19
|
+
@player.socket = @sock_path
|
20
|
+
@player.state_file = DTAS::StateFile.new(@state_tmp.path)
|
21
|
+
@player.bind
|
22
|
+
@out = Tempfile.new(%w(dtas-test .out))
|
23
|
+
@err = Tempfile.new(%w(dtas-test .err))
|
24
|
+
@out.sync = @err.sync = true
|
25
|
+
@pid = fork do
|
26
|
+
at_exit { @player.close }
|
27
|
+
ENV["SOX_OPTS"] = "#{ENV['SOX_OPTS']} -R"
|
28
|
+
unless $DEBUG
|
29
|
+
$stdout.reopen(@out)
|
30
|
+
$stderr.reopen(@err)
|
31
|
+
end
|
32
|
+
@player.run
|
33
|
+
end
|
34
|
+
|
35
|
+
# null playback device with delay to simulate a real device
|
36
|
+
@fmt = DTAS::Format.new
|
37
|
+
@period = 0.01
|
38
|
+
@period_size = @fmt.bytes_per_sample * @fmt.channels * @fmt.rate * @period
|
39
|
+
@cmd = "exec 2>/dev/null " \
|
40
|
+
"ruby -e " \
|
41
|
+
"\"b=%q();loop{STDIN.readpartial(#@period_size,b);sleep(#@period)}\""
|
42
|
+
|
43
|
+
# FIXME gross...
|
44
|
+
@player.instance_eval do
|
45
|
+
@sink_buf.close!
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module PlayerClient
|
50
|
+
def preq(args)
|
51
|
+
args = Shellwords.join(args) if Array === args
|
52
|
+
send(args, Socket::MSG_EOR)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def client_socket
|
57
|
+
s = Socket.new(:AF_UNIX, :SOCK_SEQPACKET, 0)
|
58
|
+
s.connect(Socket.pack_sockaddr_un(@sock_path))
|
59
|
+
s.extend(PlayerClient)
|
60
|
+
s
|
61
|
+
end
|
62
|
+
|
63
|
+
def wait_pid_dead(pid, time = 5)
|
64
|
+
Timeout.timeout(time) do
|
65
|
+
begin
|
66
|
+
Process.kill(0, pid)
|
67
|
+
sleep(0.01)
|
68
|
+
rescue Errno::ESRCH
|
69
|
+
return
|
70
|
+
end while true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def wait_files_not_empty(*files)
|
75
|
+
files = Array(files)
|
76
|
+
Timeout.timeout(5) { sleep(0.01) until files.all? { |f| f.size > 0 } }
|
77
|
+
end
|
78
|
+
|
79
|
+
def default_sink_pid(s)
|
80
|
+
default_pid = Tempfile.new(%w(dtas-test .pid))
|
81
|
+
pf = "echo $$ >> #{default_pid.path}; "
|
82
|
+
s.send("sink ed default command='#{pf}#@cmd'", Socket::MSG_EOR)
|
83
|
+
assert_equal "OK", s.readpartial(666)
|
84
|
+
default_pid
|
85
|
+
end
|
86
|
+
|
87
|
+
def teardown
|
88
|
+
Process.kill(:TERM, @pid) if @pid
|
89
|
+
Process.waitall
|
90
|
+
refute File.exist?(@sock_path)
|
91
|
+
@state_tmp.close!
|
92
|
+
@out.close! if @out
|
93
|
+
@err.close! if @err
|
94
|
+
end
|
95
|
+
|
96
|
+
def read_pid_file(file)
|
97
|
+
file.rewind
|
98
|
+
pid = file.read.to_i
|
99
|
+
assert_operator pid, :>, 0
|
100
|
+
pid
|
101
|
+
end
|
102
|
+
|
103
|
+
def tmp_noise(len = 5)
|
104
|
+
noise = Tempfile.open(%w(junk .sox))
|
105
|
+
cmd = %W(sox -R -n -r44100 -c2 #{noise.path} synth #{len} pluck)
|
106
|
+
assert system(*cmd), cmd
|
107
|
+
[ noise, len ]
|
108
|
+
end
|
109
|
+
|
110
|
+
def dethrottle_decoder(s)
|
111
|
+
s.send("sink ed default active=false", Socket::MSG_EOR)
|
112
|
+
assert_equal "OK", s.readpartial(666)
|
113
|
+
end
|
114
|
+
|
115
|
+
def stop_playback(pid_file, s)
|
116
|
+
s.send("skip", Socket::MSG_EOR)
|
117
|
+
assert_equal "OK", s.readpartial(666)
|
118
|
+
pid = read_pid_file(pid_file)
|
119
|
+
wait_pid_dead(pid)
|
120
|
+
end
|
121
|
+
end
|
data/test/test_buffer.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
3
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
+
require './test/helper'
|
5
|
+
require 'stringio'
|
6
|
+
require 'dtas/buffer'
|
7
|
+
|
8
|
+
class TestBuffer < Minitest::Unit::TestCase
|
9
|
+
def teardown
|
10
|
+
@to_close.each { |io| io.close unless io.closed? }
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@to_close = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def pipe
|
18
|
+
ret = IO.pipe
|
19
|
+
@to_close.concat(ret)
|
20
|
+
ret
|
21
|
+
end
|
22
|
+
|
23
|
+
def tmperr
|
24
|
+
olderr = $stderr
|
25
|
+
$stderr = newerr = StringIO.new
|
26
|
+
yield
|
27
|
+
newerr
|
28
|
+
ensure
|
29
|
+
$stderr = olderr
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_buffer
|
33
|
+
buf = DTAS::Buffer.new
|
34
|
+
@to_close << buf.to_io
|
35
|
+
@to_close << buf.wr
|
36
|
+
buf
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_set_buffer_size
|
40
|
+
buf = new_buffer
|
41
|
+
buf.buffer_size = DTAS::Buffer::MAX_SIZE
|
42
|
+
assert_equal DTAS::Buffer::MAX_SIZE, buf.buffer_size
|
43
|
+
end if defined?(DTAS::Buffer::MAX_SIZE)
|
44
|
+
|
45
|
+
def test_buffer_size
|
46
|
+
buf = new_buffer
|
47
|
+
assert_operator buf.buffer_size, :>, 128
|
48
|
+
buf.buffer_size = DTAS::Buffer::MAX_SIZE
|
49
|
+
assert_equal DTAS::Buffer::MAX_SIZE, buf.buffer_size
|
50
|
+
end if defined?(DTAS::Buffer::MAX_SIZE)
|
51
|
+
|
52
|
+
def test_broadcast_1
|
53
|
+
buf = new_buffer
|
54
|
+
r, w = IO.pipe
|
55
|
+
assert_equal :wait_readable, buf.broadcast([w])
|
56
|
+
assert_equal 0, buf.bytes_xfer
|
57
|
+
buf.wr.write "HIHI"
|
58
|
+
assert_equal :wait_readable, buf.broadcast([w])
|
59
|
+
assert_equal 4, buf.bytes_xfer
|
60
|
+
assert_equal :wait_readable, buf.broadcast([w])
|
61
|
+
assert_equal 4, buf.bytes_xfer
|
62
|
+
tmp = [w]
|
63
|
+
r.close
|
64
|
+
buf.wr.write "HIHI"
|
65
|
+
newerr = tmperr { assert_nil buf.broadcast(tmp) }
|
66
|
+
assert_equal [], tmp
|
67
|
+
assert_match(%r{dropping}, newerr.string)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_broadcast_tee
|
71
|
+
buf = new_buffer
|
72
|
+
return unless buf.respond_to?(:__broadcast_tee)
|
73
|
+
blocked = []
|
74
|
+
a = pipe
|
75
|
+
b = pipe
|
76
|
+
buf.wr.write "HELLO"
|
77
|
+
assert_equal 4, buf.__broadcast_tee(blocked, [a[1], b[1]], 4)
|
78
|
+
assert_empty blocked
|
79
|
+
assert_equal "HELL", a[0].read(4)
|
80
|
+
assert_equal "HELL", b[0].read(4)
|
81
|
+
assert_equal 5, buf.__broadcast_tee(blocked, [a[1], b[1]], 5)
|
82
|
+
assert_empty blocked
|
83
|
+
assert_equal "HELLO", a[0].read(5)
|
84
|
+
assert_equal "HELLO", b[0].read(5)
|
85
|
+
max = '*' * a[0].pipe_size
|
86
|
+
assert_equal max.size, a[1].write(max)
|
87
|
+
assert_equal a[0].nread, a[0].pipe_size
|
88
|
+
a[1].nonblock = true
|
89
|
+
assert_equal 5, buf.__broadcast_tee(blocked, [a[1], b[1]], 5)
|
90
|
+
assert_equal [a[1]], blocked
|
91
|
+
a[1].nonblock = false
|
92
|
+
b[0].read(b[0].nread)
|
93
|
+
b[1].write(max)
|
94
|
+
t = Thread.new do
|
95
|
+
sleep 0.005
|
96
|
+
[ a[0].read(max.size).size, b[0].read(max.size).size ]
|
97
|
+
end
|
98
|
+
assert_equal 5, buf.__broadcast_tee(blocked, [a[1], b[1]], 5)
|
99
|
+
assert_equal [a[1]], blocked
|
100
|
+
assert_equal [ max.size, max.size ], t.value
|
101
|
+
b[0].close
|
102
|
+
tmp = [a[1], b[1]]
|
103
|
+
|
104
|
+
newerr = tmperr { assert_equal 5, buf.__broadcast_tee(blocked, tmp, 5) }
|
105
|
+
assert_equal [a[1]], blocked
|
106
|
+
assert_match(%r{dropping}, newerr.string)
|
107
|
+
assert_equal [a[1]], tmp
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_broadcast
|
111
|
+
a = pipe
|
112
|
+
b = pipe
|
113
|
+
buf = new_buffer
|
114
|
+
buf.wr.write "HELLO"
|
115
|
+
assert_equal :wait_readable, buf.broadcast([a[1], b[1]])
|
116
|
+
assert_equal 5, buf.bytes_xfer
|
117
|
+
assert_equal "HELLO", a[0].read(5)
|
118
|
+
assert_equal "HELLO", b[0].read(5)
|
119
|
+
assert_equal :wait_readable, buf.broadcast([a[1], b[1]])
|
120
|
+
assert_equal 5, buf.bytes_xfer
|
121
|
+
|
122
|
+
b[1].nonblock = true
|
123
|
+
b[1].write('*' * b[1].pipe_size)
|
124
|
+
buf.wr.write "BYE"
|
125
|
+
assert_equal :wait_readable, buf.broadcast([a[1], b[1]])
|
126
|
+
assert_equal 8, buf.bytes_xfer
|
127
|
+
|
128
|
+
buf.wr.write "DROP"
|
129
|
+
b[0].close
|
130
|
+
tmp = [a[1], b[1]]
|
131
|
+
newerr = tmperr { assert_equal :wait_readable, buf.broadcast(tmp) }
|
132
|
+
assert_equal 12, buf.bytes_xfer
|
133
|
+
assert_equal [a[1]], tmp
|
134
|
+
assert_match(%r{dropping}, newerr.string)
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_broadcast_total_fail
|
138
|
+
a = pipe
|
139
|
+
b = pipe
|
140
|
+
buf = new_buffer
|
141
|
+
buf.wr.write "HELLO"
|
142
|
+
a[0].close
|
143
|
+
b[0].close
|
144
|
+
tmp = [a[1], b[1]]
|
145
|
+
newerr = tmperr { assert_nil buf.broadcast(tmp) }
|
146
|
+
assert_equal [], tmp
|
147
|
+
assert_match(%r{dropping}, newerr.string)
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_broadcast_mostly_fail
|
151
|
+
a = pipe
|
152
|
+
b = pipe
|
153
|
+
c = pipe
|
154
|
+
buf = new_buffer
|
155
|
+
buf.wr.write "HELLO"
|
156
|
+
b[0].close
|
157
|
+
c[0].close
|
158
|
+
tmp = [a[1], b[1], c[1]]
|
159
|
+
newerr = tmperr { assert_equal :wait_readable, buf.broadcast(tmp) }
|
160
|
+
assert_equal 5, buf.bytes_xfer
|
161
|
+
assert_equal [a[1]], tmp
|
162
|
+
assert_match(%r{dropping}, newerr.string)
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_broadcast_all_full
|
166
|
+
a = pipe
|
167
|
+
b = pipe
|
168
|
+
buf = new_buffer
|
169
|
+
a[1].write('*' * a[1].pipe_size)
|
170
|
+
b[1].write('*' * b[1].pipe_size)
|
171
|
+
|
172
|
+
a[1].nonblock = true
|
173
|
+
b[1].nonblock = true
|
174
|
+
tmp = [a[1], b[1]]
|
175
|
+
|
176
|
+
buf.wr.write "HELLO"
|
177
|
+
assert_equal tmp, buf.broadcast(tmp)
|
178
|
+
assert_equal [a[1], b[1]], tmp
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_serialize
|
182
|
+
buf = new_buffer
|
183
|
+
hash = buf.to_hsh
|
184
|
+
assert_empty hash
|
185
|
+
buf.buffer_size = 4096
|
186
|
+
hash = buf.to_hsh
|
187
|
+
assert_equal %w(buffer_size), hash.keys
|
188
|
+
assert_kind_of Integer, hash["buffer_size"]
|
189
|
+
assert_operator hash["buffer_size"], :>, 0
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_close
|
193
|
+
buf = DTAS::Buffer.new
|
194
|
+
buf.wr.write "HI"
|
195
|
+
assert_equal 2, buf.inflight
|
196
|
+
buf.close
|
197
|
+
assert_equal 0, buf.inflight
|
198
|
+
assert_nil buf.close!
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_load_nil
|
202
|
+
buf = DTAS::Buffer.load(nil)
|
203
|
+
buf.close!
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_load_empty
|
207
|
+
buf = DTAS::Buffer.load({})
|
208
|
+
buf.close!
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_load_size
|
212
|
+
buf = DTAS::Buffer.load({"buffer_size" => 4096})
|
213
|
+
assert_equal 4096, buf.buffer_size
|
214
|
+
buf.close!
|
215
|
+
end
|
216
|
+
end
|
data/test/test_format.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
3
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
+
require './test/helper'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'dtas/format'
|
7
|
+
|
8
|
+
class TestFormat < Minitest::Unit::TestCase
|
9
|
+
def test_initialize
|
10
|
+
fmt = DTAS::Format.new
|
11
|
+
assert_equal %w(-ts32 -c2 -r44100), fmt.to_sox_arg
|
12
|
+
hash = fmt.to_hsh
|
13
|
+
assert_equal({}, hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_nonstandard
|
17
|
+
fmt = DTAS::Format.new
|
18
|
+
fmt.type = "s16"
|
19
|
+
fmt.rate = 48000
|
20
|
+
fmt.channels = 4
|
21
|
+
hash = fmt.to_hsh
|
22
|
+
assert_kind_of Hash, hash
|
23
|
+
assert_equal %w(channels rate type), hash.keys.sort
|
24
|
+
assert_equal "s16", hash["type"]
|
25
|
+
assert_equal 48000, hash["rate"]
|
26
|
+
assert_equal 4, hash["channels"]
|
27
|
+
|
28
|
+
# back to stereo
|
29
|
+
fmt.channels = 2
|
30
|
+
hash = fmt.to_hsh
|
31
|
+
assert_equal %w(rate type), hash.keys.sort
|
32
|
+
assert_equal "s16", hash["type"]
|
33
|
+
assert_equal 48000, hash["rate"]
|
34
|
+
assert_nil hash["channels"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_from_file
|
38
|
+
Tempfile.open(%w(tmp .wav)) do |tmp|
|
39
|
+
# generate an empty file with 1s of audio
|
40
|
+
cmd = %W(sox -r 96000 -b 24 -c 2 -n #{tmp.path} trim 0 1)
|
41
|
+
system(*cmd)
|
42
|
+
assert $?.success?, "#{cmd.inspect} failed: #$?"
|
43
|
+
fmt = DTAS::Format.new
|
44
|
+
fmt.from_file tmp.path
|
45
|
+
assert_equal 96000, fmt.rate
|
46
|
+
assert_equal 2, fmt.channels
|
47
|
+
tmp.unlink
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_bytes_per_sample
|
52
|
+
fmt = DTAS::Format.new
|
53
|
+
assert_equal 4, fmt.bytes_per_sample
|
54
|
+
fmt.type = "f64"
|
55
|
+
assert_equal 8, fmt.bytes_per_sample
|
56
|
+
fmt.type = "f32"
|
57
|
+
assert_equal 4, fmt.bytes_per_sample
|
58
|
+
fmt.type = "s16"
|
59
|
+
assert_equal 2, fmt.bytes_per_sample
|
60
|
+
end
|
61
|
+
end
|