天天看點

Android實作兩台手機螢幕共享和遠端控制

1 螢幕共享功能介紹

螢幕共享是指在視訊通話或互動直播過程中将螢幕内容以視訊的方式分享給其他的觀衆,以增強互動體驗,提高溝通效率。螢幕共享解決方案提升了使用者實時視訊通話的溝通效率。

螢幕共享在如下場景中應用廣泛:

  • 視訊會議場景中,螢幕共享可以将講話者本地的檔案、資料、網頁、PPT 等畫面分享給其他與會人;
  • 線上課堂場景中,螢幕共享可以将老師的課件、筆記、講課内容等畫面展示給學生觀看。

2 螢幕共享示例源碼下載下傳

請參考 下載下傳示例源碼 擷取源碼。

相關源碼請檢視 “/ZegoExpressExample/Others/src/main/java/com/example/others/screensharing” 目錄下的檔案。

others
...
├── screensharing
│   ├── CaptureScreenService.java //此檔案實作了系統 Service 接口
│   ├── ScreenSharingActivity.java // 此檔案主要完成了通過 ZegoExpress SDK 将螢幕畫面資料流推送到遠端的工作
│   ├── VideoCaptureScreen.java //此檔案用于通過安卓系統接口建立 VirtualDisplay 執行個體,擷取螢幕資料,并發送給 ZEGO Express SDK
│   └── ZegoVideoCaptureCallback.java //此檔案實作了 ZegoExpress 的 IZegoCustomVideoCaptureHandler
...
           

3 螢幕共享功能實作準備工作-內建螢幕共享SDK

在實作螢幕共享功能之前,請確定:

  • 已在項目中內建 ZEGO Express SDK,實作基本的實時音視訊功能,詳情請參考 快速開始 - 內建 和 快速開始 - 實作視訊通話。
  • 已在 ZEGO 控制台 建立項目,并申請有效的 AppID 和 AppSign,詳情請參考 控制台 - 項目管理 中的“項目資訊”。

4 螢幕共享實作流程-即構螢幕共享SDK

我們需要結合 Android 系統 API 和 ZEGO Express SDK 的自定義視訊采集來進行螢幕分享。

下圖展示了 Android 平台實作螢幕共享的資料流轉:

4.1 擷取使用者錄制螢幕授權

在錄制螢幕前需要擷取使用者的授權,不同版本下需要擷取的權限如下:

  • Android 4.4 及之前版本必須擷取到 root 權限後才能實作螢幕錄制,由于目前大部分裝置的系統版本都高于 4.4,該場景此處不做贅述。
  • Android 5.0 及以上版本,可以使用系統提供的 MediaProjection 和 MediaProjectionManager 進行螢幕錄制。該版本下可以不擷取 root 權限,但會彈窗提示使用者是否允許應用錄制螢幕,需要使用者授權。
  • Android 10.0 及以上版本,螢幕錄制使用系統 API 時需要用到前台服務,詳情請參考 官方文檔。
public static MediaProjectionManager mMediaProjectionManager;
if (Build.VERSION.SDK_INT < 21) {
    Toast.makeText(ZGVideoCaptureOriginUI.this, getString(R.string.record_request), Toast.LENGTH_SHORT).show();
    finish();
} else {
    // 5.0及以上版本
    // 請求錄屏權限,等待使用者授權
   mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
   startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
    }
           

4.2 螢幕共享SDK-建立 MediaProjection 執行個體

  1. 在 AndroidManifest.xml 中添加相關配置。

為實作 Android 10.0 及以上版本應用的螢幕錄制,需要在代碼中開啟前台服務,并在 AndroidManifest.xml 中注冊 Service,添加 foregroundServiceType 屬性。

<application>
 <activity android:name="im.zego.videocapture.ui.ZGVideoCaptureDemoUI" />
 <activity android:name="im.zego.videocapture.ui.ZGVideoCaptureOriginUI"></activity>
 <service android:name=".service.CaptureScreenService"
     android:enabled="true"
     android:foregroundServiceType="mediaProjection"/>
</application>
           
  1. 使用者授權後建立 MediaProjection 執行個體。
  • 對于 Android 10.0 以下版,直接在授權成功後擷取 MediaProjection
  • 對于 Android 10.0 及以上版本,MediaProjection 執行個體的建立需要在前台服務的 onStartCommand 方法中執行。
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       super.onActivityResult(requestCode, resultCode, data);
       if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
           if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.Q){
               //Target版本高于等于10.0需要使用前台服務,并在前台服務的onStartCommand方法中建立MediaProjection
               service=new Intent(ZGVideoCaptureOriginUI.this, CaptureScreenService.class);
               service.putExtra("code",resultCode);
               service.putExtra("data",data);
               startForegroundService(service);
           }else {
               //Target版本低于10.0直接擷取MediaProjection
               mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
           }
       }
   }   
           

