问题
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:
- User click the screen share button
- You remove your Camera video track from your
PeerConnection
usingPeerConnection.removeTrack(RtpSender sender)
- You create your Screen video track using
ScreenCapturerAndroid
(as you already do) - 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