当前位置: 首页 > 工具软件 > mediasoup > 使用案例 >

Mediasoup Overview

习宸
2023-12-01

Mediasoup Overview

mediasoup 是一个基于 C++ 实现具有 SFU 的功能库,其 server 端对外提供 Nodejs API。

mediasoup 自身并不提供任何信令协议。所以需要应用程序,来确认 mediasoup 客户端与服务端进行通信的方式,用来协商客户端与服务端的相关参数和信息。在大多数情况下,此通信必须是双向的,因此通常需要全双工信道(如 TCP 或 SCTP 通道)。但是,应用程序可以将同一通道重新用于与非 mediasoup 相关的消息交换(例如身份验证过程,聊天消息,文件传输以及应用程序希望实现的任何功能),这样的多路复用策略,可以提升整个系统的性能。

传统的 VoIP 的语音客户与服务端,信令协议,一般较多采用 SIP 协议,同时通过携带 SDP 数据包,进行 service 与 client 端的 RTP 相关的媒体协商。

  • 传统的 VoIP 针对 RTP 相关的协商内容一般包括:
    • 通道 (Channel),包含 UDP IP 地址、端口以及通讯方式(sendonly, recvonly, sendrecv)
    • 媒体格式及编码 比如 Audio: PCMA/PCMU Vedio: H264/H265

mediasoup 中,针对 RTP 的相关参数,也是需要协商的。

Mediasoup RTP Parameters and Capabilities

  • Parameter 参数
    包含两个方向的参数:
    • 与会者 A 作为 producer / sender (媒体数据或者说音视频数据的生产者,以及发送者)发送给 mediasoup 云服务的 RTP Send Parameter
    • 与会者 B 作为 consumer / receiver (媒体数据或者说音视频数据的消费者,以及接收者)接收来自于 mediasoup 云服务的 RTP Receive Parameter
      注意: A 和 B 一般既是生产者也是消费者。
  • Cpabilities 能力
    • mediasoup 服务端,或者与会者 client 端能够接受的,有能力识别并可以顺利处理的 RTP Parameters 描述的媒体,即称之为该端的 RTP Capabilities

Mediasoup RTP Negotiation Overview

当创建一个 Mediasoup 的 Router 后,该 Router 提供一系列音视频 codec 来告知 Router 创建者,该 Router 能够处理的音视频。该 codec 能力,将用 RtpCodecCapability 数据结构表示。
而 Meidasoup 服务端 RTP 能力,定义在了 mediasoup/src/supportedRtpCapabilities.ts 文件中。(不止一个,是一组能力)

Guidelines for mediasoup-client and libmediasoupclient

  • mediasoup-client: a client of mediasoup wrriten by JavaScript
  • libmediasoupclient: C++ library based on libwebrtc
  • 无论 js 版本还是 c++ 版本的库,内部都可以生产 mediasoup 可接受的 RTP Parameter 对象实例,有效的简化了 mediasoup 客户端的编程。

Mediasoup C/S 基于 Websocket 的通讯

  • 假设客户端使用 Device 对象提供的方式进行连接。而 mediasoup 服务端已经完成了 Router 的创建。
  • 应用程序可以使用 WebSocket 并将每个经过身份验证的 WebSocket 连接与 peer 端关联。

