content/media/webrtc/MediaEngineWebRTC.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/webrtc/MediaEngineWebRTC.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,357 @@
     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 +#ifdef MOZ_LOGGING
     1.9 +#define FORCE_PR_LOG
    1.10 +#endif
    1.11 +
    1.12 +#if defined(PR_LOG)
    1.13 +#error "This file must be #included before any IPDL-generated files or other files that #include prlog.h"
    1.14 +#endif
    1.15 +
    1.16 +#include "nsIPrefService.h"
    1.17 +#include "nsIPrefBranch.h"
    1.18 +
    1.19 +#include "CSFLog.h"
    1.20 +#include "prenv.h"
    1.21 +
    1.22 +#ifdef PR_LOGGING
    1.23 +static PRLogModuleInfo*
    1.24 +GetUserMediaLog()
    1.25 +{
    1.26 +  static PRLogModuleInfo *sLog;
    1.27 +  if (!sLog)
    1.28 +    sLog = PR_NewLogModule("GetUserMedia");
    1.29 +  return sLog;
    1.30 +}
    1.31 +#endif
    1.32 +
    1.33 +#include "MediaEngineWebRTC.h"
    1.34 +#include "ImageContainer.h"
    1.35 +#include "nsIComponentRegistrar.h"
    1.36 +#include "MediaEngineTabVideoSource.h"
    1.37 +#include "nsITabSource.h"
    1.38 +#include "MediaTrackConstraints.h"
    1.39 +
    1.40 +#ifdef MOZ_WIDGET_ANDROID
    1.41 +#include "AndroidJNIWrapper.h"
    1.42 +#include "AndroidBridge.h"
    1.43 +#endif
    1.44 +
    1.45 +#undef LOG
    1.46 +#define LOG(args) PR_LOG(GetUserMediaLog(), PR_LOG_DEBUG, args)
    1.47 +
    1.48 +namespace mozilla {
    1.49 +
    1.50 +MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
    1.51 +  : mMutex("mozilla::MediaEngineWebRTC")
    1.52 +  , mVideoEngine(nullptr)
    1.53 +  , mVoiceEngine(nullptr)
    1.54 +  , mVideoEngineInit(false)
    1.55 +  , mAudioEngineInit(false)
    1.56 +  , mHasTabVideoSource(false)
    1.57 +{
    1.58 +#ifndef MOZ_B2G_CAMERA
    1.59 +  nsCOMPtr<nsIComponentRegistrar> compMgr;
    1.60 +  NS_GetComponentRegistrar(getter_AddRefs(compMgr));
    1.61 +  if (compMgr) {
    1.62 +    compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
    1.63 +  }
    1.64 +#else
    1.65 +  AsyncLatencyLogger::Get()->AddRef();
    1.66 +#endif
    1.67 +  // XXX
    1.68 +  gFarendObserver = new AudioOutputObserver();
    1.69 +}
    1.70 +
    1.71 +void
    1.72 +MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
    1.73 +{
    1.74 +#ifdef MOZ_B2G_CAMERA
    1.75 +  MutexAutoLock lock(mMutex);
    1.76 +
    1.77 +  /**
    1.78 +   * We still enumerate every time, in case a new device was plugged in since
    1.79 +   * the last call. TODO: Verify that WebRTC actually does deal with hotplugging
    1.80 +   * new devices (with or without new engine creation) and accordingly adjust.
    1.81 +   * Enumeration is not neccessary if GIPS reports the same set of devices
    1.82 +   * for a given instance of the engine. Likewise, if a device was plugged out,
    1.83 +   * mVideoSources must be updated.
    1.84 +   */
    1.85 +  int num = 0;
    1.86 +  nsresult result;
    1.87 +  result = ICameraControl::GetNumberOfCameras(num);
    1.88 +  if (num <= 0 || result != NS_OK) {
    1.89 +    return;
    1.90 +  }
    1.91 +
    1.92 +  for (int i = 0; i < num; i++) {
    1.93 +    nsCString cameraName;
    1.94 +    result = ICameraControl::GetCameraName(i, cameraName);
    1.95 +    if (result != NS_OK) {
    1.96 +      continue;
    1.97 +    }
    1.98 +
    1.99 +    nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
   1.100 +    NS_ConvertUTF8toUTF16 uuid(cameraName);
   1.101 +    if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
   1.102 +      // We've already seen this device, just append.
   1.103 +      aVSources->AppendElement(vSource.get());
   1.104 +    } else {
   1.105 +      vSource = new MediaEngineWebRTCVideoSource(i);
   1.106 +      mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
   1.107 +      aVSources->AppendElement(vSource);
   1.108 +    }
   1.109 +  }
   1.110 +
   1.111 +  return;
   1.112 +#else
   1.113 +  ScopedCustomReleasePtr<webrtc::ViEBase> ptrViEBase;
   1.114 +  ScopedCustomReleasePtr<webrtc::ViECapture> ptrViECapture;
   1.115 +
   1.116 +  // We spawn threads to handle gUM runnables, so we must protect the member vars
   1.117 +  MutexAutoLock lock(mMutex);
   1.118 +
   1.119 +#ifdef MOZ_WIDGET_ANDROID
   1.120 +  jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
   1.121 +
   1.122 +  // get the JVM
   1.123 +  JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
   1.124 +
   1.125 +  if (webrtc::VideoEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
   1.126 +    LOG(("VieCapture:SetAndroidObjects Failed"));
   1.127 +    return;
   1.128 +  }
   1.129 +#endif
   1.130 +  if (!mVideoEngine) {
   1.131 +    if (!(mVideoEngine = webrtc::VideoEngine::Create())) {
   1.132 +      return;
   1.133 +    }
   1.134 +  }
   1.135 +
   1.136 +  PRLogModuleInfo *logs = GetWebRTCLogInfo();
   1.137 +  if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
   1.138 +    // no need to a critical section or lock here
   1.139 +    gWebrtcTraceLoggingOn = 1;
   1.140 +
   1.141 +    const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
   1.142 +    if (!file) {
   1.143 +      file = "WebRTC.log";
   1.144 +    }
   1.145 +
   1.146 +    LOG(("%s Logging webrtc to %s level %d", __FUNCTION__, file, logs->level));
   1.147 +
   1.148 +    mVideoEngine->SetTraceFilter(logs->level);
   1.149 +    mVideoEngine->SetTraceFile(file);
   1.150 +  }
   1.151 +
   1.152 +  ptrViEBase = webrtc::ViEBase::GetInterface(mVideoEngine);
   1.153 +  if (!ptrViEBase) {
   1.154 +    return;
   1.155 +  }
   1.156 +
   1.157 +  if (!mVideoEngineInit) {
   1.158 +    if (ptrViEBase->Init() < 0) {
   1.159 +      return;
   1.160 +    }
   1.161 +    mVideoEngineInit = true;
   1.162 +  }
   1.163 +
   1.164 +  ptrViECapture = webrtc::ViECapture::GetInterface(mVideoEngine);
   1.165 +  if (!ptrViECapture) {
   1.166 +    return;
   1.167 +  }
   1.168 +
   1.169 +  /**
   1.170 +   * We still enumerate every time, in case a new device was plugged in since
   1.171 +   * the last call. TODO: Verify that WebRTC actually does deal with hotplugging
   1.172 +   * new devices (with or without new engine creation) and accordingly adjust.
   1.173 +   * Enumeration is not neccessary if GIPS reports the same set of devices
   1.174 +   * for a given instance of the engine. Likewise, if a device was plugged out,
   1.175 +   * mVideoSources must be updated.
   1.176 +   */
   1.177 +  int num = ptrViECapture->NumberOfCaptureDevices();
   1.178 +  if (num <= 0) {
   1.179 +    return;
   1.180 +  }
   1.181 +
   1.182 +  for (int i = 0; i < num; i++) {
   1.183 +    const unsigned int kMaxDeviceNameLength = 128; // XXX FIX!
   1.184 +    const unsigned int kMaxUniqueIdLength = 256;
   1.185 +    char deviceName[kMaxDeviceNameLength];
   1.186 +    char uniqueId[kMaxUniqueIdLength];
   1.187 +
   1.188 +    // paranoia
   1.189 +    deviceName[0] = '\0';
   1.190 +    uniqueId[0] = '\0';
   1.191 +    int error = ptrViECapture->GetCaptureDevice(i, deviceName,
   1.192 +                                                sizeof(deviceName), uniqueId,
   1.193 +                                                sizeof(uniqueId));
   1.194 +
   1.195 +    if (error) {
   1.196 +      LOG((" VieCapture:GetCaptureDevice: Failed %d",
   1.197 +           ptrViEBase->LastError() ));
   1.198 +      continue;
   1.199 +    }
   1.200 +#ifdef DEBUG
   1.201 +    LOG(("  Capture Device Index %d, Name %s", i, deviceName));
   1.202 +
   1.203 +    webrtc::CaptureCapability cap;
   1.204 +    int numCaps = ptrViECapture->NumberOfCapabilities(uniqueId, kMaxUniqueIdLength);
   1.205 +    LOG(("Number of Capabilities %d", numCaps));
   1.206 +    for (int j = 0; j < numCaps; j++) {
   1.207 +      if (ptrViECapture->GetCaptureCapability(uniqueId, kMaxUniqueIdLength,
   1.208 +                                              j, cap ) != 0 ) {
   1.209 +        break;
   1.210 +      }
   1.211 +      LOG(("type=%d width=%d height=%d maxFPS=%d",
   1.212 +           cap.rawType, cap.width, cap.height, cap.maxFPS ));
   1.213 +    }
   1.214 +#endif
   1.215 +
   1.216 +    if (uniqueId[0] == '\0') {
   1.217 +      // In case a device doesn't set uniqueId!
   1.218 +      strncpy(uniqueId, deviceName, sizeof(uniqueId));
   1.219 +      uniqueId[sizeof(uniqueId)-1] = '\0'; // strncpy isn't safe
   1.220 +    }
   1.221 +
   1.222 +    nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
   1.223 +    NS_ConvertUTF8toUTF16 uuid(uniqueId);
   1.224 +    if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
   1.225 +      // We've already seen this device, just append.
   1.226 +      aVSources->AppendElement(vSource.get());
   1.227 +    } else {
   1.228 +      vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
   1.229 +      mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
   1.230 +      aVSources->AppendElement(vSource);
   1.231 +    }
   1.232 +  }
   1.233 +
   1.234 +  if (mHasTabVideoSource)
   1.235 +    aVSources->AppendElement(new MediaEngineTabVideoSource());
   1.236 +
   1.237 +  return;
   1.238 +#endif
   1.239 +}
   1.240 +
   1.241 +void
   1.242 +MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >* aASources)
   1.243 +{
   1.244 +  ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
   1.245 +  ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw;
   1.246 +  // We spawn threads to handle gUM runnables, so we must protect the member vars
   1.247 +  MutexAutoLock lock(mMutex);
   1.248 +
   1.249 +#ifdef MOZ_WIDGET_ANDROID
   1.250 +  jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
   1.251 +
   1.252 +  // get the JVM
   1.253 +  JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
   1.254 +  JNIEnv *env = GetJNIForThread();
   1.255 +
   1.256 +  if (webrtc::VoiceEngine::SetAndroidObjects(jvm, env, (void*)context) != 0) {
   1.257 +    LOG(("VoiceEngine:SetAndroidObjects Failed"));
   1.258 +    return;
   1.259 +  }
   1.260 +#endif
   1.261 +
   1.262 +  if (!mVoiceEngine) {
   1.263 +    mVoiceEngine = webrtc::VoiceEngine::Create();
   1.264 +    if (!mVoiceEngine) {
   1.265 +      return;
   1.266 +    }
   1.267 +  }
   1.268 +
   1.269 +  PRLogModuleInfo *logs = GetWebRTCLogInfo();
   1.270 +  if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
   1.271 +    // no need to a critical section or lock here
   1.272 +    gWebrtcTraceLoggingOn = 1;
   1.273 +
   1.274 +    const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
   1.275 +    if (!file) {
   1.276 +      file = "WebRTC.log";
   1.277 +    }
   1.278 +
   1.279 +    LOG(("Logging webrtc to %s level %d", __FUNCTION__, file, logs->level));
   1.280 +
   1.281 +    mVoiceEngine->SetTraceFilter(logs->level);
   1.282 +    mVoiceEngine->SetTraceFile(file);
   1.283 +  }
   1.284 +
   1.285 +  ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
   1.286 +  if (!ptrVoEBase) {
   1.287 +    return;
   1.288 +  }
   1.289 +
   1.290 +  if (!mAudioEngineInit) {
   1.291 +    if (ptrVoEBase->Init() < 0) {
   1.292 +      return;
   1.293 +    }
   1.294 +    mAudioEngineInit = true;
   1.295 +  }
   1.296 +
   1.297 +  ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
   1.298 +  if (!ptrVoEHw)  {
   1.299 +    return;
   1.300 +  }
   1.301 +
   1.302 +  int nDevices = 0;
   1.303 +  ptrVoEHw->GetNumOfRecordingDevices(nDevices);
   1.304 +  for (int i = 0; i < nDevices; i++) {
   1.305 +    // We use constants here because GetRecordingDeviceName takes char[128].
   1.306 +    char deviceName[128];
   1.307 +    char uniqueId[128];
   1.308 +    // paranoia; jingle doesn't bother with this
   1.309 +    deviceName[0] = '\0';
   1.310 +    uniqueId[0] = '\0';
   1.311 +
   1.312 +    int error = ptrVoEHw->GetRecordingDeviceName(i, deviceName, uniqueId);
   1.313 +    if (error) {
   1.314 +      LOG((" VoEHardware:GetRecordingDeviceName: Failed %d",
   1.315 +           ptrVoEBase->LastError() ));
   1.316 +      continue;
   1.317 +    }
   1.318 +
   1.319 +    if (uniqueId[0] == '\0') {
   1.320 +      // Mac and Linux don't set uniqueId!
   1.321 +      MOZ_ASSERT(sizeof(deviceName) == sizeof(uniqueId)); // total paranoia
   1.322 +      strcpy(uniqueId,deviceName); // safe given assert and initialization/error-check
   1.323 +    }
   1.324 +
   1.325 +    nsRefPtr<MediaEngineWebRTCAudioSource> aSource;
   1.326 +    NS_ConvertUTF8toUTF16 uuid(uniqueId);
   1.327 +    if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) {
   1.328 +      // We've already seen this device, just append.
   1.329 +      aASources->AppendElement(aSource.get());
   1.330 +    } else {
   1.331 +      aSource = new MediaEngineWebRTCAudioSource(
   1.332 +        mVoiceEngine, i, deviceName, uniqueId
   1.333 +      );
   1.334 +      mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
   1.335 +      aASources->AppendElement(aSource);
   1.336 +    }
   1.337 +  }
   1.338 +}
   1.339 +
   1.340 +void
   1.341 +MediaEngineWebRTC::Shutdown()
   1.342 +{
   1.343 +  // This is likely paranoia
   1.344 +  MutexAutoLock lock(mMutex);
   1.345 +
   1.346 +  if (mVideoEngine) {
   1.347 +    mVideoSources.Clear();
   1.348 +    webrtc::VideoEngine::Delete(mVideoEngine);
   1.349 +  }
   1.350 +
   1.351 +  if (mVoiceEngine) {
   1.352 +    mAudioSources.Clear();
   1.353 +    webrtc::VoiceEngine::Delete(mVoiceEngine);
   1.354 +  }
   1.355 +
   1.356 +  mVideoEngine = nullptr;
   1.357 +  mVoiceEngine = nullptr;
   1.358 +}
   1.359 +
   1.360 +}

mercurial