Bug 1434600 - Add a method to clean up by window ID, on a MediaEngine. r=pehrsons

MozReview-Commit-ID: 12w4StZE2eg

--HG--
extra : rebase_source : 3c3ddf24da24e42e53d9e5352cb83945c97ead99
This commit is contained in:
Paul Adenot 2018-01-31 19:02:00 +01:00
parent 4bf54def7a
commit 8413544b59
5 changed files with 130 additions and 33 deletions

View File

@ -48,6 +48,7 @@ public:
dom::MediaSourceEnum, dom::MediaSourceEnum,
nsTArray<RefPtr<MediaEngineSource>>*) = 0; nsTArray<RefPtr<MediaEngineSource>>*) = 0;
virtual void ReleaseResourcesForWindow(uint64_t aWindowId) = 0;
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual void SetFakeDeviceChangeEvents() {} virtual void SetFakeDeviceChangeEvents() {}

View File

@ -561,13 +561,18 @@ MediaEngineDefault::EnumerateDevices(uint64_t aWindowId,
// We once had code here to find a VideoSource with the same settings and // We once had code here to find a VideoSource with the same settings and
// re-use that. This is no longer possible since the resolution gets set // re-use that. This is no longer possible since the resolution gets set
// in Allocate(). // in Allocate().
nsTArray<RefPtr<MediaEngineSource>>*
devicesForThisWindow = mVSources.LookupOrAdd(aWindowId);
auto newSource = MakeRefPtr<MediaEngineDefaultVideoSource>(); auto newSource = MakeRefPtr<MediaEngineDefaultVideoSource>();
mVSources.AppendElement(newSource); devicesForThisWindow->AppendElement(newSource);
aSources->AppendElement(newSource); aSources->AppendElement(newSource);
return; return;
} }
case dom::MediaSourceEnum::Microphone: { case dom::MediaSourceEnum::Microphone: {
for (const RefPtr<MediaEngineDefaultAudioSource>& source : mASources) { nsTArray<RefPtr<MediaEngineDefaultAudioSource>>*
devicesForThisWindow = mASources.LookupOrAdd(aWindowId);
for (const RefPtr<MediaEngineDefaultAudioSource>& source : *devicesForThisWindow) {
if (source->IsAvailable()) { if (source->IsAvailable()) {
aSources->AppendElement(source); aSources->AppendElement(source);
} }
@ -576,7 +581,7 @@ MediaEngineDefault::EnumerateDevices(uint64_t aWindowId,
if (aSources->IsEmpty()) { if (aSources->IsEmpty()) {
// All streams are currently busy, just make a new one. // All streams are currently busy, just make a new one.
auto newSource = MakeRefPtr<MediaEngineDefaultAudioSource>(); auto newSource = MakeRefPtr<MediaEngineDefaultAudioSource>();
mASources.AppendElement(newSource); devicesForThisWindow->AppendElement(newSource);
aSources->AppendElement(newSource); aSources->AppendElement(newSource);
} }
return; return;
@ -587,16 +592,52 @@ MediaEngineDefault::EnumerateDevices(uint64_t aWindowId,
} }
} }
void
MediaEngineDefault::ReleaseResourcesForWindow(uint64_t aWindowId)
{
nsTArray<RefPtr<MediaEngineDefaultAudioSource>>* audioDevicesForThisWindow =
mASources.Get(aWindowId);
if (audioDevicesForThisWindow) {
for (const RefPtr<MediaEngineDefaultAudioSource>& source :
*audioDevicesForThisWindow) {
source->Shutdown();
}
}
mASources.Remove(aWindowId);
nsTArray<RefPtr<MediaEngineSource>>* videoDevicesForThisWindow =
mVSources.Get(aWindowId);
if (videoDevicesForThisWindow) {
for (const RefPtr<MediaEngineSource>& source :
*videoDevicesForThisWindow) {
source->Shutdown();
}
}
mVSources.Remove(aWindowId);
}
void void
MediaEngineDefault::Shutdown() MediaEngineDefault::Shutdown()
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
for (RefPtr<MediaEngineDefaultVideoSource>& source : mVSources) { for (auto iter = mVSources.Iter(); !iter.Done(); iter.Next()) {
source->Shutdown(); for (const RefPtr<MediaEngineSource>& source : *iter.UserData()) {
if (source) {
source->Shutdown();
}
}
} }
for (RefPtr<MediaEngineDefaultAudioSource>& source : mASources) { for (auto iter = mASources.Iter(); !iter.Done(); iter.Next()) {
source->Shutdown(); for (const RefPtr<MediaEngineDefaultAudioSource>& source : *iter.UserData()) {
if (source) {
source->Shutdown();
}
}
} }
mVSources.Clear(); mVSources.Clear();
mASources.Clear(); mASources.Clear();

View File

@ -191,12 +191,16 @@ public:
dom::MediaSourceEnum, dom::MediaSourceEnum,
nsTArray<RefPtr<MediaEngineSource>>*) override; nsTArray<RefPtr<MediaEngineSource>>*) override;
void Shutdown() override; void Shutdown() override;
void ReleaseResourcesForWindow(uint64_t aWindowId) override;
private: private:
~MediaEngineDefault() = default; ~MediaEngineDefault() = default;
nsTArray<RefPtr<MediaEngineDefaultVideoSource>> mVSources; // WindowID -> Array of devices.
nsTArray<RefPtr<MediaEngineDefaultAudioSource>> mASources; nsClassHashtable<nsUint64HashKey,
nsTArray<RefPtr<MediaEngineSource>>> mVSources;
nsClassHashtable<nsUint64HashKey,
nsTArray<RefPtr<MediaEngineDefaultAudioSource>>> mASources;
}; };
} // namespace mozilla } // namespace mozilla

