@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.
@@ -511,12 +511,37 @@ registerProcessor('stream_processor', StreamProcessor);
511
511
  this.sampleRate = sampleRate;
512
512
  this.context = null;
513
513
  this.stream = null;
514
+ this.gainNode = null;
514
515
  this.analyser = null;
515
516
  this.trackSampleOffsets = {};
516
517
  this.interruptedTrackIds = {};
517
518
  this.finishedPlayingCallback = finishedPlayingCallback;
518
519
  this.isPlaying = false;
519
520
  this.amplitudeMonitorRaf = undefined;
521
+ this.muted = false;
522
+ }
523
+
524
+ _ensureGainNode() {
525
+ if (!this.context) {
526
+ return null;
527
+ }
528
+ if (!this.gainNode) {
529
+ this.gainNode = this.context.createGain();
530
+ this._applyGain();
531
+ }
532
+ return this.gainNode;
533
+ }
534
+
535
+ _applyGain() {
536
+ if (!this.gainNode || !this.context) {
537
+ return;
538
+ }
539
+ const target = this.muted ? 0 : 1;
540
+ try {
541
+ this.gainNode.gain.setTargetAtTime(target, this.context.currentTime, 0.01);
542
+ } catch {
543
+ this.gainNode.gain.value = target;
544
+ }
520
545
  }
521
546
 
522
547
  /**
@@ -556,6 +581,7 @@ registerProcessor('stream_processor', StreamProcessor);
556
581
  analyser.fftSize = 8192;
557
582
  analyser.smoothingTimeConstant = 0.1;
558
583
  this.analyser = analyser;
584
+ this._ensureGainNode();
559
585
  this.isPlaying = true;
560
586
  return true;
561
587
  }
@@ -625,12 +651,19 @@ registerProcessor('stream_processor', StreamProcessor);
625
651
  */
626
652
  _start() {
627
653
  const streamNode = new AudioWorkletNode(this.context, "stream_processor");
628
- streamNode.connect(this.context.destination);
654
+ const gainNode = this._ensureGainNode();
655
+ if (!gainNode) {
656
+ throw new Error("GainNode not initialized");
657
+ }
629
658
  streamNode.port.onmessage = (e) => {
630
659
  const { event } = e.data;
631
660
  if (event === "stop") {
632
661
  streamNode.disconnect();
662
+ gainNode.disconnect();
633
663
  this.stream = null;
664
+ if (this.analyser) {
665
+ this.analyser.disconnect();
666
+ }
634
667
  this.isPlaying = false;
635
668
  this.finishedPlayingCallback();
636
669
  } else if (event === "offset") {
@@ -639,8 +672,15 @@ registerProcessor('stream_processor', StreamProcessor);
639
672
  this.trackSampleOffsets[requestId] = { trackId, offset, currentTime };
640
673
  }
641
674
  };
642
- this.analyser.disconnect();
643
- streamNode.connect(this.analyser);
675
+ if (this.analyser) {
676
+ this.analyser.disconnect();
677
+ streamNode.connect(gainNode);
678
+ gainNode.connect(this.analyser);
679
+ this.analyser.connect(this.context.destination);
680
+ } else {
681
+ streamNode.connect(gainNode);
682
+ gainNode.connect(this.context.destination);
683
+ }
644
684
  this.stream = streamNode;
645
685
  this.isPlaying = true;
646
686
  return true;
@@ -770,6 +810,16 @@ registerProcessor('stream_processor', StreamProcessor);
770
810
  }
771
811
  }
772
812
 
813
+ mute() {
814
+ this.muted = true;
815
+ this._applyGain();
816
+ }
817
+
818
+ unmute() {
819
+ this.muted = false;
820
+ this._applyGain();
821
+ }
822
+
773
823
  /**
774
824
  * Disconnects the audio context and cleans up resources
775
825
  * @returns {void}
@@ -781,6 +831,11 @@ registerProcessor('stream_processor', StreamProcessor);
781
831
  this.stream = null;
782
832
  }
783
833
 
834
+ if (this.gainNode) {
835
+ this.gainNode.disconnect();
836
+ this.gainNode = null;
837
+ }
838
+
784
839
  if (this.analyser) {
785
840
  this.analyser.disconnect();
786
841
  }
@@ -3631,7 +3686,7 @@ registerProcessor('audio_processor', AudioProcessor);
3631
3686
  * @param {Object} options - Configuration options
3632
3687
  */
