mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 967364: Replace crazy already_AddRefed handling with something reasonable. r=jesup
This commit is contained in:
parent
fe6c4e28d6
commit
3588b62871
@ -144,15 +144,21 @@ static nsresult ValidateTrackConstraints(
|
||||
}
|
||||
|
||||
ErrorCallbackRunnable::ErrorCallbackRunnable(
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
|
||||
const nsAString& aErrorMsg, uint64_t aWindowID)
|
||||
: mSuccess(aSuccess)
|
||||
, mError(aError)
|
||||
, mErrorMsg(aErrorMsg)
|
||||
: mErrorMsg(aErrorMsg)
|
||||
, mWindowID(aWindowID)
|
||||
, mManager(MediaManager::GetInstance()) {
|
||||
}
|
||||
, mManager(MediaManager::GetInstance())
|
||||
{
|
||||
mSuccess.swap(aSuccess);
|
||||
mError.swap(aError);
|
||||
}
|
||||
|
||||
ErrorCallbackRunnable::~ErrorCallbackRunnable()
|
||||
{
|
||||
MOZ_ASSERT(!mSuccess && !mError);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ErrorCallbackRunnable::Run()
|
||||
@ -160,8 +166,8 @@ ErrorCallbackRunnable::Run()
|
||||
// Only run if the window is still active.
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget();
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
|
||||
|
||||
if (!(mManager->IsWindowStillActive(mWindowID))) {
|
||||
return NS_OK;
|
||||
@ -182,14 +188,16 @@ class SuccessCallbackRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SuccessCallbackRunnable(
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
|
||||
nsIDOMFile* aFile, uint64_t aWindowID)
|
||||
: mSuccess(aSuccess)
|
||||
, mError(aError)
|
||||
, mFile(aFile)
|
||||
: mFile(aFile)
|
||||
, mWindowID(aWindowID)
|
||||
, mManager(MediaManager::GetInstance()) {}
|
||||
, mManager(MediaManager::GetInstance())
|
||||
{
|
||||
mSuccess.swap(aSuccess);
|
||||
mError.swap(aError);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
@ -197,8 +205,8 @@ public:
|
||||
// Only run if the window is still active.
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget();
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
|
||||
|
||||
if (!(mManager->IsWindowStillActive(mWindowID))) {
|
||||
return NS_OK;
|
||||
@ -210,8 +218,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsCOMPtr<nsIDOMFile> mFile;
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
||||
@ -470,19 +478,21 @@ class GetUserMediaStreamRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetUserMediaStreamRunnable(
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
|
||||
uint64_t aWindowID,
|
||||
GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
MediaEngineSource* aAudioSource,
|
||||
MediaEngineSource* aVideoSource)
|
||||
: mSuccess(aSuccess)
|
||||
, mError(aError)
|
||||
, mAudioSource(aAudioSource)
|
||||
: mAudioSource(aAudioSource)
|
||||
, mVideoSource(aVideoSource)
|
||||
, mWindowID(aWindowID)
|
||||
, mListener(aListener)
|
||||
, mManager(MediaManager::GetInstance()) {}
|
||||
, mManager(MediaManager::GetInstance())
|
||||
{
|
||||
mSuccess.swap(aSuccess);
|
||||
mError.swap(aError);
|
||||
}
|
||||
|
||||
~GetUserMediaStreamRunnable() {}
|
||||
|
||||
@ -512,7 +522,7 @@ public:
|
||||
mSuccess->OnSuccess(aStream);
|
||||
}
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsRefPtr<MediaManager> mManager;
|
||||
// Keep the DOMMediaStream alive until the NotifyTracksAvailable callback
|
||||
// has fired, otherwise we might immediately destroy the DOMMediaStream and
|
||||
@ -627,8 +637,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsRefPtr<MediaEngineSource> mAudioSource;
|
||||
nsRefPtr<MediaEngineSource> mVideoSource;
|
||||
uint64_t mWindowID;
|
||||
@ -765,16 +775,6 @@ static SourceSet *
|
||||
class GetUserMediaRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* GetUserMediaRunnable is meant for dispatch off main thread, where it would
|
||||
* be illegal to free JS callbacks. Therefore, it uses a rather risky strategy
|
||||
* of holding "already_AddRefed" references to the JS callbacks that must be
|
||||
* transfered and released in consequent dispatches arriving on main thread.
|
||||
*
|
||||
* A special Arm() method must be called before dispatch to enable this
|
||||
* behavior, because GetUserMediaRunnables are held in other circumstances.
|
||||
*/
|
||||
|
||||
GetUserMediaRunnable(
|
||||
const MediaStreamConstraintsInternal& aConstraints,
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
@ -782,10 +782,8 @@ public:
|
||||
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
|
||||
MediaEnginePrefs &aPrefs)
|
||||
: mConstraints(aConstraints)
|
||||
, mSuccess(nullptr)
|
||||
, mError(nullptr)
|
||||
, mSuccessHolder(aSuccess)
|
||||
, mErrorHolder(aError)
|
||||
, mSuccess(aSuccess)
|
||||
, mError(aError)
|
||||
, mWindowID(aWindowID)
|
||||
, mListener(aListener)
|
||||
, mPrefs(aPrefs)
|
||||
@ -806,10 +804,8 @@ public:
|
||||
MediaEnginePrefs &aPrefs,
|
||||
MediaEngine* aBackend)
|
||||
: mConstraints(aConstraints)
|
||||
, mSuccess(nullptr)
|
||||
, mError(nullptr)
|
||||
, mSuccessHolder(aSuccess)
|
||||
, mErrorHolder(aError)
|
||||
, mSuccess(aSuccess)
|
||||
, mError(aError)
|
||||
, mWindowID(aWindowID)
|
||||
, mListener(aListener)
|
||||
, mPrefs(aPrefs)
|
||||
@ -821,24 +817,23 @@ public:
|
||||
~GetUserMediaRunnable() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Once "armed", GetUserMediaRunnable will leak its JS callbacks if destroyed.
|
||||
* Arm() must be called before the runnable can be dispatched or used, and the
|
||||
* runnable must be dispatched or used once armed. Callbacks get released on
|
||||
* the main thread at the runnable's completion.
|
||||
*/
|
||||
void
|
||||
Arm() {
|
||||
mSuccess = mSuccessHolder.forget();
|
||||
mError = mErrorHolder.forget();
|
||||
Fail(const nsAString& aMessage) {
|
||||
nsRefPtr<ErrorCallbackRunnable> runnable =
|
||||
new ErrorCallbackRunnable(mSuccess, mError, aMessage, mWindowID);
|
||||
// These should be empty now
|
||||
MOZ_ASSERT(!mSuccess);
|
||||
MOZ_ASSERT(!mError);
|
||||
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
||||
MOZ_ASSERT(mSuccess.mRawPtr);
|
||||
MOZ_ASSERT(mError.mRawPtr);
|
||||
MOZ_ASSERT(mSuccess);
|
||||
MOZ_ASSERT(mError);
|
||||
|
||||
MediaEngine* backend = mBackend;
|
||||
// Was a backend provided?
|
||||
@ -856,9 +851,7 @@ public:
|
||||
|
||||
// It is an error if audio or video are requested along with picture.
|
||||
if (mConstraints.mPicture && (mConstraints.mAudio || mConstraints.mVideo)) {
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, NS_LITERAL_STRING("NOT_SUPPORTED_ERR"), mWindowID
|
||||
));
|
||||
Fail(NS_LITERAL_STRING("NOT_SUPPORTED_ERR"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -878,16 +871,16 @@ public:
|
||||
nsresult
|
||||
Denied(const nsAString& aErrorMsg)
|
||||
{
|
||||
MOZ_ASSERT(mSuccess.mRawPtr);
|
||||
MOZ_ASSERT(mError.mRawPtr);
|
||||
MOZ_ASSERT(mSuccess);
|
||||
MOZ_ASSERT(mError);
|
||||
|
||||
// We add a disabled listener to the StreamListeners array until accepted
|
||||
// If this was the only active MediaStream, remove the window from the list.
|
||||
if (NS_IsMainThread()) {
|
||||
// This is safe since we're on main-thread, and the window can only
|
||||
// be invalidated from the main-thread (see OnNavigation)
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget();
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
|
||||
error->OnError(aErrorMsg);
|
||||
|
||||
// Should happen *after* error runs for consistency, but may not matter
|
||||
@ -896,14 +889,15 @@ public:
|
||||
} else {
|
||||
// This will re-check the window being alive on main-thread
|
||||
// Note: we must remove the listener on MainThread as well
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, aErrorMsg, mWindowID
|
||||
));
|
||||
Fail(aErrorMsg);
|
||||
|
||||
// MUST happen after ErrorCallbackRunnable Run()s, as it checks the active window list
|
||||
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, mListener));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mSuccess);
|
||||
MOZ_ASSERT(!mError);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -933,15 +927,14 @@ public:
|
||||
nsresult
|
||||
SelectDevice(MediaEngine* backend)
|
||||
{
|
||||
MOZ_ASSERT(mSuccess.mRawPtr);
|
||||
MOZ_ASSERT(mError.mRawPtr);
|
||||
MOZ_ASSERT(mSuccess);
|
||||
MOZ_ASSERT(mError);
|
||||
if (mConstraints.mPicture || mConstraints.mVideo) {
|
||||
ScopedDeletePtr<SourceSet> sources (GetSources(backend,
|
||||
mConstraints.mVideom, &MediaEngine::EnumerateVideoDevices));
|
||||
|
||||
if (!sources->Length()) {
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID));
|
||||
Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Pick the first available device.
|
||||
@ -954,8 +947,7 @@ public:
|
||||
mConstraints.mAudiom, &MediaEngine::EnumerateAudioDevices));
|
||||
|
||||
if (!sources->Length()) {
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID));
|
||||
Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Pick the first available device.
|
||||
@ -973,16 +965,14 @@ public:
|
||||
void
|
||||
ProcessGetUserMedia(MediaEngineSource* aAudioSource, MediaEngineSource* aVideoSource)
|
||||
{
|
||||
MOZ_ASSERT(mSuccess.mRawPtr);
|
||||
MOZ_ASSERT(mError.mRawPtr);
|
||||
MOZ_ASSERT(mSuccess);
|
||||
MOZ_ASSERT(mError);
|
||||
nsresult rv;
|
||||
if (aAudioSource) {
|
||||
rv = aAudioSource->Allocate(mPrefs);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Failed to allocate audiosource %d",rv));
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
|
||||
));
|
||||
Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -993,9 +983,7 @@ public:
|
||||
if (aAudioSource) {
|
||||
aAudioSource->Deallocate();
|
||||
}
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
|
||||
));
|
||||
Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1003,6 +991,10 @@ public:
|
||||
NS_DispatchToMainThread(new GetUserMediaStreamRunnable(
|
||||
mSuccess, mError, mWindowID, mListener, aAudioSource, aVideoSource
|
||||
));
|
||||
|
||||
MOZ_ASSERT(!mSuccess);
|
||||
MOZ_ASSERT(!mError);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1013,13 +1005,11 @@ public:
|
||||
void
|
||||
ProcessGetUserMediaSnapshot(MediaEngineSource* aSource, int aDuration)
|
||||
{
|
||||
MOZ_ASSERT(mSuccess.mRawPtr);
|
||||
MOZ_ASSERT(mError.mRawPtr);
|
||||
MOZ_ASSERT(mSuccess);
|
||||
MOZ_ASSERT(mError);
|
||||
nsresult rv = aSource->Allocate(mPrefs);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(
|
||||
mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
|
||||
));
|
||||
Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1033,16 +1023,18 @@ public:
|
||||
NS_DispatchToMainThread(new SuccessCallbackRunnable(
|
||||
mSuccess, mError, file, mWindowID
|
||||
));
|
||||
|
||||
MOZ_ASSERT(!mSuccess);
|
||||
MOZ_ASSERT(!mError);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
MediaStreamConstraintsInternal mConstraints;
|
||||
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccessHolder;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mErrorHolder;
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
|
||||
nsRefPtr<MediaDevice> mAudioDevice;
|
||||
@ -1420,7 +1412,6 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
|
||||
#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
|
||||
if (c.mPicture) {
|
||||
// ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
|
||||
runnable->Arm();
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1428,7 +1419,6 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
|
||||
// XXX No full support for picture in Desktop yet (needs proper UI)
|
||||
if (aPrivileged ||
|
||||
(c.mFake && !Preferences::GetBool("media.navigator.permission.fake"))) {
|
||||
runnable->Arm();
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
// Check if this site has persistent permissions.
|
||||
@ -1468,7 +1458,6 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
|
||||
runnable->SetContraints(c);
|
||||
}
|
||||
|
||||
runnable->Arm();
|
||||
if (!c.mAudio && !c.mVideo) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
@ -1736,7 +1725,6 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
mActiveCallbacks.Remove(key);
|
||||
runnable->Arm();
|
||||
|
||||
if (aSubject) {
|
||||
// A particular device or devices were chosen by the user.
|
||||
@ -1791,7 +1779,6 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
mActiveCallbacks.Remove(key);
|
||||
runnable->Arm();
|
||||
runnable->Denied(errorMessage);
|
||||
return NS_OK;
|
||||
|
||||
|
@ -257,13 +257,15 @@ class ErrorCallbackRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ErrorCallbackRunnable(
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
|
||||
const nsAString& aErrorMsg, uint64_t aWindowID);
|
||||
NS_IMETHOD Run();
|
||||
private:
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
~ErrorCallbackRunnable();
|
||||
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
const nsString mErrorMsg;
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
||||
@ -322,7 +324,8 @@ public:
|
||||
nsString log;
|
||||
|
||||
log.AssignASCII(errorLog, strlen(errorLog));
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(nullptr, mError.forget(),
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success;
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(success, mError,
|
||||
log, mWindowID));
|
||||
return NS_OK;
|
||||
}
|
||||
@ -424,7 +427,7 @@ private:
|
||||
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
|
||||
bool mFinish;
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
};
|
||||
|
||||
typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
|
||||
|
Loading…
Reference in New Issue
Block a user