WebRTC架构简介

来源:互联网 发布:php短链接生成器源码 编辑:程序博客网 时间:2024/04/30 06:10
1、WebRTC目的
       
       WebRTC(Web Real-Time Communication)项目的最终目的主要是让Web开发者能够基于浏览器(Chrome\FireFox\...)轻易快捷开发出丰富的实时多媒体应用,而无需下载安装任何插件,Web开发者也无需关注多媒体的数字信号处理过程,只需编写简单的Javascript程序即可实现,W3C等组织正在制定Javascript 标准API,目前是WebRTC 1.0版本,Draft状态,网址;另外WebRTC还希望能够建立一个多互联网浏览器间健壮的实时通信的平台,形成开发者与浏览器厂商良好的生态环境。同时,Google也希望和致力于让WebRTC的技术成为HTML5标准之一,可见Google布局之深远。


2、WebRTC架构图



架构图颜色标识说明:
(1)紫色部分是Web开发者API层;
(2)蓝色实线部分是面向浏览器厂商的API层(也就是红色框标内模块,也是本人专注研究的部分)
(3)蓝色虚线部分浏览器厂商可以自定义实现

3、WebRTC架构组件介绍


(1) Your Web App
Web开发者开发的程序,Web开发者可以基于集成WebRTC的浏览器提供的web API开发基于视频、音频的实时通信应用。

(2) Web API
面向第三方开发者的WebRTC标准API(Javascript),使开发者能够容易地开发出类似于网络视频聊天的web应用,最新的标准化进程可以查看这里

(3) WebRTC Native C++ API
本地C++ API层,使浏览器厂商容易实现WebRTC标准的Web API,抽象地对数字信号过程进行处理。

(4) Transport / Session
传输/会话层
会话层组件采用了libjingle库的部分组件实现,无须使用xmpp/jingle协议

a.  RTP Stack协议栈
Real Time Protocol

b.  STUN/ICE
可以通过STUN和ICE组件来建立不同类型网络间的呼叫连接。

c.  Session Management
一个抽象的会话层,提供会话建立和管理功能。该层协议留给应用开发者自定义实现。

(5) VoiceEngine
音频引擎是包含一系列音频多媒体处理的框架,包括从视频采集卡到网络传输端等整个解决方案
PS:VoiceEngine是WebRTC极具价值的技术之一,是Google收购GIPS公司后开源的。在VoIP上,技术业界领先,后面的文章会详细了解

a.  iSAC
Internet Speech Audio Codec
针对VoIP和音频流的宽带和超宽带音频编解码器,是WebRTC音频引擎的默认的编解码器
采样频率:16khz,24khz,32khz;(默认为16khz)
自适应速率为10kbit/s ~ 52kbit/;
自适应包大小:30~60ms;
算法延时:frame + 3ms

b.  iLBC
Internet Low Bitrate Codec
VoIP音频流的窄带语音编解码器
采样频率:8khz;
20ms帧比特率为15.2kbps
30ms帧比特率为13.33kbps
标准由IETF RFC3951和RFC3952定义

c.  NetEQ for Voice
针对音频软件实现的语音信号处理元件
NetEQ算法:自适应抖动控制算法以及语音包丢失隐藏算法。使其能够快速且高解析度地适应不断变化的网络环境,确保音质优美且缓冲延迟最小。
是GIPS公司独步天下的技术,能够有效的处理由于网络抖动和语音包丢失时候对语音质量产生的影响。
PS:NetEQ 也是WebRTC中一个极具价值的技术,对于提高VoIP质量有明显效果,加以AEC\NR\AGC等模块集成使用,效果更好。

d.  Acoustic Echo Canceler (AEC)
回声消除器是一个基于软件的信号处理元件,能实时的去除mic采集到的回声。

e.  Noise Reduction (NR)
噪声抑制也是一个基于软件的信号处理元件,用于消除与相关VoIP的某些类型的背景噪声(嘶嘶声,风扇噪音等等… …)

(6) VideoEngine
WebRTC视频处理引擎
VideoEngine是包含一系列视频处理的整体框架,从摄像头采集视频到视频信息网络传输再到视频显示整个完整过程的解决方案。

a.  VP8
视频图像编解码器,是WebRTC视频引擎的默认的编解码器
VP8适合实时通信应用场景,因为它主要是针对低延时而设计的编解码器。
PS:VPx编解码器是Google收购ON2公司后开源的,VPx现在是WebM项目的一部分,而WebM项目是Google致力于推动的HTML5标准之一

b.  Video Jitter Buffer
视频抖动缓冲器,可以降低由于视频抖动和视频信息包丢失带来的不良影响。

c.  Image enhancements
图像质量增强模块
对网络摄像头采集到的图像进行处理,包括明暗度检测、颜色增强、降噪处理等功能,用来提升视频质量。

底层架构

上图实为WebRTC的底层架构,可以其用到的技术非常多的,包括视频音频处理以及网络传输,防火墙穿越等技术。


