WebRTC VoiceEngine综合应用示例(二)——音频通话的基本流程

下面将以实现一个音频通话功能为示例详细介绍VoiceEngine的使用,在文末将附上相应源码的下载地址。这里参考的是voiceengine\voe_cmd_test。

第一步是创建VoiceEngine和相关的sub-apis

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2.     // Create VoiceEngine related instance  
  3.     //  
  4.     webrtc::VoiceEngine* ptrVoE = NULL;  
  5.     ptrVoE = webrtc::VoiceEngine::Create();  
  6.   
  7.     webrtc::VoEBase* ptrVoEBase = NULL;  
  8.     ptrVoEBase = webrtc::VoEBase::GetInterface(ptrVoE);  
  9.   
  10.     webrtc::VoECodec* ptrVoECodec = NULL;  
  11.     ptrVoECodec = webrtc::VoECodec::GetInterface(ptrVoE);  
  12.   
  13.     webrtc::VoEAudioProcessing* ptrVoEAp = NULL;  
  14.     ptrVoEAp = webrtc::VoEAudioProcessing::GetInterface(ptrVoE);  
  15.   
  16.     webrtc::VoEVolumeControl* ptrVoEVolume = NULL;  
  17.     ptrVoEVolume = webrtc::VoEVolumeControl::GetInterface(ptrVoE);  
  18.   
  19.     webrtc::VoENetwork* ptrVoENetwork = NULL;  
  20.     ptrVoENetwork = webrtc::VoENetwork::GetInterface(ptrVoE);  
  21.   
  22.     webrtc::VoEFile* ptrVoEFile = NULL;  
  23.     ptrVoEFile = webrtc::VoEFile::GetInterface(ptrVoE);  
  24.   
  25.     webrtc::VoEHardware* ptrVoEHardware = NULL;  
  26.     ptrVoEHardware = webrtc::VoEHardware::GetInterface(ptrVoE);  
然后可以选择设置tracefile的路径,这里我们还会对麦克风以及回放的声音做一个录制,所以也一并指明路径。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2.     //Set Trace File and Record File  
  3.     //  
  4.     const std::string trace_filename = "webrtc_trace.txt";  
  5.     VoiceEngine::SetTraceFilter(kTraceAll);  
  6.     error = VoiceEngine::SetTraceFile(trace_filename.c_str());  
  7.     if (error != 0)  
  8.     {  
  9.         printf("ERROR in VoiceEngine::SetTraceFile\n");  
  10.         return error;  
  11.     }  
  12.     error = VoiceEngine::SetTraceCallback(NULL);  
  13.     if (error != 0)  
  14.     {  
  15.         printf("ERROR in VoiceEngine::SetTraceCallback\n");  
  16.         return error;  
  17.     }  
  18.     const std::string play_filename = "recorded_playout.wav";  
  19.     const std::string mic_filename = "recorded_mic.wav";  
接下来是初始化,获取VoiceEngine的版本号

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2.     //Init  
  3.     //  
  4.     error = ptrVoEBase->Init();  
  5.     if (error != 0)  
  6.     {  
  7.         printf("ERROR in VoEBase::Init\n");  
  8.         return error;  
  9.     }  
  10.     error = ptrVoEBase->RegisterVoiceEngineObserver(my_observer);  
  11.     if (error != 0)  
  12.     {  
  13.         printf("ERROR in VoEBase:;RegisterVoiceEngineObserver\n");  
  14.         return error;  
  15.     }  
  16.     printf("Version\n");  
  17.     char tmp[1024];  
  18.     error = ptrVoEBase->GetVersion(tmp);  
  19.     if (error != 0)  
  20.     {  
  21.         printf("ERROR in VoEBase::GetVersion\n");  
  22.         return error;  
  23.     }  
  24.     printf("%s\n", tmp);  
