WebRTC技术交流群:234795279
WebRTC中,用一个结构体struct CodecInst表示特定的音频编解码器对象:
struct CodecInst { int pltype; //payload type负载类型 char plname[32]; //payload name负载名称,32个字符表示 int plfreq; //payload frequence负载频率 int pacsize; //packet size包大小 int channels; //声道 int rate; //速率或自适应 };
1、 pltype范围在1~126之间才是有效值;
pltype的值是否有效可以通过调用下面ValidPayloadType(int payload_type)方法来判断,在...\src\modules\audio_coding\main\source\acm_codec_database.cc定义
// Checks if the payload type is in the valid range. bool ACMCodecDB::ValidPayloadType(int payload_type) { if ((payload_type < 0) || (payload_type > 127)) { return false; } return true; }
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定义
ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst* codec_inst) { // All we have support for right now. if (!STR_CASE_CMP(codec_inst->plname, "ISAC")) { #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) return new ACMISAC(kISAC); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "PCMU")) { return new ACMPCMU(kPCMU); } else if (!STR_CASE_CMP(codec_inst->plname, "PCMA")) { return new ACMPCMA(kPCMA); } else if (!STR_CASE_CMP(codec_inst->plname, "ILBC")) { #ifdef WEBRTC_CODEC_ILBC return new ACMILBC(kILBC); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "AMR")) { #ifdef WEBRTC_CODEC_AMR return new ACMAMR(kGSMAMR); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "AMR-WB")) { #ifdef WEBRTC_CODEC_AMRWB return new ACMAMRwb(kGSMAMRWB); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "G722")) { #ifdef WEBRTC_CODEC_G722 return new ACMG722(kG722); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "G7221")) { switch (codec_inst->plfreq) { case 16000: { #ifdef WEBRTC_CODEC_G722_1 int codec_id; switch (codec_inst->rate) { case 16000 : { codec_id = kG722_1_16; break; } case 24000 : { codec_id = kG722_1_24; break; } case 32000 : { codec_id = kG722_1_32; break; } default: { return NULL; } return new ACMG722_1(codec_id); } #endif } case 32000: { #ifdef WEBRTC_CODEC_G722_1C int codec_id; switch (codec_inst->rate) { case 24000 : { codec_id = kG722_1C_24; break; } case 32000 : { codec_id = kG722_1C_32; break; } case 48000 : { codec_id = kG722_1C_48; break; } default: { return NULL; } return new ACMG722_1C(codec_id); } #endif } } } else if (!STR_CASE_CMP(codec_inst->plname, "CN")) { // For CN we need to check sampling frequency to know what codec to create. int codec_id; switch (codec_inst->plfreq) { case 8000: { codec_id = kCNNB; break; } case 16000: { codec_id = kCNWB; break; } case 32000: { codec_id = kCNSWB; break; } default: { return NULL; } } return new ACMCNG(codec_id); } else if (!STR_CASE_CMP(codec_inst->plname, "G729")) { #ifdef WEBRTC_CODEC_G729 return new ACMG729(kG729); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "G7291")) { #ifdef WEBRTC_CODEC_G729_1 return new ACMG729_1(kG729_1); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "speex")) { #ifdef WEBRTC_CODEC_SPEEX int codec_id; switch (codec_inst->plfreq) { case 8000: { codec_id = kSPEEX8; break; } case 16000: { codec_id = kSPEEX16; break; } default: { return NULL; } } return new ACMSPEEX(codec_id); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "CN")) { // For CN we need to check sampling frequency to know what codec to create. int codec_id; switch (codec_inst->plfreq) { case 8000: { codec_id = kCNNB; break; } case 16000: { codec_id = kCNWB; break; } case 32000: { codec_id = kCNSWB; break; } default: { return NULL; } } return new ACMCNG(codec_id); } else if (!STR_CASE_CMP(codec_inst->plname, "L16")) { #ifdef WEBRTC_CODEC_PCM16 // For L16 we need to check sampling frequency to know what codec to create. int codec_id; switch (codec_inst->plfreq) { case 8000: { codec_id = kPCM16B; break; } case 16000: { codec_id =kPCM16Bwb; break; } case 32000: { codec_id = kPCM16Bswb32kHz; break; } default: { return NULL; } } return new ACMPCM16B(codec_id); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "telephone-event")) { #ifdef WEBRTC_CODEC_AVT return new ACMDTMFPlayout(kAVT); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "red")) { #ifdef WEBRTC_CODEC_RED return new ACMRED(kRED); #endif } return NULL; }
3、 plfreq一般取如下值(在common_types.h定义);
//负载频率值 enum PayloadFrequencies { kFreq8000Hz = 8000, kFreq16000Hz = 16000, kFreq32000Hz = 32000 };
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时,表示此时启动自适应信道速率
//列出(获得)引擎支持的所有编解码器信息 //支持平台:Windows, Mac OS X, Linux #include "voe_base.h" #include "voe_codec.h" VoiceEngine* ve = VoiceEngine::Create(); VoECodec* codec = VoECodec::GetInterface(ve); for (int = 0; i < codec->NumOfCodecs(); i++) { CodecInst cinst; codec->GetCodec(i, cinst); DISPLAY_CODEC_INFO(i, cinst); } // 释放sub-API codec->Release(); //删除引擎 VoiceEngine::Delete(ve);
//初始化VoiceEngine Codec示例代码 //支持平台:Windows, Mac OS X, Linux #include "voe_codec.h" CodecInst cinst; //初始化iSAC编解码器参数 strcpy(cinst.plname, "ISAC"); cinst.plfreq = 16000; // iSAC宽带模式取样频率 cinst.pltype = 103; cinst.pacsize = 480; //使用30ms packet size,480kbps cinst.channels = 1; // 单声道 cinst.rate = -1; // 信道自适应模式 //初始化完成 //在ID为0的channel激活已初始化的iSAC codec->SetSendCodec(0, cinst);