punchblock 1.9.4 → 2.0.0.beta1

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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -2
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile +1 -0
  6. data/Guardfile +4 -0
  7. data/README.markdown +6 -0
  8. data/Rakefile +16 -0
  9. data/benchmarks/ami_event_name_comparison.rb +14 -0
  10. data/benchmarks/channel.rb +27 -0
  11. data/lib/punchblock/client.rb +2 -6
  12. data/lib/punchblock/command/accept.rb +3 -24
  13. data/lib/punchblock/command/answer.rb +3 -24
  14. data/lib/punchblock/command/dial.rb +24 -76
  15. data/lib/punchblock/command/hangup.rb +3 -19
  16. data/lib/punchblock/command/join.rb +21 -70
  17. data/lib/punchblock/command/mute.rb +3 -3
  18. data/lib/punchblock/command/redirect.rb +6 -39
  19. data/lib/punchblock/command/reject.rb +14 -54
  20. data/lib/punchblock/command/unjoin.rb +8 -40
  21. data/lib/punchblock/command/unmute.rb +3 -3
  22. data/lib/punchblock/command_node.rb +0 -17
  23. data/lib/punchblock/component/asterisk/agi/command.rb +20 -127
  24. data/lib/punchblock/component/asterisk/ami/action.rb +30 -117
  25. data/lib/punchblock/component/component_node.rb +1 -1
  26. data/lib/punchblock/component/input.rb +89 -268
  27. data/lib/punchblock/component/output.rb +106 -154
  28. data/lib/punchblock/component/prompt.rb +51 -0
  29. data/lib/punchblock/component/record.rb +41 -130
  30. data/lib/punchblock/component.rb +1 -0
  31. data/lib/punchblock/connection/asterisk.rb +31 -4
  32. data/lib/punchblock/connection/xmpp.rb +6 -14
  33. data/lib/punchblock/core_ext/blather/stanza.rb +1 -1
  34. data/lib/punchblock/event/active_speaker.rb +2 -10
  35. data/lib/punchblock/event/answered.rb +3 -3
  36. data/lib/punchblock/event/asterisk/ami/event.rb +15 -47
  37. data/lib/punchblock/event/complete.rb +26 -48
  38. data/lib/punchblock/event/dtmf.rb +3 -13
  39. data/lib/punchblock/event/end.rb +10 -11
  40. data/lib/punchblock/event/joined.rb +5 -25
  41. data/lib/punchblock/event/offer.rb +4 -25
  42. data/lib/punchblock/event/ringing.rb +3 -3
  43. data/lib/punchblock/event/unjoined.rb +5 -25
  44. data/lib/punchblock/event.rb +0 -10
  45. data/lib/punchblock/has_headers.rb +20 -26
  46. data/lib/punchblock/rayo_node.rb +46 -23
  47. data/lib/punchblock/ref.rb +39 -18
  48. data/lib/punchblock/translator/asterisk/agi_app.rb +15 -0
  49. data/lib/punchblock/translator/asterisk/agi_command.rb +3 -1
  50. data/lib/punchblock/translator/asterisk/ami_error_converter.rb +20 -0
  51. data/lib/punchblock/translator/asterisk/call.rb +60 -39
  52. data/lib/punchblock/translator/asterisk/channel.rb +41 -0
  53. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +4 -1
  54. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +4 -4
  55. data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +62 -0
  56. data/lib/punchblock/translator/asterisk/component/input.rb +1 -0
  57. data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +56 -0
  58. data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +53 -0
  59. data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +99 -0
  60. data/lib/punchblock/translator/asterisk/component/output.rb +30 -22
  61. data/lib/punchblock/translator/asterisk/component/record.rb +8 -6
  62. data/lib/punchblock/translator/asterisk/component.rb +6 -5
  63. data/lib/punchblock/translator/asterisk/unimrcp_app.rb +26 -0
  64. data/lib/punchblock/translator/asterisk.rb +24 -28
  65. data/lib/punchblock/translator/dtmf_recognizer.rb +39 -20
  66. data/lib/punchblock/translator/freeswitch/call.rb +15 -14
  67. data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +5 -4
  68. data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
  69. data/lib/punchblock/translator/freeswitch/component/input.rb +5 -0
  70. data/lib/punchblock/translator/freeswitch/component/output.rb +2 -2
  71. data/lib/punchblock/translator/freeswitch/component/record.rb +19 -13
  72. data/lib/punchblock/translator/freeswitch/component/tts_output.rb +2 -2
  73. data/lib/punchblock/translator/freeswitch/component.rb +2 -5
  74. data/lib/punchblock/translator/freeswitch.rb +2 -2
  75. data/lib/punchblock/translator/input_component.rb +33 -13
  76. data/lib/punchblock/uri_list.rb +21 -0
  77. data/lib/punchblock/version.rb +1 -1
  78. data/lib/punchblock.rb +4 -3
  79. data/punchblock.gemspec +7 -3
  80. data/spec/punchblock/client/component_registry_spec.rb +1 -1
  81. data/spec/punchblock/client_spec.rb +10 -26
  82. data/spec/punchblock/command/accept_spec.rb +41 -7
  83. data/spec/punchblock/command/answer_spec.rb +51 -7
  84. data/spec/punchblock/command/dial_spec.rb +56 -14
  85. data/spec/punchblock/command/hangup_spec.rb +41 -7
  86. data/spec/punchblock/command/join_spec.rb +53 -11
  87. data/spec/punchblock/command/mute_spec.rb +19 -4
  88. data/spec/punchblock/command/redirect_spec.rb +40 -10
  89. data/spec/punchblock/command/reject_spec.rb +43 -11
  90. data/spec/punchblock/command/unjoin_spec.rb +40 -9
  91. data/spec/punchblock/command/unmute_spec.rb +19 -4
  92. data/spec/punchblock/command_node_spec.rb +0 -4
  93. data/spec/punchblock/component/asterisk/agi/command_spec.rb +16 -39
  94. data/spec/punchblock/component/asterisk/ami/action_spec.rb +50 -53
  95. data/spec/punchblock/component/component_node_spec.rb +3 -5
  96. data/spec/punchblock/component/input_spec.rb +194 -61
  97. data/spec/punchblock/component/output_spec.rb +194 -62
  98. data/spec/punchblock/component/prompt_spec.rb +132 -0
  99. data/spec/punchblock/component/record_spec.rb +70 -32
  100. data/spec/punchblock/connection/asterisk_spec.rb +17 -3
  101. data/spec/punchblock/connection/freeswitch_spec.rb +4 -4
  102. data/spec/punchblock/connection/xmpp_spec.rb +20 -38
  103. data/spec/punchblock/event/answered_spec.rb +12 -10
  104. data/spec/punchblock/event/asterisk/ami/event_spec.rb +27 -22
  105. data/spec/punchblock/event/complete_spec.rb +15 -19
  106. data/spec/punchblock/event/dtmf_spec.rb +5 -6
  107. data/spec/punchblock/event/end_spec.rb +20 -10
  108. data/spec/punchblock/event/joined_spec.rb +8 -7
  109. data/spec/punchblock/event/offer_spec.rb +41 -12
  110. data/spec/punchblock/event/ringing_spec.rb +12 -10
  111. data/spec/punchblock/event/started_speaking_spec.rb +5 -6
  112. data/spec/punchblock/event/stopped_speaking_spec.rb +5 -6
  113. data/spec/punchblock/event/unjoined_spec.rb +7 -7
  114. data/spec/punchblock/ref_spec.rb +86 -9
  115. data/spec/punchblock/translator/asterisk/call_spec.rb +317 -154
  116. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +28 -5
  117. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +15 -13
  118. data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +237 -0
  119. data/spec/punchblock/translator/asterisk/component/input_spec.rb +171 -14
  120. data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +652 -0
  121. data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +646 -0
  122. data/spec/punchblock/translator/asterisk/component/output_spec.rb +127 -77
  123. data/spec/punchblock/translator/asterisk/component/record_spec.rb +17 -8
  124. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
  125. data/spec/punchblock/translator/asterisk/component_spec.rb +3 -7
  126. data/spec/punchblock/translator/asterisk_spec.rb +20 -24
  127. data/spec/punchblock/translator/freeswitch/call_spec.rb +103 -99
  128. data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +17 -8
  129. data/spec/punchblock/translator/freeswitch/component/input_spec.rb +26 -14
  130. data/spec/punchblock/translator/freeswitch/component/output_spec.rb +30 -52
  131. data/spec/punchblock/translator/freeswitch/component/record_spec.rb +23 -19
  132. data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +18 -8
  133. data/spec/punchblock/translator/freeswitch/component_spec.rb +4 -8
  134. data/spec/punchblock/translator/freeswitch_spec.rb +11 -14
  135. data/spec/punchblock/uri_list_spec.rb +49 -0
  136. data/spec/punchblock_spec.rb +11 -1
  137. data/spec/spec_helper.rb +7 -11
  138. data/spec/support/mock_connection_with_event_handler.rb +1 -1
  139. metadata +104 -24
  140. data/lib/punchblock/header.rb +0 -9
  141. data/lib/punchblock/key_value_pair_node.rb +0 -51
  142. data/spec/punchblock/header_spec.rb +0 -11