这里同时还注册了一个VoiceEngineObserver对象,可以根据相应的error code输出信息,比如当检测到键盘敲击的噪音时会给出提示。这个类的定义如下

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. class MyObserver : public VoiceEngineObserver {  
  2. public:  
  3.     virtual void CallbackOnError(int channel, int err_code);  
  4. };  
  5.   
  6. void MyObserver::CallbackOnError(int channel, int err_code) {  
  7.     // Add printf for other error codes here  
  8.     if (err_code == VE_TYPING_NOISE_WARNING) {  
  9.         printf("  TYPING NOISE DETECTED \n");  
  10.     }  
  11.     else if (err_code == VE_TYPING_NOISE_OFF_WARNING) {  
  12.         printf("  TYPING NOISE OFF DETECTED \n");  
  13.     }  
  14.     else if (err_code == VE_RECEIVE_PACKET_TIMEOUT) {  
  15.         printf("  RECEIVE PACKET TIMEOUT \n");  
  16.     }  
  17.     else if (err_code == VE_PACKET_RECEIPT_RESTARTED) {  
  18.         printf("  PACKET RECEIPT RESTARTED \n");  
  19.     }  
  20.     else if (err_code == VE_RUNTIME_PLAY_WARNING) {  
  21.         printf("  RUNTIME PLAY WARNING \n");  
  22.     }  
  23.     else if (err_code == VE_RUNTIME_REC_WARNING) {  
  24.         printf("  RUNTIME RECORD WARNING \n");  
  25.     }  
  26.     else if (err_code == VE_SATURATION_WARNING) {  
  27.         printf("  SATURATION WARNING \n");  
  28.     }  
  29.     else if (err_code == VE_RUNTIME_PLAY_ERROR) {  
  30.         printf("  RUNTIME PLAY ERROR \n");  
  31.     }  
  32.     else if (err_code == VE_RUNTIME_REC_ERROR) {  
  33.         printf("  RUNTIME RECORD ERROR \n");  
  34.     }  
  35.     else if (err_code == VE_REC_DEVICE_REMOVED) {  
  36.         printf("  RECORD DEVICE REMOVED \n");  
  37.     }  
  38. }  
以上完成了前期准备的工作,下面首先开始对网络的设置。如果是在本机上进行测试的话,ip地址直接写127.0.0.1即可,同时要注意的是,remote port和local port要一致。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2.     //Network Settings  
  3.     //  
  4.     int audiochannel;  
  5.     audiochannel = ptrVoEBase->CreateChannel();  
  6.     if (audiochannel < 0)  
  7.     {  
  8.         printf("ERROR in VoEBase::CreateChannel\n");  
  9.         return audiochannel;  
  10.     }  
  11.     VoiceChannelTransport* voice_channel_transport = new VoiceChannelTransport(ptrVoENetwork, audiochannel);  
  12.     char ip[64] = "127.0.0.1";  
  13.     int rPort = 800;//remote port  
  14.     int lPort = 800;//local port  
  15.     error = voice_channel_transport->SetSendDestination(ip, rPort);  
  16.     if (error != 0)  
  17.     {  
  18.         printf("ERROR in set send ip and port\n");  
  19.         return error;  
  20.     }  
  21.     error = voice_channel_transport->SetLocalReceiver(lPort);  
  22.     if (error != 0)  
  23.     {  
  24.         printf("ERROR in set receiver and port\n");  
  25.         return error;  
  26.     }  
