Android手把手教WebRTC儿童远程监控App切换摄像头与桌面共享
概述 上一节,我们成功实现了嘟宝与嘟妈之间的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 将原摄像头视频流替换为屏幕视频流,即完成从摄像头画面到屏幕画面的平滑切换。
运行视频查看效果
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
如何用拖放在Flask看板应用中更新数据库状态
在Flask看板应用中,通过HTML5拖放API结合前端fetch异步POST请求,将拖拽任务的task_id和target_state发送至后端路由;后端接收JSON后更新数据库并提交事务,实现跨列拖拽时实时更新状态。需注意将事件绑定到容器而非子元素,并在ondragover中阻止默认行为以确保drop触发。
如何用CSS :has()选择器快速实现悬停span显示相邻div
利用CSS的:has()伪类选择器,通过` bar:has(> baz:hover)+ qux`实现悬停内联元素时显示相邻块级容器,解决了传统相邻兄弟选择器无法跨层级匹配的局限,可用于悬停图标显示详情框等交互场景。需注意浏览器兼容性和性能优化,避免过度使用影响渲染效率。
display:block居中段落文本的响应式实现方法
通过`display:block`与`max-width`限制宽度,配合`margin:auto`使段落块水平居中并实现响应式布局;同时用CSS统一控制段落间距,避免脱离文档流,提升可读性与维护性。
JavaScript代码去重:高效避免重复编写的技巧
将重复代码中的变化点提取为参数,利用ES6模板字符串动态生成选择器,可消除重复、保持一致性。注意参数安全性,必要时进行白名单校验;批量化场景可扩展为数组形式;现代框架中更推荐数据驱动或组件化封装替代手动选择器。
使用容器查询单位cqw实现表单输入框相对于祖父容器百分比宽度
利用CSS容器查询单位cqw,表单输入框宽度可直接基于祖父容器计算,绕过中间包装器尺寸干扰,实现简洁响应式布局,无需硬编码或JavaScript,显著降低维护成本,提升嵌套结构下的布局灵活性。
- 热门数据榜
相关攻略
2026-07-09 07:01
2026-07-09 07:01
2026-07-09 07:01
2026-07-09 07:00
2026-07-09 07:00
2026-07-09 07:00
2026-07-09 07:00
2026-07-09 07:00
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

