NetEQ 算法

2023-05-16

NetEQ 算法中集成了自适应抖动控制算法以及语音包丢失隐藏算法。这项技术使其能够快速且高解析度地适应不断变化的网络环境,确保音质优美且缓冲延迟最小。

 

研究的重点是 NetEQ 模块,其中所涉及的处理过程包括抖动消除、丢包补偿和压缩解码。

抖动消除原理

抖动通常采用抖动缓冲技术来消除,即在接收方建立一个缓冲区,语音包到达接收端时首先进人缓冲区暂存,随后系统再以稳定平滑的速率将语音包从缓冲

区提取出来,经解压后从声卡播出。

 

4 个语音数据包(A、B、C、D)以 30ms 为间隔进行发送,即发送时间分别为 30,60,90,120ms,网络延迟分别为10,30,10,10ms。到达时间为40,90,100,130ms,所以需要在抖动缓冲中分别缓冲60,90,120,150ms。

1.静态抖动缓冲控制算法

2.自适应抖动缓冲控制算法

丢包隐藏原理

 

iLBC 的丢包隐藏只是在解码端进行处理,即在解码端根据收到的比特流逐帧进行解码的过程中,iLBC  解码器首先拿到每帧的比特流时判断当前帧是否完整,如果没有问题则按照正常的 iLBC  解码流程重建语音信号,如果发现语音数据包丢失,那么就进入 PLC 单元进行处理。见算法步骤13

 

MCU(Micro Control Unit)模块是抖动缓冲区的微控制单元,由于抖动缓冲区作用是暂存接收到的数据包,因此 MCU 的主要作用是安排数据包的插入并控制数据包的输出。数据包的插入主要是确定来自网络的新到达的数据包在缓冲区中的插入位置,而控制数据包的输出则要考虑什么时候需要输出数据,以及输出哪一个插槽的数据包。抖动消除的算法思路在 MCU 控制模块中得以体现。

DSP 模块主要负责对从 MCU 中提取出来的 PCM 源数据包进行数字信号处理,

包括解码、信号处理、数据输出等几个部分。丢包隐藏操作即在 DSP 模块中完成。


NetEQ 模块框图

 

网络数据包进入抖动缓冲区的过程,其基本步骤如下,

 

AudioCodingModuleImpl::IncomingPacket(const uint8_t*incoming_payload,const int32_t payload_length,const WebRtcRTPHeader& rtp_info)

{

...

      memcpy(payload, incoming_payload, payload_length);
      codecs_[current_receive_codec_idx_]->SplitStereoPacket(payload, &length);
      rtp_header.type.Audio.channel = 2;
      per_neteq_payload_length = length / 2;
      // Insert packet into NetEQ.
      if (neteq_.RecIn(payload, length, rtp_header,
                       last_receive_timestamp_) < 0)
...

}

ACMNetEQ::RecIn(const uint8_t*incoming_payload,const int32_t length_payload,const WebRtcRTPHeader& rtp_info,uint32_t receive_timestamp)

{

...

WebRtcNetEQ_RecInRTPStruct(inst_[0], &neteq_rtpinfo,incoming_payload, payload_length,receive_timestamp);

}

int WebRtcNetEQ_RecInRTPStruct(void *inst, WebRtcNetEQ_RTPInfo *rtpInfo,
                               const uint8_t *payloadPtr, int16_t payloadLenBytes,
                               uint32_t uw32_timeRec)

{

...

    RTPPacket_t RTPpacket;

...

    /* Load NetEQ's RTP struct from Module RTP struct */
    RTPpacket.payloadType = rtpInfo->payloadType;
    RTPpacket.seqNumber = rtpInfo->sequenceNumber;
    RTPpacket.timeStamp = rtpInfo->timeStamp;
    RTPpacket.ssrc = rtpInfo->SSRC;
    RTPpacket.payload = (const int16_t*) payloadPtr;
    RTPpacket.payloadLen = payloadLenBytes;
    RTPpacket.starts_byte1 = 0;


    WebRtcNetEQ_RecInInternal(&NetEqMainInst->MCUinst, &RTPpacket, uw32_timeRec);

}

int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput,uint32_t uw32_timeRec)

{

...

WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst,&RTPpacket[i_k], &flushed, MCU_inst->av_sync);

...

WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k],&MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst,&flushed, MCU_inst->av_sync);

...

}

int WebRtcNetEQ_PacketBufferInsert(PacketBuf_t *bufferInst, const RTPPacket_t *RTPpacket,
                                   int16_t *flushed, int av_sync)

