Log capture device information in case of getUserMedia failing to select a device
https://bugs.webkit.org/show_bug.cgi?id=213643

Reviewed by Eric Carlson.

Log constraints and device in case of a failing getUserMedia call.
No obserable change, logging addition.

* platform/mediastream/mac/CoreAudioCaptureDevice.cpp:
(WebCore::getDeviceInfo):
(WebCore::CoreAudioCaptureDevice::deviceClock):
* platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp:
(WebCore::isValidCaptureDevice):
* platform/mediastream/MediaConstraints.cpp:
(WebCore::MediaConstraint::log const):
(WebCore::BooleanConstraint::logAsBoolean const):
(WebCore::DoubleConstraint::logAsDouble const):
(WebCore::IntConstraint::logAsInt const):
* platform/mediastream/MediaConstraints.h:
* platform/mediastream/RealtimeMediaSource.cpp:
(WebCore::RealtimeMediaSource::supportsSizeAndFrameRate):
(WebCore::RealtimeMediaSource::selectSettings):
* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::RealtimeMediaSourceCenter::validateRequestConstraints):
* platform/mediastream/RealtimeVideoCaptureSource.cpp:
(WebCore::RealtimeVideoCaptureSource::bestSupportedSizeAndFrameRate):
* platform/mediastream/VideoPreset.h:
(WebCore::VideoPreset::log const):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@263623 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 4f70b84..8120fe1 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,5 +1,36 @@
 2020-06-27  Youenn Fablet  <youenn@apple.com>
 
+        Log capture device information in case of getUserMedia failing to select a device
+        https://bugs.webkit.org/show_bug.cgi?id=213643
+
+        Reviewed by Eric Carlson.
+
+        Log constraints and device in case of a failing getUserMedia call.
+        No obserable change, logging addition.
+
+        * platform/mediastream/mac/CoreAudioCaptureDevice.cpp:
+        (WebCore::getDeviceInfo):
+        (WebCore::CoreAudioCaptureDevice::deviceClock):
+        * platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp:
+        (WebCore::isValidCaptureDevice):
+        * platform/mediastream/MediaConstraints.cpp:
+        (WebCore::MediaConstraint::log const):
+        (WebCore::BooleanConstraint::logAsBoolean const):
+        (WebCore::DoubleConstraint::logAsDouble const):
+        (WebCore::IntConstraint::logAsInt const):
+        * platform/mediastream/MediaConstraints.h:
+        * platform/mediastream/RealtimeMediaSource.cpp:
+        (WebCore::RealtimeMediaSource::supportsSizeAndFrameRate):
+        (WebCore::RealtimeMediaSource::selectSettings):
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::RealtimeMediaSourceCenter::validateRequestConstraints):
+        * platform/mediastream/RealtimeVideoCaptureSource.cpp:
+        (WebCore::RealtimeVideoCaptureSource::bestSupportedSizeAndFrameRate):
+        * platform/mediastream/VideoPreset.h:
+        (WebCore::VideoPreset::log const):
+
+2020-06-27  Youenn Fablet  <youenn@apple.com>
+
         Protect SWServer::claim from a registration without active worker
         https://bugs.webkit.org/show_bug.cgi?id=213597
 
diff --git a/Source/WebCore/platform/mediastream/MediaConstraints.cpp b/Source/WebCore/platform/mediastream/MediaConstraints.cpp
index 7c40e23..f9eec45 100644
--- a/Source/WebCore/platform/mediastream/MediaConstraints.cpp
+++ b/Source/WebCore/platform/mediastream/MediaConstraints.cpp
@@ -404,7 +404,41 @@
     
     addDefaultVideoConstraints(mandatoryConstraints, needsFrameRateConstraints, needsSizeConstraints, needsFacingModeConstraints);
 }
