游乐游手机版
首页/前端开发/文章详情

Android手把手教WebRTC儿童远程监控App切换摄像头与桌面共享

时间:2026-06-13 06:55
概述 上一节,我们成功实现了嘟宝与嘟妈之间的WebRTC音视频通信,整体流程顺畅且逻辑清晰。嘟妈通过扫描二维码完成嘟宝的绑定,点击呼叫后,两端实时建立连接。嘟宝端摄像头与麦克风采集的多媒体视频流直接推送至嘟妈,画面与声音同步传输,体验流畅稳定。 嘟妈扫描二维码绑定嘟宝 嘟妈点击呼叫,与嘟宝建立Web

概述

上一节,我们成功实现了嘟宝与嘟妈之间的WebRTC音视频通信,整体流程顺畅且逻辑清晰。嘟妈通过扫描二维码完成嘟宝的绑定,点击呼叫后,两端实时建立连接。嘟宝端摄像头与麦克风采集的多媒体视频流直接推送至嘟妈,画面与声音同步传输,体验流畅稳定。

  • 嘟妈扫描二维码绑定嘟宝
  • 嘟妈点击呼叫,与嘟宝建立WebRTC实时通信
  • 嘟宝将摄像头、麦克风多媒体视频流发送至嘟妈

切换前后摄像头

接下来介绍一个非常实用的功能:远程切换摄像头。嘟妈端通过信令下发切换指令,嘟宝端摄像头可前置与后置之间无缝切换,视频流全程保持连接,画面跳转流畅,用户体验顺滑自然。

实现原理核心在于两点:获取相机采集工具,以及获取视频流。

   private VideoCapturer createCameraCapturer(boolean isFront) {
        Camera2Enumerator enumerator = new Camera2Enumerator(context.getApplicationContext());
        final String[] deviceNames = enumerator.getDeviceNames();
        for (String deviceName : deviceNames) {
            if (isFront ? enumerator.isFrontFacing(deviceName) : enumerator.isBackFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                mCamCapture = (CameraVideoCapturer) videoCapturer;
                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }
        return null;
    }

该函数逻辑十分明确:枚举设备上的所有摄像头,根据传入的 isFront 参数,返回前置或后置摄像头的采集实例。代码清晰直接,无冗余。

    private VideoTrack getVideoTrack(){
        surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", eglBase.getEglBaseContext());
        VideoCapturer videoCapturer = createCameraCapturer(true);
        VideoSource videoSource = factory.createVideoSource(videoCapturer.isScreencast());
        videoCapturer.initialize(surfaceTextureHelper, context.getApplicationContext(), videoSource.getCapturerObserver());
        videoCapturer.startCapture(480, 640, 30);
        VideoTrack videoTrack=   factory.createVideoTrack("100", videoSource);
        videoTrack.enabled();
        return videoTrack;
    }

接着,getVideoTrack 方法调用上述函数,默认选用前置摄像头,启动采集后将视频流封装为 VideoTrack 并返回。注意在 createCameraCapturer 中有一行 mCamCapture = (CameraVideoCapturer) videoCapturer;,通过强制转换得到了 CameraVideoCapturer 引用,后续摄像头切换正依赖于此。

   public void changeCam(){
        if (mCamCapture != null) {
            mCamCapture.switchCamera(null);
        }    }

只需一行 switchCamera 调用,即可完成摄像头切换,稳定可靠。

屏幕共享

另一个实用场景是屏幕共享。嘟妈可通过信令远程查看嘟宝的屏幕,例如帮助孩子调试设备或演示操作流程,极为便捷。不过获取桌面屏幕需要用户授权——嘟宝启动时必须弹窗请求同意,否则无法采集屏幕数据。

实现步骤涉及三个环节:在后台服务中声明允许屏幕采集、在 MainActivity 中发起申请、用户同意后获取 Intent 变量以捕获桌面视频流。首先看清单文件中的配置:


其中 mediaProjection 类型的 foregroundServiceType 是必需的,它赋予服务在后台执行屏幕录制的能力。

 public void startprojectionManager(){
        @SuppressLint({"NewApi", "LocalSuppress"}) MediaProjectionManager projectionManager = (MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
        @SuppressLint({"NewApi", "LocalSuppress"}) Intent intent = projectionManager.createScreenCaptureIntent();
        ActivityResultLauncher screenCaptureLauncher;
        screenCaptureLauncher=registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
            if (result.getResultCode() == RESULT_OK) {
                Intent data = result.getData();
                MyWebRtc.i=data;
            }
            else {
            }
        });
        screenCaptureLauncher.launch(intent);
    }

