punchblock 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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: