You need to enable JavaScript to run this app.
导航

Flutter 屏幕共享

最近更新时间2023.12.13 16:13:05

首次发布时间2023.12.06 17:08:30

在实时通信中,如果你希望用户可以分享本地设备播放的屏幕内容和音频,你可以使用 RTC 内置的屏幕采集功能采集屏幕,并通过屏幕共享功能,将采集到的内容与远端用户进行共享。

注意:

  1. 在使用屏幕共享功能时,仅可见用户可以发布屏幕流。详情参看用户可见性设置

  2. 仅支持SDK内部采集,自定义采集需按照 Native SDK 集成及使用方式。

适用场景
行业场景
在线教育老师共享屏幕给学生上课;美术老师共享屏幕给学生教画画。
游戏直播主播共享屏幕给观众,展现自己的游戏画面。
互动直播主播共享自己的屏幕和观众互动。
视频会议会议成员共享屏幕观看 PPT 或者文档。
前提条件
  • 已经集成 RTC SDK for Flutter,实现了基本的音视频通话

  • 支持的操作系统:

    • Android 5.0 (API 级别 21) 及以上版本。Android 5.0 ~ 10 区间版本仅支持屏幕视频采集,不支持屏幕音频采集,故推荐使用 Android 10 (API 级别 29) 及以上版本。

    • iOS 12 及以上版本。若使用 iOS 12 ~ iOS 12.2 区间的系统版本,则需集成 v 3.52 或更高版本的 RTC SDK。

iOS 端接入流程

iOS 端基于苹果提供的 Replaykit 框架实现屏幕录制,可以分享整个系统的屏幕内容。但由于苹果的隐私设置,不同 App 之间数据无法互通,因此需要当前 App(主 App 进程)额外提供一个 Extension 扩展组件(Extension 进程),并且把 App 和 Extension 配置为同一 App Group,让 Extension 录屏进程可以同主 App 进程进行跨进程通信,实现屏幕内容分享。

步骤一:创建并配置 Extension 扩展组件

参看 iOS 端屏幕共享功能实现步骤一至步骤三完成 App Group、Extension 创建并实现屏幕采集逻辑。

注意:
将 RTC iOS SDK 的屏幕共享插件引入到工程中时,请保证 VolcEngineRTC 的版本号与 Flutter SDK 内依赖的版本号一致,Flutter SDK 内依赖版本可从SDK 根目录/ios/volc_engine_rtc.podspec文件中查看。

步骤二:为 RTC Video 设置 App Group ID

创建 RTC 引擎后调用 setExtensionConfig 接口传入 Extension 的 App Group ID 和 Bundle ID,用以响应从系统控制中心发起的屏幕共享请求。

#if __has_include(<volc_engine_rtc/ByteRTCVideoManager.h>)
#import <volc_engine_rtc/ByteRTCVideoManager.h>
#else
@import volc_engine_rtc;
#endif

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [GeneratedPluginRegistrant registerWithRegistry:self];
    // Before using the built-in capture module of the SDK to capture the screen, set the Extension configuration by inputting the App Group ID shared by your app and the Extension, and the Bundle Identifier of the Extension.
    [ByteRTCVideoManager setExtensionConfig:APPGroupId bundleId:ExtensionBundleId];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end
Android 端接入流程

Android 端屏幕共享是基于Android 5(API 级别 21)中引入的媒体投影 API 和 RTC SDK API 共同实现。

注意:
SDK 内部已自动添加屏幕共享所需权限 android.permission.FOREGROUND_SERVICE,无需额外声明。

步骤一:创建录屏权限请求 Activity

在 Android 工程中创建ScreenCaptureRequestActivity.java文件,遵循 SDK 内BaseScreenCaptureRequestActivity接口类实现:

import android.app.Activity;

import com.ss.bytertc.engine.flutter.screencapture.BaseScreenCaptureRequestActivity;

public class ScreenCaptureRequestActivity extends BaseScreenCaptureRequestActivity {
    /**
     * Android 10 及以上录屏通知使用
     * 指定录屏通知上显示的大图标
     */
    @Override
    public int getLargeIcon() {
        return R.mipmap.ic_launcher;
    }

    /**
     * Android 10 及以上录屏通知使用
     * 指定录屏通知上显示的小图标
     */
    @Override
    public int getSmallIcon() {
        return R.mipmap.ic_launcher;
    }

    /**
     * Android 10 及以上录屏通知使用
     * 指定录屏通知从某一个 Activity 上弹出
     */
    @Override
    public Class<? extends Activity> getLaunchActivity() {
        return MainActivity.class;
    }

