adhearsion 2.6.4 → 3.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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -9
  3. data/CHANGELOG.md +22 -7
  4. data/Gemfile +2 -0
  5. data/README.markdown +4 -5
  6. data/Rakefile +1 -2
  7. data/adhearsion.gemspec +19 -8
  8. data/features/cli_create.feature +19 -3
  9. data/features/step_definitions/cli_steps.rb +0 -11
  10. data/features/support/env.rb +3 -4
  11. data/lib/adhearsion.rb +48 -27
  12. data/lib/adhearsion/call.rb +34 -50
  13. data/lib/adhearsion/call_controller.rb +6 -12
  14. data/lib/adhearsion/call_controller/dial.rb +15 -53
  15. data/lib/adhearsion/call_controller/input.rb +39 -162
  16. data/lib/adhearsion/call_controller/input/ask_grammar_builder.rb +44 -0
  17. data/lib/adhearsion/call_controller/input/menu_builder.rb +136 -0
  18. data/lib/adhearsion/call_controller/input/prompt_builder.rb +78 -0
  19. data/lib/adhearsion/call_controller/input/result.rb +46 -0
  20. data/lib/adhearsion/call_controller/output.rb +48 -67
  21. data/lib/adhearsion/call_controller/output/abstract_player.rb +3 -3
  22. data/lib/adhearsion/call_controller/output/async_player.rb +3 -3
  23. data/lib/adhearsion/call_controller/output/player.rb +1 -1
  24. data/lib/adhearsion/call_controller/record.rb +23 -8
  25. data/lib/adhearsion/calls.rb +1 -1
  26. data/lib/adhearsion/cli_commands/ahn_command.rb +2 -65
  27. data/lib/adhearsion/cli_commands/thor_errors.rb +0 -6
  28. data/lib/adhearsion/configuration.rb +91 -39
  29. data/lib/adhearsion/core_ext/blather/stanza.rb +41 -0
  30. data/lib/adhearsion/core_ext/blather/stanza/presence.rb +13 -0
  31. data/lib/adhearsion/error.rb +5 -0
  32. data/lib/adhearsion/event.rb +21 -0
  33. data/lib/adhearsion/event/active_speaker.rb +11 -0
  34. data/lib/adhearsion/event/answered.rb +11 -0
  35. data/lib/adhearsion/event/asterisk.rb +10 -0
  36. data/lib/adhearsion/event/asterisk/ami.rb +34 -0
  37. data/lib/adhearsion/event/complete.rb +75 -0
  38. data/lib/adhearsion/event/dtmf.rb +11 -0
  39. data/lib/adhearsion/event/end.rb +22 -0
  40. data/lib/adhearsion/event/input_timers_started.rb +9 -0
  41. data/lib/adhearsion/event/joined.rb +17 -0
  42. data/lib/adhearsion/event/offer.rb +14 -0
  43. data/lib/adhearsion/event/ringing.rb +11 -0
  44. data/lib/adhearsion/event/started_speaking.rb +13 -0
  45. data/lib/adhearsion/event/stopped_speaking.rb +13 -0
  46. data/lib/adhearsion/event/unjoined.rb +17 -0
  47. data/lib/adhearsion/events.rb +47 -66
  48. data/lib/adhearsion/foundation.rb +0 -1
  49. data/lib/adhearsion/foundation/object.rb +0 -5
  50. data/lib/adhearsion/generators/app/app_generator.rb +4 -1
  51. data/lib/adhearsion/generators/app/templates/Gemfile.erb +2 -10
  52. data/lib/adhearsion/generators/app/templates/adhearsion.erb +9 -9
  53. data/lib/adhearsion/generators/app/templates/config.ru +7 -0
  54. data/lib/adhearsion/generators/app/templates/en.yml +4 -0
  55. data/lib/adhearsion/generators/app/templates/events.erb +2 -2
  56. data/lib/adhearsion/generators/app/templates/hello_world.wav +0 -0
  57. data/lib/adhearsion/generators/app/templates/simon_game.rb +2 -1
  58. data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +2 -2
  59. data/lib/adhearsion/has_headers.rb +34 -0
  60. data/lib/adhearsion/http_server.rb +37 -0
  61. data/lib/adhearsion/initializer.rb +19 -153
  62. data/lib/adhearsion/logging.rb +6 -25
  63. data/lib/adhearsion/outbound_call.rb +5 -5
  64. data/lib/adhearsion/plugin.rb +1 -0
  65. data/lib/adhearsion/protocol_error.rb +26 -0
  66. data/lib/adhearsion/rayo.rb +30 -0
  67. data/lib/adhearsion/rayo/client.rb +62 -0
  68. data/lib/adhearsion/rayo/client/component_registry.rb +33 -0
  69. data/lib/adhearsion/rayo/command.rb +21 -0
  70. data/lib/adhearsion/rayo/command/accept.rb +16 -0
  71. data/lib/adhearsion/rayo/command/answer.rb +16 -0
  72. data/lib/adhearsion/rayo/command/dial.rb +57 -0
  73. data/lib/adhearsion/rayo/command/hangup.rb +16 -0
  74. data/lib/adhearsion/rayo/command/join.rb +43 -0
  75. data/lib/adhearsion/rayo/command/mute.rb +13 -0
  76. data/lib/adhearsion/rayo/command/redirect.rb +23 -0
  77. data/lib/adhearsion/rayo/command/reject.rb +40 -0
  78. data/lib/adhearsion/rayo/command/unjoin.rb +24 -0
  79. data/lib/adhearsion/rayo/command/unmute.rb +13 -0
  80. data/lib/adhearsion/rayo/command_node.rb +47 -0
  81. data/lib/adhearsion/rayo/component.rb +21 -0
  82. data/lib/adhearsion/rayo/component/asterisk.rb +13 -0
  83. data/lib/adhearsion/rayo/component/asterisk/agi.rb +14 -0
  84. data/lib/adhearsion/rayo/component/asterisk/agi/command.rb +46 -0
  85. data/lib/adhearsion/rayo/component/asterisk/ami.rb +14 -0
  86. data/lib/adhearsion/rayo/component/asterisk/ami/action.rb +61 -0
  87. data/lib/adhearsion/rayo/component/component_node.rb +90 -0
  88. data/lib/adhearsion/rayo/component/input.rb +186 -0
  89. data/lib/adhearsion/rayo/component/output.rb +471 -0
  90. data/lib/adhearsion/rayo/component/prompt.rb +53 -0
  91. data/lib/adhearsion/rayo/component/receive_fax.rb +26 -0
  92. data/lib/adhearsion/rayo/component/record.rb +165 -0
  93. data/lib/adhearsion/rayo/component/send_fax.rb +64 -0
  94. data/lib/adhearsion/rayo/component/stop.rb +11 -0
  95. data/lib/adhearsion/rayo/connection.rb +12 -0
  96. data/lib/adhearsion/rayo/connection/asterisk.rb +74 -0
  97. data/lib/adhearsion/rayo/connection/connected.rb +22 -0
  98. data/lib/adhearsion/rayo/connection/generic_connection.rb +22 -0
  99. data/lib/adhearsion/rayo/connection/xmpp.rb +198 -0
  100. data/lib/adhearsion/rayo/disconnected_error.rb +22 -0
  101. data/lib/adhearsion/{punchblock_plugin → rayo}/initializer.rb +19 -19
  102. data/lib/adhearsion/rayo/rayo_node.rb +127 -0
  103. data/lib/adhearsion/rayo/ref.rb +57 -0
  104. data/lib/adhearsion/statistics.rb +1 -1
  105. data/lib/adhearsion/tasks.rb +1 -2
  106. data/lib/adhearsion/tasks/configuration.rb +1 -1
  107. data/lib/adhearsion/tasks/environment.rb +0 -2
  108. data/lib/adhearsion/tasks/i18n.rb +49 -0
  109. data/lib/adhearsion/translator.rb +11 -0
  110. data/lib/adhearsion/translator/asterisk.rb +234 -0
  111. data/lib/adhearsion/translator/asterisk/agi_app.rb +17 -0
  112. data/lib/adhearsion/translator/asterisk/agi_command.rb +45 -0
  113. data/lib/adhearsion/translator/asterisk/ami_error_converter.rb +20 -0
  114. data/lib/adhearsion/translator/asterisk/call.rb +416 -0
  115. data/lib/adhearsion/translator/asterisk/channel.rb +43 -0
  116. data/lib/adhearsion/translator/asterisk/component.rb +88 -0
  117. data/lib/adhearsion/translator/asterisk/component/asterisk.rb +15 -0
  118. data/lib/adhearsion/translator/asterisk/component/asterisk/agi_command.rb +42 -0
  119. data/lib/adhearsion/translator/asterisk/component/asterisk/ami_action.rb +68 -0
  120. data/lib/adhearsion/translator/asterisk/component/composed_prompt.rb +76 -0
  121. data/lib/adhearsion/translator/asterisk/component/dtmf_recognizer.rb +137 -0
  122. data/lib/adhearsion/translator/asterisk/component/input.rb +34 -0
  123. data/lib/adhearsion/translator/asterisk/component/input_component.rb +90 -0
  124. data/lib/adhearsion/translator/asterisk/component/mrcp_native_prompt.rb +71 -0
  125. data/lib/adhearsion/translator/asterisk/component/mrcp_prompt.rb +55 -0
  126. data/lib/adhearsion/translator/asterisk/component/mrcp_recog_prompt.rb +165 -0
  127. data/lib/adhearsion/translator/asterisk/component/output.rb +233 -0
  128. data/lib/adhearsion/translator/asterisk/component/record.rb +101 -0
  129. data/lib/adhearsion/translator/asterisk/component/stop_by_redirect.rb +30 -0
  130. data/lib/adhearsion/translator/asterisk/unimrcp_app.rb +28 -0
  131. data/lib/adhearsion/uri_list.rb +21 -0
  132. data/lib/adhearsion/version.rb +1 -1
  133. data/spec/adhearsion/call_controller/dial_spec.rb +79 -1420
  134. data/spec/adhearsion/call_controller/input_spec.rb +1141 -237
  135. data/spec/adhearsion/call_controller/output/async_player_spec.rb +10 -10
  136. data/spec/adhearsion/call_controller/output/player_spec.rb +8 -8
  137. data/spec/adhearsion/call_controller/output_spec.rb +162 -215
  138. data/spec/adhearsion/call_controller/record_spec.rb +15 -16
  139. data/spec/adhearsion/call_controller_spec.rb +23 -40
  140. data/spec/adhearsion/call_spec.rb +123 -129
  141. data/spec/adhearsion/calls_spec.rb +3 -3
  142. data/spec/adhearsion/configuration_spec.rb +94 -108
  143. data/spec/adhearsion/event/answered_spec.rb +50 -0
  144. data/spec/adhearsion/event/asterisk/Find Results +402 -0
  145. data/spec/adhearsion/event/asterisk/ami_spec.rb +81 -0
  146. data/spec/adhearsion/event/complete_spec.rb +176 -0
  147. data/spec/adhearsion/event/dtmf_spec.rb +35 -0
  148. data/spec/adhearsion/event/end_spec.rb +85 -0
  149. data/spec/adhearsion/event/input_timers_started_spec.rb +19 -0
  150. data/spec/adhearsion/event/joined_spec.rb +53 -0
  151. data/spec/adhearsion/event/offer_spec.rb +106 -0
  152. data/spec/adhearsion/event/ringing_spec.rb +50 -0
  153. data/spec/adhearsion/event/started_speaking_spec.rb +37 -0
  154. data/spec/adhearsion/event/stopped_speaking_spec.rb +37 -0
  155. data/spec/adhearsion/event/unjoined_spec.rb +48 -0
  156. data/spec/adhearsion/event/untitled +0 -0
  157. data/spec/adhearsion/events_spec.rb +19 -45
  158. data/spec/adhearsion/initializer_spec.rb +12 -184
  159. data/spec/adhearsion/logging_spec.rb +5 -20
  160. data/spec/adhearsion/outbound_call_spec.rb +13 -13
  161. data/spec/adhearsion/plugin_spec.rb +3 -4
  162. data/spec/adhearsion/protocol_error_spec.rb +91 -0
  163. data/spec/adhearsion/rayo/client/component_registry_spec.rb +26 -0
  164. data/spec/adhearsion/rayo/client_spec.rb +134 -0
  165. data/spec/adhearsion/rayo/command/accept_spec.rb +63 -0
  166. data/spec/adhearsion/rayo/command/answer_spec.rb +73 -0
  167. data/spec/adhearsion/rayo/command/dial_spec.rb +156 -0
  168. data/spec/adhearsion/rayo/command/hangup_spec.rb +63 -0
  169. data/spec/adhearsion/rayo/command/join_spec.rb +158 -0
  170. data/spec/adhearsion/rayo/command/mute_spec.rb +32 -0
  171. data/spec/adhearsion/rayo/command/redirect_spec.rb +89 -0
  172. data/spec/adhearsion/rayo/command/reject_spec.rb +117 -0
  173. data/spec/adhearsion/rayo/command/unjoin_spec.rb +82 -0
  174. data/spec/adhearsion/rayo/command/unmute_spec.rb +32 -0
  175. data/spec/adhearsion/rayo/command_node_spec.rb +101 -0
  176. data/spec/adhearsion/rayo/component/asterisk/agi/command_spec.rb +111 -0
  177. data/spec/adhearsion/rayo/component/asterisk/ami/action_spec.rb +173 -0
  178. data/spec/adhearsion/rayo/component/component_node_spec.rb +110 -0
  179. data/spec/adhearsion/rayo/component/input_spec.rb +715 -0
  180. data/spec/adhearsion/rayo/component/output_spec.rb +1030 -0
  181. data/spec/adhearsion/rayo/component/prompt_spec.rb +171 -0
  182. data/spec/adhearsion/rayo/component/receive_fax_spec.rb +136 -0
  183. data/spec/adhearsion/rayo/component/record_spec.rb +497 -0
  184. data/spec/adhearsion/rayo/component/send_fax_spec.rb +144 -0
  185. data/spec/adhearsion/rayo/connection/asterisk_spec.rb +118 -0
  186. data/spec/adhearsion/rayo/connection/xmpp_spec.rb +449 -0
  187. data/spec/adhearsion/rayo/initializer_spec.rb +353 -0
  188. data/spec/adhearsion/rayo/ref_spec.rb +168 -0
  189. data/spec/adhearsion/rayo_spec.rb +7 -0
  190. data/spec/adhearsion/router/route_spec.rb +1 -1
  191. data/spec/adhearsion/statistics_spec.rb +2 -5
  192. data/spec/adhearsion/translator/asterisk/call_spec.rb +2047 -0
  193. data/spec/adhearsion/translator/asterisk/component/asterisk/agi_command_spec.rb +256 -0
  194. data/spec/adhearsion/translator/asterisk/component/asterisk/ami_action_spec.rb +151 -0
  195. data/spec/adhearsion/translator/asterisk/component/composed_prompt_spec.rb +257 -0
  196. data/spec/adhearsion/translator/asterisk/component/input_spec.rb +571 -0
  197. data/spec/adhearsion/translator/asterisk/component/mrcp_native_prompt_spec.rb +774 -0
  198. data/spec/adhearsion/translator/asterisk/component/mrcp_prompt_spec.rb +1244 -0
  199. data/spec/adhearsion/translator/asterisk/component/output_spec.rb +1850 -0
  200. data/spec/adhearsion/translator/asterisk/component/record_spec.rb +426 -0
  201. data/spec/adhearsion/translator/asterisk/component/stop_by_redirect_spec.rb +62 -0
  202. data/spec/adhearsion/translator/asterisk/component_spec.rb +83 -0
  203. data/spec/adhearsion/translator/asterisk_spec.rb +685 -0
  204. data/spec/adhearsion/uri_list_spec.rb +88 -0
  205. data/spec/adhearsion_spec.rb +89 -14
  206. data/spec/fixtures/locale/en.yml +13 -0
  207. data/spec/fixtures/locale/it.yml +13 -0
  208. data/spec/spec_helper.rb +18 -5
  209. data/spec/support/call_controller_test_helpers.rb +3 -2
  210. data/spec/support/initializer_stubs.rb +3 -1
  211. data/spec/support/punchblock_examples.rb +65 -0
  212. data/spec/support/punchblock_mocks.rb +12 -0
  213. metadata +412 -70
  214. data/features/cli_daemon.feature +0 -20
  215. data/features/cli_restart.feature +0 -52
  216. data/features/cli_stop.feature +0 -50
  217. data/lib/adhearsion/call_controller/menu_dsl.rb +0 -21
  218. data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +0 -26
  219. data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +0 -43
  220. data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +0 -45
  221. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +0 -11
  222. data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +0 -40
  223. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +0 -207
  224. data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +0 -92
  225. data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +0 -60
  226. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +0 -25
  227. data/lib/adhearsion/call_controller/utility.rb +0 -77
  228. data/lib/adhearsion/foundation/custom_daemonizer.rb +0 -52
  229. data/lib/adhearsion/punchblock_plugin.rb +0 -63
  230. data/scripts/cloc-1.64.pl +0 -10483
  231. data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +0 -76
  232. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +0 -60
  233. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +0 -61
  234. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +0 -39
  235. data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +0 -17
  236. data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +0 -165
  237. data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +0 -420
  238. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +0 -32
  239. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +0 -40
  240. data/spec/adhearsion/call_controller/utility_spec.rb +0 -90
  241. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +0 -356
  242. data/spec/adhearsion/punchblock_plugin_spec.rb +0 -59
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ module Translator
5
+ class Asterisk
6
+ module Component
7
+ class Component
8
+ attr_reader :id, :call, :call_id
9
+
10
+ def initialize(component_node, call = nil)
11
+ @component_node, @call = component_node, call
12
+ @call_id = call.id if call
13
+ @id = Adhearsion.new_uuid
14
+ @complete = false
15
+ setup
16
+ end
17
+
18
+ def setup
19
+ end
20
+
21
+ def execute_command(command)
22
+ command.response = Adhearsion::ProtocolError.new.setup 'command-not-acceptable', "Did not understand command for component #{id}", call_id, id
23
+ end
24
+
25
+ def send_complete_event(reason, recording = nil)
26
+ return if @complete
27
+ @complete = true
28
+ event = Adhearsion::Event::Complete.new reason: reason, recording: recording
29
+ send_event event
30
+ call.deregister_component id if call
31
+ end
32
+
33
+ def send_event(event)
34
+ event.component_id = id
35
+ event.target_call_id = call_id
36
+ event.source_uri = id
37
+ translator.handle_pb_event event
38
+ end
39
+
40
+ def logger_id
41
+ "#{self.class}: #{call_id ? "Call ID: #{call_id}, Component ID: #{id}" : id}"
42
+ end
43
+
44
+ def call_ended
45
+ send_complete_event Adhearsion::Event::Complete::Hangup.new
46
+ end
47
+
48
+ private
49
+
50
+ def translator
51
+ @translator ||= call.translator
52
+ end
53
+
54
+ def ami_client
55
+ translator.ami_client
56
+ end
57
+
58
+ def set_node_response(value)
59
+ @component_node.response = value
60
+ end
61
+
62
+ def send_ref
63
+ set_node_response Adhearsion::Rayo::Ref.new uri: id
64
+ end
65
+
66
+ def with_error(name, text)
67
+ set_node_response Adhearsion::ProtocolError.new.setup(name, text)
68
+ end
69
+
70
+ def complete_with_error(error)
71
+ send_complete_event Adhearsion::Event::Complete::Error.new(details: error)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ %w{
80
+ asterisk
81
+ composed_prompt
82
+ input
83
+ output
84
+ mrcp_prompt
85
+ mrcp_native_prompt
86
+ record
87
+ stop_by_redirect
88
+ }.each { |component| require "adhearsion/translator/asterisk/component/#{component}" }
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ module Translator
5
+ class Asterisk
6
+ module Component
7
+ module Asterisk
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ require 'adhearsion/translator/asterisk/component/asterisk/agi_command'
15
+ require 'adhearsion/translator/asterisk/component/asterisk/ami_action'
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ module Translator
5
+ class Asterisk
6
+ module Component
7
+ module Asterisk
8
+ class AGICommand < Component
9
+ def setup
10
+ @agi = Translator::Asterisk::AGICommand.new id, @call.channel, @component_node.name, *@component_node.params
11
+ end
12
+
13
+ def execute
14
+ @agi.execute ami_client
15
+ send_ref
16
+ rescue RubyAMI::Error
17
+ set_node_response false
18
+ rescue ChannelGoneError
19
+ set_node_response Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id)
20
+ end
21
+
22
+ def handle_ami_event(event)
23
+ if (event.name == 'AsyncAGI' && event['SubEvent'] == 'Exec') || event.name == 'AsyncAGIExec'
24
+ send_complete_event success_reason(event)
25
+ if @component_node.name == 'ASYNCAGI BREAK' && @call.channel_var('ADHEARSION_END_ON_ASYNCAGI_BREAK')
26
+ @call.handle_hangup_event nil, event.best_time
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def success_reason(event)
34
+ result = @agi.parse_result event
35
+ Adhearsion::Rayo::Component::Asterisk::AGI::Command::Complete::Success.new result
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ module Translator
5
+ class Asterisk
6
+ module Component
7
+ module Asterisk
8
+ class AMIAction < Component
9
+ attr_reader :translator
10
+
11
+ def initialize(component_node, translator, ami_client)
12
+ super component_node, nil
13
+ @translator, @ami_client = translator, ami_client
14
+ end
15
+
16
+ def execute
17
+ send_ref
18
+ response = send_action
19
+ final_event = send_events response
20
+ send_complete_event success_reason(response, final_event)
21
+ rescue RubyAMI::Error => e
22
+ send_complete_event error_reason(e)
23
+ end
24
+
25
+ private
26
+
27
+ def send_action
28
+ @ami_client.send_action @component_node.name, action_headers
29
+ end
30
+
31
+ def error_reason(response)
32
+ Adhearsion::Event::Complete::Error.new details: response.message
33
+ end
34
+
35
+ def success_reason(response, final_event = nil)
36
+ headers = response.headers
37
+ headers.merge! final_event.headers if final_event
38
+ headers.delete 'ActionID'
39
+ Adhearsion::Rayo::Component::Asterisk::AMI::Action::Complete::Success.new message: headers.delete('Message'), text_body: response.text_body, headers: headers
40
+ end
41
+
42
+ def send_events(response)
43
+ final_event = response.events.pop
44
+ response.events.each do |e|
45
+ send_event pb_event_from_ami_event(e)
46
+ end
47
+ final_event
48
+ end
49
+
50
+ def pb_event_from_ami_event(ami_event)
51
+ headers = ami_event.headers
52
+ headers.delete 'ActionID'
53
+ Adhearsion::Event::Asterisk::AMI.new name: ami_event.name, headers: headers
54
+ end
55
+
56
+ def action_headers
57
+ headers = {}
58
+ @component_node.params.each_pair do |key, value|
59
+ headers[key.to_s.capitalize] = value
60
+ end
61
+ headers
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ require 'adhearsion/translator/asterisk/component/input_component'
4
+ require 'adhearsion/translator/asterisk/component/stop_by_redirect'
5
+
6
+ module Adhearsion
7
+ module Translator
8
+ class Asterisk
9
+ module Component
10
+ class ComposedPrompt < Component
11
+ include InputComponent
12
+ include StopByRedirect
13
+
14
+ def execute
15
+ validate
16
+ output_command.request!
17
+ setup_dtmf_recognizer
18
+
19
+ @output_incomplete = true
20
+
21
+ @output_component = Output.new(output_command, @call)
22
+ call.register_component @output_component
23
+ fut = Celluloid::Future.new { @output_component.execute }
24
+
25
+ case @output_command.response
26
+ when Adhearsion::Rayo::Ref
27
+ send_ref
28
+ else
29
+ set_node_response @output_command.response
30
+ end
31
+
32
+ if @component_node.barge_in
33
+ @barged = false
34
+ register_dtmf_event_handler
35
+ fut.value # Block until output is complete before starting timers
36
+ @output_incomplete = false
37
+ start_timers unless @barged
38
+ else
39
+ fut.value # Block until output is complete before allowing input
40
+ register_dtmf_event_handler
41
+ start_timers
42
+ end
43
+ end
44
+
45
+ def process_dtmf(digit)
46
+ if @component_node.barge_in && @output_incomplete
47
+ @output_component.stop_by_redirect Adhearsion::Event::Complete::Stop.new
48
+ @barged = true
49
+ end
50
+ super
51
+ end
52
+
53
+ def output_command
54
+ @output_command ||= @component_node.output
55
+ end
56
+
57
+ private
58
+
59
+ def input_node
60
+ @input_node ||= @component_node.input
61
+ end
62
+
63
+ def register_dtmf_event_handler
64
+ @dtmf_handler_id = call.register_handler :ami, [{:name => 'DTMF', [:[], 'End'] => 'Yes'}, {:name => 'DTMFEnd'}] do |event|
65
+ process_dtmf event['Digit']
66
+ end
67
+ end
68
+
69
+ def unregister_dtmf_event_handler
70
+ call.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ruby_speech'
4
+ require 'singleton'
5
+ require 'adhearsion/translator/asterisk/component'
6
+
7
+ module Adhearsion
8
+ module Translator
9
+ class Asterisk
10
+ module Component
11
+ class DTMFRecognizer
12
+ class BuiltinMatcherCache
13
+ include Singleton
14
+ include MonitorMixin
15
+
16
+ def get(uri)
17
+ cache[uri] ||= fetch(uri)
18
+ end
19
+
20
+ private
21
+
22
+ def fetch(uri)
23
+ grammar = RubySpeech::GRXML.from_uri(uri)
24
+ RubySpeech::GRXML::Matcher.new(grammar)
25
+ end
26
+
27
+ def cache
28
+ @cache ||= {}
29
+ end
30
+ end
31
+
32
+ include Celluloid
33
+
34
+ def initialize(responder, grammar, initial_timeout = nil, inter_digit_timeout = nil, terminator = nil)
35
+ @responder = responder
36
+ self.initial_timeout = initial_timeout || -1
37
+ self.inter_digit_timeout = inter_digit_timeout || -1
38
+ @terminator = terminator
39
+ @finished = false
40
+
41
+ @matcher = if grammar.url
42
+ BuiltinMatcherCache.instance.get(grammar.url)
43
+ else
44
+ RubySpeech::GRXML::Matcher.new RubySpeech::GRXML.import(grammar.value.to_s)
45
+ end
46
+ @buffer = ""
47
+ end
48
+
49
+ def <<(digit)
50
+ cancel_initial_timer
51
+ @buffer << digit unless terminating?(digit)
52
+ case (match = get_match)
53
+ when RubySpeech::GRXML::NoMatch
54
+ finalize :nomatch
55
+ when RubySpeech::GRXML::MaxMatch
56
+ finalize :match, match
57
+ when RubySpeech::GRXML::Match
58
+ finalize :match, match if terminating?(digit)
59
+ when RubySpeech::GRXML::PotentialMatch
60
+ finalize :nomatch if terminating?(digit)
61
+ end
62
+ reset_inter_digit_timer unless @finished
63
+ end
64
+
65
+ def start_timers
66
+ begin_initial_timer @initial_timeout/1000 unless @initial_timeout == -1
67
+ end
68
+
69
+ private
70
+
71
+ def terminating?(digit)
72
+ digit == @terminator
73
+ end
74
+
75
+ def get_match
76
+ @matcher.match @buffer.dup
77
+ end
78
+
79
+ def initial_timeout=(other)
80
+ raise OptionError, 'An initial timeout value that is negative (and not -1) is invalid.' if other < -1
81
+ @initial_timeout = other
82
+ end
83
+
84
+ def inter_digit_timeout=(other)
85
+ raise OptionError, 'An inter-digit timeout value that is negative (and not -1) is invalid.' if other < -1
86
+ @inter_digit_timeout = other
87
+ end
88
+
89
+ def begin_initial_timer(timeout)
90
+ @initial_timer = after timeout do
91
+ finalize :noinput
92
+ end
93
+ end
94
+
95
+ def cancel_initial_timer
96
+ return unless instance_variable_defined?(:@initial_timer) && @initial_timer
97
+ @initial_timer.cancel
98
+ @initial_timer = nil
99
+ end
100
+
101
+ def reset_inter_digit_timer
102
+ return if @inter_digit_timeout == -1
103
+ @inter_digit_timer ||= begin
104
+ after @inter_digit_timeout/1000 do
105
+ case (match = get_match)
106
+ when RubySpeech::GRXML::Match
107
+ finalize :match, match
108
+ else
109
+ finalize :nomatch
110
+ end
111
+ end
112
+ end
113
+ @inter_digit_timer.reset
114
+ end
115
+
116
+ def cancel_inter_digit_timer
117
+ return unless instance_variable_defined?(:@inter_digit_timer) && @inter_digit_timer
118
+ @inter_digit_timer.cancel
119
+ @inter_digit_timer = nil
120
+ end
121
+
122
+ def finalize(match_type, match = nil)
123
+ cancel_initial_timer
124
+ cancel_inter_digit_timer
125
+ if match
126
+ @responder.send match_type, match
127
+ else
128
+ @responder.send match_type
129
+ end
130
+ @finished = true
131
+ terminate
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ require 'adhearsion/translator/asterisk/component/input_component'
4
+
5
+ module Adhearsion
6
+ module Translator
7
+ class Asterisk
8
+ module Component
9
+ class Input < Component
10
+
11
+ include InputComponent
12
+
13
+ def execute
14
+ @call.send_progress
15
+ super
16
+ @dtmf_handler_id = register_dtmf_event_handler
17
+ end
18
+
19
+ private
20
+
21
+ def register_dtmf_event_handler
22
+ call.register_handler :ami, [{:name => 'DTMF', [:[], 'End'] => 'Yes'}, {:name => 'DTMFEnd'}] do |event|
23
+ process_dtmf event['Digit']
24
+ end
25
+ end
26
+
27
+ def unregister_dtmf_event_handler
28
+ call.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end