WebRTC有三个模块,Voice Engine(音频引擎),Video Engine(视频引擎),Transport。Voice Engine包含iSAC/iLBC Codec(音频编解码器,前者是针对宽带和超宽带,后者是针对窄带),NetEQ for voice(处理网络抖动和语音包丢失),Echo Canceler(回声消除器),Noise Reduction(噪声抑制);Video Engine包含VP8 Codec(视频图像编解码器),Video jitter buffer(视频抖动缓冲器,处理视频抖动和视频信息包丢失),Image enhancements(图像质量增强)。Transport包含SRTP(安全的实时传输协议,用以音视频流传输),Multiplexing(多路复用),P2P,STUN+TURN+ICE(用于NAT网络和防火墙穿越的)。除此之外,安全传输可能还会用到DTLS(数据报安全传输),用于加密传输和密钥协商。整个WebRTC通信是基于UDP的

MediaStream获取音视频数据流

getUserMedia(constraints,successCallback,errCallback)

navigator上的方法,用于获取用户授权提供的音频视频数据流,三个参数分别为约束对象,成功的回调函数,发送错误的回调函数。

浏览器兼容性

1
2
3
4
const getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);

上栗子:MediaStream和Canvas实现拍照功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
let video = document.getElementById('video'),
canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
localStream = null;
getUserMedia({video:true,audio:true},stream=>{
video.src = window.URL.createObjectURL(stream);
localStream = stream;
},err=>{
console.log('get stream failed!');
});
video.addEventListener('click',()=>{
if(localStream){
ctx.drawImage(video,0,0);
document.getElementById('img').src = canvas.toDataURL('image/png');
}
});

RTCPeerConnection实现P2P通信

P2P通信基于UDP传输协议,更加注重传输实时性。P2P建立过程是比较复杂的。主要是交换SDP和ICE信息。
P2P

上图所示为利用信令服务器实现P2P通信的流程图,其中还包含了STUN服务器(非WebRTC实现)

P2P通信建立过程

交换SDP

SDP是一种会话描述协议(Session Description Protocol),包含了一系列信息包括会话使用的媒体种类,双方ip和port,带宽,会话属性等。

SDP交换采用Offer/Answer形式。

  1. 首先Offer方通过new RTCPeerConnection(config)建立PeerConnection
  2. Offer方通过createOffer生成sessionDescription,设置localDescription,并通过信令服务器发送给Answer方
  3. Answer方收到offer,发现并没有与之对应的peerConnection,新建peerConnection,并设置remoteDescription
  4. Answer方通过createAnswer生成sessionDescripton,设置localDescription,并通过信令服务器发送answer
  5. Offer方收到answer,设置remoteDescription
  6. SDP交换结束

交换ICE

ICE是一种用于实现NAT/防火墙穿越的协议,可以实现:

  1. P2P直接通信
  2. 使用STUN服务器实现突破NAT的P2P通信
  3. 使用TURN中继服务器实现突破防火墙的中继通信

交换过程:

  1. 双方在new RTCPeerConnection(config)建立连接后,当网络候选者可用时,会触发icecandidate事件
  2. 在onicecandidate事件处理程序中将candidate通过信令服务器发送给对方
  3. 双方在接受到彼此的candidate后,通过addIceCandidate将对方的candidate加入到PeerConnection实例中。

在连接建立前或者建立后调用peerConnection.addStream()方法将本地视频/音频数据流加入到connection当中,当对方接受到视频流时会触发addStream事件,在其处理程序中我们可以接受数据流将其显示。

基于Socket.io和WebRTC的两人视频聊天室

上述过程的信令服务器可以使用WebSocket服务,而Node.js可以方便的实现ws服务,socket.io更是封装了一系列API,可以方便的实现多人视频聊天室,多人视频聊天室有需要注意一些其他诸如SDP冲突问题,这里先以两人通信为例来更深入理解整个过程。

1
//代码较多这里省略

NAT/防火墙穿越技术

之所以将NAT/防火墙单独出来,是因为NAT/防火墙问题是建立端对端通信的一个重要问题
STUN

NAT

NAT将连接到公网的全局ip转换为内网ip,实现多个终端通信,防止受到来自外网的攻击,有效节省IPV4数量。WebRTC必须穿越NAT进行通信。ICE可以通过STUN技术穿越NAT。

NAT的实现方式有三种,即静态转换Static Nat、动态转换Dynamic Nat和端口多路复用OverLoad。目前用得比较多的就是端口多路复用。

STUN服务器可以是自己搭建的,也可以是直接使用现成的,比如谷歌的stun服务:stun:stun.l.google.com:19302

自己搭建STUN服务器比较简单,这里篇幅有限,省略

配置好STUN服务,以此建立RTCPeerConnection,配置方法就是上面的config对象:

1
2
3
4
const config = {
"iceServers":[{"url":"stun:stun.yourdomain.com:3478"}]
}
let peer = new RTCPeerConnection(config);

防火墙

对于防火墙,需要依靠TURN服务器来进行通信。起一各TURN服务器监听在某个端口时,需要设置防火墙开发这个端口。搭建TURN服务器也比较简单,在这里也省略。

