flutter-webrtc安装示例

1、pubspec.yaml 添加以下flutter_webrtc库

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;
      });
    }
  }
}
相关推荐
装不满的克莱因瓶1 小时前
【2026 持续更新】Flutter 零基础到精通全攻略(一)
flutter·app·dart·移动端
装不满的克莱因瓶2 小时前
React Native vs Flutter:一次深入到底的性能对比分析(含原理 + 实战)
javascript·flutter·react native·react.js·app·移动端
亚历克斯神3 小时前
Flutter 组件 t_stats 的适配 鸿蒙Harmony 实战 - 驾驭高性能统计学运算、实现鸿蒙端海量数据实时态势感知与工业级描述性统计方案
flutter·harmonyos·鸿蒙·openharmony·t_stats
键盘鼓手苏苏3 小时前
Flutter 组件 angel3_orm_mysql 的适配 鸿蒙Harmony 实战 - 驾驭专业 ORM 映射引擎、实现鸿蒙端与 MySQL 数据库的透明映射与高性能 SQL 审计方案
flutter·harmonyos·鸿蒙·openharmony·angel3_orm_mysql
左手厨刀右手茼蒿3 小时前
Flutter 组件 serverpod_swagger 的适配 鸿蒙Harmony 实战 - 驾驭 API 文档自动化、实现鸿蒙端全栈联调与 Swagger UI 动态审计方案
flutter·harmonyos·鸿蒙·openharmony·serverpod_swagger
钛态3 小时前
Flutter 三方库 discord_interactions 的鸿蒙化适配指南 - 在 OpenHarmony 打造高效的社交机器人交互底座
flutter·harmonyos·鸿蒙·openharmony·discord_interactions
加农炮手Jinx3 小时前
Flutter 组件 dascade 的适配 鸿蒙Harmony 实战 - 驾驭级联式异步数据流、实现鸿蒙端响应式 UI 状态泵与复杂业务逻辑解耦方案
flutter·harmonyos·鸿蒙·openharmony
国医中兴3 小时前
Flutter 组件 r_flutter 的适配 鸿蒙Harmony 实战 - 驾驭资源映射自动化、实现鸿蒙端资产强类型引用与资产冲突静态校验方案
flutter·r语言·harmonyos
里欧跑得慢3 小时前
Flutter 组件 postgres_crdt 的适配 鸿蒙Harmony 实战 - 驾驭分布式无冲突复制数据类型、实现鸿蒙端高性能离线对等同步架构方案
flutter·harmonyos·鸿蒙·openharmony·postgres_crdt
王码码20353 小时前
Flutter for OpenHarmony:使用 pluto_grid 打造高性能数据网格
flutter·http·华为·架构·harmonyos