这段代码通过 MediaProjectionManager 创建屏幕捕获意图,并启动 ActivityResultLauncher 等待用户授权。若用户点击允许,result.getData() 返回的 Intent 将用于后续构建屏幕采集器,此处直接赋值给 MyWebRtc.i

public void getScreenVideo() {
        surfaceTextureHelperscreen = SurfaceTextureHelper.create("CaptureThread1", eglBase.getEglBaseContext());        VideoCapturer screenCapturer=new ScreenCapturerAndroid(i, new MediaProjection.Callback() {
            @Override
            public void onStop() {
                super.onStop();
            }
        }); // eglBaseContext 是你之前初始化的 EGL 上下文
        VideoSource screenVideoSource = factory.createVideoSource(screenCapturer.isScreencast());
        VideoTrack screenVideoTrack = factory.createVideoTrack("102", screenVideoSource);        // 2. 初始化并启动 ScreenCapturer
        // 注意:需要提前准备好 SurfaceTextureHelper
        screenCapturer.initialize(surfaceTextureHelperscreen, context.getApplicationContext(), screenVideoSource.getCapturerObserver());
        screenCapturer.startCapture(/* width */ 640, /* height */ 480, /* fps */ 25);        // 3. 执行替换的关键操作
//        localVideoSender.track().setEnabled(false);
        localVideoSender.setTrack(screenVideoTrack, /* takeOwnership= */ true);
    }

获得授权 Intent 后,使用 ScreenCapturerAndroid 实例化屏幕采集器,初始化并启动采集,最终得到屏幕的 VideoTrack。最后调用 localVideoSender.setTrack 将原摄像头视频流替换为屏幕视频流,即完成从摄像头画面到屏幕画面的平滑切换。

运行视频查看效果

来源:https://juejin.cn/post/7644742969188433926
上一篇Electric同步前后端数据的高效实现方案 下一篇统一范式中后台管理项目标准化API分层开发方案(Vue/React通用)
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
如何在JavaScript中实现基于旋转视野的FOV射线绘制详解
前端开发 · 2026-07-01

如何在JavaScript中实现基于旋转视野的FOV射线绘制详解

如果用一句话概括核心,那就是:在 RayCasting 游戏开发中,绘制动态视野边界线(FOV)最可靠的方式是在逻辑层通过数学公式将坐标“算”出来,而不是依赖 Canvas 绘图上下文的旋转操作。 在实现类似 Doom 风格的 RayCasting 游戏时,动态视野(Field of View, F

TypeScript后端数据正确映射为前端接口类型的方法
前端开发 · 2026-07-01

TypeScript后端数据正确映射为前端接口类型的方法

在后端数据与前端类型之间来回转换,几乎是每位 TypeScript 开发者都无法回避的常态。后端返回的 car_brand、reg_number,和前端接口中定义的 brand、govtNumber,命名风格常常对不上号。此时,如果为了省事直接用 as 类型断言“强行”指认类型,那就踩进了常见的陷阱

动态HTML表格按层级条件合并单元格的JavaScript实现
前端开发 · 2026-07-01

动态HTML表格按层级条件合并单元格的JavaScript实现

本文详细讲解一种递归式 JavaScript 合并单元格方法,用于按列优先级(如前3列)智能合并表格行:仅当前一列已合并的前提下,才允许后续列合并相同值,从而精准实现多级分组与层级表格合并效果。 在动态生成的 HTML 表格中,按业务逻辑合并重复行是常见需求。然而,简单地对单列分别遍历合并——例如先

Next.js 13+重定向后滚动失效解决方案
前端开发 · 2026-07-01

Next.js 13+重定向后滚动失效解决方案

在 Next js App Router 的日常开发中,有一个令人颇为困扰的异常现象——当服务端执行 `redirect()` 跳转后,目标页面竟然无法正常滚动。没错,页面已经渲染完成,内容也完整显示,但垂直滚动条仿佛凭空消失。这个问题在 Next js 13 5 4 版本中尤为突出。 先给出结论:

WebGL图像加载延迟的纹理初始化时立即显示方法
前端开发 · 2026-07-01

WebGL图像加载延迟的纹理初始化时立即显示方法

本文详细介绍如何利用 Promise 与 async await 重构 WebGL 纹理加载流程,彻底解决首次渲染显示蓝色占位色、需要手动交互才能刷新的问题,实现文件导入后四张纹理平面即时正确渲染。 实际上,这个坑在 WebGL 开发中相当常见——纹理异步加载的小陷阱,说起来不大,但第一次遇到确实令