建立一個類,實作

Service

接口,在

onStartCommand

中建立

MediaProjection

執行個體。

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class CaptureScreenService extends Service {
    ...

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ···
        //在這裡擷取MediaProjection
        ZGVideoCaptureOriginUI.mMediaProjection = ZGVideoCaptureOriginUI.mMediaProjectionManager.getMediaProjection(mResultCode, Objects.requireNonNull(mResultData));
        return super.onStartCommand(intent, flags, startId);
    }
   ··· 
}
           

4.3 螢幕共享SDK-開啟 ZegoExpress SDK 的自定義視訊采集功能

調用 ZegoExpress SDK 的 enableCustomVideoCapture 開啟自定義采集功能,詳情請參考 自定義視訊采集。

//VideoCaptureScreen繼承IZegoCustomVideoCaptureHandler,用于監聽自定義采集onStart和onStop回調
VideoCaptureScreen videoCapture = new VideoCaptureScreen(ZGVideoCaptureOriginUI.mMediaProjection, DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT, mSDKEngine);
//監聽自定義采集開始停止回調
mSDKEngine.setCustomVideoCaptureHandler(videoCapture);  
ZegoCustomVideoCaptureConfig videoCaptureConfig=new ZegoCustomVideoCaptureConfig();
//使用SurfaceTexture類型進行自定義采集
videoCaptureConfig.bufferType=ZegoVideoBufferType.SURFACE_TEXTURE;
//開始自定義采集
mSDKEngine.enableCustomVideoCapture(true, videoCaptureConfig, ZegoPublishChannel.MAIN); 
           

4.4 螢幕共享SDK-登入房間并開始推流

調用 loginRoom 接口,傳入房間 ID 參數 “roomID” 和使用者參數 “user”,登入房間。

調用 startPublishingStream 接口,傳入流 ID 參數 “streamID”,向遠端使用者發送本端的音視訊流。

/** 建立使用者 */
ZegoUser user = new ZegoUser("user1");

/** 開始登入房間 */
mSDKEngine.loginRoom("room1", user);  
/** 開始推流 */
mSDKEngine.startPublishingStream("stream1");  

           

4.5 建立 VirtualDisplay 并給 ZEGO Express SDK 發送螢幕資料-

1、建立 ZegoVideoCaptureCallback 類繼承 IZegoCustomVideoCaptureHandler。

2、建立 VideoCaptureScreen 類繼承 ZegoVideoCaptureCallback。

當收到 onStart 回調後,開發者可以通過 MediaProjection 建立 VirtualDisplay 執行個體,用于擷取螢幕資料,并發送給 ZEGO Express SDK。

3、通過 createVirtualDisplay 系統 API 将虛拟顯示器的内容渲染到 Surface。

//ZegoVideoCaptureCallback繼承于IZegoCustomVideoCaptureHandler
class VideoCaptureScreen extends ZegoVideoCaptureCallback {
    @Override
    //當收到onStart回調後,就可以通過MediaProjection建立VirtualDisplay,并給ZEGO SDK塞螢幕資料
    public void onStart(ZegoPublishChannel channel) {
        if (mZegoEngine != null && !mIsCapturing && mMediaProjection != null) {
            mIsCapturing = true;
            //通過ZEGO API getCustomVideoCaptureSurfaceTexture擷取SurfaceTexture,該接口預設使用主路通道進行推流
            SurfaceTexture texture = mZegoEngine.getCustomVideoCaptureSurfaceTexture();
            texture.setDefaultBufferSize(mCaptureWidth, mCaptureHeight);
            //通過擷取的SurfaceTexture建立Surface
            mSurface = new Surface(texture);
            //通過mSurface,完成将錄屏資料塞給ZEGO SDK
            mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
                    mCaptureWidth, mCaptureHeight, 1,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mSurface, null, mHandler);
        }
    }
}       
           

至此,我們已完成采集螢幕資料并通過 ZegoExpress SDK 分享到遠端的操作。

5 觀看遠端螢幕共享-遠端控制

完成以上步驟之後,其他使用者可以使用

startPlayingStream

接口拉取螢幕共享流,詳細步驟可以參考 快速開始。

// 同樣的,拉流播放的使用者首先需要初始化 SDK 并登陸同一個房間 
...
...

// 拉流播放,需傳入發起螢幕共享的使用者推流時所用的 streamID
mSDKEngine.startPlayingStream(streamID, new ZegoCanvas(playView));
           

6 擷取螢幕共享SDK更多幫助

擷取本文的Demo、開發文檔、技術支援,通路即構文檔中心

近期有開發規劃的開發者可上即構官網檢視,恰逢即構七周年全線音視訊産品1折的優惠,聯系商務擷取RTC産品優惠;

音視訊場景解決方案分享,更多詳情可搜尋官網(https://zegoguanwang.datasink.sensorsdata.cn/t/pB)

繼續閱讀