adhearsion_cpa 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +20 -0
- data/README.md +127 -0
- data/Rakefile +10 -0
- data/adhearsion_cpa.gemspec +29 -0
- data/lib/adhearsion_cpa.rb +6 -0
- data/lib/adhearsion_cpa/controller_methods.rb +33 -0
- data/lib/adhearsion_cpa/plugin.rb +15 -0
- data/lib/adhearsion_cpa/tone_detector.rb +93 -0
- data/lib/adhearsion_cpa/version.rb +3 -0
- data/spec/adhearsion_cpa/controller_methods_spec.rb +138 -0
- data/spec/spec_helper.rb +21 -0
- metadata +175 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 78576498fddf76d14a2756d853529647a08bc674
|
4
|
+
data.tar.gz: 01259071cfe35b2c4daa379e5e61dcdf569019a7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ac156ed89e74dd1a0d1bed7a8ff5e09aace7226596ce73d554d39f27694190c636fa40716ab9e5f465a28bb621654b2cd61e77f11811c5405db84014b179109c
|
7
|
+
data.tar.gz: 28a92b969d343b08517ab4194cd0d30e64e1b53347df14332123345e42977342e79bb016f4f2e1ac95a5d7ca3bdfe5b04459301a3dce614f9da1260be73f58a2
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (C) 2013 Adhearsion Foundation Inc
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# Adhearsion-CPA [![Build Status](https://secure.travis-ci.org/grasshoppergroup/adhearsion-cpa.png?branch=master)](http://travis-ci.org/grasshoppergroup/adhearsion-cpa) [![Coverage Status](https://coveralls.io/repos/grasshoppergroup/adhearsion-cpa/badge.png?branch=master)](https://coveralls.io/r/grasshoppergroup/adhearsion-cpa?branch=master) [![Code Climate](https://codeclimate.com/github/grasshoppergroup/adhearsion-cpa.png)](https://codeclimate.com/github/grasshoppergroup/adhearsion-cpa)
|
2
|
+
|
3
|
+
This plugin aims to provide CPA detection..
|
4
|
+
|
5
|
+
## Compatibility
|
6
|
+
|
7
|
+
* Asterisk - no
|
8
|
+
* Freeswitch with Event Socket - no
|
9
|
+
* Freeswitch with [mod_rayo](https://wiki.freeswitch.org/wiki/Mod_rayo) - yes
|
10
|
+
|
11
|
+
## Requirements
|
12
|
+
|
13
|
+
* [Punchblock](https://github.com/adhearsion/punchblock) 2.21 or greater
|
14
|
+
* [Adhearsion](https://github.com/adhearsion/adhearsion)'s current [develop](https://github.com/adhearsion/adhearsion/tree/develop) branch
|
15
|
+
* Recent build of Freeswitch
|
16
|
+
* Recent build of Mod_rayo that includes CPA support
|
17
|
+
* Any modules needed for detection
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Supported detectors
|
22
|
+
|
23
|
+
- `beep` - Detect a beep.
|
24
|
+
- `dtmf` - Detect DTMF tones.
|
25
|
+
- `vad` - Detect voice activity.
|
26
|
+
- `speech` - Detect speech and decide human or machine.
|
27
|
+
- `fax-ced` - Detect a fax CED tone.
|
28
|
+
- `fax-cng` - Detect a fax CNG tone.
|
29
|
+
- `ring` - Detect a ringing tone.
|
30
|
+
- `busy` - Detect a busy tone.
|
31
|
+
- `congestion` - Detect a congestion tone.
|
32
|
+
- `sit` - Detect a Special Information Tone.
|
33
|
+
- `modem` - Detect a modem tone.
|
34
|
+
- `offhook` - Detect an off-hook tone.
|
35
|
+
|
36
|
+
All detectors require the appropiate modules loaded in Freeswitch, and configured in rayo.conf.xml.
|
37
|
+
|
38
|
+
### Basic
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class BeepOrNoBeepController < Adhearsion::CallController
|
42
|
+
def run
|
43
|
+
answer
|
44
|
+
say "Try to beep like a machine"
|
45
|
+
tone = detect_tone(:beep, timeout: 5)
|
46
|
+
if tone
|
47
|
+
say "Good job! You sound just like a #{tone.type}"
|
48
|
+
else
|
49
|
+
say "Nope, you didn't make a convincing enough beep"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
You can also watch for more than one tone type:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
say "Something is beeping" if detect_tone(:modem, :beep, timeout: 5)
|
59
|
+
```
|
60
|
+
|
61
|
+
Some detection types let you pass extra options:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
detect_tone :speech, maxTime: 4000, minSpeechDuration: 4000, timeout: 5
|
65
|
+
```
|
66
|
+
|
67
|
+
#### Fax Detection
|
68
|
+
|
69
|
+
For fax machines, you can either watch for `fax-ced` or `fax-cng`, but not both.
|
70
|
+
|
71
|
+
### Asynchronous detection
|
72
|
+
|
73
|
+
You can also call a bang version of `#detect_tone!`, which will run the detectors in a non-blocking fashion, and execute the passed block when detection occurs:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
|
77
|
+
# Start playing a message right away, so Real Humans don't have to wait
|
78
|
+
@sound = play_sound! "/foo/message.wav"
|
79
|
+
|
80
|
+
# But quit wasting a channel if we hear dialup noises
|
81
|
+
detect_tone! :modem do |tone|
|
82
|
+
logger.info "Call detected a tone"
|
83
|
+
@sound.stop!
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
#### Once or repeat
|
88
|
+
|
89
|
+
By default, the block will only be executed the first time the signal type is detected, and the detector will quit listening. If you'd prefer the block to fire every time the signal is detected, you can pass `:terminate => false` in the options hash:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
detector = detect_tone! :dtmf, terminate: false do |tone|
|
93
|
+
logger.info "Callee pushed #{tone.value}"
|
94
|
+
if tone.value == "#"
|
95
|
+
detector.stop!
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
## More Information
|
101
|
+
|
102
|
+
* [XEP-0341: Rayo CPA](http://xmpp.org/extensions/xep-0341.html)
|
103
|
+
* [Mod_rayo CPA Documentation](https://wiki.freeswitch.org/wiki/Mod_rayo#call_progress_analysis_settings)
|
104
|
+
|
105
|
+
## Credits
|
106
|
+
|
107
|
+
* Original author: [Justin Aiken](https://github.com/JustinAiken)
|
108
|
+
* Developed by [Mojo Lingo](http://mojolingo.com) in partnership with [Grasshopper](http://http://grasshopper.com/).
|
109
|
+
* Thanks to [Grasshopper](http://http://grasshopper.com/) for sponsorship of Adhearsion-CPA.
|
110
|
+
|
111
|
+
## Links
|
112
|
+
|
113
|
+
* [Source](https://github.com/grasshoppergroup/adhearsion-cpa)
|
114
|
+
* [Bug Tracker](https://github.com/grasshoppergroup/adhearsion-cpa/issues)
|
115
|
+
|
116
|
+
## Note on Patches/Pull Requests
|
117
|
+
|
118
|
+
* Fork the project.
|
119
|
+
* Make your feature addition or bug fix.
|
120
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
121
|
+
* Commit, do not mess with rakefile, version, or history.
|
122
|
+
* If you want to have your own version, that is fine but bump version in a commit by itself so I can ignore when I pull
|
123
|
+
* Send me a pull request. Bonus points for topic branches.
|
124
|
+
|
125
|
+
## Copyright
|
126
|
+
|
127
|
+
Copyright (c) 2013 Adhearsion Foundation Inc. MIT license (see LICENSE for details).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "adhearsion_cpa/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "adhearsion_cpa"
|
7
|
+
s.version = AdhearsionCpa::VERSION
|
8
|
+
s.authors = ["Justin Aiken"]
|
9
|
+
s.email = ["60tonangel@gmail.com"]
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.homepage = "https://github.com/grasshoppergroup/adhearsion-cpa"
|
12
|
+
s.summary = %q{A plugin for adding cpa to Adhearsion}
|
13
|
+
s.description = %q{A plugin for adding cpa to Adhearsion}
|
14
|
+
|
15
|
+
s.rubyforge_project = "adhearsion_cpa"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
|
20
|
+
s.add_runtime_dependency %q<adhearsion>, ["~> 2.4"]
|
21
|
+
s.add_runtime_dependency %q<punchblock>, [">= 2.2.1"]
|
22
|
+
s.add_runtime_dependency %q<activesupport>, [">= 3.0.10"]
|
23
|
+
|
24
|
+
s.add_development_dependency %q<coveralls>, ['>= 0']
|
25
|
+
s.add_development_dependency %q<bundler>, ["~> 1.0"]
|
26
|
+
s.add_development_dependency %q<rspec>, ["~> 2.5"]
|
27
|
+
s.add_development_dependency %q<rake>, [">= 0"]
|
28
|
+
s.add_development_dependency %q<guard-rspec>
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module AdhearsionCpa
|
2
|
+
module ControllerMethods
|
3
|
+
|
4
|
+
# Detects a tone
|
5
|
+
#
|
6
|
+
# @example Wait 5 seconds to detect a fax tone
|
7
|
+
# detect_tone "fax-cng", timeout: 5
|
8
|
+
# @example Check for multiple tone types
|
9
|
+
# detect_tone "fax-ced", :modem, timeout: 5
|
10
|
+
# @example Check for a type, with options
|
11
|
+
# detect_tone :speech, maxTime: 4000, minSpeechDuration: 4000, timeout: 5
|
12
|
+
# @example Check for a type, with options, and another type without
|
13
|
+
# detect_tone({:dtmf => {}, speech: {maxTime: 4000, minSpeechDuration: 4000}}, timeout: 5)
|
14
|
+
#
|
15
|
+
# @return [PunchBlock::Signal] if one of the requested tones was detected
|
16
|
+
# @return [nil] if none of the requested tones were detected in time
|
17
|
+
#
|
18
|
+
def detect_tone(*arguments)
|
19
|
+
options = arguments.last.is_a?(Hash) && arguments.count > 1 ? arguments.pop : {}
|
20
|
+
ToneDetector.new(self).detect_tones arguments, options
|
21
|
+
end
|
22
|
+
|
23
|
+
# Begin asynchronous tone detection, and run the block when the tone is detected
|
24
|
+
#
|
25
|
+
# @example Asynchronous wait for a dtmf
|
26
|
+
# detect_tone :dtmf, timeout: -1 { |detected| logger.info "Beep! Customer pushed #{detected.inspect}"}
|
27
|
+
# @example Asynchronous wait for dtmf presses, running the block multiple times if multiple signals are detected
|
28
|
+
def detect_tone!(*arguments)
|
29
|
+
options = arguments.last.is_a?(Hash) && arguments.count > 1 ? arguments.pop : {}
|
30
|
+
ToneDetector.new(self).detect_tones arguments, options.merge(async: true), &Proc.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AdhearsionCpa
|
2
|
+
class Plugin < Adhearsion::Plugin
|
3
|
+
|
4
|
+
init :adhearsion_cpa do
|
5
|
+
Adhearsion::CallController.class_eval do
|
6
|
+
include AdhearsionCpa::ControllerMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
logger.info "Adhearsion-CPA has been loaded"
|
10
|
+
end
|
11
|
+
|
12
|
+
config :adhearsion_cpa do
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module AdhearsionCpa
|
2
|
+
class ToneDetector
|
3
|
+
|
4
|
+
attr_accessor :tones, :timeout
|
5
|
+
|
6
|
+
def initialize(controller)
|
7
|
+
@controller = controller
|
8
|
+
end
|
9
|
+
|
10
|
+
def detect_tones(tones, options)
|
11
|
+
@tones = tones
|
12
|
+
process options
|
13
|
+
|
14
|
+
component.register_event_handler Punchblock::Component::Input::Signal do |event|
|
15
|
+
yield event if block_given?
|
16
|
+
end if async?
|
17
|
+
|
18
|
+
call.write_and_await_response component if call_alive?
|
19
|
+
|
20
|
+
if async?
|
21
|
+
call.after(timeout) do
|
22
|
+
if component_running?
|
23
|
+
component.stop!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
component
|
28
|
+
else
|
29
|
+
component.complete_event(timeout).reason
|
30
|
+
end
|
31
|
+
rescue Timeout::Error
|
32
|
+
component.stop! if component_running?
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def process(opts)
|
39
|
+
@async = opts.delete :async
|
40
|
+
@timeout = opts.delete :timeout
|
41
|
+
opts[:terminate] == false ? opts.delete(:terminate) : opts[:terminate] = true
|
42
|
+
|
43
|
+
@options = opts
|
44
|
+
end
|
45
|
+
|
46
|
+
def component
|
47
|
+
@component ||= Punchblock::Component::Input.new mode: :cpa, grammars: tone_grammars
|
48
|
+
end
|
49
|
+
|
50
|
+
def tone_grammars
|
51
|
+
tones.map do |tone_object|
|
52
|
+
if tone_object.is_a? Hash
|
53
|
+
tone_object.map do |tone, individual_options|
|
54
|
+
combined_options = @options.merge individual_options
|
55
|
+
build_grammar_for tone, combined_options
|
56
|
+
end
|
57
|
+
else
|
58
|
+
build_grammar_for tone_object
|
59
|
+
end
|
60
|
+
end.flatten
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_grammar_for(tone, opts={})
|
64
|
+
opts.merge! @options
|
65
|
+
ns_url = "#{Punchblock::BASE_RAYO_NAMESPACE}:cpa:#{tone}:#{Punchblock::RAYO_VERSION}"
|
66
|
+
opts.each_with_index do |(k, v), i|
|
67
|
+
if i == 0
|
68
|
+
ns_url << "?#{k}=#{v}"
|
69
|
+
else
|
70
|
+
ns_url << ";#{k}=#{v}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Punchblock::Component::Input::Grammar.new url: ns_url
|
75
|
+
end
|
76
|
+
|
77
|
+
def async?
|
78
|
+
@async
|
79
|
+
end
|
80
|
+
|
81
|
+
def call
|
82
|
+
@controller.call
|
83
|
+
end
|
84
|
+
|
85
|
+
def call_alive?
|
86
|
+
call && call.active?
|
87
|
+
end
|
88
|
+
|
89
|
+
def component_running?
|
90
|
+
component && component.executing?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module AdhearsionCpa
|
4
|
+
describe ControllerMethods do
|
5
|
+
|
6
|
+
let(:mock_call) { Adhearsion::Call.new }
|
7
|
+
subject { Adhearsion::CallController.new mock_call }
|
8
|
+
|
9
|
+
let(:expected_component) { Punchblock::Component::Input.new mode: :cpa, grammars: expected_grammars }
|
10
|
+
let(:mock_complete_event) { double 'Event', reason: mock_signal }
|
11
|
+
let(:mock_signal) { double 'Signal', type: "dtmf" }
|
12
|
+
|
13
|
+
describe "#detect_tone" do
|
14
|
+
context "when watching for a beep" do
|
15
|
+
let(:mock_signal) { double 'Signal', type: "beep" }
|
16
|
+
let(:expected_grammars) do
|
17
|
+
[ Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:beep:1?terminate=true") ]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "detects a beep" do
|
21
|
+
mock_call.should_receive(:write_and_await_response).with expected_component
|
22
|
+
Punchblock::Component::Input.any_instance.should_receive(:complete_event).and_return mock_complete_event
|
23
|
+
|
24
|
+
subject.detect_tone(:beep, timeout: 5).type.should == "beep"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when watching for a beep and modem" do
|
29
|
+
let(:mock_signal) { double 'Signal', type: :beep }
|
30
|
+
let(:expected_grammars) do
|
31
|
+
[
|
32
|
+
Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:beep:1?terminate=true"),
|
33
|
+
Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:modem:1?terminate=true")
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "detects which tone" do
|
38
|
+
mock_call.should_receive(:write_and_await_response).with(expected_component).and_return mock_signal
|
39
|
+
Punchblock::Component::Input.any_instance.should_receive(:complete_event).and_return mock_complete_event
|
40
|
+
|
41
|
+
subject.detect_tone(:beep, :modem, timeout: 5).type.should == :beep
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when timing out" do
|
46
|
+
let(:expected_grammars) { [ Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:beep:1?terminate=true") ] }
|
47
|
+
|
48
|
+
it "returns nil" do
|
49
|
+
mock_call.should_receive(:write_and_await_response).with(expected_component).and_raise Timeout::Error
|
50
|
+
Punchblock::Component::Input.any_instance.should_receive(:executing?).and_return true
|
51
|
+
Punchblock::Component::Input.any_instance.should_receive :stop!
|
52
|
+
|
53
|
+
subject.detect_tone(:beep, timeout: 5).should be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with an options hash" do
|
58
|
+
let(:expected_grammars) do
|
59
|
+
[
|
60
|
+
Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:speech:1?maxTime=4000;minSpeechDuration=4000;terminate=true"),
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "encodes them in the grammar URL" do
|
65
|
+
mock_call.should_receive(:write_and_await_response).with expected_component
|
66
|
+
Punchblock::Component::Input.any_instance.should_receive(:complete_event).and_return mock_complete_event
|
67
|
+
|
68
|
+
subject.detect_tone :speech, maxTime: 4000, minSpeechDuration: 4000, timeout: 5
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with individual options, and an options hash" do
|
73
|
+
let(:expected_grammars) do
|
74
|
+
[
|
75
|
+
Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:speech:1?foo=bar;terminate=true;maxTime=4000;minSpeechDuration=4000"),
|
76
|
+
Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:beep:1?foo=bar;terminate=true")
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
it "encodes the individual and group options in the grammar URL" do
|
81
|
+
mock_call.should_receive(:write_and_await_response).with expected_component
|
82
|
+
Punchblock::Component::Input.any_instance.should_receive(:complete_event).and_return mock_complete_event
|
83
|
+
|
84
|
+
subject.detect_tone({speech: {maxTime: 4000, minSpeechDuration: 4000}, beep: {}}, timeout: 5, foo: :bar)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#detect_tone!" do
|
90
|
+
let(:mock_component) { double Punchblock::Component::Input, executing?: true }
|
91
|
+
|
92
|
+
before do
|
93
|
+
Punchblock::Component::Input.should_receive(:new).
|
94
|
+
with(mode: :cpa, grammars: expected_grammars).
|
95
|
+
and_return mock_component
|
96
|
+
|
97
|
+
mock_component.should_receive(:register_event_handler).with Punchblock::Component::Input::Signal do |&block|
|
98
|
+
@on_detect_block = block
|
99
|
+
end
|
100
|
+
mock_call.should_receive(:write_and_await_response).with mock_component
|
101
|
+
end
|
102
|
+
|
103
|
+
context "watches in the background" do
|
104
|
+
let(:expected_grammars) do
|
105
|
+
[ Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:dtmf:1?terminate=true") ]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "detects the dtmf" do
|
109
|
+
detector = subject.detect_tone!(:dtmf, timeout: 0.02) { |tone| tone.type }
|
110
|
+
detector.should == mock_component
|
111
|
+
mock_signal.should_receive :type
|
112
|
+
@on_detect_block.call mock_signal
|
113
|
+
|
114
|
+
mock_component.should_receive :stop!
|
115
|
+
sleep 0.04
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context " with :terminate set to false" do
|
120
|
+
let(:expected_grammars) do
|
121
|
+
[ Punchblock::Component::Input::Grammar.new(url: "urn:xmpp:rayo:cpa:dtmf:1") ]
|
122
|
+
end
|
123
|
+
|
124
|
+
it "watches repeatedly in the background" do
|
125
|
+
detector = subject.detect_tone!(:dtmf, timeout: 0.02, terminate: false) { |tone| tone.type }
|
126
|
+
detector.should == mock_component
|
127
|
+
|
128
|
+
mock_signal.should_receive(:type).twice
|
129
|
+
@on_detect_block.call mock_signal
|
130
|
+
@on_detect_block.call mock_signal
|
131
|
+
|
132
|
+
mock_component.should_receive :stop!
|
133
|
+
sleep 0.04
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'adhearsion'
|
2
|
+
|
3
|
+
require 'coveralls'
|
4
|
+
Coveralls.wear!
|
5
|
+
|
6
|
+
require 'adhearsion_cpa'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.color_enabled = true
|
10
|
+
config.tty = true
|
11
|
+
|
12
|
+
config.filter_run focus: true
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
|
15
|
+
config.before(:all) do
|
16
|
+
Adhearsion::Plugin.initializers.each do |plugin_initializer|
|
17
|
+
plugin_initializer.run
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: adhearsion_cpa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Aiken
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: adhearsion
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: punchblock
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.2.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.2.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.0.10
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.0.10
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.5'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard-rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: A plugin for adding cpa to Adhearsion
|
126
|
+
email:
|
127
|
+
- 60tonangel@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- .travis.yml
|
134
|
+
- CHANGELOG.md
|
135
|
+
- Gemfile
|
136
|
+
- Guardfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- adhearsion_cpa.gemspec
|
141
|
+
- lib/adhearsion_cpa.rb
|
142
|
+
- lib/adhearsion_cpa/controller_methods.rb
|
143
|
+
- lib/adhearsion_cpa/plugin.rb
|
144
|
+
- lib/adhearsion_cpa/tone_detector.rb
|
145
|
+
- lib/adhearsion_cpa/version.rb
|
146
|
+
- spec/adhearsion_cpa/controller_methods_spec.rb
|
147
|
+
- spec/spec_helper.rb
|
148
|
+
homepage: https://github.com/grasshoppergroup/adhearsion-cpa
|
149
|
+
licenses:
|
150
|
+
- MIT
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubyforge_project: adhearsion_cpa
|
168
|
+
rubygems_version: 2.0.3
|
169
|
+
signing_key:
|
170
|
+
specification_version: 4
|
171
|
+
summary: A plugin for adding cpa to Adhearsion
|
172
|
+
test_files:
|
173
|
+
- spec/adhearsion_cpa/controller_methods_spec.rb
|
174
|
+
- spec/spec_helper.rb
|
175
|
+
has_rdoc:
|