@hivegpt/hiveai-angular 0.0.457 → 0.0.459
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/bundles/hivegpt-hiveai-angular.umd.js +90 -17
- package/bundles/hivegpt-hiveai-angular.umd.js.map +1 -1
- package/bundles/hivegpt-hiveai-angular.umd.min.js +1 -1
- package/bundles/hivegpt-hiveai-angular.umd.min.js.map +1 -1
- package/esm2015/lib/components/voice-agent/services/daily-voice-client.service.js +90 -18
- package/fesm2015/hivegpt-hiveai-angular.js +89 -17
- package/fesm2015/hivegpt-hiveai-angular.js.map +1 -1
- package/hivegpt-hiveai-angular.metadata.json +1 -1
- package/lib/components/voice-agent/services/daily-voice-client.service.d.ts +11 -5
- package/lib/components/voice-agent/services/daily-voice-client.service.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1264,13 +1264,10 @@
|
|
|
1264
1264
|
* - Create and manage Daily CallObject
|
|
1265
1265
|
* - Join Daily room using room_url
|
|
1266
1266
|
* - Handle mic capture + speaker playback
|
|
1267
|
-
* -
|
|
1268
|
-
*
|
|
1267
|
+
* - Bot speaking detection via AnalyserNode on remote track (instant)
|
|
1268
|
+
* - User speaking detection via active-speaker-change
|
|
1269
1269
|
* - Expose speaking$ (bot speaking), userSpeaking$ (user speaking), micMuted$
|
|
1270
1270
|
* - Expose localStream$ for waveform visualization (AudioAnalyzerService)
|
|
1271
|
-
*
|
|
1272
|
-
* Speaking state flips immediately when agent audio starts playing.
|
|
1273
|
-
* If user speaks while bot is talking, state switches to listening.
|
|
1274
1271
|
*/
|
|
1275
1272
|
var DailyVoiceClientService = /** @class */ (function () {
|
|
1276
1273
|
function DailyVoiceClientService(ngZone) {
|
|
@@ -1280,6 +1277,9 @@
|
|
|
1280
1277
|
this.localSessionId = null;
|
|
1281
1278
|
/** Explicit playback of remote (bot) audio; required in some browsers. */
|
|
1282
1279
|
this.remoteAudioElement = null;
|
|
1280
|
+
/** AnalyserNode-based remote audio monitor for instant bot speaking detection. */
|
|
1281
|
+
this.remoteAudioContext = null;
|
|
1282
|
+
this.remoteSpeakingRAF = null;
|
|
1283
1283
|
this.speakingSubject = new rxjs.BehaviorSubject(false);
|
|
1284
1284
|
this.userSpeakingSubject = new rxjs.BehaviorSubject(false);
|
|
1285
1285
|
this.micMutedSubject = new rxjs.BehaviorSubject(false);
|
|
@@ -1353,25 +1353,21 @@
|
|
|
1353
1353
|
};
|
|
1354
1354
|
DailyVoiceClientService.prototype.setupEventHandlers = function (call) {
|
|
1355
1355
|
var _this = this;
|
|
1356
|
-
// active-speaker-change:
|
|
1357
|
-
//
|
|
1356
|
+
// active-speaker-change: used ONLY for user speaking detection.
|
|
1357
|
+
// Bot speaking is detected by our own AnalyserNode (instant, no debounce).
|
|
1358
1358
|
call.on('active-speaker-change', function (event) {
|
|
1359
1359
|
_this.ngZone.run(function () {
|
|
1360
1360
|
var _a;
|
|
1361
1361
|
var peerId = (_a = event === null || event === void 0 ? void 0 : event.activeSpeaker) === null || _a === void 0 ? void 0 : _a.peerId;
|
|
1362
1362
|
if (!peerId || !_this.localSessionId) {
|
|
1363
|
-
_this.speakingSubject.next(false);
|
|
1364
1363
|
_this.userSpeakingSubject.next(false);
|
|
1365
1364
|
return;
|
|
1366
1365
|
}
|
|
1367
1366
|
var isLocal = peerId === _this.localSessionId;
|
|
1368
1367
|
_this.userSpeakingSubject.next(isLocal);
|
|
1369
|
-
_this.speakingSubject.next(!isLocal);
|
|
1370
1368
|
});
|
|
1371
1369
|
});
|
|
1372
|
-
// track-started / track-stopped:
|
|
1373
|
-
// Browsers often do not auto-play remote WebRTC audio; attaching to an HTMLAudioElement and
|
|
1374
|
-
// calling play() ensures the user hears the agent.
|
|
1370
|
+
// track-started / track-stopped: set up remote audio playback + AnalyserNode monitor.
|
|
1375
1371
|
call.on('track-started', function (event) {
|
|
1376
1372
|
_this.ngZone.run(function () {
|
|
1377
1373
|
var _a, _b, _c, _d;
|
|
@@ -1379,11 +1375,11 @@
|
|
|
1379
1375
|
var type = (_a = event === null || event === void 0 ? void 0 : event.type) !== null && _a !== void 0 ? _a : (_b = event === null || event === void 0 ? void 0 : event.track) === null || _b === void 0 ? void 0 : _b.kind;
|
|
1380
1376
|
var track = event === null || event === void 0 ? void 0 : event.track;
|
|
1381
1377
|
if (p && !p.local && type === 'audio') {
|
|
1382
|
-
console.log("[VoiceDebug] Got audio track from backend (track-started) \u2014 " + new Date().toISOString());
|
|
1383
|
-
_this.speakingSubject.next(true);
|
|
1378
|
+
console.log("[VoiceDebug] Got audio track from backend (track-started) \u2014 readyState=" + (track === null || track === void 0 ? void 0 : track.readyState) + ", muted=" + (track === null || track === void 0 ? void 0 : track.muted) + " \u2014 " + new Date().toISOString());
|
|
1384
1379
|
var audioTrack = track !== null && track !== void 0 ? track : (_d = (_c = p.tracks) === null || _c === void 0 ? void 0 : _c.audio) === null || _d === void 0 ? void 0 : _d.track;
|
|
1385
1380
|
if (audioTrack && typeof audioTrack === 'object') {
|
|
1386
1381
|
_this.playRemoteTrack(audioTrack);
|
|
1382
|
+
_this.monitorRemoteAudio(audioTrack);
|
|
1387
1383
|
}
|
|
1388
1384
|
}
|
|
1389
1385
|
});
|
|
@@ -1394,7 +1390,7 @@
|
|
|
1394
1390
|
var p = event === null || event === void 0 ? void 0 : event.participant;
|
|
1395
1391
|
var type = (_a = event === null || event === void 0 ? void 0 : event.type) !== null && _a !== void 0 ? _a : (_b = event === null || event === void 0 ? void 0 : event.track) === null || _b === void 0 ? void 0 : _b.kind;
|
|
1396
1392
|
if (p && !p.local && type === 'audio') {
|
|
1397
|
-
_this.
|
|
1393
|
+
_this.stopRemoteAudioMonitor();
|
|
1398
1394
|
_this.stopRemoteAudio();
|
|
1399
1395
|
}
|
|
1400
1396
|
});
|
|
@@ -1417,14 +1413,30 @@
|
|
|
1417
1413
|
DailyVoiceClientService.prototype.playRemoteTrack = function (track) {
|
|
1418
1414
|
this.stopRemoteAudio();
|
|
1419
1415
|
try {
|
|
1416
|
+
console.log("[VoiceDebug] playRemoteTrack called \u2014 track.readyState=" + track.readyState + ", track.muted=" + track.muted + " \u2014 " + new Date().toISOString());
|
|
1417
|
+
track.onunmute = function () {
|
|
1418
|
+
console.log("[VoiceDebug] Remote audio track UNMUTED (audio data arriving) \u2014 " + new Date().toISOString());
|
|
1419
|
+
};
|
|
1420
1420
|
var stream = new MediaStream([track]);
|
|
1421
1421
|
var audio = new Audio();
|
|
1422
1422
|
audio.autoplay = true;
|
|
1423
1423
|
audio.srcObject = stream;
|
|
1424
1424
|
this.remoteAudioElement = audio;
|
|
1425
|
+
audio.onplaying = function () {
|
|
1426
|
+
console.log("[VoiceDebug] Audio element PLAYING (browser started playback) \u2014 " + new Date().toISOString());
|
|
1427
|
+
};
|
|
1428
|
+
var firstTimeUpdate_1 = true;
|
|
1429
|
+
audio.ontimeupdate = function () {
|
|
1430
|
+
if (firstTimeUpdate_1) {
|
|
1431
|
+
firstTimeUpdate_1 = false;
|
|
1432
|
+
console.log("[VoiceDebug] Audio element first TIMEUPDATE (actual audio output) \u2014 " + new Date().toISOString());
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1425
1435
|
var p = audio.play();
|
|
1426
|
-
if (p && typeof p.
|
|
1427
|
-
p.
|
|
1436
|
+
if (p && typeof p.then === 'function') {
|
|
1437
|
+
p.then(function () {
|
|
1438
|
+
console.log("[VoiceDebug] audio.play() resolved \u2014 " + new Date().toISOString());
|
|
1439
|
+
}).catch(function (err) {
|
|
1428
1440
|
console.warn('DailyVoiceClient: remote audio play failed (may need user gesture)', err);
|
|
1429
1441
|
});
|
|
1430
1442
|
}
|
|
@@ -1433,6 +1445,66 @@
|
|
|
1433
1445
|
console.warn('DailyVoiceClient: failed to create remote audio element', err);
|
|
1434
1446
|
}
|
|
1435
1447
|
};
|
|
1448
|
+
/**
|
|
1449
|
+
* Monitor remote audio track energy via AnalyserNode.
|
|
1450
|
+
* Polls at ~60fps and flips speakingSubject based on actual audio energy.
|
|
1451
|
+
*/
|
|
1452
|
+
DailyVoiceClientService.prototype.monitorRemoteAudio = function (track) {
|
|
1453
|
+
var _this = this;
|
|
1454
|
+
this.stopRemoteAudioMonitor();
|
|
1455
|
+
try {
|
|
1456
|
+
var ctx = new AudioContext();
|
|
1457
|
+
var source = ctx.createMediaStreamSource(new MediaStream([track]));
|
|
1458
|
+
var analyser_1 = ctx.createAnalyser();
|
|
1459
|
+
analyser_1.fftSize = 256;
|
|
1460
|
+
source.connect(analyser_1);
|
|
1461
|
+
this.remoteAudioContext = ctx;
|
|
1462
|
+
var dataArray_1 = new Uint8Array(analyser_1.frequencyBinCount);
|
|
1463
|
+
var THRESHOLD_1 = 8;
|
|
1464
|
+
var SILENCE_MS_1 = 300;
|
|
1465
|
+
var lastSoundTime_1 = 0;
|
|
1466
|
+
var isSpeaking_1 = false;
|
|
1467
|
+
var poll_1 = function () {
|
|
1468
|
+
if (!_this.remoteAudioContext)
|
|
1469
|
+
return;
|
|
1470
|
+
analyser_1.getByteFrequencyData(dataArray_1);
|
|
1471
|
+
var sum = 0;
|
|
1472
|
+
for (var i = 0; i < dataArray_1.length; i++) {
|
|
1473
|
+
sum += dataArray_1[i];
|
|
1474
|
+
}
|
|
1475
|
+
var avg = sum / dataArray_1.length;
|
|
1476
|
+
var now = Date.now();
|
|
1477
|
+
if (avg > THRESHOLD_1) {
|
|
1478
|
+
lastSoundTime_1 = now;
|
|
1479
|
+
if (!isSpeaking_1) {
|
|
1480
|
+
isSpeaking_1 = true;
|
|
1481
|
+
console.log("[VoiceDebug] Bot audio energy detected (speaking=true) \u2014 avg=" + avg.toFixed(1) + " \u2014 " + new Date().toISOString());
|
|
1482
|
+
_this.ngZone.run(function () { return _this.speakingSubject.next(true); });
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
else if (isSpeaking_1 && now - lastSoundTime_1 > SILENCE_MS_1) {
|
|
1486
|
+
isSpeaking_1 = false;
|
|
1487
|
+
console.log("[VoiceDebug] Bot audio silence detected (speaking=false) \u2014 " + new Date().toISOString());
|
|
1488
|
+
_this.ngZone.run(function () { return _this.speakingSubject.next(false); });
|
|
1489
|
+
}
|
|
1490
|
+
_this.remoteSpeakingRAF = requestAnimationFrame(poll_1);
|
|
1491
|
+
};
|
|
1492
|
+
this.remoteSpeakingRAF = requestAnimationFrame(poll_1);
|
|
1493
|
+
}
|
|
1494
|
+
catch (err) {
|
|
1495
|
+
console.warn('DailyVoiceClient: failed to create remote audio monitor', err);
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
DailyVoiceClientService.prototype.stopRemoteAudioMonitor = function () {
|
|
1499
|
+
if (this.remoteSpeakingRAF) {
|
|
1500
|
+
cancelAnimationFrame(this.remoteSpeakingRAF);
|
|
1501
|
+
this.remoteSpeakingRAF = null;
|
|
1502
|
+
}
|
|
1503
|
+
if (this.remoteAudioContext) {
|
|
1504
|
+
this.remoteAudioContext.close().catch(function () { });
|
|
1505
|
+
this.remoteAudioContext = null;
|
|
1506
|
+
}
|
|
1507
|
+
};
|
|
1436
1508
|
DailyVoiceClientService.prototype.stopRemoteAudio = function () {
|
|
1437
1509
|
if (this.remoteAudioElement) {
|
|
1438
1510
|
try {
|
|
@@ -1479,6 +1551,7 @@
|
|
|
1479
1551
|
});
|
|
1480
1552
|
};
|
|
1481
1553
|
DailyVoiceClientService.prototype.cleanup = function () {
|
|
1554
|
+
this.stopRemoteAudioMonitor();
|
|
1482
1555
|
this.stopRemoteAudio();
|
|
1483
1556
|
if (this.callObject) {
|
|
1484
1557
|
this.callObject.destroy().catch(function () { });
|