@voicethere/agent 0.7.11 → 0.7.12
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/dist/agent.js +24 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +24 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/runtime.d.ts +3 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +68 -1
- package/dist/runtime.js.map +1 -1
- package/dist/templates/echo/agent.js +26 -2
- package/dist/templates/echo-dc/agent.js +26 -2
- package/dist/templates/game-sync/agent.js +26 -2
- package/dist/templates/positional-tts/agent.js +26 -2
- package/dist/templates/recording-consent/agent.js +26 -2
- package/dist/templates/registry.d.ts.map +1 -1
- package/dist/templates/registry.js +2 -1
- package/dist/templates/registry.js.map +1 -1
- package/dist/templates/spatial-showcase/agent.js +253 -23
- package/dist/templates/voice-showcase/agent.js +26 -2
- package/dist/templates/voice-starter/agent.js +26 -2
- package/dist/templates/webhooks/agent.js +26 -2
- package/dist/templates/webhooks-redis/agent.js +26 -2
- package/package.json +4 -4
- package/templates/README.md +10 -10
- package/templates/spatial-showcase/agent.ts +171 -28
- package/templates/spatial-showcase/protocol.ts +3 -1
- package/templates/spatial-showcase/sine.ts +43 -0
|
@@ -152,6 +152,12 @@ function isPlayStopAckMessage(value) {
|
|
|
152
152
|
const msg = value;
|
|
153
153
|
return msg.type === "play_stop_ack" && typeof msg.requestId === "string";
|
|
154
154
|
}
|
|
155
|
+
function isPlayPoseAckMessage(value) {
|
|
156
|
+
if (!value || typeof value !== "object")
|
|
157
|
+
return false;
|
|
158
|
+
const msg = value;
|
|
159
|
+
return msg.type === "play_pose_ack" && typeof msg.requestId === "string";
|
|
160
|
+
}
|
|
155
161
|
function isRecordingControlAckMessage(value) {
|
|
156
162
|
if (!value || typeof value !== "object")
|
|
157
163
|
return false;
|
|
@@ -212,7 +218,7 @@ function isParentMessage(value) {
|
|
|
212
218
|
if (!value || typeof value !== "object")
|
|
213
219
|
return false;
|
|
214
220
|
const msg = value;
|
|
215
|
-
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
221
|
+
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "play_pose_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
216
222
|
}
|
|
217
223
|
function isSessionScopedParentMessage(value) {
|
|
218
224
|
return isParentMessage(value) && !isWebhookMessage(value);
|
|
@@ -235,7 +241,9 @@ var pendingRecordingAcks = /* @__PURE__ */ new Map();
|
|
|
235
241
|
var pendingPlayAcks = /* @__PURE__ */ new Map();
|
|
236
242
|
var pendingPlayStatusAcks = /* @__PURE__ */ new Map();
|
|
237
243
|
var pendingPlayStopAcks = /* @__PURE__ */ new Map();
|
|
244
|
+
var pendingPlayPoseAcks = /* @__PURE__ */ new Map();
|
|
238
245
|
var MIX_CONTROL_ACK_TIMEOUT_MS = 5e3;
|
|
246
|
+
var STT_CONTROL_ACK_TIMEOUT_MS = 5e3;
|
|
239
247
|
var pendingMixAcks = /* @__PURE__ */ new Map();
|
|
240
248
|
var pendingSttAcks = /* @__PURE__ */ new Map();
|
|
241
249
|
function handleRecordingControlAck(message) {
|
|
@@ -290,6 +298,19 @@ function handlePlayStopAck(message) {
|
|
|
290
298
|
requestId: message.requestId
|
|
291
299
|
});
|
|
292
300
|
}
|
|
301
|
+
function handlePlayPoseAck(message) {
|
|
302
|
+
const pending = pendingPlayPoseAcks.get(message.requestId);
|
|
303
|
+
if (!pending)
|
|
304
|
+
return;
|
|
305
|
+
clearTimeout(pending.timer);
|
|
306
|
+
pendingPlayPoseAcks.delete(message.requestId);
|
|
307
|
+
pending.resolve({
|
|
308
|
+
ok: message.ok,
|
|
309
|
+
playId: message.playId,
|
|
310
|
+
reason: message.reason,
|
|
311
|
+
requestId: message.requestId
|
|
312
|
+
});
|
|
313
|
+
}
|
|
293
314
|
function handleMixControlAck(message) {
|
|
294
315
|
const pending = pendingMixAcks.get(message.requestId);
|
|
295
316
|
if (!pending)
|
|
@@ -402,7 +423,7 @@ function sendParentMessage(message) {
|
|
|
402
423
|
process.send?.(message);
|
|
403
424
|
return;
|
|
404
425
|
}
|
|
405
|
-
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop") {
|
|
426
|
+
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop" || msgType === "play_pose") {
|
|
406
427
|
process.send?.(message);
|
|
407
428
|
return;
|
|
408
429
|
}
|
|
@@ -588,6 +609,10 @@ function defineAgent(handlers) {
|
|
|
588
609
|
handlePlayStopAck(message);
|
|
589
610
|
return;
|
|
590
611
|
}
|
|
612
|
+
if (isPlayPoseAckMessage(message)) {
|
|
613
|
+
handlePlayPoseAck(message);
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
591
616
|
if (isMixControlAckMessage(message)) {
|
|
592
617
|
handleMixControlAck(message);
|
|
593
618
|
return;
|
|
@@ -778,6 +803,26 @@ async function sendTtsPoseControl(action, payload) {
|
|
|
778
803
|
});
|
|
779
804
|
});
|
|
780
805
|
}
|
|
806
|
+
async function sendSttControl(options) {
|
|
807
|
+
const requestId = randomUUID();
|
|
808
|
+
if (!isVoicethereAgentChild()) {
|
|
809
|
+
return { ok: true, reason: "local_mock", requestId };
|
|
810
|
+
}
|
|
811
|
+
return new Promise((resolve) => {
|
|
812
|
+
const timer = setTimeout(() => {
|
|
813
|
+
pendingSttAcks.delete(requestId);
|
|
814
|
+
resolve({ ok: false, reason: "timeout", requestId });
|
|
815
|
+
}, STT_CONTROL_ACK_TIMEOUT_MS);
|
|
816
|
+
pendingSttAcks.set(requestId, { resolve, timer });
|
|
817
|
+
sendParentMessage({
|
|
818
|
+
type: "stt_control",
|
|
819
|
+
requestId,
|
|
820
|
+
enabled: options.enabled,
|
|
821
|
+
...options.clientId ? { clientId: options.clientId } : {},
|
|
822
|
+
...options.sessionId ? { sessionId: options.sessionId } : {}
|
|
823
|
+
});
|
|
824
|
+
});
|
|
825
|
+
}
|
|
781
826
|
function createMixGroup(options) {
|
|
782
827
|
return sendMixControl("create_group", {
|
|
783
828
|
groupId: options.id,
|
|
@@ -809,6 +854,9 @@ function setListenerMute(options) {
|
|
|
809
854
|
muted: options.muted
|
|
810
855
|
});
|
|
811
856
|
}
|
|
857
|
+
function setSttEnabled(options) {
|
|
858
|
+
return sendSttControl(options);
|
|
859
|
+
}
|
|
812
860
|
function validatePlayOptions(options) {
|
|
813
861
|
const requestId = randomUUID();
|
|
814
862
|
const url = options.url?.trim();
|
|
@@ -928,6 +976,36 @@ function getPlay(playId) {
|
|
|
928
976
|
function stopPlay(playId) {
|
|
929
977
|
return sendPlayStop(playId);
|
|
930
978
|
}
|
|
979
|
+
async function sendPlayPose(playId, pose) {
|
|
980
|
+
const requestId = randomUUID();
|
|
981
|
+
if (!playId?.trim() || !pose) {
|
|
982
|
+
return {
|
|
983
|
+
ok: false,
|
|
984
|
+
playId: playId ?? "",
|
|
985
|
+
reason: "invalid_payload",
|
|
986
|
+
requestId
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
if (!isVoicethereAgentChild()) {
|
|
990
|
+
return { ok: true, playId, reason: "local_mock", requestId };
|
|
991
|
+
}
|
|
992
|
+
return new Promise((resolve) => {
|
|
993
|
+
const timer = setTimeout(() => {
|
|
994
|
+
pendingPlayPoseAcks.delete(requestId);
|
|
995
|
+
resolve({ ok: false, playId, reason: "timeout", requestId });
|
|
996
|
+
}, PLAY_CONTROL_ACK_TIMEOUT_MS);
|
|
997
|
+
pendingPlayPoseAcks.set(requestId, { playId, resolve, timer });
|
|
998
|
+
sendParentMessage({
|
|
999
|
+
type: "play_pose",
|
|
1000
|
+
requestId,
|
|
1001
|
+
playId,
|
|
1002
|
+
pose
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
function setPlayPose(playId, pose) {
|
|
1007
|
+
return sendPlayPose(playId, pose);
|
|
1008
|
+
}
|
|
931
1009
|
function sendToClient(sessionId, payload) {
|
|
932
1010
|
sendParentMessage({ type: "send_to_client", sessionId, payload });
|
|
933
1011
|
}
|
|
@@ -1286,12 +1364,49 @@ var ProximityRoom = class {
|
|
|
1286
1364
|
}
|
|
1287
1365
|
};
|
|
1288
1366
|
|
|
1367
|
+
// templates/spatial-showcase/sine.ts
|
|
1368
|
+
var ORBIT_SINE_DURATION_MS = 2e3;
|
|
1369
|
+
var ORBIT_SINE_FREQUENCY_HZ = 440;
|
|
1370
|
+
var ORBIT_SINE_AMPLITUDE = 8e3;
|
|
1371
|
+
var ORBIT_SINE_INLINE_URL = "https://example.com/inline-orbit-sine.wav";
|
|
1372
|
+
function buildOrbitSineInlineClipBase64(durationMs = ORBIT_SINE_DURATION_MS, frequencyHz = ORBIT_SINE_FREQUENCY_HZ, amplitude = ORBIT_SINE_AMPLITUDE) {
|
|
1373
|
+
const sampleRate = 16e3;
|
|
1374
|
+
const channels = 1;
|
|
1375
|
+
const bytesPerSample = 2;
|
|
1376
|
+
const numSamples = Math.floor(sampleRate * durationMs / 1e3);
|
|
1377
|
+
const dataSize = numSamples * channels * bytesPerSample;
|
|
1378
|
+
const buffer = Buffer.alloc(44 + dataSize);
|
|
1379
|
+
buffer.write("RIFF", 0);
|
|
1380
|
+
buffer.writeUInt32LE(36 + dataSize, 4);
|
|
1381
|
+
buffer.write("WAVE", 8);
|
|
1382
|
+
buffer.write("fmt ", 12);
|
|
1383
|
+
buffer.writeUInt32LE(16, 16);
|
|
1384
|
+
buffer.writeUInt16LE(1, 20);
|
|
1385
|
+
buffer.writeUInt16LE(channels, 22);
|
|
1386
|
+
buffer.writeUInt32LE(sampleRate, 24);
|
|
1387
|
+
buffer.writeUInt32LE(sampleRate * channels * bytesPerSample, 28);
|
|
1388
|
+
buffer.writeUInt16LE(channels * bytesPerSample, 32);
|
|
1389
|
+
buffer.writeUInt16LE(16, 34);
|
|
1390
|
+
buffer.write("data", 36);
|
|
1391
|
+
buffer.writeUInt32LE(dataSize, 40);
|
|
1392
|
+
for (let i = 0; i < numSamples; i++) {
|
|
1393
|
+
const t = i / sampleRate;
|
|
1394
|
+
const sample = Math.round(
|
|
1395
|
+
amplitude * Math.sin(2 * Math.PI * frequencyHz * t)
|
|
1396
|
+
);
|
|
1397
|
+
buffer.writeInt16LE(sample, 44 + i * 2);
|
|
1398
|
+
}
|
|
1399
|
+
return buffer.toString("base64");
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1289
1402
|
// templates/spatial-showcase/agent.ts
|
|
1290
1403
|
var ORBIT_TICK_MS = 50;
|
|
1291
1404
|
var ORBIT_POSE_EMIT_MS = 100;
|
|
1292
1405
|
var ROOM_STATE_TICK_MS = 100;
|
|
1293
1406
|
var LOOP_PAD_POLL_MS = 250;
|
|
1294
|
-
var
|
|
1407
|
+
var ORBIT_SINE_POLL_MS = 250;
|
|
1408
|
+
var ORBIT_SINE_VOLUME = 0.25;
|
|
1409
|
+
var MAX_ACTIVE_PLAYS = 12;
|
|
1295
1410
|
var SHOWCASE_ROOM_GROUP_ID = "showcase-room";
|
|
1296
1411
|
var sessions = /* @__PURE__ */ new Map();
|
|
1297
1412
|
var proximityRoom = new ProximityRoom();
|
|
@@ -1314,12 +1429,13 @@ function ack(sessionId, action, extra) {
|
|
|
1314
1429
|
...extra
|
|
1315
1430
|
});
|
|
1316
1431
|
}
|
|
1317
|
-
function ackError(sessionId, action, error) {
|
|
1432
|
+
function ackError(sessionId, action, error, extra) {
|
|
1318
1433
|
sendToClient(sessionId, {
|
|
1319
1434
|
type: "showcase_ack",
|
|
1320
1435
|
action,
|
|
1321
1436
|
ok: false,
|
|
1322
|
-
error
|
|
1437
|
+
error,
|
|
1438
|
+
...extra?.clipId !== void 0 ? { clipId: extra.clipId } : {}
|
|
1323
1439
|
});
|
|
1324
1440
|
}
|
|
1325
1441
|
async function safeMixCall(sessionId, label, fn) {
|
|
@@ -1360,6 +1476,14 @@ function clearRoomStateTimer(state) {
|
|
|
1360
1476
|
state.roomStateTimer = void 0;
|
|
1361
1477
|
}
|
|
1362
1478
|
}
|
|
1479
|
+
function stopLoopPadsForClip(sessionId, state, clipId) {
|
|
1480
|
+
for (const [playId, pad] of [...state.loopPads.entries()]) {
|
|
1481
|
+
if (pad.clipId === clipId) {
|
|
1482
|
+
void stopPlay(playId);
|
|
1483
|
+
clearLoopPad(sessionId, state, playId);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1363
1487
|
function clearLoopPad(sessionId, state, playId) {
|
|
1364
1488
|
const timer = state.loopPollTimers.get(playId);
|
|
1365
1489
|
if (timer) {
|
|
@@ -1383,6 +1507,78 @@ function clearAllPlays(sessionId, state) {
|
|
|
1383
1507
|
state.loopPads.clear();
|
|
1384
1508
|
state.loopPollTimers.clear();
|
|
1385
1509
|
}
|
|
1510
|
+
function currentOrbitPose(state) {
|
|
1511
|
+
if (!state.orbitStartMs) {
|
|
1512
|
+
return orbitTtsPose(0, state.orbit);
|
|
1513
|
+
}
|
|
1514
|
+
const elapsedSec = (Date.now() - state.orbitStartMs) / 1e3;
|
|
1515
|
+
return orbitTtsPose(elapsedSec, state.orbit);
|
|
1516
|
+
}
|
|
1517
|
+
function clearOrbitSinePoll(state) {
|
|
1518
|
+
if (state.orbitSinePollTimer) {
|
|
1519
|
+
clearInterval(state.orbitSinePollTimer);
|
|
1520
|
+
state.orbitSinePollTimer = void 0;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
async function stopOrbitSine(state) {
|
|
1524
|
+
clearOrbitSinePoll(state);
|
|
1525
|
+
const playId = state.orbitSinePlayId;
|
|
1526
|
+
state.orbitSinePlayId = void 0;
|
|
1527
|
+
if (playId) {
|
|
1528
|
+
await stopPlay(playId);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
function startOrbitSineLoopPoll(sessionId, state) {
|
|
1532
|
+
clearOrbitSinePoll(state);
|
|
1533
|
+
const playId = state.orbitSinePlayId;
|
|
1534
|
+
if (!playId) {
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
state.orbitSinePollTimer = setInterval(() => {
|
|
1538
|
+
void (async () => {
|
|
1539
|
+
if (!state.orbitSinePlayId) {
|
|
1540
|
+
clearOrbitSinePoll(state);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
const status = await getPlay(state.orbitSinePlayId);
|
|
1544
|
+
if (!status.ok) {
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
if (status.status === "ended") {
|
|
1548
|
+
const replay = await play({
|
|
1549
|
+
url: ORBIT_SINE_INLINE_URL,
|
|
1550
|
+
bytes: buildOrbitSineInlineClipBase64(),
|
|
1551
|
+
sessionIds: [sessionId],
|
|
1552
|
+
volume: ORBIT_SINE_VOLUME,
|
|
1553
|
+
pose: currentOrbitPose(state)
|
|
1554
|
+
});
|
|
1555
|
+
if (replay.ok && replay.playId) {
|
|
1556
|
+
state.orbitSinePlayId = replay.playId;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
})();
|
|
1560
|
+
}, ORBIT_SINE_POLL_MS);
|
|
1561
|
+
}
|
|
1562
|
+
async function startOrbitSinePlay(sessionId, state) {
|
|
1563
|
+
await stopOrbitSine(state);
|
|
1564
|
+
const result = await play({
|
|
1565
|
+
url: ORBIT_SINE_INLINE_URL,
|
|
1566
|
+
bytes: buildOrbitSineInlineClipBase64(),
|
|
1567
|
+
sessionIds: [sessionId],
|
|
1568
|
+
volume: ORBIT_SINE_VOLUME,
|
|
1569
|
+
pose: currentOrbitPose(state)
|
|
1570
|
+
});
|
|
1571
|
+
if (!result.ok || !result.playId) {
|
|
1572
|
+
agentLog(
|
|
1573
|
+
"warn",
|
|
1574
|
+
`spatial-showcase orbit sine play failed: ${result.reason ?? "play_failed"}`,
|
|
1575
|
+
sessionId
|
|
1576
|
+
);
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
state.orbitSinePlayId = result.playId;
|
|
1580
|
+
startOrbitSineLoopPoll(sessionId, state);
|
|
1581
|
+
}
|
|
1386
1582
|
function emitOrbitPose(sessionId, state) {
|
|
1387
1583
|
if (!state.orbitStartMs) {
|
|
1388
1584
|
return;
|
|
@@ -1405,15 +1601,23 @@ function emitOrbitPose(sessionId, state) {
|
|
|
1405
1601
|
function startOrbitDemo(sessionId, state) {
|
|
1406
1602
|
stopOrbitInterval(state);
|
|
1407
1603
|
beginOrbitClock(state);
|
|
1604
|
+
void startOrbitSinePlay(sessionId, state);
|
|
1408
1605
|
state.orbitTimer = setInterval(() => {
|
|
1409
1606
|
if (state.orbit.paused || !state.orbitStartMs) {
|
|
1410
1607
|
return;
|
|
1411
1608
|
}
|
|
1412
|
-
const
|
|
1609
|
+
const pose = currentOrbitPose(state);
|
|
1610
|
+
if (state.orbitSinePlayId) {
|
|
1611
|
+
void safeMixCall(
|
|
1612
|
+
sessionId,
|
|
1613
|
+
"setPlayPose",
|
|
1614
|
+
() => setPlayPose(state.orbitSinePlayId, pose)
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1413
1617
|
void safeMixCall(
|
|
1414
1618
|
sessionId,
|
|
1415
1619
|
"setTtsPose",
|
|
1416
|
-
() => setTtsPose(sessionId,
|
|
1620
|
+
() => setTtsPose(sessionId, pose)
|
|
1417
1621
|
);
|
|
1418
1622
|
emitOrbitPose(sessionId, state);
|
|
1419
1623
|
}, ORBIT_TICK_MS);
|
|
@@ -1482,6 +1686,13 @@ async function startLoopPadPoll(sessionId, state, playId, pad) {
|
|
|
1482
1686
|
clearLoopPad(sessionId, state, playId);
|
|
1483
1687
|
state.playIds.add(replay.playId);
|
|
1484
1688
|
state.loopPads.set(replay.playId, pad);
|
|
1689
|
+
ack(sessionId, "pad", {
|
|
1690
|
+
playId: replay.playId,
|
|
1691
|
+
clipId: pad.clipId,
|
|
1692
|
+
x: pad.x,
|
|
1693
|
+
z: pad.z,
|
|
1694
|
+
...pad.placement !== void 0 ? { placement: pad.placement } : {}
|
|
1695
|
+
});
|
|
1485
1696
|
void startLoopPadPoll(sessionId, state, replay.playId, pad);
|
|
1486
1697
|
}
|
|
1487
1698
|
} else if (status.status) {
|
|
@@ -1496,21 +1707,24 @@ async function startLoopPadPoll(sessionId, state, playId, pad) {
|
|
|
1496
1707
|
state.loopPollTimers.set(playId, timer);
|
|
1497
1708
|
}
|
|
1498
1709
|
async function handlePadPlay(sessionId, state, clipId, x, z, volume, placement) {
|
|
1499
|
-
if (state.playIds.size >= MAX_ACTIVE_PLAYS) {
|
|
1500
|
-
ackError(sessionId, "pad", "busy");
|
|
1501
|
-
return;
|
|
1502
|
-
}
|
|
1503
1710
|
const assetOrigin = state.assetOrigin;
|
|
1504
1711
|
if (!assetOrigin) {
|
|
1505
|
-
ackError(sessionId, "pad", "missing_asset_origin");
|
|
1712
|
+
ackError(sessionId, "pad", "missing_asset_origin", { clipId });
|
|
1506
1713
|
return;
|
|
1507
1714
|
}
|
|
1508
1715
|
const url = resolveClipUrl(assetOrigin, clipId);
|
|
1509
1716
|
if (!url) {
|
|
1510
|
-
ackError(sessionId, "pad", "invalid_asset_origin");
|
|
1717
|
+
ackError(sessionId, "pad", "invalid_asset_origin", { clipId });
|
|
1511
1718
|
return;
|
|
1512
1719
|
}
|
|
1513
1720
|
const sound = SHOWCASE_SOUND_FILES[clipId];
|
|
1721
|
+
if (sound.loop) {
|
|
1722
|
+
stopLoopPadsForClip(sessionId, state, clipId);
|
|
1723
|
+
}
|
|
1724
|
+
if (state.playIds.size >= MAX_ACTIVE_PLAYS) {
|
|
1725
|
+
ackError(sessionId, "pad", "busy", { clipId });
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1514
1728
|
const playVolume = volume ?? sound.defaultVolume;
|
|
1515
1729
|
const options = {
|
|
1516
1730
|
url,
|
|
@@ -1520,11 +1734,17 @@ async function handlePadPlay(sessionId, state, clipId, x, z, volume, placement)
|
|
|
1520
1734
|
};
|
|
1521
1735
|
const result = await play(options);
|
|
1522
1736
|
if (!result.ok || !result.playId) {
|
|
1523
|
-
ackError(sessionId, "pad", result.reason ?? "play_failed");
|
|
1737
|
+
ackError(sessionId, "pad", result.reason ?? "play_failed", { clipId });
|
|
1524
1738
|
return;
|
|
1525
1739
|
}
|
|
1526
1740
|
state.playIds.add(result.playId);
|
|
1527
|
-
ack(sessionId, "pad", {
|
|
1741
|
+
ack(sessionId, "pad", {
|
|
1742
|
+
playId: result.playId,
|
|
1743
|
+
clipId,
|
|
1744
|
+
x,
|
|
1745
|
+
z,
|
|
1746
|
+
...placement !== void 0 ? { placement } : {}
|
|
1747
|
+
});
|
|
1528
1748
|
if (sound.loop) {
|
|
1529
1749
|
const pad = {
|
|
1530
1750
|
clipId,
|
|
@@ -1553,9 +1773,15 @@ async function handleJoin(sessionId, demo, assetOrigin) {
|
|
|
1553
1773
|
}
|
|
1554
1774
|
ack(sessionId, "join");
|
|
1555
1775
|
switch (demo) {
|
|
1556
|
-
case "orbit":
|
|
1776
|
+
case "orbit": {
|
|
1777
|
+
void safeMixCall(
|
|
1778
|
+
sessionId,
|
|
1779
|
+
"setSttEnabled",
|
|
1780
|
+
() => setSttEnabled({ enabled: false, sessionId })
|
|
1781
|
+
);
|
|
1557
1782
|
startOrbitDemo(sessionId, state);
|
|
1558
1783
|
break;
|
|
1784
|
+
}
|
|
1559
1785
|
case "soundboard":
|
|
1560
1786
|
break;
|
|
1561
1787
|
case "proximity": {
|
|
@@ -1600,8 +1826,14 @@ function teardownSession(sessionId) {
|
|
|
1600
1826
|
}
|
|
1601
1827
|
resetOrbitSession(state);
|
|
1602
1828
|
clearRoomStateTimer(state);
|
|
1829
|
+
void stopOrbitSine(state);
|
|
1603
1830
|
clearAllPlays(sessionId, state);
|
|
1604
1831
|
void safeMixCall(sessionId, "clearTtsPose", () => clearTtsPose(sessionId));
|
|
1832
|
+
void safeMixCall(
|
|
1833
|
+
sessionId,
|
|
1834
|
+
"setSttEnabled",
|
|
1835
|
+
() => setSttEnabled({ enabled: true, sessionId })
|
|
1836
|
+
);
|
|
1605
1837
|
if (state.inProximityRoom) {
|
|
1606
1838
|
proximityRoom.leave(sessionId);
|
|
1607
1839
|
void safeMixCall(
|
|
@@ -1666,6 +1898,10 @@ async function dispatchMessage(sessionId, message) {
|
|
|
1666
1898
|
ackError(sessionId, "pad", "wrong_demo");
|
|
1667
1899
|
return;
|
|
1668
1900
|
}
|
|
1901
|
+
if (!isShowcaseClipId(message.clipId)) {
|
|
1902
|
+
ackError(sessionId, "pad", "invalid_clip_id");
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1669
1905
|
await handlePadPlay(
|
|
1670
1906
|
sessionId,
|
|
1671
1907
|
state,
|
|
@@ -1784,13 +2020,6 @@ defineAgent({
|
|
|
1784
2020
|
ok: true
|
|
1785
2021
|
});
|
|
1786
2022
|
},
|
|
1787
|
-
onUserSpeechFinal({ sessionId, text }) {
|
|
1788
|
-
const state = sessions.get(sessionId);
|
|
1789
|
-
if (!state || state.demo !== "orbit") {
|
|
1790
|
-
return;
|
|
1791
|
-
}
|
|
1792
|
-
speak(sessionId, `You said: ${text}`);
|
|
1793
|
-
},
|
|
1794
2023
|
onDataChannelMessage(ctx) {
|
|
1795
2024
|
const message = parseShowcaseMessage(ctx.message);
|
|
1796
2025
|
if (!message) {
|
|
@@ -1804,5 +2033,6 @@ defineAgent({
|
|
|
1804
2033
|
}
|
|
1805
2034
|
});
|
|
1806
2035
|
export {
|
|
2036
|
+
MAX_ACTIVE_PLAYS,
|
|
1807
2037
|
handlePadPlay
|
|
1808
2038
|
};
|
|
@@ -148,6 +148,12 @@ function isPlayStopAckMessage(value) {
|
|
|
148
148
|
const msg = value;
|
|
149
149
|
return msg.type === "play_stop_ack" && typeof msg.requestId === "string";
|
|
150
150
|
}
|
|
151
|
+
function isPlayPoseAckMessage(value) {
|
|
152
|
+
if (!value || typeof value !== "object")
|
|
153
|
+
return false;
|
|
154
|
+
const msg = value;
|
|
155
|
+
return msg.type === "play_pose_ack" && typeof msg.requestId === "string";
|
|
156
|
+
}
|
|
151
157
|
function isRecordingControlAckMessage(value) {
|
|
152
158
|
if (!value || typeof value !== "object")
|
|
153
159
|
return false;
|
|
@@ -208,7 +214,7 @@ function isParentMessage(value) {
|
|
|
208
214
|
if (!value || typeof value !== "object")
|
|
209
215
|
return false;
|
|
210
216
|
const msg = value;
|
|
211
|
-
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
217
|
+
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "play_pose_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
212
218
|
}
|
|
213
219
|
function isSessionScopedParentMessage(value) {
|
|
214
220
|
return isParentMessage(value) && !isWebhookMessage(value);
|
|
@@ -230,6 +236,7 @@ var pendingRecordingAcks = /* @__PURE__ */ new Map();
|
|
|
230
236
|
var pendingPlayAcks = /* @__PURE__ */ new Map();
|
|
231
237
|
var pendingPlayStatusAcks = /* @__PURE__ */ new Map();
|
|
232
238
|
var pendingPlayStopAcks = /* @__PURE__ */ new Map();
|
|
239
|
+
var pendingPlayPoseAcks = /* @__PURE__ */ new Map();
|
|
233
240
|
var pendingMixAcks = /* @__PURE__ */ new Map();
|
|
234
241
|
var pendingSttAcks = /* @__PURE__ */ new Map();
|
|
235
242
|
function handleRecordingControlAck(message) {
|
|
@@ -284,6 +291,19 @@ function handlePlayStopAck(message) {
|
|
|
284
291
|
requestId: message.requestId
|
|
285
292
|
});
|
|
286
293
|
}
|
|
294
|
+
function handlePlayPoseAck(message) {
|
|
295
|
+
const pending = pendingPlayPoseAcks.get(message.requestId);
|
|
296
|
+
if (!pending)
|
|
297
|
+
return;
|
|
298
|
+
clearTimeout(pending.timer);
|
|
299
|
+
pendingPlayPoseAcks.delete(message.requestId);
|
|
300
|
+
pending.resolve({
|
|
301
|
+
ok: message.ok,
|
|
302
|
+
playId: message.playId,
|
|
303
|
+
reason: message.reason,
|
|
304
|
+
requestId: message.requestId
|
|
305
|
+
});
|
|
306
|
+
}
|
|
287
307
|
function handleMixControlAck(message) {
|
|
288
308
|
const pending = pendingMixAcks.get(message.requestId);
|
|
289
309
|
if (!pending)
|
|
@@ -369,7 +389,7 @@ function sendParentMessage(message) {
|
|
|
369
389
|
process.send?.(message);
|
|
370
390
|
return;
|
|
371
391
|
}
|
|
372
|
-
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop") {
|
|
392
|
+
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop" || msgType === "play_pose") {
|
|
373
393
|
process.send?.(message);
|
|
374
394
|
return;
|
|
375
395
|
}
|
|
@@ -555,6 +575,10 @@ function defineAgent(handlers) {
|
|
|
555
575
|
handlePlayStopAck(message);
|
|
556
576
|
return;
|
|
557
577
|
}
|
|
578
|
+
if (isPlayPoseAckMessage(message)) {
|
|
579
|
+
handlePlayPoseAck(message);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
558
582
|
if (isMixControlAckMessage(message)) {
|
|
559
583
|
handleMixControlAck(message);
|
|
560
584
|
return;
|
|
@@ -148,6 +148,12 @@ function isPlayStopAckMessage(value) {
|
|
|
148
148
|
const msg = value;
|
|
149
149
|
return msg.type === "play_stop_ack" && typeof msg.requestId === "string";
|
|
150
150
|
}
|
|
151
|
+
function isPlayPoseAckMessage(value) {
|
|
152
|
+
if (!value || typeof value !== "object")
|
|
153
|
+
return false;
|
|
154
|
+
const msg = value;
|
|
155
|
+
return msg.type === "play_pose_ack" && typeof msg.requestId === "string";
|
|
156
|
+
}
|
|
151
157
|
function isRecordingControlAckMessage(value) {
|
|
152
158
|
if (!value || typeof value !== "object")
|
|
153
159
|
return false;
|
|
@@ -208,7 +214,7 @@ function isParentMessage(value) {
|
|
|
208
214
|
if (!value || typeof value !== "object")
|
|
209
215
|
return false;
|
|
210
216
|
const msg = value;
|
|
211
|
-
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
217
|
+
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "play_pose_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
212
218
|
}
|
|
213
219
|
function isSessionScopedParentMessage(value) {
|
|
214
220
|
return isParentMessage(value) && !isWebhookMessage(value);
|
|
@@ -230,6 +236,7 @@ var pendingRecordingAcks = /* @__PURE__ */ new Map();
|
|
|
230
236
|
var pendingPlayAcks = /* @__PURE__ */ new Map();
|
|
231
237
|
var pendingPlayStatusAcks = /* @__PURE__ */ new Map();
|
|
232
238
|
var pendingPlayStopAcks = /* @__PURE__ */ new Map();
|
|
239
|
+
var pendingPlayPoseAcks = /* @__PURE__ */ new Map();
|
|
233
240
|
var pendingMixAcks = /* @__PURE__ */ new Map();
|
|
234
241
|
var pendingSttAcks = /* @__PURE__ */ new Map();
|
|
235
242
|
function handleRecordingControlAck(message) {
|
|
@@ -284,6 +291,19 @@ function handlePlayStopAck(message) {
|
|
|
284
291
|
requestId: message.requestId
|
|
285
292
|
});
|
|
286
293
|
}
|
|
294
|
+
function handlePlayPoseAck(message) {
|
|
295
|
+
const pending = pendingPlayPoseAcks.get(message.requestId);
|
|
296
|
+
if (!pending)
|
|
297
|
+
return;
|
|
298
|
+
clearTimeout(pending.timer);
|
|
299
|
+
pendingPlayPoseAcks.delete(message.requestId);
|
|
300
|
+
pending.resolve({
|
|
301
|
+
ok: message.ok,
|
|
302
|
+
playId: message.playId,
|
|
303
|
+
reason: message.reason,
|
|
304
|
+
requestId: message.requestId
|
|
305
|
+
});
|
|
306
|
+
}
|
|
287
307
|
function handleMixControlAck(message) {
|
|
288
308
|
const pending = pendingMixAcks.get(message.requestId);
|
|
289
309
|
if (!pending)
|
|
@@ -369,7 +389,7 @@ function sendParentMessage(message) {
|
|
|
369
389
|
process.send?.(message);
|
|
370
390
|
return;
|
|
371
391
|
}
|
|
372
|
-
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop") {
|
|
392
|
+
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop" || msgType === "play_pose") {
|
|
373
393
|
process.send?.(message);
|
|
374
394
|
return;
|
|
375
395
|
}
|
|
@@ -555,6 +575,10 @@ function defineAgent(handlers) {
|
|
|
555
575
|
handlePlayStopAck(message);
|
|
556
576
|
return;
|
|
557
577
|
}
|
|
578
|
+
if (isPlayPoseAckMessage(message)) {
|
|
579
|
+
handlePlayPoseAck(message);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
558
582
|
if (isMixControlAckMessage(message)) {
|
|
559
583
|
handleMixControlAck(message);
|
|
560
584
|
return;
|
|
@@ -151,6 +151,12 @@ function isPlayStopAckMessage(value) {
|
|
|
151
151
|
const msg = value;
|
|
152
152
|
return msg.type === "play_stop_ack" && typeof msg.requestId === "string";
|
|
153
153
|
}
|
|
154
|
+
function isPlayPoseAckMessage(value) {
|
|
155
|
+
if (!value || typeof value !== "object")
|
|
156
|
+
return false;
|
|
157
|
+
const msg = value;
|
|
158
|
+
return msg.type === "play_pose_ack" && typeof msg.requestId === "string";
|
|
159
|
+
}
|
|
154
160
|
function isRecordingControlAckMessage(value) {
|
|
155
161
|
if (!value || typeof value !== "object")
|
|
156
162
|
return false;
|
|
@@ -211,7 +217,7 @@ function isParentMessage(value) {
|
|
|
211
217
|
if (!value || typeof value !== "object")
|
|
212
218
|
return false;
|
|
213
219
|
const msg = value;
|
|
214
|
-
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
220
|
+
return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "play_ack" || msg.type === "play_status_ack" || msg.type === "play_stop_ack" || msg.type === "play_pose_ack" || msg.type === "mix_control_ack" || msg.type === "stt_control_ack" || msg.type === "webhook";
|
|
215
221
|
}
|
|
216
222
|
function isSessionScopedParentMessage(value) {
|
|
217
223
|
return isParentMessage(value) && !isWebhookMessage(value);
|
|
@@ -233,6 +239,7 @@ var pendingRecordingAcks = /* @__PURE__ */ new Map();
|
|
|
233
239
|
var pendingPlayAcks = /* @__PURE__ */ new Map();
|
|
234
240
|
var pendingPlayStatusAcks = /* @__PURE__ */ new Map();
|
|
235
241
|
var pendingPlayStopAcks = /* @__PURE__ */ new Map();
|
|
242
|
+
var pendingPlayPoseAcks = /* @__PURE__ */ new Map();
|
|
236
243
|
var pendingMixAcks = /* @__PURE__ */ new Map();
|
|
237
244
|
var pendingSttAcks = /* @__PURE__ */ new Map();
|
|
238
245
|
function handleRecordingControlAck(message) {
|
|
@@ -287,6 +294,19 @@ function handlePlayStopAck(message) {
|
|
|
287
294
|
requestId: message.requestId
|
|
288
295
|
});
|
|
289
296
|
}
|
|
297
|
+
function handlePlayPoseAck(message) {
|
|
298
|
+
const pending = pendingPlayPoseAcks.get(message.requestId);
|
|
299
|
+
if (!pending)
|
|
300
|
+
return;
|
|
301
|
+
clearTimeout(pending.timer);
|
|
302
|
+
pendingPlayPoseAcks.delete(message.requestId);
|
|
303
|
+
pending.resolve({
|
|
304
|
+
ok: message.ok,
|
|
305
|
+
playId: message.playId,
|
|
306
|
+
reason: message.reason,
|
|
307
|
+
requestId: message.requestId
|
|
308
|
+
});
|
|
309
|
+
}
|
|
290
310
|
function handleMixControlAck(message) {
|
|
291
311
|
const pending = pendingMixAcks.get(message.requestId);
|
|
292
312
|
if (!pending)
|
|
@@ -372,7 +392,7 @@ function sendParentMessage(message) {
|
|
|
372
392
|
process.send?.(message);
|
|
373
393
|
return;
|
|
374
394
|
}
|
|
375
|
-
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop") {
|
|
395
|
+
if (msgType === "play" || msgType === "play_status" || msgType === "play_stop" || msgType === "play_pose") {
|
|
376
396
|
process.send?.(message);
|
|
377
397
|
return;
|
|
378
398
|
}
|
|
@@ -558,6 +578,10 @@ function defineAgent(handlers) {
|
|
|
558
578
|
handlePlayStopAck(message);
|
|
559
579
|
return;
|
|
560
580
|
}
|
|
581
|
+
if (isPlayPoseAckMessage(message)) {
|
|
582
|
+
handlePlayPoseAck(message);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
561
585
|
if (isMixControlAckMessage(message)) {
|
|
562
586
|
handleMixControlAck(message);
|
|
563
587
|
return;
|