Flutter WebRTC会议插件yumeeting_webrtc的使用

Flutter WebRTC会议插件yumeeting_webrtc的使用

功能性

特性 Android iOS Web macOS Windows Linux 嵌入式 Fuchsia
音频/视频 ✔️ ✔️ ✔️ ✔️ ✔️ [WIP] [WIP]
数据通道 ✔️ ✔️ ✔️ ✔️ ✔️ [WIP] [WIP]
屏幕捕获 ✔️ ✔️(*) ✔️ ✔️ ✔️
统一计划 ✔️ ✔️ ✔️ ✔️ ✔️ [WIP] [WIP]
多流传输 ✔️ ✔️ ✔️ ✔️ [WIP]
录制媒体 ⚠️ ⚠️ ✔️
插入流

使用

在你的 pubspec.yaml 文件中添加 yumeeting_webrtc 作为依赖项。

dependencies:
  yumeeting_webrtc: ^版本号

iOS

Info.plist 文件中添加以下条目:

<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) Camera Usage!</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) Microphone Usage!</string>

iOS注意事项

编译后的 WebRTC.xframework 不再支持 iOS arm 设备。因此,你需要在项目的 ios/Podfile 中添加以下配置:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' # 这一行
    end
  end
end

Android

确保在 AndroidManifest.xml 文件中包含以下权限:

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

如果需要使用蓝牙设备,请添加以下权限:

<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

确保将 build.gradle 设置为 Java 8,因为官方的 WebRTC 库现在使用了 EglBase 接口中的静态方法。只需在应用级别的 build.gradle 中添加以下内容:

android {
    // ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

如果有必要,在同一个 build.gradle 文件中增加 defaultConfigminSdkVersion 至 23(目前默认的 Flutter 生成器设置为 16)。

重要提醒

当你编译发布 APK 时,需要添加以下操作:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

示例代码

以下是一个简单的示例代码,展示了如何使用 yumeeting_webrtc 插件创建一个基本的 Flutter 应用程序。

import 'dart:core';

import 'package:flutter/foundation.dart' show debugDefaultTargetPlatformOverride;
import 'package:flutter/material.dart';
import 'package:flutter_background/flutter_background.dart';
import 'package:yumeeting_webrtc/yumeeting_webrtc.dart';

import 'src/data_channel_sample.dart';
import 'src/get_display_media_sample.dart';
import 'src/get_user_media_sample.dart'
    if (dart.library.html) 'src/get_user_media_sample_web.dart';
import 'src/loopback_sample.dart';
import 'src/loopback_sample_unified_tracks.dart';
import 'src/route_item.dart';

void main() {
  if (WebRTC.platformIsDesktop) {
    debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
  } else if (WebRTC.platformIsAndroid) {
    WidgetsFlutterBinding.ensureInitialized();
    startForegroundService();
  }
  runApp(MyApp());
}

Future<bool> startForegroundService() async {
  final androidConfig = FlutterBackgroundAndroidConfig(
    notificationTitle: 'Title of the notification',
    notificationText: 'Text of the notification',
    notificationImportance: AndroidNotificationImportance.Default,
    notificationIcon: AndroidResource(
        name: 'background_icon',
        defType: 'drawable'), // 默认为 mipmap 文件夹中的 ic_launcher
  );
  await FlutterBackground.initialize(androidConfig: androidConfig);
  return FlutterBackground.enableBackgroundExecution();
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late List<RouteItem> items;

  [@override](/user/override)
  void initState() {
    super.initState();
    _initItems();
  }

  ListBody _buildRow(context, item) {
    return ListBody(children: <Widget>[
      ListTile(
        title: Text(item.title),
        onTap: () => item.push(context),
        trailing: Icon(Icons.arrow_right),
      ),
      Divider()
    ]);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
          appBar: AppBar(
            title: Text('Flutter-WebRTC 示例'),
          ),
          body: ListView.builder(
              shrinkWrap: true,
              padding: const EdgeInsets.all(0.0),
              itemCount: items.length,
              itemBuilder: (context, i) {
                return _buildRow(context, items[i]);
              })),
    );
  }

  void _initItems() {
    items = <RouteItem>[
      RouteItem(
          title: '获取用户媒体',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => GetUserMediaSample()));
          }),
      RouteItem(
          title: '获取屏幕媒体',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) =>
                        GetDisplayMediaSample()));
          }),
      RouteItem(
          title: '回环测试',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => LoopBackSample()));
          }),
      RouteItem(
          title: '统一轨道回环测试',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) =>
                        LoopBackSampleUnifiedTracks()));
          }),
      RouteItem(
          title: '数据通道',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => DataChannelSample()));
          }),
    ];
  }
}