-    
+
+void MediaConstraint::log() const
+{
+    switch (dataType()) {
+    case DataType::Boolean:
+        downcast<const BooleanConstraint>(*this).logAsBoolean();
+        break;
+    case DataType::Double:
+        downcast<const DoubleConstraint>(*this).logAsDouble();
+        break;
+    case DataType::Integer:
+        downcast<const IntConstraint>(*this).logAsInt();
+        break;
+    case DataType::None:
+    case DataType::String:
+        WTFLogAlways("MediaConstraint %d of type %d", constraintType(), dataType());
+    }
+}
+
+void BooleanConstraint::logAsBoolean() const
+{
+    WTFLogAlways("BooleanConstraint %d, exact %d, ideal %d", constraintType(), m_exact ? *m_exact : -1, m_ideal ? *m_ideal : -1);
+}
+
+void DoubleConstraint::logAsDouble() const
+{
+    WTFLogAlways("DoubleConstraint %d, min %f, max %f, exact %f, ideal %f", constraintType(), m_min ? *m_min : -1, m_max ? *m_max : -1, m_exact ? *m_exact : -1, m_ideal ? *m_ideal : -1);
+}
+
+void IntConstraint::logAsInt() const
+{
+    WTFLogAlways("IntConstraint %d, min %d, max %d, exact %d, ideal %d", constraintType(), m_min ? *m_min : -1, m_max ? *m_max : -1, m_exact ? *m_exact : -1, m_ideal ? *m_ideal : -1);
+}
+
+
 }
 
 #endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/MediaConstraints.h b/Source/WebCore/platform/mediastream/MediaConstraints.h
index 32bf35d..ea715cb 100644
--- a/Source/WebCore/platform/mediastream/MediaConstraints.h
+++ b/Source/WebCore/platform/mediastream/MediaConstraints.h
@@ -75,6 +75,8 @@
         return true;
     }
 
+    void log() const;
+
 protected:
     MediaConstraint(const String& name, MediaConstraintType constraintType, DataType dataType)
         : m_name(name)
@@ -415,6 +417,8 @@
         ASSERT(other.isInt());
         NumericConstraint::innerMerge(downcast<const IntConstraint>(other));
     }
+
+    void logAsInt() const;
 };
 
 class DoubleConstraint final : public NumericConstraint<double> {
@@ -431,6 +435,8 @@
         ASSERT(other.isDouble());
         NumericConstraint::innerMerge(downcast<DoubleConstraint>(other));
     }
+
+    void logAsDouble() const;
 };
 
 class BooleanConstraint final : public MediaConstraint {
@@ -527,6 +533,8 @@
         return true;
     }
 
