# Tutorial: 桌面共享

## 功能描述

本文主要介绍如何在 RTC Web SDK 实现屏幕共享功能。

## 实现流程

1. 【发布端】开启屏幕共享

       var screen = room.selfUser.getScreen();
       screen.setResolution(1920, 1080); //不设置默认值是1920*1080
       screen.setFrameRate(15);
       screen.setBandwidth(8000);
       screen.publish().then(function(){
           console.log('screen.publish success');
       }).otherwise(function(e){
           console.log('screen.publish error,e:',e);
       });

2. 【订阅端】播放屏幕共享

       user.addCallback(UserCallback.publish_screen_notify, onPublishScreenNotify);
       user.addCallback(UserCallback.subscrible_screen_result, onSubscribleScreenResult);

       /**
        * 收到远端桌面共享发布的通知回调处理
        */
       function onPublishScreenNotify(screens) {
           screens.forEach(function(screen) {
               screen.subscrible().then(function(){
                    console.log("订阅桌面共享成功");
               }).otherwise(function(error){
                   console.log("订阅桌面共享失败，error:",error);
               });
           });
       }

       /**
        *
        */
       function onSubscribleScreenResult(stream, userId, userName, screenId, width, height,framerate) {
            //在页面中放置一个 id 为 `srceen_main` 的 div 标签，用于在 div 标签内播放主路流。业务侧可自定义 div 标签的 id，此处只是举例说明。
           room.selfUser.attachScreenElementMediaStream("srceen_main", stream);
       }

3. 屏幕共享 + 系统音频

   采集系统音频支持 Chrome M74+

   - 在 Windows 和 Chrome OS 上，可以采集整个系统的音频。
   - 在 Linux 和 Mac 上，只能采集某个页面的音频。
   - 其它 Chrome 版本、其它系统、其它浏览器均不支持。

       var screen = room.selfUser.getScreen();
       screen.setScreenAudioEnabled(true);  //可以设置是否支持系统音频，不设置默认是支持的。

       screen.publish().then(function(){
           console.log('screen.publish success');
       }).otherwise(function(e){
           console.log('screen.publish error,e:',e);
       });

   在弹出的对话框中勾选`分享音频`，系统音频会与本地麦克风一起发布，房间内其他用户会收到 UserCallback.subscrible_microphone_result 事件和UserCallback.subscrible_screen_audio_result事件。

4. 停止屏幕分享

    // 停止屏幕分享采集及发布
    screen.unpublish().then(function(){
        console.log('screen.unpublish success');
    }).otherwise(function(e){
        console.log('screen.unpublish error,e:',e);
    });

    // 房间内的其他用户会收到 UserCallback.unpublish_screen_notify 事件， 进行取消订阅操作。
    user.addCallback(UserCallback.unpublish_screen_notify, onUnpublishScreenNotify);
    user.addCallback(UserCallback.unsubscrible_screen_result, onUnsubscribleScreenResult);

    function onUnpublishScreenNotify(screen) {
        screen.unsubscrible().then(function(){
            console.log("+++成功取消订阅桌面共享");
        }).otherwise(alertError);
    }

    function onUnsubscribleScreenResult(userId, userName, screenId) {
        room.selfUser.attachScreenElementMediaStream(screenVideo, null);
    }

另外用户还可能会通过浏览器自带的按钮停止屏幕分享，因此屏幕分享流需要监听屏幕分享停止事件，并进行相应的处理。

    // 监听屏幕分享停止事件
    room.addCallback(RoomCallback.screen_sharing_ended, onScreenSharingEnded);

    function onScreenSharingEnded() {
        console.log("桌面共享关闭已结束");
    }

## 注意事项

1. SDK 默认使用 `1080p` 参数配置来采集屏幕分享，具体参考接口：screen.setResolution(width, height)，screen.setFrameRate(frameRate)

## 常见问题

1. Safari 屏幕分享出现报错 `getDisplayMedia must be called from a user gesture handler`

   这是因为 Safari 限制了 `getDisplayMedia` 屏幕采集的接口，必须在用户点击事件的回调函数执行的 1 秒内才可以调用。

   参考：webkit issue。

       // good
       async function onClick() {

       });

       // bad
       async function onClick() {

       }

2. Mac Chrome 在已授权屏幕录制的情况下屏幕分享失败，出现 "NotAllowedError: Permission denied by system" 或者 "NotReadableError: Could not start video source" 错误信息，Chrome bug。解决方案：打开【设置】> 点击【安全性与隐私】> 点击【隐私】> 点击【屏幕录制】> 关闭 Chrome 屏幕录制授权 > 重新打开 Chrome 屏幕录制授权 > 关闭 Chrome 浏览器 > 重新打开 Chrome 浏览器。

3. WebRTC 屏幕分享已知问题及规避方案