客户端的典型流程

  • Device Loading
  • Creating Transports
    mediasoup client 端,需要独立的 WebRTC 连接,去分别处理数据的发送和接收。
    • For sending media
      • 服务端 mediasoup router 中,必须首先创建 WebRTC 连接,方式如下:
        router.createWebRtcTransport(options)
      • 客户端中创建 WebRTC 发送连接,方式如下:
        device.createSendTransport(options)
      • 客户端必须订阅(监听)该 WebRTC 连接的如下事件:
        “connect” & “produce”
    • For receiving media
      • 服务端 router 中,首先创建 WebRTC 连接(方式同上)
      • 客户端中创建 WebRTC 接收连接,方式如下:
        device.createRecvTransport(options)
      • 客户端必须订阅(监听)该连接的 “connect” 事件
    • 以上连接中,如果需要使用 SCTP (AKA DataChannel in WebRTC)(我知道什么是SCTP,但是确实不知道什么是AKA),那么需要进行额外的处理,配置 enableSctp, 设置 SCTP 协议相关参数,给定 SCTP 协议连接池的大小等等。
  • 客户端生产数据 Producing Media
    一旦 sent 连接被建立,客户端就可以根据该连接,"生产"多轨道的音视频数据了。
    • 客户端可以通过比如 navigator.mediaDevices.getUserMedia() API 获取一个轨道。
    • 客户端调用 transport.produce(options)
      • 如果是第一次的 produce 调用这个,会触发 “connect” 事件。
      • produce 调用会触发 “produce” 事件,且该事件相关参数会被发送到服务端,服务端监听到该事件之后,会创建一个 Producer 实例。
    • 客户端会根据服务端的 Producer 实例,进行 produce 处理(Finally transport.produce() will resolve with a Producer instance in client side.这是原文,具体后续要看实验的结果,这种表达方式,不易理解)
  • 客户端 Consuming Media
    一旦 recv 连接被创建,客户端就可以根据该连接,接收并处理媒体数据了。实际过程与 producing 恰恰相反。
    • 第一,客户端必须先要把自己的 RTP 能力告知服务端(此步可以提前)。
    • 第二,服务端会调用如下接口:
      router.canConsume({ producerId, rtpCapabilities })
      作用:确定,某个 producer 的媒体 codec ,该客户端是否支持。
    • 第三,服务端调用 transport.consume(options) 接口,创建 Consumer 实例。
      • 服务端创建 Consumer 时,强烈建议将其设置 paused 置为 true ,然后将该 Consumer 参数传输到客户端,并且一旦客户端创建了其本地 consumer,此时服务单再调用 resume() 方法,激活服务端的 Consumer
    • 第四,服务端调用 transport.consume() 接口,将本地的一些参数,发送给客户端。
      • 首次调用 transport.consume() 接口,会触发一次 “connect” 事件
    • 最后,服务端通过 transport.consume() 接口,与客户端的 Cosumer 进行媒体传输
SCTP DataChannels 流程与上类似,接口略有差别

Communicating Actions and Events

mediasoup 一个核心准则,就是,当主动调用某些实例的方法,进行的一些操作,比如close,并不会触发相应的事件。

close event

无论是 server 端还是 client 端,当关闭了以上流程中涉及到的相应的对象时,那么应当及时的将关闭的状态,“通知”到相关方。
额外的, server 端,相应的对象,需要监听特定的事件,并且需要将该事件及时 notify 给到 client 端,并且,client 端需要进行特定的输出操作。

  • Transport “routerclose”. The client should call close() on the corresponding local transport.
    • transport 的 routerclose 事件,client 端应及时 close() 本端的 transport。
  • Producer “transportclose”. The client should call close() on the corresponding local producer.
  • Consumer “transportclose”. The client should call close() on the corresponding local consumer.
  • Consumer “producerclose”. The client should call close() on the corresponding local consumer.
  • DataProducer “transportclose”. The client should call close() on the corresponding local data producer.
  • DataConsumer “transportclose”. The client should call close() on the corresponding local data consumer.
  • DataConsumer “dataproducerclose”. The client should call close() on the corresponding local data consumer.

pause event

  • The same happens when pausing a RTP producer or consumer in client or server side. The action must be signaled to the other side.
  • In addition, the server side application should listen for the following events and notify the client about them:
    • Consumer “producerpause”. The client should call pause() on the corresponding local transport.
    • Consumer “producerresume”. The client should call resume() on the corresponding local transport (unless the consumer itself was also paused on purpose).

SVC or simulcast

  • When simulcast or SVC is in use, the application may be interested in signaling preferred layers and effective layers between client and server side consumers.
    • The server side application sets the consumer preferred layers via consumer.setPreferredLayers().
    • The server side consumer subscribes to the “layerschange” event and notifies the client application about the effective layers being transmitted.

mediasoup 尝鲜 demo

环境

Ubuntu 16.04 LTS
node: 12.18.2 LTS
npm: 6.15.5

  • 新建文件夹,作为我们的工作区
    mkdir csrtc

  • 进入文件夹,进行准备工作
    cd csrtc
    touch server.js
    sudo npm init
    (npm init 是一个交互过程,需要确认输入一些信息,根据提示往下走即可)

  • 补充,规避bug
    在 package.json 中添加如下内容,主要是在 stripts 中添加 start 的那一行的内容。

    "scripts": {
       "test": "echo \"Error: no test specified\" && exit 1",
       "start": "sudo node server.js"
    }
    
  • 安装 mediasoup 第三版
    sudo npm install mediasoup@3 --save

  • 验证安装,server.js 中编辑以下内容

    const mediasoup = require("mediasoup");
    console.log(mediasoup.version);
  • 运行
    sudo npm start

能够看到控制台输出 3.6.9

后续开发

如果涉及到 C++ 层面 mediasoup 内容的修改,不是添加或者删除文件之类(需要修改gyp,现阶段先尽量避免),后回到工作区执行: sudo npm rebuild 即可实现内部模块的重新编译。
 类似资料:

相关阅读

相关文章

相关问答