HTML躬行记(2)——WebRTC基础实践

简介: HTML躬行记(2)——WebRTC基础实践

 WebRTC (Web Real-Time Communications) 是一项实时通讯技术,在 2011 年由 Google 提出,经过 10 年的发展,W3C 于 2021 年正式发布 WebRTC 1.0 标准。

  

  WebRTC 标准概括介绍了两种不同的技术:媒体捕获设备和点对点连接(P2P,Peer-to-Peer),可让用户无需安装任何插件或第三方软件的情况下,实现共享桌面、文件传输、视频直播等功能。

  下图是官方给出的一张 WebRTC 整体架构设计图:

  

  • 紫色部分是前端开发所使用的 API。
  • 蓝色实线部分是各大浏览器厂商所使用的 API。
  • 蓝色虚线部分包含可自定义的 3 块:音频引擎、视频引擎和网络传输。

  由于各个浏览器对 WebRTC 的实现有所不同,因此 Google 官方提供了一个适配器脚本库:adapter.js,省去很多兼容工作。

  本文的源码已上传至 Github,有需要的可以随意下载。


一、自拍

  自拍是指通过摄像头拍照生成图片,先看下 HTML 结构,其实就 4 个元素。

<video id="video"></video>
<button id="btn">拍照</button>
<canvas id="canvas" width="300" height="300"></canvas>
<img id="img" alt="照片"/>

1)getUserMedia()

  然后在脚本中声明各个元素,通过 navigator.mediaDevices.getUserMedia() 方法获取媒体流。

const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const btn = document.getElementById('btn');
const img = document.getElementById('img');
const size = 300;
/**
 * 获取媒体流
*/
navigator.mediaDevices.getUserMedia({ 
  video: {
    width: size, 
    height: size,
  }, 
  audio: false 
}).then((stream) => {
  video.srcObject = stream;
  video.play();
}); 

  getUserMedia() 的参数是一个包含了video 和 audio 两个成员的 MediaStreamConstraints 对象,上面代码将摄像头的分辨率限制为 300 x 300。

  then() 中的 stream 参数是一个 MediaStream 媒体流,一个流相当于容器,可以包含几条轨道,例如视频和音频轨道,每条轨道都是独立的。

  video 元素中的 src 和 srcObject 是一对互斥的属性,后者可关联媒体源,根据规范也可以是 Blob 或者 File 等类型的数据。

  接着为按钮绑定点击事件,并且在点击时从流中捕获帧,画到 Canvas 内,再导出赋给 img 元素。

/**
 * 点击拍照
*/
btn.addEventListener('click', (e) => {
  const context = canvas.getContext('2d');
  // 从流中捕获帧
  context.drawImage(video, 0, 0, size, size);
  // 将帧导出为图片
  const data = canvas.toDataURL('image/png');
  img.setAttribute('src', data);
}, false);

  在下图中,左边是 video 元素,打开摄像头后就会有画面,在点击拍照按钮后,右边显示捕获的帧。

  

2)enumerateDevices()

  MediaDevices 提供了访问媒体输入和输出的设备,例如摄像头、麦克风等,得到硬件资源的媒体数据。

  mediaDevices.enumerateDevices() 会得到一个描述设备的 MediaDeviceInfo 的数组。

  其中 groupId 用于标识多个设备属于同一个物理设备,例如一个显示器内置了摄像头和麦克风。

navigator.mediaDevices.enumerateDevices()
.then((devices) => {
  devices.forEach((device) => {
    console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
  });
})

3)devicechange

  当媒体设备(例如麦克风、摄像头等)连接到系统或从系统中移除时,devicechange 事件就会被发送给设备实例。

navigator.mediaDevices.ondevicechange = (event) => { };

  event 参数没有附加任何特殊的属性。


二、共享桌面


  Windows 系统采用的共享桌面协议是 RDP(Remote Desktop Protocal),另一种可在不同操作系统共享桌面的协议是 VNC(Virtual Network Console)。

  像 TeamViewer 采用的就是后一种协议,而 WebRTC 的远程桌面没有采用传统的 RDP、VNC 等协议,因为不需要远程控制。

  WebRTC 提供了 getDisplayMedia() 方法采集桌面,在使用上与之前的 getUserMedia() 方法类似。

