dtas 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +9 -0
  4. data/.rsync_doc +3 -0
  5. data/COPYING +674 -0
  6. data/Documentation/.gitignore +3 -0
  7. data/Documentation/GNUmakefile +46 -0
  8. data/Documentation/dtas-console.txt +42 -0
  9. data/Documentation/dtas-ctl.txt +64 -0
  10. data/Documentation/dtas-cueedit.txt +24 -0
  11. data/Documentation/dtas-enq.txt +29 -0
  12. data/Documentation/dtas-msinkctl.txt +45 -0
  13. data/Documentation/dtas-player.txt +110 -0
  14. data/Documentation/dtas-player_effects.txt +45 -0
  15. data/Documentation/dtas-player_protocol.txt +181 -0
  16. data/Documentation/dtas-sinkedit.txt +41 -0
  17. data/Documentation/dtas-sourceedit.txt +33 -0
  18. data/Documentation/dtas-xdelay.txt +57 -0
  19. data/Documentation/troubleshooting.txt +13 -0
  20. data/GIT-VERSION-GEN +30 -0
  21. data/GNUmakefile +9 -0
  22. data/HACKING +12 -0
  23. data/INSTALL +53 -0
  24. data/README +103 -0
  25. data/Rakefile +97 -0
  26. data/TODO +4 -0
  27. data/bin/dtas-console +160 -0
  28. data/bin/dtas-ctl +10 -0
  29. data/bin/dtas-cueedit +78 -0
  30. data/bin/dtas-enq +13 -0
  31. data/bin/dtas-msinkctl +51 -0
  32. data/bin/dtas-player +34 -0
  33. data/bin/dtas-sinkedit +58 -0
  34. data/bin/dtas-sourceedit +48 -0
  35. data/bin/dtas-xdelay +85 -0
  36. data/dtas-linux.gemspec +18 -0
  37. data/dtas-mpris.gemspec +16 -0
  38. data/examples/dtas_state.yml +18 -0
  39. data/lib/dtas.rb +7 -0
  40. data/lib/dtas/buffer.rb +90 -0
  41. data/lib/dtas/buffer/read_write.rb +102 -0
  42. data/lib/dtas/buffer/splice.rb +142 -0
  43. data/lib/dtas/command.rb +43 -0
  44. data/lib/dtas/compat_onenine.rb +18 -0
  45. data/lib/dtas/disclaimer.rb +18 -0
  46. data/lib/dtas/format.rb +151 -0
  47. data/lib/dtas/pipe.rb +39 -0
  48. data/lib/dtas/player.rb +393 -0
  49. data/lib/dtas/player/client_handler.rb +463 -0
  50. data/lib/dtas/process.rb +87 -0
  51. data/lib/dtas/replaygain.rb +41 -0
  52. data/lib/dtas/rg_state.rb +99 -0
  53. data/lib/dtas/serialize.rb +9 -0
  54. data/lib/dtas/sigevent.rb +10 -0
  55. data/lib/dtas/sigevent/efd.rb +20 -0
  56. data/lib/dtas/sigevent/pipe.rb +28 -0
  57. data/lib/dtas/sink.rb +121 -0
  58. data/lib/dtas/source.rb +147 -0
  59. data/lib/dtas/source/command.rb +40 -0
  60. data/lib/dtas/source/common.rb +14 -0
  61. data/lib/dtas/source/mp3.rb +37 -0
  62. data/lib/dtas/state_file.rb +33 -0
  63. data/lib/dtas/unix_accepted.rb +76 -0
  64. data/lib/dtas/unix_client.rb +51 -0
  65. data/lib/dtas/unix_server.rb +110 -0
  66. data/lib/dtas/util.rb +15 -0
  67. data/lib/dtas/writable_iter.rb +22 -0
  68. data/perl/dtas-graph +129 -0
  69. data/pkg.mk +26 -0
  70. data/setup.rb +1586 -0
  71. data/test/covshow.rb +30 -0
  72. data/test/helper.rb +76 -0
  73. data/test/player_integration.rb +121 -0
  74. data/test/test_buffer.rb +216 -0
  75. data/test/test_format.rb +61 -0
  76. data/test/test_format_change.rb +49 -0
  77. data/test/test_player.rb +47 -0
  78. data/test/test_player_client_handler.rb +86 -0
  79. data/test/test_player_integration.rb +220 -0
  80. data/test/test_rg_integration.rb +117 -0
  81. data/test/test_rg_state.rb +32 -0
  82. data/test/test_sink.rb +32 -0
  83. data/test/test_sink_tee_integration.rb +34 -0
  84. data/test/test_source.rb +102 -0
  85. data/test/test_unixserver.rb +66 -0
  86. data/test/test_util.rb +15 -0
  87. metadata +208 -0
