Bug 1213453 - Add getters/setters for group id in MediaEngineSource and the derived classes. r=pehrsons
authorAlex Chronopoulos <achronop@gmail.com>
Fri, 08 Mar 2019 11:51:59 +0000
changeset 521023 7e561fa634f7
parent 521022 19934e7183f7
child 521024 1cac58480c6a
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspehrsons
bugs1213453
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1213453 - Add getters/setters for group id in MediaEngineSource and the derived classes. r=pehrsons Differential Revision: https://phabricator.services.mozilla.com/D20370
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
dom/media/webrtc/MediaEngineRemoteVideoSource.h
dom/media/webrtc/MediaEngineSource.h
dom/media/webrtc/MediaEngineTabVideoSource.cpp
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.cpp
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
dom/media/webrtc/MediaEngineWebRTCAudio.h
dom/media/webrtc/MediaTrackConstraints.cpp
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -44,16 +44,20 @@ MediaEngineDefaultVideoSource::~MediaEng
 nsString MediaEngineDefaultVideoSource::GetName() const {
   return NS_LITERAL_STRING(u"Default Video Device");
 }
 
 nsCString MediaEngineDefaultVideoSource::GetUUID() const {
   return NS_LITERAL_CSTRING("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676");
 }
 
+nsString MediaEngineDefaultVideoSource::GetGroupId() const {
+  return NS_LITERAL_STRING(u"Default Video Group");
+}
+
 uint32_t MediaEngineDefaultVideoSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
     const nsString& aDeviceId) const {
   AssertIsOnOwningThread();
 
   uint32_t distance = 0;
 #ifdef MOZ_WEBRTC
   for (const auto* cs : aConstraintSets) {
@@ -357,16 +361,20 @@ MediaEngineDefaultAudioSource::~MediaEng
 nsString MediaEngineDefaultAudioSource::GetName() const {
   return NS_LITERAL_STRING(u"Default Audio Device");
 }
 
 nsCString MediaEngineDefaultAudioSource::GetUUID() const {
   return NS_LITERAL_CSTRING("B7CBD7C1-53EF-42F9-8353-73F61C70C092");
 }
 
+nsString MediaEngineDefaultAudioSource::GetGroupId() const {
+  return NS_LITERAL_STRING(u"Default Audio Group");
+}
+
 uint32_t MediaEngineDefaultAudioSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
     const nsString& aDeviceId) const {
   uint32_t distance = 0;
 #ifdef MOZ_WEBRTC
   for (const auto* cs : aConstraintSets) {
     distance =
         MediaConstraintsHelper::GetMinimumFitnessDistance(*cs, aDeviceId);
@@ -548,40 +556,40 @@ void MediaEngineDefault::EnumerateDevice
 
       nsTArray<RefPtr<MediaEngineSource>>* devicesForThisWindow =
           mVSources.LookupOrAdd(aWindowId);
       auto newSource = MakeRefPtr<MediaEngineDefaultVideoSource>();
       devicesForThisWindow->AppendElement(newSource);
       aDevices->AppendElement(MakeRefPtr<MediaDevice>(
           newSource, newSource->GetName(),
           NS_ConvertUTF8toUTF16(newSource->GetUUID()),
-          NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+          newSource->GetGroupId(), NS_LITERAL_STRING("")));
       return;
     }
     case dom::MediaSourceEnum::Microphone: {
       nsTArray<RefPtr<MediaEngineDefaultAudioSource>>* devicesForThisWindow =
           mASources.LookupOrAdd(aWindowId);
       for (const RefPtr<MediaEngineDefaultAudioSource>& source :
            *devicesForThisWindow) {
         if (source->IsAvailable()) {
           aDevices->AppendElement(MakeRefPtr<MediaDevice>(
               source, source->GetName(),
               NS_ConvertUTF8toUTF16(source->GetUUID()),
-              NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+              source->GetGroupId(), NS_LITERAL_STRING("")));
         }
       }
 
       if (aDevices->IsEmpty()) {
         // All streams are currently busy, just make a new one.
         auto newSource = MakeRefPtr<MediaEngineDefaultAudioSource>();
         devicesForThisWindow->AppendElement(newSource);
         aDevices->AppendElement(MakeRefPtr<MediaDevice>(
             newSource, newSource->GetName(),
             NS_ConvertUTF8toUTF16(newSource->GetUUID()),
-            NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+            newSource->GetGroupId(), NS_LITERAL_STRING("")));
       }
       return;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unsupported source type");
       return;
   }
 
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -36,16 +36,17 @@ class MediaEngineDefault;
  * The default implementation of the MediaEngine interface.
  */
 class MediaEngineDefaultVideoSource : public MediaEngineSource {
  public:
   MediaEngineDefaultVideoSource();
 
   nsString GetName() const override;
   nsCString GetUUID() const override;
+  nsString GetGroupId() const override;
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs, const nsString& aDeviceId,
                     const ipc::PrincipalInfo& aPrincipalInfo,
                     AllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
   void SetTrack(const RefPtr<const AllocationHandle>& aHandle,
                 const RefPtr<SourceMediaStream>& aStream, TrackID aTrackID,
@@ -103,16 +104,17 @@ class MediaEngineDefaultVideoSource : pu
 class SineWaveGenerator;
 
 class MediaEngineDefaultAudioSource : public MediaEngineSource {
  public:
   MediaEngineDefaultAudioSource();
 
   nsString GetName() const override;
   nsCString GetUUID() const override;
+  nsString GetGroupId() const override;
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs, const nsString& aDeviceId,
                     const ipc::PrincipalInfo& aPrincipalInfo,
                     AllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
   void SetTrack(const RefPtr<const AllocationHandle>& aHandle,
                 const RefPtr<SourceMediaStream>& aStream, TrackID aTrackID,
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -81,16 +81,17 @@ void MediaEngineRemoteVideoSource::Init(
                               kMaxDeviceNameLength, uniqueId,
                               kMaxUniqueIdLength, nullptr)) {
     LOG("Error initializing RemoteVideoSource (GetCaptureDevice)");
     return;
   }
 
   SetName(NS_ConvertUTF8toUTF16(deviceName));
   SetUUID(uniqueId);
+  SetGroupId(NS_ConvertUTF8toUTF16(deviceName));
 
   mInitDone = true;
 }
 
 void MediaEngineRemoteVideoSource::Shutdown() {
   LOG(__PRETTY_FUNCTION__);
   AssertIsOnOwningThread();
 
@@ -175,16 +176,28 @@ void MediaEngineRemoteVideoSource::SetUU
 }
 
 nsCString MediaEngineRemoteVideoSource::GetUUID() const {
   AssertIsOnOwningThread();
 
   return mUniqueId;
 }
 
+void MediaEngineRemoteVideoSource::SetGroupId(nsString aGroupId) {
+  AssertIsOnOwningThread();
+
+  mGroupId = std::move(aGroupId);
+}
+
+nsString MediaEngineRemoteVideoSource::GetGroupId() const {
+  AssertIsOnOwningThread();
+
+  return mGroupId;
+}
+
 nsresult MediaEngineRemoteVideoSource::Allocate(
     const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
     const nsString& aDeviceId,
     const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
     AllocationHandle** aOutHandle, const char** aOutBadConstraint) {
   LOG(__PRETTY_FUNCTION__);
   AssertIsOnOwningThread();
 
@@ -987,11 +1000,12 @@ void MediaEngineRemoteVideoSource::Refre
                               mCapEngine, aIndex, deviceName,
                               sizeof(deviceName), uniqueId, sizeof(uniqueId),
                               nullptr)) {
     return;
   }
 
   SetName(NS_ConvertUTF8toUTF16(deviceName));
   MOZ_ASSERT(mUniqueId.Equals(uniqueId));
+  SetGroupId(NS_ConvertUTF8toUTF16(deviceName));
 }
 
 }  // namespace mozilla
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -148,16 +148,19 @@ class MediaEngineRemoteVideoSource : pub
   void Shutdown() override;
 
   nsString GetName() const override;
   void SetName(nsString aName);
 
   nsCString GetUUID() const override;
   void SetUUID(const char* aUUID);
 
+  nsString GetGroupId() const override;
+  void SetGroupId(nsString aGroupId);
+
   bool GetScary() const override { return mScary; }
 
   RefPtr<GenericNonExclusivePromise> GetFirstFramePromise() const override {
     return mFirstFramePromise;
   }
 
  private:
   // Initialize the needed Video engine interfaces.
@@ -245,16 +248,17 @@ class MediaEngineRemoteVideoSource : pub
    *
    * This is mutable so that the const method NumCapabilities() can reset it.
    * Owning thread only.
    */
   mutable nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities;
 
   nsString mDeviceName;
   nsCString mUniqueId;
+  nsString mGroupId;
   nsString mFacingMode;
 
   // Whether init has successfully completed.
   // Set in Init(), reset in Shutdown().
   // Owning thread only.
   bool mInitDone = false;
 };
 
