How to share screen remotely in a video/audio call?

喜夏-厌秋 提交于 2021-01-29 14:19:40

问题


I am trying to build a video call app which has a feature of screen sharing. The users can share their screen during the call. I'm using WebRTC SDK to meet my purpose, but they have a solution for screen share when the call starts but not for screen share while the call is ongoing. One can tick the screen sharing option and can start the call but cannot start screen sharing during the call.

I added a button on the CallActivity screen which on click calls MediaProjection Class of Android to cast the screen but the casted screen is not being shown remotly.

public void onScreenShare(boolean isScreenShared) {
    screencaptureEnabled = isScreenShared;
    if (screencaptureEnabled && videoWidth == 0 && videoHeight == 0) {
        DisplayMetrics displayMetrics = getDisplayMetrics();
        videoWidth = displayMetrics.widthPixels;
        videoHeight = displayMetrics.heightPixels;
    }

    if (isPemitted()) {
        startScreenCapture();
    } else {
        Log.i(TAG, "onScreenShare: not permitted");
    }

    /*if (peerConnectionClient != null) {
        peerConnectionClient.stopVideoSource();
    }*/
}

private void startScreenCapture() {
    MediaProjectionManager mediaProjectionManager =
            (MediaProjectionManager) getApplication().getSystemService(
                    Context.MEDIA_PROJECTION_SERVICE);
    startActivityForResult(
            mediaProjectionManager.createScreenCaptureIntent(), 
CAPTURE_PERMISSION_REQUEST_CODE);
    Log.d("tagged", ">>>>Method called :- ");
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
{
    Log.d("tagged", ">>>>Method called :- " + requestCode);
    if (requestCode != CAPTURE_PERMISSION_REQUEST_CODE)
        return;
    else {
        mediaProjectionPermissionResultCode = resultCode;
        mediaProjectionPermissionResultData = data;

if (peerConnectionParameters.videoCallEnabled) {
        videoCapturer = createVideoCapturer();
    }
    peerConnectionClient.createPeerConnection(
            localProxyVideoSink, remoteSinks, videoCapturer, 
 signalingParameters);
    }
}

private @Nullable
VideoCapturer createScreenCapturer() {
    Log.d("CheckMedia", ">>>Checking " + 
mediaProjectionPermissionResultData);
    if (mediaProjectionPermissionResultCode != Activity.RESULT_OK) {
        reportError("User didn't give permission to capture the screen.");
        return null;
    }
    return new ScreenCapturerAndroid(
            mediaProjectionPermissionResultData, new 
MediaProjection.Callback() {
        @Override
        public void onStop() {
            reportError("User revoked permission to capture the screen.");
        }
    });
}

This code starts the casting on local device but is not streaming anything on remote device.

UPDATE

 private void switchCameraInternal() {
    if (videoCapturer instanceof CameraVideoCapturer) {
        if (!isVideoCallEnabled() || isError) {
            Log.e(TAG,
                    "Failed to switch camera. Video: " + 
 isVideoCallEnabled() + ". Error : " + isError);
            return; // No video is sent or only one camera is available or 
 error happened.
        }
        Log.d(TAG, "Switch camera");
        CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) 
 videoCapturer;
        cameraVideoCapturer.switchCamera(null);

    } else {
        Log.d(TAG, "Will not switch camera, video caputurer is not a 
camera");
    }
 }

public void switchCamera() {
    executor.execute(this::switchCameraInternal);
}

private void startScreenSharing() {
    if (videoCapturer instanceof ScreenCapturerAndroid) {
        if (!isVideoCallEnabled() || isError) {
            Log.e(TAG,
                    "Failed to share screen. Video: " + isVideoCallEnabled() 
+ ". Error : " + isError);
            return; // No video is sent or only one camera is available or 
error happened.
        }
        ScreenCapturerAndroid screenCapturerAndroid = 
(ScreenCapturerAndroid) videoCapturer;
        screenCapturerAndroid.startCapture(500, 500, 30);
    }
}

public void screenSharing() {
    executor.execute(this::startScreenSharing);
}

I did the changes, and made the code look similar to switchCamera() code but I am getting an Not On Camera Thread Exception.


回答1:


I'm not sure you can stream from the Camera and Screen at the same time. However what you can do is:

  1. User click the screen share button
  2. You remove your Camera video track from your PeerConnection using PeerConnection.removeTrack(RtpSender sender)
  3. You create your Screen video track using ScreenCapturerAndroid (as you already do)
  4. You add the track to your PeerConnection

If you say that the Screen share is working without call then step 4 and 5 should already be done.

Don't forget to dispose/release all resources related to the Camera when you remove its track.

Also to stop the Screen share and go back to the Camera just do the above steps for the Screen track.

For reference : PeerConnection.java

UPDATE :

Here is a part of the WebRTC Client that allows me to achieve what you are asking for (you can adapt it to your current code base):

private fun stopCameraShare(){
        videoCapturerAndroid?.stopCapture()
        localRenderer.dispose()
        localVideoView.release()
        localVideoView.clearImage()
        stream?.removeTrack(localVideoTrack)
        localVideoTrack.dispose()
    }
private fun shareScreen(){
        stopCameraShare()
        val mediaProjectionManager = activity!!.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 29)
    }

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode != 29)
            return
        initVideos()
        videoCapturerAndroid = ScreenCapturerAndroid(
            data, object : MediaProjection.Callback() {
                override fun onStop() {
                    Timber.e("User revoked permission to capture the screen.")
                }
            })
        peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext)
        videoSource = peerConnectionFactory.createVideoSource(videoCapturerAndroid)
        localVideoTrack = peerConnectionFactory.createVideoTrack("100", videoSource)
        videoCapturerAndroid?.startCapture(300, 300, 30)
        stream?.addTrack(localVideoTrack)
    }

PS: It's very important to peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext)

Hope this will help you !



来源:https://stackoverflow.com/questions/54690592/how-to-share-screen-remotely-in-a-video-audio-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!