@jambonz/mrf 0.1.3 → 0.1.5

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
@@ -1,4 +1,5 @@
1
1
  const { EventEmitter } = require('events');
2
+ const { randomUUID } = require('crypto');
2
3
  const { parseSdp, translatePlayUrl } = require('./utils');
3
4
 
4
5
  // mediajam normalized wire events -> legacy ESL event names the
@@ -48,15 +49,27 @@ class Endpoint extends EventEmitter {
48
49
  }
49
50
  const files = Array.isArray(file) ? file : [file];
50
51
  const urls = files.map(translatePlayUrl);
51
- const data = { urls };
52
+ /* the client supplies the playId so _pendingPlays is populated BEFORE
53
+ * anything hits the wire — the server's play.start event can arrive in
54
+ * the same tcp chunk as the command response, which processes ahead of
55
+ * the awaiter's microtask; a lookup keyed on the response's playId
56
+ * misses that window (seen live: playback-start without file). */
57
+ const playId = randomUUID();
58
+ const data = { urls, playId };
52
59
  if (seekOffset > 0) data.seekOffset = parseInt(seekOffset, 10);
53
- const { playId } = await this._request('play.start', data);
54
- return new Promise((resolve, reject) => {
60
+ const result = new Promise((resolve, reject) => {
55
61
  // file (the caller's original, untranslated path) rides on the
56
62
  // playback-start/stop events: FS parity — the say/play tasks match
57
63
  // events to plays by evt.file when there is no tts playback id
58
64
  this._pendingPlays.set(playId, { resolve, reject, file: files[0] });
59
65
  });
66
+ try {
67
+ await this._request('play.start', data);
68
+ } catch (err) {
69
+ this._pendingPlays.delete(playId);
70
+ throw err;
71
+ }
72
+ return result;
60
73
  }
61
74
 
62
75
  /** fsmrf api() passthrough: translate the FS api commands in use. */
@@ -528,13 +541,23 @@ class Endpoint extends EventEmitter {
528
541
  */
529
542
  function ttsVars(tts) {
530
543
  if (!tts) return {};
531
- return {
544
+ const out = {
532
545
  ...(tts.playbackId && {variable_tts_playback_id: tts.playbackId}),
533
546
  ...(tts.ttfbMs !== undefined && {variable_tts_time_to_first_byte_ms: String(tts.ttfbMs)}),
534
547
  ...(tts.cacheFilename && {variable_tts_cache_filename: tts.cacheFilename}),
535
548
  ...(tts.error && {variable_tts_error: tts.error}),
536
549
  ...(tts.responseCode !== undefined && {variable_tts_response_code: String(tts.responseCode)}),
537
550
  };
551
+ /* vendor dial/response metadata (request id, connect timings, voice):
552
+ * FS modules exposed these as tts_<vendor>_<field> channel variables
553
+ * and the feature-server turns every variable_tts_* into an otel span
554
+ * attribute */
555
+ if (tts.vendor && tts.info) {
556
+ for (const [k, v] of Object.entries(tts.info)) {
557
+ out[`variable_tts_${tts.vendor}_${k}`] = String(v);
558
+ }
559
+ }
560
+ return out;
538
561
  }
539
562
 
540
563
  module.exports = Endpoint;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/mrf",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "node --test",
@@ -97,7 +97,7 @@ class MockMediajam {
97
97
  case 'play.start': {
98
98
  const ep = this.endpoints.get(frame.ep);
99
99
  if (!ep) return fail('unknown_endpoint', frame.ep);
100
- const playId = randomUUID().slice(0, 8);
100
+ const playId = frame.data?.playId || randomUUID().slice(0, 8);
101
101
  res({ playId });
102
102
  this.send(socket, { t: 'evt', ep: frame.ep, evt: 'play.start', data: { playId } });
103
103
  const t = setTimeout(() => {