--- a/dom/media/webrtc/MediaEngineSource.h
+++ b/dom/media/webrtc/MediaEngineSource.h
@@ -100,16 +100,21 @@ class MediaEngineSourceInterface {
   virtual nsString GetName() const = 0;
 
   /**
    * Gets the UUID of this device.
    */
   virtual nsCString GetUUID() const = 0;
 
   /**
+   * Gets the Group id of this device.
+   */
+  virtual nsString GetGroupId() const = 0;
+
+  /**
    * Get the enum describing the underlying type of MediaSource.
    */
   virtual dom::MediaSourceEnum GetMediaSource() const = 0;
 
   /**
    * Override w/true if source does end-run around cross origin restrictions.
    */
   virtual bool GetScary() const = 0;
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -110,16 +110,20 @@ nsresult MediaEngineTabVideoSource::Dest
 nsString MediaEngineTabVideoSource::GetName() const {
   return NS_LITERAL_STRING(u"&getUserMedia.videoSource.tabShare;");
 }
 
 nsCString MediaEngineTabVideoSource::GetUUID() const {
   return NS_LITERAL_CSTRING("tab");
 }
 
+nsString MediaEngineTabVideoSource::GetGroupId() const {
+  return NS_LITERAL_STRING(u"&getUserMedia.videoSource.tabShareGroup;");
+}
+
 #define DEFAULT_TABSHARE_VIDEO_MAX_WIDTH 4096
 #define DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT 4096
 #define DEFAULT_TABSHARE_VIDEO_FRAMERATE 30
 
 nsresult MediaEngineTabVideoSource::Allocate(
     const dom::MediaTrackConstraints& aConstraints,
     const MediaEnginePrefs& aPrefs, const nsString& aDeviceId,
     const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -16,16 +16,17 @@ class ImageContainer;
 }
 
 class MediaEngineTabVideoSource : public MediaEngineSource {
  public:
   MediaEngineTabVideoSource();
 
   nsString GetName() const override;
   nsCString GetUUID() const override;
+  nsString GetGroupId() const override;
 
   bool GetScary() const override { return true; }
 
   dom::MediaSourceEnum GetMediaSource() const override {
     return dom::MediaSourceEnum::Browser;
   }
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -139,25 +139,25 @@ void MediaEngineWebRTC::EnumerateVideoDe
       static_cast<MediaEngineRemoteVideoSource*>(vSource.get())->Refresh(i);
     } else {
       vSource = new MediaEngineRemoteVideoSource(i, aCapEngine,
                                                  scaryKind || scarySource);
       devicesForThisWindow->Put(uuid, vSource);
     }
     aDevices->AppendElement(MakeRefPtr<MediaDevice>(
         vSource, vSource->GetName(), NS_ConvertUTF8toUTF16(vSource->GetUUID()),
-        NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+        vSource->GetGroupId(), NS_LITERAL_STRING("")));
   }
 
   if (mHasTabVideoSource || aCapEngine == camera::BrowserEngine) {
     RefPtr<MediaEngineSource> tabVideoSource = new MediaEngineTabVideoSource();
     aDevices->AppendElement(MakeRefPtr<MediaDevice>(
         tabVideoSource, tabVideoSource->GetName(),
         NS_ConvertUTF8toUTF16(tabVideoSource->GetUUID()),
-        NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+        tabVideoSource->GetGroupId(), NS_LITERAL_STRING("")));
   }
 }
 
 void MediaEngineWebRTC::EnumerateMicrophoneDevices(
     uint64_t aWindowId, nsTArray<RefPtr<MediaDevice>>* aDevices) {
   mMutex.AssertCurrentThreadOwns();
 
   mEnumerator = CubebDeviceEnumerator::GetInstance();
@@ -176,21 +176,21 @@ void MediaEngineWebRTC::EnumerateMicroph
          NS_ConvertUTF16toUTF8(devices[i]->Name()).get(),
          devices[i]->DeviceID()));
 
     if (devices[i]->State() == CUBEB_DEVICE_STATE_ENABLED) {
       MOZ_ASSERT(devices[i]->Type() == CUBEB_DEVICE_TYPE_INPUT);
       RefPtr<MediaEngineSource> source = new MediaEngineWebRTCMicrophoneSource(
           devices[i], devices[i]->Name(),
           // Lie and provide the name as UUID
-          NS_ConvertUTF16toUTF8(devices[i]->Name()), devices[i]->MaxChannels(),
-          mDelayAgnostic, mExtendedFilter);
+          NS_ConvertUTF16toUTF8(devices[i]->Name()), devices[i]->GroupID(),
+          devices[i]->MaxChannels(), mDelayAgnostic, mExtendedFilter);
       RefPtr<MediaDevice> device = MakeRefPtr<MediaDevice>(
           source, source->GetName(), NS_ConvertUTF8toUTF16(source->GetUUID()),
-          NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING(""));
+          source->GetGroupId(), NS_LITERAL_STRING(""));
       if (devices[i]->Preferred()) {
 #ifdef DEBUG
         if (!foundPreferredDevice) {
           foundPreferredDevice = true;
         } else {
           MOZ_ASSERT(!foundPreferredDevice,
                      "Found more than one preferred audio input device"
                      "while enumerating");
@@ -259,17 +259,17 @@ void MediaEngineWebRTC::EnumerateDevices
         break;
     }
   } else if (aMediaSource == dom::MediaSourceEnum::AudioCapture) {
     RefPtr<MediaEngineWebRTCAudioCaptureSource> audioCaptureSource =
         new MediaEngineWebRTCAudioCaptureSource(nullptr);
     aDevices->AppendElement(MakeRefPtr<MediaDevice>(
         audioCaptureSource, audioCaptureSource->GetName(),
         NS_ConvertUTF8toUTF16(audioCaptureSource->GetUUID()),
-        NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+        audioCaptureSource->GetGroupId(), NS_LITERAL_STRING("")));
   } else if (aMediaSource == dom::MediaSourceEnum::Microphone) {
     MOZ_ASSERT(aMediaSource == dom::MediaSourceEnum::Microphone);
     EnumerateMicrophoneDevices(aWindowId, aDevices);
   }
 
   if (aMediaSink == MediaSinkEnum::Speaker) {
     EnumerateSpeakerDevices(aWindowId, aDevices);
   }
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -41,25 +41,26 @@ extern LazyLogModule gMediaManagerLog;
 #define LOG_ERROR(...) MOZ_LOG(gMediaManagerLog, LogLevel::Error, (__VA_ARGS__))
 
 /**
  * WebRTC Microphone MediaEngineSource.
  */
 
 MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
     RefPtr<AudioDeviceInfo> aInfo, const nsString& aDeviceName,
