protected setupAudioRedWorker()

in src/transceivercontroller/DefaultTransceiverController.ts [469:575]


  protected setupAudioRedWorker(): void {
    // @ts-ignore
    const supportsRTCScriptTransform = !!window.RTCRtpScriptTransform;
    // @ts-ignore
    const supportsInsertableStreams = !!RTCRtpSender.prototype.createEncodedStreams;

    if (supportsRTCScriptTransform) {
      // This is the prefered approach according to
      // https://github.com/w3c/webrtc-encoded-transform/blob/main/explainer.md.
      this.logger.info(
        '[AudioRed] Supports encoded insertable streams using RTCRtpScriptTransform'
      );
    } else if (supportsInsertableStreams) {
      this.logger.info('[AudioRed] Supports encoded insertable streams using TransformStream');
    } else {
      this.disableAudioRedundancy();
      // We need to recreate the peer connection without encodedInsertableStreams in the
      // peer connection config otherwise we would need to create pass through transforms
      // for all media streams. Throwing the error here and having AttackMediaInputTask throw the
      // error again will result in a full reconnect.
      throw new Error(
        '[AudioRed] Encoded insertable streams not supported. Recreating peer connection with audio redundancy disabled.'
      );
    }

    // Run the entire redundant audio worker setup in a `try` block to allow any errors to trigger a reconnect with
    // audio redundancy disabled.
    try {
      this.audioRedWorkerURL = URL.createObjectURL(
        new Blob([RedundantAudioEncoderWorkerCode], {
          type: 'application/javascript',
        })
      );
      this.logger.info(`[AudioRed] Redundant audio worker URL ${this.audioRedWorkerURL}`);
      this.audioRedWorker = new Worker(this.audioRedWorkerURL);
    } catch (error) {
      this.logger.error(`[AudioRed] Unable to create audio red worker due to ${error}`);
      URL.revokeObjectURL(this.audioRedWorkerURL);
      this.audioRedWorkerURL = null;
      this.audioRedWorker = null;

      this.disableAudioRedundancy();
      this.logger.info(`[AudioRed] Recreating peer connection with audio redundancy disabled`);

      // We need to recreate the peer connection without encodedInsertableStreams in the
      // peer connection config otherwise we would need to create pass through transforms
      // for all media streams. Throwing the error here and having AttackMediaInputTask throw the
      // error again will result in a full reconnect.
      throw error;
    }
    this.audioRedEnabled = true;

    // We cannot use console.log in production code and we cannot
    // transfer the logger object so we need the worker to post messages
    // to the main thread for logging
    this.audioRedWorker.onmessage = (event: MessageEvent) => {
      /* istanbul ignore else */
      if (event.data.type === 'REDWorkerLog') {
        this.logger.info(event.data.log);
      } /* istanbul ignore next */ else if (event.data.type === 'RedundantAudioEncoderStats') {
        const redMetricReport = new RedundantAudioRecoveryMetricReport();
        redMetricReport.currentTimestampMs = Date.now();
        redMetricReport.ssrc = event.data.ssrc;
        redMetricReport.totalAudioPacketsLost = event.data.totalAudioPacketsLost;
        redMetricReport.totalAudioPacketsExpected = event.data.totalAudioPacketsExpected;
        redMetricReport.totalAudioPacketsRecoveredRed = event.data.totalAudioPacketsRecoveredRed;
        redMetricReport.totalAudioPacketsRecoveredFec = event.data.totalAudioPacketsRecoveredFec;
        this.forEachRedMetricsObserver(redMetricReport);
      }
    };

    if (supportsRTCScriptTransform) {
      // @ts-ignore
      this._localAudioTransceiver.sender.transform = new RTCRtpScriptTransform(
        this.audioRedWorker,
        { type: 'SenderTransform' }
      );
      // @ts-ignore
      this._localAudioTransceiver.receiver.transform = new RTCRtpScriptTransform(
        this.audioRedWorker,
        { type: 'ReceiverTransform' }
      );
      // eslint-disable-next-line
    } else /* istanbul ignore else */ if (supportsInsertableStreams) {
      // @ts-ignore
      const sendStreams = this._localAudioTransceiver.sender.createEncodedStreams();
      // @ts-ignore
      const receiveStreams = this._localAudioTransceiver.receiver.createEncodedStreams();
      this.audioRedWorker.postMessage(
        {
          msgType: 'StartRedWorker',
          send: sendStreams,
          receive: receiveStreams,
        },
        [
          sendStreams.readable,
          sendStreams.writable,
          receiveStreams.readable,
          receiveStreams.writable,
        ]
      );
    }
    /* istanbul ignore next */
    this.meetingSessionContext?.audioVideoController.addObserver(this);
    /* istanbul ignore next */
    this.addRedundantAudioRecoveryMetricsObserver(this.meetingSessionContext?.statsCollector);
  }