content/media/webrtc/MediaEngineWebRTC.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     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/. */
     5 #ifdef MOZ_LOGGING
     6 #define FORCE_PR_LOG
     7 #endif
     9 #if defined(PR_LOG)
    10 #error "This file must be #included before any IPDL-generated files or other files that #include prlog.h"
    11 #endif
    13 #include "nsIPrefService.h"
    14 #include "nsIPrefBranch.h"
    16 #include "CSFLog.h"
    17 #include "prenv.h"
    19 #ifdef PR_LOGGING
    20 static PRLogModuleInfo*
    21 GetUserMediaLog()
    22 {
    23   static PRLogModuleInfo *sLog;
    24   if (!sLog)
    25     sLog = PR_NewLogModule("GetUserMedia");
    26   return sLog;
    27 }
    28 #endif
    30 #include "MediaEngineWebRTC.h"
    31 #include "ImageContainer.h"
    32 #include "nsIComponentRegistrar.h"
    33 #include "MediaEngineTabVideoSource.h"
    34 #include "nsITabSource.h"
    35 #include "MediaTrackConstraints.h"
    37 #ifdef MOZ_WIDGET_ANDROID
    38 #include "AndroidJNIWrapper.h"
    39 #include "AndroidBridge.h"
    40 #endif
    42 #undef LOG
    43 #define LOG(args) PR_LOG(GetUserMediaLog(), PR_LOG_DEBUG, args)
    45 namespace mozilla {
    47 MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
    48   : mMutex("mozilla::MediaEngineWebRTC")
    49   , mVideoEngine(nullptr)
    50   , mVoiceEngine(nullptr)
    51   , mVideoEngineInit(false)
    52   , mAudioEngineInit(false)
    53   , mHasTabVideoSource(false)
    54 {
    55 #ifndef MOZ_B2G_CAMERA
    56   nsCOMPtr<nsIComponentRegistrar> compMgr;
    57   NS_GetComponentRegistrar(getter_AddRefs(compMgr));
    58   if (compMgr) {
    59     compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
    60   }
    61 #else
    62   AsyncLatencyLogger::Get()->AddRef();
    63 #endif
    64   // XXX
    65   gFarendObserver = new AudioOutputObserver();
    66 }
    68 void
    69 MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
    70 {
    71 #ifdef MOZ_B2G_CAMERA
    72   MutexAutoLock lock(mMutex);
    74   /**
    75    * We still enumerate every time, in case a new device was plugged in since
    76    * the last call. TODO: Verify that WebRTC actually does deal with hotplugging
    77    * new devices (with or without new engine creation) and accordingly adjust.
    78    * Enumeration is not neccessary if GIPS reports the same set of devices
    79    * for a given instance of the engine. Likewise, if a device was plugged out,
    80    * mVideoSources must be updated.
    81    */
    82   int num = 0;
    83   nsresult result;
    84   result = ICameraControl::GetNumberOfCameras(num);
    85   if (num <= 0 || result != NS_OK) {
    86     return;
    87   }
    89   for (int i = 0; i < num; i++) {
    90     nsCString cameraName;
    91     result = ICameraControl::GetCameraName(i, cameraName);
    92     if (result != NS_OK) {
    93       continue;
    94     }
    96     nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
    97     NS_ConvertUTF8toUTF16 uuid(cameraName);
    98     if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
    99       // We've already seen this device, just append.
   100       aVSources->AppendElement(vSource.get());
   101     } else {
   102       vSource = new MediaEngineWebRTCVideoSource(i);
   103       mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
   104       aVSources->AppendElement(vSource);
   105     }
   106   }
   108   return;
   109 #else
   110   ScopedCustomReleasePtr<webrtc::ViEBase> ptrViEBase;
   111   ScopedCustomReleasePtr<webrtc::ViECapture> ptrViECapture;
   113   // We spawn threads to handle gUM runnables, so we must protect the member vars
   114   MutexAutoLock lock(mMutex);
   116 #ifdef MOZ_WIDGET_ANDROID
   117   jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
   119   // get the JVM
   120   JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
   122   if (webrtc::VideoEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
   123     LOG(("VieCapture:SetAndroidObjects Failed"));
   124     return;
   125   }
   126 #endif
   127   if (!mVideoEngine) {
   128     if (!(mVideoEngine = webrtc::VideoEngine::Create())) {
   129       return;
   130     }
   131   }
   133   PRLogModuleInfo *logs = GetWebRTCLogInfo();
   134   if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
   135     // no need to a critical section or lock here
   136     gWebrtcTraceLoggingOn = 1;
   138     const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
   139     if (!file) {
   140       file = "WebRTC.log";
   141     }
   143     LOG(("%s Logging webrtc to %s level %d", __FUNCTION__, file, logs->level));
   145     mVideoEngine->SetTraceFilter(logs->level);
   146     mVideoEngine->SetTraceFile(file);
   147   }
   149   ptrViEBase = webrtc::ViEBase::GetInterface(mVideoEngine);
   150   if (!ptrViEBase) {
   151     return;
   152   }
   154   if (!mVideoEngineInit) {
   155     if (ptrViEBase->Init() < 0) {
   156       return;
   157     }
   158     mVideoEngineInit = true;
   159   }
   161   ptrViECapture = webrtc::ViECapture::GetInterface(mVideoEngine);
   162   if (!ptrViECapture) {
   163     return;
   164   }
   166   /**
   167    * We still enumerate every time, in case a new device was plugged in since
   168    * the last call. TODO: Verify that WebRTC actually does deal with hotplugging
   169    * new devices (with or without new engine creation) and accordingly adjust.
   170    * Enumeration is not neccessary if GIPS reports the same set of devices
   171    * for a given instance of the engine. Likewise, if a device was plugged out,
   172    * mVideoSources must be updated.
   173    */
   174   int num = ptrViECapture->NumberOfCaptureDevices();
   175   if (num <= 0) {
   176     return;
   177   }
   179   for (int i = 0; i < num; i++) {
   180     const unsigned int kMaxDeviceNameLength = 128; // XXX FIX!
   181     const unsigned int kMaxUniqueIdLength = 256;
   182     char deviceName[kMaxDeviceNameLength];
   183     char uniqueId[kMaxUniqueIdLength];
   185     // paranoia
   186     deviceName[0] = '\0';
   187     uniqueId[0] = '\0';
   188     int error = ptrViECapture->GetCaptureDevice(i, deviceName,
   189                                                 sizeof(deviceName), uniqueId,
   190                                                 sizeof(uniqueId));
   192     if (error) {
   193       LOG((" VieCapture:GetCaptureDevice: Failed %d",
   194            ptrViEBase->LastError() ));
   195       continue;
   196     }
   197 #ifdef DEBUG
   198     LOG(("  Capture Device Index %d, Name %s", i, deviceName));
   200     webrtc::CaptureCapability cap;
   201     int numCaps = ptrViECapture->NumberOfCapabilities(uniqueId, kMaxUniqueIdLength);
   202     LOG(("Number of Capabilities %d", numCaps));
   203     for (int j = 0; j < numCaps; j++) {
   204       if (ptrViECapture->GetCaptureCapability(uniqueId, kMaxUniqueIdLength,
   205                                               j, cap ) != 0 ) {
   206         break;
   207       }
   208       LOG(("type=%d width=%d height=%d maxFPS=%d",
   209            cap.rawType, cap.width, cap.height, cap.maxFPS ));
   210     }
   211 #endif
   213     if (uniqueId[0] == '\0') {
   214       // In case a device doesn't set uniqueId!
   215       strncpy(uniqueId, deviceName, sizeof(uniqueId));
   216       uniqueId[sizeof(uniqueId)-1] = '\0'; // strncpy isn't safe
   217     }
   219     nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
   220     NS_ConvertUTF8toUTF16 uuid(uniqueId);
   221     if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
   222       // We've already seen this device, just append.
   223       aVSources->AppendElement(vSource.get());
   224     } else {
   225       vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
   226       mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
   227       aVSources->AppendElement(vSource);
   228     }
   229   }
   231   if (mHasTabVideoSource)
   232     aVSources->AppendElement(new MediaEngineTabVideoSource());
   234   return;
   235 #endif
   236 }
   238 void
   239 MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >* aASources)
   240 {
   241   ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
   242   ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw;
   243   // We spawn threads to handle gUM runnables, so we must protect the member vars
   244   MutexAutoLock lock(mMutex);
   246 #ifdef MOZ_WIDGET_ANDROID
   247   jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
   249   // get the JVM
   250   JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
   251   JNIEnv *env = GetJNIForThread();
   253   if (webrtc::VoiceEngine::SetAndroidObjects(jvm, env, (void*)context) != 0) {
   254     LOG(("VoiceEngine:SetAndroidObjects Failed"));
   255     return;
   256   }
   257 #endif
   259   if (!mVoiceEngine) {
   260     mVoiceEngine = webrtc::VoiceEngine::Create();
   261     if (!mVoiceEngine) {
   262       return;
   263     }
   264   }
   266   PRLogModuleInfo *logs = GetWebRTCLogInfo();
   267   if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
   268     // no need to a critical section or lock here
   269     gWebrtcTraceLoggingOn = 1;
   271     const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
   272     if (!file) {
   273       file = "WebRTC.log";
   274     }
   276     LOG(("Logging webrtc to %s level %d", __FUNCTION__, file, logs->level));
   278     mVoiceEngine->SetTraceFilter(logs->level);
   279     mVoiceEngine->SetTraceFile(file);
   280   }
   282   ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
   283   if (!ptrVoEBase) {
   284     return;
   285   }
   287   if (!mAudioEngineInit) {
   288     if (ptrVoEBase->Init() < 0) {
   289       return;
   290     }
   291     mAudioEngineInit = true;
   292   }
   294   ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
   295   if (!ptrVoEHw)  {
   296     return;
   297   }
   299   int nDevices = 0;
   300   ptrVoEHw->GetNumOfRecordingDevices(nDevices);
   301   for (int i = 0; i < nDevices; i++) {
   302     // We use constants here because GetRecordingDeviceName takes char[128].
   303     char deviceName[128];
   304     char uniqueId[128];
   305     // paranoia; jingle doesn't bother with this
   306     deviceName[0] = '\0';
   307     uniqueId[0] = '\0';
   309     int error = ptrVoEHw->GetRecordingDeviceName(i, deviceName, uniqueId);
   310     if (error) {
   311       LOG((" VoEHardware:GetRecordingDeviceName: Failed %d",
   312            ptrVoEBase->LastError() ));
   313       continue;
   314     }
   316     if (uniqueId[0] == '\0') {
   317       // Mac and Linux don't set uniqueId!
   318       MOZ_ASSERT(sizeof(deviceName) == sizeof(uniqueId)); // total paranoia
   319       strcpy(uniqueId,deviceName); // safe given assert and initialization/error-check
   320     }
   322     nsRefPtr<MediaEngineWebRTCAudioSource> aSource;
   323     NS_ConvertUTF8toUTF16 uuid(uniqueId);
   324     if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) {
   325       // We've already seen this device, just append.
   326       aASources->AppendElement(aSource.get());
   327     } else {
   328       aSource = new MediaEngineWebRTCAudioSource(
   329         mVoiceEngine, i, deviceName, uniqueId
   330       );
   331       mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
   332       aASources->AppendElement(aSource);
   333     }
   334   }
   335 }
   337 void
   338 MediaEngineWebRTC::Shutdown()
   339 {
   340   // This is likely paranoia
   341   MutexAutoLock lock(mMutex);
   343   if (mVideoEngine) {
   344     mVideoSources.Clear();
   345     webrtc::VideoEngine::Delete(mVideoEngine);
   346   }
   348   if (mVoiceEngine) {
   349     mAudioSources.Clear();
   350     webrtc::VoiceEngine::Delete(mVoiceEngine);
   351   }
   353   mVideoEngine = nullptr;
   354   mVoiceEngine = nullptr;
   355 }
   357 }

mercurial