dom/media/MediaManager.h

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.

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 #include "MediaEngine.h"
michael@0 6 #include "mozilla/Services.h"
michael@0 7 #include "mozilla/unused.h"
michael@0 8 #include "nsIMediaManager.h"
michael@0 9
michael@0 10 #include "nsHashKeys.h"
michael@0 11 #include "nsGlobalWindow.h"
michael@0 12 #include "nsClassHashtable.h"
michael@0 13 #include "nsRefPtrHashtable.h"
michael@0 14 #include "nsIObserver.h"
michael@0 15 #include "nsIPrefService.h"
michael@0 16 #include "nsIPrefBranch.h"
michael@0 17
michael@0 18 #include "nsPIDOMWindow.h"
michael@0 19 #include "nsIDOMNavigatorUserMedia.h"
michael@0 20 #include "nsXULAppAPI.h"
michael@0 21 #include "mozilla/Attributes.h"
michael@0 22 #include "mozilla/Preferences.h"
michael@0 23 #include "mozilla/StaticPtr.h"
michael@0 24 #include "mozilla/dom/MediaStreamBinding.h"
michael@0 25 #include "mozilla/dom/MediaStreamTrackBinding.h"
michael@0 26 #include "prlog.h"
michael@0 27 #include "DOMMediaStream.h"
michael@0 28
michael@0 29 #ifdef MOZ_WEBRTC
michael@0 30 #include "mtransport/runnable_utils.h"
michael@0 31 #endif
michael@0 32
michael@0 33 #ifdef MOZ_WIDGET_GONK
michael@0 34 #include "DOMCameraManager.h"
michael@0 35 #endif
michael@0 36
michael@0 37 namespace mozilla {
michael@0 38 namespace dom {
michael@0 39 class MediaStreamConstraints;
michael@0 40 class NavigatorUserMediaSuccessCallback;
michael@0 41 class NavigatorUserMediaErrorCallback;
michael@0 42 }
michael@0 43
michael@0 44 #ifdef PR_LOGGING
michael@0 45 extern PRLogModuleInfo* GetMediaManagerLog();
michael@0 46 #define MM_LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
michael@0 47 #else
michael@0 48 #define MM_LOG(msg)
michael@0 49 #endif
michael@0 50
michael@0 51 /**
michael@0 52 * This class is an implementation of MediaStreamListener. This is used
michael@0 53 * to Start() and Stop() the underlying MediaEngineSource when MediaStreams
michael@0 54 * are assigned and deassigned in content.
michael@0 55 */
michael@0 56 class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
michael@0 57 {
michael@0 58 public:
michael@0 59 // Create in an inactive state
michael@0 60 GetUserMediaCallbackMediaStreamListener(nsIThread *aThread,
michael@0 61 uint64_t aWindowID)
michael@0 62 : mMediaThread(aThread)
michael@0 63 , mWindowID(aWindowID)
michael@0 64 , mStopped(false)
michael@0 65 , mFinished(false)
michael@0 66 , mLock("mozilla::GUMCMSL")
michael@0 67 , mRemoved(false) {}
michael@0 68
michael@0 69 ~GetUserMediaCallbackMediaStreamListener()
michael@0 70 {
michael@0 71 // It's OK to release mStream on any thread; they have thread-safe
michael@0 72 // refcounts.
michael@0 73 }
michael@0 74
michael@0 75 void Activate(already_AddRefed<SourceMediaStream> aStream,
michael@0 76 MediaEngineSource* aAudioSource,
michael@0 77 MediaEngineSource* aVideoSource)
michael@0 78 {
michael@0 79 NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
michael@0 80 mStream = aStream;
michael@0 81 mAudioSource = aAudioSource;
michael@0 82 mVideoSource = aVideoSource;
michael@0 83 mLastEndTimeAudio = 0;
michael@0 84 mLastEndTimeVideo = 0;
michael@0 85
michael@0 86 mStream->AddListener(this);
michael@0 87 }
michael@0 88
michael@0 89 MediaStream *Stream() // Can be used to test if Activate was called
michael@0 90 {
michael@0 91 return mStream;
michael@0 92 }
michael@0 93 SourceMediaStream *GetSourceStream()
michael@0 94 {
michael@0 95 NS_ASSERTION(mStream,"Getting stream from never-activated GUMCMSListener");
michael@0 96 if (!mStream) {
michael@0 97 return nullptr;
michael@0 98 }
michael@0 99 return mStream->AsSourceStream();
michael@0 100 }
michael@0 101
michael@0 102 // mVideo/AudioSource are set by Activate(), so we assume they're capturing
michael@0 103 // if set and represent a real capture device.
michael@0 104 bool CapturingVideo()
michael@0 105 {
michael@0 106 NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
michael@0 107 return mVideoSource && !mStopped &&
michael@0 108 (!mVideoSource->IsFake() ||
michael@0 109 Preferences::GetBool("media.navigator.permission.fake"));
michael@0 110 }
michael@0 111 bool CapturingAudio()
michael@0 112 {
michael@0 113 NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
michael@0 114 return mAudioSource && !mStopped &&
michael@0 115 (!mAudioSource->IsFake() ||
michael@0 116 Preferences::GetBool("media.navigator.permission.fake"));
michael@0 117 }
michael@0 118
michael@0 119 void SetStopped()
michael@0 120 {
michael@0 121 mStopped = true;
michael@0 122 }
michael@0 123
michael@0 124 // implement in .cpp to avoid circular dependency with MediaOperationRunnable
michael@0 125 // Can be invoked from EITHER MainThread or MSG thread
michael@0 126 void Invalidate();
michael@0 127
michael@0 128 void
michael@0 129 AudioConfig(bool aEchoOn, uint32_t aEcho,
michael@0 130 bool aAgcOn, uint32_t aAGC,
michael@0 131 bool aNoiseOn, uint32_t aNoise,
michael@0 132 int32_t aPlayoutDelay)
michael@0 133 {
michael@0 134 if (mAudioSource) {
michael@0 135 #ifdef MOZ_WEBRTC
michael@0 136 // Right now these configs are only of use if webrtc is available
michael@0 137 RUN_ON_THREAD(mMediaThread,
michael@0 138 WrapRunnable(nsRefPtr<MediaEngineSource>(mAudioSource), // threadsafe
michael@0 139 &MediaEngineSource::Config,
michael@0 140 aEchoOn, aEcho, aAgcOn, aAGC, aNoiseOn, aNoise, aPlayoutDelay),
michael@0 141 NS_DISPATCH_NORMAL);
michael@0 142 #endif
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 void
michael@0 147 Remove()
michael@0 148 {
michael@0 149 NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
michael@0 150 // allow calling even if inactive (!mStream) for easier cleanup
michael@0 151 // Caller holds strong reference to us, so no death grip required
michael@0 152 MutexAutoLock lock(mLock); // protect access to mRemoved
michael@0 153 if (mStream && !mRemoved) {
michael@0 154 MM_LOG(("Listener removed on purpose, mFinished = %d", (int) mFinished));
michael@0 155 mRemoved = true; // RemoveListener is async, avoid races
michael@0 156 // If it's destroyed, don't call - listener will be removed and we'll be notified!
michael@0 157 if (!mStream->IsDestroyed()) {
michael@0 158 mStream->RemoveListener(this);
michael@0 159 }
michael@0 160 }
michael@0 161 }
michael@0 162
michael@0 163 // Proxy NotifyPull() to sources
michael@0 164 virtual void
michael@0 165 NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) MOZ_OVERRIDE
michael@0 166 {
michael@0 167 // Currently audio sources ignore NotifyPull, but they could
michael@0 168 // watch it especially for fake audio.
michael@0 169 if (mAudioSource) {
michael@0 170 mAudioSource->NotifyPull(aGraph, mStream, kAudioTrack, aDesiredTime, mLastEndTimeAudio);
michael@0 171 }
michael@0 172 if (mVideoSource) {
michael@0 173 mVideoSource->NotifyPull(aGraph, mStream, kVideoTrack, aDesiredTime, mLastEndTimeVideo);
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 virtual void
michael@0 178 NotifyFinished(MediaStreamGraph* aGraph) MOZ_OVERRIDE;
michael@0 179
michael@0 180 virtual void
michael@0 181 NotifyRemoved(MediaStreamGraph* aGraph) MOZ_OVERRIDE;
michael@0 182
michael@0 183 private:
michael@0 184 // Set at construction
michael@0 185 nsCOMPtr<nsIThread> mMediaThread;
michael@0 186 uint64_t mWindowID;
michael@0 187
michael@0 188 bool mStopped; // MainThread only
michael@0 189
michael@0 190 // Set at Activate on MainThread
michael@0 191
michael@0 192 // Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread
michael@0 193 // No locking needed as they're only addrefed except on the MediaManager thread
michael@0 194 nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe refcnt
michael@0 195 nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe refcnt
michael@0 196 nsRefPtr<SourceMediaStream> mStream; // threadsafe refcnt
michael@0 197 TrackTicks mLastEndTimeAudio;
michael@0 198 TrackTicks mLastEndTimeVideo;
michael@0 199 bool mFinished;
michael@0 200
michael@0 201 // Accessed from MainThread and MSG thread
michael@0 202 Mutex mLock; // protects mRemoved access from MainThread
michael@0 203 bool mRemoved;
michael@0 204 };
michael@0 205
michael@0 206 class GetUserMediaNotificationEvent: public nsRunnable
michael@0 207 {
michael@0 208 public:
michael@0 209 enum GetUserMediaStatus {
michael@0 210 STARTING,
michael@0 211 STOPPING
michael@0 212 };
michael@0 213 GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener,
michael@0 214 GetUserMediaStatus aStatus,
michael@0 215 bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
michael@0 216 : mListener(aListener) , mStatus(aStatus) , mIsAudio(aIsAudio)
michael@0 217 , mIsVideo(aIsVideo), mWindowID(aWindowID) {}
michael@0 218
michael@0 219 GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
michael@0 220 already_AddRefed<DOMMediaStream> aStream,
michael@0 221 DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
michael@0 222 bool aIsAudio, bool aIsVideo, uint64_t aWindowID,
michael@0 223 already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
michael@0 224 : mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
michael@0 225 mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID),
michael@0 226 mError(aError) {}
michael@0 227 virtual ~GetUserMediaNotificationEvent()
michael@0 228 {
michael@0 229
michael@0 230 }
michael@0 231
michael@0 232 NS_IMETHOD Run() MOZ_OVERRIDE;
michael@0 233
michael@0 234 protected:
michael@0 235 nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
michael@0 236 nsRefPtr<DOMMediaStream> mStream;
michael@0 237 nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
michael@0 238 GetUserMediaStatus mStatus;
michael@0 239 bool mIsAudio;
michael@0 240 bool mIsVideo;
michael@0 241 uint64_t mWindowID;
michael@0 242 nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
michael@0 243 };
michael@0 244
michael@0 245 typedef enum {
michael@0 246 MEDIA_START,
michael@0 247 MEDIA_STOP
michael@0 248 } MediaOperation;
michael@0 249
michael@0 250 class MediaManager;
michael@0 251 class GetUserMediaRunnable;
michael@0 252
michael@0 253 /**
michael@0 254 * Send an error back to content. The error is the form a string.
michael@0 255 * Do this only on the main thread. The success callback is also passed here
michael@0 256 * so it can be released correctly.
michael@0 257 */
michael@0 258 class ErrorCallbackRunnable : public nsRunnable
michael@0 259 {
michael@0 260 public:
michael@0 261 ErrorCallbackRunnable(
michael@0 262 nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
michael@0 263 nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
michael@0 264 const nsAString& aErrorMsg, uint64_t aWindowID);
michael@0 265 NS_IMETHOD Run();
michael@0 266 private:
michael@0 267 ~ErrorCallbackRunnable();
michael@0 268
michael@0 269 nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
michael@0 270 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
michael@0 271 const nsString mErrorMsg;
michael@0 272 uint64_t mWindowID;
michael@0 273 nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
michael@0 274 };
michael@0 275
michael@0 276 class ReleaseMediaOperationResource : public nsRunnable
michael@0 277 {
michael@0 278 public:
michael@0 279 ReleaseMediaOperationResource(already_AddRefed<DOMMediaStream> aStream,
michael@0 280 DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback):
michael@0 281 mStream(aStream),
michael@0 282 mOnTracksAvailableCallback(aOnTracksAvailableCallback) {}
michael@0 283 NS_IMETHOD Run() MOZ_OVERRIDE {return NS_OK;}
michael@0 284 private:
michael@0 285 nsRefPtr<DOMMediaStream> mStream;
michael@0 286 nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
michael@0 287 };
michael@0 288
michael@0 289 // Generic class for running long media operations like Start off the main
michael@0 290 // thread, and then (because nsDOMMediaStreams aren't threadsafe),
michael@0 291 // ProxyReleases mStream since it's cycle collected.
michael@0 292 class MediaOperationRunnable : public nsRunnable
michael@0 293 {
michael@0 294 public:
michael@0 295 // so we can send Stop without AddRef()ing from the MSG thread
michael@0 296 MediaOperationRunnable(MediaOperation aType,
michael@0 297 GetUserMediaCallbackMediaStreamListener* aListener,
michael@0 298 DOMMediaStream* aStream,
michael@0 299 DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
michael@0 300 MediaEngineSource* aAudioSource,
michael@0 301 MediaEngineSource* aVideoSource,
michael@0 302 bool aNeedsFinish,
michael@0 303 uint64_t aWindowID,
michael@0 304 already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
michael@0 305 : mType(aType)
michael@0 306 , mStream(aStream)
michael@0 307 , mOnTracksAvailableCallback(aOnTracksAvailableCallback)
michael@0 308 , mAudioSource(aAudioSource)
michael@0 309 , mVideoSource(aVideoSource)
michael@0 310 , mListener(aListener)
michael@0 311 , mFinish(aNeedsFinish)
michael@0 312 , mWindowID(aWindowID)
michael@0 313 , mError(aError)
michael@0 314 {}
michael@0 315
michael@0 316 ~MediaOperationRunnable()
michael@0 317 {
michael@0 318 // MediaStreams can be released on any thread.
michael@0 319 }
michael@0 320
michael@0 321 nsresult returnAndCallbackError(nsresult rv, const char* errorLog)
michael@0 322 {
michael@0 323 MM_LOG(("%s , rv=%d", errorLog, rv));
michael@0 324 NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
michael@0 325 mOnTracksAvailableCallback.forget()));
michael@0 326 nsString log;
michael@0 327
michael@0 328 log.AssignASCII(errorLog, strlen(errorLog));
michael@0 329 nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success;
michael@0 330 NS_DispatchToMainThread(new ErrorCallbackRunnable(success, mError,
michael@0 331 log, mWindowID));
michael@0 332 return NS_OK;
michael@0 333 }
michael@0 334
michael@0 335 NS_IMETHOD
michael@0 336 Run() MOZ_OVERRIDE
michael@0 337 {
michael@0 338 SourceMediaStream *source = mListener->GetSourceStream();
michael@0 339 // No locking between these is required as all the callbacks for the
michael@0 340 // same MediaStream will occur on the same thread.
michael@0 341 if (!source) // means the stream was never Activated()
michael@0 342 return NS_OK;
michael@0 343
michael@0 344 switch (mType) {
michael@0 345 case MEDIA_START:
michael@0 346 {
michael@0 347 NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
michael@0 348 nsresult rv;
michael@0 349
michael@0 350 source->SetPullEnabled(true);
michael@0 351
michael@0 352 DOMMediaStream::TrackTypeHints expectedTracks = 0;
michael@0 353 if (mAudioSource) {
michael@0 354 rv = mAudioSource->Start(source, kAudioTrack);
michael@0 355 if (NS_SUCCEEDED(rv)) {
michael@0 356 expectedTracks |= DOMMediaStream::HINT_CONTENTS_AUDIO;
michael@0 357 } else {
michael@0 358 return returnAndCallbackError(rv, "Starting audio failed");
michael@0 359 }
michael@0 360 }
michael@0 361 if (mVideoSource) {
michael@0 362 rv = mVideoSource->Start(source, kVideoTrack);
michael@0 363 if (NS_SUCCEEDED(rv)) {
michael@0 364 expectedTracks |= DOMMediaStream::HINT_CONTENTS_VIDEO;
michael@0 365 } else {
michael@0 366 return returnAndCallbackError(rv, "Starting video failed");
michael@0 367 }
michael@0 368 }
michael@0 369
michael@0 370 mOnTracksAvailableCallback->SetExpectedTracks(expectedTracks);
michael@0 371
michael@0 372 MM_LOG(("started all sources"));
michael@0 373 // Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent,
michael@0 374 // because mOnTracksAvailableCallback needs to be added to mStream
michael@0 375 // on the main thread.
michael@0 376 nsIRunnable *event =
michael@0 377 new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING,
michael@0 378 mStream.forget(),
michael@0 379 mOnTracksAvailableCallback.forget(),
michael@0 380 mAudioSource != nullptr,
michael@0 381 mVideoSource != nullptr,
michael@0 382 mWindowID, mError.forget());
michael@0 383 // event must always be released on mainthread due to the JS callbacks
michael@0 384 // in the TracksAvailableCallback
michael@0 385 NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
michael@0 386 }
michael@0 387 break;
michael@0 388
michael@0 389 case MEDIA_STOP:
michael@0 390 {
michael@0 391 NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
michael@0 392 if (mAudioSource) {
michael@0 393 mAudioSource->Stop(source, kAudioTrack);
michael@0 394 mAudioSource->Deallocate();
michael@0 395 }
michael@0 396 if (mVideoSource) {
michael@0 397 mVideoSource->Stop(source, kVideoTrack);
michael@0 398 mVideoSource->Deallocate();
michael@0 399 }
michael@0 400 // Do this after stopping all tracks with EndTrack()
michael@0 401 if (mFinish) {
michael@0 402 source->Finish();
michael@0 403 }
michael@0 404 nsIRunnable *event =
michael@0 405 new GetUserMediaNotificationEvent(mListener,
michael@0 406 GetUserMediaNotificationEvent::STOPPING,
michael@0 407 mAudioSource != nullptr,
michael@0 408 mVideoSource != nullptr,
michael@0 409 mWindowID);
michael@0 410 // event must always be released on mainthread due to the JS callbacks
michael@0 411 // in the TracksAvailableCallback
michael@0 412 NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
michael@0 413 }
michael@0 414 break;
michael@0 415
michael@0 416 default:
michael@0 417 MOZ_ASSERT(false,"invalid MediaManager operation");
michael@0 418 break;
michael@0 419 }
michael@0 420 return NS_OK;
michael@0 421 }
michael@0 422
michael@0 423 private:
michael@0 424 MediaOperation mType;
michael@0 425 nsRefPtr<DOMMediaStream> mStream;
michael@0 426 nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
michael@0 427 nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
michael@0 428 nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
michael@0 429 nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
michael@0 430 bool mFinish;
michael@0 431 uint64_t mWindowID;
michael@0 432 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
michael@0 433 };
michael@0 434
michael@0 435 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
michael@0 436 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
michael@0 437
michael@0 438 class MediaDevice : public nsIMediaDevice
michael@0 439 {
michael@0 440 public:
michael@0 441 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 442 NS_DECL_NSIMEDIADEVICE
michael@0 443
michael@0 444 static MediaDevice* Create(MediaEngineVideoSource* source);
michael@0 445 static MediaDevice* Create(MediaEngineAudioSource* source);
michael@0 446
michael@0 447 virtual ~MediaDevice() {}
michael@0 448 protected:
michael@0 449 MediaDevice(MediaEngineSource* aSource);
michael@0 450 nsString mName;
michael@0 451 nsString mID;
michael@0 452 bool mHasFacingMode;
michael@0 453 dom::VideoFacingModeEnum mFacingMode;
michael@0 454 nsRefPtr<MediaEngineSource> mSource;
michael@0 455 };
michael@0 456
michael@0 457 class VideoDevice : public MediaDevice
michael@0 458 {
michael@0 459 public:
michael@0 460 VideoDevice(MediaEngineVideoSource* aSource);
michael@0 461 NS_IMETHOD GetType(nsAString& aType);
michael@0 462 MediaEngineVideoSource* GetSource();
michael@0 463 };
michael@0 464
michael@0 465 class AudioDevice : public MediaDevice
michael@0 466 {
michael@0 467 public:
michael@0 468 AudioDevice(MediaEngineAudioSource* aSource);
michael@0 469 NS_IMETHOD GetType(nsAString& aType);
michael@0 470 MediaEngineAudioSource* GetSource();
michael@0 471 };
michael@0 472
michael@0 473 // we could add MediaManager if needed
michael@0 474 typedef void (*WindowListenerCallback)(MediaManager *aThis,
michael@0 475 uint64_t aWindowID,
michael@0 476 StreamListeners *aListeners,
michael@0 477 void *aData);
michael@0 478
michael@0 479 class MediaManager MOZ_FINAL : public nsIMediaManagerService,
michael@0 480 public nsIObserver
michael@0 481 {
michael@0 482 public:
michael@0 483 static already_AddRefed<MediaManager> GetInstance();
michael@0 484
michael@0 485 // NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
michael@0 486 // thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
michael@0 487 // from MediaManager thread.
michael@0 488 static MediaManager* Get();
michael@0 489
michael@0 490 static bool Exists()
michael@0 491 {
michael@0 492 return !!sSingleton;
michael@0 493 }
michael@0 494
michael@0 495 static nsIThread* GetThread() {
michael@0 496 return Get()->mMediaThread;
michael@0 497 }
michael@0 498
michael@0 499 static nsresult NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
michael@0 500 const nsString& aMsg,
michael@0 501 const bool& aIsAudio,
michael@0 502 const bool& aIsVideo);
michael@0 503
michael@0 504 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 505 NS_DECL_NSIOBSERVER
michael@0 506 NS_DECL_NSIMEDIAMANAGERSERVICE
michael@0 507
michael@0 508 MediaEngine* GetBackend(uint64_t aWindowId = 0);
michael@0 509 StreamListeners *GetWindowListeners(uint64_t aWindowId) {
michael@0 510 NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
michael@0 511
michael@0 512 return mActiveWindows.Get(aWindowId);
michael@0 513 }
michael@0 514 void RemoveWindowID(uint64_t aWindowId) {
michael@0 515 mActiveWindows.Remove(aWindowId);
michael@0 516 }
michael@0 517 bool IsWindowStillActive(uint64_t aWindowId) {
michael@0 518 return !!GetWindowListeners(aWindowId);
michael@0 519 }
michael@0 520 // Note: also calls aListener->Remove(), even if inactive
michael@0 521 void RemoveFromWindowList(uint64_t aWindowID,
michael@0 522 GetUserMediaCallbackMediaStreamListener *aListener);
michael@0 523
michael@0 524 nsresult GetUserMedia(bool aPrivileged,
michael@0 525 nsPIDOMWindow* aWindow,
michael@0 526 const dom::MediaStreamConstraints& aRawConstraints,
michael@0 527 nsIDOMGetUserMediaSuccessCallback* onSuccess,
michael@0 528 nsIDOMGetUserMediaErrorCallback* onError);
michael@0 529
michael@0 530 nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
michael@0 531 const dom::MediaStreamConstraints& aConstraints,
michael@0 532 nsIGetUserMediaDevicesSuccessCallback* onSuccess,
michael@0 533 nsIDOMGetUserMediaErrorCallback* onError,
michael@0 534 uint64_t aInnerWindowID = 0);
michael@0 535 void OnNavigation(uint64_t aWindowID);
michael@0 536
michael@0 537 MediaEnginePrefs mPrefs;
michael@0 538
michael@0 539 private:
michael@0 540 WindowTable *GetActiveWindows() {
michael@0 541 NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
michael@0 542 return &mActiveWindows;
michael@0 543 }
michael@0 544
michael@0 545 void GetPref(nsIPrefBranch *aBranch, const char *aPref,
michael@0 546 const char *aData, int32_t *aVal);
michael@0 547 void GetPrefBool(nsIPrefBranch *aBranch, const char *aPref,
michael@0 548 const char *aData, bool *aVal);
michael@0 549 void GetPrefs(nsIPrefBranch *aBranch, const char *aData);
michael@0 550
michael@0 551 // Make private because we want only one instance of this class
michael@0 552 MediaManager();
michael@0 553
michael@0 554 ~MediaManager() {}
michael@0 555
michael@0 556 void IterateWindowListeners(nsPIDOMWindow *aWindow,
michael@0 557 WindowListenerCallback aCallback,
michael@0 558 void *aData);
michael@0 559
michael@0 560 void StopMediaStreams();
michael@0 561
michael@0 562 // ONLY access from MainThread so we don't need to lock
michael@0 563 WindowTable mActiveWindows;
michael@0 564 nsRefPtrHashtable<nsStringHashKey, GetUserMediaRunnable> mActiveCallbacks;
michael@0 565 nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
michael@0 566 // Always exists
michael@0 567 nsCOMPtr<nsIThread> mMediaThread;
michael@0 568
michael@0 569 Mutex mMutex;
michael@0 570 // protected with mMutex:
michael@0 571 RefPtr<MediaEngine> mBackend;
michael@0 572
michael@0 573 static StaticRefPtr<MediaManager> sSingleton;
michael@0 574
michael@0 575 #ifdef MOZ_B2G_CAMERA
michael@0 576 nsRefPtr<nsDOMCameraManager> mCameraManager;
michael@0 577 #endif
michael@0 578 };
michael@0 579
michael@0 580 } // namespace mozilla

mercurial