@layercode/js-sdk 1.0.18 → 1.0.21

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.
@@ -3488,6 +3488,7 @@ registerProcessor('audio_processor', AudioProcessor);
3488
3488
  onUserAmplitudeChange: options.onUserAmplitudeChange || (() => { }),
3489
3489
  onAgentAmplitudeChange: options.onAgentAmplitudeChange || (() => { }),
3490
3490
  onStatusChange: options.onStatusChange || (() => { }),
3491
+ onUserIsSpeakingChange: options.onUserIsSpeakingChange || (() => { }),
3491
3492
  };
3492
3493
  this.AMPLITUDE_MONITORING_SAMPLE_RATE = 10;
3493
3494
  this._websocketUrl = 'wss://api.layercode.com/v1/pipelines/websocket';
@@ -3507,6 +3508,7 @@ registerProcessor('audio_processor', AudioProcessor);
3507
3508
  this.pushToTalkEnabled = false;
3508
3509
  this.canInterrupt = false;
3509
3510
  this.userIsSpeaking = false;
3511
+ this.endUserTurn = false;
3510
3512
  this.recorderStarted = false;
3511
3513
  this.readySent = false;
3512
3514
  // Bind event handlers
@@ -3523,6 +3525,7 @@ registerProcessor('audio_processor', AudioProcessor);
3523
3525
  console.log('silero vad model timeout');
3524
3526
  // TODO: send message to server to indicate that the vad model timed out
3525
3527
  this.userIsSpeaking = true; // allow audio to be sent to the server
3528
+ this.options.onUserIsSpeakingChange(true);
3526
3529
  }, 2000);
3527
3530
  if (!this.canInterrupt) {
3528
3531
  dist.MicVAD.new({
@@ -3536,17 +3539,15 @@ registerProcessor('audio_processor', AudioProcessor);
3536
3539
  onSpeechStart: () => {
3537
3540
  if (!this.wavPlayer.isPlaying) {
3538
3541
  this.userIsSpeaking = true;
3542
+ this.options.onUserIsSpeakingChange(true);
3539
3543
  }
3540
3544
  },
3541
3545
  onVADMisfire: () => {
3542
3546
  this.userIsSpeaking = false;
3547
+ this.options.onUserIsSpeakingChange(false);
3543
3548
  },
3544
3549
  onSpeechEnd: () => {
3545
- this.userIsSpeaking = false;
3546
- this._wsSend({
3547
- type: 'vad_events',
3548
- event: 'vad_end',
3549
- });
3550
+ this.endUserTurn = true; // Set flag to indicate that the user turn has ended, so we can send a vad_end event to the server
3550
3551
  },
3551
3552
  })
3552
3553
  .then((vad) => {
@@ -3581,6 +3582,7 @@ registerProcessor('audio_processor', AudioProcessor);
3581
3582
  console.log('onSpeechStart: WavPlayer is not playing, VAD will not pause.');
3582
3583
  }
3583
3584
  this.userIsSpeaking = true;
3585
+ this.options.onUserIsSpeakingChange(true);
3584
3586
  console.log('onSpeechStart: sending vad_start');
3585
3587
  this._wsSend({
3586
3588
  type: 'vad_events',
@@ -3590,6 +3592,7 @@ registerProcessor('audio_processor', AudioProcessor);
3590
3592
  onVADMisfire: () => {
3591
3593
  // If the speech detected was for less than minSpeechFrames, this is called instead of onSpeechEnd, and we should resume the assistant audio as it was a false interruption. We include a configurable delay so the assistant isn't too quick to start speaking again.
3592
3594
  this.userIsSpeaking = false;
3595
+ this.options.onUserIsSpeakingChange(false);
3593
3596
  if (this.vadPausedPlayer) {
3594
3597
  console.log('onSpeechEnd: VAD paused the player, resuming');
3595
3598
  this.wavPlayer.play();
@@ -3600,11 +3603,7 @@ registerProcessor('audio_processor', AudioProcessor);
3600
3603
  }
3601
3604
  },
3602
3605
  onSpeechEnd: () => {
3603
- this.userIsSpeaking = false;
3604
- this._wsSend({
3605
- type: 'vad_events',
3606
- event: 'vad_end',
3607
- });
3606
+ this.endUserTurn = true; // Set flag to indicate that the user turn has ended, so we can send a vad_end event to the server
3608
3607
  },
3609
3608
  })
3610
3609
  .then((vad) => {
@@ -3722,6 +3721,15 @@ registerProcessor('audio_processor', AudioProcessor);
3722
3721
  type: 'client.audio',
3723
3722
  content: base64,
3724
3723
  });
3724
+ if (this.endUserTurn) {
3725
+ this.endUserTurn = false;
3726
+ this.userIsSpeaking = false; // Reset userIsSpeaking to false so we don't send any more audio to the server
3727
+ this.options.onUserIsSpeakingChange(false);
3728
+ this._wsSend({
3729
+ type: 'vad_events',
3730
+ event: 'vad_end',
3731
+ });
3732
+ }
3725
3733
  }
3726
3734
  }
3727
3735
  catch (error) {
@@ -3867,6 +3875,25 @@ registerProcessor('audio_processor', AudioProcessor);
3867
3875
  getStream() {
3868
3876
  return this.wavRecorder.getStream();
3869
3877
  }
3878
+ /**
3879
+ * Switches the input device for the microphone and restarts recording
3880
+ * @param {string} deviceId - The deviceId of the new microphone
3881
+ */
3882
+ async setInputDevice(deviceId) {
3883
+ if (this.wavRecorder) {
3884
+ try {
3885
+ await this.wavRecorder.end();
3886
+ }
3887
+ catch (e) { }
3888
+ try {
3889
+ await this.wavRecorder.quit();
3890
+ }
3891
+ catch (e) { }
3892
+ }
3893
+ await this.wavRecorder.begin(deviceId);
3894
+ await this.wavRecorder.record(this._handleDataAvailable, 1638);
3895
+ this._setupAmplitudeMonitoring(this.wavRecorder, this.options.onUserAmplitudeChange, (amp) => (this.userAudioAmplitude = amp));
3896
+ }
3870
3897
  }
3871
3898
 
3872
3899
  return LayercodeClient;