上面出现的VoiceChannelTransport类的定义如下

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // Helper class for VoiceEngine tests.  
  2. class VoiceChannelTransport : public webrtc::test::UdpTransportData {  
  3. public:  
  4.     VoiceChannelTransport(VoENetwork* voe_network, int channel);  
  5.   
  6.     virtual ~VoiceChannelTransport();  
  7.   
  8.     // Start implementation of UdpTransportData.  
  9.     void IncomingRTPPacket(const int8_t* incoming_rtp_packet,  
  10.         const size_t packet_length,  
  11.         const char/*from_ip*/,  
  12.         const uint16_t /*from_port*/) override;  
  13.   
  14.     void IncomingRTCPPacket(const int8_t* incoming_rtcp_packet,  
  15.         const size_t packet_length,  
  16.         const char/*from_ip*/,  
  17.         const uint16_t /*from_port*/) override;  
  18.     // End implementation of UdpTransportData.  
  19.   
  20.     // Specifies the ports to receive RTP packets on.  
  21.     int SetLocalReceiver(uint16_t rtp_port);  
  22.   
  23.     // Specifies the destination port and IP address for a specified channel.  
  24.     int SetSendDestination(const char* ip_address, uint16_t rtp_port);  
  25.   
  26. private:  
  27.     int channel_;  
  28.     VoENetwork* voe_network_;  
  29.     webrtc::test::UdpTransport* socket_transport_;  
  30. };  
  31.   
  32.   
  33. VoiceChannelTransport::VoiceChannelTransport(VoENetwork* voe_network,  
  34.     int channel)  
  35.     : channel_(channel),  
  36.     voe_network_(voe_network) {  
  37.     uint8_t socket_threads = 1;  
  38.     socket_transport_ = webrtc::test::UdpTransport::Create(channel, socket_threads);  
  39.     int registered = voe_network_->RegisterExternalTransport(channel,  
  40.         *socket_transport_);  
  41. #if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)  
  42.     if (registered != 0)  
  43.         return;  
  44. #else  
  45.     assert(registered == 0);  
  46. #endif  
  47. }  
  48.   
  49. VoiceChannelTransport::~VoiceChannelTransport() {  
  50.     voe_network_->DeRegisterExternalTransport(channel_);  
  51.     webrtc::test::UdpTransport::Destroy(socket_transport_);  
  52. }  
  53.   
  54. void VoiceChannelTransport::IncomingRTPPacket(  
  55.     const int8_t* incoming_rtp_packet,  
  56.     const size_t packet_length,  
  57.     const char/*from_ip*/,  
  58.     const uint16_t /*from_port*/) {  
  59.     voe_network_->ReceivedRTPPacket(  
  60.         channel_, incoming_rtp_packet, packet_length, PacketTime());  
  61. }  
  62.   
  63. void VoiceChannelTransport::IncomingRTCPPacket(  
  64.     const int8_t* incoming_rtcp_packet,  
  65.     const size_t packet_length,  
  66.     const char/*from_ip*/,  
  67.     const uint16_t /*from_port*/) {  
  68.     voe_network_->ReceivedRTCPPacket(channel_, incoming_rtcp_packet,  
  69.         packet_length);  
  70. }  
  71.   
  72. int VoiceChannelTransport::SetLocalReceiver(uint16_t rtp_port) {  
  73.     static const int kNumReceiveSocketBuffers = 500;  
  74.     int return_value = socket_transport_->InitializeReceiveSockets(this,  
  75.         rtp_port);  
  76.     if (return_value == 0) {  
  77.         return socket_transport_->StartReceiving(kNumReceiveSocketBuffers);  
  78.     }  
  79.     return return_value;  
  80. }  
  81.   
  82. int VoiceChannelTransport::SetSendDestination(const char* ip_address,  
  83.     uint16_t rtp_port) {  
  84.     return socket_transport_->InitializeSendSockets(ip_address, rtp_port);  
  85. }  
完成了网络的设置后,进行编解码器的设置。这里简单的由用户选择使用哪一个编码器,当然还可以进一步对编码器的参数进行设置

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2. //Setup Codecs  
  3. //  
  4. CodecInst codec_params;  
  5. CodecInst cinst;  
  6. for (int i = 0; i < ptrVoECodec->NumOfCodecs(); ++i) {  
  7.     int error = ptrVoECodec->GetCodec(i, codec_params);  
  8.     if (error != 0)  
  9.     {  
  10.         printf("ERROR in VoECodec::GetCodec\n");  
  11.         return error;  
  12.     }  
  13.     printf("%2d. %3d  %s/%d/%d \n", i, codec_params.pltype, codec_params.plname,  
  14.         codec_params.plfreq, codec_params.channels);  
  15. }  
  16. printf("Select send codec: ");  
  17. int codec_selection;  
  18. scanf("%i", &codec_selection);  
  19. ptrVoECodec->GetCodec(codec_selection, cinst);  
  20. error = ptrVoECodec->SetSendCodec(audiochannel, cinst);  
  21. if (error != 0)  
  22. {  
  23.     printf("ERROR in VoECodec::SetSendCodec\n");  
  24.     return error;  
  25. }  