同样也要配置好config:

1
2
3
4
5
const config = {
"iceServers":[
{"url":"stun:stun.yourdomain.com:3478"},{"url":"turn:turn.yourdomain.com:3478","username":"yourid","credential:"yourpassword"}]
}
let peer = new RTCPeerConnection(config);

RTCDataChannel API

既然可以实现音频视频的实时通信,为何不可以实现文本,文件等数据的传输呢?RTCDataChannel API就提供了这个功能。它通过将数据直接从一个浏览器发送到另一个浏览器,不需要将数据通过服务器来进行中转发送,简化了过程,保证实时性,同时还确保数据的安全私密性。

RTCDataChannel 与RTCPeerConnection API相结合,使用SCTP(流控制传输协议)实现稳定有序的数据传递。其仍然需要信令服务器的参与。以及STUN和TURN服务器来穿越NAT/防火墙。

RTCDataChannel支持两种模式运行:不可信赖模式(类似UDP)和可信赖模式(类似于TCP)。

流程分析

  1. 通过config建立RTCPeerConnection
  2. 通过peerConnection.createDataChannel(label,dataChannelConfig)获取dataChannel对象
  3. 按照上述P2P建立流程完成SDP和ICE信息交换
  4. 调用send()方法发送消息
  5. 接收方监听message事件,获取数据
1
let dataChannel = peerConnection.createDataChannel('dataChannel',{'reliable:false'});

详细API可查看WebRTC官网




4、WebRTC核心模块API


(1)、网络传输模块:libjingle

WebRTC重用了libjingle的一些组件,主要是network和transport组件,关于libjingle的文档资料可以查看这里

(2)、音频、视频图像处理的主要数据结构

常量\VideoEngine\VoiceEngine

注意:以下所有的方法、类、结构体、枚举常量等都在webrtc命名空间里  

类、结构体、枚举常量

头文件

说明

Structures

common_types.h

Lists the structures common to the VoiceEngine & VideoEngine

Enumerators

common_types.h

List the enumerators common to the  VoiceEngine & VideoEngine

Classes

common_types.h

List the classes common to VoiceEngine & VideoEngine

class VoiceEngine

voe_base.h

How to allocate and release resources for the VoiceEngine using factory methods in the VoiceEngine class. It also lists the APIs which are required to enable file tracing and/or traces as callback messages

class VideoEngine

vie_base.h

How to allocate and release resources for the VideoEngine using factory methods in the VideoEngine class. It also lists the APIs which are required to enable file tracing and/or traces as callback messages


(3)、音频引擎(VoiceEngine)模块 APIs


下表列的是目前在 VoiceEngine中可用的sub APIs
sub-API

头文件

说明

VoEAudioProcessing

voe_audio_processing.h

Adds support for Noise Suppression (NS), Automatic Gain Control (AGC) and Echo Control (EC). Receiving side VAD is also included.

VoEBase

voe_base.h

Enables full duplex VoIP using G.711.
NOTE: This API must always be created.

VoECallReport

voe_call_report.h

Adds support for call reports which contains number of dead-or-alive detections, RTT measurements, and Echo metrics.

VoECodec

voe_codec.h

Adds non-default codecs (e.g. iLBC, iSAC, G.722 etc.), Voice Activity Detection (VAD) support.

VoEDTMF

voe_dtmf.h

Adds telephone event transmission, DTMF tone generation and telephone event detection. (Telephone events include DTMF.)

VoEEncryption

voe_encryption.h

Adds external encryption/decryption support.

VoEErrors

voe_errors.h

Error Codes for the VoiceEngine

VoEExternalMedia

voe_external_media.h

Adds support for external media processing and enables utilization of an external audio resource.

VoEFile

voe_file.h

Adds file playback, file recording and file conversion functions.

VoEHardware

voe_hardware.h

Adds sound device handling, CPU load monitoring and device information functions.

VoENetEqStats

voe_neteq_stats.h

Adds buffer statistics functions.

VoENetwork

voe_network.h

Adds external transport, port and address filtering, Windows QoS support and packet timeout notifications.

VoERTP_RTCP

voe_rtp_rtcp.h

Adds support for RTCP sender reports, SSRC handling, RTP/RTCP statistics, Forward Error Correction (FEC), RTCP APP, RTP capturing and RTP keepalive.

VoEVideoSync

voe_video_sync.h

Adds RTP header modification support, playout-delay tuning and monitoring.

VoEVolumeControl

voe_volume_control.h

Adds speaker volume controls, microphone volume controls, mute support, and additional stereo scaling methods.



(4)、视频引擎(VideoEngine)模块 APIs

下表列的是目前在 VideoEngine中可用的sub APIs

sub-API

头文件

说明

ViEBase

vie_base.h

Basic functionality for creating a VideoEngine instance, channels and VoiceEngine interaction.

NOTE: This API must always be created.

ViECapture

vie_capture.h

Adds support for capture device allocation as well as capture device capabilities.

ViECodec

vie_codec.h

Adds non-default codecs, codec settings and packet loss functionality.

ViEEncryption

vie_encryption.h

Adds external encryption/decryption support.

ViEErrors

vie_errors.h

Error codes for the VideoEngine

ViEExternalCodec

vie_external_codec.h

Adds support for using external codecs.

ViEFile

vie_file.h

Adds support for file recording, file playout, background images and snapshot.

ViEImageProcess

vie_image_process.h

Adds effect filters, deflickering, denoising and color enhancement.

ViENetwork

vie_network.h

Adds send and receive functionality, external transport, port and address filtering, Windows QoS support, packet timeout notification and changes to network settings.

ViERender

vie_render.h

Adds rendering functionality.

ViERTP_RTCP

vie_rtp_rtcp.h

Adds support for RTCP reports, SSRS handling RTP/RTCP statistics, NACK/FEC, keep-alive functionality and key frame request methods.


1、VoiceEngine Codec数据结构

       WebRTC中,用一个结构体struct CodecInst表示特定的音频编解码器对象:

[cpp] view plain copy
  1. struct CodecInst  
  2. {  
  3.     int pltype;      //payload type负载类型  
  4.     char plname[32]; //payload name负载名称,32个字符表示  
  5.     int plfreq;      //payload frequence负载频率  
  6.     int pacsize;     //packet size包大小  
  7.     int channels;    //声道  
  8.     int rate;        //速率或自适应  
  9. };  

参数详细说明:


1、 pltype范围在1~126之间才是有效值;

        pltype的值是否有效可以通过调用下面ValidPayloadType(int payload_type)方法来判断,在...\src\modules\audio_coding\main\source\acm_codec_database.cc定义

[cpp] view plain copy
  1. // Checks if the payload type is in the valid range.  
  2. bool ACMCodecDB::ValidPayloadType(int payload_type) {  
  3.   if ((payload_type < 0) || (payload_type > 127)) {  
  4.     return false;  
  5.   }  
  6.   return true;  
  7. }  


2、 plname是编解码器的名称,可能的值在CreateCodecInstance已定义,如WebRTC默认的"ISAC"

        VoiceEngine支持多个音频编解码器,具体支持的编解码器在CreateCodecInstance(const CodecInst* codec_inst)定义,比如ISAC\PCMU\PCMA\ILBC\AMR等等,在...\src\modules\audio_coding\main\source\acm_codec_database.cc定义


[cpp] view plain copy
  1. ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst* codec_inst) {  
  2.   // All we have support for right now.  
  3.   if (!STR_CASE_CMP(codec_inst->plname, "ISAC")) {  
  4. #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))  
  5.     return new ACMISAC(kISAC);  
  6. #endif  
  7.   } else if (!STR_CASE_CMP(codec_inst->plname, "PCMU")) {  
  8.     return new ACMPCMU(kPCMU);  
  9.   } else if (!STR_CASE_CMP(codec_inst->plname, "PCMA")) {  
  10.     return new ACMPCMA(kPCMA);  
  11.   } else if (!STR_CASE_CMP(codec_inst->plname, "ILBC")) {  
  12. #ifdef WEBRTC_CODEC_ILBC  
  13.     return new ACMILBC(kILBC);  
  14. #endif  
  15.   } else if (!STR_CASE_CMP(codec_inst->plname, "AMR")) {  
  16. #ifdef WEBRTC_CODEC_AMR  
  17.     return new ACMAMR(kGSMAMR);  
  18. #endif  
  19.   } else if (!STR_CASE_CMP(codec_inst->plname, "AMR-WB")) {  
  20. #ifdef WEBRTC_CODEC_AMRWB  
  21.     return new ACMAMRwb(kGSMAMRWB);  
  22. #endif  
  23.   } else if (!STR_CASE_CMP(codec_inst->plname, "G722")) {  
  24. #ifdef WEBRTC_CODEC_G722  
  25.     return new ACMG722(kG722);  
  26. #endif  
  27.   } else if (!STR_CASE_CMP(codec_inst->plname, "G7221")) {  
  28.     switch (codec_inst->plfreq) {  
  29.       case 16000: {  
  30. #ifdef WEBRTC_CODEC_G722_1  
  31.         int codec_id;  
  32.         switch (codec_inst->rate) {  
  33.           case 16000 : {  
  34.             codec_id = kG722_1_16;  
  35.             break;  
  36.           }  
  37.           case 24000 : {  
  38.             codec_id = kG722_1_24;  
  39.             break;  
  40.           }  
  41.           case 32000 : {  
  42.             codec_id = kG722_1_32;  
  43.             break;  
  44.           }  
  45.           default: {  
  46.             return NULL;  
  47.           }  
  48.           return new ACMG722_1(codec_id);  
  49.         }  
  50. #endif  
  51.       }  
  52.       case 32000: {  
  53. #ifdef WEBRTC_CODEC_G722_1C  
  54.         int codec_id;  
  55.         switch (codec_inst->rate) {  
  56.           case 24000 : {  
  57.             codec_id = kG722_1C_24;  
  58.             break;  
  59.           }  
  60.           case 32000 : {  
  61.             codec_id = kG722_1C_32;  
  62.             break;  
  63.           }  
  64.           case 48000 : {  
  65.             codec_id = kG722_1C_48;  
  66.             break;  
  67.           }  
  68.           default: {  
  69.             return NULL;  
  70.           }  
  71.           return new ACMG722_1C(codec_id);  
  72.         }  
  73. #endif  
  74.       }  
  75.     }  
  76.   } else if (!STR_CASE_CMP(codec_inst->plname, "CN")) {  
  77.     // For CN we need to check sampling frequency to know what codec to create.  
  78.     int codec_id;  
  79.     switch (codec_inst->plfreq) {  
  80.       case 8000: {  
  81.         codec_id = kCNNB;  
  82.         break;  
  83.       }  
  84.       case 16000: {  
  85.         codec_id = kCNWB;  
  86.         break;  
  87.       }  
  88.       case 32000: {  
  89.         codec_id = kCNSWB;  
  90.         break;  
  91.       }  
  92.       default: {  
  93.         return NULL;  
  94.       }  
  95.     }  
  96.     return new ACMCNG(codec_id);  
  97.   } else if (!STR_CASE_CMP(codec_inst->plname, "G729")) {  
  98. #ifdef WEBRTC_CODEC_G729  
  99.     return new ACMG729(kG729);  
  100. #endif  
  101.   } else if (!STR_CASE_CMP(codec_inst->plname, "G7291")) {  
  102. #ifdef WEBRTC_CODEC_G729_1  
  103.     return new ACMG729_1(kG729_1);  
  104. #endif  
  105.   } else if (!STR_CASE_CMP(codec_inst->plname, "speex")) {  
  106. #ifdef WEBRTC_CODEC_SPEEX  
  107.     int codec_id;  
  108.     switch (codec_inst->plfreq) {  
  109.       case 8000: {  
  110.         codec_id = kSPEEX8;  
  111.         break;  
  112.       }  
  113.       case 16000: {  
  114.         codec_id = kSPEEX16;  
  115.         break;  
  116.       }  
  117.       default: {  
  118.         return NULL;  
  119.       }  
  120.     }  
  121.     return new ACMSPEEX(codec_id);  
  122. #endif  
  123.   } else if (!STR_CASE_CMP(codec_inst->plname, "CN")) {  
  124.     // For CN we need to check sampling frequency to know what codec to create.  
  125.     int codec_id;  
  126.     switch (codec_inst->plfreq) {  
  127.       case 8000: {  
  128.         codec_id = kCNNB;  
  129.         break;  
  130.       }  
  131.       case 16000: {  
  132.         codec_id = kCNWB;  
  133.         break;  
  134.       }  
  135.       case 32000: {  
  136.         codec_id = kCNSWB;  
  137.         break;  
  138.       }  
  139.       default: {  
  140.         return NULL;  
  141.       }  
  142.     }  
  143.     return new ACMCNG(codec_id);  
  144.   } else if (!STR_CASE_CMP(codec_inst->plname, "L16")) {  
  145. #ifdef WEBRTC_CODEC_PCM16  
  146.     // For L16 we need to check sampling frequency to know what codec to create.  
  147.     int codec_id;  
  148.     switch (codec_inst->plfreq) {  
  149.       case 8000: {  
  150.         codec_id = kPCM16B;  
  151.         break;  
  152.       }  
  153.       case 16000: {  
  154.         codec_id =kPCM16Bwb;  
  155.         break;  
  156.       }  
  157.       case 32000: {  
  158.         codec_id = kPCM16Bswb32kHz;  
  159.         break;  
  160.       }  
  161.       default: {  
  162.         return NULL;  
  163.       }  
  164.     }  
  165.     return new ACMPCM16B(codec_id);  
  166. #endif  
  167.   } else if (!STR_CASE_CMP(codec_inst->plname, "telephone-event")) {  
  168. #ifdef WEBRTC_CODEC_AVT  
  169.     return new ACMDTMFPlayout(kAVT);  
  170. #endif  
  171.   } else if (!STR_CASE_CMP(codec_inst->plname, "red")) {  
  172. #ifdef WEBRTC_CODEC_RED  
  173.     return new ACMRED(kRED);  
  174. #endif  
  175.   }  
  176.   return NULL;  
  177. }  



3、 plfreq一般取如下值(在common_types.h定义);

[cpp] view plain copy
  1. //负载频率值  
  2. enum PayloadFrequencies  
  3. {  
  4.     kFreq8000Hz  = 8000,  
  5.     kFreq16000Hz = 16000,  
  6.     kFreq32000Hz = 32000  
  7. };  

4、 pacsize取值是与plfreq有关系的,单位为kbps,下面是计算公式

计算公式如下:

         如果:plfreq = 16000(单位为hz)

         如果我需要30ms(毫秒)的packet size

         那么pacsize = (plfreq *30) /1000 = 480kbps;

也即是:要得到k ms的packet size,则可计算出

                 pacsize =( plfreq * k) / 1000

而如果plfreq = 32000;20ms的packet size,则pacsize  = 640;


5、 channels取值

        channels = 1 表示单声道

        channels = 2 表示立体声道

        注意:channels  = -1时,表示此时只支持单声道模式


6、 rate取值,单位是bps

        一般取rate = 16000,32000,48000这些16000整数倍的值,即16kbps,32kbps,48kpbs

        注意:当rate = -1时,表示此时启动自适应信道速率


2、查看VoiceEngine支持的所有Codec信息示例代码

[cpp] view plain copy
  1. //列出(获得)引擎支持的所有编解码器信息  
  2. //支持平台:Windows, Mac OS X, Linux  
  3.   
  4. #include "voe_base.h"  
  5. #include "voe_codec.h"  
  6.   
  7. VoiceEngine* ve = VoiceEngine::Create();  
  8. VoECodec* codec = VoECodec::GetInterface(ve);  
  9.   
  10. for (int = 0; i < codec->NumOfCodecs(); i++)  
  11.   
  12. {  
  13.   
  14.    CodecInst cinst;  
  15.   
  16.    codec->GetCodec(i, cinst);  
  17.   
  18.    DISPLAY_CODEC_INFO(i, cinst);  
  19.   
  20. }  
  21.   
  22.   // 释放sub-API  
  23.   codec->Release();  
  24.   
  25.   //删除引擎  
  26.   VoiceEngine::Delete(ve);  

3、初始化VoiceEngine Codec示例代码

[cpp] view plain copy
  1. //初始化VoiceEngine Codec示例代码  
  2. //支持平台:Windows, Mac OS X, Linux  
  3.   
  4. #include "voe_codec.h"  
  5.   
  6. CodecInst cinst;  
  7.   
  8. //初始化iSAC编解码器参数  
  9. strcpy(cinst.plname, "ISAC");  
  10.   
  11. cinst.plfreq   = 16000; // iSAC宽带模式取样频率  
  12. cinst.pltype   = 103;   
  13. cinst.pacsize  = 480;   //使用30ms packet size,480kbps  
  14. cinst.channels = 1;     // 单声道  
  15. cinst.rate     = -1;    // 信道自适应模式  
  16. //初始化完成  
  17.   
  18. //在ID为0的channel激活已初始化的iSAC  
  19. codec->SetSendCodec(0, cinst);  


WebRTC由语音引擎,视频引擎和网络传输三大模块组成,其中语音引擎是WebRTC中最具价值的技术之一。


WebRTC语音引擎由一系列音频和网络处理模块组成,包括了从音频采集到网络传输等处理流程的完整解决方案。


语音引擎工作流程图

语音引擎的一般工作流程如下:

1.发起端进行声音采集

2.采集到的声音信号进行回声消除,噪音抑制,自动增益控制处理

3.语音压缩编码

4.通过Internet网路传输到接收端

5.到达接收端,先进入NetEQ模块进行抖动消除,丢包隐藏解码等操作

6.将处理过后的音频数据送入声卡设备进行播放

webRTC将音频会话抽象为一个通道Channel,譬如A与B进行音频通话,则A需要建立一个Channel与B进行音频数据传输。上图中有三个Channel,每个Channel包含编解码和RTP/RTCP发送功能。

以一个Channel而言,应用程序中将包含三个活动线程,录音线程,音频接收线程和播放线程。

1)录音线程:负责麦克风音频的采集,见图中红色路径,采集到音频后,缓存到一定长度,进行音频处理,主要包括EC,AGC和NS等。然后送到Channel,经过音频