    /**
     * Android 10 及以上录屏通知使用
     * 指定录屏通知上的提示文案
     */
    @Override
    public String getContextText() {
        return "正在录制/投射您的屏幕";
    }
}

步骤二:绑定录屏权限请求 Activity

在 Android 工程根目录的 AndroidManifest.xml 文件中添加如下代码:

<application
    ...
    <activity
        android:name=".ScreenCaptureRequestActivity"
        android:exported="false"
        android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
        <intent-filter>
            <action android:name="${applicationId}.action.REQUEST_SCREEN_CAPTURE" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
</application>
调用 Flutter 接口共享屏幕

API 调用时序图

alt

【可选】设置编码参数

如果默认的编码参数不能满足你的要求,你可以在开始屏幕采集前调用 setScreenVideoEncoderConfig 方法,通过 ScreenVideoEncoderConfig 设置编码参数。参看如下示例:

ScreenVideoEncoderConfig screenStream = ScreenVideoEncoderConfig(
    width: 1280,
    height: 720,
    frameRate: 15,
    maxBitrate: 600,
    minBitrate: 100,
    encoderPreference: ScreenVideoEncoderPreference.maintainFrameRate);
    
rtcVideo.setScreenVideoEncoderConfig(screenStream);
  • 若不设置分辨率,即宽高均为默认值 0 时,SDK 不会对系统采集到的屏幕视频帧进行缩放处理,

    • 若屏幕物理分辨率长边像素数小于 1920px,录制视频分辨率为屏幕物理分辨率;

    • 若屏幕物理分辨率长边像素数大于 1920px,录制视频会被系统缩放至长边像素数为 1920 左右。

  • 若设置了分辨率,SDK 则会对系统采集到的屏幕视频帧进行等比例缩放处理,

    • 若源分辨率大于目标分辨率,录制视频将被等比例缩小;

    • 若源分辨率小于目标分辨率,录制分辨率则保持不变。

开启屏幕采集

内部采集

调用 startScreenCapture 方法开启屏幕采集,你可以指定需要采集的媒体类型,包括只音频、只视频、音视频均采集。开启采集后,你可以通过updateScreenCapture 方法调整采集的媒体类型。

// 开始采集屏幕音视频流。
rtcVideo.startScreenCapture(ScreenMediaType.videoAndAudio);
// 更新采集的媒体类型为只采集视频,以达到静音效果。
rtcVideo.updateScreenCapture(ScreenMediaType.videoOnly);

iOS 端也可以从系统控制中心发起:

  1. 打开 iOS 系统的控制中心,长按录屏按钮;

  2. 在弹窗中选择你的应用,点击开始直播,开始录屏。

alt

自定义采集

强烈建议你使用 RTC 内部采集。如果你仍然希望使用自定义采集,结合 Flutter SDK 高级功能使用说明 使用 Native 中的自定义采集相关接口。

停止屏幕采集

rtcVideo.stopScreenCapture();

发布/停止发布屏幕流

// 在 RTCVideoEventHandler 中,发布与停止发布屏幕流。
engineHandler.onVideoDeviceStateChanged = (String deviceId,
    VideoDeviceType deviceType,
    MediaDeviceState deviceState,
    MediaDeviceError deviceError) {
    if (deviceType == VideoDeviceType.screenCaptureDevice) {
        if (deviceState == MediaDeviceState.started) {
            // 发布屏幕流
            rtcRoom.publishScreen(MediaStreamType.both);
        } else if (deviceState == MediaDeviceState.stopped ||
            deviceState == MediaDeviceState.runtimeError) {
            // 停止发布屏幕流
            rtcRoom.unpublishScreen(MediaStreamType.both);
        }
    }
};

渲染远端屏幕流

// 在 RTCRoomEventHandler 中收到远端用户发布屏幕流的回调中刷新 UI
roomEventHandler.onUserPublishScreen = (String uid, MediaStreamType type) {
    // 获取到 uid 后通过刷新 UI 创建 RTCViewContext.remoteContext
    // 并利用 RTCSurfaceView 渲染远端视频
}

停止渲染远端屏幕流

// 在 RTCRoomEventHandler 中收到远端用户停止发布屏幕流的回调中刷新 UI
roomEventHandler.onUserUnpublishScreen =
    (String uid, MediaStreamType type, StreamRemoveReason reason) {
    // 取消设置远端视频画布
    rtcVideo.removeRemoteVideo(
        roomId: roomId,
        uid: uid,
        streamType: StreamIndex.screen);
    // 刷新 UI 移除视频渲染视图
};