@jambonz/mrf 0.1.7 → 0.1.9
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/lib/endpoint.js +42 -7
- package/package.json +1 -1
- package/test/client.test.js +30 -0
- package/test/support/mock-server.js +5 -0
package/lib/endpoint.js
CHANGED
|
@@ -130,9 +130,10 @@ class Endpoint extends EventEmitter {
|
|
|
130
130
|
return { body: `-ERR ${err.message}` };
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
/*
|
|
134
|
-
*
|
|
135
|
-
|
|
133
|
+
/* uuid_<vendor>_s2s: the llm task interface. args arrive
|
|
134
|
+
* '^^|<uuid>|<command>[|...]'; map to s2s.* commands. ultravox passes
|
|
135
|
+
* only host/path (a pre-authenticated joinUrl — no authType/apiKey). */
|
|
136
|
+
const s2 = /^uuid_(openai|voice_agent|ultravox)_s2s$/.exec(command);
|
|
136
137
|
if (s2) {
|
|
137
138
|
const vendor = s2[1];
|
|
138
139
|
const raw = Array.isArray(args) ? args.join('|') : String(args || '');
|
|
@@ -432,11 +433,45 @@ class Endpoint extends EventEmitter {
|
|
|
432
433
|
});
|
|
433
434
|
return this;
|
|
434
435
|
}
|
|
435
|
-
dub() {
|
|
436
|
-
|
|
436
|
+
/* dub (mod_dub): fsmrf passes {action, track, play, loop, gain, say}.
|
|
437
|
+
* Map each action onto the mediajam dub.* command family. gain is in
|
|
438
|
+
* dB (the dub verb's gain), carried as gainDb. */
|
|
439
|
+
async dub(opts = {}) {
|
|
440
|
+
const {action, track} = opts;
|
|
441
|
+
switch (action) {
|
|
442
|
+
case 'addTrack':
|
|
443
|
+
await this._request('dub.addTrack', {track});
|
|
444
|
+
break;
|
|
445
|
+
case 'removeTrack':
|
|
446
|
+
await this._request('dub.removeTrack', {track});
|
|
447
|
+
break;
|
|
448
|
+
case 'silenceTrack':
|
|
449
|
+
await this._request('dub.silenceTrack', {track});
|
|
450
|
+
break;
|
|
451
|
+
case 'playOnTrack':
|
|
452
|
+
await this._request('dub.playOnTrack', {
|
|
453
|
+
track,
|
|
454
|
+
url: opts.play,
|
|
455
|
+
...(opts.loop && {loop: true}),
|
|
456
|
+
...(typeof opts.gain === 'number' && opts.gain !== 0 && {gainDb: opts.gain})
|
|
457
|
+
});
|
|
458
|
+
break;
|
|
459
|
+
case 'sayOnTrack':
|
|
460
|
+
await this._request('dub.sayOnTrack', {
|
|
461
|
+
track,
|
|
462
|
+
say: opts.say,
|
|
463
|
+
...(typeof opts.gain === 'number' && opts.gain !== 0 && {gainDb: opts.gain})
|
|
464
|
+
});
|
|
465
|
+
break;
|
|
466
|
+
default:
|
|
467
|
+
throw new Error(`mediajam: unknown dub action '${action}'`);
|
|
468
|
+
}
|
|
469
|
+
return this;
|
|
437
470
|
}
|
|
438
|
-
setGain
|
|
439
|
-
|
|
471
|
+
/* mod_dub setGain — scales the channel audio; maps to endpoint.set gainDb */
|
|
472
|
+
async setGain(gain) {
|
|
473
|
+
await this._request('endpoint.set', {gainDb: typeof gain === 'number' ? gain : parseInt(gain, 10) || 0});
|
|
474
|
+
return this;
|
|
440
475
|
}
|
|
441
476
|
join() {
|
|
442
477
|
return Promise.reject(new Error('mediajam: conference join pending Phase 3 (room.*)'));
|
package/package.json
CHANGED
package/test/client.test.js
CHANGED
|
@@ -92,6 +92,36 @@ test('execute send_dtmf maps digits and duration', async(t) => {
|
|
|
92
92
|
assert.equal(req.data.durationMs, 150);
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
+
test('dub actions map to dub.* commands', async(t) => {
|
|
96
|
+
const { ms, mock } = await setup(t);
|
|
97
|
+
const ep = await ms.createEndpoint({});
|
|
98
|
+
await ep.dub({ action: 'addTrack', track: 'music' });
|
|
99
|
+
await ep.dub({ action: 'playOnTrack', track: 'music', play: 'http://x/a.mp3', loop: true, gain: 5 });
|
|
100
|
+
await ep.dub({ action: 'sayOnTrack', track: 'music', say: 'say:{vendor=google}hello', gain: -3 });
|
|
101
|
+
await ep.dub({ action: 'silenceTrack', track: 'music' });
|
|
102
|
+
await ep.dub({ action: 'removeTrack', track: 'music' });
|
|
103
|
+
|
|
104
|
+
const add = mock.requests.find((r) => r.cmd === 'dub.addTrack');
|
|
105
|
+
assert.equal(add.data.track, 'music');
|
|
106
|
+
const play = mock.requests.find((r) => r.cmd === 'dub.playOnTrack');
|
|
107
|
+
assert.equal(play.data.url, 'http://x/a.mp3');
|
|
108
|
+
assert.equal(play.data.loop, true);
|
|
109
|
+
assert.equal(play.data.gainDb, 5);
|
|
110
|
+
const say = mock.requests.find((r) => r.cmd === 'dub.sayOnTrack');
|
|
111
|
+
assert.equal(say.data.say, 'say:{vendor=google}hello');
|
|
112
|
+
assert.equal(say.data.gainDb, -3);
|
|
113
|
+
assert.ok(mock.requests.find((r) => r.cmd === 'dub.silenceTrack'));
|
|
114
|
+
assert.ok(mock.requests.find((r) => r.cmd === 'dub.removeTrack'));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('setGain maps to endpoint.set gainDb', async(t) => {
|
|
118
|
+
const { ms, mock } = await setup(t);
|
|
119
|
+
const ep = await ms.createEndpoint({});
|
|
120
|
+
await ep.setGain(7);
|
|
121
|
+
const req = mock.requests.filter((r) => r.cmd === 'endpoint.set').pop();
|
|
122
|
+
assert.equal(req.data.gainDb, 7);
|
|
123
|
+
});
|
|
124
|
+
|
|
95
125
|
test('bridge and unbridge', async(t) => {
|
|
96
126
|
const { ms, mock } = await setup(t);
|
|
97
127
|
const a = await ms.createEndpoint({});
|
|
@@ -119,6 +119,11 @@ class MockMediajam {
|
|
|
119
119
|
case 'endpoint.unmute':
|
|
120
120
|
case 'bridge.create':
|
|
121
121
|
case 'bridge.destroy':
|
|
122
|
+
case 'dub.addTrack':
|
|
123
|
+
case 'dub.removeTrack':
|
|
124
|
+
case 'dub.silenceTrack':
|
|
125
|
+
case 'dub.playOnTrack':
|
|
126
|
+
case 'dub.sayOnTrack':
|
|
122
127
|
res({});
|
|
123
128
|
break;
|
|
124
129
|
case 'endpoint.info':
|