Codec模块编码,封装成RTP包,通过Socket发送出去;

2)接收线程:见蓝色路径,负责接收远端发送过来的音频包,解封RTP包,解码音频数据,送入NetEQ模块缓存。

3)播放线程:负责耳机声音播放,见绿色路径。播放线程去OutMixer中获取要播放的音频数据,首先依次获取参与会话的Channel中NetEQ存储的音频帧,可以对其做AGC和NS处理;然后混合多个Channel的音频信号,得到混合音频,传递给AudioProcessing模块进行远端分析。最后播放出来。

如下为本地回环录音和播放代码

VoiceEngine* ve = VoiceEngine::Create();
VoEBase* base = VoEBase::GetInterface(ve);
base->Init();
int chId = base->CreateChannel();
base->SetSendDestination(chId,3000,"127.0.0.1",4000);
base->SetLocalReceiver(chId,3000,3001,"127.0.0.1");
base->StartPlayout(chId);
base->StartReceive(chId);
base->StartSend(chId);

        //....sleep...wait.....

base->StopSend(chId);

base->StopReveive(chId);

base->StopPlayout(chId);

base->Terminate();

本文介绍WebRTC音频模块组成和结构,详细介绍音频引擎的配置和启动,相信看完本文后,很多人可以利用WebRTC完成一个音频通话程序开发。