@@ -5,174 +5,130 @@ module Punchblock
5
5
  class Output < ComponentNode
6
6
  register :output, :output
7
7
 
8
- ##
9
- # Creates an Rayo Output command
10
- #
11
- # @param [Hash] options
12
- # @option options [String, Optional] :text to speak back
13
- # @option options [String, Optional] :voice with which to render TTS
14
- # @option options [String, Optional] :ssml document to render TTS
15
- # @option options [Symbol] :interrupt_on input type on which to interrupt output. May be :speech, :dtmf or :any
16
- # @option options [Integer] :start_offset Indicates some offset through which the output should be skipped before rendering begins.
17
- # @option options [true, false] :start_paused Indicates wether or not the component should be started in a paused state to be resumed at a later time.
18
- # @option options [Integer] :repeat_interval Indicates the duration of silence that should space repeats of the rendered document.
19
- # @option options [Integer] :repeat_times Indicates the number of times the output should be played.
20
- # @option options [Integer] :max_time Indicates the maximum amount of time for which the output should be allowed to run before being terminated. Includes repeats.
21
- #
22
- # @return [Command::Output] an Rayo "output" command
23
- #
24
- # @example
25
- # output :text => 'Hello brown cow.'
26
- #
27
- # returns:
28
- # <output xmlns="urn:xmpp:rayo:output:1">Hello brown cow.</output>
29
- #
30
- def self.new(options = {})
31
- super().tap do |new_node|
32
- case options
33
- when Hash
34
- new_node.ssml = options.delete(:ssml) if options[:ssml]
35
- new_node << options.delete(:text) if options[:text]
36
- options.each_pair { |k,v| new_node.send :"#{k}=", v }
37
- when Nokogiri::XML::Element
38
- new_node.inherit options
8
+ class Document < RayoNode
9
+ register :document, :output
10
+
11
+ SSML_CONTENT_TYPE = 'application/ssml+xml'
12
+
13
+ # @return [String] the URL from which the fetch the grammar
14
+ attribute :url
15
+
16
+ # @return [String] the document content type
17
+ attribute :content_type, String, default: ->(grammar, attribute) { grammar.url ? nil : SSML_CONTENT_TYPE }
18
+
19
+ # @return [String, RubySpeech::SSML::Speak, URIList] the document
20
+ attribute :value
21
+
22
+ def inherit(xml_node)
23
+ super
24
+ self.value = if ssml?
25
+ RubySpeech::SSML.import xml_node.content
26
+ elsif urilist?
27
+ URIList.import xml_node.content
28
+ else
29
+ xml_node.content
39
30
  end