3633
3688
  constructor(options) {
3634
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
3689
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
3635
3690
  this.deviceId = null;
3636
3691
  this.options = {
3637
3692
  agentId: options.agentId,
@@ -3642,22 +3697,25 @@ registerProcessor('audio_processor', AudioProcessor);
3642
3697
  vadResumeDelay: (_c = options.vadResumeDelay) !== null && _c !== void 0 ? _c : 500,
3643
3698
  audioInput: (_d = options.audioInput) !== null && _d !== void 0 ? _d : true,
3644
3699
  audioInputChanged: (_e = options.audioInputChanged) !== null && _e !== void 0 ? _e : NOOP,
3645
- onConnect: (_f = options.onConnect) !== null && _f !== void 0 ? _f : NOOP,
3646
- onDisconnect: (_g = options.onDisconnect) !== null && _g !== void 0 ? _g : NOOP,
3647
- onError: (_h = options.onError) !== null && _h !== void 0 ? _h : NOOP,
3648
- onDeviceSwitched: (_j = options.onDeviceSwitched) !== null && _j !== void 0 ? _j : NOOP,
3649
- onDevicesChanged: (_k = options.onDevicesChanged) !== null && _k !== void 0 ? _k : NOOP,
3650
- onDataMessage: (_l = options.onDataMessage) !== null && _l !== void 0 ? _l : NOOP,
3651
- onMessage: (_m = options.onMessage) !== null && _m !== void 0 ? _m : NOOP,
3652
- onUserAmplitudeChange: (_o = options.onUserAmplitudeChange) !== null && _o !== void 0 ? _o : NOOP,
3653
- onAgentAmplitudeChange: (_p = options.onAgentAmplitudeChange) !== null && _p !== void 0 ? _p : NOOP,
3654
- onStatusChange: (_q = options.onStatusChange) !== null && _q !== void 0 ? _q : NOOP,
3655
- onUserIsSpeakingChange: (_r = options.onUserIsSpeakingChange) !== null && _r !== void 0 ? _r : NOOP,
3656
- onAgentSpeakingChange: (_s = options.onAgentSpeakingChange) !== null && _s !== void 0 ? _s : NOOP,
3657
- onMuteStateChange: (_t = options.onMuteStateChange) !== null && _t !== void 0 ? _t : NOOP,
3658
- enableAmplitudeMonitoring: (_u = options.enableAmplitudeMonitoring) !== null && _u !== void 0 ? _u : true,
3700
+ audioOutput: (_f = options.audioOutput) !== null && _f !== void 0 ? _f : true,
3701
+ audioOutputChanged: (_g = options.audioOutputChanged) !== null && _g !== void 0 ? _g : NOOP,
3702
+ onConnect: (_h = options.onConnect) !== null && _h !== void 0 ? _h : NOOP,
3703
+ onDisconnect: (_j = options.onDisconnect) !== null && _j !== void 0 ? _j : NOOP,
3704
+ onError: (_k = options.onError) !== null && _k !== void 0 ? _k : NOOP,
3705
+ onDeviceSwitched: (_l = options.onDeviceSwitched) !== null && _l !== void 0 ? _l : NOOP,
3706
+ onDevicesChanged: (_m = options.onDevicesChanged) !== null && _m !== void 0 ? _m : NOOP,
3707
+ onDataMessage: (_o = options.onDataMessage) !== null && _o !== void 0 ? _o : NOOP,
3708
+ onMessage: (_p = options.onMessage) !== null && _p !== void 0 ? _p : NOOP,
3709
+ onUserAmplitudeChange: (_q = options.onUserAmplitudeChange) !== null && _q !== void 0 ? _q : NOOP,
3710
+ onAgentAmplitudeChange: (_r = options.onAgentAmplitudeChange) !== null && _r !== void 0 ? _r : NOOP,
3711
+ onStatusChange: (_s = options.onStatusChange) !== null && _s !== void 0 ? _s : NOOP,
3712
+ onUserIsSpeakingChange: (_t = options.onUserIsSpeakingChange) !== null && _t !== void 0 ? _t : NOOP,
3713
+ onAgentSpeakingChange: (_u = options.onAgentSpeakingChange) !== null && _u !== void 0 ? _u : NOOP,
3714
+ onMuteStateChange: (_v = options.onMuteStateChange) !== null && _v !== void 0 ? _v : NOOP,
3715
+ enableAmplitudeMonitoring: (_w = options.enableAmplitudeMonitoring) !== null && _w !== void 0 ? _w : true,
3659
3716
  };
3660
- this.audioInput = (_v = options.audioInput) !== null && _v !== void 0 ? _v : true;
3717
+ this.audioInput = (_x = options.audioInput) !== null && _x !== void 0 ? _x : true;
3718
+ this.audioOutput = (_y = options.audioOutput) !== null && _y !== void 0 ? _y : true;
3661
3719
  this._emitAudioInput();
3662
3720
  this.AMPLITUDE_MONITORING_SAMPLE_RATE = 2;
3663
3721
  this._websocketUrl = DEFAULT_WS_URL;
@@ -4043,11 +4101,30 @@ registerProcessor('audio_processor', AudioProcessor);
4043
4101
  }
