@livekit/agents 1.0.5 → 1.0.6

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.
@@ -59,6 +59,15 @@ class ParticipantAudioInputStream extends import_io.AudioInput {
59
59
  return;
60
60
  }
61
61
  const participantValue = participant instanceof import_rtc_node.RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
62
+ const trackPublicationsArray = Array.from((participantValue == null ? void 0 : participantValue.trackPublications.values()) ?? []);
63
+ this.logger.info(
64
+ {
65
+ participantValue: participantValue == null ? void 0 : participantValue.identity,
66
+ trackPublications: trackPublicationsArray,
67
+ lengthOfTrackPublications: trackPublicationsArray.length
68
+ },
69
+ "participantValue.trackPublications"
70
+ );
62
71
  if (participantValue) {
63
72
  for (const publication of participantValue.trackPublications.values()) {
64
73
  if (publication.track && publication.source === import_rtc_node.TrackSource.SOURCE_MICROPHONE) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n this.logger.debug({ participant: participant.identity }, 'onTrackSubscribed in _input');\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,sBASO;AAEP,iBAAoB;AACpB,mBAA+B;AAC/B,gBAA2B;AAEpB,MAAM,oCAAoC,qBAAW;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAA6C;AAAA,EAC7C,sBAAqC;AAAA,EACrC,aAAS,gBAAI;AAAA,EACrB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,SAAK,KAAK,GAAG,0BAAU,iBAAiB,KAAK,iBAAiB;AAC9D,SAAK,KAAK,GAAG,0BAAU,kBAAkB,KAAK,kBAAkB;AAAA,EAClE;AAAA,EAEA,eAAe,aAAgD;AAC7D,SAAK,OAAO,MAAM,EAAE,YAAY,GAAG,iCAAiC;AACpE,UAAM,sBACJ,uBAAuB,oCAAoB,YAAY,WAAW;AAEpE,QAAI,KAAK,wBAAwB,qBAAqB;AACpD;AAAA,IACF;AACA,SAAK,sBAAsB;AAC3B,SAAK,YAAY;AAEjB,QAAI,CAAC,qBAAqB;AACxB;AAAA,IACF;AAEA,UAAM,mBACJ,uBAAuB,oCACnB,cACA,KAAK,KAAK,mBAAmB,IAAI,mBAAmB;AAI1D,QAAI,kBAAkB;AACpB,iBAAW,eAAe,iBAAiB,kBAAkB,OAAO,GAAG;AACrE,YAAI,YAAY,SAAS,YAAY,WAAW,4BAAY,mBAAmB;AAC7E,eAAK,kBAAkB,YAAY,OAAO,aAAa,gBAAgB;AACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAAqB,CAC3B,aACA,gBACG;AAnFP;AAoFI,UACE,UAAK,gBAAL,mBAAkB,SAAQ,YAAY,OACtC,YAAY,aAAa,KAAK,qBAC9B;AACA;AAAA,IACF;AACA,SAAK,YAAY;AAGjB,eAAWA,gBAAe,YAAY,kBAAkB,OAAO,GAAG;AAChE,UACEA,aAAY,SACZ,KAAK,kBAAkBA,aAAY,OAAOA,cAAa,WAAW,GAClE;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,QAAI,KAAK,eAAe,aAAa;AACnC,WAAK,eAAe,aAAa;AAAA,IACnC;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,oBAAoB,CAC1B,OACA,aACA,gBACY;AACZ,SAAK,OAAO,MAAM,EAAE,aAAa,YAAY,SAAS,GAAG,6BAA6B;AACtF,QACE,KAAK,wBAAwB,YAAY,YACzC,YAAY,WAAW,4BAAY,qBAClC,KAAK,eAAe,KAAK,YAAY,QAAQ,YAAY,KAC1D;AACA,aAAO;AAAA,IACT;AACA,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,UAClB,6BAAe;AAAA,QACb,QAAQ,KAAK,aAAa,KAAK;AAAA,QAC/B,YAAY,KAAK;AAAA,MACnB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,OAAgD;AACnE,WAAO,IAAI,4BAAY,OAAO;AAAA,MAC5B,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA;AAAA,IAE1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,KAAK,IAAI,0BAAU,iBAAiB,KAAK,iBAAiB;AAC/D,SAAK,KAAK,IAAI,0BAAU,kBAAkB,KAAK,kBAAkB;AACjE,SAAK,YAAY;AACjB,SAAK,eAAe,OAAO,OAAO;AAAA,EACpC;AACF;","names":["publication"]}
1
+ {"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // Convert Map iterator to array for Pino serialization\n const trackPublicationsArray = Array.from(participantValue?.trackPublications.values() ?? []);\n\n this.logger.info(\n {\n participantValue: participantValue?.identity,\n trackPublications: trackPublicationsArray,\n lengthOfTrackPublications: trackPublicationsArray.length,\n },\n 'participantValue.trackPublications',\n );\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n this.logger.debug({ participant: participant.identity }, 'onTrackSubscribed in _input');\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":"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","names":["publication"]}
@@ -1 +1 @@
1
- {"version":3,"file":"_input.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_input.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,iBAAiB,EAGjB,KAAK,IAAI,EAGV,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,qBAAa,2BAA4B,SAAQ,UAAU;IACzD,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,MAAM,CAAS;gBACX,EACV,IAAI,EACJ,UAAU,EACV,WAAW,EACX,iBAAiB,GAClB,EAAE;QACD,IAAI,EAAE,IAAI,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;KAC9C;IAWD,cAAc,CAAC,WAAW,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IAgC7D,OAAO,CAAC,kBAAkB,CAqBxB;IAEF,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,iBAAiB,CAsBvB;IAEF,OAAO,CAAC,YAAY;IASd,KAAK;CAMZ"}
1
+ {"version":3,"file":"_input.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_input.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,iBAAiB,EAGjB,KAAK,IAAI,EAGV,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,qBAAa,2BAA4B,SAAQ,UAAU;IACzD,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,MAAM,CAAS;gBACX,EACV,IAAI,EACJ,UAAU,EACV,WAAW,EACX,iBAAiB,GAClB,EAAE;QACD,IAAI,EAAE,IAAI,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;KAC9C;IAWD,cAAc,CAAC,WAAW,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IA2C7D,OAAO,CAAC,kBAAkB,CAqBxB;IAEF,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,iBAAiB,CAsBvB;IAEF,OAAO,CAAC,YAAY;IASd,KAAK;CAMZ"}
@@ -41,6 +41,15 @@ class ParticipantAudioInputStream extends AudioInput {
41
41
  return;
42
42
  }
43
43
  const participantValue = participant instanceof RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
44
+ const trackPublicationsArray = Array.from((participantValue == null ? void 0 : participantValue.trackPublications.values()) ?? []);
45
+ this.logger.info(
46
+ {
47
+ participantValue: participantValue == null ? void 0 : participantValue.identity,
48
+ trackPublications: trackPublicationsArray,
49
+ lengthOfTrackPublications: trackPublicationsArray.length
50
+ },
51
+ "participantValue.trackPublications"
52
+ );
44
53
  if (participantValue) {
45
54
  for (const publication of participantValue.trackPublications.values()) {
46
55
  if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n this.logger.debug({ participant: participant.identity }, 'onTrackSubscribed in _input');\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":"AAIA;AAAA,EACE;AAAA,EAEA;AAAA,EAIA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,WAAW;AACpB,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAEpB,MAAM,oCAAoC,WAAW;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAA6C;AAAA,EAC7C,sBAAqC;AAAA,EACrC,SAAS,IAAI;AAAA,EACrB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,SAAK,KAAK,GAAG,UAAU,iBAAiB,KAAK,iBAAiB;AAC9D,SAAK,KAAK,GAAG,UAAU,kBAAkB,KAAK,kBAAkB;AAAA,EAClE;AAAA,EAEA,eAAe,aAAgD;AAC7D,SAAK,OAAO,MAAM,EAAE,YAAY,GAAG,iCAAiC;AACpE,UAAM,sBACJ,uBAAuB,oBAAoB,YAAY,WAAW;AAEpE,QAAI,KAAK,wBAAwB,qBAAqB;AACpD;AAAA,IACF;AACA,SAAK,sBAAsB;AAC3B,SAAK,YAAY;AAEjB,QAAI,CAAC,qBAAqB;AACxB;AAAA,IACF;AAEA,UAAM,mBACJ,uBAAuB,oBACnB,cACA,KAAK,KAAK,mBAAmB,IAAI,mBAAmB;AAI1D,QAAI,kBAAkB;AACpB,iBAAW,eAAe,iBAAiB,kBAAkB,OAAO,GAAG;AACrE,YAAI,YAAY,SAAS,YAAY,WAAW,YAAY,mBAAmB;AAC7E,eAAK,kBAAkB,YAAY,OAAO,aAAa,gBAAgB;AACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAAqB,CAC3B,aACA,gBACG;AAnFP;AAoFI,UACE,UAAK,gBAAL,mBAAkB,SAAQ,YAAY,OACtC,YAAY,aAAa,KAAK,qBAC9B;AACA;AAAA,IACF;AACA,SAAK,YAAY;AAGjB,eAAWA,gBAAe,YAAY,kBAAkB,OAAO,GAAG;AAChE,UACEA,aAAY,SACZ,KAAK,kBAAkBA,aAAY,OAAOA,cAAa,WAAW,GAClE;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,QAAI,KAAK,eAAe,aAAa;AACnC,WAAK,eAAe,aAAa;AAAA,IACnC;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,oBAAoB,CAC1B,OACA,aACA,gBACY;AACZ,SAAK,OAAO,MAAM,EAAE,aAAa,YAAY,SAAS,GAAG,6BAA6B;AACtF,QACE,KAAK,wBAAwB,YAAY,YACzC,YAAY,WAAW,YAAY,qBAClC,KAAK,eAAe,KAAK,YAAY,QAAQ,YAAY,KAC1D;AACA,aAAO;AAAA,IACT;AACA,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,MAClB,eAAe;AAAA,QACb,QAAQ,KAAK,aAAa,KAAK;AAAA,QAC/B,YAAY,KAAK;AAAA,MACnB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,OAAgD;AACnE,WAAO,IAAI,YAAY,OAAO;AAAA,MAC5B,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA;AAAA,IAE1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,KAAK,IAAI,UAAU,iBAAiB,KAAK,iBAAiB;AAC/D,SAAK,KAAK,IAAI,UAAU,kBAAkB,KAAK,kBAAkB;AACjE,SAAK,YAAY;AACjB,SAAK,eAAe,OAAO,OAAO;AAAA,EACpC;AACF;","names":["publication"]}
1
+ {"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // Convert Map iterator to array for Pino serialization\n const trackPublicationsArray = Array.from(participantValue?.trackPublications.values() ?? []);\n\n this.logger.info(\n {\n participantValue: participantValue?.identity,\n trackPublications: trackPublicationsArray,\n lengthOfTrackPublications: trackPublicationsArray.length,\n },\n 'participantValue.trackPublications',\n );\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n this.logger.debug({ participant: participant.identity }, 'onTrackSubscribed in _input');\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":"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","names":["publication"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livekit/agents",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "LiveKit Agents - Node.js",
5
5
  "main": "dist/index.js",
6
6
  "require": "dist/index.cjs",
@@ -66,6 +66,17 @@ export class ParticipantAudioInputStream extends AudioInput {
66
66
  ? participant
67
67
  : this.room.remoteParticipants.get(participantIdentity);
68
68
 
69
+ // Convert Map iterator to array for Pino serialization
70
+ const trackPublicationsArray = Array.from(participantValue?.trackPublications.values() ?? []);
71
+
72
+ this.logger.info(
73
+ {
74
+ participantValue: participantValue?.identity,
75
+ trackPublications: trackPublicationsArray,
76
+ lengthOfTrackPublications: trackPublicationsArray.length,
77
+ },
78
+ 'participantValue.trackPublications',
79
+ );
69
80
  // We need to check if the participant has a microphone track and subscribe to it
70
81
  // in case we miss the tracksubscribed event
71
82
  if (participantValue) {