一、对外接口

      音频部分的对外主要接口如下,各个接口之间的关系如图1所示。

1)VoiceEngine:负责引擎的所有接口查询,存储共享数据信息ShareData。

2)VoEBase:负责音频处理的基本操作。

3)VoEAudioProcessing:音频信号处理接口,设置各个音频处理项的参数。

4)VoECodec:音频编解码接口,提供支持的编解码器查询,音频编解码设置。

5)VoEHardware:音频硬件设备接口,负责音频硬件设备的设置。

         其它的接口还有VoENetEqStats, VoENetwork, VoERTP_RTCP, VoEVideoSync, VoEVolumeControl, VoEFile, VoECallReport, VoEDtmf, VoEMeidaProcess 和VoEEncryption。

         WebRTC使用继承实现接口转换和查询,接口之间的数据共享是通过ShareData完成,首先VoiceEngineImpl继承各个对外接口的实 现,所以可以从VoiceEngineImpl很容易获取其他对外接口。而VoiceEngineImpl本身也继承ShareData,当从 VoiceEngineImpl获取其他对外接口的同时,隐式的传递了ShareData指针,因此各个接口可以很方便的获取到ShareData的数据 信息。因此虽然类与类之间的关系看起来比较混乱,但是使用上比较方便。

         利用VoiceEngine获取对外接口:VoEInterfaceXX* pInterf = VoEInterfaceXX:GetInterface(pVoiceEngine);

