@jambonz/node-red-contrib-jambonz 2.4.28 → 2.4.30
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.
- package/examples/Generic Verb Node.json +124 -0
- package/package.json +5 -4
- package/resources/editor.js +4 -4
- package/src/nodes/dial.html +57 -2
- package/src/nodes/dial.js +26 -1
- package/src/nodes/generic-verb.html +60 -0
- package/src/nodes/generic-verb.js +18 -0
- package/src/nodes/lcc.html +70 -0
- package/src/nodes/lcc.js +33 -2
- package/src/nodes/libs.js +1 -1
- package/src/nodes/tag.js +9 -2
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "5d9a3f1fa6551a9f",
|
|
4
|
+
"type": "webhook in",
|
|
5
|
+
"z": "1b97c147228e3829",
|
|
6
|
+
"name": "",
|
|
7
|
+
"url": "/call",
|
|
8
|
+
"method": "post",
|
|
9
|
+
"x": 100,
|
|
10
|
+
"y": 220,
|
|
11
|
+
"wires": [
|
|
12
|
+
[
|
|
13
|
+
"e627c4f20ede7606"
|
|
14
|
+
]
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "1d33431d324d0453",
|
|
19
|
+
"type": "webhook out",
|
|
20
|
+
"z": "1b97c147228e3829",
|
|
21
|
+
"name": "",
|
|
22
|
+
"x": 1270,
|
|
23
|
+
"y": 180,
|
|
24
|
+
"wires": []
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "9bf6ecad5a81a2bf",
|
|
28
|
+
"type": "debug",
|
|
29
|
+
"z": "1b97c147228e3829",
|
|
30
|
+
"name": "debug 18",
|
|
31
|
+
"active": true,
|
|
32
|
+
"tosidebar": true,
|
|
33
|
+
"console": false,
|
|
34
|
+
"tostatus": false,
|
|
35
|
+
"complete": "jambonz",
|
|
36
|
+
"targetType": "msg",
|
|
37
|
+
"statusVal": "",
|
|
38
|
+
"statusType": "auto",
|
|
39
|
+
"x": 1260,
|
|
40
|
+
"y": 280,
|
|
41
|
+
"wires": []
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "73e79d1cc5ac62d0",
|
|
45
|
+
"type": "generic",
|
|
46
|
+
"z": "1b97c147228e3829",
|
|
47
|
+
"name": "generic - say",
|
|
48
|
+
"verb": "say",
|
|
49
|
+
"data": "{\"text\":\"goodbye\"}",
|
|
50
|
+
"dataType": "json",
|
|
51
|
+
"x": 1030,
|
|
52
|
+
"y": 220,
|
|
53
|
+
"wires": [
|
|
54
|
+
[
|
|
55
|
+
"9bf6ecad5a81a2bf",
|
|
56
|
+
"1d33431d324d0453"
|
|
57
|
+
]
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "e627c4f20ede7606",
|
|
62
|
+
"type": "generic",
|
|
63
|
+
"z": "1b97c147228e3829",
|
|
64
|
+
"name": "generic - answer",
|
|
65
|
+
"verb": "answer",
|
|
66
|
+
"data": "{}",
|
|
67
|
+
"dataType": "json",
|
|
68
|
+
"x": 290,
|
|
69
|
+
"y": 220,
|
|
70
|
+
"wires": [
|
|
71
|
+
[
|
|
72
|
+
"453b7fb4d62ef93e"
|
|
73
|
+
]
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "453b7fb4d62ef93e",
|
|
78
|
+
"type": "generic",
|
|
79
|
+
"z": "1b97c147228e3829",
|
|
80
|
+
"name": "generic - pause",
|
|
81
|
+
"verb": "pause",
|
|
82
|
+
"data": "{\"length\":1}",
|
|
83
|
+
"dataType": "json",
|
|
84
|
+
"x": 480,
|
|
85
|
+
"y": 220,
|
|
86
|
+
"wires": [
|
|
87
|
+
[
|
|
88
|
+
"da2ac5d1cd9ab0a5"
|
|
89
|
+
]
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "da2ac5d1cd9ab0a5",
|
|
94
|
+
"type": "generic",
|
|
95
|
+
"z": "1b97c147228e3829",
|
|
96
|
+
"name": "generic -say",
|
|
97
|
+
"verb": "say",
|
|
98
|
+
"data": "{\"text\":\"Please hold\",\"loop\":1,\"earlyMedia\":false}",
|
|
99
|
+
"dataType": "json",
|
|
100
|
+
"x": 670,
|
|
101
|
+
"y": 220,
|
|
102
|
+
"wires": [
|
|
103
|
+
[
|
|
104
|
+
"b7225263b1115bde"
|
|
105
|
+
]
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"id": "b7225263b1115bde",
|
|
110
|
+
"type": "generic",
|
|
111
|
+
"z": "1b97c147228e3829",
|
|
112
|
+
"name": "generic - pause",
|
|
113
|
+
"verb": "pause",
|
|
114
|
+
"data": "{\"length\":5}",
|
|
115
|
+
"dataType": "json",
|
|
116
|
+
"x": 840,
|
|
117
|
+
"y": 220,
|
|
118
|
+
"wires": [
|
|
119
|
+
[
|
|
120
|
+
"73e79d1cc5ac62d0"
|
|
121
|
+
]
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jambonz/node-red-contrib-jambonz",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.30",
|
|
4
4
|
"description": "Node-RED nodes for jambonz platform",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node-red"
|
|
@@ -50,14 +50,15 @@
|
|
|
50
50
|
"get_calls": "src/nodes/get_calls.js",
|
|
51
51
|
"get_recent_calls": "src/nodes/get_recent_calls.js",
|
|
52
52
|
"answer": "src/nodes/answer.js",
|
|
53
|
-
"dub": "src/nodes/dub.js"
|
|
53
|
+
"dub": "src/nodes/dub.js",
|
|
54
|
+
"generic": "src/nodes/generic-verb.js"
|
|
54
55
|
}
|
|
55
56
|
},
|
|
56
57
|
"author": "Dave Horton",
|
|
57
58
|
"license": "MIT",
|
|
58
59
|
"dependencies": {
|
|
59
60
|
"aws-sdk": "^2.1665.0",
|
|
60
|
-
"body-parser": "^1.20.
|
|
61
|
+
"body-parser": "^1.20.3",
|
|
61
62
|
"cookie-parser": "^1.4.6",
|
|
62
63
|
"cors": "^2.8.5",
|
|
63
64
|
"hash-sum": "^2.0.0",
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
"on-headers": "^1.0.2",
|
|
69
70
|
"raw-body": "^2.5.2",
|
|
70
71
|
"s3-upload-stream": "^1.0.7",
|
|
71
|
-
"undici": "^5.28.
|
|
72
|
+
"undici": "^5.28.5",
|
|
72
73
|
"ws": "^8.18.0"
|
|
73
74
|
}
|
|
74
75
|
}
|
package/resources/editor.js
CHANGED
|
@@ -156,10 +156,10 @@
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
function prepareSttControls(node) {
|
|
160
|
-
var vendorElem = $(
|
|
161
|
-
var languageElem = $(
|
|
162
|
-
var mixtypeElem = $(
|
|
159
|
+
function prepareSttControls(node, vendor='#node-input-transcriptionvendor', lang='#node-input-recognizerlang', mixType='#node-input-mixtype') {
|
|
160
|
+
var vendorElem = $(vendor);
|
|
161
|
+
var languageElem = $(lang);
|
|
162
|
+
var mixtypeElem = $(mixType);
|
|
163
163
|
|
|
164
164
|
console.log('entering prepareSttControls');
|
|
165
165
|
|
package/src/nodes/dial.html
CHANGED
|
@@ -65,7 +65,16 @@
|
|
|
65
65
|
vocabularynameType: {value: 'str'},
|
|
66
66
|
vocabularyfiltername: {},
|
|
67
67
|
vocabularyfilternameType: {value: 'str'},
|
|
68
|
-
vocabularyfiltermethod: {}
|
|
68
|
+
vocabularyfiltermethod: {},
|
|
69
|
+
amd_actionHook : {},
|
|
70
|
+
amd_actionHookType: {value: 'str'},
|
|
71
|
+
amd_recognizer_vendor: {value: 'default'},
|
|
72
|
+
amd_recognizer_lang: {value: 'default'},
|
|
73
|
+
amd_thresholdWordCount: {},
|
|
74
|
+
amd_timers_decisionTimeoutMs: {},
|
|
75
|
+
amd_timers_greetingCompletionTimeoutMs:{},
|
|
76
|
+
amd_timers_noSpeechTimeoutMs: {},
|
|
77
|
+
amd_timers_toneTimeoutMs: {}
|
|
69
78
|
},
|
|
70
79
|
inputs:1,
|
|
71
80
|
outputs:1,
|
|
@@ -147,6 +156,7 @@
|
|
|
147
156
|
});
|
|
148
157
|
|
|
149
158
|
prepareSttControls(node);
|
|
159
|
+
prepareSttControls(node, '#node-input-amd_recognizer_vendor', '#node-input-amd_recognizer_lang');
|
|
150
160
|
|
|
151
161
|
$('#node-input-target-container').css('min-height','180px').css('min-width','450px').editableList({
|
|
152
162
|
addItem: function(container, i, opt) {
|
|
@@ -482,7 +492,7 @@
|
|
|
482
492
|
<div class="form-row">
|
|
483
493
|
<label for="node-input-dialmusic">Dial music</label>
|
|
484
494
|
<input type="text" id="node-input-dialmusic" placeholder="url to .wav or .mp3 file to play during dial">
|
|
485
|
-
<input type="hidden" id="node-input-
|
|
495
|
+
<input type="hidden" id="node-input-dialmusicType">
|
|
486
496
|
</div>
|
|
487
497
|
<div class="form-row">
|
|
488
498
|
<label for="node-input-dtmfcapture">Dtmf capture</label>
|
|
@@ -652,6 +662,51 @@
|
|
|
652
662
|
<ol id="node-input-headers-container"></ol>
|
|
653
663
|
</div>
|
|
654
664
|
</fieldset>
|
|
665
|
+
<fieldset>
|
|
666
|
+
<legend>Answering Machine Detection</legend>
|
|
667
|
+
<div class="form-row">
|
|
668
|
+
<label for="node-input-amd_actionHook">actionHook</label>
|
|
669
|
+
<input type="text" id="node-input-amd_actionHook">
|
|
670
|
+
<input type="hidden" id="node-input-amd_actionHookType">
|
|
671
|
+
</div>
|
|
672
|
+
<div class="form-row">
|
|
673
|
+
<label for="node-input-amd_recognizer_vendor">Vendor</label>
|
|
674
|
+
<select id="node-input-amd_recognizer_vendor">
|
|
675
|
+
<option value="default" selected>--application default--</option>
|
|
676
|
+
<option value="google">Google</option>
|
|
677
|
+
<option value="aws">AWS</option>
|
|
678
|
+
<option value="deepgram">deepgram</option>
|
|
679
|
+
<option value="microsoft">microsoft</option>
|
|
680
|
+
<option value="ibm">ibm</option>
|
|
681
|
+
<option value="nuance">nuance</option>
|
|
682
|
+
</select>
|
|
683
|
+
</div>
|
|
684
|
+
<div class="form-row">
|
|
685
|
+
<label for="node-input-amd_recognizer_lang">Language</label>
|
|
686
|
+
<select id="node-input-amd_recognizer_lang">
|
|
687
|
+
</select>
|
|
688
|
+
</div>
|
|
689
|
+
<div class="form-row">
|
|
690
|
+
<label for="node-input-amd_thresholdWordCount">Threshold Word Count</label>
|
|
691
|
+
<input type="text" id="node-input-amd_thresholdWordCount">
|
|
692
|
+
</div>
|
|
693
|
+
<div class="form-row">
|
|
694
|
+
<label for="node-input-amd_timers_decisionTimeoutMs">Decision Timeout</label>
|
|
695
|
+
<input type="text" id="node-input-amd_timers_decisionTimeoutMs">
|
|
696
|
+
</div>
|
|
697
|
+
<div class="form-row">
|
|
698
|
+
<label for="node-input-amd_timers_greetingCompletionTimeoutMs">Greeting Completion Timeout</label>
|
|
699
|
+
<input type="text" id="node-input-amd_timers_greetingCompletionTimeoutMs">
|
|
700
|
+
</div>
|
|
701
|
+
<div class="form-row">
|
|
702
|
+
<label for="node-input-amd_timers_noSpeechTimeoutMs">No-Speech Timeout</label>
|
|
703
|
+
<input type="text" id="node-input-amd_timers_noSpeechTimeoutMs">
|
|
704
|
+
</div>
|
|
705
|
+
<div class="form-row">
|
|
706
|
+
<label for="node-input-amd_timers_toneTimeoutMs">Tone Timeout</label>
|
|
707
|
+
<input type="text" id="node-input-amd_timers_toneTimeoutMs">
|
|
708
|
+
</div>
|
|
709
|
+
</fieldset>
|
|
655
710
|
</div>
|
|
656
711
|
</script>
|
|
657
712
|
|
package/src/nodes/dial.js
CHANGED
|
@@ -49,7 +49,7 @@ module.exports = function(RED) {
|
|
|
49
49
|
confirmHook: await new_resolve(RED, config.confirmhook, config.confirmhookType, node, msg),
|
|
50
50
|
dialMusic: await new_resolve(RED, config.dialmusic, config.dialmusicType, node, msg),
|
|
51
51
|
referHook: await new_resolve(RED, config.referhook, config.referhookType, node, msg),
|
|
52
|
-
dtmfHook: await new_resolve(RED, config.dtmfhook, config.dtmfhookType, node, msg)
|
|
52
|
+
dtmfHook: await new_resolve(RED, config.dtmfhook, config.dtmfhookType, node, msg)
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
if (config.hasOwnProperty('anchormedia')) {
|
|
@@ -132,6 +132,31 @@ module.exports = function(RED) {
|
|
|
132
132
|
delete data.dtmfHook;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
// AMD
|
|
136
|
+
const _amd_actionHook = await new_resolve(RED, config.amd_actionHook, config.amd_actionHookType, node, msg)
|
|
137
|
+
if (_amd_actionHook){
|
|
138
|
+
data.amd = {}
|
|
139
|
+
data.amd.actionHook = _amd_actionHook;
|
|
140
|
+
config.amd_thresholdWordCount && (data.amd.thresholdWordCount = Number(config.amd_thresholdWordCount))
|
|
141
|
+
data.amd.timers = {
|
|
142
|
+
...(config.amd_timers_decisionTimeoutMs && {decisionTimeoutMs: Number(config.amd_timers_decisionTimeoutMs)}),
|
|
143
|
+
...(config.amd_timers_greetingCompletionTimeoutMs && {greetingCompletionTimeoutMs: Number(config.amd_timers_greetingCompletionTimeoutMs)}),
|
|
144
|
+
...(config.amd_timers_noSpeechTimeoutMs && {noSpeechTimeoutMs: Number(config.amd_timers_noSpeechTimeoutMs)}),
|
|
145
|
+
...(config.amd_timers_toneTimeoutMs && {toneTimeoutMs: Number(config.amd_timers_toneTimeoutMs)}),
|
|
146
|
+
}
|
|
147
|
+
//If none of the timer values are set remove the object
|
|
148
|
+
if (Object.keys(data.amd.timers).length == 0){
|
|
149
|
+
delete(data.amd.timers)
|
|
150
|
+
}
|
|
151
|
+
//If custom recogniser is used
|
|
152
|
+
if (config.amd_recognizer_vendor != 'default'){
|
|
153
|
+
data.amd.recognizer = {
|
|
154
|
+
...(config.amd_recognizer_vendor && {vendor : config.amd_recognizer_vendor}),
|
|
155
|
+
...(config.amd_recognizer_lang && {language : config.amd_recognizer_lang})
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
135
160
|
node.log(`dial verb: ${JSON.stringify(data)}`);
|
|
136
161
|
|
|
137
162
|
appendVerb(msg, data);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!-- Javascript -->
|
|
2
|
+
<script type="text/javascript">
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
RED.nodes.registerType('generic',{
|
|
6
|
+
category: 'jambonz',
|
|
7
|
+
color: '#bbabaa',
|
|
8
|
+
defaults: {
|
|
9
|
+
name: {value: ''},
|
|
10
|
+
verb: {required: true},
|
|
11
|
+
data: {value: '{}'},
|
|
12
|
+
dataType: {value: 'json'},
|
|
13
|
+
},
|
|
14
|
+
inputs:1,
|
|
15
|
+
outputs:1,
|
|
16
|
+
icon: "font-awesome/fa-cubes",
|
|
17
|
+
label: function() { return this.name || 'generic';},
|
|
18
|
+
oneditprepare: function() {
|
|
19
|
+
$('#node-input-data').typedInput({
|
|
20
|
+
default: $('#node-input-dataType').val(),
|
|
21
|
+
types: ['json','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
22
|
+
typeField: $('#node-input-dataType')
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<!-- HTML -->
|
|
29
|
+
<script type="text/html" data-template-name="generic">
|
|
30
|
+
<div class="form-row">
|
|
31
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
32
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
33
|
+
</div>
|
|
34
|
+
<div class="form-row">
|
|
35
|
+
<label for="node-input-verb">Verb</label>
|
|
36
|
+
<input type="text" id="node-input-verb" placeholder="verb">
|
|
37
|
+
</div>
|
|
38
|
+
<div class="form-row">
|
|
39
|
+
<label for="node-input-data">Attributes</label>
|
|
40
|
+
<input type="text" id="node-input-data">
|
|
41
|
+
<input type="hidden" id="node-input-dataType">
|
|
42
|
+
</div>
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<!-- Help Text -->
|
|
46
|
+
<script type="text/html" data-help-name="generic">
|
|
47
|
+
<p>A generic node to set any verb</p>
|
|
48
|
+
<h3>Outputs</h3>
|
|
49
|
+
<dl class="message-properties">
|
|
50
|
+
<dt>jambonz<span class="property-type">object</span></dt>
|
|
51
|
+
<dd> <code>msg.jambonz</code> will contain any previous actions provided to the input with the new <code>pause</code> action appended </dd>
|
|
52
|
+
</dl>
|
|
53
|
+
|
|
54
|
+
<h3>Details</h3>
|
|
55
|
+
Allows use of complex or new verbs in Jambonz that may not have nodes, set the verb name and then pass any additional attributes as a JSON object in the data field.
|
|
56
|
+
<h3>References</h3>
|
|
57
|
+
<ul>
|
|
58
|
+
<li><a href="https://www.jambonz.org/docs/webhooks/">Jambonz Verb reference</a></li>
|
|
59
|
+
</ul>
|
|
60
|
+
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
var {appendVerb, new_resolve} = require('./libs')
|
|
2
|
+
|
|
3
|
+
module.exports = function(RED) {
|
|
4
|
+
function generic(config) {
|
|
5
|
+
RED.nodes.createNode(this, config);
|
|
6
|
+
var node = this;
|
|
7
|
+
node.verb = config.verb
|
|
8
|
+
node.on('input', async function(msg) {
|
|
9
|
+
let data = await new_resolve(RED, config.data, config.dataType, node, msg);
|
|
10
|
+
appendVerb(msg, {
|
|
11
|
+
...{verb: node.verb},
|
|
12
|
+
...data
|
|
13
|
+
});
|
|
14
|
+
node.send(msg);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
RED.nodes.registerType('generic', generic);
|
|
18
|
+
}
|
package/src/nodes/lcc.html
CHANGED
|
@@ -70,6 +70,16 @@
|
|
|
70
70
|
return action !== 'tag' || v.length > 0;
|
|
71
71
|
}},
|
|
72
72
|
tagType: {value: 'json'},
|
|
73
|
+
dubTrack: {value: ''},
|
|
74
|
+
dubTrackType: {value: 'str'},
|
|
75
|
+
dubPlay: {},
|
|
76
|
+
dubPlayType: {value: 'str'},
|
|
77
|
+
dubSay: {},
|
|
78
|
+
dubSayType: {value: 'str'},
|
|
79
|
+
dubLoop: {value: false},
|
|
80
|
+
dubLoopType: {value: 'bool'},
|
|
81
|
+
dubGain: {value: 0},
|
|
82
|
+
dubGainType: {value: 'num'},
|
|
73
83
|
},
|
|
74
84
|
inputs:1,
|
|
75
85
|
outputs:1,
|
|
@@ -91,6 +101,7 @@
|
|
|
91
101
|
var sipRequestDiv = $('#sip-request-options');
|
|
92
102
|
var dtmfDiv = $('#dtmf-options');
|
|
93
103
|
var tagDiv = $('#tag-options');
|
|
104
|
+
var dubDiv = $('#dub-options');
|
|
94
105
|
|
|
95
106
|
$('#node-input-callSid').typedInput({
|
|
96
107
|
default: $('#node-input-callSidType').val(),
|
|
@@ -152,6 +163,31 @@
|
|
|
152
163
|
types: ['msg', 'flow', 'global', 'json', 'jsonata', 'env', mustacheType],
|
|
153
164
|
typeField: $('#node-input-tagType')
|
|
154
165
|
});
|
|
166
|
+
$('#node-input-dubTrack').typedInput({
|
|
167
|
+
default: $('#node-input-dubTrackType').val(),
|
|
168
|
+
types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
|
|
169
|
+
typeField: $('#node-input-dubTrackType')
|
|
170
|
+
});
|
|
171
|
+
$('#node-input-dubPlay').typedInput({
|
|
172
|
+
default: $('#node-input-dubPlayType').val(),
|
|
173
|
+
types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
|
|
174
|
+
typeField: $('#node-input-dubPlayType')
|
|
175
|
+
});
|
|
176
|
+
$('#node-input-dubSay').typedInput({
|
|
177
|
+
default: $('#node-input-dubSayType').val(),
|
|
178
|
+
types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
|
|
179
|
+
typeField: $('#node-input-dubSayType')
|
|
180
|
+
});
|
|
181
|
+
$('#node-input-dubLoop').typedInput({
|
|
182
|
+
default: $('#node-input-dubLoopType').val(),
|
|
183
|
+
types: ['bool', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
|
|
184
|
+
typeField: $('#node-input-dubLoopType')
|
|
185
|
+
});
|
|
186
|
+
$('#node-input-dubGain').typedInput({
|
|
187
|
+
default: $('#node-input-dubFainType').val(),
|
|
188
|
+
types: ['num', 'flow', 'global', 'json', 'jsonata', 'env', mustacheType],
|
|
189
|
+
typeField: $('#node-input-dubGainType')
|
|
190
|
+
});
|
|
155
191
|
|
|
156
192
|
var onActionChanged = function () {
|
|
157
193
|
var selectedAction = actionElem.find(':selected').val();
|
|
@@ -169,6 +205,8 @@
|
|
|
169
205
|
else dtmfDiv.hide();
|
|
170
206
|
if ('tag' === selectedAction) tagDiv.show();
|
|
171
207
|
else tagDiv.hide();
|
|
208
|
+
if ('dub' === selectedAction.substring(0,3)) dubDiv.show();
|
|
209
|
+
else dubDiv.hide();
|
|
172
210
|
}
|
|
173
211
|
|
|
174
212
|
var onVendorChanged = function() {
|
|
@@ -337,6 +375,11 @@
|
|
|
337
375
|
<option value="resume_call_recording">resume call recording</option>
|
|
338
376
|
<option value="send_dtmf">send RFC 2833 DTMF</option>
|
|
339
377
|
<option value="tag">tag call</option>
|
|
378
|
+
<option value="dubAdd">Dub - addTrack</option>
|
|
379
|
+
<option value="dubRemove">Dub - removeTrack</option>
|
|
380
|
+
<option value="dubPlay">Dub - playOnTrack</option>
|
|
381
|
+
<option value="dubSay">Dub - sayOnTrack</option>
|
|
382
|
+
<option value="dubSilence">Dub - SilenceTrack</option>
|
|
340
383
|
</select>
|
|
341
384
|
</div>
|
|
342
385
|
<div id="say-options">
|
|
@@ -451,6 +494,33 @@
|
|
|
451
494
|
<input type="hidden" id="node-input-tagType">
|
|
452
495
|
</div>
|
|
453
496
|
</div>
|
|
497
|
+
<div id="dub-options">
|
|
498
|
+
<div class="form-row">
|
|
499
|
+
<label for="node-input-dubTrack">Track</label>
|
|
500
|
+
<input type="text" id="node-input-dubTrack">
|
|
501
|
+
<input type="hidden" id="node-input-dubTrackType">
|
|
502
|
+
</div>
|
|
503
|
+
<div class="form-row">
|
|
504
|
+
<label for="node-input-dubPlay">Play URL</label>
|
|
505
|
+
<input type="text" id="node-input-dubPlay" placeholder="https://example.com/file.mp3">
|
|
506
|
+
<input type="hidden" id="node-input-dubPlayType">
|
|
507
|
+
</div>
|
|
508
|
+
<div class="form-row">
|
|
509
|
+
<label for="node-input-dubSay">Say Text</label>
|
|
510
|
+
<input type="text" id="node-input-dubSay" placeholder="Text">
|
|
511
|
+
<input type="hidden" id="node-input-tagType">
|
|
512
|
+
</div>
|
|
513
|
+
<div class="form-row">
|
|
514
|
+
<label for="node-input-dubLoop">Loop</label>
|
|
515
|
+
<input type="text" id="node-input-dubLoop">
|
|
516
|
+
<input type="hidden" id="node-input-dubLoopType">
|
|
517
|
+
</div>
|
|
518
|
+
<div class="form-row">
|
|
519
|
+
<label for="node-input-dubGain">Gain</label>
|
|
520
|
+
<input type="text" id="node-input-dubGain">
|
|
521
|
+
<input type="hidden" id="node-input-dubGainType">
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
454
524
|
</script>
|
|
455
525
|
|
|
456
526
|
<!-- Help Text -->
|
package/src/nodes/lcc.js
CHANGED
|
@@ -121,8 +121,39 @@ function lcc(config) {
|
|
|
121
121
|
};
|
|
122
122
|
break;
|
|
123
123
|
case 'tag':
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
opts.tag = await new_resolve(RED, config.tag, config.tagType, node, msg);
|
|
125
|
+
break;
|
|
126
|
+
case 'dubAdd':
|
|
127
|
+
opts.dub = { action: 'addTrack' };
|
|
128
|
+
opts.dub.track = await new_resolve(RED, config.dubTrack, config.dubTrackType, node, msg);
|
|
129
|
+
opts.dub.say = await new_resolve(RED, config.dubSay, config.dubSayType, node, msg) || undefined
|
|
130
|
+
opts.dub.play = await new_resolve(RED, config.dubPlay, config.dubPlayType, node, msg) || undefined
|
|
131
|
+
opts.dub.loop = await new_resolve(RED, config.dubLoop, config.dubLoopType, node, msg)
|
|
132
|
+
opts.dub.gain = await new_resolve(RED, config.dubGain, config.dubGainType, node, msg);
|
|
133
|
+
break
|
|
134
|
+
case 'dubRemove':
|
|
135
|
+
opts.dub = { action: 'removeTrack' };
|
|
136
|
+
opts.dub.track = await new_resolve(RED, config.dubTrack, config.dubTrackType, node, msg);
|
|
137
|
+
break
|
|
138
|
+
case 'dubPlay':
|
|
139
|
+
console.log(config)
|
|
140
|
+
opts.dub = { action: 'playOnTrack' };
|
|
141
|
+
opts.dub.track = await new_resolve(RED, config.dubTrack, config.dubTrackType, node, msg);
|
|
142
|
+
opts.dub.play = await new_resolve(RED, config.dubPlay, config.dubPlayType, node, msg);
|
|
143
|
+
opts.dub.loop = await new_resolve(RED, config.dubLoop, config.dubLoopType, node, msg);
|
|
144
|
+
opts.dub.gain = await new_resolve(RED, config.dubGain, config.dubGainType, node, msg);
|
|
145
|
+
break
|
|
146
|
+
case 'dubSay':
|
|
147
|
+
opts.dub = { action : 'sayOnTrack' };
|
|
148
|
+
opts.dub.track = await new_resolve(RED, config.dubTrack, config.dubTrackType, node, msg);
|
|
149
|
+
opts.dub.say = await new_resolve(RED, config.dubSay, config.dubSayType, node, msg);
|
|
150
|
+
opts.dub.loop = await new_resolve(RED, config.dubLoop, config.dubLoopType, node, msg);
|
|
151
|
+
opts.dub.gain = await new_resolve(RED, config.dubGain, config.dubGainType, node, msg);
|
|
152
|
+
break
|
|
153
|
+
case 'dubSilence':
|
|
154
|
+
opts.dub = { action: 'silenceTrack' };
|
|
155
|
+
opts.dub.track = await new_resolve(RED, config.dubTrack, config.dubTrackType, node, msg);
|
|
156
|
+
break
|
|
126
157
|
default:
|
|
127
158
|
node.log(`invalid action: ${config.action}`);
|
|
128
159
|
send(msg);
|
package/src/nodes/libs.js
CHANGED
|
@@ -133,7 +133,7 @@ exports.appendVerb = (msg, obj) => {
|
|
|
133
133
|
const url = `${baseUrl}/v1/Accounts/${accountSid}/Calls/${callSid}`;
|
|
134
134
|
node.log(`invoking LCC with payload ${JSON.stringify(opts)} at ${url}`);
|
|
135
135
|
const response = await fetch(url, {
|
|
136
|
-
method: 'POST',
|
|
136
|
+
method: 'POST', // TODO Should move this to PUT in next major update but will need regression testing
|
|
137
137
|
headers: {
|
|
138
138
|
'Content-Type': 'application/json',
|
|
139
139
|
'Authorization': `Bearer ${apiToken}`
|
package/src/nodes/tag.js
CHANGED
|
@@ -6,8 +6,15 @@ module.exports = function(RED) {
|
|
|
6
6
|
var node = this;
|
|
7
7
|
node.on('input', async function(msg) {
|
|
8
8
|
var data = await new_resolve(RED, config.data, config.dataType, node, msg);
|
|
9
|
-
if (typeof(data) != 'object'){
|
|
10
|
-
|
|
9
|
+
if (typeof(data) != 'object') {
|
|
10
|
+
try {
|
|
11
|
+
data = JSON.parse(data)
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.log('Failed to parse data as JSON: ', data)
|
|
14
|
+
return node.send(msg);
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
data = Object.assign({}, data);
|
|
11
18
|
}
|
|
12
19
|
appendVerb(msg, {
|
|
13
20
|
verb: 'tag',
|