punchblock 0.8.4 → 0.9.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 +9 -0
- data/CHANGELOG.md +5 -0
- data/Rakefile +0 -6
- data/lib/punchblock.rb +0 -6
- data/lib/punchblock/command/dial.rb +1 -0
- data/lib/punchblock/connection/xmpp.rb +2 -1
- data/lib/punchblock/translator/asterisk/call.rb +12 -10
- data/lib/punchblock/translator/asterisk/component.rb +2 -0
- data/lib/punchblock/translator/asterisk/component/asterisk.rb +0 -2
- data/lib/punchblock/translator/asterisk/component/input.rb +114 -0
- data/lib/punchblock/translator/asterisk/component/output.rb +92 -0
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +0 -1
- data/spec/punchblock/translator/asterisk/call_spec.rb +29 -3
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +282 -0
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +491 -0
- metadata +46 -60
- data/lib/punchblock/component/tropo.rb +0 -9
- data/lib/punchblock/component/tropo/conference.rb +0 -331
- data/lib/punchblock/translator/asterisk/component/asterisk/input.rb +0 -116
- data/lib/punchblock/translator/asterisk/component/asterisk/output.rb +0 -94
- data/spec/punchblock/component/tropo/conference_spec.rb +0 -361
- data/spec/punchblock/translator/asterisk/component/asterisk/input_spec.rb +0 -284
- data/spec/punchblock/translator/asterisk/component/asterisk/output_spec.rb +0 -493
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
module Punchblock
|
|
2
|
-
module Translator
|
|
3
|
-
class Asterisk
|
|
4
|
-
module Component
|
|
5
|
-
module Asterisk
|
|
6
|
-
class Input < Component
|
|
7
|
-
|
|
8
|
-
attr_reader :grammar, :buffer
|
|
9
|
-
|
|
10
|
-
def setup
|
|
11
|
-
@media_engine = call.translator.media_engine
|
|
12
|
-
@buffer = ""
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def execute
|
|
16
|
-
initial_timeout = @component_node.initial_timeout || -1
|
|
17
|
-
@inter_digit_timeout = @component_node.inter_digit_timeout || -1
|
|
18
|
-
|
|
19
|
-
return with_error 'option error', 'A grammar document is required.' unless @component_node.grammar
|
|
20
|
-
return with_error 'option error', 'A mode value other than DTMF is unsupported on Asterisk.' unless @component_node.mode == :dtmf
|
|
21
|
-
return with_error 'option error', 'An initial timeout value that is negative (and not -1) is invalid.' unless initial_timeout >= -1
|
|
22
|
-
return with_error 'option error', 'An inter-digit timeout value that is negative (and not -1) is invalid.' unless @inter_digit_timeout >= -1
|
|
23
|
-
|
|
24
|
-
send_ref
|
|
25
|
-
|
|
26
|
-
case @media_engine
|
|
27
|
-
when :asterisk, nil
|
|
28
|
-
@grammar = @component_node.grammar.value.clone
|
|
29
|
-
grammar.inline!
|
|
30
|
-
grammar.tokenize!
|
|
31
|
-
grammar.normalize_whitespace
|
|
32
|
-
|
|
33
|
-
begin_initial_timer initial_timeout/1000 unless initial_timeout == -1
|
|
34
|
-
|
|
35
|
-
component = current_actor
|
|
36
|
-
|
|
37
|
-
@active = true
|
|
38
|
-
|
|
39
|
-
call.register_handler :ami, :name => 'DTMF' do |event|
|
|
40
|
-
component.process_dtmf! event['Digit'] if event['End'] == 'Yes'
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def process_dtmf(digit)
|
|
46
|
-
return unless @active
|
|
47
|
-
pb_logger.trace "Processing incoming DTMF digit #{digit}"
|
|
48
|
-
buffer << digit
|
|
49
|
-
cancel_initial_timer
|
|
50
|
-
case (match = grammar.match buffer.dup)
|
|
51
|
-
when RubySpeech::GRXML::Match
|
|
52
|
-
pb_logger.trace "Found a match against buffer #{buffer}"
|
|
53
|
-
complete success_reason(match)
|
|
54
|
-
when RubySpeech::GRXML::NoMatch
|
|
55
|
-
pb_logger.trace "Buffer #{buffer} does not match grammar"
|
|
56
|
-
complete Punchblock::Component::Input::Complete::NoMatch.new
|
|
57
|
-
when RubySpeech::GRXML::PotentialMatch
|
|
58
|
-
pb_logger.trace "Buffer #{buffer} potentially matches grammar. Waiting..."
|
|
59
|
-
reset_inter_digit_timer
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def begin_initial_timer(timeout)
|
|
66
|
-
pb_logger.trace "Setting initial timer for #{timeout} seconds"
|
|
67
|
-
@initial_timer = after timeout do
|
|
68
|
-
pb_logger.trace "Initial timer expired."
|
|
69
|
-
complete Punchblock::Component::Input::Complete::NoInput.new
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def cancel_initial_timer
|
|
74
|
-
return unless @initial_timer
|
|
75
|
-
@initial_timer.cancel
|
|
76
|
-
@initial_timer = nil
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def reset_inter_digit_timer
|
|
80
|
-
return if @inter_digit_timeout == -1
|
|
81
|
-
@inter_digit_timer ||= begin
|
|
82
|
-
pb_logger.trace "Setting inter-digit timer for #{@inter_digit_timeout/1000} seconds"
|
|
83
|
-
after @inter_digit_timeout/1000 do
|
|
84
|
-
pb_logger.trace "Inter digit-timer expired."
|
|
85
|
-
complete Punchblock::Component::Input::Complete::NoMatch.new
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
pb_logger.trace "Resetting inter-digit timer"
|
|
89
|
-
@inter_digit_timer.reset
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def cancel_inter_digit_timer
|
|
93
|
-
return unless @inter_digit_timer
|
|
94
|
-
@inter_digit_timer.cancel
|
|
95
|
-
@inter_digit_timer = nil
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def success_reason(match)
|
|
99
|
-
Punchblock::Component::Input::Complete::Success.new :mode => match.mode,
|
|
100
|
-
:confidence => match.confidence,
|
|
101
|
-
:utterance => match.utterance,
|
|
102
|
-
:interpretation => match.interpretation
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def complete(reason)
|
|
106
|
-
@active = false
|
|
107
|
-
cancel_initial_timer
|
|
108
|
-
cancel_inter_digit_timer
|
|
109
|
-
send_complete_event reason
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
require 'active_support/core_ext/string/filters'
|
|
2
|
-
|
|
3
|
-
module Punchblock
|
|
4
|
-
module Translator
|
|
5
|
-
class Asterisk
|
|
6
|
-
module Component
|
|
7
|
-
module Asterisk
|
|
8
|
-
class Output < Component
|
|
9
|
-
|
|
10
|
-
def setup
|
|
11
|
-
@media_engine = @call.translator.media_engine
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def execute
|
|
15
|
-
return with_error 'option error', 'An SSML document is required.' unless @component_node.ssml
|
|
16
|
-
|
|
17
|
-
return with_error 'option error', 'An interrupt-on value of speech is unsupported.' if @component_node.interrupt_on == :speech
|
|
18
|
-
|
|
19
|
-
[:start_offset, :start_paused, :repeat_interval, :repeat_times, :max_time].each do |opt|
|
|
20
|
-
return with_error 'option error', "A #{opt} value is unsupported on Asterisk." if @component_node.send opt
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
case @media_engine
|
|
24
|
-
when :asterisk, nil
|
|
25
|
-
return with_error 'option error', "A voice value is unsupported on Asterisk." if @component_node.voice
|
|
26
|
-
|
|
27
|
-
@execution_elements = @component_node.ssml.children.map do |node|
|
|
28
|
-
case node
|
|
29
|
-
when RubySpeech::SSML::Audio
|
|
30
|
-
lambda { current_actor.play_audio! node.src }
|
|
31
|
-
end
|
|
32
|
-
end.compact
|
|
33
|
-
|
|
34
|
-
@pending_actions = @execution_elements.count
|
|
35
|
-
|
|
36
|
-
send_ref
|
|
37
|
-
|
|
38
|
-
@interrupt_digits = '0123456789*#' if [:any, :dtmf].include? @component_node.interrupt_on
|
|
39
|
-
|
|
40
|
-
@execution_elements.each do |element|
|
|
41
|
-
element.call
|
|
42
|
-
wait :continue
|
|
43
|
-
process_playback_completion
|
|
44
|
-
end
|
|
45
|
-
when :unimrcp
|
|
46
|
-
doc = @component_node.ssml.to_s.squish.gsub(/["\\]/) { |m| "\\#{m}" }
|
|
47
|
-
send_ref
|
|
48
|
-
@call.send_agi_action! 'EXEC MRCPSynth', doc, mrcpsynth_options do |complete_event|
|
|
49
|
-
pb_logger.debug "MRCPSynth completed with #{complete_event}."
|
|
50
|
-
send_complete_event success_reason
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def process_playback_completion
|
|
56
|
-
@pending_actions -= 1
|
|
57
|
-
pb_logger.debug "Received action completion. Now waiting on #{@pending_actions} actions."
|
|
58
|
-
if @pending_actions < 1
|
|
59
|
-
pb_logger.debug "Sending complete event"
|
|
60
|
-
send_complete_event success_reason
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def continue(event = nil)
|
|
65
|
-
signal :continue, event
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def play_audio(path)
|
|
69
|
-
pb_logger.debug "Playing an audio file (#{path}) via STREAM FILE"
|
|
70
|
-
op = current_actor
|
|
71
|
-
@call.send_agi_action! 'STREAM FILE', path, @interrupt_digits do |complete_event|
|
|
72
|
-
pb_logger.debug "STREAM FILE completed with #{complete_event}. Signalling to continue execution."
|
|
73
|
-
op.continue! complete_event
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
private
|
|
78
|
-
|
|
79
|
-
def mrcpsynth_options
|
|
80
|
-
[].tap do |opts|
|
|
81
|
-
opts << 'i=any' if [:any, :dtmf].include? @component_node.interrupt_on
|
|
82
|
-
opts << "v=#{@component_node.voice}" if @component_node.voice
|
|
83
|
-
end.join '&'
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def success_reason
|
|
87
|
-
Punchblock::Component::Output::Complete::Success.new
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Punchblock
|
|
4
|
-
module Component
|
|
5
|
-
module Tropo
|
|
6
|
-
describe Conference do
|
|
7
|
-
it 'registers itself' do
|
|
8
|
-
RayoNode.class_from_registration(:conference, 'urn:xmpp:tropo:conference:1').should == Conference
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe "when setting options in initializer" do
|
|
12
|
-
subject do
|
|
13
|
-
Conference.new :name => '1234',
|
|
14
|
-
:terminator => '#',
|
|
15
|
-
:moderator => true,
|
|
16
|
-
:tone_passthrough => true,
|
|
17
|
-
:mute => false,
|
|
18
|
-
:announcement => {:text => "Welcome to Rayo", :voice => 'shelly'},
|
|
19
|
-
:music => {:text => "The moderator how not yet joined.. Listen to this awesome music while you wait.", :voice => 'frank'}
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
its(:name) { should == '1234' }
|
|
23
|
-
its(:mute) { should == false }
|
|
24
|
-
its(:terminator) { should == '#' }
|
|
25
|
-
its(:tone_passthrough) { should == true }
|
|
26
|
-
its(:moderator) { should == true }
|
|
27
|
-
its(:announcement) { should == Conference::Announcement.new(:text => "Welcome to Rayo", :voice => 'shelly') }
|
|
28
|
-
its(:music) { should == Conference::Music.new(:text => "The moderator how not yet joined.. Listen to this awesome music while you wait.", :voice => 'frank') }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
its(:mute_status_name) { should == :unknown_mute }
|
|
32
|
-
its(:hold_status_name) { should == :unknown_hold }
|
|
33
|
-
|
|
34
|
-
describe "#==" do
|
|
35
|
-
subject { Conference.new :name => 'the-conference' }
|
|
36
|
-
let(:conference2) { Conference.new :name => 'the-conference' }
|
|
37
|
-
let(:conference3) { Conference.new :name => 'other-conference' }
|
|
38
|
-
|
|
39
|
-
it { should == conference2 }
|
|
40
|
-
it { should_not == conference3 }
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
describe "#add_event" do
|
|
44
|
-
describe "with an on-hold" do
|
|
45
|
-
it "should call #onhold!" do
|
|
46
|
-
subject.expects(:onhold!).once
|
|
47
|
-
subject.add_event Conference::OnHold.new
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
describe "with an off-hold" do
|
|
52
|
-
it "should call #offhold!" do
|
|
53
|
-
subject.expects(:offhold!).once
|
|
54
|
-
subject.add_event Conference::OffHold.new
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe "#requested" do
|
|
60
|
-
context "when requesting to be muted" do
|
|
61
|
-
subject { Conference.new :mute => true }
|
|
62
|
-
before { subject.request! }
|
|
63
|
-
its(:mute_status_name) { should == :muted }
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
context "when requesting not to be muted" do
|
|
67
|
-
subject { Conference.new :mute => false }
|
|
68
|
-
before { subject.request! }
|
|
69
|
-
its(:mute_status_name) { should == :unmuted }
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
describe "#onhold!" do
|
|
74
|
-
before do
|
|
75
|
-
subject.onhold!
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
its(:hold_status_name) { should == :onhold }
|
|
79
|
-
|
|
80
|
-
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
81
|
-
lambda { subject.onhold! }.should raise_error(StateMachine::InvalidTransition)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
describe "#offhold!" do
|
|
86
|
-
before do
|
|
87
|
-
subject.onhold!
|
|
88
|
-
subject.offhold!
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
its(:hold_status_name) { should == :offhold }
|
|
92
|
-
|
|
93
|
-
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
94
|
-
lambda { subject.offhold! }.should raise_error(StateMachine::InvalidTransition)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
describe "actions" do
|
|
99
|
-
let(:mock_client) { mock 'Client' }
|
|
100
|
-
let(:conference) { Conference.new :name => '1234' }
|
|
101
|
-
|
|
102
|
-
before do
|
|
103
|
-
conference.component_id = 'abc123'
|
|
104
|
-
conference.call_id = '123abc'
|
|
105
|
-
conference.client = mock_client
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
describe '#mute_action' do
|
|
109
|
-
subject { conference.mute_action }
|
|
110
|
-
|
|
111
|
-
it { should be_a Command::Mute }
|
|
112
|
-
its(:component_id) { should == 'abc123' }
|
|
113
|
-
its(:call_id) { should == '123abc' }
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
describe '#mute!' do
|
|
117
|
-
describe "when unmuted" do
|
|
118
|
-
before do
|
|
119
|
-
conference.request!
|
|
120
|
-
conference.execute!
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
it "should send its command properly" do
|
|
124
|
-
mock_client.expects(:execute_command).with(conference.mute_action, :call_id => '123abc', :component_id => 'abc123').returns true
|
|
125
|
-
conference.expects :muted!
|
|
126
|
-
conference.mute!
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
describe "when muted" do
|
|
131
|
-
before { conference.muted! }
|
|
132
|
-
|
|
133
|
-
it "should raise an error" do
|
|
134
|
-
lambda { conference.mute! }.should raise_error(InvalidActionError, "Cannot mute a Conference that is already muted")
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
describe "#muted!" do
|
|
140
|
-
before do
|
|
141
|
-
subject.request!
|
|
142
|
-
subject.execute!
|
|
143
|
-
subject.muted!
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
its(:mute_status_name) { should == :muted }
|
|
147
|
-
|
|
148
|
-
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
149
|
-
lambda { subject.muted! }.should raise_error(StateMachine::InvalidTransition)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
describe '#unmute_action' do
|
|
154
|
-
subject { conference.unmute_action }
|
|
155
|
-
|
|
156
|
-
it { should be_a Command::Unmute }
|
|
157
|
-
its(:component_id) { should == 'abc123' }
|
|
158
|
-
its(:call_id) { should == '123abc' }
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
describe '#unmute!' do
|
|
162
|
-
before do
|
|
163
|
-
conference.request!
|
|
164
|
-
conference.execute!
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
describe "when muted" do
|
|
168
|
-
before do
|
|
169
|
-
conference.muted!
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it "should send its command properly" do
|
|
173
|
-
mock_client.expects(:execute_command).with(conference.unmute_action, :call_id => '123abc', :component_id => 'abc123').returns true
|
|
174
|
-
conference.expects :unmuted!
|
|
175
|
-
conference.unmute!
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
describe "when unmuted" do
|
|
180
|
-
it "should raise an error" do
|
|
181
|
-
lambda { conference.unmute! }.should raise_error(InvalidActionError, "Cannot unmute a Conference that is not muted")
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
describe "#unmuted!" do
|
|
187
|
-
before do
|
|
188
|
-
subject.request!
|
|
189
|
-
subject.execute!
|
|
190
|
-
subject.muted!
|
|
191
|
-
subject.unmuted!
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
its(:mute_status_name) { should == :unmuted }
|
|
195
|
-
|
|
196
|
-
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
197
|
-
lambda { subject.unmuted! }.should raise_error(StateMachine::InvalidTransition)
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
describe '#stop_action' do
|
|
202
|
-
subject { conference.stop_action }
|
|
203
|
-
|
|
204
|
-
its(:to_xml) { should == '<stop xmlns="urn:xmpp:rayo:1"/>' }
|
|
205
|
-
its(:component_id) { should == 'abc123' }
|
|
206
|
-
its(:call_id) { should == '123abc' }
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
describe '#stop!' do
|
|
210
|
-
describe "when the command is executing" do
|
|
211
|
-
before do
|
|
212
|
-
conference.request!
|
|
213
|
-
conference.execute!
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
it "should send its command properly" do
|
|
217
|
-
mock_client.expects(:execute_command).with(conference.stop_action, :call_id => '123abc', :component_id => 'abc123')
|
|
218
|
-
conference.stop!
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
describe "when the command is not executing" do
|
|
223
|
-
it "should raise an error" do
|
|
224
|
-
lambda { conference.stop! }.should raise_error(InvalidActionError, "Cannot stop a Conference that is not executing")
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
end # describe #stop!
|
|
228
|
-
|
|
229
|
-
describe '#kick_action' do
|
|
230
|
-
subject { conference.kick_action :message => 'bye!' }
|
|
231
|
-
|
|
232
|
-
its(:to_xml) { should == '<kick xmlns="urn:xmpp:tropo:conference:1">bye!</kick>' }
|
|
233
|
-
its(:component_id) { should == 'abc123' }
|
|
234
|
-
its(:call_id) { should == '123abc' }
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
describe '#kick!' do
|
|
238
|
-
describe "when the command is executing" do
|
|
239
|
-
before do
|
|
240
|
-
conference.request!
|
|
241
|
-
conference.execute!
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
it "should send its command properly" do
|
|
245
|
-
mock_client.expects(:execute_command).with(conference.kick_action(:message => 'bye!'), :call_id => '123abc', :component_id => 'abc123')
|
|
246
|
-
conference.kick! :message => 'bye!'
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
describe "when the command is not executing" do
|
|
251
|
-
it "should raise an error" do
|
|
252
|
-
lambda { conference.kick! }.should raise_error(InvalidActionError, "Cannot kick a Conference that is not executing")
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
end # describe #kick!
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
describe Conference::OnHold do
|
|
259
|
-
it 'registers itself' do
|
|
260
|
-
RayoNode.class_from_registration(:'on-hold', 'urn:xmpp:tropo:conference:1').should == Conference::OnHold
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
describe "from a stanza" do
|
|
264
|
-
let(:stanza) { "<on-hold xmlns='urn:xmpp:tropo:conference:1'/>" }
|
|
265
|
-
|
|
266
|
-
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
267
|
-
|
|
268
|
-
it { should be_instance_of Conference::OnHold }
|
|
269
|
-
|
|
270
|
-
it_should_behave_like 'event'
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
describe Conference::OffHold do
|
|
275
|
-
it 'registers itself' do
|
|
276
|
-
RayoNode.class_from_registration(:'off-hold', 'urn:xmpp:tropo:conference:1').should == Conference::OffHold
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
describe "from a stanza" do
|
|
280
|
-
let(:stanza) { "<off-hold xmlns='urn:xmpp:tropo:conference:1'/>" }
|
|
281
|
-
|
|
282
|
-
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
283
|
-
|
|
284
|
-
it { should be_instance_of Conference::OffHold }
|
|
285
|
-
|
|
286
|
-
it_should_behave_like 'event'
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
describe Conference::Speaking do
|
|
291
|
-
it 'registers itself' do
|
|
292
|
-
RayoNode.class_from_registration(:speaking, 'urn:xmpp:tropo:conference:1').should == Conference::Speaking
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
describe "from a stanza" do
|
|
296
|
-
let(:stanza) { "<speaking xmlns='urn:xmpp:tropo:conference:1' call-id='abc123'/>" }
|
|
297
|
-
|
|
298
|
-
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
299
|
-
|
|
300
|
-
it { should be_instance_of Conference::Speaking }
|
|
301
|
-
|
|
302
|
-
it_should_behave_like 'event'
|
|
303
|
-
|
|
304
|
-
its(:speaking_call_id) { should == 'abc123' }
|
|
305
|
-
end
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
describe Conference::FinishedSpeaking do
|
|
309
|
-
it 'registers itself' do
|
|
310
|
-
RayoNode.class_from_registration(:'finished-speaking', 'urn:xmpp:tropo:conference:1').should == Conference::FinishedSpeaking
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
describe "from a stanza" do
|
|
314
|
-
let(:stanza) { "<finished-speaking xmlns='urn:xmpp:tropo:conference:1' call-id='abc123'/>" }
|
|
315
|
-
|
|
316
|
-
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
317
|
-
|
|
318
|
-
it { should be_instance_of Conference::FinishedSpeaking }
|
|
319
|
-
|
|
320
|
-
it_should_behave_like 'event'
|
|
321
|
-
|
|
322
|
-
its(:speaking_call_id) { should == 'abc123' }
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
describe Conference::Complete::Kick do
|
|
327
|
-
let :stanza do
|
|
328
|
-
<<-MESSAGE
|
|
329
|
-
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
330
|
-
<kick xmlns='urn:xmpp:tropo:conference:complete:1'>wouldn't stop talking</kick>
|
|
331
|
-
</complete>
|
|
332
|
-
MESSAGE
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
336
|
-
|
|
337
|
-
it { should be_instance_of Conference::Complete::Kick }
|
|
338
|
-
|
|
339
|
-
its(:name) { should == :kick }
|
|
340
|
-
its(:details) { should == "wouldn't stop talking" }
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
describe Conference::Complete::Terminator do
|
|
344
|
-
let :stanza do
|
|
345
|
-
<<-MESSAGE
|
|
346
|
-
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
347
|
-
<terminator xmlns='urn:xmpp:tropo:conference:complete:1' />
|
|
348
|
-
</complete>
|
|
349
|
-
MESSAGE
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
353
|
-
|
|
354
|
-
it { should be_instance_of Conference::Complete::Terminator }
|
|
355
|
-
|
|
356
|
-
its(:name) { should == :terminator }
|
|
357
|
-
end
|
|
358
|
-
end
|
|
359
|
-
end
|
|
360
|
-
end
|
|
361
|
-
end # Punchblock
|