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

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

mercurial