31
+ self
40
32
  end
41
- end
42
33
 
43
- ##
44
- # @return [String] the TTS voice to use
45
- #
46
- def voice
47
- read_attr :voice
48
- end
34
+ def rayo_attributes
35
+ {
36
+ 'url' => url,
37
+ 'content-type' => content_type
38
+ }
39
+ end
49
40
 
50
- ##
51
- # @param [String] voice to use when rendering TTS
52
- #
53
- def voice=(voice)
54
- write_attr :voice, voice
55
- end
41
+ def rayo_children(root)
42
+ root.cdata xml_value
43
+ super
44
+ end
56
45
 
57
- ##
58
- # @return [String] the SSML document to render TTS
59
- #
60
- def ssml
61
- node = children.first
62
- RubySpeech::SSML.import node if node
63
- end
46
+ private
64
47
 
65
- ##
66
- # @param [String] ssml the SSML document to render TTS
67
- #
68
- def ssml=(ssml)
69
- return unless ssml
70
- unless ssml.is_a?(RubySpeech::SSML::Element)
71
- ssml = RubySpeech::SSML.import ssml
48
+ def xml_value
49
+ if ssml?
50
+ value.to_xml
51
+ elsif urilist?
52
+ value.to_s
53
+ elsif
54
+ value
55
+ end
72
56
  end
