5#include "private/qcameradevice_p.h"
6#include "private/qplatformmediaintegration_p.h"
14#include <emscripten.h>
18Q_LOGGING_CATEGORY(qWasmMediaDevices,
"qt.multimedia.wasm.mediadevices")
20static QWasmMediaDevices *s_mediaDevicesInstance =
nullptr;
24 return !emscripten::val::global(
"InstallTrigger").isUndefined();
39 overlay.
style.
cssText =
'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:9999;display:flex;align-items:center;justify-content:center;';
42 dialog.
style.
cssText =
'background:white;padding:24px;border-radius:8px;text-align:center;font-family:sans-serif;min-width:240px;';
70 : QPlatformVideoDevices(integration)
81 Q_ASSERT(QThread::isMainThread());
88 const QAudioFormat &fmt,
95 const QAudioFormat &fmt,
113 Q_ASSERT(QThread::isMainThread());
123 if (s_mediaDevicesInstance)
124 return s_mediaDevicesInstance;
128 s_mediaDevicesInstance =
new QWasmMediaDevices();
130 s_mediaDevicesInstance->initDevices();
131 return s_mediaDevicesInstance;
141 setupAudioOutputSelector();
148 return m_cameraDevices.values();
153 return m_audioInputs.values();
158 return m_audioOutputs.values();
163 if (devices.isNull() || devices.isUndefined()) {
164 qWarning() <<
"Something went wrong enumerating devices";
168 QList<std::string> cameraDevicesToRemove = m_cameraDevices.keys();
169 QList<std::string> audioOutputsToRemove;
170 QList<std::string> audioInputsToRemove;
172 audioOutputsToRemove = m_audioOutputs.keys();
173 audioInputsToRemove = m_audioInputs.keys();
174 m_audioInputsAdded =
false;
175 m_audioOutputsAdded =
false;
176 m_videoInputsAdded =
false;
178 bool m_videoInputsRemoved =
false;
179 bool m_audioInputsRemoved =
false;
180 bool m_audioOutputsRemoved =
false;
182 for (
int i = 0; i < devices[
"length"].as<
int>(); i++) {
184 emscripten::val mediaDevice = devices[i];
186 const std::string deviceKind = mediaDevice[
"kind"].as<
std::string>();
187 std::string label = mediaDevice[
"label"].as<
std::string>();
188 std::string deviceId = mediaDevice[
"deviceId"].as<
std::string>();
190 qCDebug(qWasmMediaDevices) << QString::fromStdString(deviceKind)
191 << QString::fromStdString(deviceId)
192 << QString::fromStdString(label);
194 if (deviceId.empty()) {
195 label =
"System " + deviceKind;
198 if (deviceKind.empty())
200 bool isDefault =
false;
202 if (deviceKind == std::string(
"videoinput")) {
203 if (!m_cameraDevices.contains(deviceId)) {
205 camera->id = QString::fromStdString(deviceId).toUtf8();
206 camera->description = QString::fromUtf8(label.c_str());
208 camera->isDefault = !m_videoInputsAdded;
209 m_cameraDevices.insert(deviceId, camera->create());
210 m_videoInputsAdded =
true;
212 cameraDevicesToRemove.removeOne(deviceId);
213 }
else if (deviceKind == std::string(
"audioinput")) {
214 if (!m_audioInputs.contains(deviceId)) {
215 isDefault = !m_audioInputsAdded;
216 m_audioInputs.insert(
218 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
219 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Input)));
221 m_audioInputsAdded =
true;
223 audioInputsToRemove.removeOne(deviceId);
224 }
else if (deviceKind == std::string(
"audiooutput")) {
225 if (!m_audioOutputs.contains(deviceId)) {
226 isDefault = !m_audioOutputsAdded;
227 m_audioOutputs.insert(
229 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
230 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Output)));
232 m_audioOutputsAdded =
true;
234 audioOutputsToRemove.removeOne(deviceId);
241 for (; j < cameraDevicesToRemove.count(); j++) {
242 m_cameraDevices.remove(cameraDevicesToRemove.at(j));
244 m_videoInputsRemoved = !cameraDevicesToRemove.isEmpty();
246 for (j = 0; j < audioInputsToRemove.count(); j++) {
247 m_audioInputs.remove(audioInputsToRemove.at(j));
249 m_audioInputsRemoved = !audioInputsToRemove.isEmpty();
251 for (j = 0; j < audioOutputsToRemove.count(); j++) {
252 m_audioOutputs.remove(audioOutputsToRemove.at(j));
254 m_audioOutputsRemoved = !audioOutputsToRemove.isEmpty();
256 if (m_videoInputsAdded || m_videoInputsRemoved) {
257 auto videoDevices =
static_cast<QWasmCameraDevices*>(QPlatformMediaIntegration::instance()->videoDevices());
258 QMetaObject::invokeMethod(videoDevices, &QWasmCameraDevices::onVideoInputsChanged,
259 Qt::QueuedConnection);
261 if (m_audioInputsAdded || m_audioInputsRemoved) {
262 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
263 QMetaObject::invokeMethod(audioDevices, &QWasmAudioDevices::onAudioInputsChanged,
264 Qt::QueuedConnection);
266 if (!m_audioOutputsAdded) {
271 m_audioOutputs.insert(
273 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
274 "",
"System output",
true, QAudioDevice::Output)));
275 m_audioOutputsAdded =
true;
277 if (m_audioOutputsAdded || m_audioOutputsRemoved) {
278 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
279 QMetaObject::invokeMethod(audioDevices, &QWasmAudioDevices::onAudioOutputsChanged,
280 Qt::QueuedConnection);
287 emscripten::val navigator = emscripten::val::global(
"navigator");
288 m_jsMediaDevicesInterface = navigator[
"mediaDevices"];
290 if (m_jsMediaDevicesInterface.isNull() || m_jsMediaDevicesInterface.isUndefined()) {
291 qWarning() <<
"No media devices found";
295 if (qstdweb::haveAsyncify()) {
297#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
298 auto asyncEnumerate = [](
void *arg){
299 QWasmMediaDevices *mediaDevices =
static_cast<QWasmMediaDevices *>(arg);
300 mediaDevices->devicesList = mediaDevices->m_jsMediaDevicesInterface.call<emscripten::val>(
"enumerateDevices").await();
301 if (mediaDevices->devicesList.isNull() || mediaDevices->devicesList.isUndefined()) {
302 qWarning() <<
"devices list error";
305 mediaDevices->parseDevices(mediaDevices->devicesList);
308 asyncEnumerate(
this);
310 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
311 m_jsMediaDevicesInterface,
"devicechange",
312 [
this, asyncEnumerate](emscripten::val) {
313 asyncEnumerate(
this);
319 qstdweb::PromiseCallbacks enumerateDevicesCallback{
321 [&](emscripten::val devices) {
322 parseDevices(devices);
325 [
this](emscripten::val error) {
326 qWarning() <<
"mediadevices enumerateDevices fail"
327 << QString::fromStdString(error[
"name"].as<std::string>())
328 << QString::fromStdString(error[
"message"].as<std::string>());
333 qstdweb::Promise::make(m_jsMediaDevicesInterface,
334 QStringLiteral(
"enumerateDevices"),
335 std::move(enumerateDevicesCallback));
338 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
339 m_jsMediaDevicesInterface,
"devicechange",
340 [
this, enumerateDevicesCallback](emscripten::val) {
341 qstdweb::Promise::make(m_jsMediaDevicesInterface,
342 QStringLiteral(
"enumerateDevices"),
343 std::move(enumerateDevicesCallback));
The QAudioDevice class provides an information about audio devices and their functionality.
The QCameraDevice class provides general information about camera devices.
QPlatformAudioSink * createAudioSink(const QAudioDevice &, const QAudioFormat &, QObject *parent) override
QList< QAudioDevice > findAudioOutputs() const override
QList< QAudioDevice > findAudioInputs() const override
QPlatformAudioSource * createAudioSource(const QAudioDevice &, const QAudioFormat &, QObject *parent) override
void connectNotify(const QMetaMethod &signal) override
void connectNotify(const QMetaMethod &signal) override
QList< QCameraDevice > findVideoInputs() const override
Combined button and popup list for selecting options.