import {
  AudioStream,
  RemoteParticipant,
  RoomEvent,
  TrackSource,
  isFrameProcessor
} from "@livekit/rtc-node";
import { log } from "../../log.js";
import { resampleStream } from "../../utils.js";
import { AudioInput } from "../io.js";
class ParticipantAudioInputStream extends AudioInput {
  room;
  sampleRate;
  numChannels;
  noiseCancellation;
  frameProcessor;
  publication = null;
  participantIdentity = null;
  currentInputId = null;
  logger = log();
  constructor({
    room,
    sampleRate,
    numChannels,
    noiseCancellation
  }) {
    super();
    this.room = room;
    this.sampleRate = sampleRate;
    this.numChannels = numChannels;
    if (isFrameProcessor(noiseCancellation)) {
      this.frameProcessor = noiseCancellation;
    } else {
      this.noiseCancellation = noiseCancellation;
    }
    this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);
    this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);
  }
  setParticipant(participant) {
    this.logger.debug({ participant }, "setting participant audio input");
    const participantIdentity = participant instanceof RemoteParticipant ? participant.identity : participant;
    if (this.participantIdentity === participantIdentity) {
      return;
    }
    if (this.participantIdentity) {
      this.closeStream();
    }
    this.participantIdentity = participantIdentity;
    if (!participantIdentity) {
      return;
    }
    const participantValue = participant instanceof RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
    const trackPublicationsArray = Array.from((participantValue == null ? void 0 : participantValue.trackPublications.values()) ?? []);
    this.logger.info(
      {
        participantValue: participantValue == null ? void 0 : participantValue.identity,
        trackPublications: trackPublicationsArray,
        lengthOfTrackPublications: trackPublicationsArray.length
      },
      "participantValue.trackPublications"
    );
    if (participantValue) {
      for (const publication of participantValue.trackPublications.values()) {
        if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {
          this.onTrackSubscribed(publication.track, publication, participantValue);
          break;
        }
      }
    }
  }
  onTrackUnpublished = (publication, participant) => {
    var _a;
    if (((_a = this.publication) == null ? void 0 : _a.sid) !== publication.sid || participant.identity !== this.participantIdentity) {
      return;
    }
    this.closeStream();
    for (const publication2 of participant.trackPublications.values()) {
      if (publication2.track && this.onTrackSubscribed(publication2.track, publication2, participant)) {
        return;
      }
    }
  };
  closeStream() {
    if (this.currentInputId) {
      void this.multiStream.removeInputStream(this.currentInputId);
      this.currentInputId = null;
    }
    this.publication = null;
  }
  onTrackSubscribed = (track, publication, participant) => {
    this.logger.debug({ participant: participant.identity }, "onTrackSubscribed in _input");
    if (this.participantIdentity !== participant.identity || publication.source !== TrackSource.SOURCE_MICROPHONE || this.publication && this.publication.sid === publication.sid) {
      return false;
    }
    this.closeStream();
    this.publication = publication;
    this.currentInputId = this.multiStream.addInputStream(
      resampleStream({
        stream: this.createStream(track),
        outputRate: this.sampleRate
      })
    );
    return true;
  };
  createStream(track) {
    return new AudioStream(track, {
      sampleRate: this.sampleRate,
      numChannels: this.numChannels,
      noiseCancellation: this.frameProcessor || this.noiseCancellation,
      // Don't let the AudioStream close the processor when the track switches —
      // this input stream owns the processor across track changes and closes it
      // itself in close().
      autoCloseNoiseCancellation: false
      // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting
    });
  }
  async close() {
    var _a;
    this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);
    this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);
    this.closeStream();
    await super.close();
    (_a = this.frameProcessor) == null ? void 0 : _a.close();
    this.frameProcessor = void 0;
  }
}
export {
  ParticipantAudioInputStream
};
//# sourceMappingURL=_input.js.map