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;
144 insertFallbackAudioOutput();
147 setupAudioOutputSelector();
154 return m_cameraDevices.values();
159 return m_audioInputs.values();
164 return m_audioOutputs.values();
169 if (devices.isNull() || devices.isUndefined()) {
170 qWarning() <<
"Something went wrong enumerating devices";
174 QList<std::string> cameraDevicesToRemove = m_cameraDevices.keys();
175 QList<std::string> audioOutputsToRemove;
176 QList<std::string> audioInputsToRemove;
178 audioOutputsToRemove = m_audioOutputs.keys();
179 audioInputsToRemove = m_audioInputs.keys();
180 m_audioInputsAdded =
false;
181 m_audioOutputsAdded =
false;
182 m_videoInputsAdded =
false;
184 bool m_videoInputsRemoved =
false;
185 bool m_audioInputsRemoved =
false;
186 bool m_audioOutputsRemoved =
false;
188 for (
int i = 0; i < devices[
"length"].as<
int>(); i++) {
190 emscripten::val mediaDevice = devices[i];
192 const std::string deviceKind = mediaDevice[
"kind"].as<
std::string>();
193 std::string label = mediaDevice[
"label"].as<
std::string>();
194 std::string deviceId = mediaDevice[
"deviceId"].as<
std::string>();
196 qCDebug(qWasmMediaDevices) << QString::fromStdString(deviceKind)
197 << QString::fromStdString(deviceId)
198 << QString::fromStdString(label);
200 if (deviceId.empty()) {
201 label =
"System " + deviceKind;
204 if (deviceKind.empty())
206 bool isDefault =
false;
208 if (deviceKind == std::string(
"videoinput")) {
209 if (!m_cameraDevices.contains(deviceId)) {
211 camera->id = QString::fromStdString(deviceId).toUtf8();
212 camera->description = QString::fromUtf8(label.c_str());
214 camera->isDefault = !m_videoInputsAdded;
215 m_cameraDevices.insert(deviceId, camera->create());
216 m_videoInputsAdded =
true;
218 cameraDevicesToRemove.removeOne(deviceId);
219 }
else if (deviceKind == std::string(
"audioinput")) {
220 if (!m_audioInputs.contains(deviceId)) {
221 isDefault = !m_audioInputsAdded;
222 m_audioInputs.insert(
224 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
225 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Input)));
227 m_audioInputsAdded =
true;
229 audioInputsToRemove.removeOne(deviceId);
230 }
else if (deviceKind == std::string(
"audiooutput")) {
231 if (!m_audioOutputs.contains(deviceId)) {
232 isDefault = !m_audioOutputsAdded;
233 m_audioOutputs.insert(
235 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
236 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Output)));
238 m_audioOutputsAdded =
true;
240 audioOutputsToRemove.removeOne(deviceId);
247 for (; j < cameraDevicesToRemove.count(); j++) {
248 m_cameraDevices.remove(cameraDevicesToRemove.at(j));
250 m_videoInputsRemoved = !cameraDevicesToRemove.isEmpty();
252 for (j = 0; j < audioInputsToRemove.count(); j++) {
253 m_audioInputs.remove(audioInputsToRemove.at(j));
255 m_audioInputsRemoved = !audioInputsToRemove.isEmpty();
257 for (j = 0; j < audioOutputsToRemove.count(); j++) {
258 m_audioOutputs.remove(audioOutputsToRemove.at(j));
260 m_audioOutputsRemoved = !audioOutputsToRemove.isEmpty();
262 if (m_videoInputsAdded || m_videoInputsRemoved) {
263 auto videoDevices =
static_cast<QWasmCameraDevices*>(QPlatformMediaIntegration::instance()->videoDevices());
264 QMetaObject::invokeMethod(videoDevices, &QWasmCameraDevices::onVideoInputsChanged,
265 Qt::QueuedConnection);
267 if (m_audioInputsAdded || m_audioInputsRemoved) {
268 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
269 QMetaObject::invokeMethod(audioDevices, &QWasmAudioDevices::onAudioInputsChanged,
270 Qt::QueuedConnection);
272 if (!m_audioOutputsAdded) {
277 insertFallbackAudioOutput();
279 if (m_audioOutputsAdded || m_audioOutputsRemoved) {
280 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
281 QMetaObject::invokeMethod(audioDevices, &QWasmAudioDevices::onAudioOutputsChanged,
282 Qt::QueuedConnection);
289 m_audioOutputs.insert(
291 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
292 "",
"System output",
true, QAudioDevice::Output)));
293 m_audioOutputsAdded =
true;
298 emscripten::val navigator = emscripten::val::global(
"navigator");
299 m_jsMediaDevicesInterface = navigator[
"mediaDevices"];
301 if (m_jsMediaDevicesInterface.isNull() || m_jsMediaDevicesInterface.isUndefined()) {
302 qWarning() <<
"No media devices found";
306 if (qstdweb::haveAsyncify()) {
308#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
309 auto asyncEnumerate = [](
void *arg){
310 QWasmMediaDevices *mediaDevices =
static_cast<QWasmMediaDevices *>(arg);
311 mediaDevices->devicesList = mediaDevices->m_jsMediaDevicesInterface.call<emscripten::val>(
"enumerateDevices").await();
312 if (mediaDevices->devicesList.isNull() || mediaDevices->devicesList.isUndefined()) {
313 qWarning() <<
"devices list error";
316 mediaDevices->parseDevices(mediaDevices->devicesList);
319 asyncEnumerate(
this);
321 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
322 m_jsMediaDevicesInterface,
"devicechange",
323 [
this, asyncEnumerate](emscripten::val) {
324 asyncEnumerate(
this);
330 qstdweb::PromiseCallbacks enumerateDevicesCallback{
332 [&](emscripten::val devices) {
333 parseDevices(devices);
336 [
this](emscripten::val error) {
337 qWarning() <<
"mediadevices enumerateDevices fail"
338 << QString::fromStdString(error[
"name"].as<std::string>())
339 << QString::fromStdString(error[
"message"].as<std::string>());
345 qstdweb::Promise::make(m_jsMediaDevicesInterface,
346 QStringLiteral(
"enumerateDevices"),
347 std::move(enumerateDevicesCallback));
350 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
351 m_jsMediaDevicesInterface,
"devicechange",
352 [
this, enumerateDevicesCallback](emscripten::val) {
353 qstdweb::Promise::make(m_jsMediaDevicesInterface,
354 QStringLiteral(
"enumerateDevices"),
355 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.