media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "CSFLog.h"
     7 #include "base/histogram.h"
     8 #include "CallControlManager.h"
     9 #include "CC_Device.h"
    10 #include "CC_Call.h"
    11 #include "CC_Observer.h"
    12 #include "ccapi_call_info.h"
    13 #include "CC_SIPCCCallInfo.h"
    14 #include "ccapi_device_info.h"
    15 #include "CC_SIPCCDeviceInfo.h"
    16 #include "vcm.h"
    17 #include "VcmSIPCCBinding.h"
    18 #include "PeerConnectionImpl.h"
    19 #include "PeerConnectionCtx.h"
    20 #include "runnable_utils.h"
    21 #include "cpr_socket.h"
    22 #include "debug-psipcc-types.h"
    23 #include "prcvar.h"
    25 #include "mozilla/Telemetry.h"
    27 #ifdef MOZILLA_INTERNAL_API
    28 #include "mozilla/dom/RTCPeerConnectionBinding.h"
    29 #include "mozilla/Preferences.h"
    30 #endif
    32 #include "nsIObserverService.h"
    33 #include "nsIObserver.h"
    34 #include "mozilla/Services.h"
    35 #include "StaticPtr.h"
    36 extern "C" {
    37 #include "../sipcc/core/common/thread_monitor.h"
    38 }
    40 static const char* logTag = "PeerConnectionCtx";
    42 extern "C" {
    43 extern PRCondVar *ccAppReadyToStartCond;
    44 extern PRLock *ccAppReadyToStartLock;
    45 extern char ccAppReadyToStart;
    46 }
    48 namespace mozilla {
    50 using namespace dom;
    52 // Convert constraints to C structures
    54 #ifdef MOZILLA_INTERNAL_API
    55 static void
    56 Apply(const Optional<bool> &aSrc, cc_boolean_constraint_t *aDst,
    57       bool mandatory = false) {
    58   if (aSrc.WasPassed() && (mandatory || !aDst->was_passed)) {
    59     aDst->was_passed = true;
    60     aDst->value = aSrc.Value();
    61     aDst->mandatory = mandatory;
    62   }
    63 }
    64 #endif
    66 MediaConstraintsExternal::MediaConstraintsExternal() {
    67   memset(&mConstraints, 0, sizeof(mConstraints));
    68 }
    70 MediaConstraintsExternal::MediaConstraintsExternal(
    71     const MediaConstraintsInternal &aSrc) {
    72   cc_media_constraints_t* c = &mConstraints;
    73   memset(c, 0, sizeof(*c));
    74 #ifdef MOZILLA_INTERNAL_API
    75   Apply(aSrc.mMandatory.mOfferToReceiveAudio, &c->offer_to_receive_audio, true);
    76   Apply(aSrc.mMandatory.mOfferToReceiveVideo, &c->offer_to_receive_video, true);
    77   if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) {
    78     c->offer_to_receive_video.was_passed = true;
    79     c->offer_to_receive_video.value = false;
    80   }
    81   Apply(aSrc.mMandatory.mMozDontOfferDataChannel, &c->moz_dont_offer_datachannel,
    82         true);
    83   Apply(aSrc.mMandatory.mMozBundleOnly, &c->moz_bundle_only, true);
    84   if (aSrc.mOptional.WasPassed()) {
    85     const Sequence<MediaConstraintSet> &array = aSrc.mOptional.Value();
    86     for (uint32_t i = 0; i < array.Length(); i++) {
    87       Apply(array[i].mOfferToReceiveAudio, &c->offer_to_receive_audio);
    88       Apply(array[i].mOfferToReceiveVideo, &c->offer_to_receive_video);
    89       Apply(array[i].mMozDontOfferDataChannel, &c->moz_dont_offer_datachannel);
    90       Apply(array[i].mMozBundleOnly, &c->moz_bundle_only);
    91     }
    92   }
    93 #endif
    94 }
    96 cc_media_constraints_t*
    97 MediaConstraintsExternal::build() const {
    98   cc_media_constraints_t* cc  = (cc_media_constraints_t*)
    99     cpr_malloc(sizeof(cc_media_constraints_t));
   100   if (cc) {
   101     *cc = mConstraints;
   102   }
   103   return cc;
   104 }
   106 class PeerConnectionCtxShutdown : public nsIObserver
   107 {
   108 public:
   109   NS_DECL_ISUPPORTS
   111   PeerConnectionCtxShutdown() {}
   113   void Init()
   114     {
   115       nsCOMPtr<nsIObserverService> observerService =
   116         services::GetObserverService();
   117       if (!observerService)
   118         return;
   120       nsresult rv = NS_OK;
   122 #ifdef MOZILLA_INTERNAL_API
   123       rv = observerService->AddObserver(this,
   124                                         NS_XPCOM_SHUTDOWN_OBSERVER_ID,
   125                                         false);
   126       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
   127 #endif
   128       (void) rv;
   129     }
   131   virtual ~PeerConnectionCtxShutdown()
   132     {
   133       nsCOMPtr<nsIObserverService> observerService =
   134         services::GetObserverService();
   135       if (observerService)
   136         observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
   137     }
   139   NS_IMETHODIMP Observe(nsISupports* aSubject, const char* aTopic,
   140                         const char16_t* aData) {
   141     if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
   142       CSFLogDebug(logTag, "Shutting down PeerConnectionCtx");
   143       sipcc::PeerConnectionCtx::Destroy();
   145       nsCOMPtr<nsIObserverService> observerService =
   146         services::GetObserverService();
   147       if (!observerService)
   148         return NS_ERROR_FAILURE;
   150       nsresult rv = observerService->RemoveObserver(this,
   151                                                     NS_XPCOM_SHUTDOWN_OBSERVER_ID);
   152       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
   154       // Make sure we're not deleted while still inside ::Observe()
   155       nsRefPtr<PeerConnectionCtxShutdown> kungFuDeathGrip(this);
   156       sipcc::PeerConnectionCtx::gPeerConnectionCtxShutdown = nullptr;
   157     }
   158     return NS_OK;
   159   }
   160 };
   162 NS_IMPL_ISUPPORTS(PeerConnectionCtxShutdown, nsIObserver);
   163 }
   165 using namespace mozilla;
   166 namespace sipcc {
   168 PeerConnectionCtx* PeerConnectionCtx::gInstance;
   169 nsIThread* PeerConnectionCtx::gMainThread;
   170 StaticRefPtr<PeerConnectionCtxShutdown> PeerConnectionCtx::gPeerConnectionCtxShutdown;
   172 // Since we have a pointer to main-thread, help make it safe for lower-level
   173 // SIPCC threads to use SyncRunnable without deadlocking, by exposing main's
   174 // dispatcher and waiter functions. See sipcc/core/common/thread_monitor.c.
   176 static void thread_ended_dispatcher(thread_ended_funct func, thread_monitor_id_t id)
   177 {
   178   nsresult rv = PeerConnectionCtx::gMainThread->Dispatch(WrapRunnableNM(func, id),
   179                                                          NS_DISPATCH_NORMAL);
   180   if (NS_FAILED(rv)) {
   181     CSFLogError( logTag, "%s(): Could not dispatch to main thread", __FUNCTION__);
   182   }
   183 }
   185 static void join_waiter() {
   186   NS_ProcessPendingEvents(PeerConnectionCtx::gMainThread);
   187 }
   189 nsresult PeerConnectionCtx::InitializeGlobal(nsIThread *mainThread,
   190   nsIEventTarget* stsThread) {
   191   if (!gMainThread) {
   192     gMainThread = mainThread;
   193     CSF::VcmSIPCCBinding::setMainThread(gMainThread);
   194     init_thread_monitor(&thread_ended_dispatcher, &join_waiter);
   195   } else {
   196 #ifdef MOZILLA_INTERNAL_API
   197     MOZ_ASSERT(gMainThread == mainThread);
   198 #endif
   199   }
   201   CSF::VcmSIPCCBinding::setSTSThread(stsThread);
   203   nsresult res;
   205 #ifdef MOZILLA_INTERNAL_API
   206   // This check fails on the unit tests because they do not
   207   // have the right thread behavior.
   208   bool on;
   209   res = gMainThread->IsOnCurrentThread(&on);
   210   NS_ENSURE_SUCCESS(res, res);
   211   MOZ_ASSERT(on);
   212 #endif
   214   if (!gInstance) {
   215     CSFLogDebug(logTag, "Creating PeerConnectionCtx");
   216     PeerConnectionCtx *ctx = new PeerConnectionCtx();
   218     res = ctx->Initialize();
   219     PR_ASSERT(NS_SUCCEEDED(res));
   220     if (!NS_SUCCEEDED(res))
   221       return res;
   223     gInstance = ctx;
   225     if (!sipcc::PeerConnectionCtx::gPeerConnectionCtxShutdown) {
   226       sipcc::PeerConnectionCtx::gPeerConnectionCtxShutdown = new PeerConnectionCtxShutdown();
   227       sipcc::PeerConnectionCtx::gPeerConnectionCtxShutdown->Init();
   228     }
   229   }
   231   return NS_OK;
   232 }
   234 PeerConnectionCtx* PeerConnectionCtx::GetInstance() {
   235   MOZ_ASSERT(gInstance);
   236   return gInstance;
   237 }
   239 bool PeerConnectionCtx::isActive() {
   240   return gInstance;
   241 }
   243 void PeerConnectionCtx::Destroy() {
   244   CSFLogDebug(logTag, "%s", __FUNCTION__);
   246   if (gInstance) {
   247     gInstance->Cleanup();
   248     delete gInstance;
   249     gInstance = nullptr;
   250   }
   251 }
   253 nsresult PeerConnectionCtx::Initialize() {
   254   mCCM = CSF::CallControlManager::create();
   256   NS_ENSURE_TRUE(mCCM.get(), NS_ERROR_FAILURE);
   258   // Add the local audio codecs
   259   // FIX - Get this list from MediaEngine instead
   260   int codecMask = 0;
   261   codecMask |= VCM_CODEC_RESOURCE_G711;
   262   codecMask |= VCM_CODEC_RESOURCE_OPUS;
   263   //codecMask |= VCM_CODEC_RESOURCE_LINEAR;
   264   //codecMask |= VCM_CODEC_RESOURCE_G722;
   265   //codecMask |= VCM_CODEC_RESOURCE_iLBC;
   266   //codecMask |= VCM_CODEC_RESOURCE_iSAC;
   267   mCCM->setAudioCodecs(codecMask);
   269   //Add the local video codecs
   270   // FIX - Get this list from MediaEngine instead
   271   // Turning them all on for now
   272   codecMask = 0;
   273   // Only adding codecs supported
   274   //codecMask |= VCM_CODEC_RESOURCE_H263;
   276 #ifdef MOZILLA_INTERNAL_API
   277   if (Preferences::GetBool("media.peerconnection.video.h264_enabled")) {
   278     codecMask |= VCM_CODEC_RESOURCE_H264;
   279   }
   280 #endif
   282   codecMask |= VCM_CODEC_RESOURCE_VP8;
   283   //codecMask |= VCM_CODEC_RESOURCE_I420;
   284   mCCM->setVideoCodecs(codecMask);
   286   ccAppReadyToStartLock = PR_NewLock();
   287   if (!ccAppReadyToStartLock) {
   288     return NS_ERROR_FAILURE;
   289   }
   291   ccAppReadyToStartCond = PR_NewCondVar(ccAppReadyToStartLock);
   292   if (!ccAppReadyToStartCond) {
   293     return NS_ERROR_FAILURE;
   294   }
   296   if (!mCCM->startSDPMode())
   297     return NS_ERROR_FAILURE;
   299   mDevice = mCCM->getActiveDevice();
   300   mCCM->addCCObserver(this);
   301   NS_ENSURE_TRUE(mDevice.get(), NS_ERROR_FAILURE);
   302   ChangeSipccState(dom::PCImplSipccState::Starting);
   304   // Now that everything is set up, we let the CCApp thread
   305   // know that it's okay to start processing messages.
   306   PR_Lock(ccAppReadyToStartLock);
   307   ccAppReadyToStart = 1;
   308   PR_NotifyAllCondVar(ccAppReadyToStartCond);
   309   PR_Unlock(ccAppReadyToStartLock);
   311   mConnectionCounter = 0;
   312 #ifdef MOZILLA_INTERNAL_API
   313   Telemetry::GetHistogramById(Telemetry::WEBRTC_CALL_COUNT)->Add(0);
   314 #endif
   316   return NS_OK;
   317 }
   319 nsresult PeerConnectionCtx::Cleanup() {
   320   CSFLogDebug(logTag, "%s", __FUNCTION__);
   322   mCCM->destroy();
   323   mCCM->removeCCObserver(this);
   324   return NS_OK;
   325 }
   327 CSF::CC_CallPtr PeerConnectionCtx::createCall() {
   328   return mDevice->createCall();
   329 }
   331 void PeerConnectionCtx::onDeviceEvent(ccapi_device_event_e aDeviceEvent,
   332                                       CSF::CC_DevicePtr aDevice,
   333                                       CSF::CC_DeviceInfoPtr aInfo ) {
   334   cc_service_state_t state = aInfo->getServiceState();
   335   // We are keeping this in a local var to avoid a data race
   336   // with ChangeSipccState in the debug message and compound if below
   337   dom::PCImplSipccState currentSipccState = mSipccState;
   339   switch (aDeviceEvent) {
   340     case CCAPI_DEVICE_EV_STATE:
   341       CSFLogDebug(logTag, "%s - %d : %d", __FUNCTION__, state,
   342                   static_cast<uint32_t>(currentSipccState));
   344       if (CC_STATE_INS == state) {
   345         // SIPCC is up
   346         if (dom::PCImplSipccState::Starting == currentSipccState ||
   347             dom::PCImplSipccState::Idle == currentSipccState) {
   348           ChangeSipccState(dom::PCImplSipccState::Started);
   349         } else {
   350           CSFLogError(logTag, "%s PeerConnection already started", __FUNCTION__);
   351         }
   352       } else {
   353         NS_NOTREACHED("Unsupported Signaling State Transition");
   354       }
   355       break;
   356     default:
   357       CSFLogDebug(logTag, "%s: Ignoring event: %s\n",__FUNCTION__,
   358                   device_event_getname(aDeviceEvent));
   359   }
   360 }
   362 static void onCallEvent_m(nsAutoPtr<std::string> peerconnection,
   363                           ccapi_call_event_e aCallEvent,
   364                           CSF::CC_CallInfoPtr aInfo);
   366 void PeerConnectionCtx::onCallEvent(ccapi_call_event_e aCallEvent,
   367                                     CSF::CC_CallPtr aCall,
   368                                     CSF::CC_CallInfoPtr aInfo) {
   369   // This is called on a SIPCC thread.
   370   //
   371   // We cannot use SyncRunnable to main thread, as that would deadlock on
   372   // shutdown. Instead, we dispatch asynchronously. We copy getPeerConnection(),
   373   // a "weak ref" to the PC, which is safe in shutdown, and CC_CallInfoPtr (an
   374   // nsRefPtr) is thread-safe and keeps aInfo alive.
   375   nsAutoPtr<std::string> pcDuped(new std::string(aCall->getPeerConnection()));
   377   // DISPATCH_NORMAL with duped string
   378   nsresult rv = gMainThread->Dispatch(WrapRunnableNM(&onCallEvent_m, pcDuped,
   379                                                      aCallEvent, aInfo),
   380                                       NS_DISPATCH_NORMAL);
   381   if (NS_FAILED(rv)) {
   382     CSFLogError( logTag, "%s(): Could not dispatch to main thread", __FUNCTION__);
   383   }
   384 }
   386 // Demux the call event to the right PeerConnection
   387 static void onCallEvent_m(nsAutoPtr<std::string> peerconnection,
   388                           ccapi_call_event_e aCallEvent,
   389                           CSF::CC_CallInfoPtr aInfo) {
   390   CSFLogDebug(logTag, "onCallEvent()");
   391   PeerConnectionWrapper pc(peerconnection->c_str());
   392   if (!pc.impl())  // This must be an event on a dead PC. Ignore
   393     return;
   394   CSFLogDebug(logTag, "Calling PC");
   395   pc.impl()->onCallEvent(OnCallEventArgs(aCallEvent, aInfo));
   396 }
   398 }  // namespace sipcc

mercurial