Bug 1286096 - Move UpdateSingleSource pattern to MediaEngine base class for reuse. r=padenot

MozReview-Commit-ID: IJjZayOSxp4

--HG--
extra : rebase_source : de44566213623492982653c90793be9cceee539b
This commit is contained in:
Jan-Ivar Bruaroey 2016-07-13 16:07:03 -04:00
parent 9f23bcc615
commit 1f7f1269f6
8 changed files with 167 additions and 133 deletions

View File

@ -8,6 +8,7 @@
#include "mozilla/RefPtr.h"
#include "DOMMediaStream.h"
#include "MediaStreamGraph.h"
#include "MediaTrackConstraints.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/dom/VideoStreamTrack.h"
@ -173,8 +174,16 @@ protected:
/**
* Common abstract base class for audio and video sources.
*
* By default, the base class implements Allocate and Deallocate using its
* UpdateSingleSource pattern, which manages allocation handles and calculates
* net constraints from competing allocations and updates a single shared device.
*
* Classes that don't operate as a single shared device can override Allocate
* and Deallocate and simply not pass the methods up.
*/
class MediaEngineSource : public nsISupports
class MediaEngineSource : public nsISupports,
protected MediaConstraintsHelper
{
public:
// code inside webrtc.org assumes these sizes; don't use anything smaller
@ -182,9 +191,17 @@ public:
static const unsigned int kMaxDeviceNameLength = 128;
static const unsigned int kMaxUniqueIdLength = 256;
virtual ~MediaEngineSource() {}
virtual ~MediaEngineSource()
{
if (!mInShutdown) {
Shutdown();
}
}
virtual void Shutdown() = 0;
virtual void Shutdown()
{
mInShutdown = true;
};
/* Populate the human readable name of this device in the nsAString */
virtual void GetName(nsAString&) const = 0;
@ -215,7 +232,30 @@ public:
};
/* Release the device back to the system. */
virtual nsresult Deallocate(AllocationHandle* aHandle) = 0;
virtual nsresult Deallocate(AllocationHandle* aHandle)
{
MOZ_ASSERT(aHandle);
RefPtr<AllocationHandle> handle = aHandle;
class Comparator {
public:
static bool Equals(const RefPtr<AllocationHandle>& a,
const RefPtr<AllocationHandle>& b) {
return a.get() == b.get();
}
};
MOZ_ASSERT(mRegisteredHandles.Contains(handle, Comparator()));
mRegisteredHandles.RemoveElementAt(mRegisteredHandles.IndexOf(handle, 0,
Comparator()));
if (mRegisteredHandles.Length() && !mInShutdown) {
// Whenever constraints are removed, other parties may get closer to ideal.
auto& first = mRegisteredHandles[0];
const char* badConstraint = nullptr;
return ReevaluateAllocation(nullptr, nullptr, first->mPrefs,
first->mDeviceId, &badConstraint);
}
return NS_OK;
}
/* Start the device and add the track to the provided SourceMediaStream, with
* the provided TrackID. You may start appending data to the track
@ -274,7 +314,20 @@ public:
const nsString& aDeviceId,
const nsACString& aOrigin,
AllocationHandle** aOutHandle,
const char** aOutBadConstraint) = 0;
const char** aOutBadConstraint)
{
MOZ_ASSERT(aOutHandle);
RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints, aOrigin,
aPrefs, aDeviceId);
nsresult rv = ReevaluateAllocation(handle, nullptr, aPrefs, aDeviceId,
aOutBadConstraint);
if (NS_FAILED(rv)) {
return rv;
}
mRegisteredHandles.AppendElement(handle);
handle.forget(aOutHandle);
return NS_OK;
}
virtual uint32_t GetBestFitnessDistance(
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
@ -293,8 +346,81 @@ protected:
#ifdef DEBUG
, mOwningThread(PR_GetCurrentThread())
#endif
, mInShutdown(false)
{}
/* UpdateSingleSource - Centralized abstract function to implement in those
* cases where a single device is being shared between users. Should apply net
* constraints and restart the device as needed.
*
* aHandle - New or existing handle, or null to update after removal.
* aNetConstraints - Net constraints to be applied to the single device.
* aPrefs - As passed in (in case of changes in about:config).
* aDeviceId - As passed in (origin dependent).
* aOutBadConstraint - Result: nonzero if failed to apply. Name of culprit.
*/
virtual nsresult
UpdateSingleSource(const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) {
return NS_ERROR_NOT_IMPLEMENTED;
};
/* ReevaluateAllocation - Call to change constraints for an allocation of
* a single device. Manages allocation handles, calculates net constraints
* from all competing allocations, and calls UpdateSingleSource with the net
* result, to restart the single device as needed.
*
* aHandle - New or existing handle, or null to update after removal.
* aConstraintsUpdate - Constraints to be applied to existing handle, or null.
* aPrefs - As passed in (in case of changes from about:config).
* aDeviceId - As passed in (origin-dependent id).
* aOutBadConstraint - Result: nonzero if failed to apply. Name of culprit.
*/
nsresult
ReevaluateAllocation(AllocationHandle* aHandle,
NormalizedConstraints* aConstraintsUpdate,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint)
{
// aHandle and/or aConstraintsUpdate may be nullptr (see below)
AutoTArray<const NormalizedConstraints*, 10> allConstraints;
for (auto& registered : mRegisteredHandles) {
if (aConstraintsUpdate && registered.get() == aHandle) {
continue; // Don't count old constraints
}
allConstraints.AppendElement(&registered->mConstraints);
}
if (aConstraintsUpdate) {
allConstraints.AppendElement(aConstraintsUpdate);
} else if (aHandle) {
// In the case of AddShareOfSingleSource, the handle isn't registered yet.
allConstraints.AppendElement(&aHandle->mConstraints);
}
NormalizedConstraints netConstraints(allConstraints);
if (netConstraints.mBadConstraint) {
*aOutBadConstraint = netConstraints.mBadConstraint;
return NS_ERROR_FAILURE;
}
nsresult rv = UpdateSingleSource(aHandle, netConstraints, aPrefs, aDeviceId,
aOutBadConstraint);
if (NS_FAILED(rv)) {
return rv;
}
if (aHandle && aConstraintsUpdate) {
aHandle->mConstraints = *aConstraintsUpdate;
}
return NS_OK;
}
void AssertIsOnOwningThread()
{
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
@ -304,6 +430,9 @@ protected:
#ifdef DEBUG
PRThread* mOwningThread;
#endif
nsTArray<RefPtr<AllocationHandle>> mRegisteredHandles;
bool mInShutdown;
// Main-thread only:
dom::MediaTrackSettings mSettings;
};