接下来进行录制设备和播放设备的设置

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2.     //Setup Devices  
  3.     //  
  4.     int rd(-1), pd(-1);  
  5.     error = ptrVoEHardware->GetNumOfRecordingDevices(rd);  
  6.     if (error != 0)  
  7.     {  
  8.         printf("ERROR in VoEHardware::GetNumOfRecordingDevices\n");  
  9.         return error;  
  10.     }  
  11.     error = ptrVoEHardware->GetNumOfPlayoutDevices(pd);  
  12.     if (error != 0)  
  13.     {  
  14.         printf("ERROR in VoEHardware::GetNumOfPlayoutDevices\n");  
  15.         return error;  
  16.     }  
  17.   
  18.     char dn[128] = { 0 };  
  19.     char guid[128] = { 0 };  
  20.     printf("\nPlayout devices (%d): \n", pd);  
  21.     for (int j = 0; j < pd; ++j) {  
  22.         error = ptrVoEHardware->GetPlayoutDeviceName(j, dn, guid);  
  23.         if (error != 0)  
  24.         {  
  25.             printf("ERROR in VoEHardware::GetPlayoutDeviceName\n");  
  26.             return error;  
  27.         }  
  28.         printf("  %d: %s \n", j, dn);  
  29.     }  
  30.   
  31.     printf("Recording devices (%d): \n", rd);  
  32.     for (int j = 0; j < rd; ++j) {  
  33.         error = ptrVoEHardware->GetRecordingDeviceName(j, dn, guid);  
  34.         if (error != 0)  
  35.         {  
  36.             printf("ERROR in VoEHardware::GetRecordingDeviceName\n");  
  37.             return error;  
  38.         }  
  39.         printf("  %d: %s \n", j, dn);  
  40.     }  
  41.   
  42.     printf("Select playout device: ");  
  43.     scanf("%d", &pd);  
  44.     error = ptrVoEHardware->SetPlayoutDevice(pd);  
  45.     if (error != 0)  
  46.     {  
  47.         printf("ERROR in VoEHardware::SetPlayoutDevice\n");  
  48.         return error;  
  49.     }  
  50.     printf("Select recording device: ");  
  51.     scanf("%d", &rd);  
  52.     getchar();  
  53.     error = ptrVoEHardware->SetRecordingDevice(rd);  
  54.     if (error != 0)  
  55.     {  
  56.         printf("ERROR in VoEHardware::SetRecordingDevice\n");  
  57.         return error;  
  58.     }  
然后对音频预处理功能进行设置,这里作为示例,把各种预处理功能都enable了

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //  
  2.     //Audio Processing  
  3.     //  
  4.     error = ptrVoECodec->SetVADStatus(0, 1);//FIX:why not use audio channel  
  5.     if (error != 0)  
  6.     {  
  7.         printf("ERROR in VoECodec::SetVADStatus\n");  
  8.         return error;  
  9.     }  
  10.     error = ptrVoEAp->SetAgcStatus(1);  
  11.     if (error != 0)  
  12.     {  
  13.         printf("ERROR in VoEAudioProcess::SetAgcStatus\n");  
  14.         return error;  
  15.     }  
  16.     error = ptrVoEAp->SetEcStatus(1);  
  17.     if (error != 0)  
  18.     {  
  19.         printf("ERROR in VoEAudioProcess::SetEcStatus\n");  
  20.         return error;  
  21.     }  
  22.     error = ptrVoEAp->SetNsStatus(1);  
  23.     if (error != 0)  
  24.     {  
  25.         printf("ERROR in VoEAudioProcess::SetNsStatus\n");  
  26.         return error;  
  27.     }  
  28.     error = ptrVoEAp->SetRxAgcStatus(audiochannel, 1);  
  29.     if (error != 0)  
  30.     {  
  31.         printf("ERROR in VoEAudioProcess::SetRxAgcStatus\n");  
  32.         return error;  
  33.     }  
  34.     error = ptrVoEAp->SetRxNsStatus(audiochannel, 1);  
  35.     if (error != 0)  
  36.     {  
  37.         printf("ERROR in VoEAudioProcess::SetRxNsStatus\n");  
  38.         return error;  
  39.     }  
