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,44 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ class CallController
5
+ module Input
6
+ class AskGrammarBuilder
7
+ def initialize(options)
8
+ @options = options
9
+ end
10
+
11
+ def grammars
12
+ @grammars ||= build_grammars
13
+ end
14
+
15
+ private
16
+
17
+ def build_grammars
18
+ grammars = []
19
+
20
+ grammars.concat [@options[:grammar]].flatten.compact.map { |val| {value: val} } if @options[:grammar]
21
+ grammars.concat [@options[:grammar_url]].flatten.compact.map { |val| {url: val} } if @options[:grammar_url]
22
+
23
+ if grammars.empty?
24
+ limit = @options[:limit]
25
+ grammar = RubySpeech::GRXML.draw mode: :dtmf, root: 'digits' do
26
+ rule id: 'digits', scope: 'public' do
27
+ item repeat: "0-#{limit}" do
28
+ one_of do
29
+ 0.upto(9) { |d| item { d.to_s } }
30
+ item { "#" }
31
+ item { "*" }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ grammars << {value: grammar}
37
+ end
38
+
39
+ grammars
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,136 @@
1
+ # encoding: utf-8
2
+
3
+ require 'adhearsion/call_controller/input/prompt_builder'
4
+
5
+ module Adhearsion
6
+ class CallController
7
+ module Input
8
+ class MenuBuilder
9
+ def initialize(options, &block)
10
+ @options = options
11
+ @matchers = []
12
+ @callbacks = {}
13
+ build(&block)
14
+ end
15
+
16
+ def match(*args, &block)
17
+ payload = block || args.pop
18
+
19
+ @matchers << Matcher.new(payload, args)
20
+ end
21
+
22
+ def invalid(&block)
23
+ register_user_supplied_callback :nomatch, &block
24
+ end
25
+
26
+ def timeout(&block)
27
+ register_user_supplied_callback :noinput, &block
28
+ end
29
+
30
+ def failure(&block)
31
+ register_user_supplied_callback :failure, &block
32
+ end
33
+
34
+ def execute(output_document, controller)
35
+ catch :match do
36
+ (@options[:tries] || 1).times do
37
+ result = PromptBuilder.new(output_document, grammars, @options).execute(controller)
38
+ process_result result
39
+ end
40
+ execute_hook :failure
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def grammars
47
+ @grammar ||= [{value: build_grammar}]
48
+ end
49
+
50
+ def process_result(result)
51
+ if result.status == :match
52
+ handle_match result
53
+ else
54
+ execute_hook result.status
55
+ end
56
+ end
57
+
58
+ def register_user_supplied_callback(name, &block)
59
+ @callbacks[name] = block
60
+ end
61
+
62
+ def execute_hook(hook_name)
63
+ callback = @callbacks[hook_name]
64
+ return unless callback
65
+ @context.instance_exec(&callback)
66
+ end
67
+
68
+ def handle_match(result)
69
+ match = @matchers[result.interpretation.to_i]
70
+ match.dispatch @context, result.utterance
71
+ throw :match
72
+ end
73
+
74
+ def build(&block)
75
+ @context = eval "self", block.binding
76
+ instance_eval(&block)
77
+ end
78
+
79
+ def method_missing(method_name, *args, &block)
80
+ if @context
81
+ @context.send method_name, *args, &block
82
+ else
83
+ super
84
+ end
85
+ end
86
+
87
+ def build_grammar
88
+ raise ArgumentError, "You must specify one or more matches." if @matchers.count < 1
89
+ matchers = @matchers
90
+
91
+ RubySpeech::GRXML.draw mode: (@options[:mode] || :dtmf), root: 'options', tag_format: 'semantics/1.0-literals' do
92
+ rule id: 'options', scope: 'public' do
93
+ item do
94
+ one_of do
95
+ matchers.each_with_index do |matcher, index|
96
+ item do
97
+ tag { index.to_s }
98
+ matcher.apply_to_grammar self
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ Matcher = Struct.new(:payload, :keys) do
108
+ def dispatch(controller, utterance)
109
+ if payload.is_a?(Proc)
110
+ controller.instance_exec utterance, &payload
111
+ else
112
+ controller.invoke payload, extension: utterance
113
+ end
114
+ end
115
+
116
+ def apply_to_grammar(grammar)
117
+ possible_options = calculate_possible_options
118
+ if possible_options.count > 1
119
+ grammar.one_of do
120
+ possible_options.each do |key|
121
+ item { key.to_s }
122
+ end
123
+ end
124
+ else
125
+ keys.first.to_s
126
+ end
127
+ end
128
+
129
+ def calculate_possible_options
130
+ keys.map { |key| key.respond_to?(:to_a) ? key.to_a : key }.flatten
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+
3
+ require 'adhearsion/call_controller/input/result'
4
+
5
+ module Adhearsion
6
+ class CallController
7
+ module Input
8
+ class PromptBuilder
9
+ def initialize(output_document, grammars, options)
10
+ input_options = {
11
+ mode: options[:mode] || :dtmf,
12
+ initial_timeout: timeout(options[:timeout] || Adhearsion.config.core.media.timeout),
13
+ inter_digit_timeout: timeout(options[:inter_digit_timeout] || Adhearsion.config.core.media.inter_digit_timeout),
14
+ max_silence: timeout(options[:timeout] || Adhearsion.config.core.media.timeout),
15
+ min_confidence: Adhearsion.config.core.media.min_confidence,
16
+ grammars: grammars,
17
+ recognizer: Adhearsion.config.core.media.recognizer,
18
+ language: Adhearsion.config.core.media.input_language,
19
+ terminator: options[:terminator]
20
+ }.merge(options[:input_options] || {})
21
+
22
+ @prompt = if output_document || options[:render_document]
23
+ output_options = {
24
+ render_document: options[:render_document] || {value: output_document},
25
+ renderer: Adhearsion.config.core.media.default_renderer,
26
+ voice: Adhearsion.config.core.media.default_voice
27
+ }.merge(options[:output_options] || {})
28
+
29
+ Adhearsion::Rayo::Component::Prompt.new output_options, input_options, barge_in: options.has_key?(:interruptible) ? options[:interruptible] : true
30
+ else
31
+ Adhearsion::Rayo::Component::Input.new input_options
32
+ end
33
+ end
34
+
35
+ def execute(controller)
36
+ controller.execute_component_and_await_completion @prompt
37
+
38
+ result @prompt.complete_event.reason
39
+ rescue Adhearsion::Call::ExpiredError
40
+ raise Adhearsion::Call::Hangup
41
+ end
42
+
43
+ private
44
+
45
+ def result(reason)
46
+ Result.new.tap do |result|
47
+ case reason
48
+ when proc { |r| r.respond_to? :nlsml }
49
+ result.status = :match
50
+ result.mode = reason.mode
51
+ result.confidence = reason.confidence
52
+ result.utterance = reason.utterance
53
+ result.interpretation = reason.interpretation
54
+ result.nlsml = reason.nlsml
55
+ when Adhearsion::Event::Complete::Error
56
+ raise InputError, reason.details
57
+ when Adhearsion::Rayo::Component::Input::Complete::NoMatch
58
+ result.status = :nomatch
59
+ when Adhearsion::Rayo::Component::Input::Complete::NoInput
60
+ result.status = :noinput
61
+ when Adhearsion::Event::Complete::Hangup
62
+ result.status = :hangup
63
+ when Adhearsion::Event::Complete::Stop
64
+ result.status = :stop
65
+ else
66
+ raise "Unknown completion reason received: #{reason}"
67
+ end
68
+ logger.debug "Ask completed with result #{result.inspect}"
69
+ end
70
+ end
71
+
72
+ def timeout(value)
73
+ value > 0 ? value * 1000 : value
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ class CallController
5
+ module Input
6
+ Result = Struct.new(:status, :mode, :confidence, :utterance, :interpretation, :nlsml) do
7
+ def to_s
8
+ utterance
9
+ end
10
+
11
+ def inspect
12
+ "#<#{self.class} status=#{status.inspect}, confidence=#{confidence.inspect}, utterance=#{utterance.inspect}, interpretation=#{interpretation.inspect}, nlsml=#{nlsml.inspect}>"
13
+ end
14
+
15
+ def utterance=(other)
16
+ self[:utterance] = mode == :dtmf ? parse_dtmf(other) : other
17
+ end
18
+
19
+ def match?
20
+ status == :match
21
+ end
22
+
23
+ private
24
+
25
+ def parse_dtmf(dtmf)
26
+ return if dtmf.nil? || dtmf.empty?
27
+ dtmf.split(' ').inject '' do |final, digit|
28
+ final << parse_dtmf_digit(digit)
29
+ end
30
+ end
31
+
32
+ # @private
33
+ def parse_dtmf_digit(digit)
34
+ case tone = digit.split('-').last
35
+ when 'star'
36
+ '*'
37
+ when 'pound'
38
+ '#'
39
+ else
40
+ tone
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require 'uri'
3
+ require 'i18n'
3
4
 
