大话ion系列(四)

a98df310eb6512250801865ec3fd88ee.gif

点击上方“LiveVideoStack”关注我们

作者 | 王朋闯

本文为王朋闯老师创作的系列ion文章,LiveVideoStack已获得授权发布,未来将持续更新。

大话ion系列(一)

大话ion系列(二)

大话ion系列(三)

七、Simulcast流程

1. Simulcast概念

先介绍WebRTC的一个概念——Simulcast(联播,俗称大小流):

推流端===f/h/q==>SFU--f--->收流端A
                 |---q--->收流端B
                 |---h--->收流端C
  • 上行一般是三路流,按分辨率和码率,一般分为fhq(大中小)三层

  • 下行可以分给不同的用户不同的流,比如网不好时分发个小流q,网变好了再切回大流f

  • 三层的streamId、trackId是一样的,但是rid和ssrc是不同的,rid一般是f、h、q

  • 对应的SDP部分

.........
a=rid:f send
a=rid:h send
a=rid:q send
a=simulcast:send f;h;q

2.收发流程

看本章之前,最好看一下前一章,熟悉一下收发流程,本文只重点介绍其中的Simulcast部分。

收发包逻辑打通步骤:

SDK推流---->OnTrack---->router.AddReceiver(设置Buffer和上行Track)------>SessionLocal.Publish(设置下行Track)---->收发包逻辑打通

3.Simulcast上行流程

非Simulcast情况,OnTrack一般会触发两次:一个audioTrack+一个videoTrack。

Simulcast下,OnTrack一般会触发四次:一个audioTrack+三个videoTrack(rid分别为fhq)。

这个流程会触发四次:

OnTrack--->router.AddReceiver--->WebRTCReceiver.AddUpTrack

三个videoTrack,共用同一个WebRTCReceiver。

type WebRTCReceiver struct {
。。。
    receiver       *webrtc.RTPReceiver
    codec          webrtc.RTPCodecParameters
    rtcpCh         chan []rtcp.Packet
    buffers        [3]*buffer.Buffer//需要三个buffer
    upTracks       [3]*webrtc.TrackRemote//三个TrackRemote
。。。
    pendingTracks  [3][]*DownTrack//三个层,每层来订阅的downtrack
。。。
}

接下来看一下AddUpTrack是如何工作的:

func (w *WebRTCReceiver) AddUpTrack(track *webrtc.TrackRemote,buff *buffer.Buffer, bestQualityFirst bool) {
    if w.closed.get() {
        return
    }
 
  //根据RID来区分layer
    var layer int
    switch track.RID() {//如果没开simulcast,为""
    case fullResolution:
        layer = 2
    case halfResolution:
        layer = 1
    default:
        layer = 0//如果没开simulcast,为0
    }
 
    w.Lock()
  //设置空域层layer的track
    w.upTracks[layer] = track
 
  //设置空域层layer的buff
    w.buffers[layer] = buff
    w.available[layer].set(true)
 
  //设置空域层layer的downtrack
    w.downTracks[layer].Store(make([]*DownTrack,0, 10))
    w.pendingTracks[layer] = make([]*DownTrack,0, 10)
    w.Unlock()
 
  //闭包函数,按最佳质量订阅,切到f层
    subBestQuality := func(targetLayerint) {
        for l := 0; l <targetLayer; l++ {
            dts :=w.downTracks[l].Load()
            if dts == nil{
                continue
            }
            for _, dt :=range dts.([]*DownTrack) {
                _ = dt.SwitchSpatialLayer(int32(targetLayer), false)
            }
        }
    }
 
  //闭包函数,按最差质量订阅,切到q层
    subLowestQuality := func(targetLayerint) {
        for l := 2; l !=targetLayer; l-- {
            dts :=w.downTracks[l].Load()
            if dts == nil{
                continue
            }
            for _, dt :=range dts.([]*DownTrack) {
         
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值