73
- self << ssml
74
- end
75
57
 
76
- ##
77
- # @return [Symbol] input type on which to interrupt output
78
- #
79
- def interrupt_on
80
- read_attr :'interrupt-on', :to_sym
81
- end
58
+ def ssml?
59
+ content_type == SSML_CONTENT_TYPE
60
+ end
82
61
 
83
- ##
84
- # @param [Symbol] other input type on which to interrupt output. May be :speech, :dtmf or :any
85
- #
86
- def interrupt_on=(other)
87
- write_attr :'interrupt-on', other
62
+ def urilist?
63
+ content_type == 'text/uri-list'
64
+ end
88
65
  end
89
66
 
90
- ##
91
- # @return [Integer] Indicates some offset through which the output should be skipped before rendering begins.
92
- #
93
- def start_offset
94
- read_attr :'start-offset', :to_i
67
+ def inherit(xml_node)
68
+ document_nodes = xml_node.xpath 'ns:document', ns: self.class.registered_ns
69
+ self.render_documents = document_nodes.to_a.map { |node| Document.from_xml node }
70
+ super
95
71
  end
96
72
 
97
- ##
98
- # @param [Integer] other Indicates some offset through which the output should be skipped before rendering begins.
99
- #
100
- def start_offset=(other)
101
- write_attr :'start-offset', other, :to_i
102
- end
73
+ # @return [String] the TTS voice to use
74
+ attribute :voice, String
103
75
 
104
- ##
105
- # @return [true, false] Indicates wether or not the component should be started in a paused state to be resumed at a later time.
106
- #
107
- def start_paused
108
- read_attr(:'start-paused') == 'true'
109
- end
76
+ # @return [Symbol] input type on which to interrupt output
77
+ attribute :interrupt_on, Symbol
110
78
 
111
- ##
112
- # @param [true, false] other Indicates wether or not the component should be started in a paused state to be resumed at a later time.
113
- #
114
- def start_paused=(other)
115
- write_attr :'start-paused', other, :to_s
116
- end
79
+ # @return [Integer] Indicates some offset through which the output should be skipped before rendering begins.
80
+ attribute :start_offset, Integer
117
81
 
