media/webrtc/signaling/src/media-conduit/AudioConduit.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1040 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "CSFLog.h"
     1.9 +#include "nspr.h"
    1.10 +
    1.11 +#ifdef HAVE_NETINET_IN_H
    1.12 +#include <netinet/in.h>
    1.13 +#elif defined XP_WIN
    1.14 +#include <winsock2.h>
    1.15 +#endif
    1.16 +
    1.17 +#include "AudioConduit.h"
    1.18 +#include "nsCOMPtr.h"
    1.19 +#include "mozilla/Services.h"
    1.20 +#include "nsServiceManagerUtils.h"
    1.21 +#include "nsIPrefService.h"
    1.22 +#include "nsIPrefBranch.h"
    1.23 +#include "nsThreadUtils.h"
    1.24 +#ifdef MOZILLA_INTERNAL_API
    1.25 +#include "Latency.h"
    1.26 +#include "mozilla/Telemetry.h"
    1.27 +#endif
    1.28 +
    1.29 +#include "webrtc/voice_engine/include/voe_errors.h"
    1.30 +#include "webrtc/system_wrappers/interface/clock.h"
    1.31 +
    1.32 +#ifdef MOZ_WIDGET_ANDROID
    1.33 +#include "AndroidJNIWrapper.h"
    1.34 +#endif
    1.35 +
    1.36 +namespace mozilla {
    1.37 +
    1.38 +static const char* logTag ="WebrtcAudioSessionConduit";
    1.39 +
    1.40 +// 32 bytes is what WebRTC CodecInst expects
    1.41 +const unsigned int WebrtcAudioConduit::CODEC_PLNAME_SIZE = 32;
    1.42 +
    1.43 +/**
    1.44 + * Factory Method for AudioConduit
    1.45 + */
    1.46 +mozilla::RefPtr<AudioSessionConduit> AudioSessionConduit::Create(AudioSessionConduit *aOther)
    1.47 +{
    1.48 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
    1.49 +#ifdef MOZILLA_INTERNAL_API
    1.50 +  // unit tests create their own "main thread"
    1.51 +  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
    1.52 +#endif
    1.53 +
    1.54 +  WebrtcAudioConduit* obj = new WebrtcAudioConduit();
    1.55 +  if(obj->Init(static_cast<WebrtcAudioConduit*>(aOther)) != kMediaConduitNoError)
    1.56 +  {
    1.57 +    CSFLogError(logTag,  "%s AudioConduit Init Failed ", __FUNCTION__);
    1.58 +    delete obj;
    1.59 +    return nullptr;
    1.60 +  }
    1.61 +  CSFLogDebug(logTag,  "%s Successfully created AudioConduit ", __FUNCTION__);
    1.62 +  return obj;
    1.63 +}
    1.64 +
    1.65 +/**
    1.66 + * Destruction defines for our super-classes
    1.67 + */
    1.68 +WebrtcAudioConduit::~WebrtcAudioConduit()
    1.69 +{
    1.70 +#ifdef MOZILLA_INTERNAL_API
    1.71 +  // unit tests create their own "main thread"
    1.72 +  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
    1.73 +#endif
    1.74 +
    1.75 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
    1.76 +  for(std::vector<AudioCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
    1.77 +  {
    1.78 +    delete mRecvCodecList[i];
    1.79 +  }
    1.80 +  delete mCurSendCodecConfig;
    1.81 +
    1.82 +  // The first one of a pair to be deleted shuts down media for both
    1.83 +  if(mPtrVoEXmedia)
    1.84 +  {
    1.85 +    if (!mShutDown) {
    1.86 +      mPtrVoEXmedia->SetExternalRecordingStatus(false);
    1.87 +      mPtrVoEXmedia->SetExternalPlayoutStatus(false);
    1.88 +    }
    1.89 +  }
    1.90 +
    1.91 +  //Deal with the transport
    1.92 +  if(mPtrVoENetwork)
    1.93 +  {
    1.94 +    if (!mShutDown) {
    1.95 +      mPtrVoENetwork->DeRegisterExternalTransport(mChannel);
    1.96 +    }
    1.97 +  }
    1.98 +
    1.99 +  if(mPtrVoEBase)
   1.100 +  {
   1.101 +    if (!mShutDown) {
   1.102 +      mPtrVoEBase->StopPlayout(mChannel);
   1.103 +      mPtrVoEBase->StopSend(mChannel);
   1.104 +      mPtrVoEBase->StopReceive(mChannel);
   1.105 +      mPtrVoEBase->DeleteChannel(mChannel);
   1.106 +      mPtrVoEBase->Terminate();
   1.107 +    }
   1.108 +  }
   1.109 +
   1.110 +  if (mOtherDirection)
   1.111 +  {
   1.112 +    // mOtherDirection owns these now!
   1.113 +    mOtherDirection->mOtherDirection = nullptr;
   1.114 +    // let other side we terminated the channel
   1.115 +    mOtherDirection->mShutDown = true;
   1.116 +    mVoiceEngine = nullptr;
   1.117 +  } else {
   1.118 +    // We shouldn't delete the VoiceEngine until all these are released!
   1.119 +    // And we can't use a Scoped ptr, since the order is arbitrary
   1.120 +    mPtrVoENetwork = nullptr;
   1.121 +    mPtrVoEBase = nullptr;
   1.122 +    mPtrVoECodec = nullptr;
   1.123 +    mPtrVoEXmedia = nullptr;
   1.124 +    mPtrVoEProcessing = nullptr;
   1.125 +    mPtrVoEVideoSync = nullptr;
   1.126 +    mPtrVoERTP_RTCP = nullptr;
   1.127 +    mPtrRTP = nullptr;
   1.128 +
   1.129 +    // only one opener can call Delete.  Have it be the last to close.
   1.130 +    if(mVoiceEngine)
   1.131 +    {
   1.132 +      webrtc::VoiceEngine::Delete(mVoiceEngine);
   1.133 +    }
   1.134 +  }
   1.135 +}
   1.136 +
   1.137 +bool WebrtcAudioConduit::GetLocalSSRC(unsigned int* ssrc) {
   1.138 +  return !mPtrRTP->GetLocalSSRC(mChannel, *ssrc);
   1.139 +}
   1.140 +
   1.141 +bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) {
   1.142 +  return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc);
   1.143 +}
   1.144 +
   1.145 +bool WebrtcAudioConduit::GetAVStats(int32_t* jitterBufferDelayMs,
   1.146 +                                    int32_t* playoutBufferDelayMs,
   1.147 +                                    int32_t* avSyncOffsetMs) {
   1.148 +  return !mPtrVoEVideoSync->GetDelayEstimate(mChannel,
   1.149 +                                             jitterBufferDelayMs,
   1.150 +                                             playoutBufferDelayMs,
   1.151 +                                             avSyncOffsetMs);
   1.152 +}
   1.153 +
   1.154 +bool WebrtcAudioConduit::GetRTPStats(unsigned int* jitterMs,
   1.155 +                                     unsigned int* cumulativeLost) {
   1.156 +  unsigned int maxJitterMs = 0;
   1.157 +  unsigned int discardedPackets;
   1.158 +  *jitterMs = 0;
   1.159 +  *cumulativeLost = 0;
   1.160 +  return !mPtrRTP->GetRTPStatistics(mChannel, *jitterMs, maxJitterMs,
   1.161 +                                    discardedPackets, *cumulativeLost);
   1.162 +}
   1.163 +
   1.164 +DOMHighResTimeStamp
   1.165 +NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow) {
   1.166 +  return (uint32_t(ntpHigh - webrtc::kNtpJan1970) +
   1.167 +          double(ntpLow) / webrtc::kMagicNtpFractionalUnit) * 1000;
   1.168 +}
   1.169 +
   1.170 +bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
   1.171 +                                               uint32_t* jitterMs,
   1.172 +                                               uint32_t* packetsReceived,
   1.173 +                                               uint64_t* bytesReceived,
   1.174 +                                               uint32_t* cumulativeLost,
   1.175 +                                               int32_t* rttMs) {
   1.176 +  uint32_t ntpHigh, ntpLow;
   1.177 +  uint16_t fractionLost;
   1.178 +  bool result = !mPtrRTP->GetRemoteRTCPReceiverInfo(mChannel, ntpHigh, ntpLow,
   1.179 +                                                    *packetsReceived,
   1.180 +                                                    *bytesReceived,
   1.181 +                                                    *jitterMs,
   1.182 +                                                    fractionLost,
   1.183 +                                                    *cumulativeLost,
   1.184 +                                                    *rttMs);
   1.185 +  if (result) {
   1.186 +    *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow);
   1.187 +  }
   1.188 +  return result;
   1.189 +}
   1.190 +
   1.191 +bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
   1.192 +                                             unsigned int* packetsSent,
   1.193 +                                             uint64_t* bytesSent) {
   1.194 +  struct webrtc::SenderInfo senderInfo;
   1.195 +  bool result = !mPtrRTP->GetRemoteRTCPSenderInfo(mChannel, &senderInfo);
   1.196 +  if (result) {
   1.197 +    *timestamp = NTPtoDOMHighResTimeStamp(senderInfo.NTP_timestamp_high,
   1.198 +                                          senderInfo.NTP_timestamp_low);
   1.199 +    *packetsSent = senderInfo.sender_packet_count;
   1.200 +    *bytesSent = senderInfo.sender_octet_count;
   1.201 +  }
   1.202 +  return result;
   1.203 +}
   1.204 +
   1.205 +/*
   1.206 + * WebRTCAudioConduit Implementation
   1.207 + */
   1.208 +MediaConduitErrorCode WebrtcAudioConduit::Init(WebrtcAudioConduit *other)
   1.209 +{
   1.210 +  CSFLogDebug(logTag,  "%s this=%p other=%p", __FUNCTION__, this, other);
   1.211 +
   1.212 +  if (other) {
   1.213 +    MOZ_ASSERT(!other->mOtherDirection);
   1.214 +    other->mOtherDirection = this;
   1.215 +    mOtherDirection = other;
   1.216 +
   1.217 +    // only one can call ::Create()/GetVoiceEngine()
   1.218 +    MOZ_ASSERT(other->mVoiceEngine);
   1.219 +    mVoiceEngine = other->mVoiceEngine;
   1.220 +  } else {
   1.221 +#ifdef MOZ_WIDGET_ANDROID
   1.222 +      jobject context = jsjni_GetGlobalContextRef();
   1.223 +
   1.224 +      // get the JVM
   1.225 +      JavaVM *jvm = jsjni_GetVM();
   1.226 +      JNIEnv* jenv = jsjni_GetJNIForThread();
   1.227 +
   1.228 +      if (webrtc::VoiceEngine::SetAndroidObjects(jvm, jenv, (void*)context) != 0) {
   1.229 +        CSFLogError(logTag, "%s Unable to set Android objects", __FUNCTION__);
   1.230 +        return kMediaConduitSessionNotInited;
   1.231 +      }
   1.232 +#endif
   1.233 +
   1.234 +    // Per WebRTC APIs below function calls return nullptr on failure
   1.235 +    if(!(mVoiceEngine = webrtc::VoiceEngine::Create()))
   1.236 +    {
   1.237 +      CSFLogError(logTag, "%s Unable to create voice engine", __FUNCTION__);
   1.238 +      return kMediaConduitSessionNotInited;
   1.239 +    }
   1.240 +
   1.241 +    PRLogModuleInfo *logs = GetWebRTCLogInfo();
   1.242 +    if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
   1.243 +      // no need to a critical section or lock here
   1.244 +      gWebrtcTraceLoggingOn = 1;
   1.245 +
   1.246 +      const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
   1.247 +      if (!file) {
   1.248 +        file = "WebRTC.log";
   1.249 +      }
   1.250 +      CSFLogDebug(logTag,  "%s Logging webrtc to %s level %d", __FUNCTION__,
   1.251 +                  file, logs->level);
   1.252 +      mVoiceEngine->SetTraceFilter(logs->level);
   1.253 +      mVoiceEngine->SetTraceFile(file);
   1.254 +    }
   1.255 +  }
   1.256 +
   1.257 +  if(!(mPtrVoEBase = VoEBase::GetInterface(mVoiceEngine)))
   1.258 +  {
   1.259 +    CSFLogError(logTag, "%s Unable to initialize VoEBase", __FUNCTION__);
   1.260 +    return kMediaConduitSessionNotInited;
   1.261 +  }
   1.262 +
   1.263 +  if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
   1.264 +  {
   1.265 +    CSFLogError(logTag, "%s Unable to initialize VoENetwork", __FUNCTION__);
   1.266 +    return kMediaConduitSessionNotInited;
   1.267 +  }
   1.268 +
   1.269 +  if(!(mPtrVoECodec = VoECodec::GetInterface(mVoiceEngine)))
   1.270 +  {
   1.271 +    CSFLogError(logTag, "%s Unable to initialize VoEBCodec", __FUNCTION__);
   1.272 +    return kMediaConduitSessionNotInited;
   1.273 +  }
   1.274 +
   1.275 +  if(!(mPtrVoEProcessing = VoEAudioProcessing::GetInterface(mVoiceEngine)))
   1.276 +  {
   1.277 +    CSFLogError(logTag, "%s Unable to initialize VoEProcessing", __FUNCTION__);
   1.278 +    return kMediaConduitSessionNotInited;
   1.279 +  }
   1.280 +  if(!(mPtrVoEXmedia = VoEExternalMedia::GetInterface(mVoiceEngine)))
   1.281 +  {
   1.282 +    CSFLogError(logTag, "%s Unable to initialize VoEExternalMedia", __FUNCTION__);
   1.283 +    return kMediaConduitSessionNotInited;
   1.284 +  }
   1.285 +  if(!(mPtrVoERTP_RTCP = VoERTP_RTCP::GetInterface(mVoiceEngine)))
   1.286 +  {
   1.287 +    CSFLogError(logTag, "%s Unable to initialize VoERTP_RTCP", __FUNCTION__);
   1.288 +    return kMediaConduitSessionNotInited;
   1.289 +  }
   1.290 +
   1.291 +  if(!(mPtrVoEVideoSync = VoEVideoSync::GetInterface(mVoiceEngine)))
   1.292 +  {
   1.293 +    CSFLogError(logTag, "%s Unable to initialize VoEVideoSync", __FUNCTION__);
   1.294 +    return kMediaConduitSessionNotInited;
   1.295 +  }
   1.296 +  if (!(mPtrRTP = webrtc::VoERTP_RTCP::GetInterface(mVoiceEngine)))
   1.297 +  {
   1.298 +    CSFLogError(logTag, "%s Unable to get audio RTP/RTCP interface ",
   1.299 +                __FUNCTION__);
   1.300 +    return kMediaConduitSessionNotInited;
   1.301 +  }
   1.302 +
   1.303 +  if (other) {
   1.304 +    mChannel = other->mChannel;
   1.305 +  } else {
   1.306 +    // init the engine with our audio device layer
   1.307 +    if(mPtrVoEBase->Init() == -1)
   1.308 +    {
   1.309 +      CSFLogError(logTag, "%s VoiceEngine Base Not Initialized", __FUNCTION__);
   1.310 +      return kMediaConduitSessionNotInited;
   1.311 +    }
   1.312 +
   1.313 +    if( (mChannel = mPtrVoEBase->CreateChannel()) == -1)
   1.314 +    {
   1.315 +      CSFLogError(logTag, "%s VoiceEngine Channel creation failed",__FUNCTION__);
   1.316 +      return kMediaConduitChannelError;
   1.317 +    }
   1.318 +
   1.319 +    CSFLogDebug(logTag, "%s Channel Created %d ",__FUNCTION__, mChannel);
   1.320 +
   1.321 +    if(mPtrVoENetwork->RegisterExternalTransport(mChannel, *this) == -1)
   1.322 +    {
   1.323 +      CSFLogError(logTag, "%s VoiceEngine, External Transport Failed",__FUNCTION__);
   1.324 +      return kMediaConduitTransportRegistrationFail;
   1.325 +    }
   1.326 +
   1.327 +    if(mPtrVoEXmedia->SetExternalRecordingStatus(true) == -1)
   1.328 +    {
   1.329 +      CSFLogError(logTag, "%s SetExternalRecordingStatus Failed %d",__FUNCTION__,
   1.330 +                  mPtrVoEBase->LastError());
   1.331 +      return kMediaConduitExternalPlayoutError;
   1.332 +    }
   1.333 +
   1.334 +    if(mPtrVoEXmedia->SetExternalPlayoutStatus(true) == -1)
   1.335 +    {
   1.336 +      CSFLogError(logTag, "%s SetExternalPlayoutStatus Failed %d ",__FUNCTION__,
   1.337 +                  mPtrVoEBase->LastError());
   1.338 +      return kMediaConduitExternalRecordingError;
   1.339 +    }
   1.340 +    CSFLogDebug(logTag ,  "%s AudioSessionConduit Initialization Done (%p)",__FUNCTION__, this);
   1.341 +  }
   1.342 +  return kMediaConduitNoError;
   1.343 +}
   1.344 +
   1.345 +// AudioSessionConduit Implementation
   1.346 +MediaConduitErrorCode
   1.347 +WebrtcAudioConduit::AttachTransport(mozilla::RefPtr<TransportInterface> aTransport)
   1.348 +{
   1.349 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   1.350 +
   1.351 +  if(!aTransport)
   1.352 +  {
   1.353 +    CSFLogError(logTag, "%s NULL Transport", __FUNCTION__);
   1.354 +    return kMediaConduitInvalidTransport;
   1.355 +  }
   1.356 +  // set the transport
   1.357 +  mTransport = aTransport;
   1.358 +  return kMediaConduitNoError;
   1.359 +}
   1.360 +
   1.361 +MediaConduitErrorCode
   1.362 +WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
   1.363 +{
   1.364 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   1.365 +  MediaConduitErrorCode condError = kMediaConduitNoError;
   1.366 +  int error = 0;//webrtc engine errors
   1.367 +  webrtc::CodecInst cinst;
   1.368 +
   1.369 +  //validate codec param
   1.370 +  if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
   1.371 +  {
   1.372 +    return condError;
   1.373 +  }
   1.374 +
   1.375 +  //are we transmitting already, stop and apply the send codec
   1.376 +  if(mEngineTransmitting)
   1.377 +  {
   1.378 +    CSFLogDebug(logTag, "%s Engine Already Sending. Attemping to Stop ", __FUNCTION__);
   1.379 +    if(mPtrVoEBase->StopSend(mChannel) == -1)
   1.380 +    {
   1.381 +      CSFLogError(logTag, "%s StopSend() Failed %d ", __FUNCTION__,
   1.382 +                  mPtrVoEBase->LastError());
   1.383 +      return kMediaConduitUnknownError;
   1.384 +    }
   1.385 +  }
   1.386 +
   1.387 +  mEngineTransmitting = false;
   1.388 +
   1.389 +  if(!CodecConfigToWebRTCCodec(codecConfig,cinst))
   1.390 +  {
   1.391 +    CSFLogError(logTag,"%s CodecConfig to WebRTC Codec Failed ",__FUNCTION__);
   1.392 +    return kMediaConduitMalformedArgument;
   1.393 +  }
   1.394 +
   1.395 +  if(mPtrVoECodec->SetSendCodec(mChannel, cinst) == -1)
   1.396 +  {
   1.397 +    error = mPtrVoEBase->LastError();
   1.398 +    CSFLogError(logTag, "%s SetSendCodec - Invalid Codec %d ",__FUNCTION__,
   1.399 +                                                                    error);
   1.400 +
   1.401 +    if(error ==  VE_CANNOT_SET_SEND_CODEC || error == VE_CODEC_ERROR)
   1.402 +    {
   1.403 +      CSFLogError(logTag, "%s Invalid Send Codec", __FUNCTION__);
   1.404 +      return kMediaConduitInvalidSendCodec;
   1.405 +    }
   1.406 +    CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
   1.407 +                                         mPtrVoEBase->LastError());
   1.408 +    return kMediaConduitUnknownError;
   1.409 +  }
   1.410 +
   1.411 +#ifdef MOZILLA_INTERNAL_API
   1.412 +  // TEMPORARY - see bug 694814 comment 2
   1.413 +  nsresult rv;
   1.414 +  nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
   1.415 +  if (NS_SUCCEEDED(rv)) {
   1.416 +    nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
   1.417 +
   1.418 +    if (branch) {
   1.419 +      branch->GetIntPref("media.peerconnection.capture_delay", &mCaptureDelay);
   1.420 +    }
   1.421 +  }
   1.422 +#endif
   1.423 +
   1.424 +  //Let's Send Transport State-machine on the Engine
   1.425 +  if(mPtrVoEBase->StartSend(mChannel) == -1)
   1.426 +  {
   1.427 +    error = mPtrVoEBase->LastError();
   1.428 +    CSFLogError(logTag, "%s StartSend failed %d", __FUNCTION__, error);
   1.429 +    return kMediaConduitUnknownError;
   1.430 +  }
   1.431 +
   1.432 +  //Copy the applied config for future reference.
   1.433 +  delete mCurSendCodecConfig;
   1.434 +
   1.435 +  mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
   1.436 +                                              codecConfig->mName,
   1.437 +                                              codecConfig->mFreq,
   1.438 +                                              codecConfig->mPacSize,
   1.439 +                                              codecConfig->mChannels,
   1.440 +                                              codecConfig->mRate,
   1.441 +                                              codecConfig->mLoadManager);
   1.442 +
   1.443 +  mEngineTransmitting = true;
   1.444 +  return kMediaConduitNoError;
   1.445 +}
   1.446 +
   1.447 +MediaConduitErrorCode
   1.448 +WebrtcAudioConduit::ConfigureRecvMediaCodecs(
   1.449 +                    const std::vector<AudioCodecConfig*>& codecConfigList)
   1.450 +{
   1.451 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   1.452 +  MediaConduitErrorCode condError = kMediaConduitNoError;
   1.453 +  int error = 0; //webrtc engine errors
   1.454 +  bool success = false;
   1.455 +
   1.456 +  // Are we receiving already? If so, stop receiving and playout
   1.457 +  // since we can't apply new recv codec when the engine is playing.
   1.458 +  if(mEngineReceiving)
   1.459 +  {
   1.460 +    CSFLogDebug(logTag, "%s Engine Already Receiving. Attemping to Stop ", __FUNCTION__);
   1.461 +    // AudioEngine doesn't fail fatally on stopping reception. Ref:voe_errors.h.
   1.462 +    // hence we need not be strict in failing here on errors
   1.463 +    mPtrVoEBase->StopReceive(mChannel);
   1.464 +    CSFLogDebug(logTag, "%s Attemping to Stop playout ", __FUNCTION__);
   1.465 +    if(mPtrVoEBase->StopPlayout(mChannel) == -1)
   1.466 +    {
   1.467 +      if( mPtrVoEBase->LastError() == VE_CANNOT_STOP_PLAYOUT)
   1.468 +      {
   1.469 +        CSFLogDebug(logTag, "%s Stop-Playout Failed %d", __FUNCTION__, mPtrVoEBase->LastError());
   1.470 +        return kMediaConduitPlayoutError;
   1.471 +      }
   1.472 +    }
   1.473 +  }
   1.474 +
   1.475 +  mEngineReceiving = false;
   1.476 +
   1.477 +  if(codecConfigList.empty())
   1.478 +  {
   1.479 +    CSFLogError(logTag, "%s Zero number of codecs to configure", __FUNCTION__);
   1.480 +    return kMediaConduitMalformedArgument;
   1.481 +  }
   1.482 +
   1.483 +  // Try Applying the codecs in the list.
   1.484 +  // We succeed if at least one codec was applied and reception was
   1.485 +  // started successfully.
   1.486 +  for(std::vector<AudioCodecConfig*>::size_type i=0 ;i<codecConfigList.size();i++)
   1.487 +  {
   1.488 +    //if the codec param is invalid or diplicate, return error
   1.489 +    if((condError = ValidateCodecConfig(codecConfigList[i],false)) != kMediaConduitNoError)
   1.490 +    {
   1.491 +      return condError;
   1.492 +    }
   1.493 +
   1.494 +    webrtc::CodecInst cinst;
   1.495 +    if(!CodecConfigToWebRTCCodec(codecConfigList[i],cinst))
   1.496 +    {
   1.497 +      CSFLogError(logTag,"%s CodecConfig to WebRTC Codec Failed ",__FUNCTION__);
   1.498 +      continue;
   1.499 +    }
   1.500 +
   1.501 +    if(mPtrVoECodec->SetRecPayloadType(mChannel,cinst) == -1)
   1.502 +    {
   1.503 +      error = mPtrVoEBase->LastError();
   1.504 +      CSFLogError(logTag,  "%s SetRecvCodec Failed %d ",__FUNCTION__, error);
   1.505 +      continue;
   1.506 +    } else {
   1.507 +      CSFLogDebug(logTag, "%s Successfully Set RecvCodec %s", __FUNCTION__,
   1.508 +                                          codecConfigList[i]->mName.c_str());
   1.509 +      //copy this to local database
   1.510 +      if(CopyCodecToDB(codecConfigList[i]))
   1.511 +      {
   1.512 +        success = true;
   1.513 +      } else {
   1.514 +        CSFLogError(logTag,"%s Unable to updated Codec Database", __FUNCTION__);
   1.515 +        return kMediaConduitUnknownError;
   1.516 +      }
   1.517 +
   1.518 +    }
   1.519 +
   1.520 +  } //end for
   1.521 +
   1.522 +  if(!success)
   1.523 +  {
   1.524 +    CSFLogError(logTag, "%s Setting Receive Codec Failed ", __FUNCTION__);
   1.525 +    return kMediaConduitInvalidReceiveCodec;
   1.526 +  }
   1.527 +
   1.528 +  //If we are here, atleast one codec should have been set
   1.529 +  if(mPtrVoEBase->StartReceive(mChannel) == -1)
   1.530 +  {
   1.531 +    error = mPtrVoEBase->LastError();
   1.532 +    CSFLogError(logTag ,  "%s StartReceive Failed %d ",__FUNCTION__, error);
   1.533 +    if(error == VE_RECV_SOCKET_ERROR)
   1.534 +    {
   1.535 +      return kMediaConduitSocketError;
   1.536 +    }
   1.537 +    return kMediaConduitUnknownError;
   1.538 +  }
   1.539 +
   1.540 +
   1.541 +  if(mPtrVoEBase->StartPlayout(mChannel) == -1)
   1.542 +  {
   1.543 +    CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__);
   1.544 +    return kMediaConduitPlayoutError;
   1.545 +  }
   1.546 +  //we should be good here for setting this.
   1.547 +  mEngineReceiving = true;
   1.548 +  DumpCodecDB();
   1.549 +  return kMediaConduitNoError;
   1.550 +}
   1.551 +MediaConduitErrorCode
   1.552 +WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled, uint8_t id)
   1.553 +{
   1.554 +  CSFLogDebug(logTag,  "%s %d %d ", __FUNCTION__, enabled, id);
   1.555 +
   1.556 +  if (mPtrVoERTP_RTCP->SetRTPAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
   1.557 +  {
   1.558 +    CSFLogError(logTag, "%s SetRTPAudioLevelIndicationStatus Failed", __FUNCTION__);
   1.559 +    return kMediaConduitUnknownError;
   1.560 +  }
   1.561 +
   1.562 +  return kMediaConduitNoError;
   1.563 +}
   1.564 +
   1.565 +MediaConduitErrorCode
   1.566 +WebrtcAudioConduit::SendAudioFrame(const int16_t audio_data[],
   1.567 +                                    int32_t lengthSamples,
   1.568 +                                    int32_t samplingFreqHz,
   1.569 +                                    int32_t capture_delay)
   1.570 +{
   1.571 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   1.572 +  // Following checks need to be performed
   1.573 +  // 1. Non null audio buffer pointer,
   1.574 +  // 2. invalid sampling frequency -  less than 0 or unsupported ones
   1.575 +  // 3. Appropriate Sample Length for 10 ms audio-frame. This represents
   1.576 +  //    block size the VoiceEngine feeds into encoder for passed in audio-frame
   1.577 +  //    Ex: for 16000 sampling rate , valid block-length is 160
   1.578 +  //    Similarly for 32000 sampling rate, valid block length is 320
   1.579 +  //    We do the check by the verify modular operator below to be zero
   1.580 +
   1.581 +  if(!audio_data || (lengthSamples <= 0) ||
   1.582 +                    (IsSamplingFreqSupported(samplingFreqHz) == false) ||
   1.583 +                    ((lengthSamples % (samplingFreqHz / 100) != 0)) )
   1.584 +  {
   1.585 +    CSFLogError(logTag, "%s Invalid Parameters ",__FUNCTION__);
   1.586 +    MOZ_ASSERT(PR_FALSE);
   1.587 +    return kMediaConduitMalformedArgument;
   1.588 +  }
   1.589 +
   1.590 +  //validate capture time
   1.591 +  if(capture_delay < 0 )
   1.592 +  {
   1.593 +    CSFLogError(logTag,"%s Invalid Capture Delay ", __FUNCTION__);
   1.594 +    MOZ_ASSERT(PR_FALSE);
   1.595 +    return kMediaConduitMalformedArgument;
   1.596 +  }
   1.597 +
   1.598 +  // if transmission is not started .. conduit cannot insert frames
   1.599 +  if(!mEngineTransmitting)
   1.600 +  {
   1.601 +    CSFLogError(logTag, "%s Engine not transmitting ", __FUNCTION__);
   1.602 +    return kMediaConduitSessionNotInited;
   1.603 +  }
   1.604 +
   1.605 +#ifdef MOZILLA_INTERNAL_API
   1.606 +    if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
   1.607 +      struct Processing insert = { TimeStamp::Now(), 0 };
   1.608 +      mProcessing.AppendElement(insert);
   1.609 +    }
   1.610 +#endif
   1.611 +
   1.612 +  capture_delay = mCaptureDelay;
   1.613 +  //Insert the samples
   1.614 +  if(mPtrVoEXmedia->ExternalRecordingInsertData(audio_data,
   1.615 +                                                lengthSamples,
   1.616 +                                                samplingFreqHz,
   1.617 +                                                capture_delay) == -1)
   1.618 +  {
   1.619 +    int error = mPtrVoEBase->LastError();
   1.620 +    CSFLogError(logTag,  "%s Inserting audio data Failed %d", __FUNCTION__, error);
   1.621 +    if(error == VE_RUNTIME_REC_ERROR)
   1.622 +    {
   1.623 +      return kMediaConduitRecordingError;
   1.624 +    }
   1.625 +    return kMediaConduitUnknownError;
   1.626 +  }
   1.627 +  // we should be good here
   1.628 +  return kMediaConduitNoError;
   1.629 +}
   1.630 +
   1.631 +MediaConduitErrorCode
   1.632 +WebrtcAudioConduit::GetAudioFrame(int16_t speechData[],
   1.633 +                                   int32_t samplingFreqHz,
   1.634 +                                   int32_t capture_delay,
   1.635 +                                   int& lengthSamples)
   1.636 +{
   1.637 +
   1.638 +  CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   1.639 +  unsigned int numSamples = 0;
   1.640 +
   1.641 +  //validate params
   1.642 +  if(!speechData )
   1.643 +  {
   1.644 +    CSFLogError(logTag,"%s Null Audio Buffer Pointer", __FUNCTION__);
   1.645 +    MOZ_ASSERT(PR_FALSE);
   1.646 +    return kMediaConduitMalformedArgument;
   1.647 +  }
   1.648 +
   1.649 +  // Validate sample length
   1.650 +  if((numSamples = GetNum10msSamplesForFrequency(samplingFreqHz)) == 0  )
   1.651 +  {
   1.652 +    CSFLogError(logTag,"%s Invalid Sampling Frequency ", __FUNCTION__);
   1.653 +    MOZ_ASSERT(PR_FALSE);
   1.654 +    return kMediaConduitMalformedArgument;
   1.655 +  }
   1.656 +
   1.657 +  //validate capture time
   1.658 +  if(capture_delay < 0 )
   1.659 +  {
   1.660 +    CSFLogError(logTag,"%s Invalid Capture Delay ", __FUNCTION__);
   1.661 +    MOZ_ASSERT(PR_FALSE);
   1.662 +    return kMediaConduitMalformedArgument;
   1.663 +  }
   1.664 +
   1.665 +  //Conduit should have reception enabled before we ask for decoded
   1.666 +  // samples
   1.667 +  if(!mEngineReceiving)
   1.668 +  {
   1.669 +    CSFLogError(logTag, "%s Engine not Receiving ", __FUNCTION__);
   1.670 +    return kMediaConduitSessionNotInited;
   1.671 +  }
   1.672 +
   1.673 +
   1.674 +  lengthSamples = 0;  //output paramter
   1.675 +
   1.676 +  if(mPtrVoEXmedia->ExternalPlayoutGetData( speechData,
   1.677 +                                            samplingFreqHz,
   1.678 +                                            capture_delay,
   1.679 +                                            lengthSamples) == -1)
   1.680 +  {
   1.681 +    int error = mPtrVoEBase->LastError();
   1.682 +    CSFLogError(logTag,  "%s Getting audio data Failed %d", __FUNCTION__, error);
   1.683 +    if(error == VE_RUNTIME_PLAY_ERROR)
   1.684 +    {
   1.685 +      return kMediaConduitPlayoutError;
   1.686 +    }
   1.687 +    return kMediaConduitUnknownError;
   1.688 +  }
   1.689 +
   1.690 +  // Not #ifdef DEBUG or on a log module so we can use it for about:webrtc/etc
   1.691 +  mSamples += lengthSamples;
   1.692 +  if (mSamples >= mLastSyncLog + samplingFreqHz) {
   1.693 +    int jitter_buffer_delay_ms;
   1.694 +    int playout_buffer_delay_ms;
   1.695 +    int avsync_offset_ms;
   1.696 +    if (GetAVStats(&jitter_buffer_delay_ms,
   1.697 +                   &playout_buffer_delay_ms,
   1.698 +                   &avsync_offset_ms)) {
   1.699 +#ifdef MOZILLA_INTERNAL_API
   1.700 +      if (avsync_offset_ms < 0) {
   1.701 +        Telemetry::Accumulate(Telemetry::WEBRTC_AVSYNC_WHEN_VIDEO_LAGS_AUDIO_MS,
   1.702 +                              -avsync_offset_ms);
   1.703 +      } else {
   1.704 +        Telemetry::Accumulate(Telemetry::WEBRTC_AVSYNC_WHEN_AUDIO_LAGS_VIDEO_MS,
   1.705 +                              avsync_offset_ms);
   1.706 +      }
   1.707 +#endif
   1.708 +      CSFLogError(logTag,
   1.709 +                  "A/V sync: sync delta: %dms, audio jitter delay %dms, playout delay %dms",
   1.710 +                  avsync_offset_ms, jitter_buffer_delay_ms, playout_buffer_delay_ms);
   1.711 +    } else {
   1.712 +      CSFLogError(logTag, "A/V sync: GetAVStats failed");
   1.713 +    }
   1.714 +    mLastSyncLog = mSamples;
   1.715 +  }
   1.716 +
   1.717 +#ifdef MOZILLA_INTERNAL_API
   1.718 +  if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
   1.719 +    if (mProcessing.Length() > 0) {
   1.720 +      unsigned int now;
   1.721 +      mPtrVoEVideoSync->GetPlayoutTimestamp(mChannel, now);
   1.722 +      if (static_cast<uint32_t>(now) != mLastTimestamp) {
   1.723 +        mLastTimestamp = static_cast<uint32_t>(now);
   1.724 +        // Find the block that includes this timestamp in the network input
   1.725 +        while (mProcessing.Length() > 0) {
   1.726 +          // FIX! assumes 20ms @ 48000Hz
   1.727 +          // FIX handle wrap-around
   1.728 +          if (mProcessing[0].mRTPTimeStamp + 20*(48000/1000) >= now) {
   1.729 +            TimeDuration t = TimeStamp::Now() - mProcessing[0].mTimeStamp;
   1.730 +            // Wrap-around?
   1.731 +            int64_t delta = t.ToMilliseconds() + (now - mProcessing[0].mRTPTimeStamp)/(48000/1000);
   1.732 +            LogTime(AsyncLatencyLogger::AudioRecvRTP, ((uint64_t) this), delta);
   1.733 +            break;
   1.734 +          }
   1.735 +          mProcessing.RemoveElementAt(0);
   1.736 +        }
   1.737 +      }
   1.738 +    }
   1.739 +  }
   1.740 +#endif
   1.741 +  CSFLogDebug(logTag,"%s GetAudioFrame:Got samples: length %d ",__FUNCTION__,
   1.742 +                                                               lengthSamples);
   1.743 +  return kMediaConduitNoError;
   1.744 +}
   1.745 +
   1.746 +// Transport Layer Callbacks
   1.747 +MediaConduitErrorCode
   1.748 +WebrtcAudioConduit::ReceivedRTPPacket(const void *data, int len)
   1.749 +{
   1.750 +  CSFLogDebug(logTag,  "%s : channel %d", __FUNCTION__, mChannel);
   1.751 +
   1.752 +  if(mEngineReceiving)
   1.753 +  {
   1.754 +#ifdef MOZILLA_INTERNAL_API
   1.755 +    if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
   1.756 +      // timestamp is at 32 bits in ([1])
   1.757 +      struct Processing insert = { TimeStamp::Now(),
   1.758 +                                   ntohl(static_cast<const uint32_t *>(data)[1]) };
   1.759 +      mProcessing.AppendElement(insert);
   1.760 +    }
   1.761 +#endif
   1.762 +
   1.763 +    if(mPtrVoENetwork->ReceivedRTPPacket(mChannel,data,len) == -1)
   1.764 +    {
   1.765 +      int error = mPtrVoEBase->LastError();
   1.766 +      CSFLogError(logTag, "%s RTP Processing Error %d", __FUNCTION__, error);
   1.767 +      if(error == VE_RTP_RTCP_MODULE_ERROR)
   1.768 +      {
   1.769 +        return kMediaConduitRTPRTCPModuleError;
   1.770 +      }
   1.771 +      return kMediaConduitUnknownError;
   1.772 +    }
   1.773 +  } else {
   1.774 +    CSFLogError(logTag, "Error: %s when not receiving", __FUNCTION__);
   1.775 +    return kMediaConduitSessionNotInited;
   1.776 +  }
   1.777 +
   1.778 +  return kMediaConduitNoError;
   1.779 +}
   1.780 +
   1.781 +MediaConduitErrorCode
   1.782 +WebrtcAudioConduit::ReceivedRTCPPacket(const void *data, int len)
   1.783 +{
   1.784 +  CSFLogDebug(logTag,  "%s : channel %d",__FUNCTION__, mChannel);
   1.785 +
   1.786 +  if(mEngineTransmitting)
   1.787 +  {
   1.788 +    if(mPtrVoENetwork->ReceivedRTCPPacket(mChannel, data, len) == -1)
   1.789 +    {
   1.790 +      int error = mPtrVoEBase->LastError();
   1.791 +      CSFLogError(logTag, "%s RTCP Processing Error %d", __FUNCTION__, error);
   1.792 +      if(error == VE_RTP_RTCP_MODULE_ERROR)
   1.793 +      {
   1.794 +        return kMediaConduitRTPRTCPModuleError;
   1.795 +      }
   1.796 +      return kMediaConduitUnknownError;
   1.797 +    }
   1.798 +  } else {
   1.799 +    CSFLogError(logTag, "Error: %s when not receiving", __FUNCTION__);
   1.800 +    return kMediaConduitSessionNotInited;
   1.801 +  }
   1.802 +  return kMediaConduitNoError;
   1.803 +}
   1.804 +
   1.805 +//WebRTC::RTP Callback Implementation
   1.806 +int WebrtcAudioConduit::SendPacket(int channel, const void* data, int len)
   1.807 +{
   1.808 +  CSFLogDebug(logTag,  "%s : channel %d %s", __FUNCTION__, channel,
   1.809 +              (mEngineReceiving && mOtherDirection) ? "(using mOtherDirection)" : "");
   1.810 +
   1.811 +  if (mEngineReceiving)
   1.812 +  {
   1.813 +    if (mOtherDirection)
   1.814 +    {
   1.815 +      return mOtherDirection->SendPacket(channel, data, len);
   1.816 +    }
   1.817 +    CSFLogDebug(logTag,  "%s : Asked to send RTP without an RTP sender on channel %d",
   1.818 +                __FUNCTION__, channel);
   1.819 +    return -1;
   1.820 +  } else {
   1.821 +#ifdef MOZILLA_INTERNAL_API
   1.822 +    if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
   1.823 +      if (mProcessing.Length() > 0) {
   1.824 +        TimeStamp started = mProcessing[0].mTimeStamp;
   1.825 +        mProcessing.RemoveElementAt(0);
   1.826 +        mProcessing.RemoveElementAt(0); // 20ms packetization!  Could automate this by watching sizes
   1.827 +        TimeDuration t = TimeStamp::Now() - started;
   1.828 +        int64_t delta = t.ToMilliseconds();
   1.829 +        LogTime(AsyncLatencyLogger::AudioSendRTP, ((uint64_t) this), delta);
   1.830 +      }
   1.831 +    }
   1.832 +#endif
   1.833 +    if(mTransport && (mTransport->SendRtpPacket(data, len) == NS_OK))
   1.834 +    {
   1.835 +      CSFLogDebug(logTag, "%s Sent RTP Packet ", __FUNCTION__);
   1.836 +      return len;
   1.837 +    } else {
   1.838 +      CSFLogError(logTag, "%s RTP Packet Send Failed ", __FUNCTION__);
   1.839 +      return -1;
   1.840 +    }
   1.841 +  }
   1.842 +}
   1.843 +
   1.844 +int WebrtcAudioConduit::SendRTCPPacket(int channel, const void* data, int len)
   1.845 +{
   1.846 +  CSFLogDebug(logTag,  "%s : channel %d", __FUNCTION__, channel);
   1.847 +
   1.848 +  if (mEngineTransmitting)
   1.849 +  {
   1.850 +    if (mOtherDirection)
   1.851 +    {
   1.852 +      return mOtherDirection->SendRTCPPacket(channel, data, len);
   1.853 +    }
   1.854 +  }
   1.855 +
   1.856 +  // We come here if we have only one pipeline/conduit setup,
   1.857 +  // such as for unidirectional streams.
   1.858 +  // We also end up here if we are receiving
   1.859 +  if(mTransport && mTransport->SendRtcpPacket(data, len) == NS_OK)
   1.860 +  {
   1.861 +    CSFLogDebug(logTag, "%s Sent RTCP Packet ", __FUNCTION__);
   1.862 +    return len;
   1.863 +  } else {
   1.864 +    CSFLogError(logTag, "%s RTCP Packet Send Failed ", __FUNCTION__);
   1.865 +    return -1;
   1.866 +  }
   1.867 +}
   1.868 +
   1.869 +/**
   1.870 + * Converts between CodecConfig to WebRTC Codec Structure.
   1.871 + */
   1.872 +
   1.873 +bool
   1.874 +WebrtcAudioConduit::CodecConfigToWebRTCCodec(const AudioCodecConfig* codecInfo,
   1.875 +                                              webrtc::CodecInst& cinst)
   1.876 + {
   1.877 +  const unsigned int plNameLength = codecInfo->mName.length()+1;
   1.878 +  memset(&cinst, 0, sizeof(webrtc::CodecInst));
   1.879 +  if(sizeof(cinst.plname) < plNameLength)
   1.880 +  {
   1.881 +    CSFLogError(logTag, "%s Payload name buffer capacity mismatch ",
   1.882 +                                                      __FUNCTION__);
   1.883 +    return false;
   1.884 +  }
   1.885 +  memcpy(cinst.plname, codecInfo->mName.c_str(),codecInfo->mName.length());
   1.886 +  cinst.plname[plNameLength]='\0';
   1.887 +  cinst.pltype   =  codecInfo->mType;
   1.888 +  cinst.rate     =  codecInfo->mRate;
   1.889 +  cinst.pacsize  =  codecInfo->mPacSize;
   1.890 +  cinst.plfreq   =  codecInfo->mFreq;
   1.891 +  cinst.channels =  codecInfo->mChannels;
   1.892 +  return true;
   1.893 + }
   1.894 +
   1.895 +/**
   1.896 +  *  Supported Sampling Frequncies.
   1.897 +  */
   1.898 +bool
   1.899 +WebrtcAudioConduit::IsSamplingFreqSupported(int freq) const
   1.900 +{
   1.901 +  if(GetNum10msSamplesForFrequency(freq))
   1.902 +  {
   1.903 +    return true;
   1.904 +  } else {
   1.905 +    return false;
   1.906 +  }
   1.907 +}
   1.908 +
   1.909 +/* Return block-length of 10 ms audio frame in number of samples */
   1.910 +unsigned int
   1.911 +WebrtcAudioConduit::GetNum10msSamplesForFrequency(int samplingFreqHz) const
   1.912 +{
   1.913 +  switch(samplingFreqHz)
   1.914 +  {
   1.915 +    case 16000: return 160; //160 samples
   1.916 +    case 32000: return 320; //320 samples
   1.917 +    case 44100: return 441; //441 samples
   1.918 +    case 48000: return 480; //480 samples
   1.919 +    default:    return 0; // invalid or unsupported
   1.920 +  }
   1.921 +}
   1.922 +
   1.923 +//Copy the codec passed into Conduit's database
   1.924 +bool
   1.925 +WebrtcAudioConduit::CopyCodecToDB(const AudioCodecConfig* codecInfo)
   1.926 +{
   1.927 +
   1.928 +  AudioCodecConfig* cdcConfig = new AudioCodecConfig(codecInfo->mType,
   1.929 +                                                     codecInfo->mName,
   1.930 +                                                     codecInfo->mFreq,
   1.931 +                                                     codecInfo->mPacSize,
   1.932 +                                                     codecInfo->mChannels,
   1.933 +                                                     codecInfo->mRate,
   1.934 +                                                     codecInfo->mLoadManager);
   1.935 +  mRecvCodecList.push_back(cdcConfig);
   1.936 +  return true;
   1.937 +}
   1.938 +
   1.939 +/**
   1.940 + * Checks if 2 codec structs are same
   1.941 + */
   1.942 +bool
   1.943 +WebrtcAudioConduit::CheckCodecsForMatch(const AudioCodecConfig* curCodecConfig,
   1.944 +                                         const AudioCodecConfig* codecInfo) const
   1.945 +{
   1.946 +  if(!curCodecConfig)
   1.947 +  {
   1.948 +    return false;
   1.949 +  }
   1.950 +
   1.951 +  if(curCodecConfig->mType   == codecInfo->mType &&
   1.952 +      (curCodecConfig->mName.compare(codecInfo->mName) == 0) &&
   1.953 +      curCodecConfig->mFreq   == codecInfo->mFreq &&
   1.954 +      curCodecConfig->mPacSize == codecInfo->mPacSize &&
   1.955 +      curCodecConfig->mChannels == codecInfo->mChannels &&
   1.956 +      curCodecConfig->mRate == codecInfo->mRate)
   1.957 +  {
   1.958 +    return true;
   1.959 +  }
   1.960 +
   1.961 +  return false;
   1.962 +}
   1.963 +
   1.964 +/**
   1.965 + * Checks if the codec is already in Conduit's database
   1.966 + */
   1.967 +bool
   1.968 +WebrtcAudioConduit::CheckCodecForMatch(const AudioCodecConfig* codecInfo) const
   1.969 +{
   1.970 +  //the db should have atleast one codec
   1.971 +  for(std::vector<AudioCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
   1.972 +  {
   1.973 +    if(CheckCodecsForMatch(mRecvCodecList[i],codecInfo))
   1.974 +    {
   1.975 +      //match
   1.976 +      return true;
   1.977 +    }
   1.978 +  }
   1.979 +  //no match or empty local db
   1.980 +  return false;
   1.981 +}
   1.982 +
   1.983 +
   1.984 +/**
   1.985 + * Perform validation on the codecConfig to be applied.
   1.986 + * Verifies if the codec is already applied.
   1.987 + */
   1.988 +MediaConduitErrorCode
   1.989 +WebrtcAudioConduit::ValidateCodecConfig(const AudioCodecConfig* codecInfo,
   1.990 +                                        bool send) const
   1.991 +{
   1.992 +  bool codecAppliedAlready = false;
   1.993 +
   1.994 +  if(!codecInfo)
   1.995 +  {
   1.996 +    CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
   1.997 +    return kMediaConduitMalformedArgument;
   1.998 +  }
   1.999 +
  1.1000 +  if((codecInfo->mName.empty()) ||
  1.1001 +     (codecInfo->mName.length() >= CODEC_PLNAME_SIZE))
  1.1002 +  {
  1.1003 +    CSFLogError(logTag, "%s Invalid Payload Name Length ", __FUNCTION__);
  1.1004 +    return kMediaConduitMalformedArgument;
  1.1005 +  }
  1.1006 +
  1.1007 +  //Only mono or stereo channels supported
  1.1008 +  if( (codecInfo->mChannels != 1) && (codecInfo->mChannels != 2))
  1.1009 +  {
  1.1010 +    CSFLogError(logTag, "%s Channel Unsupported ", __FUNCTION__);
  1.1011 +    return kMediaConduitMalformedArgument;
  1.1012 +  }
  1.1013 +
  1.1014 +  //check if we have the same codec already applied
  1.1015 +  if(send)
  1.1016 +  {
  1.1017 +    codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
  1.1018 +  } else {
  1.1019 +    codecAppliedAlready = CheckCodecForMatch(codecInfo);
  1.1020 +  }
  1.1021 +
  1.1022 +  if(codecAppliedAlready)
  1.1023 +  {
  1.1024 +    CSFLogDebug(logTag, "%s Codec %s Already Applied  ", __FUNCTION__, codecInfo->mName.c_str());
  1.1025 +    return kMediaConduitCodecInUse;
  1.1026 +  }
  1.1027 +  return kMediaConduitNoError;
  1.1028 +}
  1.1029 +
  1.1030 +void
  1.1031 +WebrtcAudioConduit::DumpCodecDB() const
  1.1032 + {
  1.1033 +    for(std::vector<AudioCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
  1.1034 +    {
  1.1035 +      CSFLogDebug(logTag,"Payload Name: %s", mRecvCodecList[i]->mName.c_str());
  1.1036 +      CSFLogDebug(logTag,"Payload Type: %d", mRecvCodecList[i]->mType);
  1.1037 +      CSFLogDebug(logTag,"Payload Frequency: %d", mRecvCodecList[i]->mFreq);
  1.1038 +      CSFLogDebug(logTag,"Payload PacketSize: %d", mRecvCodecList[i]->mPacSize);
  1.1039 +      CSFLogDebug(logTag,"Payload Channels: %d", mRecvCodecList[i]->mChannels);
  1.1040 +      CSFLogDebug(logTag,"Payload Sampling Rate: %d", mRecvCodecList[i]->mRate);
  1.1041 +    }
  1.1042 + }
  1.1043 +}// end namespace

mercurial