WebRTC(七):媒体能力协商

目的

在 WebRTC 中,每个浏览器或终端支持的音视频编解码器、分辨率、码率、帧率等可能不同。媒体能力协商的目的就是:

  • 确保双方能“听得懂”对方发的媒体流;
  • 明确谁发送、谁接收、怎么发送;
  • 保障连接的互操作性兼容性

P2P的基本流程

在这里插入图片描述

参与角色

角色说明
peerA发起连接的端(通常是主叫)
peerB接收连接的端(通常是被叫)
signal信令服务器,用于中转 SDP 和 ICE 信息,但不参与媒体传输
stun/turnSTUN/TURN 服务器,用于穿透 NAT 或作为中继,辅助建立 P2P 或 Relay 通信

流程详解

连接信令服务器

  • peerApeerB 分别通过 WebSocket 或其他方式连接信令服务器,用于后续中转 SDP 和 ICE 数据。

PeerConnection 创建 + 添加媒体流(媒体准备)

peerA

  • 创建 RTCPeerConnection 实例。
  • 通过 getUserMedia() 获取本地音视频流。
  • addTrack()addStream() 将媒体加入连接对象。

创建 Offer SDP(发起协商)

  • peerA 调用 createOffer()
    • 生成包含自身媒体能力(支持的音视频编解码器、方向、SSRC、码率等)的 SDP。
  • peerA 调用 setLocalDescription(offer)
    • 表示将该 SDP 用作自己的本地描述。
    • 浏览器会开始进行 ICE 候选收集(即寻找可用的 IP/端口路径)。

发送 Offer SDP(信令交换)

  • peerA 将 Offer SDP 通过 signal 发送给 peerB
  • 此时可以看到 peerA → signal → peerB 的 “Send SDP Offer”。

接收方处理 Offer

peerB

  • 创建 RTCPeerConnection 实例。
  • setRemoteDescription(offer) 设置远端描述(即 peerA 的 SDP)。
  • 浏览器据此了解 peerA 的媒体能力,并开始准备回答。

创建 Answer SDP(应答协商)

  • peerB 调用 createAnswer(),根据双方交集生成 Answer SDP。
  • 调用 setLocalDescription(answer) 设置为自己的本地描述。

发送 Answer SDP(信令交换)

  • peerB → signal → peerA 发送 Answer SDP。
  • peerA 调用 setRemoteDescription(answer),设置为远端描述,协商正式完成。

到这一步为止,媒体能力协商完成(Codec、方向等确认)

ICE 候选协商(网络通路探测)

  • 双方浏览器后台通过 STUN 向公网发送绑定请求,收集本地的候选地址(ICE candidate)。
  • 每收集到一个 ICE 候选地址,会触发 onicecandidate 事件。

发送和添加 ICE 候选(网络路径建立)

  • 每次 onicecandidate 被触发,候选地址通过信令发送给对方:
    • peerAsignalpeerB
    • peerBsignalpeerA
  • 收到对方候选后,使用 addIceCandidate() 添加。

当 ICE 连接状态变为 connectedcompleted 时,即可开始进行媒体传输。

媒体流建立

  • 媒体协商完成,网络路径打通后:
    • peerB 触发 onAddStreamontrack 事件,表示收到远端音视频流。
    • 同样地,peerA 也会收到对方的流。

重点流程

阶段关键函数作用
媒体协商createOffer / createAnswer生成 SDP
setLocalDescription / setRemoteDescription设置 SDP 本地/远端描述
网络协商onicecandidate / addIceCandidate交换并使用候选地址建立连接
信令传输signal中转 SDP 和 ICE,但不传输媒体
媒体传输addTrack / ontrack接收对方音视频流

重要函数

createOffer()

作用

生成一个 SDP Offer,描述本地支持的音视频媒体能力(如 codec、媒体方向、分辨率、带宽等)。

使用示例

const offer = await pc.createOffer();

应用场景

  • 发起方调用,用于开始媒体协商;
  • 会触发 ICE 候选的收集。

createAnswer()

作用

接收到对方 SDP Offer 后,根据自己的能力生成一个 SDP Answer。