至此,就可以开始发送、接收、录制了

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //Start Receive  
  2.     error = ptrVoEBase->StartReceive(audiochannel);  
  3.     if (error != 0)  
  4.     {  
  5.         printf("ERROR in VoEBase::StartReceive\n");  
  6.         return error;  
  7.     }  
  8.     //Start Playout  
  9.     error = ptrVoEBase->StartPlayout(audiochannel);  
  10.     if (error != 0)  
  11.     {  
  12.         printf("ERROR in VoEBase::StartPlayout\n");  
  13.         return error;  
  14.     }  
  15.     //Start Send  
  16.     error = ptrVoEBase->StartSend(audiochannel);  
  17.     if (error != 0)  
  18.     {  
  19.         printf("ERROR in VoEBase::StartSend\n");  
  20.         return error;  
  21.     }  
  22.     //Start Record  
  23.     error = ptrVoEFile->StartRecordingMicrophone(mic_filename.c_str());  
  24.     if (error != 0)  
  25.     {  
  26.         printf("ERROR in VoEFile::StartRecordingMicrophone\n");  
  27.         return error;  
  28.     }  
  29.     error = ptrVoEFile->StartRecordingPlayout(audiochannel, play_filename.c_str());  
  30.     if (error != 0)  
  31.     {  
  32.         printf("ERROR in VoEFile::StartRecordingPlayout\n");  
  33.         return error;  
  34.     }  

在通话结束之后,还需要进行相应的stop\release

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //Stop Record  
  2.     error = ptrVoEFile->StopRecordingMicrophone();  
  3.     if (error != 0)  
  4.     {  
  5.         printf("ERROR in VoEFile::StopRecordingMicrophone\n");  
  6.         return error;  
  7.     }  
  8.     error = ptrVoEFile->StopRecordingPlayout(audiochannel);  
  9.     if (error != 0)  
  10.     {  
  11.         printf("ERROR in VoEFile::StopRecordingPlayout\n");  
  12.         return error;  
  13.     }  
  14.     //Stop Receive  
  15.     error = ptrVoEBase->StopReceive(audiochannel);  
  16.     if (error != 0)  
  17.     {  
  18.         printf("ERROR in VoEBase::StopReceive\n");  
  19.         return error;  
  20.     }  
  21.     //Stop Send  
  22.     error = ptrVoEBase->StopSend(audiochannel);  
  23.     if (error != 0)  
  24.     {  
  25.         printf("ERROR in VoEBase::StopSend\n");  
  26.         return error;  
  27.     }  
  28.     //Stop Playout  
  29.     error = ptrVoEBase->StopPlayout(audiochannel);  
  30.     if (error != 0)  
  31.     {  
  32.         printf("ERROR in VoEBase::StopPlayout\n");  
  33.         return error;  
  34.     }  
  35.     //Delete Channel  
  36.     error = ptrVoEBase->DeleteChannel(audiochannel);  
  37.     if (error != 0)  
  38.     {  
  39.         printf("ERROR in VoEBase::DeleteChannel\n");  
  40.         return error;  
  41.     }  
  42.   
  43.     delete voice_channel_transport;  
  44.   
  45.     ptrVoEBase->DeRegisterVoiceEngineObserver();  
  46.     error = ptrVoEBase->Terminate();  
  47.     if (error != 0)  
  48.     {  
  49.         printf("ERROR in VoEBase::Terminate\n");  
  50.         return error;  
  51.     }  
  52.   
  53.     int remainingInterfaces = 0;  
  54.     remainingInterfaces += ptrVoEBase->Release();  
  55.     remainingInterfaces = ptrVoECodec->Release();  
  56.     remainingInterfaces += ptrVoEVolume->Release();  
  57.     remainingInterfaces += ptrVoEFile->Release();  
  58.     remainingInterfaces += ptrVoEAp->Release();  
  59.     remainingInterfaces += ptrVoEHardware->Release();  
  60.     remainingInterfaces += ptrVoENetwork->Release();  
  61.   
  62.   
  63.     /*if (remainingInterfaces > 0) 
  64.     { 
  65.     printf("ERROR: Could not release all interfaces\n"); 
  66.     return -1; 
  67.     }*/  
  68.   
  69.     bool deleted = webrtc::VoiceEngine::Delete(ptrVoE);  
  70.     if (deleted == false)  
  71.     {  
  72.         printf("ERROR in VoiceEngine::Delete\n");  
  73.         return -1;  
  74.     }  
需要注意的是,这里remainingInterfaces最后不会为0,因为我们没有用到VoiceEngine的全部sub-apis。

 至此,就实现了一个音频通话的功能。

本项目源代码下载地址。github地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值