【问题标题】:How to share screen remotely in a video/audio call?如何在视频/音频通话中远程共享屏幕?
【发布时间】:2019-02-14 12:37:58
【问题描述】:

我正在尝试构建一个具有屏幕共享功能的视频通话应用程序。用户可以在通话期间共享他们的屏幕。我正在使用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;
    }

    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.");
        }
    });
}

此代码在本地设备上开始投射,但不在远程设备上流式传输任何内容。

更新

 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);
}

我做了更改,使代码看起来类似于 switchCamera() 代码,但我得到一个 Not On Camera Thread 异常。

【问题讨论】:

  • 您提到如果您不先启动视频,则共享工作正常,因此除了在添加新视频轨道之前删除视频轨道外,无需进行任何更改。检查我的更新
  • Reference 仍然无法成功。你能帮帮我吗,实际上是从过去 5 天开始尝试的。
  • 您可以查看我的代码示例并满足您的需求
  • @113408 我陷入了与上述相同的情况。如果我能获得您的代码链接以满足我的需要,那将非常有帮助。

标签: android webrtc screensharing android-mediaprojection


【解决方案1】:

我不确定您是否可以同时从相机和屏幕流式传输。但是你可以做的是:

  1. 用户点击屏幕共享按钮
  2. 您使用PeerConnection.removeTrack(RtpSender sender) 从您的PeerConnection 中删除您的相机 视频轨道
  3. 您使用ScreenCapturerAndroid 创建您的屏幕视频轨道(就像您已经做的那样)
  4. 您将曲目添加到您的PeerConnection

如果您说屏幕共享无需调用即可工作,那么步骤 4 和 5 应该已经完成​​。

当您删除它的轨道时,不要忘记处置/释放与Camera 相关的所有资源。

同样要停止屏幕分享并返回相机,只需对屏幕轨道执行上述步骤。

供参考:PeerConnection.java

更新:

这是 WebRTC 客户端的一部分,可让我实现您的要求(您可以将其调整到您当前的代码库):

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:很重要peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext)

希望对你有帮助!

【讨论】:

  • 我们不能从相机和屏幕流式传输,同意。但是我想在屏幕共享开始时停止相机。会按照你的步骤,你做过类似的事情吗?
  • 是的,我们有类似的设置。如果您实现了相机开关(前后之间),那么它几乎是相同的
  • 我们使用的是 PeerConnection.addTrack() 而不是 MediaStream,对此有任何建议。
  • 我使用的 WebRTC 版本可能与我的情况不同,我创建了一个 MediaStream 并给它 AudioTrack 和 VideoTrack 然后将所述流传递给 PeerConnection.addStream(MediaStream)。您使用的是哪个版本的 WebRTC?
  • 我需要帮助,因为我在 peerconnectionfactory 中找不到 setVideoHwAccelerationOptions(rootEglBase.eglBaseContext, rootEglBase.eglBaseContext) 方法。
猜你喜欢
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-09
  • 2020-09-10
相关资源
最近更新 更多