118
- ##
119
- # @return [Integer] Indicates the duration of silence that should space repeats of the rendered document.
120
- #
121
- def repeat_interval
122
- read_attr :'repeat-interval', :to_i
123
- end
82
+ # @return [true, false] Indicates wether or not the component should be started in a paused state to be resumed at a later time.
83
+ attribute :start_paused, Boolean, default: false
124
84
 
125
- ##
126
- # @param [Integer] other Indicates the duration of silence that should space repeats of the rendered document.
127
- #
128
- def repeat_interval=(other)
129
- write_attr :'repeat-interval', other, :to_i
130
- end
85
+ # @return [Integer] Indicates the duration of silence that should space repeats of the rendered document.
86
+ attribute :repeat_interval, Integer
131
87
 
132
- ##
133
88
  # @return [Integer] Indicates the number of times the output should be played.
134
- #
135
- def repeat_times
136
- read_attr :'repeat-times', :to_i
137
- end
138
-
139
- ##
140
- # @param [Integer] other Indicates the number of times the output should be played.
141
- #
142
- def repeat_times=(other)
143
- write_attr :'repeat-times', other, :to_i
144
- end
89
+ attribute :repeat_times, Integer
145
90
 
146
- ##
147
91
  # @return [Integer] Indicates the maximum amount of time for which the output should be allowed to run before being terminated. Includes repeats.
148
- #
149
- def max_time
150
- read_attr :'max-time', :to_i
151
- end
92
+ attribute :max_time, Integer
152
93
 
153
- ##
154
- # @param [Integer] other Indicates the maximum amount of time for which the output should be allowed to run before being terminated. Includes repeats.
155
- #
156
- def max_time=(other)
157
- write_attr :'max-time', other, :to_i
94
+ # @return [String] the rendering engine requested by the component
95
+ attribute :renderer, String
96
+
97
+ def rayo_attributes
98
+ {
99
+ 'voice' => voice,
100
+ 'interrupt-on' => interrupt_on,
101
+ 'start-offset' => start_offset,
102
+ 'start-paused' => start_paused,
103
+ 'repeat-interval' => repeat_interval,
104
+ 'repeat-times' => repeat_times,
105
+ 'max-time' => max_time,
106
+ 'renderer' => renderer
107
+ }
158
108
  end
159
109
 
160
- ##
161
- # @return [String] the rendering engine requested by the component
162
- #
163
- def renderer
164
- read_attr :renderer
110
+ def rayo_children(root)
111
+ render_documents.each do |render_document|
112
+ render_document.to_rayo root.parent
113
+ end
114
+ super
165
115
  end
166
116
 
117
+ # @return [Document] the document to render
118
+ attribute :render_documents, Array[Document], default: []
119
+
167
120
  ##
168
- # @param [String] the rendering engine to use with this component
121
+ # @param [Hash] other
122
+ # @option other [String] :content_type the document content type
123
+ # @option other [String] :value the output doucment
124
+ # @option other [String] :url the url from which to fetch the document
169
125
  #
170
- def renderer=(renderer)
171
- write_attr :renderer, renderer
126
+ def render_document=(other)
127
+ self.render_documents = [other].compact
172
128
  end
173
129
 
174
- def inspect_attributes
175
- super + [:voice, :ssml, :interrupt_on, :start_offset, :start_paused, :repeat_interval, :repeat_times, :max_time, :renderer]
130
+ def ssml=(other)
131
+ self.render_documents = [{:value => other}]
176
132
  end
177
133
 
178
134
  state_machine :state do
@@ -281,20 +237,8 @@ module Punchblock
281
237
  class Seek < CommandNode # :nodoc:
282
238
  register :seek, :output
283
239
 
284
- def self.new(options = {})
285
- super.tap do |new_node|
286
- new_node.direction = options[:direction]
287
- new_node.amount = options[:amount]
288
- end
289
- end
290
-
291
- def direction=(other)
292
- write_attr :direction, other
293
- end
294
-
295
- def amount=(other)
296
- write_attr :amount, other
297
- end
240
+ attribute :direction
241
+ attribute :amount
298
242
 
