问题描述
我正在尝试构建一个具有屏幕共享功能的视频通话应用.用户可以在通话期间共享他们的屏幕.我正在使用 WebRTC
SDK 来满足我的目的,但他们有一个在通话开始时共享屏幕的解决方案,但没有在通话进行时共享屏幕.可以勾选屏幕共享选项,可以开始通话,但在通话过程中无法开始屏幕共享.
我在 CallActivity 屏幕上添加了一个按钮,点击时调用 Android 的 MediaProjection 类来投射屏幕,但投射的屏幕没有远程显示.
public void onScreenShare(boolean isScreenShared) {screencaptureEnabled = isScreenShared;if (screencaptureEnabled && videoWidth == 0 && videoHeight == 0) {DisplayMetrics displayMetrics = getDisplayMetrics();videoWidth = displayMetrics.widthPixels;videoHeight = displayMetrics.heightPixels;}如果(isPemitted()){startScreenCapture();} 别的 {Log.i(TAG, "onScreenShare: not allowed");}/*if (peerConnectionClient != null) {peerConnectionClient.stopVideoSource();}*/}私有无效 startScreenCapture() {MediaProjectionManager mediaProjectionManager =(MediaProjectionManager) getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(),CAPTURE_PERMISSION_REQUEST_CODE);Log.d("tagged", ">>>>方法调用:-");}@覆盖public void onActivityResult(int requestCode, int resultCode, Intent data){Log.d("tagged", ">>>>方法调用:-" + requestCode);如果(请求代码!= CAPTURE_PERMISSION_REQUEST_CODE)返回;别的 {mediaProjectionPermissionResultCode = 结果代码;mediaProjectionPermissionResultData = 数据;如果(peerConnectionParameters.videoCallEnabled){videoCapturer = createVideoCapturer();}peerConnectionClient.createPeerConnection(localProxyVideoSink、remoteSinks、videoCapturer、信号参数);}}私人@NullableVideoCapturer createScreenCapturer() {Log.d("CheckMedia", ">>>检查" +mediaProjectionPermissionResultData);如果(mediaProjectionPermissionResultCode != Activity.RESULT_OK){reportError("用户没有授予截屏权限.");返回空;}返回新的 ScreenCapturerAndroid(mediaProjectionPermissionResultData, 新MediaProjection.Callback() {@覆盖公共无效 onStop() {reportError("用户撤销了截屏权限.");}});}
此代码在本地设备上开始投射,但不在远程设备上流式传输任何内容.
更新
private void switchCameraInternal() {if (videoCapturer instanceof CameraVideoCapturer) {if (!isVideoCallEnabled() || isError) {日志.e(标签,"切换相机失败.视频:" +isVideoCallEnabled() + ".错误:" + isError);返回;//不发送视频或只有一台摄像机可用或发生错误.}Log.d(TAG, "切换相机");CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer)视频捕捉器;cameraVideoCapturer.switchCamera(null);} 别的 {Log.d(TAG, "不会切换相机,视频捕获器不是相机");}}公共无效开关相机(){executor.execute(this::switchCameraInternal);}私有无效 startScreenSharing() {if (videoCapturer instanceof ScreenCapturerAndroid) {if (!isVideoCallEnabled() || isError) {日志.e(标签,"无法共享屏幕.视频:" + isVideoCallEnabled()+ ".错误:" + isError);返回;//不发送视频或只有一台摄像机可用或发生错误.}ScreenCapturerAndroid screenCapturerAndroid =(ScreenCapturerAndroid) videoCapturer;screenCapturerAndroid.startCapture(500, 500, 30);}}公共无效屏幕共享(){executor.execute(this::startScreenSharing);}
我进行了更改,并使代码看起来类似于 switchCamera()代码,但我收到了 Not On Camera Thread 异常.
我不确定您是否可以同时从 Camera 和 Screen 流式传输.但是你可以做的是:
- 用户点击屏幕共享按钮
- 您使用
PeerConnection.removeTrack(RtpSender sender)
从 - 您使用
ScreenCapturerAndroid
创建您的 Screen 视频轨道(就像您已经做的那样) - 您将轨道添加到您的
PeerConnection
PeerConnection
中删除您的 Camera 视频轨道如果您说屏幕共享在没有调用的情况下工作,那么步骤 4 和 5 应该已经完成.
当你移除它的轨道时,不要忘记处理/释放与 Camera
相关的所有资源.
还要停止屏幕共享并返回相机,只需对屏幕轨道执行上述步骤.
更新:
这是 WebRTC 客户端的一部分,它允许我实现您的要求(您可以将其调整为您当前的代码库):
私人乐趣 stopCameraShare(){videoCapturerAndroid?.stopCapture()localRenderer.dispose()localVideoView.release()localVideoView.clearImage()流? .removeTrack(localVideoTrack)localVideoTrack.dispose()}私人乐趣 shareScreen(){停止相机共享()val mediaProjectionManager = activity!!.getSystemService(Context.MEDIA_PROJECTION_SERVICE) 作为 MediaProjectionManagerstartActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 29)}覆盖 fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {如果(请求代码!= 29)返回initVideos()videoCapturerAndroid = ScreenCapturerAndroid(数据,对象:MediaProjection.Callback() {覆盖乐趣 onStop() {Timber.e("用户撤销了截屏权限.")}})peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext)videoSource = peerConnectionFactory.createVideoSource(videoCapturerAndroid)localVideoTrack = peerConnectionFactory.createVideoTrack("100", videoSource)videoCapturerAndroid?.startCapture(300, 300, 30)流?.addTrack(localVideoTrack)}
PS:peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext)很重要
希望对你有帮助!
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'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 !
这篇关于如何在视频/音频通话中远程共享屏幕?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!