{//This function inserts an RTP packet into the packet buffer.

...

    /* Copy the packet information */
    bufferInst->payloadLocation[bufferInst->insertPosition] = bufferInst->currentMemoryPos;
    bufferInst->payloadLengthBytes[bufferInst->insertPosition] = RTPpacket->payloadLen;
    bufferInst->payloadType[bufferInst->insertPosition] = RTPpacket->payloadType;
    bufferInst->seqNumber[bufferInst->insertPosition] = RTPpacket->seqNumber;
    bufferInst->timeStamp[bufferInst->insertPosition] = RTPpacket->timeStamp;
    bufferInst->rcuPlCntr[bufferInst->insertPosition] = RTPpacket->rcuPlCntr;
    bufferInst->waitingTime[bufferInst->insertPosition] = 0;
...

}

int WebRtcNetEQ_SplitAndInsertPayload(RTPPacket_t* packet,PacketBuf_t* Buffer_inst,SplitInfo_t* split_inst,int16_t* flushed,int av_sync)

{

}

1:解析数据包并将其插入到抖动缓冲区中( Parse the payload and insert it into the buffer)。WebRtcNetEQ_SplitAndInsertPayload

WebRtcNetEQ_PacketBufferInsert(Buffer_inst, &temp_packet, &localFlushed);循环将输入数据packets split到PacketBuf_t 的实例中

  while (len >= split_inst->deltaBytes)

{

....

  i_ok = WebRtcNetEQ_PacketBufferInsert(Buffer_inst, &temp_packet, &localFlushed);

...

}

    /* Insert packet in the found position */
    if (RTPpacket->starts_byte1 == 0)
    {
        /* Payload is 16-bit aligned => just copy it */


        WEBRTC_SPL_MEMCPY_W16(bufferInst->currentMemoryPos,
            RTPpacket->payload, (RTPpacket->payloadLen + 1) >> 1);
    }
    else
    {
        /* Payload is not 16-bit aligned => align it during copy operation */
        for (i = 0; i < RTPpacket->payloadLen; i++)
        {
            /* copy the (i+1)-th byte to the i-th byte */


            WEBRTC_SPL_SET_BYTE(bufferInst->currentMemoryPos,
                (WEBRTC_SPL_GET_BYTE(RTPpacket->payload, (i + 1))), i);
        }
    }

2:更新 automode 中的参数,重点计算网络延迟的统计值 BLo(optBufferLevel)。WebRtcNetEQ_UpdateIatStatistics

      2.1

      /* calculate inter-arrival time in integer packets (rounding down) */
        timeIat = WebRtcSpl_DivW32W16(inst->packetIatCountSamp, packetLenSamp);

     2.2    /* update iatProb = forgetting_factor * iatProb for all elements */

      2.3        /* Calculate optimal buffer level based on updated statistics */
        tempvar = (int32_t) WebRtcNetEQ_CalcOptimalBufLvl(inst, fsHz, mdCodec, timeIat,
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

提取 10ms 数据到声卡的算法过程

3:将 DSP 的 endTimeStamp 赋值给 playedOutTS(用于提取数据的参考条件)并记录语音缓冲区中等待播放的样本数 sampleLeft。Write status data to shared memory

4:从抖动缓冲区提取数据。WebRtcNetEQ_DSP2MCUinterrupt

5:遍历查找抖动缓冲区中数据包的时间戳。 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,inst->timeStamp, &uw32_availableTS, &i_bufferpos, 1, &payloadType);

      5.1/* Loop through all slots in buffer. */

       5.2/* If old payloads should be discarded. */

6:统计进入接收端的 NetEQ 模块但仍未被播放的数据量,记为 bufsize。calculate total current buffer size (in ms*8), including sync buffer

 w32_bufsize = WebRtcSpl_DivW32W16((w32_bufsize + dspInfo.samplesLeft), fs_mult)

7.根据 bufsize 计算 BLc(bufferLevelFilt).WebRtcNetEQ_BufferLevelFilter

         * Current buffer level in packet lengths
         * = (curSizeMs8 * fsMult) / packetSpeechLenSamp     
         curSizeFrames = Sb/Lp;
         Sb = Np*Lp+sampleLeft;

 

    /* Filter buffer level */
    if (inst->levelFiltFact > 0) /* check that filter factor is set */
    {
        /* Filter:
         * buffLevelFilt = levelFiltFact * buffLevelFilt
         *                  + (1-levelFiltFact) * curSizeFrames
         *
         * levelFiltFact is in Q8
         */
        inst->buffLevelFilt = ((inst->levelFiltFact * inst->buffLevelFilt) >> 8) +
            (256 - inst->levelFiltFact) * curSizeFrames;
    }

