0

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.

Vismay Patil
  • 64
  • 4
  • 14
  • You mentioned that the sharing is working fine if you don't start video first so there is no need to change anything apart from removing the video track before adding the new one. Check my update – 113408 Feb 14 '19 at 14:26
  • [Reference](https://github.com/duttaime/WebRTCAndroid) Still not able to make it. Can you help me out here, actually trying this from past 5 days now. – Vismay Patil Feb 15 '19 at 11:37
  • You can check my code example and fit it to your needs – 113408 Feb 16 '19 at 08:49
  • @113408 I am stuck in the same situation as mentioned above. It will be really helpful if i could get the link your code to fit my need. – Sunil kumar Jun 21 '20 at 06:12

1 Answers1

0

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 !

113408
  • 3,364
  • 6
  • 27
  • 54
  • We cannot stream from camera and screen, agreed. But I want to stop camera when screen sharing starts. Will follow your steps, have you done anything similar? – Vismay Patil Feb 14 '19 at 12:57
  • Yes we have a similar setup. If you implemented the camera switch(between front and back) then it’s mostly same – 113408 Feb 14 '19 at 12:59
  • We are using PeerConnection.addTrack() and not MediaStream, any suggestion regarding this. – Vismay Patil Feb 14 '19 at 13:43
  • I'm using a probably different version of WebRTC as in my case, I create a `MediaStream` and give it the `AudioTrack` and `VideoTrack` then pass the said stream to `PeerConnection.addStream(MediaStream)`. What revision of WebRTC are you using ? – 113408 Feb 14 '19 at 14:02
  • @113408..I have implemented the same and it works fine. But it stops after few minutes. I am getting : buffer queue has abundant. As error –  Jun 12 '19 at 18:52
  • @user2980181 I would suggest you create a separate question with stack trace of the error you get to have the help from the community – 113408 Jun 12 '19 at 19:02
  • @user2980181 did you ever figure out that error? I am getting the same – Tyler Whitman Oct 03 '19 at 22:41
  • @VismayPatil Did your screen-share works fine now along with the video call? Seems like the reference link mentioned above doesn't have the screen share implementation. Would be great if you could suggest something as your asked question is similar to my use case. – Sunil kumar Jun 21 '20 at 06:24
  • @Sunilkumar I moved on from this and using video conferencing sdk for example Twilio where just calling a method will allow me to share my screen without thinking about the internal logic. – Vismay Patil Jun 22 '20 at 07:54
  • @VismayPatil Thanks for your response.Any specific reason related performance or anything else regarding production use of WebRTC. Actually we are targeting to use this app in large audience Video Confernce. Whats your opinion on WebRTC performance? – Sunil kumar Jun 22 '20 at 10:27
  • Using WebRTC directly needs lot of things to be handled. It depends on your need whether you just want audio/video calling in your app or you want to create a platform like a wrapper around webRTC which can be used by others. If yours is the first case then I suggest you should choose some third party library who does all the webRTC handling on their side and provide you with necessary callbacks. – Vismay Patil Jun 22 '20 at 14:40
  • 1
    I need help in this since i can't find setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext) method in peerconnectionfactory. – Vipin NU Jul 08 '20 at 18:41
  • The method setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext) has been removed (see my question here: https://stackoverflow.com/questions/63137545/webrtc-how-to-enable-hardware-acceleration-for-the-video-encoder). Do you know an alternative? – Valelik Jul 31 '20 at 13:46