webrtc之精读audio jitterbuffer

 

目录

webrtc之精读audio jitterbuffer

前言:

一 NetEq之Inserpacket

1.1 InsertPacketInternal

1.2 InsertPacketList

1.3 InsertPacket

二 DelayManager

2.1 Update

2.2 UpdateHistogram

2.3 CalculateTargetLevel

2.4 LimitTargetLevel

三 DelayPeakDetector

四 NetEq之GetAudio

四 结尾. 参照,感谢

 


 

webrtc之精读audio jitterbuffer

前言:

先看从网上摘来的2张图片,webrtc核心之一的技术就是其neteq,从图中可以看出其所处位置,及它的模块构成这里网上参考文章很多,不详细介绍,下面文献主要是阅读过程中的一些参考。

  • 抗抖动:增加buffer来抵抗网络造成的抖动,让buffer中的数据平稳输出
  • 去重:将收到的重复包丢弃。
  • 触发重传:jitter buffer中每个packet(包)都有sequence number, 即包的序列号,序列号有间隔,则说明有丢包;有丢包则需要重传。

如何计算jitter

两个连续的包,收到的时间点之差,减去,发送的时间点之差,即是当前的抖动,计算公式如下
jitter = (packet[i].recvTime - packet[i-1].recvTime) - (packet[i].sendTime - packet[i-1].sendTime);
jitter > 0 说明需要加速播放
jitter < 0 说明需要延迟播放

一般音频数据不止一个包,连续的包,则会产生一系列的抖动值。

 

 

一 NetEq之Inserpacket

1.1 InsertPacketInternal

insertpacket主体流程代码主要是InsertPacketInternal,总体流程如下:

  1. 将数据放入局部变量 PacketList 中
  2. 处理 RTP 包逻辑
    • 转换内外部时间戳
    • NACK(否定应答) 处理
    • 判断冗余大包(RED)并解为小包
    • 检查包类型
    • 判断并处理 DTMF(双音多频) 包
    • 带宽估算
  3. 分析包
    • 去除噪音包
    • 解包头获取包的信息
    • 计算除纠错包和冗余包以外的正常语音包数量
  4. 将语音包插入 PacketBuffer(抖动缓冲区)
int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
                                    rtc::ArrayView<const uint8_t> payload,
                                    uint32_t receive_timestamp) {
  if (payload.empty()) {   //判断是否payload为空
    RTC_LOG_F(LS_ERROR) << "payload is empty";
    return kInvalidPointer;
  }

  PacketList packet_list;   //局部变量packet_list,存放生成的语音包
  // Insert packet in a packet list.
  packet_list.push_back([&rtp_header, &payload] {
    // Convert to Packet.
    Packet packet;
    packet.payload_type = rtp_header.payloadType;  
    packet.sequence_number = rtp_header.sequenceNumber;
    packet.timestamp = rtp_header.timestamp;
    packet.payload.SetData(payload.data(), payload.size());
    // Waiting time will be set upon inserting the packet in the buffer.
    RTC_DCHECK(!packet.waiting_time);
    return packet;
  }());     //将语音包通过lamda表达式调用生成push_back至packet_list

  bool update_sample_rate_and_channels =          //是否是首包或者发现ssrc_发生变化
      first_packet_ || (rtp_header.ssrc != ssrc_);

  if (update_sample_rate_and_channels) {             //首次 曾重置源码时间戳缩放类
   /*
    WebRTC中的时间戳缩放类用于将外部时间戳转换为内部时间戳,或者将内部时间戳转换为外部时间戳。    
    内部 / 外部时间戳概念
   外部时间戳即为RTP携带的时间戳字段,它表示RTP报文发送的时钟频率,在语音中通常等于pcm语音的采样 
   率(RTP携带Opus编码时 时钟频率设置为固定的48kHz,而采样率可以有很多值),在视频中无论是哪种是 
   视频编码,外部时间戳(时钟频率)都设置为固定的90kHz。
   外部时间戳转换为内部时间戳就是将外部时间戳按照采样率缩放。设初始内部时间戳为0,则
   内部时间戳 += 外部时间戳间隔 * ( 采样率 / 外部时间戳 )
   相反,用内部时间戳转换为外部时间戳就是按照采样率扩大。设初始外部时间戳为0,则
   外部时间戳 += 内部时间戳间隔 * ( 外部时间戳 / 采样率 )
   */
    // Reset timestamp scaling.
    timestamp_scaler_->Reset();
  }

  if (!decoder_database_->IsRed(rtp_header.payloadType)) { //非red冗余包则转换为内部时间戳
    // Scale timestamp to internal domain (only for some codecs).
    timestamp_scaler_->ToInternal(&packet_list);
  }

  // Store these for later use, since the first packet may very well disappear
  // before we need these values.
  uint32_t main_timestamp = packet_list.front().timestamp;  //主时间戳
  uint8_t main_payload_type = packet_list.front().payload_type; 
  uint16_t main_sequence_number = packet_list.front().sequence_number;

  // Reinitialize NetEq if it's needed (changed SSRC or first call).
  if (update_sample_rate_and_channels) {     //首次则初始话相关数据结构
    // Note: |first_packet_| will be cleared further down in this method, once
    // the packet has been successfully inserted into the packet buffer.

    rtcp_.Init(rtp_header.sequenceNumber);    //初始话rtcp_模块

    // Flush the packet buffer and DTMF buffer.
    packet_buffer_->Flush();            //包缓存
    dtmf_buffer_->Flush();              //看rfc这个用来保存来电呼叫铃声? 本地调试未看见

    // Store new SSRC.
    ssrc_ = rtp_header.ssrc;            //初始化ssrc_

    // Update audio 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值