Bug 842715: Refactor gUM prefs use to be on mainthread, and prepare for constraints r=derf

This commit is contained in:
Randell Jesup 2013-03-04 16:02:17 -05:00
parent f22ad604ac
commit c92ed777f4
10 changed files with 218 additions and 222 deletions

View File

@ -20,6 +20,7 @@ namespace mozilla {
*/
class MediaEngineVideoSource;
class MediaEngineAudioSource;
struct MediaEnginePrefs;
enum MediaEngineState {
kAllocated,
@ -39,6 +40,11 @@ class MediaEngine
public:
virtual ~MediaEngine() {}
static const int DEFAULT_VIDEO_FPS = 30;
static const int DEFAULT_VIDEO_MIN_FPS = 10;
static const int DEFAULT_VIDEO_WIDTH = 640;
static const int DEFAULT_VIDEO_HEIGHT = 480;
/* Populate an array of video sources in the nsTArray. Also include devices
* that are currently unavailable. */
virtual void EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >*) = 0;
@ -63,7 +69,7 @@ public:
virtual void GetUUID(nsAString&) = 0;
/* This call reserves but does not start the device. */
virtual nsresult Allocate() = 0;
virtual nsresult Allocate(const MediaEnginePrefs &aPrefs) = 0;
/* Release the device back to the system. */
virtual nsresult Deallocate() = 0;
@ -113,27 +119,17 @@ protected:
/**
* Video source and friends.
*/
enum MediaEngineVideoCodecType {
kVideoCodecH263,
kVideoCodecVP8,
kVideoCodecI420
};
struct MediaEngineVideoOptions {
uint32_t mWidth;
uint32_t mHeight;
uint32_t mMaxFPS;
MediaEngineVideoCodecType codecType;
struct MediaEnginePrefs {
int32_t mWidth;
int32_t mHeight;
int32_t mFPS;
int32_t mMinFPS;
};
class MediaEngineVideoSource : public MediaEngineSource
{
public:
virtual ~MediaEngineVideoSource() {}
/* Return a MediaEngineVideoOptions struct with appropriate values for all
* fields. */
virtual const MediaEngineVideoOptions *GetOptions() = 0;
};
/**

View File

@ -30,14 +30,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultVideoSource, nsITimerCallback)
* Default video source.
*/
MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource(int32_t aWidth,
int32_t aHeight,
int32_t aFPS)
MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
: mTimer(nullptr)
{
mOpts.mWidth = aWidth;
mOpts.mHeight = aHeight;
mOpts.mMaxFPS = aFPS;
mState = kReleased;
}
@ -59,12 +54,13 @@ MediaEngineDefaultVideoSource::GetUUID(nsAString& aUUID)
}
nsresult
MediaEngineDefaultVideoSource::Allocate()
MediaEngineDefaultVideoSource::Allocate(const MediaEnginePrefs &aPrefs)
{
if (mState != kReleased) {
return NS_ERROR_FAILURE;
}
mOpts = aPrefs;
mState = kAllocated;
return NS_OK;
}
@ -79,12 +75,6 @@ MediaEngineDefaultVideoSource::Deallocate()
return NS_OK;
}
const MediaEngineVideoOptions *
MediaEngineDefaultVideoSource::GetOptions()
{
return &mOpts;
}
static void AllocateSolidColorFrame(layers::PlanarYCbCrImage::Data& aData,
int aWidth, int aHeight,
int aY, int aCb, int aCr)
@ -150,7 +140,7 @@ MediaEngineDefaultVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
// AddTrack takes ownership of segment
VideoSegment *segment = new VideoSegment();
segment->AppendFrame(image.forget(), USECS_PER_S / mOpts.mMaxFPS,
segment->AppendFrame(image.forget(), USECS_PER_S / mOpts.mFPS,
gfxIntSize(mOpts.mWidth, mOpts.mHeight));
mSource->AddTrack(aID, VIDEO_RATE, 0, segment);
@ -161,7 +151,7 @@ MediaEngineDefaultVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
mTrackID = aID;
// Start timer for subsequent frames
mTimer->InitWithCallback(this, 1000 / mOpts.mMaxFPS, nsITimer::TYPE_REPEATING_SLACK);
mTimer->InitWithCallback(this, 1000 / mOpts.mFPS, nsITimer::TYPE_REPEATING_SLACK);
mState = kStarted;
return NS_OK;
@ -250,7 +240,7 @@ MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
// AddTrack takes ownership of segment
VideoSegment segment;
segment.AppendFrame(ycbcr_image.forget(), USECS_PER_S / mOpts.mMaxFPS,
segment.AppendFrame(ycbcr_image.forget(), USECS_PER_S / mOpts.mFPS,
gfxIntSize(mOpts.mWidth, mOpts.mHeight));
mSource->AppendToTrack(mTrackID, &segment);
@ -301,7 +291,7 @@ MediaEngineDefaultAudioSource::GetUUID(nsAString& aUUID)
}
nsresult
MediaEngineDefaultAudioSource::Allocate()
MediaEngineDefaultAudioSource::Allocate(const MediaEnginePrefs &aPrefs)
{
if (mState != kReleased) {
return NS_ERROR_FAILURE;
@ -393,45 +383,14 @@ MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer)
void
MediaEngineDefault::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources) {
MutexAutoLock lock(mMutex);
int32_t found = false;
int32_t len = mVSources.Length();
int32_t width = MediaEngineDefaultVideoSource::DEFAULT_VIDEO_WIDTH;
int32_t height = MediaEngineDefaultVideoSource::DEFAULT_VIDEO_HEIGHT;
int32_t fps = MediaEngineDefaultVideoSource::DEFAULT_VIDEO_FPS;
// We once had code here to find a VideoSource with the same settings and re-use that.
// This no longer is possible since the resolution is being set in Allocate().
// FIX - these should be passed in originating in prefs and/or getUserMedia constraints
// Bug 778801
nsresult rv;
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
nsRefPtr<MediaEngineVideoSource> newSource = new MediaEngineDefaultVideoSource();
mVSources.AppendElement(newSource);
aVSources->AppendElement(newSource);
if (branch) {
// these very rarely change
branch->GetIntPref("media.navigator.video.default_width", &width);
branch->GetIntPref("media.navigator.video.default_height", &height);
branch->GetIntPref("media.navigator.video.default_fps", &fps);
}
}
for (int32_t i = 0; i < len; i++) {
nsRefPtr<MediaEngineVideoSource> source = mVSources.ElementAt(i);
aVSources->AppendElement(source);
const MediaEngineVideoOptions *opts = source->GetOptions();
if (source->IsAvailable() &&
opts->mWidth == width && opts->mHeight == height && opts->mMaxFPS == fps) {
found = true;
}
}
// All streams are currently busy (or wrong resolution), just make a new one.
if (!found) {
nsRefPtr<MediaEngineVideoSource> newSource =
new MediaEngineDefaultVideoSource(width, height, fps);
mVSources.AppendElement(newSource);
aVSources->AppendElement(newSource);
}
return;
}