二、模块组成

主要由五大模块组成:AudioDeviceModule音频设备模块,AudioProcess音频处理模块,AudioCodingModule音频编码模块,AudioConferenceMixer混音模块和RtpRtcp传输模块。

         ShareData用于粘合各个模块之间的关系,负责管理全局的对象,包括AudioDeviceModule,TransmitMixer,OutputMixer,ChannelManager和AudioProcess。

         录音流程:AudioDeviceWinCore负责采集音频数据,传递到AudioDeviceBuffer中缓 存,AudioDeviceBuffer则将数据送入TransmixMixer,首先交给AudioProcess进行近端音频处理,完成后分发到各个 Channel中,Channel则通过AudioCodingModule进行编码,编码后再交付到RtpRtcp中经由RTPSender发送出去。

         接收流程:RTPReceiver负责接收音频RTP包,接收到RTP包后交给Channel,Channel转交给AudioCodingModule中的ACMNetEQ模块,进行解码缓存。

         播放流程:Channel从ACMNetEQ模块中取出缓存的解码音频数据,如果需要进行远端数据处理的话,传递给AudioProcess处理。最后 所有Channel都汇入到OutputMixer中进行混音,混音后再传递到AudioProcess进行远端音频分析。最后送入 AudioDeviceModule中的AudioDevceWinCore播放。