299
243
  def request!
300
244
  source.seeking!
@@ -305,6 +249,10 @@ module Punchblock
305
249
  source.stopped_seeking!
306
250
  super
307
251
  end
252
+
253
+ def rayo_attributes
254
+ {'direction' => direction, 'amount' => amount}
255
+ end
308
256
  end
309
257
 
310
258
  ##
@@ -496,8 +444,12 @@ module Punchblock
496
444
  end
497
445
 
498
446
  class Complete
499
- class Success < Event::Complete::Reason
500
- register :success, :output_complete
447
+ class Finish < Event::Complete::Reason
448
+ register :finish, :output_complete
449
+ end
450
+
451
+ class MaxTime < Event::Complete::Reason
452
+ register :'max-time', :output_complete
501
453
  end
502
454
  end
503
455
  end # Output
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ module Punchblock
4
+ module Component
5
+ class Prompt < ComponentNode
6
+ register :prompt, :prompt
7
+
8
+ attribute :barge_in, Boolean
9
+ attribute :output, Output
10
+ attribute :input, Input
11
+
12
+ ##
13
+ # Create a prompt command
14
+ #
15
+ # @param [Output] output
16
+ # @param [Input] input
17
+ # @param [Hash] options
18
+ # @option options [true, false, optional] :barge_in Indicates wether or not the input should interrupt then output
19
+ #
20
+ # @return [Component::Prompt] a formatted Rayo prompt command
21
+ #
22
+ def initialize(output = nil, input = nil, options = {})
23
+ super options
24
+ self.output = output
25
+ self.input = input
26
+ end
27
+
28
+ def inherit(xml_node)
29
+ input_node = xml_node.at_xpath('ns:input', ns: Input.registered_ns)
30
+ self.input = Input.from_xml input_node if input_node
31
+
32
+ output_node = xml_node.at_xpath('ns:output', ns: Output.registered_ns)
33
+ self.output = Output.from_xml output_node if output_node
34
+
35
+ super
36
+ end
37
+
38
+ def rayo_attributes
39
+ {
40
+ 'barge-in' => barge_in
41
+ }
42
+ end
43
+
44
+ def rayo_children(root)
45
+ input.to_rayo(root) if input
46
+ output.to_rayo(root) if output
47
+ super
48
+ end
49
+ end
50
+ end
51
+ end
@@ -7,132 +7,51 @@ module Punchblock
7
7
 
8
8
  VALID_DIRECTIONS = [:duplex, :send, :recv].freeze
9
9
 
10
- ##
11
- # Creates an Rayo Record command
12
- #
13
- # @param [Hash] options
14
- # @option options [String] :format to use for recording
15
- # @option options [Integer] :initial_timeout Controls how long the recognizer should wait after the end of the prompt for the caller to speak before sending a Recorder event.
16
- # @option options [Integer] :final_timeout Controls the length of a period of silence after callers have spoken to conclude they finished.
17
- # @option options [Integer] :max_duration Indicates the maximum duration for the recording.
18
- # @option options [true, false] :start_beep Indicates whether subsequent record will be preceded with a beep.
19
- # @option options [true, false] :start_paused Whether subsequent record will start in PAUSE mode.
20
- #
21
- # @return [Command::Record] a Rayo "record" command
22
- #
23
- # @example
24
- # record :text => 'Hello brown cow.'
25
- #
26
- # returns:
27
- # <record xmlns="urn:xmpp:rayo:record:1">Hello brown cow.</record>
28
- #
29
- def self.new(options = {})
30
- super().tap do |new_node|
31
- options.each_pair { |k,v| new_node.send :"#{k}=", v }
32
- end
33
- end
34
-
35
- ##
36
- # @return [Integer] Controls the length of a period of silence after callers have spoken to conclude they finished.
37
- #
38
- def final_timeout
39
- read_attr :'final-timeout', :to_i
40
- end
41
-
42
- ##
43
- # @param [Integer] timeout Controls the length of a period of silence after callers have spoken to conclude they finished.
44
- #
45
- def final_timeout=(timeout)
46
- write_attr :'final-timeout', timeout, :to_i
47
- end
48
-
49
- ##
50
10
  # @return [String] the codec to use for recording
