flutter-webrtc安装示例

发布于:2025-02-11 ⋅ 阅读:(11) ⋅ 点赞:(0)

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;
      });
    }
  }
}