WebRTC音視頻引擎研究(2)--VoiceEngine音頻編解碼器數據結構以及參數設置

WebRTC技術交流羣:234795279


1、VoiceEngine Codec數據結構

       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時,表示此時啓動自適應信道速率


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

//列出(獲得)引擎支持的所有編解碼器信息
//支持平臺: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);

3、初始化VoiceEngine Codec示例代碼

//初始化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);


歡迎指出不對之處:[email protected]

/==================================================================================================================/
    Author: zengxijin    [email protected]     歡迎轉載,請註明出處
/==================================================================================================================/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章