View File

@ -6,7 +6,6 @@
#define MediaEngineCameraVideoSource_h
#include "MediaEngine.h"
#include "MediaTrackConstraints.h"
#include "nsDirectoryServiceDefs.h"
@ -21,8 +20,7 @@ bool operator == (const webrtc::CaptureCapability& a,
bool operator != (const webrtc::CaptureCapability& a,
const webrtc::CaptureCapability& b);
class MediaEngineCameraVideoSource : public MediaEngineVideoSource,
protected MediaConstraintsHelper
class MediaEngineCameraVideoSource : public MediaEngineVideoSource
{
public:
// Some subclasses use an index to track multiple instances.
@ -34,7 +32,6 @@ public:
, mHeight(0)
, mInitDone(false)
, mHasDirectListeners(false)
, mNrAllocations(0)
, mCaptureIndex(aIndex)
, mTrackID(0)
{}
@ -117,7 +114,6 @@ protected:
bool mInitDone;
bool mHasDirectListeners;
int mNrAllocations; // When this becomes 0, we shut down HW
int mCaptureIndex;
TrackID mTrackID;

View File

@ -39,8 +39,6 @@ class MediaEngineDefaultVideoSource : public nsITimerCallback,
public:
MediaEngineDefaultVideoSource();
void Shutdown() override {};
void GetName(nsAString&) const override;
void GetUUID(nsACString&) const override;
@ -108,14 +106,11 @@ protected:
class SineWaveGenerator;
class MediaEngineDefaultAudioSource : public nsITimerCallback,
public MediaEngineAudioSource,
private MediaConstraintsHelper
public MediaEngineAudioSource
{
public:
MediaEngineDefaultAudioSource();
void Shutdown() override {};
void GetName(nsAString&) const override;
void GetUUID(nsACString&) const override;
@ -197,6 +192,7 @@ protected:
class MediaEngineDefault : public MediaEngine
{
typedef MediaEngine Super;
public:
explicit MediaEngineDefault() : mMutex("mozilla::MediaEngineDefault") {}
@ -212,9 +208,7 @@ public:
};
private:
~MediaEngineDefault() {
Shutdown();
}
~MediaEngineDefault() {}
Mutex mMutex;
// protected with mMutex:

View File

@ -32,8 +32,7 @@ MediaEngineRemoteVideoSource::MediaEngineRemoteVideoSource(
dom::MediaSourceEnum aMediaSource, const char* aMonitorName)
: MediaEngineCameraVideoSource(aIndex, aMonitorName),
mMediaSource(aMediaSource),
mCapEngine(aCapEngine),
mInShutdown(false)
mCapEngine(aCapEngine)
{
MOZ_ASSERT(aMediaSource != dom::MediaSourceEnum::Other);
mSettings.mWidth.Construct(0);
@ -72,7 +71,7 @@ MediaEngineRemoteVideoSource::Shutdown()
if (!mInitDone) {
return;
}
mInShutdown = true;
Super::Shutdown();
if (mState == kStarted) {
SourceMediaStream *source;
bool empty;
@ -119,10 +118,8 @@ MediaEngineRemoteVideoSource::Allocate(
return NS_ERROR_FAILURE;
}
RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints, aOrigin,
aPrefs, aDeviceId);
nsresult rv = UpdateNew(handle, aPrefs, aDeviceId, aOutBadConstraint);
nsresult rv = Super::Allocate(aConstraints, aPrefs, aDeviceId, aOrigin,
aOutHandle, aOutBadConstraint);
if (NS_FAILED(rv)) {
return rv;
}
@ -136,9 +133,6 @@ MediaEngineRemoteVideoSource::Allocate(
LOG(("Video device %d allocated shared", mCaptureIndex));
}
}
mRegisteredHandles.AppendElement(handle);
++mNrAllocations;
handle.forget(aOutHandle);
return NS_OK;
}
@ -147,24 +141,10 @@ MediaEngineRemoteVideoSource::Deallocate(AllocationHandle* aHandle)
{
LOG((__PRETTY_FUNCTION__));
AssertIsOnOwningThread();
MOZ_ASSERT(aHandle);
RefPtr<AllocationHandle> handle = aHandle;
class Comparator {
public:
static bool Equals(const RefPtr<AllocationHandle>& a,
const RefPtr<AllocationHandle>& b) {
return a.get() == b.get();
}
};
MOZ_ASSERT(mRegisteredHandles.Contains(handle, Comparator()));
mRegisteredHandles.RemoveElementAt(mRegisteredHandles.IndexOf(handle, 0,
Comparator()));
--mNrAllocations;
MOZ_ASSERT(mNrAllocations >= 0, "Double-deallocations are prohibited");
Super::Deallocate(aHandle);
if (mNrAllocations == 0) {
MOZ_ASSERT(!mRegisteredHandles.Length());
if (!mRegisteredHandles.Length()) {
if (mState != kStopped && mState != kAllocated) {
return NS_ERROR_FAILURE;
}
@ -175,13 +155,6 @@ MediaEngineRemoteVideoSource::Deallocate(AllocationHandle* aHandle)
LOG(("Video device %d deallocated", mCaptureIndex));
} else {
LOG(("Video device %d deallocated but still in use", mCaptureIndex));
MOZ_ASSERT(mRegisteredHandles.Length());
if (!mInShutdown) {
// Whenever constraints are removed, other parties may get closer to ideal.
auto& first = mRegisteredHandles[0];
const char* badConstraint = nullptr;
return UpdateRemove(first->mPrefs, first->mDeviceId, &badConstraint);
}
}
return NS_OK;
}
@ -280,48 +253,26 @@ MediaEngineRemoteVideoSource::Restart(AllocationHandle* aHandle,
}
MOZ_ASSERT(aHandle);
NormalizedConstraints constraints(aConstraints);
return UpdateExisting(aHandle, &constraints, aPrefs, aDeviceId, aOutBadConstraint);
return ReevaluateAllocation(aHandle, &constraints, aPrefs, aDeviceId,
aOutBadConstraint);
}
nsresult
MediaEngineRemoteVideoSource::UpdateExisting(AllocationHandle* aHandle,
NormalizedConstraints* aNewConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint)
MediaEngineRemoteVideoSource::UpdateSingleSource(
const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint)
{
// aHandle and/or aNewConstraints may be nullptr
AutoTArray<const NormalizedConstraints*, 10> allConstraints;
for (auto& registered : mRegisteredHandles) {
if (aNewConstraints && registered.get() == aHandle) {
continue; // Don't count old constraints
}
allConstraints.AppendElement(&registered->mConstraints);
}
if (aNewConstraints) {
allConstraints.AppendElement(aNewConstraints);
} else if (aHandle) {
// In the case of UpdateNew, the handle isn't registered yet.
allConstraints.AppendElement(&aHandle->mConstraints);
}
NormalizedConstraints netConstraints(allConstraints);
if (netConstraints.mBadConstraint) {
*aOutBadConstraint = netConstraints.mBadConstraint;
return NS_ERROR_FAILURE;
}
if (!ChooseCapability(netConstraints, aPrefs, aDeviceId)) {
*aOutBadConstraint = FindBadConstraint(netConstraints, *this, aDeviceId);
if (!ChooseCapability(aNetConstraints, aPrefs, aDeviceId)) {
*aOutBadConstraint = FindBadConstraint(aNetConstraints, *this, aDeviceId);
return NS_ERROR_FAILURE;
}
switch (mState) {
case kReleased:
MOZ_ASSERT(aHandle);
MOZ_ASSERT(!aNewConstraints);
MOZ_ASSERT(!mRegisteredHandles.Length());
if (camera::GetChildAndCall(&camera::CamerasChild::AllocateCaptureDevice,
mCapEngine, GetUUID().get(),
kMaxUniqueIdLength, mCaptureIndex,
@ -353,9 +304,6 @@ MediaEngineRemoteVideoSource::UpdateExisting(AllocationHandle* aHandle,
(aHandle? aHandle->mOrigin.get() : ""), mState));
break;
}
if (aHandle && aNewConstraints) {
aHandle->mConstraints = *aNewConstraints;
}
return NS_OK;
}

View File

@ -50,6 +50,7 @@ namespace mozilla {
class MediaEngineRemoteVideoSource : public MediaEngineCameraVideoSource,
public webrtc::ExternalRenderer
{
typedef MediaEngineCameraVideoSource Super;
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -103,7 +104,7 @@ public:
void Shutdown() override;
protected:
~MediaEngineRemoteVideoSource() { Shutdown(); }
~MediaEngineRemoteVideoSource() { }
private:
// Initialize the needed Video engine interfaces.
@ -112,46 +113,18 @@ private:
void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) const override;
void SetLastCapability(const webrtc::CaptureCapability& aCapability);
/* UpdateExisting - Centralized function to apply constraints and restart
* device as needed, considering all allocations and changes to one.
*
* aHandle - New or existing handle, or null to update after removal.
* aNewConstraints - Constraints to be applied to existing handle, or null.
* aPrefs - As passed in (in case of changes in about:config).
* aDeviceId - As passed in (origin dependent).
* aOutBadConstraint - Result: nonzero if failed to apply. Name of culprit.
*/
nsresult
UpdateExisting(AllocationHandle* aHandle,
NormalizedConstraints* aNewConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint);
nsresult
UpdateNew(AllocationHandle* aHandle,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) {
return UpdateExisting(aHandle, nullptr, aPrefs, aDeviceId, aOutBadConstraint);
}
nsresult
UpdateRemove(const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) {
return UpdateExisting(nullptr, nullptr, aPrefs, aDeviceId, aOutBadConstraint);
}
UpdateSingleSource(const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) override;
dom::MediaSourceEnum mMediaSource; // source of media (camera | application | screen)
mozilla::camera::CaptureEngine mCapEngine;
nsTArray<RefPtr<AllocationHandle>> mRegisteredHandles;
// To only restart camera when needed, we keep track previous settings.
webrtc::CaptureCapability mLastCapability;
bool mInShutdown;
};
}

View File

@ -19,7 +19,6 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList
NS_DECL_NSITIMERCALLBACK
MediaEngineTabVideoSource();
void Shutdown() override {};
void GetName(nsAString_internal&) const override;
void GetUUID(nsACString_internal&) const override;
nsresult Allocate(const dom::MediaTrackConstraints &,

View File

@ -91,10 +91,6 @@ public:
MOZ_ASSERT(!aHandle);
return NS_OK;
}
void Shutdown() override
{
// Nothing to do here, everything is managed in MediaManager.cpp
}
nsresult Start(SourceMediaStream* aMediaStream,
TrackID aId,
const PrincipalHandle& aPrincipalHandle) override;
@ -139,7 +135,7 @@ public:
const nsString& aDeviceId) const override;
protected:
virtual ~MediaEngineWebRTCAudioCaptureSource() { Shutdown(); }
virtual ~MediaEngineWebRTCAudioCaptureSource() {}
nsCString mUUID;
};
@ -419,9 +415,9 @@ private:
};
class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource,
public webrtc::VoEMediaProcess,
private MediaConstraintsHelper
public webrtc::VoEMediaProcess
{
typedef MediaEngineAudioSource Super;
public:
MediaEngineWebRTCMicrophoneSource(nsIThread* aThread,
webrtc::VoiceEngine* aVoiceEnginePtr,
@ -515,9 +511,7 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
protected:
~MediaEngineWebRTCMicrophoneSource() {
Shutdown();
}
~MediaEngineWebRTCMicrophoneSource() {}
private:
// These allocate/configure and release the channel
@ -591,6 +585,7 @@ private:
class MediaEngineWebRTC : public MediaEngine
{
typedef MediaEngine Super;
public:
explicit MediaEngineWebRTC(MediaEnginePrefs& aPrefs);
@ -607,7 +602,6 @@ public:
nsTArray<RefPtr<MediaEngineAudioSource>>*) override;
private:
~MediaEngineWebRTC() {
Shutdown();
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
AsyncLatencyLogger::Get()->Release();
#endif

View File

@ -714,6 +714,7 @@ MediaEngineWebRTCMicrophoneSource::FreeChannel()
void
MediaEngineWebRTCMicrophoneSource::Shutdown()
{
Super::Shutdown();
if (mListener) {
// breaks a cycle, since the WebRTCAudioDataListener has a RefPtr to us
mListener->Shutdown();