Manage Audio and Video Devices - Flutter
This feature allows hosts to switch their microphone, speaker, or camera devices during a live stream. Hosts (in SEND_AND_RECV mode) can change the microphone and camera they broadcast with, ensuring they maintain control over their audio and video quality, while audience members (in RECV_ONLY mode) continue to receive the broadcast. Audience members can still switch the speaker they listen on.
Changing Audio Input Device
During the livestream at any point a host wishes to switch his/her input audio device, it can be done using the below mentioned methods.
On Android and iOS, the microphone and the speaker share a single audio route. Changing the microphone with changeMic() also changes where you hear audio, and setAudioDevice() changes both too.
getMics()
-
The
getMics()method of theVideoSDKclass lists the audio devices you can switch to, as a list ofMicrophoneDeviceInfoobjects. Each one is an audio route. -
The
MicrophoneDeviceInfoobject will contain thedeviceIdandlabelfor the device. -
On Android, the devices are
SPEAKER_PHONE,EARPIECE,WIRED_HEADSETandBLUETOOTH, as each one is connected. On iOS, the list starts withSpeaker, which is not a microphone, followed by the microphones you can use, such asiPhone Microphone,Headphonesfor a wired headset, or the name of a Bluetooth headset.
changeMic()
-
After selecting the desired device, you can switch the audio input by passing its
deviceIdtochangeMic(deviceId:). -
Calling
changeMic()without a device switches to the next microphone. -
A muted microphone stays muted. If the microphone is on, it is turned off and on again on the new device, so you get
Events.streamDisabledand thenEvents.streamEnabledfor your audio stream. -
You can call
changeMic()with a device before you join. The room uses that device when you join. -
changeMic()returns aFuturethat throws aVideoSDKErrorif the switch fails, for example3059when the device is not available. The same error also reaches yourEvents.errorhandler.
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class LiveStreamScreen extends StatefulWidget {
const LiveStreamScreen({Key? key}) : super(key: key);
@override
_LiveStreamScreenState createState() => _LiveStreamScreenState();
}
class _LiveStreamScreenState extends State<LiveStreamScreen> {
late Room _room;
List<MicrophoneDeviceInfo> mics = [];
@override
void initState() {
super.initState();
fetchMics();
}
void fetchMics() async {
List<MicrophoneDeviceInfo>? audioDevices = await VideoSDK.getMics();
setState(() {
// On iOS, "Speaker" is not a microphone.
mics = (audioDevices ?? [])
.where((device) => device.label != 'Speaker')
.toList();
});
}
Future<void> changeMic(MicrophoneDeviceInfo device) async {
try {
await _room.changeMic(deviceId: device.deviceId);
} on VideoSDKError catch (error) {
print("changeMic failed: ${error.code} ${error.name}");
}
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
child: Text("Change Input Device"),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Select Audio Device"),
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SingleChildScrollView(
reverse: true,
child: mics.isNotEmpty
? Column(
children: mics
.map(
(device) => ElevatedButton(
child: Text(device.label),
onPressed: () async {
Navigator.pop(context);
await changeMic(device);
},
),
)
.toList(),
)
: const Text("No Microphone Devices found."),
)
],
),
),
);
}),
]);
}
}
Changing Audio Output Device
During the livestream at any point a host wishes to switch his/her output audio like from headphones to speaker, it can be done using the below mentioned methods.
On Android and iOS, the microphone and the speaker share a single audio route, so setAudioDevice() changes both. To choose the microphone, see Changing Audio Input Device.
getMics()
-
The
getMics()method will help you to list down all the audio devices you can switch to, which will return a list ofMicrophoneDeviceInfoobjects. Each one is an audio route. -
The
MicrophoneDeviceInfoobject will contain thedeviceIdandlabelfor the device.
setAudioDevice()
-
After selecting the desired device, you can switch the audio output by passing the corresponding
MicrophoneDeviceInfoobject as a parameter to thesetAudioDevice()method. -
The microphone stays muted or unmuted as it was.
-
setAudioDevice()returns aFuturethat throws aVideoSDKErrorif the switch fails.
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class LiveStreamScreen extends StatefulWidget {
const LiveStreamScreen({Key? key}) : super(key: key);
@override
_LiveStreamScreenState createState() => _LiveStreamScreenState();
}
class _LiveStreamScreenState extends State<LiveStreamScreen> {
late Room _room;
List<MicrophoneDeviceInfo> speakers = [];
@override
void initState() {
super.initState();
fetchSpeakers();
}
void fetchSpeakers() async {
List<MicrophoneDeviceInfo>? audioDevices = await VideoSDK.getMics();
setState(() => speakers = audioDevices ?? []);
}
Future<void> setAudioDevice(MicrophoneDeviceInfo device) async {
try {
await _room.setAudioDevice(device);
} on VideoSDKError catch (error) {
print("setAudioDevice failed: ${error.code} ${error.name}");
}
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
child: const Text("Change Audio Device"),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Select Audio Device"),
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SingleChildScrollView(
reverse: true,
child: speakers.isNotEmpty
? Column(
children: speakers
.map(
(device) => ElevatedButton(
child: Text(device.label),
onPressed: () async {
Navigator.pop(context);
await setAudioDevice(device);
},
),
)
.toList(),
)
: const Text("No Speaker Devices found."),
)
],
),
),
);
}),
]);
}
}
Changing Camera Input Device
During the livestream at any point a host wishes to switch his/her input video device, it can be done using the below mentioned methods.
getCameras()
-
This method of the
VideoSDKclass will give you the list of all the available cameras which can be shown in a list. -
This method will return a list of
CameraDeviceInfowhich will contain thedeviceId,labelandkindof the camera input devices.
changeCam()
-
After selecting the desired device, you can switch the camera input by passing its
deviceIdtochangeCam(deviceId:). -
Call
changeCam()without a device to switch to the next camera, for example from the front camera to the back camera. -
changeCam()returns aFuturethat throws aVideoSDKErrorif the switch fails, for example3051when the camera is not available. The same error also reaches yourEvents.errorhandler.
Future<void> switchToNextCamera() async {
try {
// No device: switch to the next camera
await _room.changeCam();
} on VideoSDKError catch (error) {
print("changeCam failed: ${error.code} ${error.name}");
}
}
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class LiveStreamScreen extends StatefulWidget {
const LiveStreamScreen({Key? key}) : super(key: key);
@override
_LiveStreamScreenState createState() => _LiveStreamScreenState();
}
class _LiveStreamScreenState extends State<LiveStreamScreen> {
late Room _room;
List<CameraDeviceInfo>? cameras = [];
@override
void initState() {
super.initState();
fetchCameras();
}
void fetchCameras() async {
cameras = await VideoSDK.getCameras();
setState(() {});
}
Future<void> changeCam(CameraDeviceInfo device) async {
try {
await _room.changeCam(deviceId: device.deviceId);
} on VideoSDKError catch (error) {
print("changeCam failed: ${error.code} ${error.name}");
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
child: const Text("Change Camera"),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Select Camera Device"),
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SingleChildScrollView(
reverse: true,
child: cameras != null && cameras!.isNotEmpty
? Column(
children: cameras!.map(
(device) => ElevatedButton(
child: Text(device.label),
onPressed: () async {
Navigator.pop(context);
await changeCam(device);
},
),
).toList(),
)
: const Text("No Camera Devices found."),
),
],
),
),
);
},
),
],
);
}
}
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