navigator.mediaDevices.getDisplayMedia({ 
  video: {
    width: 2000,
    height: 1000
  }
}).then((stream) => {
  video.srcObject = stream;
  video.play();
});

  在刷新页面后,会要求选择共享的桌面,包括整个屏幕、窗口或 Chrome 标签页。

  


三、录像


  WebRTC 的录像包括录制音频和视频两种流,通过 Blob 对象将数据保存成多媒体文件。

1)MediaRecorder

  WebRTC 提供了 MediaRecorder 类,它能接收两个参数,第一个是远程的 MediaStream 媒体流,第二个是配置项。

  其配置项包括编解码器、音视频码率、容器的 MIME 类型(例如 video/webm、video/mp4 )等相关信息。

  先看个示例,HTML结构如下所示,一个 video 元素和两个 button 元素:回放和下载。

<video id="video"></video>
<button id="playback">回放</button>
<button id="download">下载</button>

  然后看下录像的整体逻辑,和之前自拍一节类似,也需要调用 getUserMedia() 获取媒体流。

  在 then() 的回调中实例化 MediaRecorder 类,并配置多媒体格式。

  其中WebM是一个由Google资助,免版权费用的视频文件格式;VP8是一个开放的影像压缩格式。

const video = document.getElementById('video');
const playback = document.getElementById('playback');
const download = document.getElementById('download');
const size = 300;
const chunks = [];    // 一个由 Blob 对象组成的数组
navigator.mediaDevices.getUserMedia({ 
  video: {
    width: size, 
    height: size,
  }, 
  audio: true 
}).then((stream) => {
  // 配置多媒体格式
  const options = { mimeType: 'video/webm;codecs=vp8' };
  // 实例化录制对象
  const recorder = new MediaRecorder(stream, options);
  // 当收到数据时触发该事件
  recorder.ondataavailable = function(e) {
    chunks.push(e.data);    // data 是一个可用的 Blob 对象
  }
  // 开始录制
  recorder.start(10);
});

  recorder 的 dataavailable 事件会在收到数据时触发,e 参数的 data 属性是一个可用的 Blob 对象。

  最后在开始录制调用 start() 方法时,可以配置一个毫秒级的时间片,那么在录制时会按照配置的值分割成一个个单独的区块,而不是录制一个非常大的整块内容。

  分块可以提高效率和可靠性,如果是一整块,那么会变得越来越大,读写效率也会变差。

2)回放

  首先根据 chunks 生成 Blob 对象,再根据 Blob 对象生成 URL 对象。

playback.addEventListener('click', () => {
  // 根据 chunks 生成 Blob 对象
  const blob = new Blob(chunks, {type: 'video/webm'});
  // 根据 Blob 对象生成 URL 对象
  video.src = window.URL.createObjectURL(blob);
  video.play();
}, false);

  URL.createObjectURL 是一个静态方法,返回值是一个指定的 File 对象或 Blob 对象。

3)下载

  首先与回放一样,也是生成一个 URL 对象,然后创建 a 元素,将对象赋给 href 属性。

  并且要指定 download 属性,告诉浏览器下载 URL 而不是导航。

download.addEventListener('click', (e) => {
  const blob = new Blob(chunks, {type: 'video/webm'});
  const url = window.URL.createObjectURL(blob);
  // 创建 a 元素
  const a = document.createElement('a');
  a.href = url;
  // 指示浏览器下载 URL 而不是导航
  a.download = 'test.webm';
  a.click();
}, false);

 

参考资料:

WebRTC官方

WebRTC MDN

Build the backend services needed for a WebRTC app

