Skip to main content
Version: 5.x.x

On / Off Camera - Flutter

This feature enables hosts to turn their cameras on or off to share their video stream with other hosts and audience members during the livestream. Only hosts (in SEND_AND_RECV mode) can broadcast their camera feed, while audience members (in RECV_ONLY mode) can view it in real time.

enableCam()​

  • By using the enableCam() function of the Room class, the host can publish their video to other hosts and audience members.

  • You can also pass a customised video track in enableCam() by using Custom Video Track.

  • Video stream of the participant can be accessed from the streams property of Participant object.

  • room.isCamEnabled tells you whether your own camera is on.

disableCam()​

  • By using the disableCam() function of the Room Class, the host can stop publishing their video to other hosts and audience members.

enableCam() and disableCam() return a Future that throws a VideoSDKError when the SDK refuses the call, for example 3054 when the camera is already on or off, or 3055 while another camera change is still running. await them inside try/catch. On Android, a call made while the livestream reconnects is reported on Events.error instead of being thrown, so keep an Events.error handler too.

Events associated with enableCam​

  • Every Participant will receive a callback on Events.streamEnabled of the Room object with RTCStream object. stream.participantId is the id of the host who turned the camera on.

Events associated with disableCam​

  • Every Participant will receive a callback on Events.streamDisabled of the Room object with RTCStream object. stream.participantId is the id of the host who turned the camera off.

streamEnabled and streamDisabled also reach handlers added with participant.on() on the participant who owns the stream.

import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';

class ParticipantTile extends StatefulWidget {
final Room room;
final Participant participant;
const ParticipantTile(
{super.key, required this.room, required this.participant});

@override
State<ParticipantTile> createState() => _ParticipantTileState();
}

class _ParticipantTileState extends State<ParticipantTile> {
RTCStream? videoStream;

@override
void initState() {
super.initState();
// initial video stream for the participant
//Check if camera stream is already present
videoStream = widget.participant.streams.values
.where((stream) => stream.kind == MediaType.VIDEO)
.firstOrNull;
_initStreamListeners();
}

Future<void> enableCam() async {
try {
await widget.room.enableCam();
} on VideoSDKError catch (error) {
print("enableCam failed: ${error.code} ${error.name}");
}
}

Future<void> disableCam() async {
try {
await widget.room.disableCam();
} on VideoSDKError catch (error) {
print("disableCam failed: ${error.code} ${error.name}");
}
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Camera of ${widget.participant.displayName} is ${videoStream != null ? "on" : "off"}"),
// The buttons act on your own camera, so show them on your own tile.
if (widget.participant.isLocal) ...[
ElevatedButton(
onPressed: enableCam,
child: const Text("Enable Camera"),
),
ElevatedButton(
onPressed: disableCam,
child: const Text("Disable Camera"),
),
],
],
);
}

//Change state according to the events received
void _initStreamListeners() {
widget.room.on(Events.streamEnabled, _onStreamEnabled);
widget.room.on(Events.streamDisabled, _onStreamDisabled);
}

bool _isVideoOfThisParticipant(RTCStream stream) =>
stream.participantId == widget.participant.id && stream.kind == MediaType.VIDEO;

void _onStreamEnabled(RTCStream stream) {
if (_isVideoOfThisParticipant(stream)) {
setState(() => videoStream = stream);
}
}

void _onStreamDisabled(RTCStream stream) {
if (_isVideoOfThisParticipant(stream)) {
setState(() => videoStream = null);
}
}

@override
void dispose() {
// The room outlives the tile, so remove the handlers from it.
widget.room.off(Events.streamEnabled, _onStreamEnabled);
widget.room.off(Events.streamDisabled, _onStreamDisabled);
super.dispose();
}
}

Video Permissions​

  • If permissions are not granted, use the requestPermissions() method of the VideoSDK class to prompt users to grant access to their devices.
  • On Android, the SDK does not ask for camera permission. Call requestPermissions() before enableCam(). Without the permission, the camera stays off: enableCam() throws error 3017, and the same error reaches Events.error.
  • To enable requesting of camera permission on iOS devices, add the following to your Info.plist, located at <project root>/ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) Camera Usage!</string>
note

In case permissions are blocked by the user, the permission request dialogue cannot be re-rendered programmatically. In such cases, consider providing guidance to users on manually adjusting their permissions.

Future<void> requestMediaPermissions() async {
try {
//For requesting just video permission.
Map<String, bool> reqVideoPermissions =
await VideoSDK.requestPermissions(Permissions.VIDEO);
if (reqVideoPermissions['video'] != true) {
// The user did not allow the camera.
}
} catch (ex) {
print("Error in requestPermission ");
}
}
  • Requesting permissions if not already granted:

API Reference​

The API references for all the methods and events utilised in this guide are provided below.

Got a Question? Ask us on discord