View File

@ -34,14 +34,13 @@ class MediaEngineDefaultVideoSource : public nsITimerCallback,
public MediaEngineVideoSource
{
public:
MediaEngineDefaultVideoSource(int aWidth, int aHeight, int aFPS);
MediaEngineDefaultVideoSource();
~MediaEngineDefaultVideoSource();
virtual void GetName(nsAString&);
virtual void GetUUID(nsAString&);
virtual const MediaEngineVideoOptions *GetOptions();
virtual nsresult Allocate();
virtual nsresult Allocate(const MediaEnginePrefs &aPrefs);
virtual nsresult Deallocate();
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop(SourceMediaStream*, TrackID);
@ -73,7 +72,7 @@ protected:
SourceMediaStream* mSource;
layers::PlanarYCbCrImage* mImage;
MediaEngineVideoOptions mOpts;
MediaEnginePrefs mOpts;
int mCb;
int mCr;
};
@ -88,7 +87,7 @@ public:
virtual void GetName(nsAString&);
virtual void GetUUID(nsAString&);
virtual nsresult Allocate();
virtual nsresult Allocate(const MediaEnginePrefs &aPrefs);
virtual nsresult Deallocate();
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop(SourceMediaStream*, TrackID);

View File

@ -43,36 +43,6 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
// We spawn threads to handle gUM runnables, so we must protect the member vars
MutexAutoLock lock(mMutex);
int32_t width = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_WIDTH;
int32_t height = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_HEIGHT;
int32_t fps = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_FPS;
int32_t minfps = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_MIN_FPS;
// FIX - these should be passed in originating in prefs and/or getUserMedia constraints
// Bug 778801
nsresult rv;
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
if (branch) {
branch->GetIntPref("media.navigator.video.default_width", &width);
branch->GetIntPref("media.navigator.video.default_height", &height);
branch->GetIntPref("media.navigator.video.default_fps", &fps);
branch->GetIntPref("media.navigator.video.default_min_fps", &minfps);
}
}
LOG(("%s: %dx%d @%dfps (min %d)", __FUNCTION__, width, height, fps, minfps));
bool changed = false;
if (width != mWidth || height != mHeight || fps != mFPS || minfps != mMinFPS) {
changed = true;
}
mWidth = width;
mHeight = height;
mFPS = fps;
mMinFPS = minfps;
if (!mVideoEngine) {
if (!(mVideoEngine = webrtc::VideoEngine::Create())) {
return;
@ -162,17 +132,16 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
if (uniqueId[0] == '\0') {
// In case a device doesn't set uniqueId!
strncpy(uniqueId, deviceName, sizeof(uniqueId));
uniqueId[sizeof(uniqueId)-1] = '\0'; // strncpy isn't safe
uniqueId[sizeof(uniqueId)-1] = '\0'; // strncpy isn't safe
}
nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
NS_ConvertUTF8toUTF16 uuid(uniqueId);
if (!changed && mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
// We've already seen this device, just append.
aVSources->AppendElement(vSource.get());
} else {
vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i,
width, height, fps, minfps);
vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
aVSources->AppendElement(vSource);
}

View File

@ -56,27 +56,18 @@ class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource,
public nsRunnable
{
public:
static const int DEFAULT_VIDEO_FPS = 60;
static const int DEFAULT_VIDEO_MIN_FPS = 10;
static const int DEFAULT_VIDEO_WIDTH = 640;
static const int DEFAULT_VIDEO_HEIGHT = 480;
// ViEExternalRenderer.
virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
virtual int DeliverFrame(unsigned char*, int, uint32_t, int64_t);
MediaEngineWebRTCVideoSource(webrtc::VideoEngine* aVideoEnginePtr,
int aIndex,
int aWidth = DEFAULT_VIDEO_WIDTH, int aHeight = DEFAULT_VIDEO_HEIGHT,
int aFps = DEFAULT_VIDEO_FPS, int aMinFps = DEFAULT_VIDEO_MIN_FPS)
MediaEngineWebRTCVideoSource(webrtc::VideoEngine* aVideoEnginePtr, int aIndex)
: mVideoEngine(aVideoEnginePtr)
, mCaptureIndex(aIndex)
, mCapabilityChosen(false)
, mWidth(aWidth)
, mHeight(aHeight)
, mWidth(0)
, mHeight(0)
, mFps(-1)
, mMinFps(-1)
, mMonitor("WebRTCCamera.Monitor")
, mFps(aFps)
, mMinFps(aMinFps)
, mInitDone(false)
, mInSnapshotMode(false)
, mSnapshotPath(NULL) {
@ -88,8 +79,7 @@ public:
virtual void GetName(nsAString&);
virtual void GetUUID(nsAString&);
virtual const MediaEngineVideoOptions *GetOptions();
virtual nsresult Allocate();
virtual nsresult Allocate(const MediaEnginePrefs &aPrefs);
virtual nsresult Deallocate();
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop(SourceMediaStream*, TrackID);
@ -141,8 +131,9 @@ private:
webrtc::CaptureCapability mCapability; // Doesn't work on OS X.
int mCaptureIndex;
bool mCapabilityChosen;
int mWidth, mHeight;
int mFps; // Track rate (30 fps by default)
int mMinFps; // Min rate we want to accept
// mMonitor protects mImage access/changes, and transitions of mState
// from kStarted to kStopped (which are combined with EndTrack() and
@ -151,8 +142,6 @@ private:
mozilla::ReentrantMonitor mMonitor; // Monitor for processing WebRTC frames.
nsTArray<SourceMediaStream *> mSources; // When this goes empty, we shut down HW
int mFps; // Track rate (30 fps by default)
int mMinFps; // Min rate we want to accept
bool mInitDone;
bool mInSnapshotMode;
nsString* mSnapshotPath;
@ -167,8 +156,7 @@ private:
char mDeviceName[KMaxDeviceNameLength];
char mUniqueId[KMaxUniqueIdLength];
void ChooseCapability(uint32_t aWidth, uint32_t aHeight, uint32_t aMinFPS);
MediaEngineVideoOptions mOpts;
void ChooseCapability(const MediaEnginePrefs &aPrefs);
};
class MediaEngineWebRTCAudioSource : public MediaEngineAudioSource,
@ -198,7 +186,7 @@ public:
virtual void GetName(nsAString&);
virtual void GetUUID(nsAString&);
virtual nsresult Allocate();
virtual nsresult Allocate(const MediaEnginePrefs &aPrefs);
virtual nsresult Deallocate();
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop(SourceMediaStream*, TrackID);
@ -288,9 +276,6 @@ private:
bool mVideoEngineInit;
bool mAudioEngineInit;
// the last set of selection vars for video sources
int mHeight, mWidth, mFPS, mMinFPS;
// Store devices we've already seen in a hashtable for quick return.
// Maps UUID to MediaEngineSource (one set for audio, one for video).
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCVideoSource > mVideoSources;

View File

@ -101,7 +101,7 @@ MediaEngineWebRTCAudioSource::Config(bool aEchoOn, uint32_t aEcho,
}
nsresult
MediaEngineWebRTCAudioSource::Allocate()
MediaEngineWebRTCAudioSource::Allocate(const MediaEnginePrefs &aPrefs)
{
if (mState == kReleased && mInitDone) {
webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);

View File

@ -55,6 +55,11 @@ MediaEngineWebRTCVideoSource::DeliverFrame(
return 0;
}
MOZ_ASSERT(mWidth*mHeight*3/2 == size);
if (mWidth*mHeight*3/2 != size) {
return 0;
}
// Create a video frame and append it to the track.
ImageFormat format = PLANAR_YCBCR;
@ -119,11 +124,24 @@ MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph,
TrackTicks delta = target - aLastEndTime;
LOGFRAME(("NotifyPull, desired = %ld, target = %ld, delta = %ld %s", (int64_t) aDesiredTime,
(int64_t) target, (int64_t) delta, image ? "" : "<null>"));
// Bug 846188 We may want to limit incoming frames to the requested frame rate
// mFps - if you want 30FPS, and the camera gives you 60FPS, this could
// cause issues.
// We may want to signal if the actual frame rate is below mMinFPS -
// cameras often don't return the requested frame rate especially in low
// light; we should consider surfacing this so that we can switch to a
// lower resolution (which may up the frame rate)
// Don't append if we've already provided a frame that supposedly goes past the current aDesiredTime
// Doing so means a negative delta and thus messes up handling of the graph
if (delta > 0) {
// NULL images are allowed
segment.AppendFrame(image ? image.forget() : nullptr, delta, gfxIntSize(mWidth, mHeight));
if (image) {
segment.AppendFrame(image.forget(), delta, gfxIntSize(mWidth, mHeight));
} else {
segment.AppendFrame(nullptr, delta, gfxIntSize(0,0));
}
// This can fail if either a) we haven't added the track yet, or b)
// we've removed or finished the track.
if (aSource->AppendToTrack(aID, &(segment))) {
@ -133,21 +151,19 @@ MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph,
}
void
MediaEngineWebRTCVideoSource::ChooseCapability(uint32_t aWidth, uint32_t aHeight, uint32_t aMinFPS)
MediaEngineWebRTCVideoSource::ChooseCapability(const MediaEnginePrefs &aPrefs)
{
int num = mViECapture->NumberOfCapabilities(mUniqueId, KMaxUniqueIdLength);
NS_WARN_IF_FALSE(!mCapabilityChosen,"Shouldn't select capability of a device twice");
LOG(("ChooseCapability: prefs: %dx%d @%d-%dfps", aPrefs.mWidth, aPrefs.mHeight, aPrefs.mFPS, aPrefs.mMinFPS));
if (num <= 0) {
// Set to default values
mCapability.width = mOpts.mWidth = aWidth;
mCapability.height = mOpts.mHeight = aHeight;
mCapability.maxFPS = mOpts.mMaxFPS = DEFAULT_VIDEO_FPS;
mOpts.codecType = kVideoCodecI420;
mCapability.width = aPrefs.mWidth;
mCapability.height = aPrefs.mHeight;
mCapability.maxFPS = MediaEngine::DEFAULT_VIDEO_FPS;
// Mac doesn't support capabilities.
mCapabilityChosen = true;
return;
}
@ -160,31 +176,26 @@ MediaEngineWebRTCVideoSource::ChooseCapability(uint32_t aWidth, uint32_t aHeight
mViECapture->GetCaptureCapability(mUniqueId, KMaxUniqueIdLength, i, cap);
if (higher) {
if (i == 0 ||
(mOpts.mWidth > cap.width && mOpts.mHeight > cap.height)) {
mOpts.mWidth = cap.width;
mOpts.mHeight = cap.height;
mOpts.mMaxFPS = cap.maxFPS;
(mCapability.width > cap.width && mCapability.height > cap.height)) {
// closer than the current choice
mCapability = cap;
// FIXME: expose expected capture delay?
}
if (cap.width <= aWidth && cap.height <= aHeight) {
if (cap.width <= (uint32_t) aPrefs.mWidth && cap.height <= (uint32_t) aPrefs.mHeight) {
higher = false;
}
} else {
if (cap.width > aWidth || cap.height > aHeight || cap.maxFPS < aMinFPS) {
if (cap.width > (uint32_t) aPrefs.mWidth || cap.height > (uint32_t) aPrefs.mHeight ||
cap.maxFPS < (uint32_t) aPrefs.mMinFPS) {
continue;
}
if (mOpts.mWidth < cap.width && mOpts.mHeight < cap.height) {
mOpts.mWidth = cap.width;
mOpts.mHeight = cap.height;
mOpts.mMaxFPS = cap.maxFPS;
if (mCapability.width < cap.width && mCapability.height < cap.height) {
mCapability = cap;
// FIXME: expose expected capture delay?
}
}
}
LOG(("chose cap %dx%d @%dfps", mOpts.mWidth, mOpts.mHeight, mOpts.mMaxFPS));
mCapabilityChosen = true;
LOG(("chose cap %dx%d @%dfps", mCapability.width, mCapability.height, mCapability.maxFPS));
}
void
@ -202,15 +213,15 @@ MediaEngineWebRTCVideoSource::GetUUID(nsAString& aUUID)
}
nsresult
MediaEngineWebRTCVideoSource::Allocate()
MediaEngineWebRTCVideoSource::Allocate(const MediaEnginePrefs &aPrefs)
{
LOG((__FUNCTION__));
if (!mCapabilityChosen) {
// XXX these should come from constraints
ChooseCapability(mWidth, mHeight, mMinFps);
}
if (mState == kReleased && mInitDone) {
// Note: if shared, we don't allow a later opener to affect the resolution.
// (This may change depending on spec changes for Constraints/settings)
ChooseCapability(aPrefs);
if (mViECapture->AllocateCaptureDevice(mUniqueId, KMaxUniqueIdLength, mCaptureIndex)) {
return NS_ERROR_FAILURE;
}
@ -262,15 +273,6 @@ MediaEngineWebRTCVideoSource::Deallocate()
return NS_OK;
}
const MediaEngineVideoOptions*
MediaEngineWebRTCVideoSource::GetOptions()
{
if (!mCapabilityChosen) {
ChooseCapability(mWidth, mHeight, mMinFps);
}
return &mOpts;
}
nsresult
MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
{
@ -445,7 +447,9 @@ MediaEngineWebRTCVideoSource::Init()
mDeviceName[0] = '\0'; // paranoia
mUniqueId[0] = '\0';
(void) mFps; // fix compile warning for this being unused. (remove once used)
// fix compile warning for these being unused. (remove once used)
(void) mFps;
(void) mMinFps;
LOG((__FUNCTION__));
if (mVideoEngine == NULL) {

View File

@ -11,8 +11,6 @@
#include "nsIScriptGlobalObject.h"
#include "nsIPopupWindowManager.h"
#include "nsISupportsArray.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIDocShell.h"
// For PR_snprintf
@ -454,6 +452,7 @@ public:
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
MediaEnginePrefs &aPrefs,
MediaDevice* aAudioDevice, MediaDevice* aVideoDevice)
: mAudio(aAudio)
, mVideo(aVideo)
@ -462,22 +461,24 @@ public:
, mError(aError)
, mWindowID(aWindowID)
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(true)
, mBackendChosen(false)
, mManager(MediaManager::GetInstance())
{
if (mAudio) {
mAudioDevice = aAudioDevice;
}
if (mVideo) {
mVideoDevice = aVideoDevice;
}
{
if (mAudio) {
mAudioDevice = aAudioDevice;
}
if (mVideo) {
mVideoDevice = aVideoDevice;
}
}
GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture,
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener)
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
MediaEnginePrefs &aPrefs)
: mAudio(aAudio)
, mVideo(aVideo)
, mPicture(aPicture)
@ -485,9 +486,11 @@ public:
, mError(aError)
, mWindowID(aWindowID)
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(false)
, mBackendChosen(false)
, mManager(MediaManager::GetInstance()) {}
, mManager(MediaManager::GetInstance())
{}
/**
* The caller can also choose to provide their own backend instead of
@ -497,6 +500,7 @@ public:
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
MediaEnginePrefs &aPrefs,
MediaEngine* aBackend)
: mAudio(aAudio)
, mVideo(aVideo)
@ -505,10 +509,12 @@ public:
, mError(aError)
, mWindowID(aWindowID)
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(false)
, mBackendChosen(true)
, mBackend(aBackend)
, mManager(MediaManager::GetInstance()) {}
, mManager(MediaManager::GetInstance())
{}
~GetUserMediaRunnable() {
if (mBackendChosen) {
@ -678,7 +684,7 @@ public:
{
nsresult rv;
if (aAudioSource) {
rv = aAudioSource->Allocate();
rv = aAudioSource->Allocate(mPrefs);
if (NS_FAILED(rv)) {
LOG(("Failed to allocate audiosource %d",rv));
NS_DispatchToMainThread(new ErrorCallbackRunnable(
@ -688,7 +694,7 @@ public:
}
}
if (aVideoSource) {
rv = aVideoSource->Allocate();
rv = aVideoSource->Allocate(mPrefs);
if (NS_FAILED(rv)) {
LOG(("Failed to allocate videosource %d\n",rv));
if (aAudioSource) {
@ -714,7 +720,7 @@ public:
void
ProcessGetUserMediaSnapshot(MediaEngineSource* aSource, int aDuration)
{
nsresult rv = aSource->Allocate();
nsresult rv = aSource->Allocate(mPrefs);
if (NS_FAILED(rv)) {
NS_DispatchToMainThread(new ErrorCallbackRunnable(
mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
@ -746,6 +752,7 @@ private:
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
nsRefPtr<MediaDevice> mAudioDevice;
nsRefPtr<MediaDevice> mVideoDevice;
MediaEnginePrefs mPrefs;
bool mDeviceChosen;
bool mBackendChosen;
@ -769,8 +776,7 @@ public:
: mSuccess(aSuccess)
, mError(aError)
, mManager(MediaManager::GetInstance())
{}
~GetUserMediaDevicesRunnable() {}
{}
NS_IMETHOD
Run()
@ -817,10 +823,65 @@ private:
nsRefPtr<MediaManager> mManager;
};
MediaManager::MediaManager()
: mMediaThread(nullptr)
, mMutex("mozilla::MediaManager")
, mBackend(nullptr) {
mPrefs.mWidth = MediaEngine::DEFAULT_VIDEO_WIDTH;
mPrefs.mHeight = MediaEngine::DEFAULT_VIDEO_HEIGHT;
mPrefs.mFPS = MediaEngine::DEFAULT_VIDEO_FPS;
mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS;
nsresult rv;
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
if (branch) {
GetPrefs(branch, nullptr);
}
}
LOG(("%s: default prefs: %dx%d @%dfps (min %d)", __FUNCTION__,
mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS, mPrefs.mMinFPS));
mActiveWindows.Init();
mActiveCallbacks.Init();
}
NS_IMPL_THREADSAFE_ISUPPORTS2(MediaManager, nsIMediaManagerService, nsIObserver)
/* static */ StaticRefPtr<MediaManager> MediaManager::sSingleton;
// NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
// from MediaManager thread.
/* static */ MediaManager*
MediaManager::Get() {
if (!sSingleton) {
sSingleton = new MediaManager();
NS_NewThread(getter_AddRefs(sSingleton->mMediaThread));
LOG(("New Media thread for gum"));
NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
obs->AddObserver(sSingleton, "getUserMedia:revoke", false);
}
// else MediaManager won't work properly and will leak (see bug 837874)
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
prefs->AddObserver("media.navigator.video.default_width", sSingleton, false);
prefs->AddObserver("media.navigator.video.default_height", sSingleton, false);
prefs->AddObserver("media.navigator.video.default_fps", sSingleton, false);
prefs->AddObserver("media.navigator.video.default_minfps", sSingleton, false);
}
}
return sSingleton;
}
/* static */ already_AddRefed<MediaManager>
MediaManager::GetInstance()
{
@ -966,23 +1027,24 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
*
* If a fake stream was requested, we force the use of the default backend.
*/
// XXX take options from constraints instead of prefs
if (fake) {
// Fake stream from default backend.
gUMRunnable = new GetUserMediaRunnable(
audio, video, onSuccess.forget(), onError.forget(), windowID, listener,
audio, video, onSuccess.forget(), onError.forget(), windowID, listener, mPrefs,
new MediaEngineDefault()
);
} else if (audiodevice || videodevice) {
// Stream from provided device.
gUMRunnable = new GetUserMediaRunnable(
audio, video, picture, onSuccess.forget(), onError.forget(), windowID, listener,
audio, video, picture, onSuccess.forget(), onError.forget(), windowID, listener, mPrefs,
static_cast<MediaDevice*>(audiodevice.get()),
static_cast<MediaDevice*>(videodevice.get())
);
} else {
// Stream from default device from WebRTC backend.
gUMRunnable = new GetUserMediaRunnable(
audio, video, picture, onSuccess.forget(), onError.forget(), windowID, listener
audio, video, picture, onSuccess.forget(), onError.forget(), windowID, listener, mPrefs
);
}
@ -1156,6 +1218,27 @@ MediaManager::RemoveFromWindowList(uint64_t aWindowID,
}
}
void
MediaManager::GetPref(nsIPrefBranch *aBranch, const char *aPref,
const char *aData, int32_t *aVal)
{
int32_t temp;
if (aData == nullptr || strcmp(aPref,aData) == 0) {
if (NS_SUCCEEDED(aBranch->GetIntPref(aPref, &temp))) {
*aVal = temp;
}
}
}
void
MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
{
GetPref(aBranch, "media.navigator.video.default_width", aData, &mPrefs.mWidth);
GetPref(aBranch, "media.navigator.video.default_height", aData, &mPrefs.mHeight);
GetPref(aBranch, "media.navigator.video.default_fps", aData, &mPrefs.mFPS);
GetPref(aBranch, "media.navigator.video.default_minfps", aData, &mPrefs.mMinFPS);
}
nsresult
MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
@ -1163,12 +1246,27 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!strcmp(aTopic, "xpcom-shutdown")) {
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
nsCOMPtr<nsIPrefBranch> branch( do_QueryInterface(aSubject) );
if (branch) {
GetPrefs(branch,NS_ConvertUTF16toUTF8(aData).get());
LOG(("%s: %dx%d @%dfps (min %d)", __FUNCTION__,
mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS, mPrefs.mMinFPS));
}
} else if (!strcmp(aTopic, "xpcom-shutdown")) {
obs->RemoveObserver(this, "xpcom-shutdown");
obs->RemoveObserver(this, "getUserMedia:response:allow");
obs->RemoveObserver(this, "getUserMedia:response:deny");
obs->RemoveObserver(this, "getUserMedia:revoke");
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
prefs->RemoveObserver("media.navigator.video.default_width", this);
prefs->RemoveObserver("media.navigator.video.default_height", this);
prefs->RemoveObserver("media.navigator.video.default_fps", this);
prefs->RemoveObserver("media.navigator.video.default_minfps", this);
}
// Close off any remaining active windows.
{
MutexAutoLock lock(mMutex);
@ -1178,9 +1276,8 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
}
return NS_OK;
}
if (!strcmp(aTopic, "getUserMedia:response:allow")) {
} else if (!strcmp(aTopic, "getUserMedia:response:allow")) {
nsString key(aData);
nsRefPtr<nsRunnable> runnable;
if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
@ -1225,9 +1322,8 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
// Reuse the same thread to save memory.
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return NS_OK;
}
if (!strcmp(aTopic, "getUserMedia:response:deny")) {
} else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
nsString errorMessage(NS_LITERAL_STRING("PERMISSION_DENIED"));
if (aSubject) {
@ -1249,9 +1345,8 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
static_cast<GetUserMediaRunnable*>(runnable.get());
gUMRunnable->Denied(errorMessage);
return NS_OK;
}
if (!strcmp(aTopic, "getUserMedia:revoke")) {
} else if (!strcmp(aTopic, "getUserMedia:revoke")) {
nsresult rv;
uint64_t windowID = nsString(aData).ToInteger64(&rv);
MOZ_ASSERT(NS_SUCCEEDED(rv));

View File

@ -13,6 +13,8 @@
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsObserverService.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMNavigatorUserMedia.h"
@ -379,25 +381,8 @@ public:
// NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
// from MediaManager thread.
static MediaManager* Get() {
if (!sSingleton) {
sSingleton = new MediaManager();
static MediaManager* Get();
NS_NewThread(getter_AddRefs(sSingleton->mMediaThread));
MM_LOG(("New Media thread for gum"));
NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
obs->AddObserver(sSingleton, "getUserMedia:revoke", false);
}
// else MediaManager won't work properly and will leak (see bug 837874)
}
return sSingleton;
}
static nsIThread* GetThread() {
return Get()->mMediaThread;
}
@ -431,20 +416,20 @@ public:
nsIDOMGetUserMediaErrorCallback* onError);
void OnNavigation(uint64_t aWindowID);
MediaEnginePrefs mPrefs;
private:
WindowTable *GetActiveWindows() {
NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
return &mActiveWindows;
}
void GetPref(nsIPrefBranch *aBranch, const char *aPref,
const char *aData, int32_t *aVal);
void GetPrefs(nsIPrefBranch *aBranch, const char *aData);
// Make private because we want only one instance of this class
MediaManager()
: mMediaThread(nullptr)
, mMutex("mozilla::MediaManager")
, mBackend(nullptr) {
mActiveWindows.Init();
mActiveCallbacks.Init();
}
MediaManager();
~MediaManager() {
delete mBackend;

View File

@ -180,6 +180,10 @@ pref("media.gstreamer.enabled", true);
#endif
#ifdef MOZ_WEBRTC
pref("media.navigator.enabled", true);
pref("media.navigator.video.default_width",640);
pref("media.navigator.video.default_height",480);
pref("media.navigator.video.default_fps",30);
pref("media.navigator.video.default_minfps",10);
pref("media.peerconnection.enabled", true);
pref("media.navigator.permission.disabled", false);
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:23.21.150.121\"}]");