WebRTC音视频引擎研究(2)--VoiceEngine音频编解码器数据结构以及参数设置

时间:2021-02-08 16:57:19

1、VoiceEngine Codec数据结构

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

  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定义

  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定义

  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定义);

  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信息示例代码

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

3、初始化VoiceEngine Codec示例代码

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