@layercode/js-sdk 2.4.0 → 2.6.0
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.
|
@@ -505,12 +505,37 @@ class WavStreamPlayer {
|
|
|
505
505
|
this.sampleRate = sampleRate;
|
|
506
506
|
this.context = null;
|
|
507
507
|
this.stream = null;
|
|
508
|
+
this.gainNode = null;
|
|
508
509
|
this.analyser = null;
|
|
509
510
|
this.trackSampleOffsets = {};
|
|
510
511
|
this.interruptedTrackIds = {};
|
|
511
512
|
this.finishedPlayingCallback = finishedPlayingCallback;
|
|
512
513
|
this.isPlaying = false;
|
|
513
514
|
this.amplitudeMonitorRaf = undefined;
|
|
515
|
+
this.muted = false;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
_ensureGainNode() {
|
|
519
|
+
if (!this.context) {
|
|
520
|
+
return null;
|
|
521
|
+
}
|
|
522
|
+
if (!this.gainNode) {
|
|
523
|
+
this.gainNode = this.context.createGain();
|
|
524
|
+
this._applyGain();
|
|
525
|
+
}
|
|
526
|
+
return this.gainNode;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
_applyGain() {
|
|
530
|
+
if (!this.gainNode || !this.context) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const target = this.muted ? 0 : 1;
|
|
534
|
+
try {
|
|
535
|
+
this.gainNode.gain.setTargetAtTime(target, this.context.currentTime, 0.01);
|
|
536
|
+
} catch {
|
|
537
|
+
this.gainNode.gain.value = target;
|
|
538
|
+
}
|
|
514
539
|
}
|
|
515
540
|
|
|
516
541
|
/**
|
|
@@ -550,6 +575,7 @@ class WavStreamPlayer {
|
|
|
550
575
|
analyser.fftSize = 8192;
|
|
551
576
|
analyser.smoothingTimeConstant = 0.1;
|
|
552
577
|
this.analyser = analyser;
|
|
578
|
+
this._ensureGainNode();
|
|
553
579
|
this.isPlaying = true;
|
|
554
580
|
return true;
|
|
555
581
|
}
|
|
@@ -619,12 +645,19 @@ class WavStreamPlayer {
|
|
|
619
645
|
*/
|
|
620
646
|
_start() {
|
|
621
647
|
const streamNode = new AudioWorkletNode(this.context, "stream_processor");
|
|
622
|
-
|
|
648
|
+
const gainNode = this._ensureGainNode();
|
|
649
|
+
if (!gainNode) {
|
|
650
|
+
throw new Error("GainNode not initialized");
|
|
651
|
+
}
|
|
623
652
|
streamNode.port.onmessage = (e) => {
|
|
624
653
|
const { event } = e.data;
|
|
625
654
|
if (event === "stop") {
|
|
626
655
|
streamNode.disconnect();
|
|
656
|
+
gainNode.disconnect();
|
|
627
657
|
this.stream = null;
|
|
658
|
+
if (this.analyser) {
|
|
659
|
+
this.analyser.disconnect();
|
|
660
|
+
}
|
|
628
661
|
this.isPlaying = false;
|
|
629
662
|
this.finishedPlayingCallback();
|
|
630
663
|
} else if (event === "offset") {
|
|
@@ -633,8 +666,15 @@ class WavStreamPlayer {
|
|
|
633
666
|
this.trackSampleOffsets[requestId] = { trackId, offset, currentTime };
|
|
634
667
|
}
|
|
635
668
|
};
|
|
636
|
-
this.analyser
|
|
637
|
-
|
|
669
|
+
if (this.analyser) {
|
|
670
|
+
this.analyser.disconnect();
|
|
671
|
+
streamNode.connect(gainNode);
|
|
672
|
+
gainNode.connect(this.analyser);
|
|
673
|
+
this.analyser.connect(this.context.destination);
|
|
674
|
+
} else {
|
|
675
|
+
streamNode.connect(gainNode);
|
|
676
|
+
gainNode.connect(this.context.destination);
|
|
677
|
+
}
|
|
638
678
|
this.stream = streamNode;
|
|
639
679
|
this.isPlaying = true;
|
|
640
680
|
return true;
|
|
@@ -764,6 +804,16 @@ class WavStreamPlayer {
|
|
|
764
804
|
}
|
|
765
805
|
}
|
|
766
806
|
|
|
807
|
+
mute() {
|
|
808
|
+
this.muted = true;
|
|
809
|
+
this._applyGain();
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
unmute() {
|
|
813
|
+
this.muted = false;
|
|
814
|
+
this._applyGain();
|
|
815
|
+
}
|
|
816
|
+
|
|
767
817
|
/**
|
|
768
818
|
* Disconnects the audio context and cleans up resources
|
|
769
819
|
* @returns {void}
|
|
@@ -775,6 +825,11 @@ class WavStreamPlayer {
|
|
|
775
825
|
this.stream = null;
|
|
776
826
|
}
|
|
777
827
|
|
|
828
|
+
if (this.gainNode) {
|
|
829
|
+
this.gainNode.disconnect();
|
|
830
|
+
this.gainNode = null;
|
|
831
|
+
}
|
|
832
|
+
|
|
778
833
|
if (this.analyser) {
|
|
779
834
|
this.analyser.disconnect();
|
|
780
835
|
}
|
|
@@ -3625,7 +3680,7 @@ class LayercodeClient {
|
|
|
3625
3680
|
* @param {Object} options - Configuration options
|
|
3626
3681
|
*/
|
|
3627
3682
|
constructor(options) {
|
|
3628
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
3683
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
3629
3684
|
this.deviceId = null;
|
|
3630
3685
|
this.options = {
|
|
3631
3686
|
agentId: options.agentId,
|
|
@@ -3636,22 +3691,25 @@ class LayercodeClient {
|
|
|
3636
3691
|
vadResumeDelay: (_c = options.vadResumeDelay) !== null && _c !== void 0 ? _c : 500,
|
|
3637
3692
|
audioInput: (_d = options.audioInput) !== null && _d !== void 0 ? _d : true,
|
|
3638
3693
|
audioInputChanged: (_e = options.audioInputChanged) !== null && _e !== void 0 ? _e : NOOP,
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3694
|
+
audioOutput: (_f = options.audioOutput) !== null && _f !== void 0 ? _f : true,
|
|
3695
|
+
audioOutputChanged: (_g = options.audioOutputChanged) !== null && _g !== void 0 ? _g : NOOP,
|
|
3696
|
+
onConnect: (_h = options.onConnect) !== null && _h !== void 0 ? _h : NOOP,
|
|
3697
|
+
onDisconnect: (_j = options.onDisconnect) !== null && _j !== void 0 ? _j : NOOP,
|
|
3698
|
+
onError: (_k = options.onError) !== null && _k !== void 0 ? _k : NOOP,
|
|
3699
|
+
onDeviceSwitched: (_l = options.onDeviceSwitched) !== null && _l !== void 0 ? _l : NOOP,
|
|
3700
|
+
onDevicesChanged: (_m = options.onDevicesChanged) !== null && _m !== void 0 ? _m : NOOP,
|
|
3701
|
+
onDataMessage: (_o = options.onDataMessage) !== null && _o !== void 0 ? _o : NOOP,
|
|
3702
|
+
onMessage: (_p = options.onMessage) !== null && _p !== void 0 ? _p : NOOP,
|
|
3703
|
+
onUserAmplitudeChange: (_q = options.onUserAmplitudeChange) !== null && _q !== void 0 ? _q : NOOP,
|
|
3704
|
+
onAgentAmplitudeChange: (_r = options.onAgentAmplitudeChange) !== null && _r !== void 0 ? _r : NOOP,
|
|
3705
|
+
onStatusChange: (_s = options.onStatusChange) !== null && _s !== void 0 ? _s : NOOP,
|
|
3706
|
+
onUserIsSpeakingChange: (_t = options.onUserIsSpeakingChange) !== null && _t !== void 0 ? _t : NOOP,
|
|
3707
|
+
onAgentSpeakingChange: (_u = options.onAgentSpeakingChange) !== null && _u !== void 0 ? _u : NOOP,
|
|
3708
|
+
onMuteStateChange: (_v = options.onMuteStateChange) !== null && _v !== void 0 ? _v : NOOP,
|
|
3709
|
+
enableAmplitudeMonitoring: (_w = options.enableAmplitudeMonitoring) !== null && _w !== void 0 ? _w : true,
|
|
3653
3710
|
};
|
|
3654
|
-
this.audioInput = (
|
|
3711
|
+
this.audioInput = (_x = options.audioInput) !== null && _x !== void 0 ? _x : true;
|
|
3712
|
+
this.audioOutput = (_y = options.audioOutput) !== null && _y !== void 0 ? _y : true;
|
|
3655
3713
|
this._emitAudioInput();
|
|
3656
3714
|
this.AMPLITUDE_MONITORING_SAMPLE_RATE = 2;
|
|
3657
3715
|
this._websocketUrl = DEFAULT_WS_URL;
|
|
@@ -4037,11 +4095,30 @@ class LayercodeClient {
|
|
|
4037
4095
|
}
|
|
4038
4096
|
}
|
|
4039
4097
|
_stopAmplitudeMonitoring() {
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4098
|
+
this._stopPlayerAmplitudeMonitoring();
|
|
4099
|
+
this._stopRecorderAmplitudeMonitoring();
|
|
4100
|
+
}
|
|
4101
|
+
_stopPlayerAmplitudeMonitoring() {
|
|
4102
|
+
var _a;
|
|
4103
|
+
this.agentAudioAmplitude = 0;
|
|
4104
|
+
if (this.options.enableAmplitudeMonitoring && this.options.onAgentAmplitudeChange !== NOOP) {
|
|
4105
|
+
this.options.onAgentAmplitudeChange(0);
|
|
4106
|
+
}
|
|
4107
|
+
if (this.stopPlayerAmplitude) {
|
|
4108
|
+
(_a = this.stopPlayerAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
4109
|
+
this.stopPlayerAmplitude = undefined;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
_stopRecorderAmplitudeMonitoring() {
|
|
4113
|
+
var _a;
|
|
4114
|
+
this.userAudioAmplitude = 0;
|
|
4115
|
+
if (this.options.enableAmplitudeMonitoring && this.options.onUserAmplitudeChange !== NOOP) {
|
|
4116
|
+
this.options.onUserAmplitudeChange(0);
|
|
4117
|
+
}
|
|
4118
|
+
if (this.stopRecorderAmplitude) {
|
|
4119
|
+
(_a = this.stopRecorderAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
4120
|
+
this.stopRecorderAmplitude = undefined;
|
|
4121
|
+
}
|
|
4045
4122
|
}
|
|
4046
4123
|
async audioInputConnect() {
|
|
4047
4124
|
// Turn mic ON
|
|
@@ -4050,10 +4127,9 @@ class LayercodeClient {
|
|
|
4050
4127
|
this._setupDeviceChangeListener();
|
|
4051
4128
|
}
|
|
4052
4129
|
async audioInputDisconnect() {
|
|
4053
|
-
var _a;
|
|
4054
4130
|
try {
|
|
4055
4131
|
// stop amplitude monitoring tied to the recorder
|
|
4056
|
-
|
|
4132
|
+
this._stopRecorderAmplitudeMonitoring();
|
|
4057
4133
|
// Try a graceful stop; end() already stops tracks and closes the AudioContext
|
|
4058
4134
|
await this.wavRecorder.end();
|
|
4059
4135
|
this.stopVad();
|
|
@@ -4061,7 +4137,7 @@ class LayercodeClient {
|
|
|
4061
4137
|
this._teardownDeviceListeners();
|
|
4062
4138
|
this.recorderStarted = false;
|
|
4063
4139
|
}
|
|
4064
|
-
catch (
|
|
4140
|
+
catch (_a) {
|
|
4065
4141
|
// If there wasn't an active session, just release any stray tracks
|
|
4066
4142
|
const stream = this.wavRecorder.getStream();
|
|
4067
4143
|
stream === null || stream === void 0 ? void 0 : stream.getTracks().forEach((t) => t.stop());
|
|
@@ -4079,10 +4155,25 @@ class LayercodeClient {
|
|
|
4079
4155
|
}
|
|
4080
4156
|
}
|
|
4081
4157
|
}
|
|
4158
|
+
async setAudioOutput(state) {
|
|
4159
|
+
if (this.audioOutput !== state) {
|
|
4160
|
+
this.audioOutput = state;
|
|
4161
|
+
this._emitAudioOutput();
|
|
4162
|
+
if (state) {
|
|
4163
|
+
this.wavPlayer.unmute();
|
|
4164
|
+
}
|
|
4165
|
+
else {
|
|
4166
|
+
this.wavPlayer.mute();
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4082
4170
|
/** Emitters for audio flags */
|
|
4083
4171
|
_emitAudioInput() {
|
|
4084
4172
|
this.options.audioInputChanged(this.audioInput);
|
|
4085
4173
|
}
|
|
4174
|
+
_emitAudioOutput() {
|
|
4175
|
+
this.options.audioOutputChanged(this.audioOutput);
|
|
4176
|
+
}
|
|
4086
4177
|
get audioInputEnabled() {
|
|
4087
4178
|
return this.audioInput;
|
|
4088
4179
|
}
|
|
@@ -4208,6 +4299,12 @@ class LayercodeClient {
|
|
|
4208
4299
|
if (!this.options.enableAmplitudeMonitoring) {
|
|
4209
4300
|
this.agentAudioAmplitude = 0;
|
|
4210
4301
|
}
|
|
4302
|
+
if (this.audioOutput) {
|
|
4303
|
+
this.wavPlayer.unmute();
|
|
4304
|
+
}
|
|
4305
|
+
else {
|
|
4306
|
+
this.wavPlayer.mute();
|
|
4307
|
+
}
|
|
4211
4308
|
}
|
|
4212
4309
|
async connectToAudioInput() {
|
|
4213
4310
|
if (!this.audioInput) {
|
|
@@ -4281,16 +4378,15 @@ class LayercodeClient {
|
|
|
4281
4378
|
* Restarts audio recording after a device switch to ensure audio is captured from the new device
|
|
4282
4379
|
*/
|
|
4283
4380
|
async _restartAudioRecording() {
|
|
4284
|
-
var _a, _b
|
|
4381
|
+
var _a, _b;
|
|
4285
4382
|
try {
|
|
4286
4383
|
console.debug('Restarting audio recording after device switch...');
|
|
4287
4384
|
// Stop amplitude monitoring tied to the previous recording session before tearing it down
|
|
4288
|
-
|
|
4289
|
-
this.stopRecorderAmplitude = undefined;
|
|
4385
|
+
this._stopRecorderAmplitudeMonitoring();
|
|
4290
4386
|
try {
|
|
4291
4387
|
await this.wavRecorder.end();
|
|
4292
4388
|
}
|
|
4293
|
-
catch (
|
|
4389
|
+
catch (_c) {
|
|
4294
4390
|
// Ignore cleanup errors
|
|
4295
4391
|
}
|
|
4296
4392
|
// Start with new device
|
|
@@ -4312,7 +4408,7 @@ class LayercodeClient {
|
|
|
4312
4408
|
this.recorderStarted = true;
|
|
4313
4409
|
this._sendReadyIfNeeded();
|
|
4314
4410
|
}
|
|
4315
|
-
const reportedDeviceId = (
|
|
4411
|
+
const reportedDeviceId = (_a = this.activeDeviceId) !== null && _a !== void 0 ? _a : (this.useSystemDefaultDevice ? 'default' : (_b = this.deviceId) !== null && _b !== void 0 ? _b : 'default');
|
|
4316
4412
|
if (reportedDeviceId !== previousReportedDeviceId) {
|
|
4317
4413
|
this.lastReportedDeviceId = reportedDeviceId;
|
|
4318
4414
|
if (this.options.onDeviceSwitched) {
|
|
@@ -4456,6 +4552,7 @@ class LayercodeClient {
|
|
|
4456
4552
|
console.log('Microphone muted');
|
|
4457
4553
|
this.options.onMuteStateChange(true);
|
|
4458
4554
|
this.stopVad();
|
|
4555
|
+
this._stopRecorderAmplitudeMonitoring();
|
|
4459
4556
|
}
|
|
4460
4557
|
}
|
|
4461
4558
|
/**
|
|
@@ -4467,6 +4564,9 @@ class LayercodeClient {
|
|
|
4467
4564
|
console.log('Microphone unmuted');
|
|
4468
4565
|
this.options.onMuteStateChange(false);
|
|
4469
4566
|
this._initializeVAD();
|
|
4567
|
+
if (this.stopRecorderAmplitude === undefined) {
|
|
4568
|
+
this._setupAmplitudeMonitoring(this.wavRecorder, this.options.onUserAmplitudeChange, (amp) => (this.userAudioAmplitude = amp));
|
|
4569
|
+
}
|
|
4470
4570
|
}
|
|
4471
4571
|
}
|
|
4472
4572
|
}
|