1、pubspec.yaml 添加以下flutter_webrtc库
![](https://i-blog.csdnimg.cn/direct/b4297828fbaa4edf88c4f15f403ee26b.png)
flutter pub get 安装库
2、使用示例
class GetUserMediaSample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _GetUserMediaSampleState();
}
}
class _GetUserMediaSampleState extends State<GetUserMediaSample> {
// 定义本地和远程视频渲染器
final RTCVideoRenderer _localRenderer = RTCVideoRenderer();
final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
bool _isFrontCamera = false;
// 本地媒体流(摄像头+麦克风)
MediaStream? _localStream;
// PeerConnection(简化示例中未实际连接)
RTCPeerConnection? _peerConnection;
@override
void initState() {
super.initState();
// 初始化渲染器并获取本地媒体流
_initializeRenderers();
}
@override
void dispose() {
// 释放资源
_localRenderer.dispose();
_remoteRenderer.dispose();
_localStream?.dispose();
_peerConnection?.close();
super.dispose();
}
// 初始化视频渲染器
Future<void> _initializeRenderers() async {
await _localRenderer.initialize();
await _remoteRenderer.initialize();
await _getUserMedia(false);
}
// 获取摄像头和麦克风权限并绑定到渲染器
Future<void> _getUserMedia(bool useFrontCamera) async {
try {
final devices = await navigator.mediaDevices.enumerateDevices();
final videoDevices =
devices.where((d) => d.kind == 'videoinput').toList();
String? targetDeviceId;
for (var device in videoDevices) {
if (useFrontCamera && device.label.contains("front") ||
!useFrontCamera && device.label.contains("back")) {
targetDeviceId = device.deviceId;
break;
}
}
targetDeviceId ??= videoDevices.first.deviceId;
// 定义媒体约束(视频+音频)
final constraints = {
'audio': true,
'video': {
'deviceId': targetDeviceId,
'width': 1920,
'height': 1080,
'mandatory': {
'minWidth': '640',
'minHeight': '480',
'minFrameRate': '30',
},
}
};
// 获取媒体流
_localStream = await navigator.mediaDevices.getUserMedia(constraints);
// 将本地流绑定到渲染器
setState(() {
_localRenderer.srcObject = _localStream;
});
} catch (e) {
print("获取媒体设备失败: $e");
}
}
void _switchCamera() async {
setState(() {
_isFrontCamera = !_isFrontCamera;
});
await _getUserMedia(_isFrontCamera);
}
// 构建 UI
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('WebRTC 示例'),
),
body: Column(
children: [
// 本地视频预览
Expanded(
child: Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(color: Colors.blue),
),
child: RTCVideoView(_localRenderer),
),
),
// 远程视频预览(简化示例中未实际连接)
// Expanded(
// child: Container(
// margin: EdgeInsets.all(8),
// decoration: BoxDecoration(
// border: Border.all(color: Colors.red),
// ),
// child: RTCVideoView(_remoteRenderer),
// ),
// ),
// 控制按钮
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.videocam_off),
onPressed: _toggleVideo,
),
IconButton(
icon: Icon(Icons.mic_off),
onPressed: _toggleAudio,
),
IconButton(onPressed: _switchCamera, icon: Icon(Icons.cached))
],
),
],
),
);
}
// 切换摄像头开关
void _toggleVideo() {
if (_localStream != null) {
final videoTrack = _localStream!.getVideoTracks().first;
setState(() {
videoTrack.enabled = !videoTrack.enabled;
});
}
}
// 切换麦克风开关
void _toggleAudio() {
if (_localStream != null) {
final audioTrack = _localStream!.getAudioTracks().first;
setState(() {
audioTrack.enabled = !audioTrack.enabled;
});
}
}
}