8.根据 BLo(optBufferLevel)、BLc(bufferLevelFilt)、bufsize、playedOutTS、availableTS 及 NetEQ 的上一播放模式进行 MCU 控制命令的判断

9.根据 MCU 的控制命令及当前语音缓冲区中解码后未被播放的数据量sampleLeft 进行判断考虑是否需要从抖动缓冲区取数据.  Check sync buffer size     (Step 11) 

10.提取一个数据包送入共享内存暂存器.WebRtcNetEQ_PacketBufferExtract

11.根据从抖动缓冲区取数据之前的 MCU 的控制命令得到相应的 DSP的处理命令。 Step 13

12.解码取到的数据(Do decoding).inst->codec_ptr_inst.funcDecode()

13.丢包补偿.inst->codec_ptr_inst.funcDecodePLC

14.根据 DSP 操作命令进入相应的的播放模式对解码数据及语音缓冲区中数据进行相关操作。Step 15

15.从语音缓冲区的 curPosition 为起始位置取 10ms 数据传输到声卡。WEBRTC_SPL_MEMCPY_W16(pw16_outData, &inst->speechBuffer[inst->curPosition], w16_tmp1);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NetEQ 算法 的相关文章

  • T t与T t = T()的区别

    主要的区别就是默认构造函数对内置类型的初始化上 如果没有T中没有定义构造函数 xff0c 则对于 T t xff0c 并不会对 t 中内置类型设置初始值 xff0c 是一个随机值 但对于 T t 61 T xff0c 对 t 中内置类型会设
  • Effective STL:杂记(一)

    1 避免使用vector lt bool gt vector lt bool gt 实际上并不能算是一个STL容器 xff0c 实际上也并不存储bool 因为一个对象要成为STL容器 xff0c 就必须满足C 43 43 标准的第23 1节
  • 限制长度双向链表的插入操作

    面试遇到的问题 xff0c 一开始面试官是问我有什么方案可以实现排行榜 xff0c 当时给出了两个方案 后面面试官又在我的其中一种方案上让我手写代码实现排序双线链表的插入 xff0c 根据score值插入 xff0c 并且链表长度限制在10
  • SYD8821 IIC模块使用说明

    SYD8821是具有全球领先低功耗 RX 2 4mA 64 94 5dBm灵敏度 xff0c TX 4 3mA 64 0dBm输出功率 的蓝牙低功耗SOC芯片 xff0c 在极低电流下实现了优异的射频性能 xff0c 搭配176kB SRA
  • Python下载文件时出现乱码的解决方法之一:Content-Encoding: gzip

    之前写过一个简单的爬虫程序 xff0c 这次想试着再写一个下载固定文件的爬虫程序 写完之后发现下载的文件 xff0c 有些是可以正常打开的 xff0c 而有些是提示了编码错误 xff0c 用wireshark抓包 xff0c 过滤出http
  • Python爬虫判断url链接的是下载文件还是html文件

    最近在写一个网络爬虫的代码 xff0c 提供命令行来下载文件或者是打印根域名下指定节点及深度的子节点 用的是urllib2库 xff0c 算是比较简单 xff0c 但是功能并没有很强大 说重点吧 xff0c 在实际爬网页的过程中 xff0c
  • recvmsg和sendmsg函数

    在unp第14章讲了这两个函数 xff0c 但是只是讲了两个数据结构及参数而已 xff0c 所以自己想根据介绍来重构udp回射的客户端程序 但是sendmsg和recvmsg都遇到了问题 xff0c 并且纠结了很久 xff0c 所以在此记录
  • STL中map的[]运算导致程序挂掉的问题

    在项目的开发中 xff0c 使用 设置map变量时 xff0c 出现了Segment Fault的问题 xff0c 使用GDB bt命令得到调用栈 xff08 中间部分被我去掉了 xff09 如下 xff1a 0 0x00000000008
  • 结构体的vector resize()与初始化

    转自 xff1a https www cnblogs com kongse qi p 6798873 html 序 xff1a 我们在使用vector的时候可以自定义里面的数据类型 例如这样 xff1a struct Edge int fr
  • new(p) T1(value) 的操作

    最近开始看 STL源码剖析 xff0c 看到空间配置器的时候 xff0c 发现这么一段代码 xff1a template lt class T1 class T2 gt inline void construct T1 p const T2
  • Protobuf 编码及序列化的记录

    工作中用到了protobuf xff0c 然后之前在面试的时候面试官就问了一个问题 xff0c 如果将int32类型的字段的值设置为0 xff0c 那还会将该值进行序列化吗 xff1f 当时是懵了的 xff0c 因为自己还没有研究这部分 当
  • STM32驱动lcd1602,并口8位 6800时序

    STM32驱动lcd1602 xff0c 并口8位 6800时序 一 LCD1602 xff08 3 3V硬件版本 xff09 简介 1 1 引脚 引脚 xff0c lcd1602采用标准接口 xff0c 6800时序8位并行数据传输 第
  • CAN总线详解

    1 简介 CAN是控制器局域网络 Controller Area Network CAN 的简称 xff0c 是一种能够实现分布式实时控制的串行通信网络 优点 xff1a 传输速度最高到1Mbps xff0c 通信距离最远到10km xff
  • VS C#工程三【使用配置文件保存应用程序里的配置数据】[Resources找不到][打印log到VS窗口]【安全从工程删除图片】[发布exe并附带动态链接库dll]

    SYD8801是一款低功耗高性能蓝牙低功耗SOC xff0c 集成了高性能2 4GHz射频收发机 32位ARM Cortex M0处理器 128kB Flash存储器 以及丰富的数字接口 SYD8801片上集成了Balun无需阻抗匹配网络
  • 对Socket CAN的理解(2)——【Socket的原理及使用】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 为了能够对Socket CAN的深入理解 xff0c 我们需要了解Socket的机制 Socket的中文翻译为 插座 xff0c 在计算机
  • 对Socket CAN的理解(3)——【Socket CAN发送数据流程】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 对于本文 xff0c 我们将从用户层使用Socket CAN进行数据发送时 xff0c 数据从用户空间到底层驱动的整个通信流程 xff0c
  • 对Socket CAN的理解(4)——【Socket CAN接收数据流程】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 现在我们来分析一下CAN总线的接收数据流程 xff0c 对于网络设备 xff0c 数据接收大体上采用中断 43 NAPI机制进行数据的接收
  • docker创建ubuntu16.04容器(上)

    容器三大基本概念 xff0c docker整个生命周期就是这三个概念 镜像 image Docker镜像就是一个只读的模板 镜像可以用来创建Docker容器 Docker提供了一个很简单的机制来创建镜像或者更新现有的镜像 xff0c 用户甚
  • SPDIF接口介绍

    一 S PDIF接口规范详解 S PDIF是sony和philips在80年代为一般家用器材所定制出来的一种数字讯号传输接口 xff0c 基本上是以AES EBU 也称AES3 专业用数字接口为参考然后做了一些小变动而成的家用版本 可以使用