相关文章
|
4月前
|
存储 移动开发 JavaScript
html5手机Web单页应用实践--起点移动阅读
html5手机Web单页应用实践--起点移动阅读
|
7月前
|
设计模式 前端开发 Java
Java与HTML的深度融合:技术解析与应用实践
Java与HTML的深度融合:技术解析与应用实践
443 1
|
7月前
|
存储 移动开发 前端开发
使用HTML5和CSS3构建现代网页:技术详解与实践
【5月更文挑战第28天】本文详细介绍了使用HTML5和CSS3构建现代网页的技术与实践。HTML5新增语义化标签、多媒体支持、本地存储和表单验证等功能,提升了网页开发效率和用户体验。CSS3则带来了更多选择器、盒模型改进、背景与边框样式以及动画过渡效果,使网页设计更具视觉冲击力。通过实例展示了如何结合两者创建结构清晰、交互丰富、响应式的现代网页。
|
7月前
|
移动开发 缓存 前端开发
【专栏:HTML与CSS实践篇】网页性能优化:CSS与HTML的最佳实践
【4月更文挑战第30天】本文探讨了优化CSS和HTML以提升网页性能的最佳实践。HTML优化包括:精简结构、压缩代码、异步加载脚本和利用缓存。CSS优化则涉及:精简代码、合并文件、使用CSS Sprite、善用CSS3属性、避免@import及响应式设计。这些方法能加快加载速度,改善用户体验。
93 6
|
7月前
|
移动开发 前端开发 JavaScript
:掌握移动端开发:HTML5 与 CSS3 的高效实践
:掌握移动端开发:HTML5 与 CSS3 的高效实践 “【5月更文挑战第6天】”
100 1
|
7月前
|
移动开发 前端开发 UED
【专栏:HTML与CSS前端技术趋势篇】渐进式增强与优雅降级在前端开发中的实践
【4月更文挑战第30天】前端开发中的渐进式增强和优雅降级是确保跨浏览器、跨设备良好用户体验的关键策略。渐进式增强是从基础功能开始,逐步增加高级特性,保证所有用户能访问基本内容;而优雅降级则是从完整版本出发,向下兼容,确保低版本浏览器仍能使用基本功能。实践中,遵循HTML5/CSS3规范,使用流式布局和响应式设计,检测浏览器特性,并提供备选方案,都是实现这两种策略的有效方法。选择合适策略优化网站,提升用户体验。
120 4
|
7月前
|
前端开发 JavaScript 开发者
【专栏:HTML与CSS实践篇】CSS框架(Bootstrap/Foundation)快速上手
【4月更文挑战第30天】Bootstrap和Foundation是两种流行的CSS框架,用于构建响应式网页。它们包含预定义的样式、栅格系统和组件,加速开发流程。Bootstrap以其12列栅格系统闻名,而Foundation提供更定制化和模块化选项。了解并熟练运用这些框架的基本概念和组件,结合最佳实践和性能优化,能帮助开发者高效创建符合现代设计趋势的网页项目。
136 3
|
7月前
|
编解码 前端开发 UED
【专栏:HTML 与 CSS 实践篇】网页图标与字体图标的使用
【4月更文挑战第30天】本文探讨了网页设计中两种主要图标形式——传统图标和字体图标。传统图标(PNG, JPEG, GIF)视觉效果丰富但文件大,易影响加载速度且维护不便。字体图标占用空间小,易于维护和定制,但视觉效果相对简单,选择有限。实际应用中,两者可结合使用,以导航栏、操作按钮和提示信息为例说明了图标的重要性。设计师需注意兼容性、清晰度和性能优化问题,根据项目需求选择合适图标类型,以提升网页质量和用户体验。
91 3
|
7月前
|
编解码 前端开发 UED
【专栏:HTML与CSS实践篇】HTML与CSS在电商网站中的应用
【4月更文挑战第30天】本文探讨了HTML和CSS在电商网站中的关键作用。HTML作为基础结构,定义网页内容和布局,用于页面布局、内容展示和表单处理;而CSS则负责样式设计和美化,包括响应式设计、交互效果和模块化,两者结合创建出功能齐全、视觉吸引力强的在线购物环境,提升用户体验。
118 2
|
7月前
|
编解码 前端开发 UED
【专栏:HTML与CSS实践篇】响应式网站开发实战
【4月更文挑战第30天】本文探讨了响应式网站开发,它能根据用户设备自动调整布局,提供最佳浏览体验。通过HTML和CSS,利用媒体查询、Flexbox和百分比宽度等技术实现响应式设计。媒体查询按屏幕尺寸定义CSS规则,Flexbox处理元素排列。文章通过新闻网站首页设计实例,展示了如何应用这些理论,包括使用Flexbox设计导航栏,使用媒体查询调整轮播图和内容区域,以及创建自适应页脚。遵循移动优先原则,关注性能优化和用户体验,响应式设计是前端开发的关键,为多设备用户提供优质浏览体验。
113 2