-    const nsCString& aDeviceUUID, uint32_t aMaxChannelCount,
-    bool aDelayAgnostic, bool aExtendedFilter)
+    const nsCString& aDeviceUUID, const nsString& aDeviceGroup,
+    uint32_t aMaxChannelCount, bool aDelayAgnostic, bool aExtendedFilter)
     : mTrackID(TRACK_NONE),
       mPrincipal(PRINCIPAL_HANDLE_NONE),
       mDeviceInfo(std::move(aInfo)),
       mDelayAgnostic(aDelayAgnostic),
       mExtendedFilter(aExtendedFilter),
       mDeviceName(aDeviceName),
       mDeviceUUID(aDeviceUUID),
+      mDeviceGroup(aDeviceGroup),
       mDeviceMaxChannelCount(aMaxChannelCount),
       mSettings(new nsMainThreadPtrHolder<
                 media::Refcountable<dom::MediaTrackSettings>>(
           "MediaEngineWebRTCMicrophoneSource::mSettings",
           new media::Refcountable<dom::MediaTrackSettings>(),
           // Non-strict means it won't assert main thread for us.
           // It would be great if it did but we're already on the media thread.
           /* aStrict = */ false)) {
@@ -79,16 +80,20 @@ MediaEngineWebRTCMicrophoneSource::Media
 nsString MediaEngineWebRTCMicrophoneSource::GetName() const {
   return mDeviceName;
 }
 
 nsCString MediaEngineWebRTCMicrophoneSource::GetUUID() const {
   return mDeviceUUID;
 }
 
+nsString MediaEngineWebRTCMicrophoneSource::GetGroupId() const {
+  return mDeviceGroup;
+}
+
 // GetBestFitnessDistance returns the best distance the capture device can offer
 // as a whole, given an accumulated number of ConstraintSets.
 // Ideal values are considered in the first ConstraintSet only.
 // Plain values are treated as Ideal in the first ConstraintSet.
 // Plain values are treated as Exact in subsequent ConstraintSets.
 // Infinity = UINT32_MAX e.g. device cannot satisfy accumulated ConstraintSets.
 // A finite result may be used to calculate this device's ranking as a choice.
 
@@ -1158,16 +1163,20 @@ nsCString MediaEngineWebRTCAudioCaptureS
 
   uuid.ToProvidedString(uuidBuffer);
   asciiString.AssignASCII(uuidBuffer);
 
   // Remove {} and the null terminator
   return nsCString(Substring(asciiString, 1, NSID_LENGTH - 3));
 }
 
