LCOV - code coverage report
Current view: top level - media/webrtc/signaling/src/media-conduit - AudioConduit.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 516 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 40 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "CSFLog.h"
       6             : #include "nspr.h"
       7             : 
       8             : #ifdef HAVE_NETINET_IN_H
       9             : #include <netinet/in.h>
      10             : #elif defined XP_WIN
      11             : #include <winsock2.h>
      12             : #endif
      13             : 
      14             : #include "AudioConduit.h"
      15             : #include "nsCOMPtr.h"
      16             : #include "mozilla/Services.h"
      17             : #include "nsServiceManagerUtils.h"
      18             : #include "nsIPrefService.h"
      19             : #include "nsIPrefBranch.h"
      20             : #include "nsThreadUtils.h"
      21             : #include "Latency.h"
      22             : #include "mozilla/Telemetry.h"
      23             : 
      24             : #include "webrtc/modules/audio_processing/include/audio_processing.h"
      25             : #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
      26             : #include "webrtc/voice_engine/include/voe_errors.h"
      27             : #include "webrtc/voice_engine/voice_engine_impl.h"
      28             : #include "webrtc/system_wrappers/include/clock.h"
      29             : 
      30             : #ifdef MOZ_WIDGET_ANDROID
      31             : #include "AndroidJNIWrapper.h"
      32             : #endif
      33             : 
      34             : namespace mozilla {
      35             : 
      36             : static const char* logTag ="WebrtcAudioSessionConduit";
      37             : 
      38             : // 32 bytes is what WebRTC CodecInst expects
      39             : const unsigned int WebrtcAudioConduit::CODEC_PLNAME_SIZE = 32;
      40             : 
      41             : /**
      42             :  * Factory Method for AudioConduit
      43             :  */
      44           0 : RefPtr<AudioSessionConduit> AudioSessionConduit::Create()
      45             : {
      46           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
      47           0 :   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
      48             : 
      49           0 :   WebrtcAudioConduit* obj = new WebrtcAudioConduit();
      50           0 :   if(obj->Init() != kMediaConduitNoError)
      51             :   {
      52           0 :     CSFLogError(logTag,  "%s AudioConduit Init Failed ", __FUNCTION__);
      53           0 :     delete obj;
      54           0 :     return nullptr;
      55             :   }
      56           0 :   CSFLogDebug(logTag,  "%s Successfully created AudioConduit ", __FUNCTION__);
      57           0 :   return obj;
      58             : }
      59             : 
      60             : /**
      61             :  * Destruction defines for our super-classes
      62             :  */
      63           0 : WebrtcAudioConduit::~WebrtcAudioConduit()
      64             : {
      65           0 :   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
      66             : 
      67           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
      68           0 :   for(auto & codec : mRecvCodecList)
      69             :   {
      70           0 :     delete codec;
      71             :   }
      72             : 
      73             :   // The first one of a pair to be deleted shuts down media for both
      74           0 :   if(mPtrVoEXmedia)
      75             :   {
      76           0 :     mPtrVoEXmedia->SetExternalRecordingStatus(false);
      77           0 :     mPtrVoEXmedia->SetExternalPlayoutStatus(false);
      78             :   }
      79             : 
      80             :   //Deal with the transport
      81           0 :   if(mPtrVoENetwork)
      82             :   {
      83           0 :     mPtrVoENetwork->DeRegisterExternalTransport(mChannel);
      84             :   }
      85             : 
      86           0 :   if(mPtrVoEBase)
      87             :   {
      88           0 :     mPtrVoEBase->StopPlayout(mChannel);
      89           0 :     mPtrVoEBase->StopSend(mChannel);
      90           0 :     mPtrVoEBase->StopReceive(mChannel);
      91           0 :     mChannelProxy = nullptr;
      92           0 :     mPtrVoEBase->DeleteChannel(mChannel);
      93             :     // We don't Terminate() the VoEBase here, because the Call (owned by
      94             :     // PeerConnectionMedia) actually owns the (shared) VoEBase/VoiceEngine
      95             :     // here
      96             :   }
      97             : 
      98             :   // We shouldn't delete the VoiceEngine until all these are released!
      99             :   // And we can't use a Scoped ptr, since the order is arbitrary
     100           0 :   mPtrVoENetwork = nullptr;
     101           0 :   mPtrVoEBase = nullptr;
     102           0 :   mPtrVoECodec = nullptr;
     103           0 :   mPtrVoEXmedia = nullptr;
     104           0 :   mPtrVoEProcessing = nullptr;
     105           0 :   mPtrVoEVideoSync = nullptr;
     106           0 :   mPtrVoERTP_RTCP = nullptr;
     107           0 :   mPtrRTP = nullptr;
     108             : 
     109           0 :   if (mVoiceEngine)
     110             :   {
     111           0 :     webrtc::VoiceEngine::Delete(mVoiceEngine);
     112             :   }
     113           0 : }
     114             : 
     115           0 : bool WebrtcAudioConduit::SetLocalSSRCs(const std::vector<unsigned int> & aSSRCs)
     116             : {
     117             :   // This should hold true until the WebRTC.org VoE refactor
     118           0 :   MOZ_ASSERT(aSSRCs.size() == 1,"WebrtcAudioConduit::SetLocalSSRCs accepts exactly 1 ssrc.");
     119             : 
     120           0 :   std::vector<unsigned int> oldSsrcs = GetLocalSSRCs();
     121           0 :   if (oldSsrcs.empty()) {
     122           0 :     MOZ_ASSERT(false, "GetLocalSSRC failed");
     123             :     return false;
     124             :   }
     125             : 
     126           0 :   if (oldSsrcs == aSSRCs) {
     127           0 :     return true;
     128             :   }
     129             : 
     130           0 :   bool wasTransmitting = mEngineTransmitting;
     131           0 :   if (StopTransmitting() != kMediaConduitNoError) {
     132           0 :     return false;
     133             :   }
     134             : 
     135           0 :   if (mPtrRTP->SetLocalSSRC(mChannel, aSSRCs[0])) {
     136           0 :     return false;
     137             :   }
     138             : 
     139           0 :   if (wasTransmitting) {
     140           0 :     if (StartTransmitting() != kMediaConduitNoError) {
     141           0 :       return false;
     142             :     }
     143             :   }
     144           0 :   return true;
     145             : }
     146             : 
     147           0 : std::vector<unsigned int> WebrtcAudioConduit::GetLocalSSRCs() const {
     148             :   unsigned int ssrc;
     149           0 :   if (!mPtrRTP->GetLocalSSRC(mChannel, ssrc)) {
     150           0 :     return std::vector<unsigned int>(1,ssrc);
     151             :   }
     152           0 :   return std::vector<unsigned int>();
     153             : }
     154             : 
     155           0 : bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) {
     156           0 :   return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc);
     157             : }
     158             : 
     159           0 : bool WebrtcAudioConduit::SetLocalCNAME(const char* cname)
     160             : {
     161             :   char temp[256];
     162           0 :   strncpy(temp, cname, sizeof(temp) - 1);
     163           0 :   temp[sizeof(temp) - 1] = 0;
     164           0 :   return !mPtrRTP->SetRTCP_CNAME(mChannel, temp);
     165             : }
     166             : 
     167           0 : bool WebrtcAudioConduit::GetSendPacketTypeStats(
     168             :   webrtc::RtcpPacketTypeCounter* aPacketCounts)
     169             : {
     170           0 :   if (!mEngineTransmitting) {
     171           0 :     return false;
     172             :   }
     173           0 :   return !mPtrVoERTP_RTCP->GetRTCPPacketTypeCounters(mChannel, *aPacketCounts);
     174             : }
     175             : 
     176           0 : bool WebrtcAudioConduit::GetRecvPacketTypeStats(
     177             :   webrtc::RtcpPacketTypeCounter* aPacketCounts)
     178             : {
     179           0 :   if (!mEngineReceiving) {
     180           0 :     return false;
     181             :   }
     182           0 :   return !mPtrRTP->GetRTCPPacketTypeCounters(mChannel, *aPacketCounts);
     183             : }
     184             : 
     185           0 : bool WebrtcAudioConduit::GetAVStats(int32_t* jitterBufferDelayMs,
     186             :                                     int32_t* playoutBufferDelayMs,
     187             :                                     int32_t* avSyncOffsetMs) {
     188           0 :   return !mPtrVoEVideoSync->GetDelayEstimate(mChannel,
     189             :                                              jitterBufferDelayMs,
     190             :                                              playoutBufferDelayMs,
     191           0 :                                              avSyncOffsetMs);
     192             : }
     193             : 
     194           0 : bool WebrtcAudioConduit::GetRTPStats(unsigned int* jitterMs,
     195             :                                      unsigned int* cumulativeLost) {
     196           0 :   unsigned int maxJitterMs = 0;
     197             :   unsigned int discardedPackets;
     198           0 :   *jitterMs = 0;
     199           0 :   *cumulativeLost = 0;
     200           0 :   return !mPtrRTP->GetRTPStatistics(mChannel, *jitterMs, maxJitterMs,
     201           0 :                                     discardedPackets, *cumulativeLost);
     202             : }
     203             : 
     204             : DOMHighResTimeStamp
     205           0 : NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow) {
     206           0 :   return (uint32_t(ntpHigh - webrtc::kNtpJan1970) +
     207           0 :           double(ntpLow) / webrtc::kMagicNtpFractionalUnit) * 1000;
     208             : }
     209             : 
     210           0 : bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
     211             :                                                uint32_t* jitterMs,
     212             :                                                uint32_t* packetsReceived,
     213             :                                                uint64_t* bytesReceived,
     214             :                                                uint32_t* cumulativeLost,
     215             :                                                int32_t* rttMs) {
     216             : 
     217             :   // We get called on STS thread... the proxy thread-checks to MainThread
     218             :   // I removed the check, since GetRTCPStatistics ends up going down to
     219             :   // methods (rtp_receiver_->SSRC() and rtp_receive_statistics_->GetStatistician()
     220             :   // and GetStatistics that internally lock, so we're ok here without a thread-check.
     221           0 :   webrtc::CallStatistics call_stats = mChannelProxy->GetRTCPStatistics();
     222           0 :   *bytesReceived = call_stats.bytesReceived;
     223           0 :   *packetsReceived = call_stats.packetsReceived;
     224           0 :   *cumulativeLost = call_stats.cumulativeLost;
     225           0 :   *rttMs = call_stats.rttMs;
     226             : 
     227             :   unsigned int averageJitterMs;
     228             :   unsigned int maxJitterMs;
     229             :   unsigned int discardedPackets;
     230             :   unsigned int cumulative;
     231           0 :   mChannelProxy->GetRTPStatistics(averageJitterMs, maxJitterMs, discardedPackets, cumulative);
     232           0 :   *jitterMs = averageJitterMs;
     233             : 
     234             :   // XXX Note: timestamp is not correct per the spec... should be time the
     235             :   // rtcp was received (remote) or sent (local)
     236           0 :   *timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
     237           0 :   return true;
     238             : }
     239             : 
     240           0 : bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
     241             :                                              unsigned int* packetsSent,
     242             :                                              uint64_t* bytesSent) {
     243             :   webrtc::RTCPSenderInfo senderInfo;
     244             :   webrtc::RtpRtcp * rtpRtcpModule;
     245             :   webrtc::RtpReceiver * rtp_receiver;
     246             :   bool result =
     247           0 :     !mPtrVoEVideoSync->GetRtpRtcp(mChannel,&rtpRtcpModule,&rtp_receiver) &&
     248           0 :     !rtpRtcpModule->RemoteRTCPStat(&senderInfo);
     249           0 :   if (result){
     250           0 :     *timestamp = NTPtoDOMHighResTimeStamp(senderInfo.NTPseconds,
     251             :                                           senderInfo.NTPfraction);
     252           0 :     *packetsSent = senderInfo.sendPacketCount;
     253           0 :     *bytesSent = senderInfo.sendOctetCount;
     254             :    }
     255           0 :    return result;
     256             :  }
     257             : 
     258           0 : bool WebrtcAudioConduit::SetDtmfPayloadType(unsigned char type, int freq) {
     259           0 :   CSFLogInfo(logTag, "%s : setting dtmf payload %d", __FUNCTION__, (int)type);
     260             : 
     261           0 :   int result = mChannelProxy->SetSendTelephoneEventPayloadType(type, freq);
     262           0 :   if (result == -1) {
     263           0 :     CSFLogError(logTag, "%s Failed call to SetSendTelephoneEventPayloadType(%u, %d)",
     264           0 :                 __FUNCTION__, type, freq);
     265             :   }
     266           0 :   return result != -1;
     267             : }
     268             : 
     269           0 : bool WebrtcAudioConduit::InsertDTMFTone(int channel, int eventCode,
     270             :                                         bool outOfBand, int lengthMs,
     271             :                                         int attenuationDb) {
     272           0 :   NS_ASSERTION(!NS_IsMainThread(), "Do not call on main thread");
     273             : 
     274           0 :   if (!mVoiceEngine || !mDtmfEnabled) {
     275           0 :     return false;
     276             :   }
     277             : 
     278           0 :   int result = 0;
     279           0 :   if (outOfBand){
     280           0 :     result = mChannelProxy->SendTelephoneEventOutband(eventCode, lengthMs);
     281             :   }
     282           0 :   return result != -1;
     283             : }
     284             : 
     285             : /*
     286             :  * WebRTCAudioConduit Implementation
     287             :  */
     288           0 : MediaConduitErrorCode WebrtcAudioConduit::Init()
     289             : {
     290           0 :   CSFLogDebug(logTag,  "%s this=%p", __FUNCTION__, this);
     291             : 
     292             : #ifdef MOZ_WIDGET_ANDROID
     293             :     jobject context = jsjni_GetGlobalContextRef();
     294             :     // get the JVM
     295             :     JavaVM *jvm = jsjni_GetVM();
     296             : 
     297             :     if (webrtc::VoiceEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
     298             :       CSFLogError(logTag, "%s Unable to set Android objects", __FUNCTION__);
     299             :       return kMediaConduitSessionNotInited;
     300             :     }
     301             : #endif
     302             : 
     303             :   // Per WebRTC APIs below function calls return nullptr on failure
     304           0 :   if(!(mVoiceEngine = webrtc::VoiceEngine::Create()))
     305             :   {
     306           0 :     CSFLogError(logTag, "%s Unable to create voice engine", __FUNCTION__);
     307           0 :     return kMediaConduitSessionNotInited;
     308             :   }
     309             : 
     310           0 :   if(!(mPtrVoEBase = VoEBase::GetInterface(mVoiceEngine)))
     311             :   {
     312           0 :     CSFLogError(logTag, "%s Unable to initialize VoEBase", __FUNCTION__);
     313           0 :     return kMediaConduitSessionNotInited;
     314             :   }
     315             : 
     316             :   // init the engine with our audio device layer
     317           0 :   if(mPtrVoEBase->Init() == -1)
     318             :   {
     319           0 :     CSFLogError(logTag, "%s VoiceEngine Base Not Initialized", __FUNCTION__);
     320           0 :     return kMediaConduitSessionNotInited;
     321             :   }
     322             : 
     323           0 :   if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
     324             :   {
     325           0 :     CSFLogError(logTag, "%s Unable to initialize VoENetwork", __FUNCTION__);
     326           0 :     return kMediaConduitSessionNotInited;
     327             :   }
     328             : 
     329           0 :   if(!(mPtrVoECodec = VoECodec::GetInterface(mVoiceEngine)))
     330             :   {
     331           0 :     CSFLogError(logTag, "%s Unable to initialize VoEBCodec", __FUNCTION__);
     332           0 :     return kMediaConduitSessionNotInited;
     333             :   }
     334             : 
     335           0 :   if(!(mPtrVoEProcessing = VoEAudioProcessing::GetInterface(mVoiceEngine)))
     336             :   {
     337           0 :     CSFLogError(logTag, "%s Unable to initialize VoEProcessing", __FUNCTION__);
     338           0 :     return kMediaConduitSessionNotInited;
     339             :   }
     340           0 :   if(!(mPtrVoEXmedia = VoEExternalMedia::GetInterface(mVoiceEngine)))
     341             :   {
     342           0 :     CSFLogError(logTag, "%s Unable to initialize VoEExternalMedia", __FUNCTION__);
     343           0 :     return kMediaConduitSessionNotInited;
     344             :   }
     345           0 :   if(!(mPtrVoERTP_RTCP = VoERTP_RTCP::GetInterface(mVoiceEngine)))
     346             :   {
     347           0 :     CSFLogError(logTag, "%s Unable to initialize VoERTP_RTCP", __FUNCTION__);
     348           0 :     return kMediaConduitSessionNotInited;
     349             :   }
     350             : 
     351           0 :   if(!(mPtrVoEVideoSync = VoEVideoSync::GetInterface(mVoiceEngine)))
     352             :   {
     353           0 :     CSFLogError(logTag, "%s Unable to initialize VoEVideoSync", __FUNCTION__);
     354           0 :     return kMediaConduitSessionNotInited;
     355             :   }
     356           0 :   if (!(mPtrRTP = webrtc::VoERTP_RTCP::GetInterface(mVoiceEngine)))
     357             :   {
     358             :     CSFLogError(logTag, "%s Unable to get audio RTP/RTCP interface ",
     359           0 :                 __FUNCTION__);
     360           0 :     return kMediaConduitSessionNotInited;
     361             :   }
     362             : 
     363           0 :   if( (mChannel = mPtrVoEBase->CreateChannel()) == -1)
     364             :   {
     365           0 :     CSFLogError(logTag, "%s VoiceEngine Channel creation failed",__FUNCTION__);
     366           0 :     return kMediaConduitChannelError;
     367             :   }
     368             :   // Needed to access TelephoneEvent APIs in 57 if we're not using Call/audio_send_stream/etc
     369           0 :   webrtc::VoiceEngineImpl* s = static_cast<webrtc::VoiceEngineImpl*>(mVoiceEngine);
     370           0 :   mChannelProxy = s->GetChannelProxy(mChannel);
     371           0 :   MOZ_ASSERT(mChannelProxy);
     372             : 
     373           0 :   CSFLogDebug(logTag, "%s Channel Created %d ",__FUNCTION__, mChannel);
     374             : 
     375           0 :   if(mPtrVoENetwork->RegisterExternalTransport(mChannel, *this) == -1)
     376             :   {
     377           0 :     CSFLogError(logTag, "%s VoiceEngine, External Transport Failed",__FUNCTION__);
     378           0 :     return kMediaConduitTransportRegistrationFail;
     379             :   }
     380             : 
     381           0 :   if(mPtrVoEXmedia->SetExternalRecordingStatus(true) == -1)
     382             :   {
     383           0 :     CSFLogError(logTag, "%s SetExternalRecordingStatus Failed %d",__FUNCTION__,
     384           0 :                 mPtrVoEBase->LastError());
     385           0 :     return kMediaConduitExternalPlayoutError;
     386             :   }
     387             : 
     388           0 :   if(mPtrVoEXmedia->SetExternalPlayoutStatus(true) == -1)
     389             :   {
     390           0 :     CSFLogError(logTag, "%s SetExternalPlayoutStatus Failed %d ",__FUNCTION__,
     391           0 :                 mPtrVoEBase->LastError());
     392           0 :     return kMediaConduitExternalRecordingError;
     393             :   }
     394             : 
     395           0 :   CSFLogDebug(logTag ,  "%s AudioSessionConduit Initialization Done (%p)",__FUNCTION__, this);
     396           0 :   return kMediaConduitNoError;
     397             : }
     398             : 
     399             : // AudioSessionConduit Implementation
     400             : MediaConduitErrorCode
     401           0 : WebrtcAudioConduit::SetTransmitterTransport(RefPtr<TransportInterface> aTransport)
     402             : {
     403           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
     404             : 
     405           0 :   ReentrantMonitorAutoEnter enter(mTransportMonitor);
     406             :   // set the transport
     407           0 :   mTransmitterTransport = aTransport;
     408           0 :   return kMediaConduitNoError;
     409             : }
     410             : 
     411             : MediaConduitErrorCode
     412           0 : WebrtcAudioConduit::SetReceiverTransport(RefPtr<TransportInterface> aTransport)
     413             : {
     414           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
     415             : 
     416           0 :   ReentrantMonitorAutoEnter enter(mTransportMonitor);
     417             :   // set the transport
     418           0 :   mReceiverTransport = aTransport;
     419           0 :   return kMediaConduitNoError;
     420             : }
     421             : 
     422             : MediaConduitErrorCode
     423           0 : WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
     424             : {
     425           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
     426           0 :   MediaConduitErrorCode condError = kMediaConduitNoError;
     427           0 :   int error = 0;//webrtc engine errors
     428             :   webrtc::CodecInst cinst;
     429             : 
     430             :   {
     431             :     //validate codec param
     432           0 :     if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
     433             :     {
     434           0 :       return condError;
     435             :     }
     436             :   }
     437             : 
     438           0 :   condError = StopTransmitting();
     439           0 :   if (condError != kMediaConduitNoError) {
     440           0 :     return condError;
     441             :   }
     442             : 
     443           0 :   if(!CodecConfigToWebRTCCodec(codecConfig,cinst))
     444             :   {
     445           0 :     CSFLogError(logTag,"%s CodecConfig to WebRTC Codec Failed ",__FUNCTION__);
     446           0 :     return kMediaConduitMalformedArgument;
     447             :   }
     448             : 
     449           0 :   if(mPtrVoECodec->SetSendCodec(mChannel, cinst) == -1)
     450             :   {
     451           0 :     error = mPtrVoEBase->LastError();
     452             :     CSFLogError(logTag, "%s SetSendCodec - Invalid Codec %d ",__FUNCTION__,
     453           0 :                                                                     error);
     454             : 
     455           0 :     if(error ==  VE_CANNOT_SET_SEND_CODEC || error == VE_CODEC_ERROR)
     456             :     {
     457           0 :       CSFLogError(logTag, "%s Invalid Send Codec", __FUNCTION__);
     458           0 :       return kMediaConduitInvalidSendCodec;
     459             :     }
     460           0 :     CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
     461           0 :                                          mPtrVoEBase->LastError());
     462           0 :     return kMediaConduitUnknownError;
     463             :   }
     464             : 
     465             :   // This must be called after SetSendCodec
     466           0 :   if (mPtrVoECodec->SetFECStatus(mChannel, codecConfig->mFECEnabled) == -1) {
     467           0 :     CSFLogError(logTag, "%s SetFECStatus Failed %d ", __FUNCTION__,
     468           0 :                 mPtrVoEBase->LastError());
     469           0 :     return kMediaConduitFECStatusError;
     470             :   }
     471             : 
     472           0 :   mDtmfEnabled = codecConfig->mDtmfEnabled;
     473             : 
     474           0 :   if (codecConfig->mName == "opus" && codecConfig->mMaxPlaybackRate) {
     475           0 :     if (mPtrVoECodec->SetOpusMaxPlaybackRate(
     476             :           mChannel,
     477           0 :           codecConfig->mMaxPlaybackRate) == -1) {
     478           0 :       CSFLogError(logTag, "%s SetOpusMaxPlaybackRate Failed %d ", __FUNCTION__,
     479           0 :                   mPtrVoEBase->LastError());
     480           0 :       return kMediaConduitUnknownError;
     481             :     }
     482             :   }
     483             : 
     484             :   // TEMPORARY - see bug 694814 comment 2
     485             :   nsresult rv;
     486           0 :   nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
     487           0 :   if (NS_SUCCEEDED(rv)) {
     488           0 :     nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
     489             : 
     490           0 :     if (branch) {
     491           0 :       branch->GetIntPref("media.peerconnection.capture_delay", &mCaptureDelay);
     492             :     }
     493             :   }
     494             : 
     495           0 :   condError = StartTransmitting();
     496           0 :   if (condError != kMediaConduitNoError) {
     497           0 :     return condError;
     498             :   }
     499             : 
     500             :   {
     501           0 :     MutexAutoLock lock(mCodecMutex);
     502             : 
     503             :     //Copy the applied config for future reference.
     504           0 :     mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
     505             :                                                codecConfig->mName,
     506           0 :                                                codecConfig->mFreq,
     507           0 :                                                codecConfig->mPacSize,
     508           0 :                                                codecConfig->mChannels,
     509           0 :                                                codecConfig->mRate,
     510           0 :                                                codecConfig->mFECEnabled);
     511             :   }
     512           0 :   return kMediaConduitNoError;
     513             : }
     514             : 
     515             : MediaConduitErrorCode
     516           0 : WebrtcAudioConduit::ConfigureRecvMediaCodecs(
     517             :                     const std::vector<AudioCodecConfig*>& codecConfigList)
     518             : {
     519           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
     520           0 :   MediaConduitErrorCode condError = kMediaConduitNoError;
     521           0 :   int error = 0; //webrtc engine errors
     522           0 :   bool success = false;
     523             : 
     524             :   // Are we receiving already? If so, stop receiving and playout
     525             :   // since we can't apply new recv codec when the engine is playing.
     526           0 :   condError = StopReceiving();
     527           0 :   if (condError != kMediaConduitNoError) {
     528           0 :     return condError;
     529             :   }
     530             : 
     531           0 :   if(codecConfigList.empty())
     532             :   {
     533           0 :     CSFLogError(logTag, "%s Zero number of codecs to configure", __FUNCTION__);
     534           0 :     return kMediaConduitMalformedArgument;
     535             :   }
     536             : 
     537             :   // Try Applying the codecs in the list.
     538             :   // We succeed if at least one codec was applied and reception was
     539             :   // started successfully.
     540           0 :   for(auto codec : codecConfigList)
     541             :   {
     542             :     //if the codec param is invalid or diplicate, return error
     543           0 :     if((condError = ValidateCodecConfig(codec,false)) != kMediaConduitNoError)
     544             :     {
     545           0 :       return condError;
     546             :     }
     547             : 
     548             :     webrtc::CodecInst cinst;
     549           0 :     if(!CodecConfigToWebRTCCodec(codec,cinst))
     550             :     {
     551           0 :       CSFLogError(logTag,"%s CodecConfig to WebRTC Codec Failed ",__FUNCTION__);
     552           0 :       continue;
     553             :     }
     554             : 
     555           0 :     if(mPtrVoECodec->SetRecPayloadType(mChannel,cinst) == -1)
     556             :     {
     557           0 :       error = mPtrVoEBase->LastError();
     558           0 :       CSFLogError(logTag,  "%s SetRecvCodec Failed %d ",__FUNCTION__, error);
     559           0 :       continue;
     560             :     }
     561           0 :     CSFLogDebug(logTag, "%s Successfully Set RecvCodec %s", __FUNCTION__,
     562           0 :                                         codec->mName.c_str());
     563             : 
     564             :     //copy this to local database
     565           0 :     if(!CopyCodecToDB(codec)) {
     566           0 :         CSFLogError(logTag,"%s Unable to updated Codec Database", __FUNCTION__);
     567           0 :         return kMediaConduitUnknownError;
     568             :     }
     569           0 :     success = true;
     570             : 
     571             :   } //end for
     572             : 
     573           0 :   if(!success)
     574             :   {
     575           0 :     CSFLogError(logTag, "%s Setting Receive Codec Failed ", __FUNCTION__);
     576           0 :     return kMediaConduitInvalidReceiveCodec;
     577             :   }
     578             : 
     579             :   //If we are here, atleast one codec should have been set
     580           0 :   condError = StartReceiving();
     581           0 :   if (condError != kMediaConduitNoError) {
     582           0 :     return condError;
     583             :   }
     584             : 
     585           0 :   DumpCodecDB();
     586           0 :   return kMediaConduitNoError;
     587             : }
     588             : MediaConduitErrorCode
     589           0 : WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled, uint8_t id)
     590             : {
     591           0 :   CSFLogDebug(logTag,  "%s %d %d ", __FUNCTION__, enabled, id);
     592             : 
     593           0 :   if (mPtrVoERTP_RTCP->SetSendAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
     594             :   {
     595           0 :     CSFLogError(logTag, "%s SetSendAudioLevelIndicationStatus Failed", __FUNCTION__);
     596           0 :     return kMediaConduitUnknownError;
     597             :   }
     598             : 
     599           0 :   return kMediaConduitNoError;
     600             : }
     601             : 
     602             : MediaConduitErrorCode
     603           0 : WebrtcAudioConduit::SendAudioFrame(const int16_t audio_data[],
     604             :                                     int32_t lengthSamples,
     605             :                                     int32_t samplingFreqHz,
     606             :                                     int32_t capture_delay)
     607             : {
     608           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
     609             :   // Following checks need to be performed
     610             :   // 1. Non null audio buffer pointer,
     611             :   // 2. invalid sampling frequency -  less than 0 or unsupported ones
     612             :   // 3. Appropriate Sample Length for 10 ms audio-frame. This represents
     613             :   //    block size the VoiceEngine feeds into encoder for passed in audio-frame
     614             :   //    Ex: for 16000 sampling rate , valid block-length is 160
     615             :   //    Similarly for 32000 sampling rate, valid block length is 320
     616             :   //    We do the check by the verify modular operator below to be zero
     617             : 
     618           0 :   if(!audio_data || (lengthSamples <= 0) ||
     619           0 :                     (IsSamplingFreqSupported(samplingFreqHz) == false) ||
     620           0 :                     ((lengthSamples % (samplingFreqHz / 100) != 0)) )
     621             :   {
     622           0 :     CSFLogError(logTag, "%s Invalid Parameters ",__FUNCTION__);
     623           0 :     MOZ_ASSERT(PR_FALSE);
     624             :     return kMediaConduitMalformedArgument;
     625             :   }
     626             : 
     627             :   //validate capture time
     628           0 :   if(capture_delay < 0 )
     629             :   {
     630           0 :     CSFLogError(logTag,"%s Invalid Capture Delay ", __FUNCTION__);
     631           0 :     MOZ_ASSERT(PR_FALSE);
     632             :     return kMediaConduitMalformedArgument;
     633             :   }
     634             : 
     635             :   // if transmission is not started .. conduit cannot insert frames
     636           0 :   if(!mEngineTransmitting)
     637             :   {
     638           0 :     CSFLogError(logTag, "%s Engine not transmitting ", __FUNCTION__);
     639           0 :     return kMediaConduitSessionNotInited;
     640             :   }
     641             : 
     642           0 :   if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
     643           0 :     struct Processing insert = { TimeStamp::Now(), 0 };
     644           0 :     mProcessing.AppendElement(insert);
     645             :   }
     646             : 
     647           0 :   capture_delay = mCaptureDelay;
     648             :   //Insert the samples
     649           0 :   if(mPtrVoEXmedia->ExternalRecordingInsertData(audio_data,
     650             :                                                 lengthSamples,
     651             :                                                 samplingFreqHz,
     652           0 :                                                 capture_delay) == -1)
     653             :   {
     654           0 :     int error = mPtrVoEBase->LastError();
     655           0 :     CSFLogError(logTag,  "%s Inserting audio data Failed %d", __FUNCTION__, error);
     656           0 :     if(error == VE_RUNTIME_REC_ERROR)
     657             :     {
     658           0 :       return kMediaConduitRecordingError;
     659             :     }
     660           0 :     return kMediaConduitUnknownError;
     661             :   }
     662             :   // we should be good here
     663           0 :   return kMediaConduitNoError;
     664             : }
     665             : 
     666             : MediaConduitErrorCode
     667           0 : WebrtcAudioConduit::GetAudioFrame(int16_t speechData[],
     668             :                                    int32_t samplingFreqHz,
     669             :                                    int32_t capture_delay,
     670             :                                    int& lengthSamples)
     671             : {
     672             : 
     673           0 :   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
     674           0 :   unsigned int numSamples = 0;
     675             : 
     676             :   //validate params
     677           0 :   if(!speechData )
     678             :   {
     679           0 :     CSFLogError(logTag,"%s Null Audio Buffer Pointer", __FUNCTION__);
     680           0 :     MOZ_ASSERT(PR_FALSE);
     681             :     return kMediaConduitMalformedArgument;
     682             :   }
     683             : 
     684             :   // Validate sample length
     685           0 :   if((numSamples = GetNum10msSamplesForFrequency(samplingFreqHz)) == 0  )
     686             :   {
     687           0 :     CSFLogError(logTag,"%s Invalid Sampling Frequency ", __FUNCTION__);
     688           0 :     MOZ_ASSERT(PR_FALSE);
     689             :     return kMediaConduitMalformedArgument;
     690             :   }
     691             : 
     692             :   //validate capture time
     693           0 :   if(capture_delay < 0 )
     694             :   {
     695           0 :     CSFLogError(logTag,"%s Invalid Capture Delay ", __FUNCTION__);
     696           0 :     MOZ_ASSERT(PR_FALSE);
     697             :     return kMediaConduitMalformedArgument;
     698             :   }
     699             : 
     700             :   //Conduit should have reception enabled before we ask for decoded
     701             :   // samples
     702           0 :   if(!mEngineReceiving)
     703             :   {
     704           0 :     CSFLogError(logTag, "%s Engine not Receiving ", __FUNCTION__);
     705           0 :     return kMediaConduitSessionNotInited;
     706             :   }
     707             : 
     708             : 
     709           0 :   lengthSamples = 0;  //output paramter
     710             : 
     711           0 :   if(mPtrVoEXmedia->ExternalPlayoutGetData( speechData,
     712             :                                             samplingFreqHz,
     713             :                                             capture_delay,
     714           0 :                                             lengthSamples) == -1)
     715             :   {
     716           0 :     int error = mPtrVoEBase->LastError();
     717           0 :     CSFLogError(logTag,  "%s Getting audio data Failed %d", __FUNCTION__, error);
     718           0 :     if(error == VE_RUNTIME_PLAY_ERROR)
     719             :     {
     720           0 :       return kMediaConduitPlayoutError;
     721             :     }
     722           0 :     return kMediaConduitUnknownError;
     723             :   }
     724             : 
     725             :   // Not #ifdef DEBUG or on a log module so we can use it for about:webrtc/etc
     726           0 :   mSamples += lengthSamples;
     727           0 :   if (mSamples >= mLastSyncLog + samplingFreqHz) {
     728             :     int jitter_buffer_delay_ms;
     729             :     int playout_buffer_delay_ms;
     730             :     int avsync_offset_ms;
     731           0 :     if (GetAVStats(&jitter_buffer_delay_ms,
     732             :                    &playout_buffer_delay_ms,
     733           0 :                    &avsync_offset_ms)) {
     734           0 :       if (avsync_offset_ms < 0) {
     735           0 :         Telemetry::Accumulate(Telemetry::WEBRTC_AVSYNC_WHEN_VIDEO_LAGS_AUDIO_MS,
     736           0 :                               -avsync_offset_ms);
     737             :       } else {
     738           0 :         Telemetry::Accumulate(Telemetry::WEBRTC_AVSYNC_WHEN_AUDIO_LAGS_VIDEO_MS,
     739           0 :                               avsync_offset_ms);
     740             :       }
     741             :       CSFLogError(logTag,
     742             :                   "A/V sync: sync delta: %dms, audio jitter delay %dms, playout delay %dms",
     743           0 :                   avsync_offset_ms, jitter_buffer_delay_ms, playout_buffer_delay_ms);
     744             :     } else {
     745           0 :       CSFLogError(logTag, "A/V sync: GetAVStats failed");
     746             :     }
     747           0 :     mLastSyncLog = mSamples;
     748             :   }
     749             : 
     750           0 :   if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
     751           0 :     if (mProcessing.Length() > 0) {
     752             :       unsigned int now;
     753           0 :       mPtrVoEVideoSync->GetPlayoutTimestamp(mChannel, now);
     754           0 :       if (static_cast<uint32_t>(now) != mLastTimestamp) {
     755           0 :         mLastTimestamp = static_cast<uint32_t>(now);
     756             :         // Find the block that includes this timestamp in the network input
     757           0 :         while (mProcessing.Length() > 0) {
     758             :           // FIX! assumes 20ms @ 48000Hz
     759             :           // FIX handle wrap-around
     760           0 :           if (mProcessing[0].mRTPTimeStamp + 20*(48000/1000) >= now) {
     761           0 :             TimeDuration t = TimeStamp::Now() - mProcessing[0].mTimeStamp;
     762             :             // Wrap-around?
     763           0 :             int64_t delta = t.ToMilliseconds() + (now - mProcessing[0].mRTPTimeStamp)/(48000/1000);
     764           0 :             LogTime(AsyncLatencyLogger::AudioRecvRTP, ((uint64_t) this), delta);
     765           0 :             break;
     766             :           }
     767           0 :           mProcessing.RemoveElementAt(0);
     768             :         }
     769             :       }
     770             :     }
     771             :   }
     772           0 :   CSFLogDebug(logTag,"%s GetAudioFrame:Got samples: length %d ",__FUNCTION__,
     773           0 :                                                                lengthSamples);
     774           0 :   return kMediaConduitNoError;
     775             : }
     776             : 
     777             : // Transport Layer Callbacks
     778             : MediaConduitErrorCode
     779           0 : WebrtcAudioConduit::ReceivedRTPPacket(const void *data, int len, uint32_t ssrc)
     780             : {
     781           0 :   CSFLogDebug(logTag,  "%s : channel %d", __FUNCTION__, mChannel);
     782             : 
     783           0 :   if(mEngineReceiving)
     784             :   {
     785           0 :     if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
     786             :       // timestamp is at 32 bits in ([1])
     787             :       struct Processing insert = { TimeStamp::Now(),
     788           0 :                                    ntohl(static_cast<const uint32_t *>(data)[1]) };
     789           0 :       mProcessing.AppendElement(insert);
     790             :     }
     791             : 
     792             :     // XXX we need to get passed the time the packet was received
     793           0 :     if(mPtrVoENetwork->ReceivedRTPPacket(mChannel, data, len) == -1)
     794             :     {
     795           0 :       int error = mPtrVoEBase->LastError();
     796           0 :       CSFLogError(logTag, "%s RTP Processing Error %d", __FUNCTION__, error);
     797           0 :       if(error == VE_RTP_RTCP_MODULE_ERROR)
     798             :       {
     799           0 :         return kMediaConduitRTPRTCPModuleError;
     800             :       }
     801           0 :       return kMediaConduitUnknownError;
     802             :     }
     803             :   } else {
     804           0 :     CSFLogError(logTag, "Error: %s when not receiving", __FUNCTION__);
     805           0 :     return kMediaConduitSessionNotInited;
     806             :   }
     807             : 
     808           0 :   return kMediaConduitNoError;
     809             : }
     810             : 
     811             : MediaConduitErrorCode
     812           0 : WebrtcAudioConduit::ReceivedRTCPPacket(const void *data, int len)
     813             : {
     814           0 :   CSFLogDebug(logTag,  "%s : channel %d",__FUNCTION__, mChannel);
     815             : 
     816           0 :   if(mPtrVoENetwork->ReceivedRTCPPacket(mChannel, data, len) == -1)
     817             :   {
     818           0 :     int error = mPtrVoEBase->LastError();
     819           0 :     CSFLogError(logTag, "%s RTCP Processing Error %d", __FUNCTION__, error);
     820           0 :     if(error == VE_RTP_RTCP_MODULE_ERROR)
     821             :     {
     822           0 :       return kMediaConduitRTPRTCPModuleError;
     823             :     }
     824           0 :     return kMediaConduitUnknownError;
     825             :   }
     826           0 :   return kMediaConduitNoError;
     827             : }
     828             : 
     829             : MediaConduitErrorCode
     830           0 : WebrtcAudioConduit::StopTransmitting()
     831             : {
     832           0 :   if(mEngineTransmitting)
     833             :   {
     834           0 :     CSFLogDebug(logTag, "%s Engine Already Sending. Attemping to Stop ", __FUNCTION__);
     835           0 :     if(mPtrVoEBase->StopSend(mChannel) == -1)
     836             :     {
     837           0 :       CSFLogError(logTag, "%s StopSend() Failed %d ", __FUNCTION__,
     838           0 :                   mPtrVoEBase->LastError());
     839           0 :       return kMediaConduitUnknownError;
     840             :     }
     841           0 :     mEngineTransmitting = false;
     842             :   }
     843             : 
     844           0 :   return kMediaConduitNoError;
     845             : }
     846             : 
     847             : MediaConduitErrorCode
     848           0 : WebrtcAudioConduit::StartTransmitting()
     849             : {
     850           0 :   if (!mEngineTransmitting) {
     851             :     //Let's Send Transport State-machine on the Engine
     852           0 :     if(mPtrVoEBase->StartSend(mChannel) == -1)
     853             :     {
     854           0 :       int error = mPtrVoEBase->LastError();
     855           0 :       CSFLogError(logTag, "%s StartSend failed %d", __FUNCTION__, error);
     856           0 :       return kMediaConduitUnknownError;
     857             :     }
     858           0 :     mEngineTransmitting = true;
     859             :   }
     860             : 
     861           0 :   return kMediaConduitNoError;
     862             : }
     863             : 
     864             : MediaConduitErrorCode
     865           0 : WebrtcAudioConduit::StopReceiving()
     866             : {
     867           0 :   if(mEngineReceiving)
     868             :   {
     869           0 :     CSFLogDebug(logTag, "%s Engine Already Receiving. Attemping to Stop ", __FUNCTION__);
     870             :     // AudioEngine doesn't fail fatally on stopping reception. Ref:voe_errors.h.
     871             :     // hence we need not be strict in failing here on errors
     872           0 :     mPtrVoEBase->StopReceive(mChannel);
     873           0 :     CSFLogDebug(logTag, "%s Attemping to Stop playout ", __FUNCTION__);
     874           0 :     if(mPtrVoEBase->StopPlayout(mChannel) == -1)
     875             :     {
     876           0 :       if( mPtrVoEBase->LastError() == VE_CANNOT_STOP_PLAYOUT)
     877             :       {
     878           0 :         CSFLogDebug(logTag, "%s Stop-Playout Failed %d", __FUNCTION__, mPtrVoEBase->LastError());
     879           0 :         return kMediaConduitPlayoutError;
     880             :       }
     881             :     }
     882           0 :     mEngineReceiving = false;
     883             :   }
     884             : 
     885           0 :   return kMediaConduitNoError;
     886             : }
     887             : 
     888             : MediaConduitErrorCode
     889           0 : WebrtcAudioConduit::StartReceiving()
     890             : {
     891           0 :   if (!mEngineReceiving) {
     892           0 :     if(mPtrVoEBase->StartReceive(mChannel) == -1)
     893             :     {
     894           0 :       int error = mPtrVoEBase->LastError();
     895           0 :       CSFLogError(logTag ,  "%s StartReceive Failed %d ",__FUNCTION__, error);
     896           0 :       if(error == VE_RECV_SOCKET_ERROR)
     897             :       {
     898           0 :         return kMediaConduitSocketError;
     899             :       }
     900           0 :       return kMediaConduitUnknownError;
     901             :     }
     902             : 
     903           0 :     if(mPtrVoEBase->StartPlayout(mChannel) == -1)
     904             :     {
     905           0 :       CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__);
     906           0 :       return kMediaConduitPlayoutError;
     907             :     }
     908           0 :     mEngineReceiving = true;
     909             :   }
     910             : 
     911           0 :   return kMediaConduitNoError;
     912             : }
     913             : 
     914             : //WebRTC::RTP Callback Implementation
     915             : // Called on AudioGUM or MSG thread
     916             : bool
     917           0 : WebrtcAudioConduit::SendRtp(const uint8_t* data,
     918             :                             size_t len,
     919             :                             const webrtc::PacketOptions& options)
     920             : {
     921           0 :   CSFLogDebug(logTag,  "%s: len %lu", __FUNCTION__, (unsigned long)len);
     922             : 
     923           0 :   if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
     924           0 :     if (mProcessing.Length() > 0) {
     925           0 :       TimeStamp started = mProcessing[0].mTimeStamp;
     926           0 :       mProcessing.RemoveElementAt(0);
     927           0 :       mProcessing.RemoveElementAt(0); // 20ms packetization!  Could automate this by watching sizes
     928           0 :       TimeDuration t = TimeStamp::Now() - started;
     929           0 :       int64_t delta = t.ToMilliseconds();
     930           0 :       LogTime(AsyncLatencyLogger::AudioSendRTP, ((uint64_t) this), delta);
     931             :     }
     932             :   }
     933           0 :   ReentrantMonitorAutoEnter enter(mTransportMonitor);
     934             :   // XXX(pkerr) - the PacketOptions are being ignored. This parameter was added along
     935             :   // with the Call API update in the webrtc.org codebase.
     936             :   // The only field in it is the packet_id, which is used when the header
     937             :   // extension for TransportSequenceNumber is being used, which we don't.
     938             :   (void)options;
     939           0 :   if(mTransmitterTransport &&
     940           0 :      (mTransmitterTransport->SendRtpPacket(data, len) == NS_OK))
     941             :   {
     942           0 :     CSFLogDebug(logTag, "%s Sent RTP Packet ", __FUNCTION__);
     943           0 :     return true;
     944             :   }
     945           0 :   CSFLogError(logTag, "%s RTP Packet Send Failed ", __FUNCTION__);
     946           0 :   return false;
     947             : }
     948             : 
     949             : // Called on WebRTC Process thread and perhaps others
     950             : bool
     951           0 : WebrtcAudioConduit::SendRtcp(const uint8_t* data, size_t len)
     952             : {
     953           0 :   CSFLogDebug(logTag, "%s : len %lu, first rtcp = %u ",
     954             :               __FUNCTION__,
     955             :               (unsigned long) len,
     956           0 :               static_cast<unsigned>(data[1]));
     957             : 
     958             :   // We come here if we have only one pipeline/conduit setup,
     959             :   // such as for unidirectional streams.
     960             :   // We also end up here if we are receiving
     961           0 :   ReentrantMonitorAutoEnter enter(mTransportMonitor);
     962           0 :   if(mReceiverTransport &&
     963           0 :      mReceiverTransport->SendRtcpPacket(data, len) == NS_OK)
     964             :   {
     965             :     // Might be a sender report, might be a receiver report, we don't know.
     966           0 :     CSFLogDebug(logTag, "%s Sent RTCP Packet ", __FUNCTION__);
     967           0 :     return true;
     968             :   }
     969           0 :   if (mTransmitterTransport &&
     970           0 :       (mTransmitterTransport->SendRtcpPacket(data, len) == NS_OK)) {
     971           0 :     CSFLogDebug(logTag, "%s Sent RTCP Packet (sender report) ", __FUNCTION__);
     972           0 :     return true;
     973             :   }
     974           0 :   CSFLogError(logTag, "%s RTCP Packet Send Failed ", __FUNCTION__);
     975           0 :   return false;
     976             : }
     977             : 
     978             : /**
     979             :  * Converts between CodecConfig to WebRTC Codec Structure.
     980             :  */
     981             : 
     982             : bool
     983           0 : WebrtcAudioConduit::CodecConfigToWebRTCCodec(const AudioCodecConfig* codecInfo,
     984             :                                               webrtc::CodecInst& cinst)
     985             : {
     986           0 :   const unsigned int plNameLength = codecInfo->mName.length();
     987           0 :   memset(&cinst, 0, sizeof(webrtc::CodecInst));
     988           0 :   if(sizeof(cinst.plname) < plNameLength+1)
     989             :   {
     990             :     CSFLogError(logTag, "%s Payload name buffer capacity mismatch ",
     991           0 :                                                       __FUNCTION__);
     992           0 :     return false;
     993             :   }
     994           0 :   memcpy(cinst.plname, codecInfo->mName.c_str(), plNameLength);
     995           0 :   cinst.plname[plNameLength]='\0';
     996           0 :   cinst.pltype   =  codecInfo->mType;
     997           0 :   cinst.rate     =  codecInfo->mRate;
     998           0 :   cinst.pacsize  =  codecInfo->mPacSize;
     999           0 :   cinst.plfreq   =  codecInfo->mFreq;
    1000           0 :   if (codecInfo->mName == "G722") {
    1001             :     // Compensate for G.722 spec error in RFC 1890
    1002           0 :     cinst.plfreq = 16000;
    1003             :   }
    1004           0 :   cinst.channels =  codecInfo->mChannels;
    1005           0 :   return true;
    1006             : }
    1007             : 
    1008             : /**
    1009             :   *  Supported Sampling Frequencies.
    1010             :   */
    1011             : bool
    1012           0 : WebrtcAudioConduit::IsSamplingFreqSupported(int freq) const
    1013             : {
    1014           0 :   return GetNum10msSamplesForFrequency(freq) != 0;
    1015             : }
    1016             : 
    1017             : /* Return block-length of 10 ms audio frame in number of samples */
    1018             : unsigned int
    1019           0 : WebrtcAudioConduit::GetNum10msSamplesForFrequency(int samplingFreqHz) const
    1020             : {
    1021           0 :   switch (samplingFreqHz)
    1022             :   {
    1023           0 :     case 16000: return 160; //160 samples
    1024           0 :     case 32000: return 320; //320 samples
    1025           0 :     case 44100: return 441; //441 samples
    1026           0 :     case 48000: return 480; //480 samples
    1027           0 :     default:    return 0; // invalid or unsupported
    1028             :   }
    1029             : }
    1030             : 
    1031             : //Copy the codec passed into Conduit's database
    1032             : bool
    1033           0 : WebrtcAudioConduit::CopyCodecToDB(const AudioCodecConfig* codecInfo)
    1034             : {
    1035             : 
    1036           0 :   AudioCodecConfig* cdcConfig = new AudioCodecConfig(codecInfo->mType,
    1037             :                                                      codecInfo->mName,
    1038           0 :                                                      codecInfo->mFreq,
    1039           0 :                                                      codecInfo->mPacSize,
    1040           0 :                                                      codecInfo->mChannels,
    1041           0 :                                                      codecInfo->mRate,
    1042           0 :                                                      codecInfo->mFECEnabled);
    1043           0 :   mRecvCodecList.push_back(cdcConfig);
    1044           0 :   return true;
    1045             : }
    1046             : 
    1047             : /**
    1048             :  * Checks if 2 codec structs are same
    1049             :  */
    1050             : bool
    1051           0 : WebrtcAudioConduit::CheckCodecsForMatch(const AudioCodecConfig* curCodecConfig,
    1052             :                                          const AudioCodecConfig* codecInfo) const
    1053             : {
    1054           0 :   if(!curCodecConfig)
    1055             :   {
    1056           0 :     return false;
    1057             :   }
    1058             : 
    1059           0 :   if(curCodecConfig->mType   == codecInfo->mType &&
    1060           0 :       (curCodecConfig->mName.compare(codecInfo->mName) == 0) &&
    1061           0 :       curCodecConfig->mFreq   == codecInfo->mFreq &&
    1062           0 :       curCodecConfig->mPacSize == codecInfo->mPacSize &&
    1063           0 :       curCodecConfig->mChannels == codecInfo->mChannels &&
    1064           0 :       curCodecConfig->mRate == codecInfo->mRate)
    1065             :   {
    1066           0 :     return true;
    1067             :   }
    1068             : 
    1069           0 :   return false;
    1070             : }
    1071             : 
    1072             : /**
    1073             :  * Checks if the codec is already in Conduit's database
    1074             :  */
    1075             : bool
    1076           0 : WebrtcAudioConduit::CheckCodecForMatch(const AudioCodecConfig* codecInfo) const
    1077             : {
    1078             :   //the db should have atleast one codec
    1079           0 :   for(auto codec : mRecvCodecList)
    1080             :   {
    1081           0 :     if(CheckCodecsForMatch(codec,codecInfo))
    1082             :     {
    1083             :       //match
    1084           0 :       return true;
    1085             :     }
    1086             :   }
    1087             :   //no match or empty local db
    1088           0 :   return false;
    1089             : }
    1090             : 
    1091             : 
    1092             : /**
    1093             :  * Perform validation on the codecConfig to be applied.
    1094             :  * Verifies if the codec is already applied.
    1095             :  */
    1096             : MediaConduitErrorCode
    1097           0 : WebrtcAudioConduit::ValidateCodecConfig(const AudioCodecConfig* codecInfo,
    1098             :                                         bool send)
    1099             : {
    1100           0 :   bool codecAppliedAlready = false;
    1101             : 
    1102           0 :   if(!codecInfo)
    1103             :   {
    1104           0 :     CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
    1105           0 :     return kMediaConduitMalformedArgument;
    1106             :   }
    1107             : 
    1108           0 :   if((codecInfo->mName.empty()) ||
    1109           0 :      (codecInfo->mName.length() >= CODEC_PLNAME_SIZE))
    1110             :   {
    1111           0 :     CSFLogError(logTag, "%s Invalid Payload Name Length ", __FUNCTION__);
    1112           0 :     return kMediaConduitMalformedArgument;
    1113             :   }
    1114             : 
    1115             :   //Only mono or stereo channels supported
    1116           0 :   if( (codecInfo->mChannels != 1) && (codecInfo->mChannels != 2))
    1117             :   {
    1118           0 :     CSFLogError(logTag, "%s Channel Unsupported ", __FUNCTION__);
    1119           0 :     return kMediaConduitMalformedArgument;
    1120             :   }
    1121             : 
    1122             :   //check if we have the same codec already applied
    1123           0 :   if(send)
    1124             :   {
    1125           0 :     MutexAutoLock lock(mCodecMutex);
    1126             : 
    1127           0 :     codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
    1128             :   } else {
    1129           0 :     codecAppliedAlready = CheckCodecForMatch(codecInfo);
    1130             :   }
    1131             : 
    1132           0 :   if(codecAppliedAlready)
    1133             :   {
    1134           0 :     CSFLogDebug(logTag, "%s Codec %s Already Applied  ", __FUNCTION__, codecInfo->mName.c_str());
    1135             :   }
    1136           0 :   return kMediaConduitNoError;
    1137             : }
    1138             : 
    1139             : void
    1140           0 : WebrtcAudioConduit::DumpCodecDB() const
    1141             :  {
    1142           0 :     for(auto& codec : mRecvCodecList)
    1143             :     {
    1144           0 :       CSFLogDebug(logTag,"Payload Name: %s", codec->mName.c_str());
    1145           0 :       CSFLogDebug(logTag,"Payload Type: %d", codec->mType);
    1146           0 :       CSFLogDebug(logTag,"Payload Frequency: %d", codec->mFreq);
    1147           0 :       CSFLogDebug(logTag,"Payload PacketSize: %d", codec->mPacSize);
    1148           0 :       CSFLogDebug(logTag,"Payload Channels: %d", codec->mChannels);
    1149           0 :       CSFLogDebug(logTag,"Payload Sampling Rate: %d", codec->mRate);
    1150             :     }
    1151           0 :  }
    1152             : }// end namespace

Generated by: LCOV version 1.13