Mute / Unmute Mic - Flutter
This feature allows hosts to communicate with each other during the livestream by enabling or disabling their microphones. While only hosts (participants in SEND_AND_RECV mode) can speak, audience members (in RECV_ONLY mode) can listen to the conversation in real time.
unmuteMic()
-
By using the
unmuteMic()function of theRoomclass, the host can publish their audio to other hosts and audience members. -
You can also pass a customised audio track in the
unmuteMic()method by using Custom Audio Track. -
Audio stream of the participant can be accessed from the
streamsmap of theParticipantobject. -
room.isMicEnabledtells you whether your own mic is on.
muteMic()
- By using the
muteMic()function of theRoomclass, the host can stop publishing their audio to other hosts and audience members.
unmuteMic() and muteMic() return a Future that throws a VideoSDKError when the SDK refuses the call, for example 3054 when the mic is already on or off, or 3055 while another mic 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 unmuteMic
- Every Participant will receive a callback on
Events.streamEnabledof theRoomobject withRTCStreamobject.stream.participantIdis the id of the host who unmuted.
Events associated with muteMic
- Every Participant will receive a callback on
Events.streamDisabledof theRoomobject withRTCStreamobject.stream.participantIdis the id of the host who muted.
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? audioStream;
@override
void initState() {
super.initState();
// initial audio stream for the participant
//Check if audio stream is already present
audioStream = widget.participant.streams.values
.where((stream) => stream.kind == MediaType.AUDIO)
.firstOrNull;
_initStreamListeners();
}
//Change state according to the events received
void _initStreamListeners() {
widget.room.on(Events.streamEnabled, _onStreamEnabled);
widget.room.on(Events.streamDisabled, _onStreamDisabled);
}
bool _isAudioOfThisParticipant(RTCStream stream) =>
stream.participantId == widget.participant.id && stream.kind == MediaType.AUDIO;
void _onStreamEnabled(RTCStream stream) {
if (_isAudioOfThisParticipant(stream)) {
//Mic Turned On
setState(() => audioStream = stream);
}
}
void _onStreamDisabled(RTCStream stream) {
if (_isAudioOfThisParticipant(stream)) {
//Mic Turned Off
setState(() => audioStream = 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();
}
Future<void> unmuteMic() async {
try {
await widget.room.unmuteMic();
} on VideoSDKError catch (error) {
print("unmuteMic failed: ${error.code} ${error.name}");
}
}
Future<void> muteMic() async {
try {
await widget.room.muteMic();
} on VideoSDKError catch (error) {
print("muteMic failed: ${error.code} ${error.name}");
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Mic of ${widget.participant.displayName} is ${audioStream != null ? "on" : "off"}"),
// The buttons act on your own mic, so show them on your own tile.
if (widget.participant.isLocal) ...[
ElevatedButton(
onPressed: unmuteMic,
child: const Text("Unmute Mic"),
),
ElevatedButton(
onPressed: muteMic,
child: const Text("Mute Mic"),
),
],
],
);
}
}
Audio Permissions
- If permissions are not granted, use the
requestPermissions()method of theVideoSDKclass to prompt users to grant access to their devices. - On Android, the SDK does not ask for microphone permission. Call
requestPermissions()beforeunmuteMic(). Without the permission, the mic stays off:unmuteMic()throws error3018, and the same error reachesEvents.error. - To enable requesting of microphone permission on iOS devices, add the following to your
Info.plist, located at<project root>/ios/Runner/Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) Microphone Usage!</string>
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 audio permission.
Map<String, bool> reqAudioPermissions =
await VideoSDK.requestPermissions(Permissions.AUDIO);
if (reqAudioPermissions['audio'] != true) {
// The user did not allow the microphone.
}
} 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