更多关于Flutter WebRTC会议插件yumeeting_webrtc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter WebRTC会议插件yumeeting_webrtc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


yumeeting_webrtc 是一个用于 Flutter 的插件,旨在简化 WebRTC 的实现,特别是在视频会议场景中。它封装了 WebRTC 的复杂性,使得开发者能够更轻松地集成实时音视频通信功能。

以下是如何在 Flutter 项目中使用 yumeeting_webrtc 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 yumeeting_webrtc 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  yumeeting_webrtc: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 初始化插件

在你的 Flutter 应用中初始化 yumeeting_webrtc 插件。

import 'package:yumeeting_webrtc/yumeeting_webrtc.dart';

void main() {
  YumeetingWebRTC.initialize();
  runApp(MyApp());
}

3. 创建会议房间

使用 YumeetingWebRTC 创建或加入一个会议房间。

class MeetingScreen extends StatefulWidget {
  @override
  _MeetingScreenState createState() => _MeetingScreenState();
}

class _MeetingScreenState extends State<MeetingScreen> {
  YumeetingWebRTC _yumeetingWebRTC = YumeetingWebRTC();

  @override
  void initState() {
    super.initState();
    _joinMeeting();
  }

  void _joinMeeting() async {
    try {
      await _yumeetingWebRTC.joinRoom(
        roomId: 'your-room-id',
        userId: 'your-user-id',
        token: 'your-token',
      );
    } catch (e) {
      print('Failed to join meeting: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Meeting Room'),
      ),
      body: Center(
        child: Text('Meeting in progress...'),
      ),
    );
  }
}

4. 显示本地和远程视频流

yumeeting_webrtc 插件提供了 RTCVideoView 来显示本地和远程的视频流。

class MeetingScreen extends StatefulWidget {
  @override
  _MeetingScreenState createState() => _MeetingScreenState();
}

class _MeetingScreenState extends State<MeetingScreen> {
  YumeetingWebRTC _yumeetingWebRTC = YumeetingWebRTC();
  RTCVideoRenderer _localRenderer = RTCVideoRenderer();
  RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();

  @override
  void initState() {
    super.initState();
    _initRenderers();
    _joinMeeting();
  }

  void _initRenderers() async {
    await _localRenderer.initialize();
    await _remoteRenderer.initialize();
  }

  void _joinMeeting() async {
    try {
      await _yumeetingWebRTC.joinRoom(
        roomId: 'your-room-id',
        userId: 'your-user-id',
        token: 'your-token',
      );

      _yumeetingWebRTC.onLocalStream = (stream) {
        _localRenderer.srcObject = stream;
      };

      _yumeetingWebRTC.onRemoteStream = (stream) {
        _remoteRenderer.srcObject = stream;
      };
    } catch (e) {
      print('Failed to join meeting: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Meeting Room'),
      ),
      body: Column(
        children: [
          Expanded(
            child: RTCVideoView(_localRenderer),
          ),
          Expanded(
            child: RTCVideoView(_remoteRenderer),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _localRenderer.dispose();
    _remoteRenderer.dispose();
    super.dispose();
  }
}

5. 处理会议事件

你可以监听和处理会议中的各种事件,例如用户加入、离开、音视频状态变化等。

_yumeetingWebRTC.onUserJoined = (userId) {
  print('User joined: $userId');
};

_yumeetingWebRTC.onUserLeft = (userId) {
  print('User left: $userId');
};

_yumeetingWebRTC.onAudioMuted = (userId, muted) {
  print('User $userId audio muted: $muted');
};

_yumeetingWebRTC.onVideoMuted = (userId, muted) {
  print('User $userId video muted: $muted');
};

6. 离开会议

在会议结束时,调用 leaveRoom 方法离开会议。

void _leaveMeeting() async {
  await _yumeetingWebRTC.leaveRoom();
}

7. 处理权限

确保在使用 WebRTC 之前获取了必要的权限(例如摄像头和麦克风权限)。

import 'package:permission_handler/permission_handler.dart';

void _requestPermissions() async {
  await Permission.camera.request();
  await Permission.microphone.request();
}

8. 处理错误

在实际使用中,可能会遇到各种错误,例如网络问题、权限问题等。确保你正确处理这些错误。

try {
  await _yumeetingWebRTC.joinRoom(
    roomId: 'your-room-id',
    userId: 'your-user-id',
    token: 'your-token',
  );
} catch (e) {
  print('Failed to join meeting: $e');
}
回到顶部