punchblock 1.7.1 → 1.8.0

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/.travis.yml CHANGED
@@ -2,8 +2,12 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
- # - jruby-19mode
6
- # - rbx-19mode
7
- # - ruby-head
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ - ruby-head
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: rbx-19mode
11
+ - rvm: jruby-19mode
8
12
  notifications:
9
13
  irc: "irc.freenode.org#adhearsion"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # [develop](https://github.com/adhearsion/punchblock)
2
2
 
3
+ # [v1.8.0](https://github.com/adhearsion/punchblock/compare/v1.7.1...v1.8.0) - [2013-01-10](https://rubygems.org/gems/punchblock/versions/1.8.0)
4
+ * Feature: Join command now enforces a list of valid direction attribute values
5
+ * Feature: Added support for media direction to the Record component
6
+ * Feature: Record direction support on FS
7
+ * Bugfix: Fixed answering during early media on FS
8
+ * Bugfix: Doing multiple recordings on Asterisk during the lifetime of a call was crashing Punchblock
9
+
3
10
  # [v1.7.1](https://github.com/adhearsion/punchblock/compare/v1.7.0...v1.7.1) - [2012-12-17](https://rubygems.org/gems/punchblock/versions/1.7.1)
4
11
  * Bugfix: Deal with nil media engines on FS/* properly
5
12
 
@@ -5,6 +5,8 @@ module Punchblock
5
5
  class Join < CommandNode
6
6
  register :join, :core
7
7
 
8
+ VALID_DIRECTIONS = [:duplex, :send, :recv].freeze
9
+
8
10
  ##
9
11
  # Create a join command
10
12
  #
@@ -59,8 +61,11 @@ module Punchblock
59
61
 
60
62
  ##
61
63
  # @param [String] other the direction in which media should flow. Can be :duplex, :recv or :send
62
- def direction=(other)
63
- write_attr :direction, other
64
+ def direction=(direction)
65
+ if direction && !VALID_DIRECTIONS.include?(direction.to_sym)
66
+ raise ArgumentError, "Invalid Direction (#{direction}), use: #{VALID_DIRECTIONS*' '}"
67
+ end
68
+ write_attr :direction, direction
64
69
  end
65
70
 
66
71
  ##
@@ -10,7 +10,6 @@ module Punchblock
10
10
  autoload :Output
11
11
  autoload :Record
12
12
  autoload :Stop
13
- autoload :Tropo
14
13
 
15
14
  InvalidActionError = Class.new StandardError
16
15
  end # Component
@@ -5,6 +5,8 @@ module Punchblock
5
5
  class Record < ComponentNode
6
6
  register :record, :record
7
7
 
8
+ VALID_DIRECTIONS = [:duplex, :send, :recv].freeze
9
+
8
10
  ##
9
11
  # Creates an Rayo Record command
10
12
  #
@@ -114,8 +116,23 @@ module Punchblock
114
116
  write_attr :'start-paused', other
115
117
  end
116
118
 
119
+ ##
120
+ # @return [Symbol] the direction of media to be recorded.
121
+ def direction
122
+ read_attr :direction, :to_sym
123
+ end
124
+
125
+ ##
126
+ # @param [#to_s] otherthe direction of media to be recorded. Can be :duplex, :recv or :send
127
+ def direction=(direction)
128
+ if direction && !VALID_DIRECTIONS.include?(direction.to_sym)
129
+ raise ArgumentError, "Invalid Direction (#{direction}), use: #{VALID_DIRECTIONS*' '}"
130
+ end
131
+ write_attr :direction, direction
132
+ end
133
+
117
134
  def inspect_attributes # :nodoc:
118
- [:final_timeout, :format, :initial_timeout, :max_duration, :start_beep, :start_paused] + super
135
+ [:final_timeout, :format, :initial_timeout, :max_duration, :start_beep, :start_paused, :direction] + super
119
136
  end
120
137
 
121
138
  state_machine :state do
@@ -24,7 +24,7 @@ module Punchblock
24
24
 
25
25
 
26
26
  component = current_actor
27
- call.register_handler :ami, :name => 'MonitorStop' do |event|
27
+ call.register_tmp_handler :ami, :name => 'MonitorStop' do |event|
28
28
  component.finished
29
29
  end
30
30
 
@@ -104,6 +104,7 @@ module Punchblock
104
104
  if component = component_with_id(event[:scope_variable_punchblock_component_id])
105
105
  safe_from_dead_actors { component.handle_es_event event if component.alive? }
106
106
  end
107
+ throw :pass
107
108
  end
108
109
  end
109
110
 
@@ -29,6 +29,14 @@ module Punchblock
29
29
 
30
30
  record_args = ['start', filename]
31
31
  record_args << max_duration/1000 unless max_duration == -1
32
+ case @component_node.direction
33
+ when :send
34
+ call.uuid_foo :setvar, "RECORD_WRITE_ONLY true"
35
+ when :recv
36
+ call.uuid_foo :setvar, "RECORD_READ_ONLY true"
37
+ else
38
+ call.uuid_foo :setvar, "RECORD_STEREO true"
39
+ end
32
40
  call.uuid_foo :record, record_args.join(' ')
33
41
 
34
42
  send_ref
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Punchblock
4
- VERSION = "1.7.1"
4
+ VERSION = "1.8.0"
5
5
  end
data/punchblock.gemspec CHANGED
@@ -23,12 +23,13 @@ Gem::Specification.new do |s|
23
23
  s.required_rubygems_version = Gem::Requirement.new(">= 1.3.7") if s.respond_to? :required_rubygems_version=
24
24
 
25
25
  s.add_runtime_dependency %q<niceogiri>, ["~> 1.1"]
26
+ s.add_runtime_dependency %q<nokogiri>, ["~> 1.5", ">= 1.5.6"]
26
27
  s.add_runtime_dependency %q<blather>, [">= 0.7.0"]
27
28
  s.add_runtime_dependency %q<activesupport>, ["~> 3.0"]
28
29
  s.add_runtime_dependency %q<state_machine>, ["~> 1.0"]
29
30
  s.add_runtime_dependency %q<future-resource>, ["~> 1.0"]
30
31
  s.add_runtime_dependency %q<has-guarded-handlers>, ["~> 1.5"]
31
- s.add_runtime_dependency %q<celluloid>, ["~> 0.12", ">= 0.12.3"]
32
+ s.add_runtime_dependency %q<celluloid>, ["~> 0.12", ">= 0.12.4"]
32
33
  s.add_runtime_dependency %q<ruby_ami>, ["~> 1.2", ">= 1.2.1"]
33
34
  s.add_runtime_dependency %q<ruby_fs>, ["~> 1.0"]
34
35
  s.add_runtime_dependency %q<ruby_speech>, ["~> 1.0"]
@@ -41,5 +42,5 @@ Gem::Specification.new do |s|
41
42
  s.add_development_dependency %q<i18n>, [">= 0"]
42
43
  s.add_development_dependency %q<countdownlatch>, [">= 0"]
43
44
  s.add_development_dependency %q<guard-rspec>
44
- s.add_development_dependency %q<ruby_gntp>
45
+ s.add_development_dependency %q<rb-fsevent>, ['~> 0.9']
45
46
  end
@@ -39,6 +39,28 @@ module Punchblock
39
39
  its(:direction) { should be == :duplex }
40
40
  its(:media) { should be == :bridge }
41
41
  end
42
+
43
+ describe "with a direction" do
44
+ [nil, :duplex, :send, :recv].each do |direction|
45
+ describe direction do
46
+ subject { Join.new :direction => direction }
47
+
48
+ its(:direction) { should be == direction }
49
+ end
50
+ end
51
+
52
+ describe "no direction" do
53
+ subject { Join.new }
54
+
55
+ its(:direction) { should be_nil }
56
+ end
57
+
58
+ describe "blahblahblah" do
59
+ it "should raise an error" do
60
+ expect { Join.new(:direction => :blahblahblah) }.to raise_error ArgumentError
61
+ end
62
+ end
63
+ end
42
64
  end
43
65
  end
44
66
  end # Punchblock
@@ -16,7 +16,8 @@ module Punchblock
16
16
  :start_paused => false,
17
17
  :max_duration => 500000,
18
18
  :initial_timeout => 10000,
19
- :final_timeout => 30000
19
+ :final_timeout => 30000,
20
+ :direction => :duplex
20
21
  end
21
22
 
22
23
  its(:format) { should be == 'WAV' }
@@ -25,6 +26,7 @@ module Punchblock
25
26
  its(:max_duration) { should be == 500000 }
26
27
  its(:initial_timeout) { should be == 10000 }
27
28
  its(:final_timeout) { should be == 30000 }
29
+ its(:direction) { should be == :duplex }
28
30
  end
29
31
 
30
32
  describe "from a stanza" do
@@ -36,6 +38,7 @@ module Punchblock
36
38
  start-paused="false"
37
39
  max-duration="500000"
38
40
  initial-timeout="10000"
41
+ direction="duplex"
39
42
  final-timeout="30000"/>
40
43
  MESSAGE
41
44
  end
@@ -50,6 +53,29 @@ module Punchblock
50
53
  its(:max_duration) { should be == 500000 }
51
54
  its(:initial_timeout) { should be == 10000 }
52
55
  its(:final_timeout) { should be == 30000 }
56
+ its(:direction) { should be == :duplex }
57
+ end
58
+
59
+ describe "with a direction" do
60
+ [nil, :duplex, :send, :recv].each do |direction|
61
+ describe direction do
62
+ subject { Record.new :direction => direction }
63
+
64
+ its(:direction) { should be == direction }
65
+ end
66
+ end
67
+
68
+ describe "no direction" do
69
+ subject { Record.new }
70
+
71
+ its(:direction) { should be_nil }
72
+ end
73
+
74
+ describe "blahblahblah" do
75
+ it "should raise an error" do
76
+ expect { Record.new(:direction => :blahblahblah) }.to raise_error ArgumentError
77
+ end
78
+ end
53
79
  end
54
80
 
55
81
  describe "actions" do
@@ -65,6 +65,21 @@ module Punchblock
65
65
  original_command.should be_complete
66
66
  end
67
67
 
68
+ it "can be called multiple times on the same call" do
69
+ mock_call.should_receive(:send_ami_action!).twice
70
+ subject.execute
71
+
72
+ monitor_stop_event = RubyAMI::Event.new('MonitorStop').tap do |e|
73
+ e['Channel'] = channel
74
+ end
75
+
76
+ mock_call.process_ami_event monitor_stop_event
77
+
78
+ (Record.new original_command, mock_call).execute
79
+ (Punchblock::Component::Record.new command_options).request!
80
+ mock_call.process_ami_event monitor_stop_event
81
+ end
82
+
68
83
  describe 'start_paused' do
69
84
  context "set to nil" do
70
85
  let(:command_options) { { :start_paused => nil } }
@@ -706,6 +706,19 @@ module Punchblock
706
706
  subject.should be_answered
707
707
  subject.execute_command command
708
708
  end
709
+
710
+ context "when a component has previously been executed" do
711
+ it "should set the answer command's response correctly" do
712
+ subject
713
+ Punchblock.should_receive(:new_uuid).once.and_return 'abc123'
714
+ subject.wrapped_object.should_receive(:application).once.with('answer', "%[punchblock_command_id=abc123]")
715
+ subject.should_not be_answered
716
+ subject.execute_command command
717
+ subject.handle_es_event RubyFS::Event.new(nil, :event_name => 'CHANNEL_ANSWER', :scope_variable_punchblock_command_id => 'abc123', :scope_variable_punchblock_component_id => 'dj182989j')
718
+ command.response(0.5).should be true
719
+ subject.should be_answered
720
+ end
721
+ end
709
722
  end
710
723
 
711
724
  def expect_hangup_with_reason(reason)
@@ -22,7 +22,10 @@ module Punchblock
22
22
  {}
23
23
  end
24
24
 
25
- before { mock_stream.as_null_object }
25
+ before do
26
+ mock_stream.as_null_object
27
+ mock_call.stub(:uuid_foo)
28
+ end
26
29
 
27
30
  subject { Record.new original_command, mock_call }
28
31
 
@@ -62,7 +65,7 @@ module Punchblock
62
65
  context "set to nil" do
63
66
  let(:command_options) { { :start_paused => nil } }
64
67
  it "should execute normally" do
65
- mock_call.should_receive(:uuid_foo).once
68
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
66
69
  subject.execute
67
70
  original_command.response(0.1).should be_a Ref
68
71
  end
@@ -71,7 +74,7 @@ module Punchblock
71
74
  context "set to false" do
72
75
  let(:command_options) { { :start_paused => false } }
73
76
  it "should execute normally" do
74
- mock_call.should_receive(:uuid_foo).once
77
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
75
78
  subject.execute
76
79
  original_command.response(0.1).should be_a Ref
77
80
  end
@@ -92,7 +95,7 @@ module Punchblock
92
95
  context "set to nil" do
93
96
  let(:command_options) { { :initial_timeout => nil } }
94
97
  it "should execute normally" do
95
- mock_call.should_receive(:uuid_foo).once
98
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
96
99
  subject.execute
97
100
  original_command.response(0.1).should be_a Ref
98
101
  end
@@ -101,7 +104,7 @@ module Punchblock
101
104
  context "set to -1" do
102
105
  let(:command_options) { { :initial_timeout => -1 } }
103
106
  it "should execute normally" do
104
- mock_call.should_receive(:uuid_foo).once
107
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
105
108
  subject.execute
106
109
  original_command.response(0.1).should be_a Ref
107
110
  end
@@ -122,7 +125,7 @@ module Punchblock
122
125
  context "set to nil" do
123
126
  let(:command_options) { { :final_timeout => nil } }
124
127
  it "should execute normally" do
125
- mock_call.should_receive(:uuid_foo).once
128
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
126
129
  subject.execute
127
130
  original_command.response(0.1).should be_a Ref
128
131
  end
@@ -131,7 +134,7 @@ module Punchblock
131
134
  context "set to -1" do
132
135
  let(:command_options) { { :final_timeout => -1 } }
133
136
  it "should execute normally" do
134
- mock_call.should_receive(:uuid_foo).once
137
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
135
138
  subject.execute
136
139
  original_command.response(0.1).should be_a Ref
137
140
  end
@@ -194,7 +197,7 @@ module Punchblock
194
197
  context "set to nil" do
195
198
  let(:command_options) { { :start_beep => nil } }
196
199
  it "should execute normally" do
197
- mock_call.should_receive(:uuid_foo).once
200
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
198
201
  subject.execute
199
202
  original_command.response(0.1).should be_a Ref
200
203
  end
@@ -203,7 +206,7 @@ module Punchblock
203
206
  context "set to false" do
204
207
  let(:command_options) { { :start_beep => false } }
205
208
  it "should execute normally" do
206
- mock_call.should_receive(:uuid_foo).once
209
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/)
207
210
  subject.execute
208
211
  original_command.response(0.1).should be_a Ref
209
212
  end
@@ -262,6 +265,45 @@ module Punchblock
262
265
  end
263
266
  end
264
267
  end
268
+
269
+ describe 'direction' do
270
+ context "with nil" do
271
+ let(:command_options) { { :direction => nil } }
272
+ it "should execute the setvar application with duplex options before recording" do
273
+ mock_call.should_receive(:uuid_foo).once.with(:setvar, "RECORD_STEREO true").ordered
274
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/).ordered
275
+ subject.execute
276
+ original_command.response(0.1).should be_a Ref
277
+ end
278
+ end
279
+ context "with :duplex" do
280
+ let(:command_options) { { :direction => :duplex } }
281
+ it "should execute the setvar application with duplex options before recording" do
282
+ mock_call.should_receive(:uuid_foo).once.with(:setvar, "RECORD_STEREO true").ordered
283
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/).ordered
284
+ subject.execute
285
+ original_command.response(0.1).should be_a Ref
286
+ end
287
+ end
288
+ context "with :send" do
289
+ let(:command_options) { { :direction => :send } }
290
+ it "should execute the setvar application with send options before recording" do
291
+ mock_call.should_receive(:uuid_foo).once.with(:setvar, "RECORD_WRITE_ONLY true").ordered
292
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/).ordered
293
+ subject.execute
294
+ original_command.response(0.1).should be_a Ref
295
+ end
296
+ end
297
+ context "with :recv" do
298
+ let(:command_options) { { :direction => :recv } }
299
+ it "should execute the setvar application with recv options before recording" do
300
+ mock_call.should_receive(:uuid_foo).once.with(:setvar, "RECORD_READ_ONLY true").ordered
301
+ mock_call.should_receive(:uuid_foo).once.with(:record, /.wav$/).ordered
302
+ subject.execute
303
+ original_command.response(0.1).should be_a Ref
304
+ end
305
+ end
306
+ end
265
307
  end
266
308
 
267
309
  describe "#execute_command" do
@@ -282,7 +324,6 @@ module Punchblock
282
324
  let(:command) { Punchblock::Component::Stop.new }
283
325
 
284
326
  before do
285
- mock_call.should_receive :uuid_foo
286
327
  command.request!
287
328
  original_command.request!
288
329
  subject.execute
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: punchblock
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.1
4
+ version: 1.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-12-17 00:00:00.000000000 Z
14
+ date: 2013-01-10 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: niceogiri
@@ -29,6 +29,28 @@ dependencies:
29
29
  - - ~>
30
30
  - !ruby/object:Gem::Version
31
31
  version: '1.1'
32
+ - !ruby/object:Gem::Dependency
33
+ name: nokogiri
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '1.5'
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 1.5.6
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ~>
49
+ - !ruby/object:Gem::Version
50
+ version: '1.5'
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 1.5.6
32
54
  - !ruby/object:Gem::Dependency
33
55
  name: blather
34
56
  requirement: !ruby/object:Gem::Requirement
@@ -119,7 +141,7 @@ dependencies:
119
141
  version: '0.12'
120
142
  - - ! '>='
121
143
  - !ruby/object:Gem::Version
122
- version: 0.12.3
144
+ version: 0.12.4
123
145
  type: :runtime
124
146
  prerelease: false
125
147
  version_requirements: !ruby/object:Gem::Requirement
@@ -130,7 +152,7 @@ dependencies:
130
152
  version: '0.12'
131
153
  - - ! '>='
132
154
  - !ruby/object:Gem::Version
133
- version: 0.12.3
155
+ version: 0.12.4
134
156
  - !ruby/object:Gem::Dependency
135
157
  name: ruby_ami
136
158
  requirement: !ruby/object:Gem::Requirement
@@ -314,21 +336,21 @@ dependencies:
314
336
  - !ruby/object:Gem::Version
315
337
  version: '0'
316
338
  - !ruby/object:Gem::Dependency
317
- name: ruby_gntp
339
+ name: rb-fsevent
318
340
  requirement: !ruby/object:Gem::Requirement
319
341
  none: false
320
342
  requirements:
321
- - - ! '>='
343
+ - - ~>
322
344
  - !ruby/object:Gem::Version
323
- version: '0'
345
+ version: '0.9'
324
346
  type: :development
325
347
  prerelease: false
326
348
  version_requirements: !ruby/object:Gem::Requirement
327
349
  none: false
328
350
  requirements:
329
- - - ! '>='
351
+ - - ~>
330
352
  - !ruby/object:Gem::Version
331
- version: '0'
353
+ version: '0.9'
332
354
  description: Like Rack is to Rails and Sinatra, Punchblock provides a consistent API
333
355
  on top of several underlying third-party call control protocols.
334
356
  email: punchblock@adhearsion.com
@@ -499,7 +521,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
499
521
  version: '0'
500
522
  segments:
501
523
  - 0
502
- hash: -2704704399660670461
524
+ hash: 1644648502358388529
503
525
  required_rubygems_version: !ruby/object:Gem::Requirement
504
526
  none: false
505
527
  requirements: