@layercode/js-sdk 2.8.1 → 2.8.2

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.
@@ -5968,6 +5968,7 @@ registerProcessor('audio_processor', AudioProcessor);
5968
5968
  this.canInterrupt = false;
5969
5969
  this.userIsSpeaking = false;
5970
5970
  this.agentIsSpeaking = false;
5971
+ this.agentIsPlayingAudio = false;
5971
5972
  this.recorderStarted = false;
5972
5973
  this.readySent = false;
5973
5974
  this.currentTurnId = null;
@@ -6120,6 +6121,8 @@ registerProcessor('audio_processor', AudioProcessor);
6120
6121
  await this.audioOutputReady;
6121
6122
  }
6122
6123
  _setAgentSpeaking(isSpeaking) {
6124
+ // Track the actual audio playback state regardless of audioOutput setting
6125
+ this.agentIsPlayingAudio = isSpeaking;
6123
6126
  const shouldReportSpeaking = this.audioOutput && isSpeaking;
6124
6127
  if (this.agentIsSpeaking === shouldReportSpeaking) {
6125
6128
  return;
@@ -6213,11 +6216,24 @@ registerProcessor('audio_processor', AudioProcessor);
6213
6216
  });
6214
6217
  break;
6215
6218
  }
6216
- case 'response.audio':
6219
+ case 'response.audio': {
6217
6220
  await this._waitForAudioOutputReady();
6218
- this._setAgentSpeaking(true);
6219
6221
  const audioBuffer = base64ToArrayBuffer(message.content);
6220
- this.wavPlayer.add16BitPCM(audioBuffer, message.turn_id);
6222
+ const hasAudioSamples = audioBuffer.byteLength > 0;
6223
+ let audioEnqueued = false;
6224
+ if (hasAudioSamples) {
6225
+ try {
6226
+ const playbackBuffer = this.wavPlayer.add16BitPCM(audioBuffer, message.turn_id);
6227
+ audioEnqueued = Boolean(playbackBuffer && playbackBuffer.length > 0);
6228
+ }
6229
+ catch (error) {
6230
+ this._setAgentSpeaking(false);
6231
+ throw error;
6232
+ }
6233
+ }
6234
+ else {
6235
+ console.debug(`Skipping empty audio response for turn ${message.turn_id}`);
6236
+ }
6221
6237
  // TODO: once we've added turn_id to the turn.start msgs sent from teh server, we should move this currentTurnId switching logic to the turn.start msg case. We can then remove the currentTurnId setting logic from the response.audio and response.text cases.
6222
6238
  // Set current turn ID from first audio message, or update if different turn
6223
6239
  if (!this.currentTurnId || this.currentTurnId !== message.turn_id) {
@@ -6226,7 +6242,11 @@ registerProcessor('audio_processor', AudioProcessor);
6226
6242
  // Clean up interrupted tracks, keeping only the current turn
6227
6243
  this.wavPlayer.clearInterruptedTracks(this.currentTurnId ? [this.currentTurnId] : []);
6228
6244
  }
6245
+ if (audioEnqueued) {
6246
+ this._setAgentSpeaking(true);
6247
+ }
6229
6248
  break;
6249
+ }
6230
6250
  case 'response.text':
6231
6251
  // Set turn ID from first text message if not set
6232
6252
  if (!this.currentTurnId) {
@@ -6438,6 +6458,8 @@ registerProcessor('audio_processor', AudioProcessor);
6438
6458
  this._emitAudioOutput();
6439
6459
  if (state) {
6440
6460
  this.wavPlayer.unmute();
6461
+ // Sync agentSpeaking state with actual playback state when enabling audio output
6462
+ this._syncAgentSpeakingState();
6441
6463
  }
6442
6464
  else {
6443
6465
  this.wavPlayer.mute();
@@ -6445,6 +6467,17 @@ registerProcessor('audio_processor', AudioProcessor);
6445
6467
  }
6446
6468
  }
6447
6469
  }
6470
+ /**
6471
+ * Syncs the reported agentSpeaking state with the actual audio playback state.
6472
+ * Called when audioOutput is enabled to ensure proper state synchronization.
6473
+ */
6474
+ _syncAgentSpeakingState() {
6475
+ const shouldReportSpeaking = this.audioOutput && this.agentIsPlayingAudio;
6476
+ if (this.agentIsSpeaking !== shouldReportSpeaking) {
6477
+ this.agentIsSpeaking = shouldReportSpeaking;
6478
+ this.options.onAgentSpeakingChange(shouldReportSpeaking);
6479
+ }
6480
+ }
6448
6481
  /** Emitters for audio flags */
6449
6482
  _emitAudioInput() {
6450
6483
  this.options.audioInputChanged(this.audioInput);