[WPE][GTK] Bump minimum versions of GLib, GTK, libsoup, ATK, GStreamer, and Cairo
[WebKit-https.git] / Source / WebCore / platform / mediastream / gstreamer / GStreamerCaptureDeviceManager.cpp
1 /*
2  * Copyright (C) 2018 Metrological Group B.V.
3  * Author: Thibault Saunier <tsaunier@igalia.com>
4  * Author: Alejandro G. Castro <alex@igalia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * aint with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
25 #include "GStreamerCaptureDeviceManager.h"
26
27 #include "GStreamerCommon.h"
28
29 namespace WebCore {
30
31 static gint sortDevices(gconstpointer a, gconstpointer b)
32 {
33     GstDevice* adev = GST_DEVICE(a), *bdev = GST_DEVICE(b);
34     GUniquePtr<GstStructure> aprops(gst_device_get_properties(adev));
35     GUniquePtr<GstStructure> bprops(gst_device_get_properties(bdev));
36     gboolean aIsDefault = FALSE, bIsDefault = FALSE;
37
38     gst_structure_get_boolean(aprops.get(), "is-default", &aIsDefault);
39     gst_structure_get_boolean(bprops.get(), "is-default", &bIsDefault);
40
41     if (aIsDefault == bIsDefault) {
42         GUniquePtr<char> aName(gst_device_get_display_name(adev));
43         GUniquePtr<char> bName(gst_device_get_display_name(bdev));
44
45         return g_strcmp0(aName.get(), bName.get());
46     }
47
48     return aIsDefault > bIsDefault ? -1 : 1;
49 }
50
51 GStreamerAudioCaptureDeviceManager& GStreamerAudioCaptureDeviceManager::singleton()
52 {
53     static NeverDestroyed<GStreamerAudioCaptureDeviceManager> manager;
54     return manager;
55 }
56
57 GStreamerVideoCaptureDeviceManager& GStreamerVideoCaptureDeviceManager::singleton()
58 {
59     static NeverDestroyed<GStreamerVideoCaptureDeviceManager> manager;
60     return manager;
61 }
62
63 GStreamerDisplayCaptureDeviceManager& GStreamerDisplayCaptureDeviceManager::singleton()
64 {
65     static NeverDestroyed<GStreamerDisplayCaptureDeviceManager> manager;
66     return manager;
67 }
68
69 Optional<GStreamerCaptureDevice> GStreamerCaptureDeviceManager::gstreamerDeviceWithUID(const String& deviceID)
70 {
71     captureDevices();
72
73     for (auto& device : m_gstreamerDevices) {
74         if (device.persistentId() == deviceID)
75             return device;
76     }
77     return WTF::nullopt;
78 }
79
80 const Vector<CaptureDevice>& GStreamerCaptureDeviceManager::captureDevices()
81 {
82     initializeGStreamer();
83     if (m_devices.isEmpty())
84         refreshCaptureDevices();
85
86     return m_devices;
87 }
88
89 void GStreamerCaptureDeviceManager::addDevice(GRefPtr<GstDevice>&& device)
90 {
91     GUniquePtr<GstStructure> properties(gst_device_get_properties(device.get()));
92     const char* klass = gst_structure_get_string(properties.get(), "device.class");
93
94     if (klass && !g_strcmp0(klass, "monitor"))
95         return;
96
97     CaptureDevice::DeviceType type = deviceType();
98     GUniquePtr<char> deviceClassChar(gst_device_get_device_class(device.get()));
99     String deviceClass(String(deviceClassChar.get()));
100     if (type == CaptureDevice::DeviceType::Microphone && !deviceClass.startsWith("Audio"))
101         return;
102     if (type == CaptureDevice::DeviceType::Camera && !deviceClass.startsWith("Video"))
103         return;
104
105     // This isn't really a UID but should be good enough (libwebrtc
106     // itself does that at least for pulseaudio devices).
107     GUniquePtr<char> deviceName(gst_device_get_display_name(device.get()));
108     gboolean isDefault = FALSE;
109     gst_structure_get_boolean(properties.get(), "is-default", &isDefault);
110
111     String identifier = makeString(isDefault ? "default: " : "", deviceName.get());
112
113     auto gstCaptureDevice = GStreamerCaptureDevice(WTFMove(device), identifier, type, identifier);
114     gstCaptureDevice.setEnabled(true);
115     m_gstreamerDevices.append(WTFMove(gstCaptureDevice));
116     // FIXME: We need a CaptureDevice copy in other vector just for captureDevices API.
117     auto captureDevice = CaptureDevice(identifier, type, identifier);
118     captureDevice.setEnabled(true);
119     m_devices.append(WTFMove(captureDevice));
120 }
121
122 void GStreamerCaptureDeviceManager::refreshCaptureDevices()
123 {
124     if (!m_deviceMonitor) {
125         m_deviceMonitor = adoptGRef(gst_device_monitor_new());
126
127         CaptureDevice::DeviceType type = deviceType();
128         if (type == CaptureDevice::DeviceType::Camera) {
129             GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_empty_simple("video/x-raw"));
130             gst_device_monitor_add_filter(m_deviceMonitor.get(), "Video/Source", caps.get());
131         } else if (type == CaptureDevice::DeviceType::Microphone) {
132             GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_empty_simple("audio/x-raw"));
133             gst_device_monitor_add_filter(m_deviceMonitor.get(), "Audio/Source", caps.get());
134         } else
135             return;
136     }
137
138     // FIXME: Add monitor for added/removed messages on the bus.
139     if (!gst_device_monitor_start(m_deviceMonitor.get())) {
140         GST_WARNING_OBJECT(m_deviceMonitor.get(), "Could not start device monitor");
141         m_deviceMonitor = nullptr;
142
143         return;
144     }
145
146     GList* devices = g_list_sort(gst_device_monitor_get_devices(m_deviceMonitor.get()), sortDevices);
147     while (devices) {
148         GRefPtr<GstDevice> device = adoptGRef(GST_DEVICE_CAST(devices->data));
149
150         addDevice(WTFMove(device));
151         devices = g_list_delete_link(devices, devices);
152     }
153
154     gst_device_monitor_stop(m_deviceMonitor.get());
155 }
156
157 } // namespace WebCore
158
159 #endif // ENABLE(MEDIA_STREAM) && USE(GSTREAMER)