--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -6,16 +6,17 @@
#include "MediaManager.h"
#include "MediaStreamGraph.h"
#include "mozilla/dom/MediaStreamTrack.h"
#include "MediaStreamListener.h"
#include "nsArray.h"
#include "nsContentUtils.h"
+#include "nsGlobalWindow.h"
#include "nsHashPropertyBag.h"
#include "nsIEventTarget.h"
#include "nsIUUIDGenerator.h"
#include "nsIScriptGlobalObject.h"
#include "nsIPermissionManager.h"
#include "nsIPopupWindowManager.h"
#include "nsIDocShell.h"
#include "nsIDocument.h"
@@ -25,16 +26,17 @@
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsICryptoHash.h"
#include "nsICryptoHMAC.h"
#include "nsIKeyModule.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIInputStream.h"
#include "nsILineInputStream.h"
+#include "nsPIDOMWindow.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Types.h"
#include "mozilla/PeerIdentity.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/File.h"
@@ -522,25 +524,26 @@ public:
return true;
}
void StopSharing();
void StopRawID(const nsString& removedDeviceID);
/**
- * Called by one of our SourceListeners when one of its tracks has stopped.
+ * Called by one of our SourceListeners when one of its tracks has changed so
+ * that chrome state is affected.
* Schedules an event for the next stable state to update chrome.
*/
- void NotifySourceTrackStopped();
+ void ChromeAffectingStateChanged();
/**
* Called in stable state to send a notification to update chrome.
*/
- void NotifyChromeOfTrackStops();
+ void NotifyChrome();
bool CapturingVideo() const
{
MOZ_ASSERT(NS_IsMainThread());
for (auto& l : mActiveListeners) {
if (l->CapturingVideo()) {
return true;
}
@@ -1220,19 +1223,18 @@ public:
mWindowListener->Activate(mSourceListener, stream, mAudioDevice, mVideoDevice);
// Note: includes JS callbacks; must be released on MainThread
auto callback = MakeRefPtr<Refcountable<UniquePtr<OnTracksAvailableCallback>>>(
new TracksAvailableCallback(mManager, mOnSuccess.forget(), mWindowID, domStream));
// Dispatch to the media thread to ask it to start the sources,
// because that can take a while.
- // Pass ownership of domStream through the lambda to
- // GetUserMediaNotificationEvent to ensure it's kept alive until the
- // GetUserMediaNotificationEvent runs or is discarded.
+ // Pass ownership of domStream through the lambda to the nested chrome
+ // notification lambda to ensure it's kept alive until that lambda runs or is discarded.
RefPtr<GetUserMediaStreamRunnable> self = this;
MediaManager::PostTask(NewTaskFrom([self, domStream, callback]() mutable {
MOZ_ASSERT(MediaManager::IsInMediaThread());
SourceMediaStream* source = self->mSourceListener->GetSourceStream();
RefPtr<MediaMgrError> error = nullptr;
if (self->mAudioDevice) {
nsresult rv =
@@ -1280,34 +1282,40 @@ public:
// Start() queued the tracks to be added synchronously to avoid races
source->FinishAddTracks();
source->SetPullEnabled(true);
source->AdvanceKnownTracksTime(STREAM_TIME_MAX);
LOG(("started all sources"));
- // Forward onTracksAvailableCallback to GetUserMediaNotificationEvent,
- // because onTracksAvailableCallback needs to be added to domStream
- // on the main thread.
- // The event runnable must always be released on mainthread due to the JS
- // callbacks in the TracksAvailableCallback.
- NS_DispatchToMainThread(do_AddRef(
- new GetUserMediaNotificationEvent(
- GetUserMediaNotificationEvent::STARTING,
- domStream.forget(),
- callback.forget(),
- self->mWindowID,
- self->mOnFailure.forget())));
- NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::SendPendingGUMRequest",
- []() -> void {
+ // onTracksAvailableCallback must be added to domStream on the main thread.
+ uint64_t windowID = self->mWindowID;
+ NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::NotifyChromeOfStart",
+ [domStream, callback, windowID]() mutable {
MediaManager* manager = MediaManager::GetIfExists();
if (!manager) {
return;
}
+
+ nsGlobalWindowInner* window =
+ nsGlobalWindowInner::GetInnerWindowWithId(windowID);
+ if (!window) {
+ MOZ_ASSERT_UNREACHABLE("Should have window");
+ return;
+ }
+
+ domStream->OnTracksAvailable(callback->release());
+
+ nsresult rv = MediaManager::NotifyRecordingStatusChange(window->AsInner());
+ if (NS_FAILED(rv)) {
+ MOZ_ASSERT_UNREACHABLE("Should be able to notify chrome");
+ return;
+ }
+
manager->SendPendingGUMRequest();
}));
return NS_OK;
}));
if (!IsPincipalInfoPrivate(mPrincipalInfo)) {
// Call GetPrincipalKey again, this time w/persist = true, to promote
// deviceIds to persistent, in case they're not already. Fire'n'forget.
@@ -2009,18 +2017,17 @@ MediaManager::PostTask(already_AddRefed<
return;
}
NS_ASSERTION(Get(), "MediaManager singleton?");
NS_ASSERTION(Get()->mMediaThread, "No thread yet");
Get()->mMediaThread->message_loop()->PostTask(Move(task));
}
/* static */ nsresult
-MediaManager::NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow,
- const nsString& aMsg)
+MediaManager::NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow)
{
NS_ENSURE_ARG(aWindow);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
NS_WARNING("Could not get the Observer service for GetUserMedia recording notification.");
return NS_ERROR_FAILURE;
}
@@ -2035,17 +2042,17 @@ MediaManager::NotifyRecordingStatusChang
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF8toUTF16 requestURL(pageURL);
props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
"recording-device-events",
- aMsg.get());
+ nullptr);
return NS_OK;
}
int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
{
bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
@@ -3829,17 +3836,17 @@ SourceListener::StopTrack(TrackID aTrack
LOG(("SourceListener %p this was the last track stopped", this));
Stop();
}
if (!mWindowListener) {
MOZ_ASSERT(false, "Should still have window listener");
return;
}
- mWindowListener->NotifySourceTrackStopped();
+ mWindowListener->ChromeAffectingStateChanged();
}
void
SourceListener::DisableTrack(TrackID aTrackID)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
if (!Activated()) {
@@ -4283,93 +4290,48 @@ GetUserMediaWindowListener::StopRawID(co
if (removedDeviceID.Equals(id)) {
source->StopTrack(kVideoTrack);
}
}
}
}
void
-GetUserMediaWindowListener::NotifySourceTrackStopped()
+GetUserMediaWindowListener::ChromeAffectingStateChanged()
{
MOZ_ASSERT(NS_IsMainThread());
// We wait until stable state before notifying chrome so chrome only does one
// update if more tracks are stopped in this event loop.
if (mChromeNotificationTaskPosted) {
return;
}
nsCOMPtr<nsIRunnable> runnable =
- NewRunnableMethod("GetUserMediaWindowListener::NotifyChromeOfTrackStops",
+ NewRunnableMethod("GetUserMediaWindowListener::NotifyChrome",
this,
- &GetUserMediaWindowListener::NotifyChromeOfTrackStops);
+ &GetUserMediaWindowListener::NotifyChrome);
nsContentUtils::RunInStableState(runnable.forget());
mChromeNotificationTaskPosted = true;
}
void
-GetUserMediaWindowListener::NotifyChromeOfTrackStops()
+GetUserMediaWindowListener::NotifyChrome()
{
MOZ_ASSERT(mChromeNotificationTaskPosted);
mChromeNotificationTaskPosted = false;
- NS_DispatchToMainThread(do_AddRef(new GetUserMediaNotificationEvent(
- GetUserMediaNotificationEvent::STOPPING, mWindowID)));
-}
-
-GetUserMediaNotificationEvent::GetUserMediaNotificationEvent(
- GetUserMediaStatus aStatus,
- uint64_t aWindowID)
- : Runnable("GetUserMediaNotificationEvent")
- , mStatus(aStatus)
- , mWindowID(aWindowID)
-{
-}
-
-GetUserMediaNotificationEvent::GetUserMediaNotificationEvent(
- GetUserMediaStatus aStatus,
- already_AddRefed<DOMMediaStream> aStream,
- already_AddRefed<Refcountable<UniquePtr<OnTracksAvailableCallback>>>
- aOnTracksAvailableCallback,
- uint64_t aWindowID,
- already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
- : Runnable("GetUserMediaNotificationEvent")
- , mStream(aStream)
- , mOnTracksAvailableCallback(aOnTracksAvailableCallback)
- , mStatus(aStatus)
- , mWindowID(aWindowID)
- , mOnFailure(aError)
-{
-}
-GetUserMediaNotificationEvent::~GetUserMediaNotificationEvent()
-{
-}
-
-NS_IMETHODIMP
-GetUserMediaNotificationEvent::Run()
-{
- MOZ_ASSERT(NS_IsMainThread());
- // Make sure mStream is cleared and our reference to the DOMMediaStream
- // is dropped on the main thread, no matter what happens in this method.
- // Otherwise this object might be destroyed off the main thread,
- // releasing DOMMediaStream off the main thread, which is not allowed.
- RefPtr<DOMMediaStream> stream = mStream.forget();
-
- nsString msg;
- switch (mStatus) {
- case STARTING:
- msg = NS_LITERAL_STRING("starting");
- stream->OnTracksAvailable(mOnTracksAvailableCallback->release());
- break;
- case STOPPING:
- msg = NS_LITERAL_STRING("shutdown");
- break;
- }
-
- RefPtr<nsGlobalWindowInner> window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
- NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
- return MediaManager::NotifyRecordingStatusChange(window->AsInner(), msg);
+ NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::NotifyChrome",
+ [windowID = mWindowID]() {
+ nsGlobalWindowInner* window =
+ nsGlobalWindowInner::GetInnerWindowWithId(windowID);
+ if (!window) {
+ MOZ_ASSERT_UNREACHABLE("Should have window");
+ return;
+ }
+
+ DebugOnly<nsresult> rv = MediaManager::NotifyRecordingStatusChange(window->AsInner());
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Should be able to notify chrome");
+ }));
}
} // namespace mozilla
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -9,24 +9,22 @@
#include "mozilla/media/DeviceChangeCallback.h"
#include "mozilla/dom/GetUserMediaRequest.h"
#include "mozilla/Services.h"
#include "mozilla/Unused.h"
#include "nsAutoPtr.h"
#include "nsIMediaManager.h"
#include "nsHashKeys.h"
-#include "nsGlobalWindow.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsIObserver.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
-#include "nsPIDOMWindow.h"
#include "nsIDOMNavigatorUserMedia.h"
#include "nsXULAppAPI.h"
#include "mozilla/Attributes.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/dom/MediaStreamError.h"
@@ -124,44 +122,16 @@ class AudioDevice : public MediaDevice
public:
typedef MediaEngineAudioSource Source;
explicit AudioDevice(Source* aSource);
NS_IMETHOD GetType(nsAString& aType) override;
Source* GetSource() override;
};
-class GetUserMediaNotificationEvent: public Runnable
-{
- public:
- enum GetUserMediaStatus {
- STARTING,
- STOPPING,
- };
- GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
- uint64_t aWindowID);
-
- GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
- already_AddRefed<DOMMediaStream> aStream,
- already_AddRefed<media::Refcountable<UniquePtr<OnTracksAvailableCallback>>> aOnTracksAvailableCallback,
- uint64_t aWindowID,
- already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError);
- virtual ~GetUserMediaNotificationEvent();
-
- NS_IMETHOD Run() override;
-
- protected:
- RefPtr<GetUserMediaWindowListener> mListener; // threadsafe
- RefPtr<DOMMediaStream> mStream;
- RefPtr<media::Refcountable<UniquePtr<OnTracksAvailableCallback>>> mOnTracksAvailableCallback;
- GetUserMediaStatus mStatus;
- uint64_t mWindowID;
- RefPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
-};
-
typedef enum {
MEDIA_STOP,
MEDIA_STOP_TRACK,
MEDIA_DIRECT_LISTENERS,
} MediaOperation;
class ReleaseMediaOperationResource : public Runnable
{
@@ -208,18 +178,17 @@ public:
static bool IsInMediaThread();
#endif
static bool Exists()
{
return !!sSingleton;
}
- static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow,
- const nsString& aMsg);
+ static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow);
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIMEDIAMANAGERSERVICE
media::Parent<media::NonE10s>* GetNonE10sParent();
MediaEngine* GetBackend(uint64_t aWindowId = 0);