51
- #
52
- def format
53
- read_attr :format
54
- end
55
-
56
- ##
57
- # @param [String] codec to use for recording
58
- #
59
- def format=(format)
60
- write_attr :format, format
61
- end
11
+ attribute :format
62
12
 
63
- ##
64
13
  # @return [Integer] Controls how long the recognizer should wait after the end of the prompt for the caller to speak before sending a Recorder event.
65
- #
66
- def initial_timeout
67
- read_attr :'initial-timeout', :to_i
68
- end
14
+ attribute :initial_timeout, Integer
69
15
 
70
- ##
71
- # @param [Integer] timeout Controls how long the recognizer should wait after the end of the prompt for the caller to speak before sending a Recorder event.
72
- #
73
- def initial_timeout=(timeout)
74
- write_attr :'initial-timeout', timeout, :to_i
75
- end
16
+ # @return [Integer] Controls the length of a period of silence after callers have spoken to conclude they finished.
17
+ attribute :final_timeout, Integer
76
18
 
77
- ##
78
19
  # @return [Integer] Indicates the maximum duration for the recording.
79
- #
80
- def max_duration
81
- read_attr :'max-duration', :to_i
82
- end
20
+ attribute :max_duration, Integer
83
21
 
84
- ##
85
- # @param [Integer] other Indicates the maximum duration for the recording.
86
- #
87
- def max_duration=(other)
88
- write_attr :'max-duration', other, :to_i
89
- end
22
+ # @return [true, false] Indicates whether record will be preceded with a beep.
23
+ attribute :start_beep, Boolean
90
24
 
91
- ##
92
- # @return [true, false] Indicates whether subsequent record will be preceded with a beep.
93
- #
94
- def start_beep
95
- read_attr(:'start-beep') == 'true'
96
- end
25
+ # @return [true, false] Indicates whether record will be followed by a beep.
26
+ attribute :stop_beep, Boolean
97
27
 
98
- ##
99
- # @param [true, false] sb Indicates whether subsequent record will be preceded with a beep.
100
- #
101
- def start_beep=(sb)
102
- write_attr :'start-beep', sb
103
- end
104
-
105
- ##
106
28
  # @return [true, false] Whether subsequent record will start in PAUSE mode.
107
- #
108
- def start_paused
109
- read_attr(:'start-paused') == 'true'
110
- end
29
+ attribute :start_paused, Boolean
111
30
 
112
- ##
113
- # @param [true, false] other Whether subsequent record will start in PAUSE mode.
114
- #
115
- def start_paused=(other)
116
- write_attr :'start-paused', other
117
- end
118
-
119
- ##
120
31
  # @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
32
+ attribute :direction, Symbol
127
33
  def direction=(direction)
128
34
  if direction && !VALID_DIRECTIONS.include?(direction.to_sym)
129
35
  raise ArgumentError, "Invalid Direction (#{direction}), use: #{VALID_DIRECTIONS*' '}"
130
36
  end
131
- write_attr :direction, direction
37
+ super
132
38
  end
133
39
 
134
- def inspect_attributes # :nodoc:
135
- [:final_timeout, :format, :initial_timeout, :max_duration, :start_beep, :start_paused, :direction] + super
40
+ # @return [true, false] wether to mix audio down or not
41
+ attribute :mix, Boolean
42
+
43
+ def rayo_attributes
44
+ {
45
+ 'format' => format,
46
+ 'initial-timeout' => initial_timeout,
47
+ 'final-timeout' => final_timeout,
48
+ 'max-duration' => max_duration,
49
+ 'start-beep' => start_beep,
50
+ 'stop-beep' => start_beep,
51
+ 'start-paused' => start_paused,
52
+ 'direction' => direction,
53
+ 'mix' => mix
54
+ }
136
55
  end
