clickVideo function
- ClickVideoOptions options
Toggles the video stream on or off based on the user's input and checks required permissions and constraints.
Parameters:
options
(ClickVideoOptions
): Contains the parameters needed for toggling video, including:checkMediaPermission
: Boolean to verify media permission.hasCameraPermission
: Boolean indicating if camera permission is granted.videoAlreadyOn
: Boolean to check if the video is already on.audioOnlyRoom
: Boolean indicating if the room is audio-only.recordStarted
,recordResumed
,recordPaused
,recordStopped
: Flags for recording state.recordingMediaOptions
: String defining the current recording mode ("video" or "audio").islevel
: User level (e.g., host, co-host).showAlert
: Optional function for displaying alerts.vidCons
: Video constraints for video width, height, etc.frameRate
: Preferred frame rate for video.userDefaultVideoInputDevice
: The device ID of the user's preferred video input device.currentFacingMode
: The facing mode for the camera (e.g., front or back).
Process:
-
Permission and Recording State Check:
- Checks if the user is in an audio-only room or if video toggling conflicts with ongoing recording.
-
Video Turn Off:
- If the video is already on, it disables the video tracks and disconnects the transport.
-
Video Turn On:
- Checks for admin or co-host restrictions before proceeding.
- If permitted, requests camera access if not already granted, applies media constraints, and initiates the video stream.
Helper Functions:
- _buildMediaConstraints: Builds media constraints using device ID and other parameters.
- _buildAltMediaConstraints: Builds alternative media constraints when the preferred device is unavailable.
- _buildFinalMediaConstraints: Builds final media constraints for the video stream.
- _attemptStream: Attempts to initialize the video stream with the specified constraints.
Example Usage:
final options = ClickVideoOptions(
parameters: ClickVideoParameters(
checkMediaPermission: true,
hasCameraPermission: false,
videoAlreadyOn: false,
audioOnlyRoom: false,
showAlert: (message, type, duration) => print('Alert: $message'),
vidCons: VidCons(width: 1280, height: 720),
frameRate: 30,
userDefaultVideoInputDevice: 'front',
currentFacingMode: 'user',
),
);
await clickVideo(options);
Error Handling:
- Handles permission issues by displaying alerts.
- Attempts to access alternative video devices if the preferred device is unavailable.
- Displays a message if camera access is denied or unavailable.
Implementation
Future<void> clickVideo(ClickVideoOptions options) async {
final parameters = options.parameters.getUpdatedAllParams();
final checkMediaPermission = parameters.checkMediaPermission;
final hasCameraPermission = parameters.hasCameraPermission;
bool videoAlreadyOn = parameters.videoAlreadyOn;
final audioOnlyRoom = parameters.audioOnlyRoom;
final recordStarted = parameters.recordStarted;
final recordResumed = parameters.recordResumed;
final recordPaused = parameters.recordPaused;
final recordStopped = parameters.recordStopped;
final recordingMediaOptions = parameters.recordingMediaOptions;
final islevel = parameters.islevel;
final youAreCoHost = parameters.youAreCoHost;
final adminRestrictSetting = parameters.adminRestrictSetting;
final videoRequestState = parameters.videoRequestState;
final videoRequestTime = parameters.videoRequestTime;
final member = parameters.member;
final socket = parameters.socket;
final roomName = parameters.roomName;
final userDefaultVideoInputDevice = parameters.userDefaultVideoInputDevice;
final currentFacingMode = parameters.currentFacingMode;
final vidCons = parameters.vidCons;
final frameRate = parameters.frameRate;
final videoAction = parameters.videoAction;
var localStream = parameters.localStream;
final audioSetting = parameters.audioSetting;
final videoSetting = parameters.videoSetting;
final screenshareSetting = parameters.screenshareSetting;
final chatSetting = parameters.chatSetting;
final updateRequestIntervalSeconds = parameters.updateRequestIntervalSeconds;
final streamSuccessVideo = parameters.streamSuccessVideo;
final showAlert = parameters.showAlert;
final updateVideoAlreadyOn = parameters.updateVideoAlreadyOn;
final updateVideoRequestState = parameters.updateVideoRequestState;
final updateLocalStream = parameters.updateLocalStream;
final disconnectSendTransportVideo = parameters.disconnectSendTransportVideo;
final requestPermissionCamera = parameters.requestPermissionCamera;
final checkPermission = parameters.checkPermission;
if (audioOnlyRoom) {
showAlert?.call(
message: 'You cannot turn on your camera in an audio-only event.',
type: 'danger',
duration: 3000,
);
return;
}
if (videoAlreadyOn) {
if (islevel == '2' && (recordStarted || recordResumed)) {
if (!(recordPaused || recordStopped) &&
recordingMediaOptions == 'video') {
showAlert?.call(
message:
'You cannot turn off your camera while recording video. Please pause or stop recording first.',
type: 'danger',
duration: 3000,
);
return;
}
}
videoAlreadyOn = false;
updateVideoAlreadyOn(videoAlreadyOn);
localStream!.getVideoTracks()[0].enabled = false;
updateLocalStream(localStream);
final optionsDisconnect = DisconnectSendTransportVideoOptions(
parameters: parameters,
);
await disconnectSendTransportVideo(optionsDisconnect);
} else {
if (adminRestrictSetting) {
showAlert?.call(
message: 'You cannot turn on your camera. Access denied by host.',
duration: 3000,
type: 'danger',
);
return;
}
int response = 2;
if (!videoAction && islevel != '2' && !youAreCoHost) {
final optionsCheck = CheckPermissionOptions(
permissionType: 'videoSetting',
audioSetting: audioSetting,
videoSetting: videoSetting,
screenshareSetting: screenshareSetting,
chatSetting: chatSetting,
);
response = await checkPermission(
optionsCheck,
);
} else {
response = 0;
}
if (response == 1) {
if (videoRequestState == 'pending') {
showAlert?.call(
message: 'A request is pending. Please wait for the host to respond.',
type: 'danger',
duration: 3000,
);
return;
}
if (videoRequestState == 'rejected' &&
DateTime.now().millisecondsSinceEpoch - videoRequestTime! <
updateRequestIntervalSeconds) {
showAlert?.call(
message:
'A request was rejected. Please wait $updateRequestIntervalSeconds seconds before sending another request.',
type: 'danger',
duration: 3000,
);
return;
}
showAlert?.call(
message: 'Request sent to host.',
type: 'success',
duration: 3000,
);
updateVideoRequestState('pending');
socket!.emit('participantRequest', {
'userRequest': {'id': socket.id, 'name': member, 'icon': 'fa-video'},
'roomName': roomName,
});
} else if (response == 2) {
showAlert?.call(
message: 'You cannot turn on your camera. Access denied by host.',
type: 'danger',
duration: 3000,
);
} else {
if (!hasCameraPermission && checkMediaPermission) {
final statusCamera = await requestPermissionCamera();
if (!statusCamera) {
showAlert?.call(
message:
'Allow access to your camera or check if your camera is not being used by another application.',
type: 'danger',
duration: 3000,
);
return;
}
}
Map<String, dynamic> mediaConstraints =
userDefaultVideoInputDevice.isNotEmpty
? _buildMediaConstraints(userDefaultVideoInputDevice, vidCons,
currentFacingMode, frameRate)
: _buildAltMediaConstraints(vidCons, frameRate);
try {
await _attemptStream(
mediaConstraints, streamSuccessVideo, parameters, showAlert);
} catch (error) {
mediaConstraints = _buildAltMediaConstraints(vidCons, frameRate);
try {
await _attemptStream(
mediaConstraints, streamSuccessVideo, parameters, showAlert);
} catch (error) {
mediaConstraints = _buildFinalMediaConstraints(vidCons);
try {
await _attemptStream(
mediaConstraints, streamSuccessVideo, parameters, showAlert);
} catch (error) {
showAlert?.call(
message:
'Allow access to your camera or check if it is not being used by another application.',
type: 'danger',
duration: 3000,
);
}
}
}
}
}
}