@voicethere/agent 0.7.10 → 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 +255 -24
- 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 +188 -33
- 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,18 +1601,27 @@ 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);
|
|
1624
|
+
emitOrbitPose(sessionId, state);
|
|
1420
1625
|
speak(sessionId, "I'll circle around you.");
|
|
1421
1626
|
}
|
|
1422
1627
|
function broadcastRoomStateIfChanged() {
|
|
@@ -1481,6 +1686,13 @@ async function startLoopPadPoll(sessionId, state, playId, pad) {
|
|
|
1481
1686
|
clearLoopPad(sessionId, state, playId);
|
|
1482
1687
|
state.playIds.add(replay.playId);
|
|
1483
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
|
+
});
|
|
1484
1696
|
void startLoopPadPoll(sessionId, state, replay.playId, pad);
|
|
1485
1697
|
}
|
|
1486
1698
|
} else if (status.status) {
|
|
@@ -1495,21 +1707,24 @@ async function startLoopPadPoll(sessionId, state, playId, pad) {
|
|
|
1495
1707
|
state.loopPollTimers.set(playId, timer);
|
|
1496
1708
|
}
|
|
1497
1709
|
async function handlePadPlay(sessionId, state, clipId, x, z, volume, placement) {
|
|
1498
|
-
if (state.playIds.size >= MAX_ACTIVE_PLAYS) {
|
|
1499
|
-
ackError(sessionId, "pad", "busy");
|
|
1500
|
-
return;
|
|
1501
|
-
}
|
|
1502
1710
|
const assetOrigin = state.assetOrigin;
|
|
1503
1711
|
if (!assetOrigin) {
|
|
1504
|
-
ackError(sessionId, "pad", "missing_asset_origin");
|
|
1712
|
+
ackError(sessionId, "pad", "missing_asset_origin", { clipId });
|
|
1505
1713
|
return;
|
|
1506
1714
|
}
|
|
1507
1715
|
const url = resolveClipUrl(assetOrigin, clipId);
|
|
1508
1716
|
if (!url) {
|
|
1509
|
-
ackError(sessionId, "pad", "invalid_asset_origin");
|
|
1717
|
+
ackError(sessionId, "pad", "invalid_asset_origin", { clipId });
|
|
1510
1718
|
return;
|
|
1511
1719
|
}
|
|
1512
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
|
+
}
|
|
1513
1728
|
const playVolume = volume ?? sound.defaultVolume;
|
|
1514
1729
|
const options = {
|
|
1515
1730
|
url,
|
|
@@ -1519,11 +1734,17 @@ async function handlePadPlay(sessionId, state, clipId, x, z, volume, placement)
|
|
|
1519
1734
|
};
|
|
1520
1735
|
const result = await play(options);
|
|
1521
1736
|
if (!result.ok || !result.playId) {
|
|
1522
|
-
ackError(sessionId, "pad", result.reason ?? "play_failed");
|
|
1737
|
+
ackError(sessionId, "pad", result.reason ?? "play_failed", { clipId });
|
|
1523
1738
|
return;
|
|
1524
1739
|
}
|
|
1525
1740
|
state.playIds.add(result.playId);
|
|
1526
|
-
ack(sessionId, "pad", {
|
|
1741
|
+
ack(sessionId, "pad", {
|
|
1742
|
+
playId: result.playId,
|
|
1743
|
+
clipId,
|
|
1744
|
+
x,
|
|
1745
|
+
z,
|
|
1746
|
+
...placement !== void 0 ? { placement } : {}
|
|
1747
|
+
});
|
|
1527
1748
|
if (sound.loop) {
|
|
1528
1749
|
const pad = {
|
|
1529
1750
|
clipId,
|
|
@@ -1552,9 +1773,15 @@ async function handleJoin(sessionId, demo, assetOrigin) {
|
|
|
1552
1773
|
}
|
|
1553
1774
|
ack(sessionId, "join");
|
|
1554
1775
|
switch (demo) {
|
|
1555
|
-
case "orbit":
|
|
1776
|
+
case "orbit": {
|
|
1777
|
+
void safeMixCall(
|
|
1778
|
+
sessionId,
|
|
1779
|
+
"setSttEnabled",
|
|
1780
|
+
() => setSttEnabled({ enabled: false, sessionId })
|
|
1781
|
+
);
|
|
1556
1782
|
startOrbitDemo(sessionId, state);
|
|
1557
1783
|
break;
|
|
1784
|
+
}
|
|
1558
1785
|
case "soundboard":
|
|
1559
1786
|
break;
|
|
1560
1787
|
case "proximity": {
|
|
@@ -1581,13 +1808,13 @@ async function handleJoin(sessionId, demo, assetOrigin) {
|
|
|
1581
1808
|
return;
|
|
1582
1809
|
}
|
|
1583
1810
|
state.inProximityRoom = true;
|
|
1811
|
+
startProximityRoomBroadcast(sessionId, state);
|
|
1584
1812
|
speak(sessionId, "Welcome to the proximity room.");
|
|
1585
1813
|
await safeMixCall(
|
|
1586
1814
|
sessionId,
|
|
1587
1815
|
"setTtsPose",
|
|
1588
1816
|
() => setTtsPose(sessionId, poseAt(0, 0))
|
|
1589
1817
|
);
|
|
1590
|
-
startProximityRoomBroadcast(sessionId, state);
|
|
1591
1818
|
break;
|
|
1592
1819
|
}
|
|
1593
1820
|
}
|
|
@@ -1599,8 +1826,14 @@ function teardownSession(sessionId) {
|
|
|
1599
1826
|
}
|
|
1600
1827
|
resetOrbitSession(state);
|
|
1601
1828
|
clearRoomStateTimer(state);
|
|
1829
|
+
void stopOrbitSine(state);
|
|
1602
1830
|
clearAllPlays(sessionId, state);
|
|
1603
1831
|
void safeMixCall(sessionId, "clearTtsPose", () => clearTtsPose(sessionId));
|
|
1832
|
+
void safeMixCall(
|
|
1833
|
+
sessionId,
|
|
1834
|
+
"setSttEnabled",
|
|
1835
|
+
() => setSttEnabled({ enabled: true, sessionId })
|
|
1836
|
+
);
|
|
1604
1837
|
if (state.inProximityRoom) {
|
|
1605
1838
|
proximityRoom.leave(sessionId);
|
|
1606
1839
|
void safeMixCall(
|
|
@@ -1665,6 +1898,10 @@ async function dispatchMessage(sessionId, message) {
|
|
|
1665
1898
|
ackError(sessionId, "pad", "wrong_demo");
|
|
1666
1899
|
return;
|
|
1667
1900
|
}
|
|
1901
|
+
if (!isShowcaseClipId(message.clipId)) {
|
|
1902
|
+
ackError(sessionId, "pad", "invalid_clip_id");
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1668
1905
|
await handlePadPlay(
|
|
1669
1906
|
sessionId,
|
|
1670
1907
|
state,
|
|
@@ -1783,13 +2020,6 @@ defineAgent({
|
|
|
1783
2020
|
ok: true
|
|
1784
2021
|
});
|
|
1785
2022
|
},
|
|
1786
|
-
onUserSpeechFinal({ sessionId, text }) {
|
|
1787
|
-
const state = sessions.get(sessionId);
|
|
1788
|
-
if (!state || state.demo !== "orbit") {
|
|
1789
|
-
return;
|
|
1790
|
-
}
|
|
1791
|
-
speak(sessionId, `You said: ${text}`);
|
|
1792
|
-
},
|
|
1793
2023
|
onDataChannelMessage(ctx) {
|
|
1794
2024
|
const message = parseShowcaseMessage(ctx.message);
|
|
1795
2025
|
if (!message) {
|
|
@@ -1803,5 +2033,6 @@ defineAgent({
|
|
|
1803
2033
|
}
|
|
1804
2034
|
});
|
|
1805
2035
|
export {
|
|
2036
|
+
MAX_ACTIVE_PLAYS,
|
|
1806
2037
|
handlePadPlay
|
|
1807
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;
|