webrtc的历史比较简单如下:
2010年Google以6820万美元收购VoIP软件开发商Global IP Solutions的GIPS引擎[4][5][6][7],并改为名为“WebRTC”。WebRTC 使用GIPS引擎,实现了基于网页的视频会议,并支持722,PCM,ILBC,ISAC等编码,同时使用谷歌自家的VP8视频编解码;同时支持RTP/SRTP传输等。
2012年谷歌已经把这款软件集成到Chrome浏览器中。同时 FreeSWITCH 项目宣称[8]支持 iSAC audio codec
WEBRTC工程吸引人的地方只要一下几方面:
(1)杰出出的音频处理算法,这给许多做语音处理、压缩相关的人员提供许多便利的地方。
(2)完整的音视频解决方案,提供AE/VE完整的实现方案,稍微改变一下就可以应用在视频监控、P2P或者视频会议中,以及实现跨平台性。目前WEBRTC支持WINDOWS/MAX/LINUX/IOS/ANDROID。
(3)WEBRTC已经成为一项标准,将来会在chrome/firefox中使用,可以实现无插件化的音视频用用,这点事一个突破型的应用。
webrtc的工程需要使用GOOGLE自己的一套工具进行下载和配置,生成相应的工程。这个比较简单网上资料比较多,不多做介绍。
webrtc在win平台下默认生成的都是静态库,这里简单的DEMO的代码贴一下:
// setup video engine
char cCameraName[MAX_CAMERA_NAME_LENGTH];
memset(cCameraName, 0 , MAX_CAMERA_NAME_LENGTH);
int iRet = RET_SUCCESS;
CaptureCapability stCurSelectCapbility;
char cCameraID[MAX_CAMERA_ID_LENGTH];
memset(cCameraID, 0 , MAX_CAMERA_ID_LENGTH);
int iCapdeviceCount = 0;
iCapdeviceCount = m_VieCapture->NumberOfCaptureDevices();
ASSERT(iCapdeviceCount > 0);
for(int i = 0; i < iCapdeviceCount; i++)
{
iRet = m_VieCapture->GetCaptureDevice(i, cCameraName, MAX_CAMERA_NAME_LENGTH, cCameraID, MAX_CAMERA_ID_LENGTH);
ASSERT(iRet == RET_SUCCESS);
int iCapbilityCount = 0;
iCapbilityCount = m_VieCapture->NumberOfCapabilities(cCameraID, MAX_CAMERA_ID_LENGTH);
ASSERT(iCapbilityCount > 0);
iRet = m_VieCapture->GetCaptureCapability(cCameraID, MAX_CAMERA_ID_LENGTH, iCapbilityCount - 1, stCurSelectCapbility);
ASSERT(iRet == RET_SUCCESS);
}
int iCaptureId;
iRet = m_VieCapture->AllocateCaptureDevice(cCameraID, MAX_CAMERA_ID_LENGTH, iCaptureId);
ASSERT(iRet == RET_SUCCESS);
iRet = ViECreateWindow(m_CapRenderHwnd, 500,200, 500, 500,_T("Local Render"));
ASSERT(iRet == RET_SUCCESS);
iRet = ViECreateWindow(m_DecRenderHwnd, 500, 700, 500,500, _T("Remote Render"));
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRender->AddRenderer(iCaptureId,(void*)m_CapRenderHwnd, 0, 0.0,0.0,1.0,1.0);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieCapture->StartCapture(iCaptureId, stCurSelectCapbility);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRender->StartRender(iCaptureId);
VideoCodec videoCodec;
int numOfVieCodecs = m_VieCodec->NumberOfCodecs();
bool bFindVideoCode = false;
ASSERT(numOfVieCodecs > 0);
for(int i=0; i<numOfVieCodecs;++i)
{
if(m_VieCodec->GetCodec(i,videoCodec)!=-1)
{
if(videoCodec.codecType == kVideoCodecVP8)
{
bFindVideoCode = true;
break;
}
}
}
ASSERT(bFindVideoCode);
iRet = m_VieBase->CreateChannel(m_ChannelId);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRender->AddRenderer(m_ChannelId,(void*)m_DecRenderHwnd, 0, 0.0,0.0,1.0,1.0);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRender->StartRender(m_ChannelId);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieCodec->SetSendCodec(m_ChannelId, videoCodec);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieCodec->SetReceiveCodec(m_ChannelId, videoCodec);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieCapture->ConnectCaptureDevice(iCaptureId, m_ChannelId);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRTP_RTCP->SetRTCPStatus(m_ChannelId, webrtc::kRtcpCompound_RFC4585);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRTP_RTCP->SetKeyFrameRequestMethod(m_ChannelId, webrtc::kViEKeyFrameRequestPliRtcp);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieRTP_RTCP->SetTMMBRStatus(m_ChannelId, true);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieNetwork->SetSendDestination(m_ChannelId, "127.0.0.1", 11111, 11112);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieNetwork->SetLocalReceiver(m_ChannelId, 11111, 11112, "127.0.0.1");
iRet = m_VieBase->StartSend(m_ChannelId);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VieBase->StartReceive(m_ChannelId);
ASSERT(iRet == RET_SUCCESS);
//setup voice engine
CodecInst voiceCodec;
int numOfVoeCodecs = m_VoeCodec->NumOfCodecs();
bool bFindAudioCode = false;
for(int i=0; i<numOfVoeCodecs;++i)
{
if(m_VoeCodec->GetCodec(i,voiceCodec)!=-1)
{
if(strncmp(voiceCodec.plname,"ISAC",4)==0)
{
bFindAudioCode = true;
break;
}
}
}
ASSERT(bFindAudioCode);
// define iSAC codec parameters
strcpy(voiceCodec.plname, "ISAC");
voiceCodec.plfreq = 16000; // iSAC宽带模式
voiceCodec.pltype = 103; // 默认动态负载类型
voiceCodec.pacsize = 480; // 480kbps,即使用30ms的packet size
voiceCodec.channels = 1; // 单声道
voiceCodec.rate = -1; // 信道自适应模式,单位bps
int iMaxAEChannelNum = m_VoeBase->MaxNumOfChannels();
m_AudioChannel = m_VoeBase->CreateChannel();
ASSERT((m_AudioChannel < iMaxAEChannelNum) && (m_AudioChannel >= 0));
iRet = m_VoeCodec->SetSendCodec(m_AudioChannel, voiceCodec);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeRTCP->SetRTCPStatus(m_AudioChannel, true);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeNetwork->SetSourceFilter(m_AudioChannel, 11113, 11114, "127.0.0.1");
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeBase->SetSendDestination(m_AudioChannel, 11113, "127.0.0.1", -1, 11114);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeBase->SetLocalReceiver(m_AudioChannel, 11113, 11114, "127.0.0.1");
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeBase->StartPlayout(m_AudioChannel);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeBase->StartReceive(m_AudioChannel);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeBase->StartSend(m_AudioChannel);
ASSERT(iRet == RET_SUCCESS);
NsModes mode(kNsDefault);//
iRet = m_VoeApmPtr->SetRxNsStatus(m_AudioChannel, true, mode);
ASSERT(iRet == RET_SUCCESS);
AgcModes agcmode(kAgcDefault);
iRet = m_VoeApmPtr->SetRxAgcStatus(m_AudioChannel, true, agcmode);
ASSERT(iRet == RET_SUCCESS);
iRet = m_VoeApmPtr->SetEcStatus(true, kEcAec);
ASSERT(iRet == RET_SUCCESS);