137
56
 
138
57
  state_machine :state do
@@ -221,32 +140,24 @@ module Punchblock
221
140
  class Recording < Event
222
141
  register :recording, :record_complete
223
142
 
224
- def uri
225
- read_attr :uri
226
- end
227
-
228
- def uri=(other)
229
- write_attr :uri, other
230
- end
231
-
232
- def duration
233
- read_attr :duration, :to_i
234
- end
143
+ attribute :uri
144
+ attribute :duration, Integer
145
+ attribute :size, Integer
146
+ end
235
147
 
236
- def size
237
- read_attr :size, :to_i
148
+ class Complete
149
+ class MaxDuration < Event::Complete::Reason
150
+ register :'max-duration', :record_complete
238
151
  end
239
152
 
240
- def inspect_attributes # :nodoc:
241
- [:uri, :duration, :size] + super
153
+ class InitialTimeout < Event::Complete::Reason
154
+ register :'initial-timeout', :record_complete
242
155
  end
243
- end
244
156
 
245
- class Complete
246
- class Success < Event::Complete::Reason
247
- register :success, :record_complete
157
+ class FinalTimeout < Event::Complete::Reason
158
+ register :'final-timeout', :record_complete
248
159
  end
249
160
  end
250
- end # Record
251
- end # Command
252
- end # Punchblock
161
+ end
162
+ end
163
+ end
@@ -8,6 +8,7 @@ module Punchblock
8
8
  autoload :ComponentNode
9
9
  autoload :Input
10
10
  autoload :Output
11
+ autoload :Prompt
11
12
  autoload :Record
12
13
  autoload :Stop
13
14
 
@@ -9,14 +9,15 @@ module Punchblock
9
9
  attr_accessor :event_handler
10
10
 
11
11
  def initialize(options = {})
12
- @ami_client = RubyAMI::Stream.new options[:host], options[:port], options[:username], options[:password], ->(event) { translator.async.handle_ami_event event }, pb_logger
13
- @translator = Translator::Asterisk.new @ami_client, self, options[:media_engine]
12
+ @stream_options = options.values_at(:host, :port, :username, :password)
13
+ @translator_options = options.values_at(:media_engine)
14
+ @ami_client = new_ami_stream
15
+ @translator = Translator::Asterisk.new @ami_client, self, *@translator_options
14
16
  super()
15
17
  end
16
18
 
17
19
  def run
18
- ami_client.async.run
19
- Celluloid::Actor.join(ami_client)
20
+ start_ami_client
20
21
  raise DisconnectedError
21
22
  end
22
23
 
@@ -32,6 +33,32 @@ module Punchblock
32
33
  def handle_event(event)
33
34
  event_handler.call event
34
35
  end
36
+
37
+ def new_ami_stream
38
+ stream = RubyAMI::Stream.new(*@stream_options, ->(event) { translator.async.handle_ami_event event }, pb_logger)
39
+ client = (ami_client || RubyAMIStreamProxy.new(stream))
40
+ client.stream = stream
41
+ client
42
+ end
43
+
44
+ def start_ami_client
45
+ @ami_client = new_ami_stream unless ami_client.alive?
46
+ ami_client.async.run
47
+ Celluloid::Actor.join(ami_client)
48
+ end
49
+ end
50
+
51
+ class RubyAMIStreamProxy
52
+ attr_accessor :stream
53
+
54
+ def initialize(ami)
55
+ @stream = ami
56
+ end
57
+
58
+ def method_missing(method, *args, &block)
59
+ stream.__send__(method, *args, &block)
60
+ end
61
+
35
62
  end
36
63
  end
37
64
  end