随机推荐

  • 【音频】I2S协议详解

    一 I2S介绍 I2S Inter IC Sound 总线 又称 集成电路内置音频总线 xff0c 是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准 xff0c 该总线专门用于音频设备之间的数据传输 xff0c 广泛应用于各
  • linux 音频驱动实验

    文章目录 一 音频接口简介 1 为何需要音频编解码芯片2 WM8960简介3 I2S总线接口4 6u SAI简介 二 硬件原理图三 音频驱动使能 1 修改设备树 1 Wm8906 i2c接口设备树2 6u SAI接口设备树3 I MX6UL
  • 【UBI文件系统制作】-(1)UBI文件系统简介

    1 引言 在Linux 2 6 27以前 xff0c 谈到Flash文件系统 xff0c 大家很多时候多会想到CRAMFS JFFS2 YAFFS2等文件系统 它们也都是基于文件系统 43 MTD 43 Flash设备的架构 Linux 2
  • 分享篇 - Android 如何使用其他 APP 的 App ID 做微信分享

    1 需求背景 一些 APP 分享到微信 xff0c 朋友圈经常被封 如果在微信分享时 xff0c 我们将微信分享的 App ID 改成其他应用的 App ID xff0c 就可以使用其他 App 的名义进行分享 xff0c 而且分享出去的内
  • 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int---->解决方法

    写了一个对应让其出的错误 xff08 其实也挺不容易的喔 xff09 错误如下 xff1a 1 gt d work win32project testeachotherclude testeachotherclude test2 h 9 e
  • 58同城Android端-最小插件化框架实战和原理分析

    目录 背景插件化需要了解的知识 2 1 类加载过程和类加载器 2 2 ClassLoader 的 findClass findLibrary findResource 2 3 DexClassLoader 的 oat 配置 2 4 Load
  • MetaX组件化框架

    目录 MetaX 框架介绍MetaX 是如何设计的MetaX 运行效果 1 MetaX 框架介绍 MetaX 是 58无线 Android 团队开发的一套增强版的组件化框架 xff0c 它制定了一系列的标准和规范 xff0c 来解决现有组件
  • 58同城首页腰部动态化技术选型(布局动态化)

    1 行业情况 1 1 基本概念介绍 1 1 1 Web混合 Web 前端和客户端的混合开发 使用 WebView 进行页面渲染 逻辑执行 xff1b 依赖客户端的能力需要通过 JSBridge 通信桥 的方式进行调用 xff0c 比如调用客
  • Java篇 - 四种引用(Reference)实战

    Java的垃圾回收 GC 是虚拟机自动管理的 xff0c 前面我有篇文章专门讲GC xff1a JVM篇 GC给你整明白 Java内存管理分为内存分配和内存回收 xff0c 都不需要程序员负责 xff0c 垃圾回收的机制主要是看对象是否有引
  • 网络篇 - https协议中的数据是否需要二次加密

    随着互联网整体的发展 xff0c https 也被越来越多的应用 甚至苹果去年还曾经放言要强制所有的 app 都使用 https xff0c 可见在如今的互联网它的重要性 前面的文章说了 OSI 七层模型 xff0c https 可以保证数
  • 加解密篇 - 对称加密算法 (DES、3DES、AES、RC)

    这篇文章来讲讲对称加密 xff0c 对称加密在开发中用的很多 xff0c 如 AES xff0c DES xff0c 3DES xff0c RC 目录 介绍优点和缺点DES算法3DES算法AES算法RC算法 1 介绍 1 1 概念 采用单钥
  • 加解密篇 - 非对称加密算法 (RSA、DSA、ECC、DH)

    最近的文章中多次出现了非对称加密 xff0c 今天就来分析一下非对称加密的算法 目录 xff1a 简介RSA算法DSA算法ECC算法DH算法 1 简介 1 1 概念 非对称加密需要两个密钥 xff1a 公钥 publickey 和私钥 pr
  • 跨平台技术篇 - 使用 Flutter 与原生技术混合开发示例

    目前主流的混合开发方案有两种集成方式 xff1a 源码集成 xff1a 也就是谷歌官方提供的方案 https github com flutter flutter wiki Add Flutter to existing apps 产物集成
  • 音视频篇 - Android 音视频涉及到的技术

    前言 现在市面上的图像 xff0c 音视频软件越来越多 xff0c 最近两年也是直播 xff0c 短视频的红利期 而图像 音视频一直是互联网视觉的入口 xff0c 掌握并熟练运用音视频 图像技术已经是当前互联网时代不可或缺的技能 xff0c
  • sockaddr_in的一个小理解

    之前一直认为是sockaddr 设计时有缺陷 xff0c 在编写网络通信时 xff0c 都使用sockaddr in xff0c 因为它将sockaddr 中的 char sa data 14 拆分为了 unsigned short sin
  • Linux虚拟机下WWW(HTTP)服务器的搭建与使用(详细)

    1 简介 1 1 关于www服务器 WWW服务器是被动程序 xff0c 只有接收到互联网中其他计算机发出的请求后才会响应 xff0c 然后WWW服务器才会使用HTTP或者HTTPS将指导文件传输到客户机的浏览器上 1 2 关于HTTP协议
  • 非抢占式优先级调度算法

    Priority scheduling is a type of scheduling algorithm used by the operating system to schedule the processes for executi
  • Eclipse中使用jstl标签库

    在MyEclipse中使用jstl标签只需导读jstl jar就能使用 xff0c 但是在Eclipse中还需要一点小套路 步骤 xff1a 一 导入jstl jar 二 导入导入standard jar 三 web xml加上如下配置 l
  • hibernate HQL 投影查询 + 多表关联

    64 Test public void testQueryProjection Session session 61 HibernateUtils openSession session beginTransaction 操作 hql 默认
  • NetEQ 算法

    NetEQ 算法中集成了自适应抖动控制算法以及语音包丢失隐藏算法 这项技术使其能够快速且高解析度地适应不断变化的网络环境 xff0c 确保音质优美且缓冲延迟最小 研究的重点是 NetEQ 模块 xff0c 其中所涉及的处理过程包括抖动消除