+    void logAsBoolean() const;
+
 private:
     Optional<bool> m_exact;
     Optional<bool> m_ideal;
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
index cfb31e2..486dbd6 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
@@ -311,6 +311,8 @@
     if (widthConstraint && capabilities.supportsWidth()) {
         double constraintDistance = fitnessDistance(*widthConstraint);
         if (std::isinf(constraintDistance)) {
+            auto range = capabilities.width();
+            WTFLogAlways("RealtimeMediaSource::supportsSizeAndFrameRate failed width constraint, capabilities are [%d, %d]", range.rangeMin().asInt, range.rangeMax().asInt);
             badConstraint = widthConstraint->name();
             return false;
         }
@@ -326,6 +328,8 @@
     if (heightConstraint && capabilities.supportsHeight()) {
         double constraintDistance = fitnessDistance(*heightConstraint);
         if (std::isinf(constraintDistance)) {
+            auto range = capabilities.height();
+            WTFLogAlways("RealtimeMediaSource::supportsSizeAndFrameRate failed height constraint, capabilities are [%d, %d]", range.rangeMin().asInt, range.rangeMax().asInt);
             badConstraint = heightConstraint->name();
             return false;
         }
@@ -341,6 +345,8 @@
     if (frameRateConstraint && capabilities.supportsFrameRate()) {
         double constraintDistance = fitnessDistance(*frameRateConstraint);
         if (std::isinf(constraintDistance)) {
+            auto range = capabilities.frameRate();
+            WTFLogAlways("RealtimeMediaSource::supportsSizeAndFrameRate failed frame rate constraint, capabilities are [%d, %d]", range.rangeMin().asInt, range.rangeMax().asInt);
             badConstraint = frameRateConstraint->name();
             return false;
         }
@@ -661,7 +667,7 @@
     if (!supportsSizeAndFrameRate(constraints.mandatoryConstraints.width(), constraints.mandatoryConstraints.height(), constraints.mandatoryConstraints.frameRate(), failedConstraint, minimumDistance))
         return false;
 
-    constraints.mandatoryConstraints.filter([&](const MediaConstraint& constraint) {
+    constraints.mandatoryConstraints.filter([&](auto& constraint) {
         if (!supportsConstraint(constraint))
             return false;
 
@@ -672,6 +678,7 @@
 
         double constraintDistance = fitnessDistance(constraint);
         if (std::isinf(constraintDistance)) {
+            WTFLogAlways("RealtimeMediaSource::selectSettings failed constraint %d", constraint.constraintType());
             failedConstraint = constraint.name();
             return true;
         }
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
index 2d32b24..0dbf1dc 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
@@ -246,7 +246,18 @@
     else
         getUserMediaDevices(request, String { deviceIdentifierHashSalt }, audioDeviceInfo, videoDeviceInfo, firstInvalidConstraint);
 
-    if ((request.audioConstraints.isValid && audioDeviceInfo.isEmpty()) || (request.videoConstraints.isValid && videoDeviceInfo.isEmpty())) {
+    if (request.audioConstraints.isValid && audioDeviceInfo.isEmpty()) {
+        WTFLogAlways("Audio capture was requested but no device was found amongst %zu devices", audioCaptureFactory().audioCaptureDeviceManager().captureDevices().size());
+        request.audioConstraints.mandatoryConstraints.forEach([](auto& constraint) { constraint.log(); });
+
+        invalidHandler(firstInvalidConstraint);
+        return;
+    }
+
+    if (request.videoConstraints.isValid && videoDeviceInfo.isEmpty()) {
+        WTFLogAlways("Video capture was requested but no device was found amongst %zu devices", videoCaptureFactory().videoCaptureDeviceManager().captureDevices().size());
+        request.videoConstraints.mandatoryConstraints.forEach([](auto& constraint) { constraint.log(); });
+
         invalidHandler(firstInvalidConstraint);
         return;
     }
diff --git a/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp b/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp
index 4bbd27d..d9e01af0 100644
--- a/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp
@@ -329,8 +329,13 @@
         }
     }
 
-    if (!exactSizePreset && !aspectRatioPreset && !resizePreset)
+    if (!exactSizePreset && !aspectRatioPreset && !resizePreset) {
+        WTFLogAlways("RealtimeVideoCaptureSource::bestSupportedSizeAndFrameRate failed supporting constraints %d %d %f", requestedWidth ? *requestedWidth : -1, requestedHeight ? *requestedHeight : -1, requestedFrameRate ? *requestedFrameRate : -1);
+        for (const auto& preset : presets())
+            preset->log();
+
         return { };
+    }
 
     result.requestedFrameRate = requestedFrameRate.value();
     if (exactSizePreset) {
diff --git a/Source/WebCore/platform/mediastream/VideoPreset.h b/Source/WebCore/platform/mediastream/VideoPreset.h
index 2033c76..7f8f931 100644
--- a/Source/WebCore/platform/mediastream/VideoPreset.h
+++ b/Source/WebCore/platform/mediastream/VideoPreset.h
@@ -114,6 +114,8 @@
     Vector<FrameRateRange> frameRateRanges;
     VideoPresetType type;
 
+    void log()const;
+
 protected:
     VideoPreset(IntSize size, Vector<FrameRateRange>&& frameRateRanges, VideoPresetType type)
         : size(size)
@@ -123,6 +125,13 @@
     }
 };
 
+inline void VideoPreset::log() const
+{
+    WTFLogAlways("VideoPreset of size (%d,%d) and type %d", size.width(), size.height(), type);
+    for (auto range : frameRateRanges)
+        WTFLogAlways("VideoPreset frame rate range [%f, %f]", range.minimum, range.maximum);
+}
+
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::VideoPreset)
diff --git a/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp b/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp
index 2be85b0..0684683 100644
--- a/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp
+++ b/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp
@@ -45,7 +45,7 @@
     UInt32 dataSize = sizeof(uniqueID);
     auto err = AudioObjectGetPropertyData(static_cast<UInt32>(deviceID), &address, 0, nullptr, &dataSize, &uniqueID);
     if (err) {
-        LOG(Media, "CoreAudioCaptureDevice::getDeviceInfo failed to get device unique id with error %d (%.4s)", (int)err, (char*)&err);
+        RELEASE_LOG_ERROR(WebRTC, "CoreAudioCaptureDevice::getDeviceInfo failed to get device unique id with error %d (%.4s)", (int)err, (char*)&err);
         return false;
     }
     persistentID = uniqueID;
@@ -56,7 +56,7 @@
     dataSize = sizeof(localizedName);
     err = AudioObjectGetPropertyData(static_cast<UInt32>(deviceID), &address, 0, nullptr, &dataSize, &localizedName);
     if (err) {
-        LOG(Media, "CoreAudioCaptureDevice::getDeviceInfo failed to get device name with error %d (%.4s)", (int)err, (char*)&err);
+        RELEASE_LOG_ERROR(WebRTC, "CoreAudioCaptureDevice::getDeviceInfo failed to get device name with error %d (%.4s)", (int)err, (char*)&err);
         return false;
     }
     label = localizedName;
@@ -89,7 +89,7 @@
     CMClockRef clock;
     auto err = CMAudioDeviceClockCreate(kCFAllocatorDefault, persistentId().createCFString().get(), &clock);
     if (err) {
-        LOG(Media, "CoreAudioCaptureDevice::CMAudioDeviceClockCreate(%p) CMAudioDeviceClockCreate failed with error %d (%.4s)", this, (int)err, (char*)&err);
+        RELEASE_LOG_ERROR(WebRTC, "CoreAudioCaptureDevice::CMAudioDeviceClockCreate(%p) CMAudioDeviceClockCreate failed with error %d (%.4s)", this, (int)err, (char*)&err);
         return nullptr;
     }
 
diff --git a/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp b/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp
index ae958b2..f7e64f1 100644
--- a/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp
+++ b/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp
@@ -84,8 +84,10 @@
 {
     // Ignore output devices that have input only for echo cancellation.
     AudioObjectPropertyAddress address = { kAudioDevicePropertyTapEnabled, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
-    if (AudioObjectHasProperty(device.deviceID(), &address))
+    if (AudioObjectHasProperty(device.deviceID(), &address)) {
+        RELEASE_LOG(WebRTC, "Ignoring output device that have input only for echo cancellation");
         return false;
+    }
 
     // Ignore non-aggregable devices.
     UInt32 dataSize = 0;
@@ -96,11 +98,23 @@
     bool isNonAggregable = !name || !String(name).startsWith("com.apple.audio.CoreAudio");
     if (name)
         CFRelease(name);
-    if (isNonAggregable)
+    if (isNonAggregable) {
+        RELEASE_LOG(WebRTC, "Ignoring output device that is non aggregable");
         return false;
+    }
 
     // Ignore unnamed devices and aggregate devices created by VPIO.
-    return !device.label().isEmpty() && !device.label().startsWith("VPAUAggregateAudioDevice");
+    if (device.label().isEmpty()) {
+        RELEASE_LOG(WebRTC, "Ignoring output device that is unnamed");
+        return false;
+    }
+
+    if (device.label().startsWith("VPAUAggregateAudioDevice")) {
+        RELEASE_LOG(WebRTC, "Ignoring output VPAUAggregateAudioDevice device");
+        return false;
+    }
+
+    return true;
 }
 
 static inline Optional<CoreAudioCaptureDevice> getDefaultCaptureInputDevice()