@jambonz/mrf 0.1.6 → 0.1.8

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 CHANGED
@@ -432,11 +432,45 @@ class Endpoint extends EventEmitter {
432
432
  });
433
433
  return this;
434
434
  }
435
- dub() {
436
- return Promise.reject(new Error('mediajam: dub pending Phase 2 (dub.*)'));
435
+ /* dub (mod_dub): fsmrf passes {action, track, play, loop, gain, say}.
436
+ * Map each action onto the mediajam dub.* command family. gain is in
437
+ * dB (the dub verb's gain), carried as gainDb. */
438
+ async dub(opts = {}) {
439
+ const {action, track} = opts;
440
+ switch (action) {
441
+ case 'addTrack':
442
+ await this._request('dub.addTrack', {track});
443
+ break;
444
+ case 'removeTrack':
445
+ await this._request('dub.removeTrack', {track});
446
+ break;
447
+ case 'silenceTrack':
448
+ await this._request('dub.silenceTrack', {track});
449
+ break;
450
+ case 'playOnTrack':
451
+ await this._request('dub.playOnTrack', {
452
+ track,
453
+ url: opts.play,
454
+ ...(opts.loop && {loop: true}),
455
+ ...(typeof opts.gain === 'number' && opts.gain !== 0 && {gainDb: opts.gain})
456
+ });
457
+ break;
458
+ case 'sayOnTrack':
459
+ await this._request('dub.sayOnTrack', {
460
+ track,
461
+ say: opts.say,
462
+ ...(typeof opts.gain === 'number' && opts.gain !== 0 && {gainDb: opts.gain})
463
+ });
464
+ break;
465
+ default:
466
+ throw new Error(`mediajam: unknown dub action '${action}'`);
467
+ }
468
+ return this;
437
469
  }
438
- setGain() {
439
- return Promise.reject(new Error('mediajam: setGain pending Phase 2 (dub.*)'));
470
+ /* mod_dub setGain — scales the channel audio; maps to endpoint.set gainDb */
471
+ async setGain(gain) {
472
+ await this._request('endpoint.set', {gainDb: typeof gain === 'number' ? gain : parseInt(gain, 10) || 0});
473
+ return this;
440
474
  }
441
475
  join() {
442
476
  return Promise.reject(new Error('mediajam: conference join pending Phase 3 (room.*)'));
@@ -136,9 +136,7 @@ class MediaServer extends EventEmitter {
136
136
  const data = {};
137
137
  if (opts.remoteSdp) data.remoteSdp = opts.remoteSdp;
138
138
  if (opts.codecs) data.codecs = Array.isArray(opts.codecs) ? opts.codecs : [opts.codecs];
139
- /* direction tag for session accounting (mediajam-cli subtotals):
140
- * connectCaller marks inbound; everything else defaults outbound */
141
- data.tags = { direction: 'outbound', ...(opts.tags || {}) };
139
+ if (opts.tags) data.tags = opts.tags;
142
140
  const options = {};
143
141
  if (opts.media_timeout) options.mediaTimeoutMs = parseInt(opts.media_timeout, 10);
144
142
  if (opts.media_hold_timeout) options.holdTimeoutMs = parseInt(opts.media_hold_timeout, 10);
@@ -156,11 +154,7 @@ class MediaServer extends EventEmitter {
156
154
  * it. Works with drachtio req/res objects (duck-typed).
157
155
  */
158
156
  async connectCaller(req, res, opts = {}) {
159
- const endpoint = await this.createEndpoint({
160
- ...opts,
161
- remoteSdp: req.body,
162
- tags: { direction: 'inbound', ...(opts.tags || {}) }
163
- });
157
+ const endpoint = await this.createEndpoint({ ...opts, remoteSdp: req.body });
164
158
  const dialog = await res.send(200, { body: endpoint.local.sdp });
165
159
  return { endpoint, dialog };
166
160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/mrf",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "node --test",
@@ -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':