4
5
  %w(
5
6
  abstract_player
@@ -18,7 +19,7 @@ module Adhearsion
18
19
  # Speak output using text-to-speech (TTS)
19
20
  #
20
21
  # @param [String, #to_s] text The text to be rendered
21
- # @param [Hash] options A set of options for output. Includes everything in Punchblock::Component::Output.new.
22
+ # @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
22
23
  #
23
24
  # @raise [PlaybackError] if the given argument could not be played
24
25
  #
@@ -32,7 +33,7 @@ module Adhearsion
32
33
  # Speak output using text-to-speech (TTS) and return as soon as it begins
33
34
  #
34
35
  # @param [String, #to_s] text The text to be rendered
35
- # @param [Hash] options A set of options for output. Includes everything in Punchblock::Component::Output.new.
36
+ # @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
36
37
  #
37
38
  # @raise [PlaybackError] if the given argument could not be played
38
39
  #
@@ -49,7 +50,7 @@ module Adhearsion
49
50
  # say_characters('abc123')
50
51
  #
51
52
  # @param [String, #to_s] characters The string of characters to be spoken
52
- # @param [Hash] options A set of options for output. Includes everything in Punchblock::Component::Output.new.
53
+ # @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
53
54
  #
54
55
  # @raise [PlaybackError] if the given argument could not be played
55
56
  #
@@ -64,7 +65,7 @@ module Adhearsion
64
65
  # say_characters!('abc123')
65
66
  #
66
67
  # @param [String, #to_s] characters The string of characters to be spoken
67
- # @param [Hash] options A set of options for output. Includes everything in Punchblock::Component::Output.new.
68
+ # @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
68
69
  #
69
70
  # @raise [PlaybackError] if the given argument could not be played
70
71
  #
@@ -79,7 +80,7 @@ module Adhearsion
79
80
  # additional options. See play_time for more information.
80
81
  #
81
82
  # @param [Array<String, Fixnum, Time, Date>, String, Fixnum, Time, Date] outputs A collection of outputs to render.
82
- # @param [Hash] options A set of options for output. Includes everything in Punchblock::Component::Output.new.
83
+ # @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
83
84
  #
84
85
  # @example Play file hello-world
85
86
  # play 'http://www.example.com/hello-world.mp3'
@@ -113,7 +114,7 @@ module Adhearsion
113
114
  # additional options. See play_time for more information.
114
115
  #
115
116
  # @param [Array<String, Fixnum, Time, Date>, String, Fixnum, Time, Date] outputs A collection of outputs to render.
116
- # @param [Hash] options A set of options for output. Includes everything in Punchblock::Component::Output.new.
117
+ # @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
117
118
  #
118
119
  # @example Play file hello-world
119
120
  # play 'http://www.example.com/hello-world.mp3'
@@ -130,7 +131,7 @@ module Adhearsion
130
131
  # play "/path/to/you-sound-cute.mp3", "/path/to/what-are-you-wearing.wav"
131
132
  #
132
133
  # @raise [PlaybackError] if (one of) the given argument(s) could not be played
133
- # @return [Punchblock::Component::Output]
134
+ # @return [Adhearsion::Rayo::Component::Output]
134
135
  #
135
136
  def play!(*outputs, options)
136
137
  options = process_output_options outputs, options
@@ -143,10 +144,9 @@ module Adhearsion
143
144
  #
144
145
  # Plays the given audio file.
145
146
  # SSML supports http:// paths and full disk paths.
146
- # The Punchblock backend will have to handle cases like Asterisk where there is a fixed sounds directory.
147
147
  #
148
148
  # @param [String] file http:// URL or full disk path to the sound file
149
- # @param [Hash] options Additional options Includes everything in Punchblock::Component::Output.new.
149
+ # @param [Hash] options Additional options Includes everything in Adhearsion::Rayo::Component::Output.new.
150
150
  # @option options [String] :fallback The text to play if the file is not available
151
151
  #
152
152
  # @raise [PlaybackError] if (one of) the given argument(s) could not be played
@@ -159,14 +159,13 @@ module Adhearsion
159
159
  #
160
160
  # Plays the given audio file and returns as soon as it begins.
161
161
  # SSML supports http:// paths and full disk paths.
162
- # The Punchblock backend will have to handle cases like Asterisk where there is a fixed sounds directory.
163
162
  #
164
163
  # @param [String] file http:// URL or full disk path to the sound file
165
- # @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Punchblock::Component::Output.new.
164
+ # @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Adhearsion::Rayo::Component::Output.new.
166
165
  # @option options [String] :fallback The text to play if the file is not available
167
166
  #
168
167
  # @raise [PlaybackError] if (one of) the given argument(s) could not be played
169
- # @return [Punchblock::Component::Output]
168
+ # @return [Adhearsion::Rayo::Component::Output]
170
169
  #
171
170
  def play_audio!(file, options = {})
172
171
  async_player.play_ssml(output_formatter.ssml_for_audio(file, options), options)
@@ -177,7 +176,7 @@ module Adhearsion
177
176
  # using the given timezone and format.
178
177
  #
179
178
  # @param [Date, Time, DateTime] time Time to be said.
180
- # @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Punchblock::Component::Output.new.
179
+ # @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Adhearsion::Rayo::Component::Output.new.
181
180
  # @option options [String] :format This format is used only to disambiguate times that could be interpreted in different ways.
182
181
  # For example, 01/06/2011 could mean either the 1st of June or the 6th of January.
183
182
  # Please refer to the SSML specification.
@@ -198,7 +197,7 @@ module Adhearsion
198
197
  # using the given timezone and format and returns as soon as it begins.
199
198
  #
200
199
  # @param [Date, Time, DateTime] time Time to be said.
201
- # @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Punchblock::Component::Output.new.
200
+ # @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Adhearsion::Rayo::Component::Output.new.
202
201
  # @option options [String] :format This format is used only to disambiguate times that could be interpreted in different ways.
203
202
  # For example, 01/06/2011 could mean either the 1st of June or the 6th of January.
204
203
  # Please refer to the SSML specification.
@@ -207,7 +206,7 @@ module Adhearsion
207
206
  # It uses Time::strftime symbols.
208
207
  #
209
208
  # @raise [ArgumentError] if the given argument can not be played
210
- # @return [Punchblock::Component::Output]
209
+ # @return [Adhearsion::Rayo::Component::Output]
211
210
  #
212
211
  def play_time!(time, options = {})
213
212
  raise ArgumentError unless [Date, Time, DateTime].include?(time.class) && options.is_a?(Hash)
@@ -220,7 +219,7 @@ module Adhearsion
220
219
  # is pronounced as "one hundred" instead of "one zero zero".
221
220
  #
222
221
  # @param [Numeric, String] number Numeric or String containing a valid Numeric, like "321".
223
- # @param [Hash] options A set of options for output. See Punchblock::Component::Output.new for details.
222
+ # @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
224
223
  #
225
224
  # @raise [ArgumentError] if the given argument can not be played
226
225
  #
@@ -236,10 +235,10 @@ module Adhearsion
236
235
  # is pronounced as "one hundred" instead of "one zero zero".
237
236
  #
238
237
  # @param [Numeric, String] number Numeric or String containing a valid Numeric, like "321".
239
- # @param [Hash] options A set of options for output. See Punchblock::Component::Output.new for details.
238
+ # @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
240
239
  #
241
240
  # @raise [ArgumentError] if the given argument can not be played
242
- # @return [Punchblock::Component::Output]
241
+ # @return [Adhearsion::Rayo::Component::Output]
243
242
  #
244
243
  def play_numeric!(number, options = {})
245
244
  raise ArgumentError unless number.kind_of?(Numeric) || number =~ /^\d+$/
@@ -250,7 +249,7 @@ module Adhearsion
250
249
  # Plays the given SSML document from a URL.
251
250
  #
252
251
  # @param [String] url String containing a valid URL, like "http://example.com/document.ssml".
253
- # @param [Hash] options A set of options for output. See Punchblock::Component::Output.new for details.
252
+ # @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
254
253
  #
255
254
  # @raise [ArgumentError] if the given argument can not be played
256
255
  #
@@ -264,68 +263,50 @@ module Adhearsion
264
263
  # Plays the given SSML document from a URL and returns as soon as it begins.
265
264
  #
266
265
  # @param [String] url String containing a valid URL, like "http://example.com/document.ssml".
267
- # @param [Hash] options A set of options for output. See Punchblock::Component::Output.new for details.
266
+ # @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
268
267
  #
269
268
  # @raise [ArgumentError] if the given argument can not be played
270
- # @return [Punchblock::Component::Output]
269
+ # @return [Adhearsion::Rayo::Component::Output]
271
270
  #
272
271
  def play_document!(url, options = {})
273
272
  raise ArgumentError unless url =~ URI::regexp
274
273
  async_player.play_url url, options
275
274
  end
276
275
 
277
- #
278
- # Plays the given output, allowing for DTMF input of a single digit from the user
279
- # At the end of the played file it returns nil
280
- #
281
- # @example Ask the user for a number, then play it back
282
- # ssml = RubySpeech::SSML.draw do
283
- # "Please press a button"
284
- # end
285
- # input = interruptible_play ssml
286
- # play input unless input.nil?
287
- #
288
- # @param [String, Numeric, Date, Time, RubySpeech::SSML::Speak, Array, Hash] outputs The argument to play to the user, or an array of arguments.
289
- # @param [Hash] options Additional options.
290
- #
291
- # @return [String, nil] The single DTMF character entered by the user, or nil if nothing was entered
292
- # @raise [PlaybackError] if (one of) the given argument(s) could not be played
293
- #
294
- def interruptible_play(*outputs, options)
295
- options = process_output_options outputs, options
296
- outputs.find do |output|
297
- digit = stream_file output, '0123456789#*', options
298
- return digit if digit
276
+ def t(key, options = {})
277
+ this_locale = options[:locale] || locale
278
+ options = {default: '', locale: locale}.merge(options)
279
+ prompt = ::I18n.t "#{key}.audio", options
280
+ text = ::I18n.t "#{key}.text", options
281
+
282
+ if prompt.empty? && text.empty?
283
+ # Look for a translation key that doesn't follow the Adhearsion-I18n structure
284
+ text = ::I18n.t key, options
299
285
  end
300
- end
301
286
 
302
- #
303
- # Plays a single output, not only files, accepting interruption by one of the digits specified
304
- #
305
- # @param [Object] argument String or Hash specifying output and options
306
- # @param [String] digits String with the digits that are allowed to interrupt output
307
- #
308
- # @return [String, nil] The pressed digit, or nil if nothing was pressed
309
- # @private
310
- #
311
- def stream_file(argument, digits = '0123456789#*', output_options = {})
312
- result = nil
313
- stopper = Punchblock::Component::Input.new :mode => :dtmf,
314
- :grammar => {
315
- :value => grammar_accept(digits)
316
- }
287
+ unless prompt.empty?
288
+ prompt = "file://#{Adhearsion.root + "/" unless Adhearsion.config.core.i18n.audio_path.start_with?("/")}#{Adhearsion.config.core.i18n.audio_path}/#{this_locale}/#{prompt}"
289
+ end
317
290
 
318
- player.output output_formatter.ssml_for(argument), output_options do |output_component|
319
- stopper.register_event_handler Punchblock::Event::Complete do |event|
320
- output_component.stop! unless output_component.complete?
291
+ RubySpeech::SSML.draw language: this_locale do
292
+ if prompt.empty?
293
+ string text
294
+ else
295
+ if Adhearsion.config.core.i18n.fallback
296
+ audio(src: prompt) { string text }
297
+ else
298
+ audio(src: prompt)
299
+ end
321
300
  end
322
- write_and_await_response stopper
323
301
  end
302
+ end
303
+
304
+ def locale
305
+ call[:locale] || I18n.default_locale
306
+ end
324
307
 
325
- stopper.stop! if stopper.executing?
326
- reason = stopper.complete_event.reason
327
- result = reason.respond_to?(:utterance) ? reason.utterance : nil
328
- parse_dtmf result
308
+ def locale=(l)
309
+ call[:locale] = l
329
310
  end
330
311
 
331
312
  # @private