@@ -0,0 +1,49 @@
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/player_integration'
5
+ require 'tmpdir'
6
+ class TestFormatChange < Minitest::Unit::TestCase
7
+ include PlayerIntegration
8
+
9
+ def test_format_change
10
+ s = client_socket
11
+ default_pid = default_sink_pid(s)
12
+ Dir.mktmpdir do |dir|
13
+ d = "#{dir}/dump.$CHANNELS.$RATE"
14
+ f44100 = File.open("#{dir}/dump.2.44100", IO::RDWR|IO::CREAT)
15
+ f88200 = File.open("#{dir}/dump.2.88200", IO::RDWR|IO::CREAT)
16
+ s.preq("sink ed dump active=true command='cat > #{d}'")
17
+ assert_equal "OK", s.readpartial(666)
18
+ noise, len = tmp_noise
19
+ s.preq(%W(enq #{noise.path}))
20
+ assert_equal "OK", s.readpartial(666)
21
+ wait_files_not_empty(default_pid, f44100)
22
+
23
+ s.preq("format rate=88200")
24
+ assert_equal "OK", s.readpartial(666)
25
+
26
+ wait_files_not_empty(f88200)
27
+
28
+ dethrottle_decoder(s)
29
+
30
+ Timeout.timeout(len) do
31
+ begin
32
+ s.preq("current")
33
+ cur = YAML.load(s.readpartial(6666))
34
+ end while cur["sinks"] && sleep(0.01)
35
+ end
36
+
37
+ c = "sox -R -ts32 -c2 -r88200 #{dir}/dump.2.88200 " \
38
+ "-ts32 -c2 -r44100 #{dir}/part2"
39
+ assert(system(c), c)
40
+
41
+ c = "sox -R -ts32 -c2 -r44100 #{dir}/dump.2.44100 " \
42
+ "-ts32 -c2 -r44100 #{dir}/part2 #{dir}/res.sox"
43
+ assert(system(c), c)
44
+
45
+ assert_equal `soxi -s #{dir}/res.sox`, `soxi -s #{noise.path}`
46
+ File.unlink(*Dir["#{dir}/*"].to_a)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,47 @@
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/player'
7
+
8
+ class TestPlayer < Minitest::Unit::TestCase
9
+ def setup
10
+ @player = nil
11
+ tmp = Tempfile.new(%w(dtas-player-test .sock))
12
+ @path = tmp.path
13
+ File.unlink(@path)
14
+ end
15
+
16
+ def teardown
17
+ @player.close if @player
18
+ end
19
+
20
+ def test_player_new
21
+ player = DTAS::Player.new
22
+ player.socket = @path
23
+ player.bind
24
+ assert File.socket?(@path)
25
+ ensure
26
+ player.close
27
+ refute File.socket?(@path)
28
+ end
29
+
30
+ def test_player_serialize
31
+ @player = DTAS::Player.new
32
+ @player.socket = @path
33
+ @player.bind
34
+ hash = @player.to_hsh
35
+ assert_equal({"socket" => @path}, hash)
36
+ end
37
+
38
+ def test_player_serialize_format
39
+ fmt = DTAS::Format.new
40
+ fmt.type = "f32"
41
+ fmt.rate = 48000
42
+ player = DTAS::Player.load("format" => fmt.to_hsh)
43
+ fhash = player.to_hsh["format"]
44
+ assert_equal "f32", fhash["type"]
45
+ assert_equal 48000, fhash["rate"]
46
+ end
47
+ end
@@ -0,0 +1,86 @@
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
+
7
+ class TestPlayerClientHandler < Minitest::Unit::TestCase
8
+ class MockIO < Array
9
+ alias emit push
10
+ end
11
+
12
+ include DTAS::Player::ClientHandler
13
+
14
+ def setup
15
+ @sinks = {}
16
+ @io = MockIO.new
17
+ @srv = nil # unused mock
18
+ end
19
+
20
+ def test_delete
21
+ @sinks["default"] = DTAS::Sink.new
22
+ @targets = []
23
+ sink_handler(@io, %w(rm default))
24
+ assert @sinks.empty?
25
+ assert_equal %w(OK), @io.to_a
26
+ end
27
+
28
+ def test_delete_noexist
29
+ sink_handler(@io, %w(rm default))
30
+ assert @sinks.empty?
31
+ assert_equal ["ERR default not found"], @io.to_a
32
+ end
33
+
34
+ def test_env
35
+ sink_handler(@io, %w(ed default env.FOO=bar))
36
+ assert_equal "bar", @sinks["default"].env["FOO"]
37
+ sink_handler(@io, %w(ed default env.FOO=))
38
+ assert_equal "", @sinks["default"].env["FOO"]
39
+ sink_handler(@io, %w(ed default env#FOO))
40
+ assert_nil @sinks["default"].env["FOO"]
41
+ end
42
+
43
+ def test_sink_ed
44
+ command = 'sox -t $SOX_FILETYPE -r $RATE -c $CHANNELS - \
45
+ -t s$SINK_BITS -r $SINK_RATE -c $SINK_CHANNELS - | \
46
+ aplay -D hw:DAC_1 -v -q -M --buffer-size=500000 --period-size=500 \
47
+ --disable-softvol --start-delay=100 \
48
+ --disable-format --disable-resample --disable-channels \
49
+ -t raw -c $SINK_CHANNELS -f S${SINK_BITS}_3LE -r $SINK_RATE
50
+ '
51
+ sink_handler(@io, %W(ed foo command=#{command}))
52
+ assert_equal command, @sinks["foo"].command
53
+ assert_empty @sinks["foo"].env
54
+ sink_handler(@io, %W(ed foo env.SINK_BITS=24))
55
+ sink_handler(@io, %W(ed foo env.SINK_CHANNELS=2))
56
+ sink_handler(@io, %W(ed foo env.SINK_RATE=48000))
57
+ expect = {
58
+ "SINK_BITS" => "24",
59
+ "SINK_CHANNELS" => "2",
60
+ "SINK_RATE" => "48000",
61
+ }
62
+ assert_equal expect, @sinks["foo"].env
63
+ @io.all? { |s| assert_equal "OK", s }
64
+ assert_equal 4, @io.size
65
+ end
66
+
67
+ def test_cat
68
+ sink = DTAS::Sink.new
69
+ sink.name = "default"
70
+ sink.command += "dither -s"
71
+ @sinks["default"] = sink
72
+ sink_handler(@io, %W(cat default))
73
+ assert_equal 1, @io.size
74
+ hsh = YAML.load(@io[0])
75
+ assert_kind_of Hash, hsh
76
+ assert_equal "default", hsh["name"]
77
+ assert_match("dither -s", hsh["command"])
78
+ end
79
+
80
+ def test_ls
81
+ expect = %w(a b c d)
82
+ expect.each { |s| @sinks[s] = true }
83
+ sink_handler(@io, %W(ls))
84
+ assert_equal expect, Shellwords.split(@io[0])
85
+ end
86
+ end
@@ -0,0 +1,220 @@
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/player_integration'
5
+ class TestPlayerIntegration < Minitest::Unit::TestCase
6
+ include PlayerIntegration
7
+
8
+ def test_cmd_rate
9
+ pid = fork do
10
+ @fmt.to_env.each { |k,v| ENV[k] = v }
11
+ exec("sox -n $SOXFMT - synth 3 pinknoise | #@cmd")
12
+ end
13
+ t = Time.now
14
+ _, _ = Process.waitpid2(pid)
15
+ elapsed = Time.now - t
16
+ assert_in_delta 3.0, elapsed, 0.5
17
+ end if ENV["MATH_IS_HARD"] # ensure our @cmd timing is accurate
18
+
19
+ def test_sink_close_after_play
20
+ s = client_socket
21
+ @cmd = "cat >/dev/null"
22
+ default_pid = default_sink_pid(s)
23
+ Tempfile.open('junk') do |junk|
24
+ pink = "sox -n $SOXFMT - synth 0.0001 pinknoise | tee -i #{junk.path}"
25
+ s.send("enq-cmd \"#{pink}\"", Socket::MSG_EOR)
26
+ wait_files_not_empty(junk)
27
+ assert_equal "OK", s.readpartial(666)
28
+ end
29
+ wait_files_not_empty(default_pid)
30
+ pid = read_pid_file(default_pid)
31
+ wait_pid_dead(pid)
32
+ end
33
+
34
+ def test_sink_killed_during_play
35
+ s = client_socket
36
+ default_pid = default_sink_pid(s)
37
+ cmd = Tempfile.new(%w(sox-cmd .pid))
38
+ pink = "echo $$ > #{cmd.path}; sox -n $SOXFMT - synth 100 pinknoise"
39
+ s.send("enq-cmd \"#{pink}\"", Socket::MSG_EOR)
40
+ assert_equal "OK", s.readpartial(666)
41
+ wait_files_not_empty(cmd, default_pid)
42
+ pid = read_pid_file(default_pid)
43
+ Process.kill(:KILL, pid)
44
+ cmd_pid = read_pid_file(cmd)
45
+ wait_pid_dead(cmd_pid)
46
+ end
47
+
48
+ def test_sink_activate
49
+ s = client_socket
50
+ s.send("sink ls", Socket::MSG_EOR)
51
+ assert_equal "default", s.readpartial(666)
52
+
53
+ # setup two outputs
54
+
55
+ # make the default sink trickle
56
+ default_pid = Tempfile.new(%w(dtas-test .pid))
57
+ pf = "echo $$ >> #{default_pid.path}; "
58
+ s.send("sink ed default command='#{pf}#@cmd'", Socket::MSG_EOR)
59
+ assert_equal "OK", s.readpartial(666)
60
+
61
+ # make a sleepy sink trickle, too
62
+ sleepy_pid = Tempfile.new(%w(dtas-test .pid))
63
+ pf = "echo $$ >> #{sleepy_pid.path};"
64
+ s.send("sink ed sleepy command='#{pf}#@cmd' active=true", Socket::MSG_EOR)
65
+ assert_equal "OK", s.readpartial(666)
66
+
67
+ # ensure both sinks were created
68
+ s.send("sink ls", Socket::MSG_EOR)
69
+ assert_equal "default sleepy", s.readpartial(666)
70
+
71
+ # generate pinknoise
72
+ pinknoise = "sox -n -r 44100 -c 2 -t s32 - synth 0 pinknoise"
73
+ s.send("enq-cmd \"#{pinknoise}\"", Socket::MSG_EOR)
74
+ assert_equal "OK", s.readpartial(666)
75
+
76
+ # wait for sinks to start
77
+ wait_files_not_empty(sleepy_pid, default_pid)
78
+
79
+ # deactivate sleepy sink and ensure it's gone
80
+ sleepy = File.read(sleepy_pid).to_i
81
+ assert_operator sleepy, :>, 0
82
+ Process.kill(0, sleepy)
83
+ s.send("sink ed sleepy active=false", Socket::MSG_EOR)
84
+ assert_equal "OK", s.readpartial(666)
85
+ wait_pid_dead(sleepy)
86
+
87
+ # ensure default sink is still alive
88
+ default = File.read(default_pid).to_i
89
+ assert_operator default, :>, 0
90
+ Process.kill(0, default)
91
+
92
+ # restart sleepy sink
93
+ sleepy_pid.sync = true
94
+ sleepy_pid.seek(0)
95
+ sleepy_pid.truncate(0)
96
+ s.send("sink ed sleepy active=true", Socket::MSG_EOR)
97
+ assert_equal "OK", s.readpartial(666)
98
+
99
+ # wait for sleepy sink
100
+ wait_files_not_empty(sleepy_pid)
101
+
102
+ # check sleepy restarted
103
+ sleepy = File.read(sleepy_pid).to_i
104
+ assert_operator sleepy, :>, 0
105
+ Process.kill(0, sleepy)
106
+
107
+ # stop playing current track
108
+ s.send("skip", Socket::MSG_EOR)
109
+ assert_equal "OK", s.readpartial(666)
110
+
111
+ wait_pid_dead(sleepy)
112
+ wait_pid_dead(default)
113
+ end
114
+
115
+ def test_env_change
116
+ s = client_socket
117
+ tmp = Tempfile.new(%w(env .txt))
118
+ s.preq("sink ed default active=true command='cat >/dev/null'")
119
+ assert_equal "OK", s.readpartial(666)
120
+
121
+ s.preq("env FOO=BAR")
122
+ assert_equal "OK", s.readpartial(666)
123
+ s.preq(["enq-cmd", "echo $FOO | tee #{tmp.path}"])
124
+ assert_equal "OK", s.readpartial(666)
125
+ wait_files_not_empty(tmp)
126
+ assert_equal "BAR\n", tmp.read
127
+
128
+ tmp.rewind
129
+ tmp.truncate(0)
130
+ s.preq("env FOO#")
131
+ assert_equal "OK", s.readpartial(666)
132
+ s.preq(["enq-cmd", "echo -$FOO- | tee #{tmp.path}"])
133
+ assert_equal "OK", s.readpartial(666)
134
+ wait_files_not_empty(tmp)
135
+ assert_equal "--\n", tmp.read
136
+ end
137
+
138
+ def test_sink_env
139
+ s = client_socket
140
+ tmp = Tempfile.new(%w(env .txt))
141
+ s.preq("sink ed default active=true command='echo -$FOO- > #{tmp.path}'")
142
+ assert_equal "OK", s.readpartial(666)
143
+
144
+ s.preq("sink ed default env.FOO=BAR")
145
+ assert_equal "OK", s.readpartial(666)
146
+ s.preq(["enq-cmd", "echo HI"])
147
+ assert_equal "OK", s.readpartial(666)
148
+ wait_files_not_empty(tmp)
149
+ assert_equal "-BAR-\n", tmp.read
150
+
151
+ tmp.rewind
152
+ tmp.truncate(0)
153
+ s.preq("sink ed default env#FOO")
154
+ assert_equal "OK", s.readpartial(666)
155
+
156
+ Timeout.timeout(5) do
157
+ begin
158
+ s.preq("current")
159
+ yaml = s.readpartial(66666)
160
+ cur = YAML.load(yaml)
161
+ end while cur["sinks"] && sleep(0.01)
162
+ end
163
+
164
+ s.preq(["enq-cmd", "echo HI"])
165
+ assert_equal "OK", s.readpartial(666)
166
+ wait_files_not_empty(tmp)
167
+ assert_equal "--\n", tmp.read
168
+ end
169
+
170
+ def test_enq_head
171
+ s = client_socket
172
+ default_sink_pid(s)
173
+ dump = Tempfile.new(%W(d .sox))
174
+ s.preq "sink ed dump active=true command='sox $SOXFMT - #{dump.path}'"
175
+ assert_equal "OK", s.readpartial(666)
176
+ noise, len = tmp_noise
177
+ s.preq("enq-head #{noise.path}")
178
+ assert_equal "OK", s.readpartial(666)
179
+ s.preq("enq-head #{noise.path} 4")
180
+ assert_equal "OK", s.readpartial(666)
181
+ s.preq("enq-head #{noise.path} 3")
182
+ assert_equal "OK", s.readpartial(666)
183
+ dethrottle_decoder(s)
184
+ expect = Tempfile.new(%W(expect .sox))
185
+
186
+ c = "sox #{noise.path} -t sox '|sox #{noise.path} -p trim 3' " \
187
+ "-t sox '|sox #{noise.path} -p trim 4' #{expect.path}"
188
+ assert system(c)
189
+ Timeout.timeout(len) do
190
+ begin
191
+ s.preq("current")
192
+ yaml = s.readpartial(66666)
193
+ cur = YAML.load(yaml)
194
+ end while cur["sinks"] && sleep(0.01)
195
+ end
196
+ assert(system("cmp", dump.path, expect.path),
197
+ "files don't match #{dump.path} != #{expect.path}")
198
+ end
199
+
200
+ def test_cd_pwd
201
+ s = client_socket
202
+ pwd = Dir.pwd
203
+
204
+ s.preq("pwd")
205
+ assert_equal pwd, s.readpartial(6666)
206
+
207
+ s.preq("cd /")
208
+ assert_equal "OK", s.readpartial(6)
209
+
210
+ s.preq("pwd")
211
+ assert_equal "/", s.readpartial(6)
212
+
213
+ s.preq("cd /this-better-be-totally-non-existent-on-any-system-#{rand}")
214
+ err = s.readpartial(666)
215
+ assert_match(%r{\AERR }, err, err)
216
+
217
+ s.preq("pwd")
218
+ assert_equal "/", s.readpartial(6)
219
+ end
220
+ end
@@ -0,0 +1,117 @@
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/player_integration'
5
+ class TestRgIntegration < Minitest::Unit::TestCase
6
+ include PlayerIntegration
7
+
8
+ def tmp_pluck(len = 5)
9
+ pluck = Tempfile.open(%w(pluck .flac))
10
+ cmd = %W(sox -R -n -r44100 -c2 -C0 #{pluck.path} synth #{len} pluck)
11
+ assert system(*cmd), cmd
12
+ cmd = %W(metaflac
13
+ --set-tag=REPLAYGAIN_TRACK_GAIN=-2
14
+ --set-tag=REPLAYGAIN_ALBUM_GAIN=-3.0
15
+ --set-tag=REPLAYGAIN_TRACK_PEAK=0.666
16
+ --set-tag=REPLAYGAIN_ALBUM_PEAK=0.999
17
+ #{pluck.path})
18
+ assert system(*cmd), cmd
19
+ [ pluck, len ]
20
+ end
21
+
22
+ def test_rg_changes_added
23
+ s = client_socket
24
+ pluck, len = tmp_pluck
25
+
26
+ # create the default sink, as well as a dumper
27
+ dumper = Tempfile.open(%w(dump .sox))
28
+ dump_pid = Tempfile.new(%w(dump .pid))
29
+ default_pid = default_sink_pid(s)
30
+ dump_cmd = "echo $$ > #{dump_pid.path}; sox $SOXFMT - #{dumper.path}"
31
+ s.send("sink ed dump active=true command='#{dump_cmd}'", Socket::MSG_EOR)
32
+ assert_equal("OK", s.readpartial(666))
33
+
34
+ # start playback!
35
+ s.send("enq \"#{pluck.path}\"", Socket::MSG_EOR)
36
+ assert_equal "OK", s.readpartial(666)
37
+
38
+ # wait for playback to start
39
+ yaml = cur = nil
40
+ Timeout.timeout(5) do
41
+ begin
42
+ s.send("current", Socket::MSG_EOR)
43
+ cur = YAML.load(yaml = s.readpartial(1666))
44
+ end while cur["current_offset"] == 0 && sleep(0.01)
45
+ end
46
+
47
+ assert_nil cur["current"]["env"]["RGFX"]
48
+
49
+ assert_equal DTAS::Format.new.rate * len, cur["current_expect"]
50
+
51
+ wait_files_not_empty(dump_pid)
52
+ pid = read_pid_file(dump_pid)
53
+
54
+ check_gain = proc do |expect, mode|
55
+ s.send("rg mode=#{mode}", Socket::MSG_EOR)
56
+ assert_equal "OK", s.readpartial(666)
57
+ Timeout.timeout(5) do
58
+ begin
59
+ s.send("current", Socket::MSG_EOR)
60
+ cur = YAML.load(yaml = s.readpartial(3666))
61
+ end while cur["current"]["env"]["RGFX"] !~ expect && sleep(0.01)
62
+ end
63
+ assert_match expect, cur["current"]["env"]["RGFX"]
64
+ end
65
+
66
+ check_gain.call(%r{vol -3dB}, "album_gain")
67
+ check_gain.call(%r{vol -2dB}, "track_gain")
68
+ check_gain.call(%r{vol 1\.3}, "track_peak")
69
+ check_gain.call(%r{vol 1\.0}, "album_peak")
70
+
71
+ s.send("rg preamp+=1", Socket::MSG_EOR)
72
+ assert_equal "OK", s.readpartial(666)
73
+ s.send("rg", Socket::MSG_EOR)
74
+ rg = YAML.load(yaml = s.readpartial(3666))
75
+ assert_equal 1, rg["preamp"]
76
+
77
+ s.send("rg preamp-=1", Socket::MSG_EOR)
78
+ assert_equal "OK", s.readpartial(666)
79
+ s.send("rg", Socket::MSG_EOR)
80
+ rg = YAML.load(yaml = s.readpartial(3666))
81
+ assert_nil rg["preamp"]
82
+
83
+ s.send("rg preamp=2", Socket::MSG_EOR)
84
+ assert_equal "OK", s.readpartial(666)
85
+ s.send("rg", Socket::MSG_EOR)
86
+ rg = YAML.load(yaml = s.readpartial(3666))
87
+ assert_equal 2, rg["preamp"]
88
+
89
+ s.send("rg preamp-=0.3", Socket::MSG_EOR)
90
+ assert_equal "OK", s.readpartial(666)
91
+ s.send("rg", Socket::MSG_EOR)
92
+ rg = YAML.load(yaml = s.readpartial(3666))
93
+ assert_equal 1.7, rg["preamp"]
94
+
95
+ s.send("rg preamp-=-0.3", Socket::MSG_EOR)
96
+ assert_equal "OK", s.readpartial(666)
97
+ s.send("rg", Socket::MSG_EOR)
98
+ rg = YAML.load(yaml = s.readpartial(3666))
99
+ assert_equal 2.0, rg["preamp"]
100
+
101
+ s.send("rg preamp-=+0.3", Socket::MSG_EOR)
102
+ assert_equal "OK", s.readpartial(666)
103
+ s.send("rg", Socket::MSG_EOR)
104
+ rg = YAML.load(yaml = s.readpartial(3666))
105
+ assert_equal 1.7, rg["preamp"]
106
+
107
+ dethrottle_decoder(s)
108
+
109
+ # ensure we did not change audio length
110
+ wait_pid_dead(pid, len)
111
+ samples = `soxi -s #{dumper.path}`.to_i
112
+ assert_equal cur["current_expect"], samples
113
+ assert_equal `soxi -d #{dumper.path}`, `soxi -d #{pluck.path}`
114
+
115
+ stop_playback(default_pid, s)
116
+ end
117
+ end