punchblock 0.4.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/.document +5 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +31 -0
- data/Rakefile +23 -0
- data/assets/ozone/ask-1.0.xsd +56 -0
- data/assets/ozone/conference-1.0.xsd +17 -0
- data/assets/ozone/ozone-1.0.xsd +127 -0
- data/assets/ozone/say-1.0.xsd +24 -0
- data/assets/ozone/transfer-1.0.xsd +32 -0
- data/bin/punchblock-console +125 -0
- data/lib/punchblock/command/accept.rb +30 -0
- data/lib/punchblock/command/answer.rb +30 -0
- data/lib/punchblock/command/dial.rb +88 -0
- data/lib/punchblock/command/hangup.rb +25 -0
- data/lib/punchblock/command/join.rb +81 -0
- data/lib/punchblock/command/mute.rb +7 -0
- data/lib/punchblock/command/redirect.rb +49 -0
- data/lib/punchblock/command/reject.rb +61 -0
- data/lib/punchblock/command/unjoin.rb +50 -0
- data/lib/punchblock/command/unmute.rb +7 -0
- data/lib/punchblock/command.rb +16 -0
- data/lib/punchblock/command_node.rb +46 -0
- data/lib/punchblock/component/input.rb +320 -0
- data/lib/punchblock/component/output.rb +449 -0
- data/lib/punchblock/component/record.rb +216 -0
- data/lib/punchblock/component/tropo/ask.rb +197 -0
- data/lib/punchblock/component/tropo/conference.rb +328 -0
- data/lib/punchblock/component/tropo/say.rb +113 -0
- data/lib/punchblock/component/tropo/transfer.rb +178 -0
- data/lib/punchblock/component/tropo.rb +12 -0
- data/lib/punchblock/component.rb +73 -0
- data/lib/punchblock/connection.rb +209 -0
- data/lib/punchblock/core_ext/blather/stanza/presence.rb +11 -0
- data/lib/punchblock/core_ext/blather/stanza.rb +26 -0
- data/lib/punchblock/dsl.rb +46 -0
- data/lib/punchblock/event/answered.rb +7 -0
- data/lib/punchblock/event/complete.rb +65 -0
- data/lib/punchblock/event/dtmf.rb +19 -0
- data/lib/punchblock/event/end.rb +15 -0
- data/lib/punchblock/event/info.rb +15 -0
- data/lib/punchblock/event/joined.rb +50 -0
- data/lib/punchblock/event/offer.rb +29 -0
- data/lib/punchblock/event/ringing.rb +7 -0
- data/lib/punchblock/event/unjoined.rb +50 -0
- data/lib/punchblock/event.rb +16 -0
- data/lib/punchblock/generic_connection.rb +18 -0
- data/lib/punchblock/has_headers.rb +34 -0
- data/lib/punchblock/header.rb +47 -0
- data/lib/punchblock/media_container.rb +39 -0
- data/lib/punchblock/media_node.rb +17 -0
- data/lib/punchblock/protocol_error.rb +16 -0
- data/lib/punchblock/rayo_node.rb +88 -0
- data/lib/punchblock/ref.rb +26 -0
- data/lib/punchblock/version.rb +3 -0
- data/lib/punchblock.rb +42 -0
- data/log/.gitkeep +0 -0
- data/punchblock.gemspec +42 -0
- data/spec/punchblock/command/accept_spec.rb +13 -0
- data/spec/punchblock/command/answer_spec.rb +13 -0
- data/spec/punchblock/command/dial_spec.rb +54 -0
- data/spec/punchblock/command/hangup_spec.rb +13 -0
- data/spec/punchblock/command/join_spec.rb +21 -0
- data/spec/punchblock/command/mute_spec.rb +11 -0
- data/spec/punchblock/command/redirect_spec.rb +19 -0
- data/spec/punchblock/command/reject_spec.rb +43 -0
- data/spec/punchblock/command/unjoin_spec.rb +19 -0
- data/spec/punchblock/command/unmute_spec.rb +11 -0
- data/spec/punchblock/command_node_spec.rb +80 -0
- data/spec/punchblock/component/input_spec.rb +188 -0
- data/spec/punchblock/component/output_spec.rb +531 -0
- data/spec/punchblock/component/record_spec.rb +235 -0
- data/spec/punchblock/component/tropo/ask_spec.rb +183 -0
- data/spec/punchblock/component/tropo/conference_spec.rb +360 -0
- data/spec/punchblock/component/tropo/say_spec.rb +171 -0
- data/spec/punchblock/component/tropo/transfer_spec.rb +153 -0
- data/spec/punchblock/component_spec.rb +126 -0
- data/spec/punchblock/connection_spec.rb +194 -0
- data/spec/punchblock/event/answered_spec.rb +23 -0
- data/spec/punchblock/event/complete_spec.rb +80 -0
- data/spec/punchblock/event/dtmf_spec.rb +24 -0
- data/spec/punchblock/event/end_spec.rb +30 -0
- data/spec/punchblock/event/info_spec.rb +30 -0
- data/spec/punchblock/event/joined_spec.rb +32 -0
- data/spec/punchblock/event/offer_spec.rb +35 -0
- data/spec/punchblock/event/ringing_spec.rb +23 -0
- data/spec/punchblock/event/unjoined_spec.rb +32 -0
- data/spec/punchblock/header_spec.rb +44 -0
- data/spec/punchblock/protocol_error_spec.rb +9 -0
- data/spec/punchblock/ref_spec.rb +21 -0
- data/spec/spec_helper.rb +43 -0
- metadata +353 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
module Punchblock
|
|
2
|
+
module Component
|
|
3
|
+
module Tropo
|
|
4
|
+
class Ask < ComponentNode
|
|
5
|
+
register :ask, :ask
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Create an ask message
|
|
9
|
+
#
|
|
10
|
+
# @param [Hash] options for asking/prompting a specific call
|
|
11
|
+
# @option options [Choices, Hash] :choices to allow the user to input
|
|
12
|
+
# @option options [Prompt, Hash, Optional] :prompt to play/read to the caller as the question
|
|
13
|
+
# @option options [Symbol, Optional] :mode by which to accept input. Can be :speech, :dtmf or :any
|
|
14
|
+
# @option options [Integer, Optional] :timeout to wait for user input
|
|
15
|
+
# @option options [Boolean, Optional] :bargein wether or not to allow the caller to begin their response before the prompt finishes
|
|
16
|
+
# @option options [String, Optional] :recognizer to use for speech recognition
|
|
17
|
+
# @option options [String, Optional] :terminator by which to signal the end of input
|
|
18
|
+
# @option options [Float, Optional] :min_confidence with which to consider a response acceptable
|
|
19
|
+
#
|
|
20
|
+
# @return [Command::Ask] a formatted Rayo ask command
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# ask :prompt => {:text => 'Please enter your postal code.', :voice => 'simon'},
|
|
24
|
+
# :choices => {:value => '[5 DIGITS]'},
|
|
25
|
+
# :timeout => 30,
|
|
26
|
+
# :recognizer => 'es-es'
|
|
27
|
+
#
|
|
28
|
+
# returns:
|
|
29
|
+
# <ask xmlns="urn:xmpp:tropo:ask:1" timeout="30" recognizer="es-es">
|
|
30
|
+
# <prompt voice='simon'>Please enter your postal code.</prompt>
|
|
31
|
+
# <choices content-type="application/grammar+voxeo">[5 DIGITS]</choices>
|
|
32
|
+
# </ask>
|
|
33
|
+
#
|
|
34
|
+
def self.new(options = {})
|
|
35
|
+
super().tap do |new_node|
|
|
36
|
+
options.each_pair { |k,v| new_node.send :"#{k}=", v }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# @return [Boolean] wether or not to allow the caller to begin their response before the prompt finishes
|
|
42
|
+
#
|
|
43
|
+
def bargein
|
|
44
|
+
read_attr(:bargein) == "true"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
# @param [Boolean] bargein wether or not to allow the caller to begin their response before the prompt finishes
|
|
49
|
+
#
|
|
50
|
+
def bargein=(bargein)
|
|
51
|
+
write_attr :bargein, bargein.to_s
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# @return [Float] Confidence with which to consider a response acceptable
|
|
56
|
+
#
|
|
57
|
+
def min_confidence
|
|
58
|
+
read_attr 'min-confidence', :to_f
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# @param [Float] min_confidence with which to consider a response acceptable
|
|
63
|
+
#
|
|
64
|
+
def min_confidence=(min_confidence)
|
|
65
|
+
write_attr 'min-confidence', min_confidence
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# @return [Symbol] mode by which to accept input. Can be :speech, :dtmf or :any
|
|
70
|
+
#
|
|
71
|
+
def mode
|
|
72
|
+
read_attr :mode, :to_sym
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
##
|
|
76
|
+
# @param [Symbol] mode by which to accept input. Can be :speech, :dtmf or :any
|
|
77
|
+
#
|
|
78
|
+
def mode=(mode)
|
|
79
|
+
write_attr :mode, mode
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
##
|
|
83
|
+
# @return [String] recognizer to use for speech recognition
|
|
84
|
+
#
|
|
85
|
+
def recognizer
|
|
86
|
+
read_attr :recognizer
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# @param [String] recognizer to use for speech recognition
|
|
91
|
+
#
|
|
92
|
+
def recognizer=(recognizer)
|
|
93
|
+
write_attr :recognizer, recognizer
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
##
|
|
97
|
+
# @return [String] terminator by which to signal the end of input
|
|
98
|
+
#
|
|
99
|
+
def terminator
|
|
100
|
+
read_attr :terminator
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
##
|
|
104
|
+
# @param [String] terminator by which to signal the end of input
|
|
105
|
+
#
|
|
106
|
+
def terminator=(terminator)
|
|
107
|
+
write_attr :terminator, terminator
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
##
|
|
111
|
+
# @return [Integer] timeout to wait for user input
|
|
112
|
+
#
|
|
113
|
+
def timeout
|
|
114
|
+
read_attr :timeout, :to_i
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
##
|
|
118
|
+
# @param [Integer] timeout to wait for user input
|
|
119
|
+
#
|
|
120
|
+
def timeout=(timeout)
|
|
121
|
+
write_attr :timeout, timeout
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
##
|
|
125
|
+
# @return [Prompt] the prompt by which to introduce the question
|
|
126
|
+
#
|
|
127
|
+
def prompt
|
|
128
|
+
Prompt.new find_first('//ns:prompt', :ns => self.registered_ns)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
##
|
|
132
|
+
# @param [Hash] p
|
|
133
|
+
# @option p [String] :text to read the caller via TTS as the question
|
|
134
|
+
# @option p [String] :voice to use for speech synthesis
|
|
135
|
+
#
|
|
136
|
+
def prompt=(p)
|
|
137
|
+
remove_children :prompt
|
|
138
|
+
p = Prompt.new(p) unless p.is_a?(Prompt)
|
|
139
|
+
self << p
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
class Prompt < MediaNode
|
|
143
|
+
register :prompt, :ask
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
##
|
|
147
|
+
# @return [Choices] the choices available
|
|
148
|
+
#
|
|
149
|
+
def choices
|
|
150
|
+
Choices.new find_first('ns:choices', :ns => self.class.registered_ns)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
##
|
|
154
|
+
# @param [Hash] choices
|
|
155
|
+
# @option choices [String] :content_type
|
|
156
|
+
# @option choices [String] :value the choices available
|
|
157
|
+
#
|
|
158
|
+
def choices=(choices)
|
|
159
|
+
remove_children :choices
|
|
160
|
+
choices = Choices.new(choices) unless choices.is_a?(Choices)
|
|
161
|
+
self << choices
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def inspect_attributes # :nodoc:
|
|
165
|
+
[:bargein, :min_confidence, :mode, :recognizer, :terminator, :timeout, :prompt, :choices] + super
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
class Choices < Input::Grammar
|
|
169
|
+
##
|
|
170
|
+
# @param [Hash] options
|
|
171
|
+
# @option options [String] :content_type
|
|
172
|
+
# @option options [String] :value the choices available
|
|
173
|
+
#
|
|
174
|
+
def self.new(options = {})
|
|
175
|
+
super(options).tap do |new_node|
|
|
176
|
+
new_node.name = 'choices'
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end # Choices
|
|
180
|
+
|
|
181
|
+
class Complete
|
|
182
|
+
class Success < Input::Complete::Success
|
|
183
|
+
register :success, :ask_complete
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class NoMatch < Input::Complete::NoMatch
|
|
187
|
+
register :nomatch, :ask_complete
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
class NoInput < Input::Complete::NoInput
|
|
191
|
+
register :noinput, :ask_complete
|
|
192
|
+
end
|
|
193
|
+
end # Complete
|
|
194
|
+
end # Ask
|
|
195
|
+
end # Tropo
|
|
196
|
+
end # Command
|
|
197
|
+
end # Punchblock
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
module Punchblock
|
|
2
|
+
module Component
|
|
3
|
+
module Tropo
|
|
4
|
+
class Conference < ComponentNode
|
|
5
|
+
register :conference, :conference
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Creates an Rayo conference command
|
|
9
|
+
#
|
|
10
|
+
# @param [Hash] options
|
|
11
|
+
# @option options [String] :name room id to with which to create or join the conference
|
|
12
|
+
# @option options [Announcement, Hash, Optional] :announcement to play on entry
|
|
13
|
+
# @option options [Music, Hash, Optional] :music to play to the participant when no moderator is present
|
|
14
|
+
# @option options [Boolean, Optional] :mute If set to true, the user will be muted in the conference
|
|
15
|
+
# @option options [Boolean, Optional] :moderator Whether or not the conference should be moderated
|
|
16
|
+
# @option options [Boolean, Optional] :tone_passthrough Identifies whether or not conference members can hear the tone generated when a a key on the phone is pressed.
|
|
17
|
+
# @option options [String, Optional] :terminator This is the touch-tone key (also known as "DTMF digit") used to exit the conference.
|
|
18
|
+
#
|
|
19
|
+
# @return [Command::Conference] a formatted Rayo conference command
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# conference :name => 'the_one_true_conference', :terminator => '#'
|
|
23
|
+
#
|
|
24
|
+
# returns:
|
|
25
|
+
# <conference xmlns="urn:xmpp:tropo:conference:1" name="the_one_true_conference" terminator="#"/>
|
|
26
|
+
def self.new(options = {})
|
|
27
|
+
super().tap do |new_node|
|
|
28
|
+
options.each_pair do |k,v|
|
|
29
|
+
new_node.send :"#{k}=", v
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# @return [String] the name of the conference
|
|
36
|
+
#
|
|
37
|
+
def name
|
|
38
|
+
read_attr :name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# @param [String] name of the conference
|
|
43
|
+
#
|
|
44
|
+
def name=(name)
|
|
45
|
+
write_attr :name, name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# @return [Boolean] If set to true, the user will be muted in the conference.
|
|
50
|
+
#
|
|
51
|
+
def mute
|
|
52
|
+
read_attr(:mute) == 'true'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# @param [Boolean] mute If set to true, the user will be muted in the conference
|
|
57
|
+
#
|
|
58
|
+
def mute=(mute)
|
|
59
|
+
write_attr :mute, mute.to_s
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# @return [String] This is the touch-tone key (also known as "DTMF digit") used to exit the conference.
|
|
64
|
+
#
|
|
65
|
+
def terminator
|
|
66
|
+
read_attr :terminator
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# @param [String] terminator This is the touch-tone key (also known as "DTMF digit") used to exit the conference.
|
|
71
|
+
#
|
|
72
|
+
def terminator=(terminator)
|
|
73
|
+
write_attr :terminator, terminator
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# @return [Boolean] Identifies whether or not conference members can hear the tone generated when a a key on the phone is pressed.
|
|
78
|
+
#
|
|
79
|
+
def tone_passthrough
|
|
80
|
+
read_attr('tone-passthrough') == 'true'
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# @param [Boolean] tone_passthrough Identifies whether or not conference members can hear the tone generated when a a key on the phone is pressed.
|
|
85
|
+
#
|
|
86
|
+
def tone_passthrough=(tone_passthrough)
|
|
87
|
+
write_attr 'tone-passthrough', tone_passthrough.to_s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# @return [Boolean] Whether or not the conference should be moderated
|
|
92
|
+
#
|
|
93
|
+
def moderator
|
|
94
|
+
read_attr(:moderator) == 'true'
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# @param [Boolean] moderator Whether or not the conference should be moderated
|
|
99
|
+
#
|
|
100
|
+
def moderator=(moderator)
|
|
101
|
+
write_attr :moderator, moderator.to_s
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
##
|
|
105
|
+
# @return [Announcement] the announcement to play to the participant on entry
|
|
106
|
+
#
|
|
107
|
+
def announcement
|
|
108
|
+
node = find_first '//ns:announcement', :ns => self.registered_ns
|
|
109
|
+
Announcement.new node if node
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
##
|
|
113
|
+
# @param [Announcement, Hash] ann
|
|
114
|
+
# @option ann [String] :text Text to speak to the caller as an announcement
|
|
115
|
+
# @option ann [String] :url URL to play to the caller as an announcement
|
|
116
|
+
#
|
|
117
|
+
def announcement=(ann)
|
|
118
|
+
ann = Announcement.new(ann) unless ann.is_a? Announcement
|
|
119
|
+
self << ann
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
##
|
|
123
|
+
# @return [Music] the music to play to the participant on entry if there's no moderator present
|
|
124
|
+
#
|
|
125
|
+
def music
|
|
126
|
+
node = find_first '//ns:music', :ns => self.registered_ns
|
|
127
|
+
Music.new node if node
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
##
|
|
131
|
+
# @param [Music, Hash] m
|
|
132
|
+
# @option m [String] :text Text to speak to the caller
|
|
133
|
+
# @option m [String] :url URL to play to the caller
|
|
134
|
+
#
|
|
135
|
+
def music=(m)
|
|
136
|
+
m = Music.new(m) unless m.is_a? Announcement
|
|
137
|
+
self << m
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class Announcement < MediaNode
|
|
141
|
+
register :announcement, :conference
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
class Music < MediaNode
|
|
145
|
+
register :music, :conference
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def inspect_attributes # :nodoc:
|
|
149
|
+
[:name, :mute, :terminator, :tone_passthrough, :moderator, :announcement, :music] + super
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def transition_state!(event)
|
|
153
|
+
super
|
|
154
|
+
case event
|
|
155
|
+
when OnHold
|
|
156
|
+
onhold!
|
|
157
|
+
when OffHold
|
|
158
|
+
offhold!
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
state_machine :state do
|
|
163
|
+
after_transition :new => :requested do |command, transition|
|
|
164
|
+
command.mute ? command.muted! : command.unmuted!
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
state_machine :mute_status, :initial => :unknown_mute do
|
|
169
|
+
event :muted do
|
|
170
|
+
transition [:unmuted, :unknown_mute] => :muted
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
event :unmuted do
|
|
174
|
+
transition [:muted, :unknown_mute] => :unmuted
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
state_machine :hold_status, :initial => :unknown_hold do
|
|
179
|
+
event :onhold do
|
|
180
|
+
transition [:offhold, :unknown_hold] => :onhold
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
event :offhold do
|
|
184
|
+
transition [:onhold, :unknown_hold] => :offhold
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
class OnHold < Event
|
|
189
|
+
register :'on-hold', :conference
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
class OffHold < Event
|
|
193
|
+
register :'off-hold', :conference
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
module ActiveSpeaker
|
|
197
|
+
def speaking_call_id
|
|
198
|
+
read_attr :'call-id'
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
class Speaking < Event
|
|
203
|
+
register :speaking, :conference
|
|
204
|
+
include ActiveSpeaker
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
class FinishedSpeaking < Event
|
|
208
|
+
register :'finished-speaking', :conference
|
|
209
|
+
include ActiveSpeaker
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
class Complete
|
|
213
|
+
class Kick < Event::Complete::Reason
|
|
214
|
+
register :kick, :conference_complete
|
|
215
|
+
|
|
216
|
+
alias :details :text
|
|
217
|
+
|
|
218
|
+
def inspect_attributes # :nodoc:
|
|
219
|
+
[:details] + super
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
class Terminator < Event::Complete::Reason
|
|
224
|
+
register :terminator, :conference_complete
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
##
|
|
229
|
+
# Create an Rayo mute message for the current conference
|
|
230
|
+
#
|
|
231
|
+
# @return [Command::Conference::Mute] an Rayo mute message
|
|
232
|
+
#
|
|
233
|
+
# @example
|
|
234
|
+
# conf_obj.mute_action.to_xml
|
|
235
|
+
#
|
|
236
|
+
# returns:
|
|
237
|
+
# <mute xmlns="urn:xmpp:tropo:conference:1"/>
|
|
238
|
+
#
|
|
239
|
+
def mute_action
|
|
240
|
+
Command::Mute.new :component_id => component_id, :call_id => call_id
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
##
|
|
244
|
+
# Sends an Rayo mute message for the current Conference
|
|
245
|
+
#
|
|
246
|
+
def mute!
|
|
247
|
+
raise InvalidActionError, "Cannot mute a Conference that is already muted" if muted?
|
|
248
|
+
mute_action.tap do |action|
|
|
249
|
+
result = write_action action
|
|
250
|
+
muted! if result
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
##
|
|
255
|
+
# Create an Rayo unmute message for the current conference
|
|
256
|
+
#
|
|
257
|
+
# @return [Command::Conference::Unmute] an Rayo unmute message
|
|
258
|
+
#
|
|
259
|
+
# @example
|
|
260
|
+
# conf_obj.unmute_action.to_xml
|
|
261
|
+
#
|
|
262
|
+
# returns:
|
|
263
|
+
# <unmute xmlns="urn:xmpp:tropo:conference:1"/>
|
|
264
|
+
#
|
|
265
|
+
def unmute_action
|
|
266
|
+
Command::Unmute.new :component_id => component_id, :call_id => call_id
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
##
|
|
270
|
+
# Sends an Rayo unmute message for the current Conference
|
|
271
|
+
#
|
|
272
|
+
def unmute!
|
|
273
|
+
raise InvalidActionError, "Cannot unmute a Conference that is not muted" unless muted?
|
|
274
|
+
unmute_action.tap do |action|
|
|
275
|
+
result = write_action action
|
|
276
|
+
unmuted! if result
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
##
|
|
281
|
+
# Create an Rayo conference kick message
|
|
282
|
+
#
|
|
283
|
+
# @param [Hash] options
|
|
284
|
+
# @option options [String] :message to explain the reason for kicking
|
|
285
|
+
#
|
|
286
|
+
# @return [Command::Conference::Kick] an Rayo conference kick message
|
|
287
|
+
#
|
|
288
|
+
# @example
|
|
289
|
+
# conf_obj.kick_action(:message => 'bye!').to_xml
|
|
290
|
+
#
|
|
291
|
+
# returns:
|
|
292
|
+
# <kick xmlns="urn:xmpp:tropo:conference:1">bye!</kick>
|
|
293
|
+
#
|
|
294
|
+
def kick_action(options = {})
|
|
295
|
+
Kick.new options.merge(:component_id => component_id, :call_id => call_id)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
##
|
|
299
|
+
# Sends an Rayo kick message for the current Conference
|
|
300
|
+
#
|
|
301
|
+
# @param [Hash] options
|
|
302
|
+
# @option options [String] :message to explain the reason for kicking
|
|
303
|
+
#
|
|
304
|
+
def kick!(options = {})
|
|
305
|
+
raise InvalidActionError, "Cannot kick a Conference that is not executing" unless executing?
|
|
306
|
+
kick_action.tap do |action|
|
|
307
|
+
write_action action
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
class Kick < CommandNode # :nodoc:
|
|
312
|
+
register :kick, :conference
|
|
313
|
+
|
|
314
|
+
def self.new(options = {})
|
|
315
|
+
super.tap do |new_node|
|
|
316
|
+
new_node.message = options[:message]
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def message=(m)
|
|
321
|
+
self << m if m
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
end # Conference
|
|
326
|
+
end # Tropo
|
|
327
|
+
end # Command
|
|
328
|
+
end # Punchblock
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module Punchblock
|
|
2
|
+
module Component
|
|
3
|
+
module Tropo
|
|
4
|
+
class Say < ComponentNode
|
|
5
|
+
register :say, :say
|
|
6
|
+
|
|
7
|
+
include MediaContainer
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Creates an Rayo Say command
|
|
11
|
+
#
|
|
12
|
+
# @param [Hash] options
|
|
13
|
+
# @option options [String, Optional] :text to speak back
|
|
14
|
+
# @option options [String, Optional] :voice with which to render TTS
|
|
15
|
+
# @option options [String, Optional] :ssml document to render TTS
|
|
16
|
+
#
|
|
17
|
+
# @return [Command::Say] an Rayo "say" command
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# say :text => 'Hello brown cow.'
|
|
21
|
+
#
|
|
22
|
+
# returns:
|
|
23
|
+
# <say xmlns="urn:xmpp:tropo:say:1">Hello brown cow.</say>
|
|
24
|
+
#
|
|
25
|
+
def self.new(options = {})
|
|
26
|
+
super().tap do |new_node|
|
|
27
|
+
case options
|
|
28
|
+
when Hash
|
|
29
|
+
new_node.voice = options.delete(:voice) if options[:voice]
|
|
30
|
+
new_node.ssml = options.delete(:ssml) if options[:ssml]
|
|
31
|
+
new_node << options.delete(:text) if options[:text]
|
|
32
|
+
when Nokogiri::XML::Element
|
|
33
|
+
new_node.inherit options
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
state_machine :state do
|
|
39
|
+
event :paused do
|
|
40
|
+
transition :executing => :paused
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
event :resumed do
|
|
44
|
+
transition :paused => :executing
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Pauses a running Say
|
|
49
|
+
#
|
|
50
|
+
# @return [Command::Say::Pause] an Rayo pause message for the current Say
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# say_obj.pause_action.to_xml
|
|
54
|
+
#
|
|
55
|
+
# returns:
|
|
56
|
+
# <pause xmlns="urn:xmpp:tropo:say:1"/>
|
|
57
|
+
def pause_action
|
|
58
|
+
Pause.new :component_id => component_id, :call_id => call_id
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# Sends an Rayo pause message for the current Say
|
|
63
|
+
#
|
|
64
|
+
def pause!
|
|
65
|
+
raise InvalidActionError, "Cannot pause a Say that is not executing" unless executing?
|
|
66
|
+
pause_action.tap do |action|
|
|
67
|
+
result = write_action action
|
|
68
|
+
paused! if result
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Create an Rayo resume message for the current Say
|
|
74
|
+
#
|
|
75
|
+
# @return [Command::Say::Resume] an Rayo resume message
|
|
76
|
+
#
|
|
77
|
+
# @example
|
|
78
|
+
# say_obj.resume_action.to_xml
|
|
79
|
+
#
|
|
80
|
+
# returns:
|
|
81
|
+
# <resume xmlns="urn:xmpp:tropo:say:1"/>
|
|
82
|
+
def resume_action
|
|
83
|
+
Resume.new :component_id => component_id, :call_id => call_id
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# Sends an Rayo resume message for the current Say
|
|
88
|
+
#
|
|
89
|
+
def resume!
|
|
90
|
+
raise InvalidActionError, "Cannot resume a Say that is not paused." unless paused?
|
|
91
|
+
resume_action.tap do |action|
|
|
92
|
+
result = write_action action
|
|
93
|
+
resumed! if result
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
class Pause < CommandNode # :nodoc:
|
|
98
|
+
register :pause, :say
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class Resume < CommandNode # :nodoc:
|
|
102
|
+
register :resume, :say
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class Complete
|
|
106
|
+
class Success < Event::Complete::Reason
|
|
107
|
+
register :success, :say_complete
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end # Say
|
|
111
|
+
end # Tropo
|
|
112
|
+
end # Command
|
|
113
|
+
end # Punchblock
|