produce method

Future<void> produce({
  1. required String label,
  2. required MediaStream? stream,
  3. bool? stopTrackOnClose = false,
  4. Map<String, dynamic>? appData,
})

Produce a stream with a given label and appData to all the Remote Peers

Implementation

Future<void> produce({
  required String label,
  required MediaStream? stream,
  bool? stopTrackOnClose = false,
  Map<String, dynamic>? appData,
}) async {
  logger.i("produce called");

  try {
    if (!checkPermission(permissionTypeCheck: PermissionType.canProduce)) {
      logger.e('Access Denied: Cannot Produce');
      return;
    }
    String? kind = stream != null ? getMediaStreamKind(stream) : null;
    MediaStreamTrack? track;
    if (label == 'audio') {
      track = stream?.getAudioTracks().first;
    } else {
      track = stream?.getVideoTracks().first;
    }

    if (track != null) {
      track.onEnded = () {
        stopProducing(label: label);
      };
    }

    if (!joined ||
        (_sendTransport?.connectionState != 'connected' &&
            _sendTransport?.connectionState != 'new')) {
      final completer = Completer<void>();

      Future<void> fn() async {
        try {
          await produce(label: label, stream: stream);
          completer.complete();
        } finally {
          _pendingProducerTasks.remove(label);
        }
      }

      _waitingToProduce[label] = fn;
      return completer.future;
    }

    if (_sendTransport == null) {
      throw StateError('❌ Send Transport Not Initialized, Internal Error');
    }
    logger.i("🔔 Produce Called for kind: $kind, label: $label");

    // RtpCodecCapability? videoCodec =
    //     _device?.rtpCapabilities.codecs.firstWhere(
    //   (RtpCodecCapability c) =>
    //       c.mimeType.toLowerCase() == 'video/vp9' ||
    //       c.mimeType.toLowerCase() == 'video/h265',
    //   // || c.mimeType.toLowerCase() == 'video/vp8',
    //   orElse: () => throw 'desired codec-configuration is not supported',
    // );

    if (stream != null) {
      if (label == 'audio') {
        logger.i("localPeer-produce | audio");

        _sendTransport?.produce(
          track: stream.getAudioTracks().first,
          codecOptions: ProducerCodecOptions(
            opusStereo: 1,
            opusDtx: 1,
          ),
          stream: stream,
          stopTracks: true,
          zeroRtpOnPause: true,
          disableTrackOnPause: stopTrackOnClose ?? false,
          source: label,
          appData: {
            'producerPeerId': peerId,
            'label': label,
          },
          accept: (params) async {
            logger.d(params);
          },
        );
      }
      if (label == 'video') {
        logger.i("localPeer-produce | video");
        _sendTransport?.produce(
          track: stream.getVideoTracks().first,
          codecOptions: ProducerCodecOptions(
            videoGoogleStartBitrate: 1000,
          ),
          // codec: videoCodec,
          // encodings: [],
          stream: stream,
          source: label,
          appData: {
            'producerPeerId': peerId,
            'label': label,
            'targetPeerIds': '*',
          },
          accept: (params) async {
            logger.d(params);
          },
        );
      }
    }
    _sendTransport?.on('transportclose', () {
      stopProducing(label: label);
    });

    emit('stream-playable', {
      'label': label,
    });
    logger.i('🔔 Producer Created sucessfully with label : $label');
  } catch (error) {
    logger.e('❌ Error Create Producer Failed | error: $error');
    throw Exception('❌ Error Create Producer Failed');
  }
}