clickAudio function

Future<void> clickAudio(
  1. ClickAudioOptions options
)

Toggles audio for a user, either enabling or disabling the microphone.

Parameters:

  • options (ClickAudioOptions): Contains all required parameters and callbacks.
    • parameters (ClickAudioParameters): The key configurations for permissions, media settings, callback functions, and state variables.

Workflow:

  1. Audio Toggle:

    • Disable: Checks if recording is active and if it's safe to disable audio.
    • Enable: Verifies permissions and sends a request to the host if necessary.
  2. Permissions & Requests:

    • If the user lacks permissions, sends a request to the host or prompts for permissions.
    • Uses callbacks to update the UI and emit requests or permission checks.
  3. Media Constraints:

    • Configures constraints for getUserMedia based on device and user preference.

Example Usage:

final parameters = ClickAudioParameters(
  checkMediaPermission: true,
  hasAudioPermission: false,
  audioPaused: false,
  // Other properties and callbacks...
);

await clickAudio(ClickAudioOptions(parameters: parameters));

Error Handling:

  • Logs any errors to the console in debug mode.

Implementation

Future<void> clickAudio(ClickAudioOptions options) async {
  try {
    final parameters = options.parameters;

    // Destructure parameters
    final bool checkMediaPermission = parameters.checkMediaPermission;
    bool hasAudioPermission = parameters.hasAudioPermission;
    bool audioPaused = parameters.audioPaused;
    bool audioAlreadyOn = parameters.audioAlreadyOn;
    final bool audioOnlyRoom = parameters.audioOnlyRoom;
    final bool recordStarted = parameters.recordStarted;
    final bool recordResumed = parameters.recordResumed;
    final bool recordPaused = parameters.recordPaused;
    final bool recordStopped = parameters.recordStopped;
    final String recordingMediaOptions = parameters.recordingMediaOptions;
    final String islevel = parameters.islevel;
    final bool youAreCoHost = parameters.youAreCoHost;
    final bool adminRestrictSetting = parameters.adminRestrictSetting;
    String? audioRequestState = parameters.audioRequestState;
    final int? audioRequestTime = parameters.audioRequestTime;
    final String member = parameters.member;
    final io.Socket? socket = parameters.socket;
    final io.Socket? localSocket = parameters.localSocket;
    final String roomName = parameters.roomName;
    final String userDefaultAudioInputDevice =
        parameters.userDefaultAudioInputDevice;
    bool micAction = parameters.micAction;
    MediaStream? localStream = parameters.localStream;
    final String audioSetting = parameters.audioSetting;
    final String videoSetting = parameters.videoSetting;
    final String screenshareSetting = parameters.screenshareSetting;
    final String chatSetting = parameters.chatSetting;
    final int updateRequestIntervalSeconds =
        parameters.updateRequestIntervalSeconds;
    final List<Participant> participants = parameters.participants;
    bool transportCreated = parameters.transportCreated;
    bool transportCreatedAudio = parameters.transportCreatedAudio;

    // Callback functions
    final updateAudioAlreadyOn = parameters.updateAudioAlreadyOn;
    final updateAudioRequestState = parameters.updateAudioRequestState;
    final updateAudioPaused = parameters.updateAudioPaused;
    final updateLocalStream = parameters.updateLocalStream;
    final updateParticipants = parameters.updateParticipants;
    final updateTransportCreated = parameters.updateTransportCreated;
    final updateTransportCreatedAudio = parameters.updateTransportCreatedAudio;
    final updateMicAction = parameters.updateMicAction;
    final showAlert = parameters.showAlert;

    // mediasfu functions
    final checkPermission = parameters.checkPermission;
    final streamSuccessAudio = parameters.streamSuccessAudio;
    final requestPermissionAudio = parameters.requestPermissionAudio;
    final disconnectSendTransportAudio =
        parameters.disconnectSendTransportAudio;
    final resumeSendTransportAudio = parameters.resumeSendTransportAudio;

    if (audioOnlyRoom) {
      showAlert?.call(
          message: "You cannot turn on your camera in an audio-only event.",
          type: "danger",
          duration: 3000);
      return;
    }

    if (audioAlreadyOn) {
      // Check and alert before turning off
      if (islevel == '2' &&
          (recordStarted || recordResumed) &&
          !(recordPaused || recordStopped) &&
          recordingMediaOptions == 'audio') {
        showAlert?.call(
            message:
                "You cannot turn off your audio while recording, please pause or stop recording first.",
            type: "danger",
            duration: 3000);
        return;
      }

      // Update the icon and turn off audio
      audioAlreadyOn = false;
      updateAudioAlreadyOn(audioAlreadyOn);
      localStream?.getAudioTracks()[0].enabled = false;
      updateLocalStream(localStream);
      final optionsDisconnect = DisconnectSendTransportAudioOptions(
        parameters: parameters,
      );
      await disconnectSendTransportAudio(optionsDisconnect);
      audioPaused = true;
      updateAudioPaused(audioPaused);
    } else {
      if (adminRestrictSetting) {
        showAlert?.call(
            message:
                "You cannot turn on your microphone. Access denied by host.",
            type: "danger",
            duration: 3000);
        return;
      }

      int response = 2;

      if (!micAction && islevel != '2' && !youAreCoHost) {
        final optionsCheck = CheckPermissionOptions(
          permissionType: 'audioSetting',
          audioSetting: audioSetting,
          videoSetting: videoSetting,
          screenshareSetting: screenshareSetting,
          chatSetting: chatSetting,
        );
        response = await checkPermission(optionsCheck);
      } else {
        response = 0;
      }

      switch (response) {
        case 1:
          if (audioRequestState == 'pending') {
            showAlert?.call(
                message:
                    "A request is pending. Please wait for the host to respond.",
                type: "danger",
                duration: 3000);
            return;
          }

          if (audioRequestState == 'rejected' &&
              DateTime.now().millisecondsSinceEpoch - audioRequestTime! <
                  updateRequestIntervalSeconds * 1000) {
            showAlert?.call(
                message:
                    "A request was rejected. Please wait for $updateRequestIntervalSeconds seconds before sending another request.",
                type: "danger",
                duration: 3000);
            return;
          }

          showAlert?.call(
              message: "Request sent to host.",
              type: "success",
              duration: 3000);
          audioRequestState = 'pending';
          updateAudioRequestState(audioRequestState);

          final userRequest = {
            'id': socket!.id,
            'name': member,
            'icon': 'fa-microphone'
          };
          socket.emit('participantRequest',
              {'userRequest': userRequest, 'roomName': roomName});
          break;

        case 2:
          showAlert?.call(
            message:
                'You cannot turn on your microphone. Access denied by host.',
            type: 'danger',
            duration: 3000,
          );

          break;

        case 0:
          if (audioPaused) {
            localStream?.getAudioTracks()[0].enabled = true;
            updateAudioAlreadyOn(true);
            final optionsResume = ResumeSendTransportAudioOptions(
              parameters: parameters,
            );
            await resumeSendTransportAudio(options: optionsResume);
            socket!.emit("resumeProducerAudio",
                {"mediaTag": "audio", "roomName": roomName});

            try {
              if (localSocket != null && localSocket.id != null) {
                localSocket.emit("resumeProducerAudio",
                    {"mediaTag": "audio", "roomName": roomName});
              }
            } catch (e) {
              if (kDebugMode) {
                print(e);
              }
            }

            updateLocalStream(localStream);
            if (micAction == true) {
              micAction = false;
              updateMicAction(micAction);
            }

            for (var participant in participants) {
              if (participant['socketId'] == socket.id &&
                  participant.name == member) {
                participant.muted = false;
              }
            }
            updateParticipants(participants);

            transportCreated = true;
            updateTransportCreated(transportCreated);
            transportCreatedAudio = true;
            updateTransportCreatedAudio(transportCreatedAudio);
          } else {
            // First check if permission is granted
            if (!hasAudioPermission) {
              if (checkMediaPermission) {
                bool statusMic = await requestPermissionAudio();
                if (statusMic != true) {
                  showAlert?.call(
                      message:
                          "Allow access to your microphone or check if your microphone is not being used by another application.",
                      type: "danger",
                      duration: 3000);
                  return;
                }
              }
            }

            final mediaConstraints = userDefaultAudioInputDevice.isNotEmpty
                ? {
                    'audio': {'deviceId': userDefaultAudioInputDevice},
                    'video': false
                  }
                : {'audio': true, 'video': false};

            try {
              final stream =
                  await navigator.mediaDevices.getUserMedia(mediaConstraints);
              final optionsStream = StreamSuccessAudioOptions(
                parameters: parameters,
                stream: stream,
                audioConstraints: mediaConstraints,
              );
              await streamSuccessAudio(optionsStream);
            } catch (error) {
              showAlert?.call(
                  message:
                      "Allow access to your microphone or check if your microphone is not being used by another application.",
                  type: "danger",
                  duration: 3000);
            }
          }
          break;

        default:
          break;
      }
    }
  } catch (error) {
    if (kDebugMode) {
      print('Error in clickAudio: $error');
    }
  }
}