Bug 1286429 - Fire fake devicechange event in Camera IPC thread for mochitest; r?jib
MozReview-Commit-ID: 9sDLnMGh3xL
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1704,16 +1704,17 @@ MediaManager::MediaManager()
mPrefs.mHeight = 0; // adaptive default
mPrefs.mFPS = MediaEngine::DEFAULT_VIDEO_FPS;
mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS;
mPrefs.mAecOn = false;
mPrefs.mAgcOn = false;
mPrefs.mNoiseOn = false;
mPrefs.mExtendedFilter = true;
mPrefs.mDelayAgnostic = true;
+ mPrefs.mFakeDeviceChangeEventOn = false;
#ifdef MOZ_WEBRTC
mPrefs.mAec = webrtc::kEcUnchanged;
mPrefs.mAgc = webrtc::kAgcUnchanged;
mPrefs.mNoise = webrtc::kNsUnchanged;
#else
mPrefs.mAec = 0;
mPrefs.mAgc = 0;
mPrefs.mNoise = 0;
@@ -1802,16 +1803,17 @@ MediaManager::Get() {
#ifdef MOZ_WEBRTC
prefs->AddObserver("media.getusermedia.aec_enabled", sSingleton, false);
prefs->AddObserver("media.getusermedia.aec", sSingleton, false);
prefs->AddObserver("media.getusermedia.agc_enabled", sSingleton, false);
prefs->AddObserver("media.getusermedia.agc", sSingleton, false);
prefs->AddObserver("media.getusermedia.noise_enabled", sSingleton, false);
prefs->AddObserver("media.getusermedia.noise", sSingleton, false);
prefs->AddObserver("media.getusermedia.playout_delay", sSingleton, false);
+ prefs->AddObserver("media.ondevicechange.fakeDeviceChangeEvent.enabled", sSingleton, false);
#endif
}
// Prepare async shutdown
nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase = GetShutdownPhase();
class Blocker : public media::ShutdownBlocker
@@ -1994,19 +1996,22 @@ bool MediaManager::IsPrivateBrowsing(nsP
{
nsCOMPtr<nsIDocument> doc = window->GetDoc();
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
return loadContext && loadContext->UsePrivateBrowsing();
}
int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
{
- MediaManager::PostTask(NewTaskFrom([]() {
+ bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
+ MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
RefPtr<MediaManager> manager = MediaManager_GetInstance();
manager->GetBackend(0)->AddDeviceChangeCallback(manager);
+ if (fakeDeviceChangeEventOn)
+ manager->GetBackend(0)->SetFakeDeviceChangeEvents();
}));
return DeviceChangeCallback::AddDeviceChangeCallback(aCallback);
}
void MediaManager::OnDeviceChange() {
RefPtr<MediaManager> self(this);
NS_DispatchToMainThread(media::NewRunnableFrom([self,this]() mutable {
@@ -2870,16 +2875,17 @@ MediaManager::GetPrefs(nsIPrefBranch *aB
GetPrefBool(aBranch, "media.getusermedia.agc_enabled", aData, &mPrefs.mAgcOn);
GetPrefBool(aBranch, "media.getusermedia.noise_enabled", aData, &mPrefs.mNoiseOn);
GetPref(aBranch, "media.getusermedia.aec", aData, &mPrefs.mAec);
GetPref(aBranch, "media.getusermedia.agc", aData, &mPrefs.mAgc);
GetPref(aBranch, "media.getusermedia.noise", aData, &mPrefs.mNoise);
GetPref(aBranch, "media.getusermedia.playout_delay", aData, &mPrefs.mPlayoutDelay);
GetPrefBool(aBranch, "media.getusermedia.aec_extended_filter", aData, &mPrefs.mExtendedFilter);
GetPrefBool(aBranch, "media.getusermedia.aec_aec_delay_agnostic", aData, &mPrefs.mDelayAgnostic);
+ GetPrefBool(aBranch, "media.ondevicechange.fakeDeviceChangeEvent.enabled", aData, &mPrefs.mFakeDeviceChangeEventOn);
#endif
GetPrefBool(aBranch, "media.navigator.audio.full_duplex", aData, &mPrefs.mFullDuplex);
}
void
MediaManager::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
@@ -2906,16 +2912,17 @@ MediaManager::Shutdown()
#ifdef MOZ_WEBRTC
prefs->RemoveObserver("media.getusermedia.aec_enabled", this);
prefs->RemoveObserver("media.getusermedia.aec", this);
prefs->RemoveObserver("media.getusermedia.agc_enabled", this);
prefs->RemoveObserver("media.getusermedia.agc", this);
prefs->RemoveObserver("media.getusermedia.noise_enabled", this);
prefs->RemoveObserver("media.getusermedia.noise", this);
prefs->RemoveObserver("media.getusermedia.playout_delay", this);
+ prefs->RemoveObserver("media.ondevicechange.fakeDeviceChangeEvent.enabled", this);
#endif
prefs->RemoveObserver("media.navigator.audio.full_duplex", this);
}
// Close off any remaining active windows.
GetActiveWindows()->Clear();
mActiveCallbacks.Clear();
mCallIds.Clear();
--- a/dom/media/systemservices/CamerasChild.cpp
+++ b/dom/media/systemservices/CamerasChild.cpp
@@ -20,30 +20,61 @@
#include "nsThreadUtils.h"
#undef LOG
#undef LOG_ENABLED
mozilla::LazyLogModule gCamerasChildLog("CamerasChild");
#define LOG(args) MOZ_LOG(gCamerasChildLog, mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() MOZ_LOG_TEST(gCamerasChildLog, mozilla::LogLevel::Debug)
+#define FAKE_ONDEVICECHANGE_EVENT_PERIOD_IN_MS 5000
+#define FAKE_ONDEVICECHANGE_EVENT_REPEAT_COUNT 30
+
namespace mozilla {
namespace camera {
CamerasSingleton::CamerasSingleton()
: mCamerasMutex("CamerasSingleton::mCamerasMutex"),
mCameras(nullptr),
mCamerasChildThread(nullptr) {
LOG(("CamerasSingleton: %p", this));
}
CamerasSingleton::~CamerasSingleton() {
LOG(("~CamerasSingleton: %p", this));
}
+class FakeOnDeviceChangeEventRunnable : public Runnable
+{
+public:
+ explicit FakeOnDeviceChangeEventRunnable(uint8_t counter)
+ : mCounter(counter) {}
+
+ NS_IMETHOD Run() override
+ {
+ OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
+
+ CamerasChild* child = CamerasSingleton::Child();
+ if (child) {
+ child->OnDeviceChange();
+
+ if (mCounter++ < FAKE_ONDEVICECHANGE_EVENT_REPEAT_COUNT) {
+ RefPtr<FakeOnDeviceChangeEventRunnable> evt = new FakeOnDeviceChangeEventRunnable(mCounter);
+ CamerasSingleton::Thread()->DelayedDispatch(evt.forget(),
+ FAKE_ONDEVICECHANGE_EVENT_PERIOD_IN_MS);
+ }
+ }
+
+ return NS_OK;
+ }
+
+private:
+ uint8_t mCounter;
+};
+
class InitializeIPCThread : public Runnable
{
public:
InitializeIPCThread()
: mCamerasChild(nullptr) {}
NS_IMETHOD Run() override {
// Try to get the PBackground handle
@@ -587,16 +618,29 @@ CamerasChild::RecvDeliverFrame(const int
bool
CamerasChild::RecvDeviceChange()
{
this->OnDeviceChange();
return true;
}
+int
+CamerasChild::SetFakeDeviceChangeEvents()
+{
+ CamerasSingleton::Mutex().AssertCurrentThreadOwns();
+
+ // To simulate the devicechange event in mochitest,
+ // we fire a fake devicechange event in Camera IPC thread periodically
+ RefPtr<FakeOnDeviceChangeEventRunnable> evt = new FakeOnDeviceChangeEventRunnable(0);
+ CamerasSingleton::Thread()->Dispatch(evt.forget(), NS_DISPATCH_NORMAL);
+
+ return 0;
+}
+
bool
CamerasChild::RecvFrameSizeChange(const int& capEngine,
const int& capId,
const int& w, const int& h)
{
LOG((__PRETTY_FUNCTION__));
MutexAutoLock lock(mCallbackMutex);
CaptureEngine capEng = static_cast<CaptureEngine>(capEngine);
--- a/dom/media/systemservices/CamerasChild.h
+++ b/dom/media/systemservices/CamerasChild.h
@@ -155,16 +155,17 @@ public:
// these are the actual callbacks with data
virtual bool RecvDeliverFrame(const int&, const int&, mozilla::ipc::Shmem&&,
const size_t&, const uint32_t&, const int64_t&,
const int64_t&) override;
virtual bool RecvFrameSizeChange(const int&, const int&,
const int& w, const int& h) override;
virtual bool RecvDeviceChange() override;
+ int SetFakeDeviceChangeEvents();
// these are response messages to our outgoing requests
virtual bool RecvReplyNumberOfCaptureDevices(const int&) override;
virtual bool RecvReplyNumberOfCapabilities(const int&) override;
virtual bool RecvReplyAllocateCaptureDevice(const int&) override;
virtual bool RecvReplyGetCaptureCapability(const CaptureCapability& capability) override;
virtual bool RecvReplyGetCaptureDevice(const nsCString& device_name,
const nsCString& device_id) override;
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -71,16 +71,18 @@ public:
/* Populate an array of audio sources in the nsTArray. Also include devices
* that are currently unavailable. */
virtual void EnumerateAudioDevices(dom::MediaSourceEnum,
nsTArray<RefPtr<MediaEngineAudioSource> >*) = 0;
virtual void Shutdown() = 0;
+ virtual void SetFakeDeviceChangeEvents() {}
+
protected:
virtual ~MediaEngine() {}
};
/**
* Video source and friends.
*/
class MediaEnginePrefs {
@@ -96,16 +98,17 @@ public:
, mNoiseOn(false)
, mAec(0)
, mAgc(0)
, mNoise(0)
, mPlayoutDelay(0)
, mFullDuplex(false)
, mExtendedFilter(false)
, mDelayAgnostic(false)
+ , mFakeDeviceChangeEventOn(false)
{}
int32_t mWidth;
int32_t mHeight;
int32_t mFPS;
int32_t mMinFPS;
int32_t mFreq; // for test tones (fake:true)
bool mAecOn;
@@ -113,16 +116,17 @@ public:
bool mNoiseOn;
int32_t mAec;
int32_t mAgc;
int32_t mNoise;
int32_t mPlayoutDelay;
bool mFullDuplex;
bool mExtendedFilter;
bool mDelayAgnostic;
+ bool mFakeDeviceChangeEventOn;
// mWidth and/or mHeight may be zero (=adaptive default), so use functions.
int32_t GetWidth(bool aHD = false) const {
return mWidth? mWidth : (mHeight?
(mHeight * GetDefWidth(aHD)) / GetDefHeight(aHD) :
GetDefWidth(aHD));
}
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -127,16 +127,23 @@ MediaEngineWebRTC::MediaEngineWebRTC(Med
gFarendObserver = new AudioOutputObserver();
camera::GetChildAndCall(
&camera::CamerasChild::AddDeviceChangeCallback,
this);
}
void
+MediaEngineWebRTC::SetFakeDeviceChangeEvents()
+{
+ camera::GetChildAndCall(
+ &camera::CamerasChild::SetFakeDeviceChangeEvents);
+}
+
+void
MediaEngineWebRTC::EnumerateVideoDevices(dom::MediaSourceEnum aMediaSource,
nsTArray<RefPtr<MediaEngineVideoSource> >* aVSources)
{
// We spawn threads to handle gUM runnables, so we must protect the member vars
MutexAutoLock lock(mMutex);
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
if (aMediaSource != dom::MediaSourceEnum::Camera) {
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -566,16 +566,18 @@ private:
};
class MediaEngineWebRTC : public MediaEngine
{
typedef MediaEngine Super;
public:
explicit MediaEngineWebRTC(MediaEnginePrefs& aPrefs);
+ virtual void SetFakeDeviceChangeEvents() override;
+
// Clients should ensure to clean-up sources video/audio sources
// before invoking Shutdown on this class.
void Shutdown() override;
// Returns whether the host supports duplex audio stream.
bool SupportsDuplex();
void EnumerateVideoDevices(dom::MediaSourceEnum,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4792,16 +4792,19 @@ pref("dom.w3c_touch_events.enabled", 2);
pref("dom.w3c_pointer_events.enabled", false);
// W3C draft ImageCapture API
pref("dom.imagecapture.enabled", false);
// W3C MediaDevices devicechange event
pref("media.ondevicechange.enabled", false);
+// W3C MediaDevices devicechange fake event
+pref("media.ondevicechange.fakeDeviceChangeEvent.enabled", false);
+
// W3C touch-action css property (related to touch and pointer events)
// Note that we turn this on even on platforms/configurations where touch
// events are not supported (e.g. OS X, or Windows with e10s disabled). For
// those platforms we don't handle touch events anyway so it's conceptually
// a no-op.
#ifdef NIGHTLY_BUILD
pref("layout.css.touch_action.enabled", true);
#else