View File

@ -238,15 +238,20 @@ MediaEngineWebRTC::EnumerateDevices(uint64_t aWindowId,
} }
NS_ConvertUTF8toUTF16 uuid(uniqueId); NS_ConvertUTF8toUTF16 uuid(uniqueId);
RefPtr<MediaEngineSource> vSource = mVideoSources.Get(uuid); RefPtr<MediaEngineSource> vSource;
if (vSource && vSource->RequiresSharing()) {
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource>*
devicesForThisWindow = mVideoSources.LookupOrAdd(aWindowId);
if (devicesForThisWindow->Get(uuid, getter_AddRefs(vSource)) &&
vSource->RequiresSharing()) {
// We've already seen this shared device, just refresh and append. // We've already seen this shared device, just refresh and append.
static_cast<MediaEngineRemoteVideoSource*>(vSource.get())->Refresh(i); static_cast<MediaEngineRemoteVideoSource*>(vSource.get())->Refresh(i);
aSources->AppendElement(vSource.get()); aSources->AppendElement(vSource.get());
} else { } else {
vSource = new MediaEngineRemoteVideoSource(i, capEngine, aMediaSource, vSource = new MediaEngineRemoteVideoSource(i, capEngine, aMediaSource,
scaryKind || scarySource); scaryKind || scarySource);
mVideoSources.Put(uuid, vSource); devicesForThisWindow->Put(uuid, vSource);
aSources->AppendElement(vSource); aSources->AppendElement(vSource);
} }
} }
@ -300,9 +305,15 @@ MediaEngineWebRTC::EnumerateDevices(uint64_t aWindowId,
strcpy(uniqueId, deviceName); // safe given assert and initialization/error-check strcpy(uniqueId, deviceName); // safe given assert and initialization/error-check
} }
RefPtr<MediaEngineSource> aSource;
NS_ConvertUTF8toUTF16 uuid(uniqueId); NS_ConvertUTF8toUTF16 uuid(uniqueId);
RefPtr<MediaEngineSource> aSource = mAudioSources.Get(uuid);
if (aSource && aSource->RequiresSharing()) { nsRefPtrHashtable<nsStringHashKey, MediaEngineSource>*
devicesForThisWindow = mAudioSources.LookupOrAdd(aWindowId);
if (devicesForThisWindow->Get(uuid, getter_AddRefs(aSource)) &&
aSource->RequiresSharing()) {
// We've already seen this device, just append. // We've already seen this device, just append.
aSources->AppendElement(aSource.get()); aSources->AppendElement(aSource.get());
} else { } else {
@ -310,7 +321,7 @@ MediaEngineWebRTC::EnumerateDevices(uint64_t aWindowId,
new mozilla::AudioInputCubeb(i), new mozilla::AudioInputCubeb(i),
i, deviceName, uniqueId, i, deviceName, uniqueId,
mDelayAgnostic, mExtendedFilter); mDelayAgnostic, mExtendedFilter);
mAudioSources.Put(uuid, aSource); // Hashtable takes ownership. devicesForThisWindow->Put(uuid, aSource);
aSources->AppendElement(aSource); aSources->AppendElement(aSource);
} }
} }
@ -323,6 +334,53 @@ MediaEngineWebRTC::SupportsDuplex()
return mFullDuplex; return mFullDuplex;
} }
void
MediaEngineWebRTC::ReleaseResourcesForWindow(uint64_t aWindowId)
{
{
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource>*
audioDevicesForThisWindow = mAudioSources.Get(aWindowId);
if (audioDevicesForThisWindow) {
for (auto iter = audioDevicesForThisWindow->Iter(); !iter.Done();
iter.Next()) {
iter.UserData()->Shutdown();
}
// This makes audioDevicesForThisWindow invalid.
mAudioSources.Remove(aWindowId);
}
}
{
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource>*
videoDevicesForThisWindow = mVideoSources.Get(aWindowId);
if (videoDevicesForThisWindow) {
for (auto iter = videoDevicesForThisWindow->Iter(); !iter.Done();
iter.Next()) {
iter.UserData()->Shutdown();
}
// This makes videoDevicesForThisWindow invalid.
mVideoSources.Remove(aWindowId);
}
}
}
namespace {
template<typename T>
void ShutdownSources(T& aHashTable)
{
for (auto iter = aHashTable.Iter(); !iter.Done(); iter.Next()) {
for (auto iterInner = iter.UserData()->Iter(); !iterInner.Done();
iterInner.Next()) {
MediaEngineSource* source = iterInner.UserData();
source->Shutdown();
}
}
}
}
void void
MediaEngineWebRTC::Shutdown() MediaEngineWebRTC::Shutdown()
{ {
@ -337,20 +395,8 @@ MediaEngineWebRTC::Shutdown()
LOG(("%s", __FUNCTION__)); LOG(("%s", __FUNCTION__));
// Shutdown all the sources, since we may have dangling references to the // Shutdown all the sources, since we may have dangling references to the
// sources in nsDOMUserMediaStreams waiting for GC/CC // sources in nsDOMUserMediaStreams waiting for GC/CC
for (auto iter = mVideoSources.Iter(); !iter.Done(); iter.Next()) { ShutdownSources(mVideoSources);
MediaEngineSource* source = iter.UserData(); ShutdownSources(mAudioSources);
if (source) {
source->Shutdown();
}
}
for (auto iter = mAudioSources.Iter(); !iter.Done(); iter.Next()) {
MediaEngineSource* source = iter.UserData();
if (source) {
source->Shutdown();
}
}
mVideoSources.Clear();
mAudioSources.Clear();
mozilla::camera::Shutdown(); mozilla::camera::Shutdown();
AudioInputCubeb::CleanupGlobalData(); AudioInputCubeb::CleanupGlobalData();

View File

@ -621,6 +621,7 @@ public:
void EnumerateDevices(uint64_t aWindowId, void EnumerateDevices(uint64_t aWindowId,
dom::MediaSourceEnum, dom::MediaSourceEnum,
nsTArray<RefPtr<MediaEngineSource>>*) override; nsTArray<RefPtr<MediaEngineSource>>*) override;
void ReleaseResourcesForWindow(uint64_t aWindowId) override;
private: private:
~MediaEngineWebRTC() = default; ~MediaEngineWebRTC() = default;
@ -634,10 +635,14 @@ private:
bool mExtendedFilter; bool mExtendedFilter;
bool mHasTabVideoSource; bool mHasTabVideoSource;
// Store devices we've already seen in a hashtable for quick return. // Maps WindowID to a map of device uuid to their MediaEngineSource,
// Maps UUID to MediaEngineSource (one set for audio, one for video). // separately for audio and video.
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource> mVideoSources; nsClassHashtable<nsUint64HashKey,
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource> mAudioSources; nsRefPtrHashtable<nsStringHashKey,
MediaEngineSource>> mVideoSources;
nsClassHashtable<nsUint64HashKey,
nsRefPtrHashtable<nsStringHashKey,
MediaEngineSource>> mAudioSources;
}; };
} }