+nsString MediaEngineWebRTCAudioCaptureSource::GetGroupId() const {
+  return NS_LITERAL_STRING(u"AudioCaptureGroup");
+}
+
 void MediaEngineWebRTCAudioCaptureSource::SetTrack(
     const RefPtr<const AllocationHandle>&,
     const RefPtr<SourceMediaStream>& aStream, TrackID aTrackID,
     const PrincipalHandle& aPrincipalHandle) {
   AssertIsOnOwningThread();
   // Nothing to do here. aStream is a placeholder dummy and not exposed.
 }
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.h
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.h
@@ -23,24 +23,25 @@ class AudioInputProcessing;
 //   the main thread and then the MSG thread so that it can be used as part of
 //   the graph processing. On destruction, similarly, a message is sent to the
 //   graph so that it stops using it, and then it is deleted.
 // - mSettings is created on the MediaManager thread is always ever accessed on
 //   the Main Thread. It is const.
 class MediaEngineWebRTCMicrophoneSource : public MediaEngineSource {
  public:
   MediaEngineWebRTCMicrophoneSource(RefPtr<AudioDeviceInfo> aInfo,
-                                    const nsString& name, const nsCString& uuid,
-                                    uint32_t maxChannelCount,
+                                    const nsString& aName, const nsCString& aUuid,
+                                    const nsString& aGroupId, uint32_t aMaxChannelCount,
                                     bool aDelayAgnostic, bool aExtendedFilter);
 
   bool RequiresSharing() const override { return false; }
 
   nsString GetName() const override;
   nsCString GetUUID() const override;
+  nsString GetGroupId() const override;
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs, const nsString& aDeviceId,
                     const ipc::PrincipalInfo& aPrincipalInfo,
                     AllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
   nsresult Deallocate(const RefPtr<const AllocationHandle>& aHandle) override;
   void SetTrack(const RefPtr<const AllocationHandle>& aHandle,
@@ -112,16 +113,17 @@ class MediaEngineWebRTCMicrophoneSource 
   TrackID mTrackID = TRACK_NONE;
   PrincipalHandle mPrincipal = PRINCIPAL_HANDLE_NONE;
 
   const RefPtr<AudioDeviceInfo> mDeviceInfo;
   const bool mDelayAgnostic;
   const bool mExtendedFilter;
   const nsString mDeviceName;
   const nsCString mDeviceUUID;
+  const nsString mDeviceGroup;
 
   // The maximum number of channels that this device supports.
   const uint32_t mDeviceMaxChannelCount;
   // The current settings for the underlying device.
   // Constructed on the MediaManager thread, and then only ever accessed on the
   // main thread.
   const nsMainThreadPtrHandle<media::Refcountable<dom::MediaTrackSettings>>
       mSettings;
@@ -250,16 +252,17 @@ class AudioInputProcessing : public Audi
   bool mEnded;
 };
 
 class MediaEngineWebRTCAudioCaptureSource : public MediaEngineSource {
  public:
   explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid) {}
   nsString GetName() const override;
   nsCString GetUUID() const override;
+  nsString GetGroupId() const override;
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs, const nsString& aDeviceId,
                     const ipc::PrincipalInfo& aPrincipalInfo,
                     AllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override {
     // Nothing to do here, everything is managed in MediaManager.cpp
     *aOutHandle = nullptr;
     return NS_OK;
--- a/dom/media/webrtc/MediaTrackConstraints.cpp
+++ b/dom/media/webrtc/MediaTrackConstraints.cpp
@@ -514,17 +514,17 @@ uint32_t MediaConstraintsHelper::Fitness
 
 /* static */ const char* MediaConstraintsHelper::FindBadConstraint(
     const NormalizedConstraints& aConstraints,
     const RefPtr<MediaEngineSource>& aMediaEngineSource,
     const nsString& aDeviceId) {
   AutoTArray<RefPtr<MediaDevice>, 1> devices;
   devices.AppendElement(MakeRefPtr<MediaDevice>(
       aMediaEngineSource, aMediaEngineSource->GetName(), aDeviceId,
-      NS_LITERAL_STRING("GroupID"), NS_LITERAL_STRING("")));
+      aMediaEngineSource->GetGroupId(), NS_LITERAL_STRING("")));
   return FindBadConstraint(aConstraints, devices);
 }
 
 static void LogConstraintStringRange(
     const NormalizedConstraintSet::StringRange& aRange) {
   if (aRange.mExact.size() <= 1 && aRange.mIdeal.size() <= 1) {
     LOG("  %s: { exact: [%s], ideal: [%s] }", aRange.mName,
         (aRange.mExact.size()