三、配置

1、音频引擎创建与删除

         VoiceEngine*pVoeEngine = VoiceEngine::Create();

         VoiceEngine::Delete(pVoeEngine);

2、音频收发

1)音频通话链路创建

         WebRTC中的Channel,为一路音频。作为网络语音通信,至少要创建一路音频Channel。

        Channel没有提供对外接口,是有VoEBase来管理的,通过索引号来选定对应的Channel。

         VoEBase*base = VoEBase::GetInterface(pVoeEngine);

         int ch0 =base->CreateChannel();

2)网络端口设置

         音频通过RTP和RTCP发送出去,RTP和RTCP使用UDP实现,需要配置网络端口和地址。

         //设置发送给.2机器的3000端口

         base->SetSendDestination(ch0,3000,”192.168.8.2”);

        //在本机的3000端口接收RTP包

        base->SetLocalReceiver(ch0,3000);

3)音频编码选择

         VoECodec负责编解码的配置。

         VoECodec*codec = VoEBase::GetInterface(pVoeEngine);

         设置Channel的编码类型之前,要查询支持的编码列表。

         CodecInstinst;

         Intnum = codec->NumOfCodecs();

         for(int i=0; i<num; ++i)

        {

              Codec->GetCodec(I,inst);

             //打印编码信息

        }

       //设置编码0

       Codec->GetCodec(0,inst);

       Codec->SetSendCodec(ch0,inst);

       WebRTC自动识别编码类型,因此解码不需要设置。

4)启动

         启动播放:base->StartPlayout(ch0);该操作含义是将通话ch0进行混音输出。

         启动接收:base->StartReceive(ch0);开始接收后,每增加一路通话,引擎会将音频进行混音再输出。

         启动发送:base->StartSend(ch0);启动发送的时候,会检查是否正在录音,如果已经开启录音,则不再开启;否则会执行音频设备录音操作。

3、音频处理的配置

         VoEAudioProcessing负责音频处理的配置。

         VoEAudioProcessing*pAudioProc = VoEAudioProcessing::GetInterface(pVoeEngine);

         //启动AGC功能

         pAudioProc->SetAgcStatus(true);

4、音频设备的配置

         VoEHardware接口可以查看录音和播放设备,可以选择指定的设备进行音频通话。

         VoEHardware*pHardware=VoEAudioProcessing::GetInterface(pVoeEngine);

         Int numin =pHardware->GetNumOfRecordingDevices();

         For(int i=0;i<numin; ++i)

        {

             pHardware->GetRecordingDeviceNames(…)

             //打印录音设备

        }

       //选择设备0作为录音设备

       pHardware->SetRecordingDevice(0);

      播放设备配置类似。






