2012-06-03 00:35:15 -07:00
|
|
|
/* 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/. */
|
|
|
|
|
2014-09-30 16:17:53 -07:00
|
|
|
#ifndef MOZILLA_MEDIAMANAGER_H
|
|
|
|
#define MOZILLA_MEDIAMANAGER_H
|
|
|
|
|
2012-06-03 00:35:15 -07:00
|
|
|
#include "MediaEngine.h"
|
|
|
|
#include "mozilla/Services.h"
|
2013-01-24 18:45:36 -08:00
|
|
|
#include "mozilla/unused.h"
|
2012-12-22 00:09:36 -08:00
|
|
|
#include "nsIMediaManager.h"
|
2012-06-03 00:35:15 -07:00
|
|
|
|
|
|
|
#include "nsHashKeys.h"
|
2012-07-12 04:53:48 -07:00
|
|
|
#include "nsGlobalWindow.h"
|
2012-06-03 00:35:15 -07:00
|
|
|
#include "nsClassHashtable.h"
|
2012-10-05 17:20:47 -07:00
|
|
|
#include "nsRefPtrHashtable.h"
|
2014-04-14 12:04:27 -07:00
|
|
|
#include "nsIObserver.h"
|
2013-03-04 13:02:17 -08:00
|
|
|
#include "nsIPrefService.h"
|
|
|
|
#include "nsIPrefBranch.h"
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2012-06-10 16:44:50 -07:00
|
|
|
#include "nsPIDOMWindow.h"
|
2012-06-03 00:35:15 -07:00
|
|
|
#include "nsIDOMNavigatorUserMedia.h"
|
2013-01-24 18:45:36 -08:00
|
|
|
#include "nsXULAppAPI.h"
|
2012-06-14 19:31:55 -07:00
|
|
|
#include "mozilla/Attributes.h"
|
2014-02-25 03:50:42 -08:00
|
|
|
#include "mozilla/Preferences.h"
|
2012-12-22 00:09:36 -08:00
|
|
|
#include "mozilla/StaticPtr.h"
|
2014-04-04 02:54:25 -07:00
|
|
|
#include "mozilla/dom/MediaStreamBinding.h"
|
2013-09-15 23:34:57 -07:00
|
|
|
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
2014-10-27 12:42:56 -07:00
|
|
|
#include "mozilla/dom/MediaStreamError.h"
|
2012-10-15 13:41:46 -07:00
|
|
|
#include "prlog.h"
|
2013-05-02 22:07:37 -07:00
|
|
|
#include "DOMMediaStream.h"
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2013-01-29 08:55:09 -08:00
|
|
|
#ifdef MOZ_WEBRTC
|
|
|
|
#include "mtransport/runnable_utils.h"
|
|
|
|
#endif
|
|
|
|
|
2014-09-12 07:49:39 -07:00
|
|
|
// Note, these suck in Windows headers, unfortunately.
|
|
|
|
#include "base/thread.h"
|
|
|
|
#include "base/task.h"
|
|
|
|
|
2013-05-02 05:00:12 -07:00
|
|
|
#ifdef MOZ_WIDGET_GONK
|
|
|
|
#include "DOMCameraManager.h"
|
|
|
|
#endif
|
|
|
|
|
2012-06-03 00:35:15 -07:00
|
|
|
namespace mozilla {
|
2013-09-15 23:34:57 -07:00
|
|
|
namespace dom {
|
2014-06-18 17:57:51 -07:00
|
|
|
struct MediaStreamConstraints;
|
2013-09-15 23:34:57 -07:00
|
|
|
class NavigatorUserMediaSuccessCallback;
|
|
|
|
class NavigatorUserMediaErrorCallback;
|
2014-09-24 08:17:33 -07:00
|
|
|
struct MediaTrackConstraintSet;
|
2013-09-15 23:34:57 -07:00
|
|
|
}
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2012-10-15 13:41:46 -07:00
|
|
|
#ifdef PR_LOGGING
|
2012-10-29 16:32:10 -07:00
|
|
|
extern PRLogModuleInfo* GetMediaManagerLog();
|
|
|
|
#define MM_LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
|
2012-10-15 13:41:46 -07:00
|
|
|
#else
|
|
|
|
#define MM_LOG(msg)
|
|
|
|
#endif
|
|
|
|
|
2012-12-31 15:12:15 -08:00
|
|
|
/**
|
|
|
|
* 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:
|
2013-01-06 18:31:32 -08:00
|
|
|
// Create in an inactive state
|
2014-09-12 07:49:39 -07:00
|
|
|
GetUserMediaCallbackMediaStreamListener(base::Thread *aThread,
|
2013-01-06 18:31:32 -08:00
|
|
|
uint64_t aWindowID)
|
2012-12-31 15:12:15 -08:00
|
|
|
: mMediaThread(aThread)
|
2013-01-07 18:44:43 -08:00
|
|
|
, mWindowID(aWindowID)
|
2013-03-02 18:49:29 -08:00
|
|
|
, mStopped(false)
|
2013-03-02 19:04:40 -08:00
|
|
|
, mFinished(false)
|
2013-01-07 18:44:43 -08:00
|
|
|
, mLock("mozilla::GUMCMSL")
|
|
|
|
, mRemoved(false) {}
|
2012-12-31 15:12:15 -08:00
|
|
|
|
|
|
|
~GetUserMediaCallbackMediaStreamListener()
|
|
|
|
{
|
2013-01-07 18:44:43 -08:00
|
|
|
// It's OK to release mStream on any thread; they have thread-safe
|
2013-01-04 09:16:32 -08:00
|
|
|
// refcounts.
|
2012-12-31 15:12:15 -08:00
|
|
|
}
|
|
|
|
|
2013-01-06 18:31:32 -08:00
|
|
|
void Activate(already_AddRefed<SourceMediaStream> aStream,
|
|
|
|
MediaEngineSource* aAudioSource,
|
|
|
|
MediaEngineSource* aVideoSource)
|
|
|
|
{
|
2013-01-07 18:44:43 -08:00
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
2013-03-02 18:49:29 -08:00
|
|
|
mStream = aStream;
|
2013-01-06 18:31:32 -08:00
|
|
|
mAudioSource = aAudioSource;
|
|
|
|
mVideoSource = aVideoSource;
|
|
|
|
mLastEndTimeAudio = 0;
|
|
|
|
mLastEndTimeVideo = 0;
|
|
|
|
|
|
|
|
mStream->AddListener(this);
|
|
|
|
}
|
|
|
|
|
2013-03-02 18:49:29 -08:00
|
|
|
MediaStream *Stream() // Can be used to test if Activate was called
|
2013-01-04 09:16:32 -08:00
|
|
|
{
|
|
|
|
return mStream;
|
|
|
|
}
|
2012-12-31 15:12:15 -08:00
|
|
|
SourceMediaStream *GetSourceStream()
|
|
|
|
{
|
2013-01-08 19:10:09 -08:00
|
|
|
NS_ASSERTION(mStream,"Getting stream from never-activated GUMCMSListener");
|
|
|
|
if (!mStream) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-01-04 09:16:32 -08:00
|
|
|
return mStream->AsSourceStream();
|
2012-12-31 15:12:15 -08:00
|
|
|
}
|
|
|
|
|
2014-08-22 02:27:16 -07:00
|
|
|
void StopScreenWindowSharing();
|
|
|
|
|
2014-08-26 22:03:50 -07:00
|
|
|
void StopTrack(TrackID aID, bool aIsAudio);
|
|
|
|
|
2013-07-04 22:53:10 -07:00
|
|
|
// mVideo/AudioSource are set by Activate(), so we assume they're capturing
|
|
|
|
// if set and represent a real capture device.
|
2013-02-27 12:36:06 -08:00
|
|
|
bool CapturingVideo()
|
|
|
|
{
|
2013-03-02 18:49:29 -08:00
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
2014-02-25 03:50:42 -08:00
|
|
|
return mVideoSource && !mStopped &&
|
2014-07-17 19:23:00 -07:00
|
|
|
mVideoSource->GetMediaSource() == MediaSourceType::Camera &&
|
2014-02-25 03:50:42 -08:00
|
|
|
(!mVideoSource->IsFake() ||
|
|
|
|
Preferences::GetBool("media.navigator.permission.fake"));
|
2013-02-27 12:36:06 -08:00
|
|
|
}
|
|
|
|
bool CapturingAudio()
|
|
|
|
{
|
2013-03-02 18:49:29 -08:00
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
2014-02-25 03:50:42 -08:00
|
|
|
return mAudioSource && !mStopped &&
|
|
|
|
(!mAudioSource->IsFake() ||
|
|
|
|
Preferences::GetBool("media.navigator.permission.fake"));
|
2013-03-02 18:49:29 -08:00
|
|
|
}
|
2014-07-17 19:23:00 -07:00
|
|
|
bool CapturingScreen()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
2014-08-22 02:27:16 -07:00
|
|
|
return mVideoSource && !mStopped && !mVideoSource->IsAvailable() &&
|
2014-07-17 19:23:00 -07:00
|
|
|
mVideoSource->GetMediaSource() == MediaSourceType::Screen;
|
|
|
|
}
|
|
|
|
bool CapturingWindow()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
2014-08-22 02:27:16 -07:00
|
|
|
return mVideoSource && !mStopped && !mVideoSource->IsAvailable() &&
|
2014-07-17 19:23:00 -07:00
|
|
|
mVideoSource->GetMediaSource() == MediaSourceType::Window;
|
|
|
|
}
|
2014-08-20 15:05:23 -07:00
|
|
|
bool CapturingApplication()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
|
|
|
return mVideoSource && !mStopped && !mVideoSource->IsAvailable() &&
|
|
|
|
mVideoSource->GetMediaSource() == MediaSourceType::Application;
|
|
|
|
}
|
2013-03-02 18:49:29 -08:00
|
|
|
|
|
|
|
void SetStopped()
|
|
|
|
{
|
|
|
|
mStopped = true;
|
2013-02-27 12:36:06 -08:00
|
|
|
}
|
|
|
|
|
2014-09-12 07:49:39 -07:00
|
|
|
// implement in .cpp to avoid circular dependency with MediaOperationTask
|
2013-01-07 18:44:43 -08:00
|
|
|
// Can be invoked from EITHER MainThread or MSG thread
|
|
|
|
void Invalidate();
|
2012-12-31 15:12:15 -08:00
|
|
|
|
2013-01-29 08:55:09 -08:00
|
|
|
void
|
|
|
|
AudioConfig(bool aEchoOn, uint32_t aEcho,
|
|
|
|
bool aAgcOn, uint32_t aAGC,
|
2014-04-02 10:58:19 -07:00
|
|
|
bool aNoiseOn, uint32_t aNoise,
|
2014-09-12 07:49:39 -07:00
|
|
|
int32_t aPlayoutDelay);
|
2013-01-29 08:55:09 -08:00
|
|
|
|
2012-12-31 15:12:15 -08:00
|
|
|
void
|
|
|
|
Remove()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
2013-01-07 18:44:43 -08:00
|
|
|
// allow calling even if inactive (!mStream) for easier cleanup
|
2012-12-31 15:12:15 -08:00
|
|
|
// Caller holds strong reference to us, so no death grip required
|
2013-01-07 18:44:43 -08:00
|
|
|
MutexAutoLock lock(mLock); // protect access to mRemoved
|
|
|
|
if (mStream && !mRemoved) {
|
|
|
|
MM_LOG(("Listener removed on purpose, mFinished = %d", (int) mFinished));
|
|
|
|
mRemoved = true; // RemoveListener is async, avoid races
|
2013-01-16 23:38:21 -08:00
|
|
|
// If it's destroyed, don't call - listener will be removed and we'll be notified!
|
|
|
|
if (!mStream->IsDestroyed()) {
|
|
|
|
mStream->RemoveListener(this);
|
|
|
|
}
|
2013-01-07 18:44:43 -08:00
|
|
|
}
|
2012-12-31 15:12:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Proxy NotifyPull() to sources
|
2013-01-07 18:44:43 -08:00
|
|
|
virtual void
|
|
|
|
NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) MOZ_OVERRIDE
|
2012-12-31 15:12:15 -08:00
|
|
|
{
|
|
|
|
// Currently audio sources ignore NotifyPull, but they could
|
|
|
|
// watch it especially for fake audio.
|
|
|
|
if (mAudioSource) {
|
2013-01-04 09:16:32 -08:00
|
|
|
mAudioSource->NotifyPull(aGraph, mStream, kAudioTrack, aDesiredTime, mLastEndTimeAudio);
|
2012-12-31 15:12:15 -08:00
|
|
|
}
|
|
|
|
if (mVideoSource) {
|
2013-01-04 09:16:32 -08:00
|
|
|
mVideoSource->NotifyPull(aGraph, mStream, kVideoTrack, aDesiredTime, mLastEndTimeVideo);
|
2012-12-31 15:12:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-07 18:44:43 -08:00
|
|
|
virtual void
|
2014-07-13 22:47:56 -07:00
|
|
|
NotifyEvent(MediaStreamGraph* aGraph,
|
2014-07-13 22:48:02 -07:00
|
|
|
MediaStreamListener::MediaStreamGraphEvent aEvent) MOZ_OVERRIDE
|
2014-07-13 22:47:56 -07:00
|
|
|
{
|
2014-07-13 22:48:02 -07:00
|
|
|
switch (aEvent) {
|
2014-07-13 22:47:56 -07:00
|
|
|
case EVENT_FINISHED:
|
|
|
|
NotifyFinished(aGraph);
|
|
|
|
break;
|
|
|
|
case EVENT_REMOVED:
|
|
|
|
NotifyRemoved(aGraph);
|
|
|
|
break;
|
|
|
|
case EVENT_HAS_DIRECT_LISTENERS:
|
2014-07-13 22:48:02 -07:00
|
|
|
NotifyDirectListeners(aGraph, true);
|
|
|
|
break;
|
2014-07-13 22:47:56 -07:00
|
|
|
case EVENT_HAS_NO_DIRECT_LISTENERS:
|
2014-07-13 22:48:02 -07:00
|
|
|
NotifyDirectListeners(aGraph, false);
|
|
|
|
break;
|
|
|
|
default:
|
2014-07-13 22:47:56 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void
|
|
|
|
NotifyFinished(MediaStreamGraph* aGraph);
|
2013-01-07 18:44:43 -08:00
|
|
|
|
|
|
|
virtual void
|
2014-07-13 22:47:56 -07:00
|
|
|
NotifyRemoved(MediaStreamGraph* aGraph);
|
2012-12-31 15:12:15 -08:00
|
|
|
|
2014-07-13 22:48:02 -07:00
|
|
|
virtual void
|
|
|
|
NotifyDirectListeners(MediaStreamGraph* aGraph, bool aHasListeners);
|
|
|
|
|
2012-12-31 15:12:15 -08:00
|
|
|
private:
|
2013-01-07 18:44:43 -08:00
|
|
|
// Set at construction
|
2014-09-12 07:49:39 -07:00
|
|
|
base::Thread* mMediaThread;
|
2013-01-06 18:31:32 -08:00
|
|
|
uint64_t mWindowID;
|
2013-01-07 18:44:43 -08:00
|
|
|
|
2013-03-02 18:49:29 -08:00
|
|
|
bool mStopped; // MainThread only
|
|
|
|
|
2013-01-07 18:44:43 -08:00
|
|
|
// Set at Activate on MainThread
|
|
|
|
|
|
|
|
// Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread
|
|
|
|
// No locking needed as they're only addrefed except on the MediaManager thread
|
|
|
|
nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe refcnt
|
|
|
|
nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe refcnt
|
|
|
|
nsRefPtr<SourceMediaStream> mStream; // threadsafe refcnt
|
2014-09-17 22:20:43 -07:00
|
|
|
StreamTime mLastEndTimeAudio;
|
|
|
|
StreamTime mLastEndTimeVideo;
|
2013-01-07 18:44:43 -08:00
|
|
|
bool mFinished;
|
|
|
|
|
|
|
|
// Accessed from MainThread and MSG thread
|
|
|
|
Mutex mLock; // protects mRemoved access from MainThread
|
|
|
|
bool mRemoved;
|
2012-12-31 15:12:15 -08:00
|
|
|
};
|
|
|
|
|
2013-03-02 18:49:29 -08:00
|
|
|
class GetUserMediaNotificationEvent: public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum GetUserMediaStatus {
|
|
|
|
STARTING,
|
2014-08-22 02:27:16 -07:00
|
|
|
STOPPING,
|
|
|
|
STOPPED_TRACK
|
2013-03-02 18:49:29 -08:00
|
|
|
};
|
|
|
|
GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener,
|
2013-10-23 04:10:42 -07:00
|
|
|
GetUserMediaStatus aStatus,
|
|
|
|
bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
|
|
|
|
: mListener(aListener) , mStatus(aStatus) , mIsAudio(aIsAudio)
|
|
|
|
, mIsVideo(aIsVideo), mWindowID(aWindowID) {}
|
2013-03-02 18:49:29 -08:00
|
|
|
|
2013-05-02 22:07:37 -07:00
|
|
|
GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
|
|
|
|
already_AddRefed<DOMMediaStream> aStream,
|
2013-10-23 04:10:42 -07:00
|
|
|
DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
|
2013-12-05 06:29:07 -08:00
|
|
|
bool aIsAudio, bool aIsVideo, uint64_t aWindowID,
|
2013-12-05 13:30:50 -08:00
|
|
|
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
|
2013-05-02 22:07:37 -07:00
|
|
|
: mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
|
2013-12-05 06:29:07 -08:00
|
|
|
mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID),
|
2014-10-17 17:47:46 -07:00
|
|
|
mOnFailure(aError) {}
|
2013-05-02 22:07:37 -07:00
|
|
|
virtual ~GetUserMediaNotificationEvent()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2013-03-02 18:49:29 -08:00
|
|
|
|
2013-08-27 21:14:57 -07:00
|
|
|
NS_IMETHOD Run() MOZ_OVERRIDE;
|
2013-03-02 18:49:29 -08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
|
2013-05-02 22:07:37 -07:00
|
|
|
nsRefPtr<DOMMediaStream> mStream;
|
|
|
|
nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
|
2013-03-02 18:49:29 -08:00
|
|
|
GetUserMediaStatus mStatus;
|
2013-10-23 04:10:42 -07:00
|
|
|
bool mIsAudio;
|
|
|
|
bool mIsVideo;
|
|
|
|
uint64_t mWindowID;
|
2014-10-17 17:47:46 -07:00
|
|
|
nsRefPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
2013-03-02 18:49:29 -08:00
|
|
|
};
|
|
|
|
|
2012-10-24 16:21:15 -07:00
|
|
|
typedef enum {
|
|
|
|
MEDIA_START,
|
2014-07-13 22:48:02 -07:00
|
|
|
MEDIA_STOP,
|
2014-08-22 02:27:16 -07:00
|
|
|
MEDIA_STOP_TRACK,
|
2014-07-13 22:48:02 -07:00
|
|
|
MEDIA_DIRECT_LISTENERS
|
2012-10-24 16:21:15 -07:00
|
|
|
} MediaOperation;
|
|
|
|
|
2013-12-05 06:29:07 -08:00
|
|
|
class MediaManager;
|
2014-09-12 07:49:39 -07:00
|
|
|
class GetUserMediaTask;
|
2013-12-05 06:29:07 -08:00
|
|
|
|
|
|
|
/**
|
2014-10-27 12:42:56 -07:00
|
|
|
* Send an error back to content.
|
2014-10-17 17:47:46 -07:00
|
|
|
* Do this only on the main thread. The onSuccess callback is also passed here
|
2013-12-05 06:29:07 -08:00
|
|
|
* so it can be released correctly.
|
|
|
|
*/
|
|
|
|
class ErrorCallbackRunnable : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ErrorCallbackRunnable(
|
2014-10-27 12:42:56 -07:00
|
|
|
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess,
|
|
|
|
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
|
|
|
|
MediaMgrError& aError, uint64_t aWindowID);
|
2013-12-05 06:29:07 -08:00
|
|
|
NS_IMETHOD Run();
|
|
|
|
private:
|
2014-03-15 12:00:15 -07:00
|
|
|
~ErrorCallbackRunnable();
|
|
|
|
|
2014-10-17 17:47:46 -07:00
|
|
|
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
|
|
|
|
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
2014-10-27 12:42:56 -07:00
|
|
|
nsRefPtr<MediaMgrError> mError;
|
2013-12-05 06:29:07 -08:00
|
|
|
uint64_t mWindowID;
|
|
|
|
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
|
|
|
};
|
|
|
|
|
|
|
|
class ReleaseMediaOperationResource : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ReleaseMediaOperationResource(already_AddRefed<DOMMediaStream> aStream,
|
|
|
|
DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback):
|
|
|
|
mStream(aStream),
|
|
|
|
mOnTracksAvailableCallback(aOnTracksAvailableCallback) {}
|
|
|
|
NS_IMETHOD Run() MOZ_OVERRIDE {return NS_OK;}
|
|
|
|
private:
|
|
|
|
nsRefPtr<DOMMediaStream> mStream;
|
|
|
|
nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
|
|
|
|
};
|
|
|
|
|
2012-12-28 12:27:57 -08:00
|
|
|
// Generic class for running long media operations like Start off the main
|
|
|
|
// thread, and then (because nsDOMMediaStreams aren't threadsafe),
|
|
|
|
// ProxyReleases mStream since it's cycle collected.
|
2014-09-12 07:49:39 -07:00
|
|
|
class MediaOperationTask : public Task
|
2012-10-24 16:21:15 -07:00
|
|
|
{
|
|
|
|
public:
|
2012-12-18 23:07:37 -08:00
|
|
|
// so we can send Stop without AddRef()ing from the MSG thread
|
2014-09-12 07:49:39 -07:00
|
|
|
MediaOperationTask(MediaOperation aType,
|
2012-12-31 15:12:15 -08:00
|
|
|
GetUserMediaCallbackMediaStreamListener* aListener,
|
2013-05-02 22:07:37 -07:00
|
|
|
DOMMediaStream* aStream,
|
|
|
|
DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
|
2012-10-24 16:21:15 -07:00
|
|
|
MediaEngineSource* aAudioSource,
|
2013-01-06 18:31:32 -08:00
|
|
|
MediaEngineSource* aVideoSource,
|
2014-07-13 22:48:02 -07:00
|
|
|
bool aBool,
|
2013-12-05 06:29:07 -08:00
|
|
|
uint64_t aWindowID,
|
2013-12-05 13:30:50 -08:00
|
|
|
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
|
2012-10-24 16:21:15 -07:00
|
|
|
: mType(aType)
|
2013-05-02 22:07:37 -07:00
|
|
|
, mStream(aStream)
|
|
|
|
, mOnTracksAvailableCallback(aOnTracksAvailableCallback)
|
2012-10-24 16:21:15 -07:00
|
|
|
, mAudioSource(aAudioSource)
|
|
|
|
, mVideoSource(aVideoSource)
|
2012-12-31 15:12:15 -08:00
|
|
|
, mListener(aListener)
|
2014-07-13 22:48:02 -07:00
|
|
|
, mBool(aBool)
|
2013-10-23 04:10:42 -07:00
|
|
|
, mWindowID(aWindowID)
|
2014-10-17 17:47:46 -07:00
|
|
|
, mOnFailure(aError)
|
2013-12-05 06:29:07 -08:00
|
|
|
{}
|
2012-10-24 16:21:15 -07:00
|
|
|
|
2014-09-12 07:49:39 -07:00
|
|
|
~MediaOperationTask()
|
2012-12-03 22:17:38 -08:00
|
|
|
{
|
2013-01-04 09:16:32 -08:00
|
|
|
// MediaStreams can be released on any thread.
|
2012-12-03 22:17:38 -08:00
|
|
|
}
|
|
|
|
|
2014-09-12 07:49:39 -07:00
|
|
|
void
|
|
|
|
ReturnCallbackError(nsresult rv, const char* errorLog)
|
2013-12-05 06:29:07 -08:00
|
|
|
{
|
|
|
|
MM_LOG(("%s , rv=%d", errorLog, rv));
|
|
|
|
NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
|
|
|
|
mOnTracksAvailableCallback.forget()));
|
|
|
|
nsString log;
|
|
|
|
|
2014-10-27 12:42:56 -07:00
|
|
|
log.AssignASCII(errorLog);
|
2014-10-17 17:47:46 -07:00
|
|
|
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess;
|
2014-10-27 12:42:56 -07:00
|
|
|
nsRefPtr<MediaMgrError> error = new MediaMgrError(
|
|
|
|
NS_LITERAL_STRING("InternalError"), log);
|
2014-10-17 17:47:46 -07:00
|
|
|
NS_DispatchToMainThread(new ErrorCallbackRunnable(onSuccess, mOnFailure,
|
2014-10-27 12:42:56 -07:00
|
|
|
*error, mWindowID));
|
2013-12-05 06:29:07 -08:00
|
|
|
}
|
|
|
|
|
2014-09-12 07:49:39 -07:00
|
|
|
void
|
|
|
|
Run()
|
2012-10-24 16:21:15 -07:00
|
|
|
{
|
2013-01-04 09:16:32 -08:00
|
|
|
SourceMediaStream *source = mListener->GetSourceStream();
|
2012-12-03 22:17:38 -08:00
|
|
|
// No locking between these is required as all the callbacks for the
|
|
|
|
// same MediaStream will occur on the same thread.
|
2013-01-08 19:10:09 -08:00
|
|
|
if (!source) // means the stream was never Activated()
|
2014-09-12 07:49:39 -07:00
|
|
|
return;
|
2012-12-31 15:12:15 -08:00
|
|
|
|
2012-10-24 16:21:15 -07:00
|
|
|
switch (mType) {
|
|
|
|
case MEDIA_START:
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
|
|
|
|
nsresult rv;
|
|
|
|
|
2012-12-31 15:12:15 -08:00
|
|
|
source->SetPullEnabled(true);
|
2012-10-24 16:21:15 -07:00
|
|
|
|
2013-05-02 22:07:37 -07:00
|
|
|
DOMMediaStream::TrackTypeHints expectedTracks = 0;
|
2012-10-24 16:21:15 -07:00
|
|
|
if (mAudioSource) {
|
2012-12-31 15:12:15 -08:00
|
|
|
rv = mAudioSource->Start(source, kAudioTrack);
|
2013-05-02 22:07:37 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
expectedTracks |= DOMMediaStream::HINT_CONTENTS_AUDIO;
|
|
|
|
} else {
|
2014-09-12 07:49:39 -07:00
|
|
|
ReturnCallbackError(rv, "Starting audio failed");
|
|
|
|
return;
|
2012-10-24 16:21:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mVideoSource) {
|
2012-12-31 15:12:15 -08:00
|
|
|
rv = mVideoSource->Start(source, kVideoTrack);
|
2013-05-02 22:07:37 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
expectedTracks |= DOMMediaStream::HINT_CONTENTS_VIDEO;
|
|
|
|
} else {
|
2014-09-12 07:49:39 -07:00
|
|
|
ReturnCallbackError(rv, "Starting video failed");
|
|
|
|
return;
|
2012-10-24 16:21:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 22:07:37 -07:00
|
|
|
mOnTracksAvailableCallback->SetExpectedTracks(expectedTracks);
|
|
|
|
|
2012-10-24 16:21:15 -07:00
|
|
|
MM_LOG(("started all sources"));
|
2013-05-02 22:07:37 -07:00
|
|
|
// Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent,
|
|
|
|
// because mOnTracksAvailableCallback needs to be added to mStream
|
|
|
|
// on the main thread.
|
2013-12-05 13:30:51 -08:00
|
|
|
nsIRunnable *event =
|
2013-05-02 22:07:37 -07:00
|
|
|
new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING,
|
|
|
|
mStream.forget(),
|
2013-10-23 04:10:42 -07:00
|
|
|
mOnTracksAvailableCallback.forget(),
|
|
|
|
mAudioSource != nullptr,
|
|
|
|
mVideoSource != nullptr,
|
2014-10-17 17:47:46 -07:00
|
|
|
mWindowID, mOnFailure.forget());
|
2013-12-05 13:30:51 -08:00
|
|
|
// event must always be released on mainthread due to the JS callbacks
|
|
|
|
// in the TracksAvailableCallback
|
2014-05-23 12:53:17 -07:00
|
|
|
NS_DispatchToMainThread(event);
|
2012-10-24 16:21:15 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIA_STOP:
|
2014-08-22 02:27:16 -07:00
|
|
|
case MEDIA_STOP_TRACK:
|
2012-10-24 16:21:15 -07:00
|
|
|
{
|
|
|
|
NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
|
|
|
|
if (mAudioSource) {
|
2012-12-31 15:12:15 -08:00
|
|
|
mAudioSource->Stop(source, kAudioTrack);
|
2012-10-24 16:21:15 -07:00
|
|
|
mAudioSource->Deallocate();
|
|
|
|
}
|
|
|
|
if (mVideoSource) {
|
2012-12-31 15:12:15 -08:00
|
|
|
mVideoSource->Stop(source, kVideoTrack);
|
2012-10-24 16:21:15 -07:00
|
|
|
mVideoSource->Deallocate();
|
|
|
|
}
|
|
|
|
// Do this after stopping all tracks with EndTrack()
|
2014-07-13 22:48:02 -07:00
|
|
|
if (mBool) {
|
2013-01-06 18:31:32 -08:00
|
|
|
source->Finish();
|
|
|
|
}
|
2014-08-22 02:27:16 -07:00
|
|
|
|
2013-12-05 13:30:51 -08:00
|
|
|
nsIRunnable *event =
|
2013-10-23 04:10:42 -07:00
|
|
|
new GetUserMediaNotificationEvent(mListener,
|
2014-08-22 02:27:16 -07:00
|
|
|
mType == MEDIA_STOP ?
|
|
|
|
GetUserMediaNotificationEvent::STOPPING :
|
|
|
|
GetUserMediaNotificationEvent::STOPPED_TRACK,
|
2013-10-23 04:10:42 -07:00
|
|
|
mAudioSource != nullptr,
|
|
|
|
mVideoSource != nullptr,
|
|
|
|
mWindowID);
|
2013-12-05 13:30:51 -08:00
|
|
|
// event must always be released on mainthread due to the JS callbacks
|
|
|
|
// in the TracksAvailableCallback
|
2014-05-23 12:53:17 -07:00
|
|
|
NS_DispatchToMainThread(event);
|
2012-10-24 16:21:15 -07:00
|
|
|
}
|
|
|
|
break;
|
2012-12-28 12:27:57 -08:00
|
|
|
|
2014-07-13 22:48:02 -07:00
|
|
|
case MEDIA_DIRECT_LISTENERS:
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
|
|
|
|
if (mVideoSource) {
|
|
|
|
mVideoSource->SetDirectListeners(mBool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2012-12-28 12:27:57 -08:00
|
|
|
default:
|
|
|
|
MOZ_ASSERT(false,"invalid MediaManager operation");
|
|
|
|
break;
|
2012-10-24 16:21:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
MediaOperation mType;
|
2013-05-02 22:07:37 -07:00
|
|
|
nsRefPtr<DOMMediaStream> mStream;
|
|
|
|
nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
|
2012-12-03 22:17:38 -08:00
|
|
|
nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
|
|
|
|
nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
|
2012-12-31 15:12:15 -08:00
|
|
|
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
|
2014-07-13 22:48:02 -07:00
|
|
|
bool mBool;
|
2013-10-23 04:10:42 -07:00
|
|
|
uint64_t mWindowID;
|
2014-10-17 17:47:46 -07:00
|
|
|
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
2012-06-03 00:35:15 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
|
|
|
|
typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
|
|
|
|
|
2012-09-20 12:54:00 -07:00
|
|
|
class MediaDevice : public nsIMediaDevice
|
|
|
|
{
|
|
|
|
public:
|
2013-07-18 19:21:20 -07:00
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
2012-09-20 12:54:00 -07:00
|
|
|
NS_DECL_NSIMEDIADEVICE
|
|
|
|
|
2014-04-18 12:15:10 -07:00
|
|
|
protected:
|
2014-06-23 12:56:07 -07:00
|
|
|
virtual ~MediaDevice() {}
|
2014-08-31 20:50:23 -07:00
|
|
|
explicit MediaDevice(MediaEngineSource* aSource);
|
2012-09-20 12:54:00 -07:00
|
|
|
nsString mName;
|
2012-12-17 05:28:24 -08:00
|
|
|
nsString mID;
|
2013-09-15 23:34:57 -07:00
|
|
|
bool mHasFacingMode;
|
|
|
|
dom::VideoFacingModeEnum mFacingMode;
|
2014-07-17 19:23:00 -07:00
|
|
|
MediaSourceType mMediaSource;
|
2012-09-20 12:54:00 -07:00
|
|
|
nsRefPtr<MediaEngineSource> mSource;
|
|
|
|
};
|
|
|
|
|
2014-04-18 12:15:10 -07:00
|
|
|
class VideoDevice : public MediaDevice
|
|
|
|
{
|
|
|
|
public:
|
2014-09-24 08:17:33 -07:00
|
|
|
typedef MediaEngineVideoSource Source;
|
|
|
|
|
|
|
|
explicit VideoDevice(Source* aSource);
|
2014-04-18 12:15:10 -07:00
|
|
|
NS_IMETHOD GetType(nsAString& aType);
|
2014-09-24 08:17:33 -07:00
|
|
|
Source* GetSource();
|
2014-09-24 16:00:02 -07:00
|
|
|
bool SatisfiesConstraintSets(
|
|
|
|
const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets);
|
2014-04-18 12:15:10 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
class AudioDevice : public MediaDevice
|
|
|
|
{
|
|
|
|
public:
|
2014-09-24 08:17:33 -07:00
|
|
|
typedef MediaEngineAudioSource Source;
|
|
|
|
|
|
|
|
explicit AudioDevice(Source* aSource);
|
2014-04-18 12:15:10 -07:00
|
|
|
NS_IMETHOD GetType(nsAString& aType);
|
2014-09-24 08:17:33 -07:00
|
|
|
Source* GetSource();
|
2014-09-24 16:00:02 -07:00
|
|
|
bool SatisfiesConstraintSets(
|
|
|
|
const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets);
|
2014-04-18 12:15:10 -07:00
|
|
|
};
|
|
|
|
|
2014-09-19 14:24:28 -07:00
|
|
|
// we could add MediaManager if needed
|
|
|
|
typedef void (*WindowListenerCallback)(MediaManager *aThis,
|
|
|
|
uint64_t aWindowID,
|
|
|
|
StreamListeners *aListeners,
|
|
|
|
void *aData);
|
|
|
|
|
2012-12-22 00:09:36 -08:00
|
|
|
class MediaManager MOZ_FINAL : public nsIMediaManagerService,
|
|
|
|
public nsIObserver
|
2012-09-20 12:54:00 -07:00
|
|
|
{
|
2012-06-03 00:35:15 -07:00
|
|
|
public:
|
2012-12-22 00:09:36 -08:00
|
|
|
static already_AddRefed<MediaManager> GetInstance();
|
|
|
|
|
2013-02-14 11:59:27 -08:00
|
|
|
// NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
|
|
|
|
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
|
|
|
|
// from MediaManager thread.
|
2013-03-04 13:02:17 -08:00
|
|
|
static MediaManager* Get();
|
2014-09-12 07:49:39 -07:00
|
|
|
static MessageLoop* GetMessageLoop();
|
2013-03-04 13:02:17 -08:00
|
|
|
|
2014-09-05 13:02:54 -07:00
|
|
|
static bool Exists()
|
|
|
|
{
|
|
|
|
return !!sSingleton;
|
|
|
|
}
|
|
|
|
|
2013-11-25 22:22:16 -08:00
|
|
|
static nsresult NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
|
|
|
|
const nsString& aMsg,
|
|
|
|
const bool& aIsAudio,
|
|
|
|
const bool& aIsVideo);
|
|
|
|
|
2013-07-18 19:21:20 -07:00
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
2012-06-03 00:35:15 -07:00
|
|
|
NS_DECL_NSIOBSERVER
|
2012-12-22 00:09:36 -08:00
|
|
|
NS_DECL_NSIMEDIAMANAGERSERVICE
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2013-11-05 19:32:42 -08:00
|
|
|
MediaEngine* GetBackend(uint64_t aWindowId = 0);
|
2012-11-13 13:55:02 -08:00
|
|
|
StreamListeners *GetWindowListeners(uint64_t aWindowId) {
|
2012-10-25 17:14:47 -07:00
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
|
|
|
|
|
2012-11-13 13:55:02 -08:00
|
|
|
return mActiveWindows.Get(aWindowId);
|
|
|
|
}
|
2014-08-22 03:21:48 -07:00
|
|
|
void RemoveWindowID(uint64_t aWindowId);
|
2012-11-13 13:55:02 -08:00
|
|
|
bool IsWindowStillActive(uint64_t aWindowId) {
|
|
|
|
return !!GetWindowListeners(aWindowId);
|
2012-10-25 17:14:47 -07:00
|
|
|
}
|
2013-01-06 18:31:32 -08:00
|
|
|
// Note: also calls aListener->Remove(), even if inactive
|
|
|
|
void RemoveFromWindowList(uint64_t aWindowID,
|
|
|
|
GetUserMediaCallbackMediaStreamListener *aListener);
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2014-09-30 16:17:53 -07:00
|
|
|
nsresult GetUserMedia(
|
2013-09-15 23:34:57 -07:00
|
|
|
nsPIDOMWindow* aWindow,
|
2014-09-30 16:17:53 -07:00
|
|
|
const dom::MediaStreamConstraints& aConstraints,
|
2012-06-03 00:35:15 -07:00
|
|
|
nsIDOMGetUserMediaSuccessCallback* onSuccess,
|
|
|
|
nsIDOMGetUserMediaErrorCallback* onError);
|
2013-09-15 23:34:57 -07:00
|
|
|
|
2012-09-20 12:54:00 -07:00
|
|
|
nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
|
2014-04-18 11:00:16 -07:00
|
|
|
const dom::MediaStreamConstraints& aConstraints,
|
2012-09-20 12:54:00 -07:00
|
|
|
nsIGetUserMediaDevicesSuccessCallback* onSuccess,
|
2014-02-14 11:32:58 -08:00
|
|
|
nsIDOMGetUserMediaErrorCallback* onError,
|
|
|
|
uint64_t aInnerWindowID = 0);
|
2012-08-22 08:56:38 -07:00
|
|
|
void OnNavigation(uint64_t aWindowID);
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2013-03-04 13:02:17 -08:00
|
|
|
MediaEnginePrefs mPrefs;
|
|
|
|
|
2012-06-03 00:35:15 -07:00
|
|
|
private:
|
2012-10-25 17:14:47 -07:00
|
|
|
WindowTable *GetActiveWindows() {
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
|
|
|
|
return &mActiveWindows;
|
2012-12-09 09:23:19 -08:00
|
|
|
}
|
2012-10-25 17:14:47 -07:00
|
|
|
|
2013-03-04 13:02:17 -08:00
|
|
|
void GetPref(nsIPrefBranch *aBranch, const char *aPref,
|
|
|
|
const char *aData, int32_t *aVal);
|
2013-12-06 11:34:40 -08:00
|
|
|
void GetPrefBool(nsIPrefBranch *aBranch, const char *aPref,
|
|
|
|
const char *aData, bool *aVal);
|
2013-03-04 13:02:17 -08:00
|
|
|
void GetPrefs(nsIPrefBranch *aBranch, const char *aData);
|
|
|
|
|
2012-06-03 00:35:15 -07:00
|
|
|
// Make private because we want only one instance of this class
|
2013-03-04 13:02:17 -08:00
|
|
|
MediaManager();
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2014-02-09 12:34:40 -08:00
|
|
|
~MediaManager() {}
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2014-08-22 02:27:16 -07:00
|
|
|
void StopScreensharing(uint64_t aWindowID);
|
2014-09-19 14:24:28 -07:00
|
|
|
void IterateWindowListeners(nsPIDOMWindow *aWindow,
|
|
|
|
WindowListenerCallback aCallback,
|
|
|
|
void *aData);
|
2014-08-22 02:27:16 -07:00
|
|
|
|
2013-09-13 01:51:48 -07:00
|
|
|
void StopMediaStreams();
|
|
|
|
|
2012-10-25 17:14:47 -07:00
|
|
|
// ONLY access from MainThread so we don't need to lock
|
|
|
|
WindowTable mActiveWindows;
|
2014-09-12 07:49:39 -07:00
|
|
|
nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
|
2014-01-08 13:51:33 -08:00
|
|
|
nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
|
2012-10-25 17:14:47 -07:00
|
|
|
// Always exists
|
2014-09-12 07:49:39 -07:00
|
|
|
nsAutoPtr<base::Thread> mMediaThread;
|
2012-10-25 17:14:47 -07:00
|
|
|
|
2012-10-24 16:21:15 -07:00
|
|
|
Mutex mMutex;
|
|
|
|
// protected with mMutex:
|
2014-02-09 12:34:40 -08:00
|
|
|
RefPtr<MediaEngine> mBackend;
|
2012-06-03 00:35:15 -07:00
|
|
|
|
2012-12-22 00:09:36 -08:00
|
|
|
static StaticRefPtr<MediaManager> sSingleton;
|
2013-05-02 05:00:12 -07:00
|
|
|
|
2014-02-09 12:34:40 -08:00
|
|
|
#ifdef MOZ_B2G_CAMERA
|
2013-05-02 05:00:12 -07:00
|
|
|
nsRefPtr<nsDOMCameraManager> mCameraManager;
|
|
|
|
#endif
|
2012-06-03 00:35:15 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mozilla
|
2014-09-30 16:17:53 -07:00
|
|
|
|
|
|
|
#endif // MOZILLA_MEDIAMANAGER_H
|