/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaEngine.h" #include "mozilla/Services.h" #include "nsHashKeys.h" #include "nsGlobalWindow.h" #include "nsClassHashtable.h" #include "nsRefPtrHashtable.h" #include "nsObserverService.h" #include "nsPIDOMWindow.h" #include "nsIDOMNavigatorUserMedia.h" #include "mozilla/Attributes.h" namespace mozilla { class GetUserMediaNotificationEvent: public nsRunnable { public: enum GetUserMediaStatus { STARTING, STOPPING }; GetUserMediaNotificationEvent(GetUserMediaStatus aStatus) : mStatus(aStatus) {} NS_IMETHOD Run() { nsCOMPtr obs = mozilla::services::GetObserverService(); if (!obs) { NS_WARNING("Could not get the Observer service for GetUserMedia recording notification."); return NS_ERROR_FAILURE; } if (mStatus) { obs->NotifyObservers(nullptr, "recording-device-events", NS_LITERAL_STRING("starting").get()); } else { obs->NotifyObservers(nullptr, "recording-device-events", NS_LITERAL_STRING("shutdown").get()); } return NS_OK; } protected: GetUserMediaStatus mStatus; }; /** * This class is an implementation of MediaStreamListener. This is used * to Start() and Stop() the underlying MediaEngineSource when MediaStreams * are assigned and deassigned in content. */ class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener { public: GetUserMediaCallbackMediaStreamListener(MediaEngineSource* aSource, nsDOMMediaStream* aStream, TrackID aListenId) : mSource(aSource) , mStream(aStream) , mID(aListenId) , mValid(true) {} void Invalidate() { if (!mValid) { return; } mValid = false; mSource->Stop(); mSource->Deallocate(); nsCOMPtr event = new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming) { if (aConsuming == CONSUMED) { SourceMediaStream* stream = mStream->GetStream()->AsSourceStream(); mSource->Start(stream, mID); nsCOMPtr event = new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); return; } // NOT_CONSUMED Invalidate(); return; } void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {} void NotifyOutput(MediaStreamGraph* aGraph) {} void NotifyFinished(MediaStreamGraph* aGraph) {} void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, TrackRate aTrackRate, TrackTicks aTrackOffset, uint32_t aTrackEvents, const MediaSegment& aQueuedMedia) {} private: nsRefPtr mSource; nsCOMPtr mStream; TrackID mID; bool mValid; }; typedef nsTArray > StreamListeners; typedef nsClassHashtable WindowTable; class MediaDevice : public nsIMediaDevice { public: NS_DECL_ISUPPORTS NS_DECL_NSIMEDIADEVICE MediaDevice(MediaEngineVideoSource* aSource) { mSource = aSource; mType.Assign(NS_LITERAL_STRING("video")); mSource->GetName(mName); }; MediaDevice(MediaEngineAudioSource* aSource) { mSource = aSource; mType.Assign(NS_LITERAL_STRING("audio")); mSource->GetName(mName); }; virtual ~MediaDevice() {}; MediaEngineSource* GetSource(); private: nsString mName; nsString mType; nsRefPtr mSource; }; class MediaManager MOZ_FINAL : public nsIObserver { public: static MediaManager* Get() { if (!sSingleton) { sSingleton = new MediaManager(); nsCOMPtr obs = services::GetObserverService(); obs->AddObserver(sSingleton, "xpcom-shutdown", false); obs->AddObserver(sSingleton, "getUserMedia:response:allow", false); obs->AddObserver(sSingleton, "getUserMedia:response:deny", false); } return sSingleton; } NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER MediaEngine* GetBackend(); WindowTable* GetActiveWindows(); nsresult GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow, nsIMediaStreamOptions* aParams, nsIDOMGetUserMediaSuccessCallback* onSuccess, nsIDOMGetUserMediaErrorCallback* onError); nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow, nsIGetUserMediaDevicesSuccessCallback* onSuccess, nsIDOMGetUserMediaErrorCallback* onError); void OnNavigation(uint64_t aWindowID); private: // Make private because we want only one instance of this class MediaManager() : mBackend(nullptr) , mMediaThread(nullptr) { mActiveWindows.Init(); mActiveCallbacks.Init(); }; MediaManager(MediaManager const&) {}; ~MediaManager() { delete mBackend; }; MediaEngine* mBackend; nsCOMPtr mMediaThread; WindowTable mActiveWindows; nsRefPtrHashtable mActiveCallbacks; static nsRefPtr sSingleton; }; } // namespace mozilla