4044
4102
  }
4045
4103
  _stopAmplitudeMonitoring() {
4046
- var _a, _b;
4047
- (_a = this.stopPlayerAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
4048
- (_b = this.stopRecorderAmplitude) === null || _b === void 0 ? void 0 : _b.call(this);
4049
- this.stopPlayerAmplitude = undefined;
4050
- this.stopRecorderAmplitude = undefined;
4104
+ this._stopPlayerAmplitudeMonitoring();
4105
+ this._stopRecorderAmplitudeMonitoring();
4106
+ }
4107
+ _stopPlayerAmplitudeMonitoring() {
4108
+ var _a;
4109
+ this.agentAudioAmplitude = 0;
4110
+ if (this.options.enableAmplitudeMonitoring && this.options.onAgentAmplitudeChange !== NOOP) {
4111
+ this.options.onAgentAmplitudeChange(0);
4112
+ }
4113
+ if (this.stopPlayerAmplitude) {
4114
+ (_a = this.stopPlayerAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
4115
+ this.stopPlayerAmplitude = undefined;
4116
+ }
4117
+ }
4118
+ _stopRecorderAmplitudeMonitoring() {
4119
+ var _a;
4120
+ this.userAudioAmplitude = 0;
4121
+ if (this.options.enableAmplitudeMonitoring && this.options.onUserAmplitudeChange !== NOOP) {
4122
+ this.options.onUserAmplitudeChange(0);
4123
+ }
4124
+ if (this.stopRecorderAmplitude) {
4125
+ (_a = this.stopRecorderAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
4126
+ this.stopRecorderAmplitude = undefined;
4127
+ }
4051
4128
  }
4052
4129
  async audioInputConnect() {
4053
4130
  // Turn mic ON
@@ -4056,10 +4133,9 @@ registerProcessor('audio_processor', AudioProcessor);
4056
4133
  this._setupDeviceChangeListener();
4057
4134
  }
4058
4135
  async audioInputDisconnect() {
4059
- var _a;
4060
4136
  try {
4061
4137
  // stop amplitude monitoring tied to the recorder
4062
- (_a = this.stopRecorderAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
4138
+ this._stopRecorderAmplitudeMonitoring();
4063
4139
  // Try a graceful stop; end() already stops tracks and closes the AudioContext
4064
4140
  await this.wavRecorder.end();
4065
4141
  this.stopVad();
@@ -4067,7 +4143,7 @@ registerProcessor('audio_processor', AudioProcessor);
4067
4143
  this._teardownDeviceListeners();
4068
4144
  this.recorderStarted = false;
4069
4145
  }
4070
- catch (_b) {
4146
+ catch (_a) {
4071
4147
  // If there wasn't an active session, just release any stray tracks
4072
4148
  const stream = this.wavRecorder.getStream();
4073
4149
  stream === null || stream === void 0 ? void 0 : stream.getTracks().forEach((t) => t.stop());
@@ -4085,10 +4161,25 @@ registerProcessor('audio_processor', AudioProcessor);
4085
4161
  }
4086
4162
  }
4087
4163
  }
4164
+ async setAudioOutput(state) {
4165
+ if (this.audioOutput !== state) {
4166
+ this.audioOutput = state;
4167
+ this._emitAudioOutput();
4168
+ if (state) {
4169
+ this.wavPlayer.unmute();
4170
+ }
4171
+ else {
4172
+ this.wavPlayer.mute();
4173
+ }
4174
+ }
4175
+ }
4088
4176
  /** Emitters for audio flags */
4089
4177
  _emitAudioInput() {
4090
4178
  this.options.audioInputChanged(this.audioInput);
4091
4179
  }
4180
+ _emitAudioOutput() {
4181
+ this.options.audioOutputChanged(this.audioOutput);
4182
+ }
4092
4183
  get audioInputEnabled() {
4093
4184
  return this.audioInput;
4094
4185
  }
@@ -4214,6 +4305,12 @@ registerProcessor('audio_processor', AudioProcessor);
4214
4305
  if (!this.options.enableAmplitudeMonitoring) {
4215
4306
  this.agentAudioAmplitude = 0;
4216
4307
  }
4308
+ if (this.audioOutput) {
4309
+ this.wavPlayer.unmute();
4310
+ }
4311
+ else {
4312
+ this.wavPlayer.mute();
4313
+ }
4217
4314
  }
4218
4315
  async connectToAudioInput() {
4219
4316
  if (!this.audioInput) {
@@ -4287,16 +4384,15 @@ registerProcessor('audio_processor', AudioProcessor);
4287
4384
  * Restarts audio recording after a device switch to ensure audio is captured from the new device
4288
4385
  */
4289
4386
  async _restartAudioRecording() {
4290
- var _a, _b, _c;
4387
+ var _a, _b;
4291
4388
  try {
4292
4389
  console.debug('Restarting audio recording after device switch...');
4293
4390
  // Stop amplitude monitoring tied to the previous recording session before tearing it down
4294
- (_a = this.stopRecorderAmplitude) === null || _a === void 0 ? void 0 : _a.call(this);
4295
- this.stopRecorderAmplitude = undefined;
4391
+ this._stopRecorderAmplitudeMonitoring();
4296
4392
  try {
4297
4393
  await this.wavRecorder.end();
4298
4394
  }
4299
- catch (_d) {
4395
+ catch (_c) {
4300
4396
  // Ignore cleanup errors
4301
4397
  }
4302
4398
  // Start with new device
@@ -4318,7 +4414,7 @@ registerProcessor('audio_processor', AudioProcessor);
4318
4414
  this.recorderStarted = true;
4319
4415
  this._sendReadyIfNeeded();
4320
4416
  }
4321
- const reportedDeviceId = (_b = this.activeDeviceId) !== null && _b !== void 0 ? _b : (this.useSystemDefaultDevice ? 'default' : (_c = this.deviceId) !== null && _c !== void 0 ? _c : 'default');
4417
+ const reportedDeviceId = (_a = this.activeDeviceId) !== null && _a !== void 0 ? _a : (this.useSystemDefaultDevice ? 'default' : (_b = this.deviceId) !== null && _b !== void 0 ? _b : 'default');
4322
4418
  if (reportedDeviceId !== previousReportedDeviceId) {
4323
4419
  this.lastReportedDeviceId = reportedDeviceId;
4324
4420
  if (this.options.onDeviceSwitched) {
@@ -4462,6 +4558,7 @@ registerProcessor('audio_processor', AudioProcessor);
4462
4558
  console.log('Microphone muted');
4463
4559
  this.options.onMuteStateChange(true);
4464
4560
  this.stopVad();
4561
+ this._stopRecorderAmplitudeMonitoring();
4465
4562
  }
4466
4563
  }
4467
4564
  /**
@@ -4473,6 +4570,9 @@ registerProcessor('audio_processor', AudioProcessor);
4473
4570
  console.log('Microphone unmuted');
4474
4571
  this.options.onMuteStateChange(false);
4475
4572
  this._initializeVAD();
4573
+ if (this.stopRecorderAmplitude === undefined) {
4574
+ this._setupAmplitudeMonitoring(this.wavRecorder, this.options.onUserAmplitudeChange, (amp) => (this.userAudioAmplitude = amp));
4575
+ }
4476
4576
  }
4477
4577
  }
4478
4578
  }