使用示例

const answer = await pc.createAnswer();

应用场景

  • 接收方调用,用于回应媒体协商;
  • 也会触发 ICE 候选收集。

setLocalDescription(desc)

作用

设置本地描述(Offer 或 Answer),并开始 ICE 候选收集。

使用示例

await pc.setLocalDescription(offer); // offer 或 answer 都可以

说明

  • 必须在发送 SDP 之前调用;
  • 必须配合 createOffercreateAnswer 使用。

setRemoteDescription(desc)

作用

设置远端 SDP 描述(对方发送的 offer 或 answer),用于协商建立媒体连接。

使用示例

await pc.setRemoteDescription(remoteOffer);

注意

  • 必须在 createAnswer() 前调用(即先设置远端再生成应答);
  • SDP 是通过信令服务器中转接收的。

onicecandidate

作用

监听本地收集到的每一个 ICE 候选地址(IP + port),用于网络路径穿透。

示例

pc.onicecandidate = (event) => {if (event.candidate) {sendCandidateToPeer(event.candidate); // 通过信令发送}
};

注意

  • 每收集一个候选地址就触发一次;
  • 全部收集完毕会收到一个 nullevent.candidate

addIceCandidate(candidate)

作用

将从对方接收到的 ICE 候选加入本地 ICE 代理中,用于连接建立。

示例

await pc.addIceCandidate(remoteCandidate);

注意

  • 一定要在 setRemoteDescription 之后调用;
  • 多次调用用于添加多个候选。

addTrack

作用

添加音频或视频轨道(MediaStreamTrack)。

示例

const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
const pc = new RTCPeerConnection();stream.getTracks().forEach(track => {pc.addTrack(track, stream); // 同一个 MediaStream 确保同步
});

特性

特性说明
精细轨道控制每次添加单个 MediaStreamTrack(音频或视频)
支持多轨道发送可多次调用添加多个音频/视频轨
支持轨道同步若多个轨道来自同一个 MediaStream,浏览器会自动尝试同步播放
返回 RTCRtpSender可动态设置编码参数、带宽、分辨率等
支持动态添加轨道连接建立后也可添加轨道,会触发重新协商
可用于替代 addStream现代 WebRTC 标准推荐使用,addStream() 已废弃
ontrack 配套使用远端通过 ontrack 事件接收媒体轨道
轨道标签与 ID 传递SDP 会携带轨道的 id 和所属流 stream id(用于标识同步组)
支持 simulcast(多编码)搭配 RTCRtpSender.setParameters() 支持多编码流发送

ontrack

作用

当远端添加了新的媒体轨(音轨/视频轨)时触发,一般用于播放远程视频或音频。

示例

pc.ontrack = (event) => {remoteVideo.srcObject = event.streams[0];
};

特性

  • 可接收多个轨道;
  • addTrack()recvonly 类型媒体方向配合使用的标准回调。

发起端与接收端

发起端

const pc = new RTCPeerConnection();pc.onicecandidate = e => sendCandidate(e.candidate);
pc.ontrack = e => remoteVideo.srcObject = e.streams[0];localStream.getTracks().forEach(track => {pc.addTrack(track, localStream);
});const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
sendOffer(offer);

接收端

const pc = new RTCPeerConnection();pc.onicecandidate = e => sendCandidate(e.candidate);
pc.ontrack = e => remoteVideo.srcObject = e.streams[0];await pc.setRemoteDescription(offer);
localStream.getTracks().forEach(track => {pc.addTrack(track, localStream);
});
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
sendAnswer(answer);

总结

  • 目的:确保双方选用兼容的音视频编解码器、分辨率、码率和传输参数,实现高质量的实时通信。
  • 载体:基于 SDP(Session Description Protocol)协议,描述媒体的相关能力。
  • 流程
    • 一方创建并发送包含自身支持能力的 SDP Offer
    • 对方收到后生成 SDP Answer,确认兼容参数
    • 双方通过设置本地和远端描述完成协商
  • 内容包括
    • 编解码器列表(如 VP8、H.264、Opus)
    • 媒体流方向(发送、接收、双向)
    • 带宽限制和媒体属性
    • 网络传输细节(ICE、DTLS安全层)
  • 结果:协商成功后,双方基于共同支持的参数建立安全稳定的音视频流通道。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84924.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84924.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可信启动方案设计

安全之安全(security)博客目录导读 目录 一、引言 二、关键数据(Critical Data) 三、度量槽(Measurement Slot) 四、可信启动后端 1、事件日志(Event Log) 2、离散型 TPM(Discrete TPM) 3、RSE(运行时安全引擎) 五、平台接口 平台接口的职责: 1、函数:b…

✨通义万相2.1深度解析:AI视频生成引擎FLF2V-14B全流程指南(命令行参数+模型架构+数据流)

🌟 从零详解:如何用AI模型生成视频?命令行、模型结构、数据流全解析! 本文通过一个实际案例,详细解析使用AI模型生成视频的整个流程。从命令行参数解读到模型结构,再到数据在模型间的流动,一步步…

在 TypeScript 前端中使用 Umi-Request 调用 Java 接口的完整指南

下面我将详细介绍如何在基于 TypeScript 的前端项目中使用 umi-request 调用 IntelliJ IDEA 中开发的 Java 接口,包括完整的实现方案和代码示例。 整体方案设计 一、Java 后端接口准备 1. 创建 Spring Boot 控制器 // src/main/java/com/example/demo/controller…

GO Gin Web框架面试题及参考答案

目录 Gin 与 net/http 有哪些主要区别?为什么选择 Gin? 如何使用 Gin 启动一个 HTTP 服务并设置默认路由? Gin 的默认路由和自定义路由器组是如何工作的? 如何在 Gin 中绑定请求参数(Query、Form、JSON、XML)? 如何在 Gin 中使用中间件?中间件执行顺序是怎样的? …

asp.net core Razor动态语言编程代替asp.net .aspx更高级吗?

For Each item In products<tr><td>item.Id</td><td>item.Name</td><td>item.Price.ToString("C")</td></tr>Next为什么要用<tr> ? 在Blazor的Razor语法中&#xff0c;使用<tr>是为了在VB.NET代码块中…

css语法中的选择器与属性详解:嵌套声明、集体声明、全局声明、混合选择器

嵌套声明 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>嵌套声明</title> <!-- 这里p span 的含义是p标签下面的span标签 所以有嵌套关系--><style>p span {font-weight:…

Linux 系统中,/usr/bin/ 和/bin/的区别?

在 Linux 系统中&#xff0c;/bin/ 和 /usr/bin/ 都是存放可执行程序&#xff08;命令&#xff09;的目录&#xff0c;但它们在历史定位、用途、挂载策略和系统设计上有一定区别。 ✅ 快速对比总结 项目/bin//usr/bin/全称含义binary&#xff08;核心二进制&#xff09;user b…

苍穹外卖--WebSocket、来单提醒、客户催单

WebSocket 1.介绍 WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传送。 HTTP协议和WebSocket协议对比&#xff1a; ①Http是短连接 ②W…

Linux 信号(Signal)与信号量(Semaphore)区别

特性信号 (Signal)信号量 (Semaphore)本质软件中断进程间同步机制用途通知进程发生了某个事件控制对共享资源的访问通信方向单向 (内核→进程 或 进程→进程)多进程共享数据类型整数信号编号内核维护的计数器持久性瞬时,不排队持久,直到显式释放实现层次内核实现内核或用户空…

华为OD机考-观看文艺汇演问题-区间问题(JAVA 2025B卷)

import java.util.*; /*** version Ver 1.0* date 2025/6/20* description 观看文艺汇演*/ public class WatchMovie {public static void main(String[] args) {Scanner sc new Scanner(System.in);int num Integer.parseInt(sc.nextLine());List<Movie> movies new …

DeepSeek今天喝什么随机奶茶推荐器

用DeepSeek生成了一个随机奶茶推荐器-今天喝什么&#xff0c;效果非常棒&#xff01;UI界面美观。 提示词prompt如下 用html5帮我生成一个今天喝什么的网页 点击按钮随机生成奶茶品牌等&#xff0c;要包括中国常见的知名的奶茶品牌 如果不满意还可以随机再次生成 ui界面要好看 …

【国产AI服务器】全国产PCIE5.0交换板,替代博通89104/89144,支持海光、龙芯等平台

实物图 核心硬件配置 1、控制器芯片‌ 采用国产TL63104控制芯片‌&#xff0c;支持2.5GT/s、5GT/s、8GT/s、16GT/s、32GT/s的PCIe传输速率&#xff0c;支持968Lanes。支持6个x16的group和1个x8的group&#xff0c;每个group支持1至8个端口。x16group支持x16、x8、x4、x2端口…

GPIO-LED驱动

一、LED引脚说明 寄存器地址地图&#xff1a; 原理图&#xff1a; 关于MOS管的说明&#xff1a; 总结&#xff1a;当GPIO0_B5这个引脚输出高电平的时候&#xff0c;对应的N-MOS管导通—LED点亮 当GPIO0_B5这个引脚输出低电平的时候&#xff0c;对应的N-MOS管截止---LED熄灭 二…

Gartner《Generative AI Use - Case Comparison for Legal Departments》

概述 这篇文章由 Gartner, Inc. 出品,聚焦于生成式人工智能(GenAI)在法律部门中的应用情况,通过对 16 个较为突出的 GenAI 法律技术应用场景进行分析,从商业价值和可行性两个维度进行评估,旨在为法律总顾问等提供战略对话依据,以便更好地做出技术投资决策,推动法律部门…

Vue 中 filter 过滤的语法详解与注意事项

Vue 中 filter 过滤的语法详解与注意事项 在 Vue.js 中,"过滤"通常指两种不同概念:模板过滤器(Vue 2 特性)和数组过滤(数据过滤)。由于 Vue 3 已移除模板过滤器,我将重点介绍更实用且通用的数组过滤语法和注意事项。 一、数组过滤核心语法(推荐方式) 1. …

webpack+vite前端构建工具 -6从loader本质看各种语言处理 7webpack处理html

6 从loader本质看各种语言处理 语法糖&#xff1f; 6.1 loader的本质 loader本质是一个方法&#xff0c;接收要处理的资源的内容&#xff0c;处理完毕后给出内容&#xff0c;作为打包结果。 所有的loader&#xff08;例如babel-loader, url-loader等&#xff09;export出一个方…

算法第41天|188.买卖股票的最佳时机IV、309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费

188.买卖股票的最佳时机IV 题目 思路与解法 基于 买卖股票的最佳时机iii&#xff0c;得出的解法。关键在于&#xff0c;每一天的卖或者买都由前一天推导而来。 class Solution { public:int maxProfit(int k, vector<int>& prices) {if(prices.size() 0) return …

【AI News | 20250623】每日AI进展

AI Repos 1、tools Strands Agents Tools提供了一个强大的模型驱动方法&#xff0c;通过少量代码即可构建AI Agent。它提供了一系列即用型工具&#xff0c;弥合了大型语言模型与实际应用之间的鸿沟&#xff0c;涵盖文件操作、Shell集成、内存管理&#xff08;支持Mem0和Amazon…

Python装饰器decorators和pytest夹具fixture详解和使用

此前一直认为fixture就叫python中的装饰器&#xff0c;学习后才发现decorators才是装饰器&#xff0c;fixture是pytest框架的夹具&#xff0c;只是通过装饰器去定义和使用。所以要了解fixture就得先了解python装饰器。 一、装饰器(decorators) 1.定义 装饰器&#xff08;dec…

目标检测之YOLOv5到YOLOv11——从架构设计和损失函数的变化分析

YOLO&#xff08;You Only Look Once&#xff09;系列作为实时目标检测领域的标杆性框架&#xff0c;自2016年YOLOv1问世以来&#xff0c;已历经十余年迭代。本文将聚焦YOLOv5&#xff08;2020年发布&#xff09;到YOLOv11&#xff08;2024年前后&#xff09;的核心技术演进&am…