NetEQ模块是Webrtc语音引擎中的核心模块


NetEQ模块框图

从上图看,NetEQ模块基本上分为:自适应缓冲器(Adaptive Packet Buffer),语音解码器(SpeechDecoder),抖动控制和丢包隐藏(Jitter Control and Error Concealment) 以及播放(PlayOut)四大部分。其中抖动控制和丢包隐藏模块是NetEQ的核心算法,既控制着自适应缓冲器,又与解码器进行紧密的交互,并且将最终的计算结果交给声卡去播放。


WebRTC的语音引擎在运行时会启动两个线程:一个线程用于接收来自于网络的数据包,并将其插入到抖动缓冲区中;另外一个线程每隔10ms从NetEQ中提取10ms语音数据进行播放。

网络数据包进入抖动缓冲区的过程在:

 


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

提取10ms语音数据到声卡的过程在:
int32_t ACMNetEQ::RecOut(AudioFrame& audio_frame) 



其他参考资料如下

WebRTC代码结构:


http://blog.sina.com.cn/s/blog_40d608bb01010n73.html
http://www.cnblogs.com/fangkm/p/4370492.html
http://mojiapp.cn/a/yuanmashili/2015/0708/542.html
http://max.book118.com/html/2015/1228/32140782.shtm
https://www.slideshare.net/libfetion/webrtc
https://chromium.googlesource.com/external/webrtc/+/master
https://source.codeaurora.org/quic/lc/external/webrtc/tree/webrtc?h=chromium.org/master


webrtc之视频捕获模块--video_capture:


http://www.cnblogs.com/qazwsxwtc/p/5415416.html
http://www.cnblogs.com/fangkm/p/4374610.html
http://www.cnblogs.com/fangkm/p/4374668.html
http://befo.io/4644.html
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=video_capture
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+video_capture&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


webrtc之视频显示模块--video_render:


http://www.cnblogs.com/qazwsxwtc/p/5415419.html
http://m.blog.csdn.net/article/details?id=52267164
WebRTC视频流渲染中插入图片帧:http://www.jianshu.com/p/c126c4831e8b
Android WebRTC视频旋转问题:http://www.mamicode.com/info-detail-1112555.html
commits: 
https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=video_render
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+video_render&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


视频编解码---video_coding


http://www.cnblogs.com/fangkm/p/4401143.html
http://www.aichengxu.com/data/2493554.htm
https://tools.ietf.org/html/draft-garcia-simulcast-and-layered-video-webrtc-00
https://codereview.webrtc.org/2007553003
https://groups.google.com/forum/#!searchin/discuss-webrtc/video_coding%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=video_coding
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+video_coding&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


视频加密--video_engine_encryption


http://www.voidcn.com/blog/bamboolsu/article/p-3481712.html
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=video_engine_encryption
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+video_engine_encryption&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


视频媒体文件--media_file


http://stackoverflow.com/questions/17469367/stream-media-file-using-webrtc
https://groups.google.com/forum/#!searchin/discuss-webrtc/media_file%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=media_file
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+media_file&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


视频图像处理--video_processing


https://codereview.webrtc.org/2595543002
https://tools.ietf.org/html/draft-ietf-rtcweb-video-04
https://groups.google.com/forum/#!searchin/discuss-webrtc/video_processing%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=video_processing
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=video_processing&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


音频设备---audio_device


https://groups.google.com/forum/#!searchin/discuss-webrtc/audio_device%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=audio_device
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=audio_device&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


音频编解码---audio_coding


https://groups.google.com/forum/#!searchin/discuss-webrtc/audio_coding%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=audio_coding
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+audio_coding&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


声音加密--voice_engine_encryption


commits: 
https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=voice_engine_encryption
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+voice_engine_encryption&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


声音文件--media_file


http://stackoverflow.com/questions/17469367/stream-media-file-using-webrtc
https://groups.google.com/forum/#!searchin/discuss-webrtc/media_file%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=media_file
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+media_file&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


声音处理--audio_processing


https://www.freedesktop.org/software/pulseaudio/webrtc-audio-processing/

编译webrtc到pjsip中的方法
http://www.07net01.com/program/2016/01/1153506.html

WebRTC Audio Processing Module (APM) and calculating echo delay for a playback device

http://stackoverflow.com/questions/31163306/webrtc-audio-processing-module-apm-and-calculating-echo-delay-for-a-playback-d
https://arunraghavan.net/2015/10/psa-breaking-webrtc-audio-processing-api/
http://packages.ubuntu.com/source/trusty/webrtc-audio-processing
http://linuxsoft.cern.ch/cern/centos/7/updates/x86_64/repoview/webrtc-audio-processing.html
https://groups.google.com/forum/#!searchin/discuss-webrtc/audio_processing%7Csort:relevance
commits: https://source.codeaurora.org/quic/lc/external/webrtc/log/?h=chromium.org%2Fmaster&qt=grep&q=audio_processing
bugs: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=webrtc+audio_processing&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids


0 0
原创粉丝点击