5#include "private/qcameradevice_p.h"
6#include "private/qplatformmediaintegration_p.h"
14#include <emscripten.h>
18Q_LOGGING_CATEGORY(qWasmMediaDevices,
"qt.multimedia.wasm.mediadevices")
20Q_GLOBAL_STATIC(QWasmMediaDevices, s_wasmMediaDevicesInstance);
23 return !emscripten::val::global(
"InstallTrigger").isUndefined();
38 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;';
41 dialog.
style.
cssText =
'background:white;padding:24px;border-radius:8px;text-align:center;font-family:sans-serif;min-width:240px;';
69 : QPlatformVideoDevices(integration)
80 Q_ASSERT(QThread::isMainThread());
87 const QAudioFormat &fmt,
94 const QAudioFormat &fmt,
112 Q_ASSERT(QThread::isMainThread());
123 return s_wasmMediaDevicesInstance();
133 setupAudioOutputSelector();
140 return m_cameraDevices.values();
145 return m_audioInputs.values();
150 return m_audioOutputs.values();
155 if (devices.isNull() || devices.isUndefined()) {
156 qWarning() <<
"Something went wrong enumerating devices";
160 QList<std::string> cameraDevicesToRemove = m_cameraDevices.keys();
161 QList<std::string> audioOutputsToRemove;
162 QList<std::string> audioInputsToRemove;
164 audioOutputsToRemove = m_audioOutputs.keys();
165 audioInputsToRemove = m_audioInputs.keys();
166 m_audioInputsAdded =
false;
167 m_audioOutputsAdded =
false;
168 m_videoInputsAdded =
false;
170 bool m_videoInputsRemoved =
false;
171 bool m_audioInputsRemoved =
false;
172 bool m_audioOutputsRemoved =
false;
174 for (
int i = 0; i < devices[
"length"].as<
int>(); i++) {
176 emscripten::val mediaDevice = devices[i];
178 const std::string deviceKind = mediaDevice[
"kind"].as<
std::string>();
179 std::string label = mediaDevice[
"label"].as<
std::string>();
180 std::string deviceId = mediaDevice[
"deviceId"].as<
std::string>();
182 qCDebug(qWasmMediaDevices) << QString::fromStdString(deviceKind)
183 << QString::fromStdString(deviceId)
184 << QString::fromStdString(label);
186 if (deviceId.empty()) {
187 label =
"System " + deviceKind;
190 if (deviceKind.empty())
192 bool isDefault =
false;
194 if (deviceKind == std::string(
"videoinput")) {
195 if (!m_cameraDevices.contains(deviceId)) {
197 camera->id = QString::fromStdString(deviceId).toUtf8();
198 camera->description = QString::fromUtf8(label.c_str());
200 camera->isDefault = !m_videoInputsAdded;
201 m_cameraDevices.insert(deviceId, camera->create());
202 m_videoInputsAdded =
true;
204 cameraDevicesToRemove.removeOne(deviceId);
205 }
else if (deviceKind == std::string(
"audioinput")) {
206 if (!m_audioInputs.contains(deviceId)) {
207 isDefault = !m_audioInputsAdded;
208 m_audioInputs.insert(
210 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
211 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Input)));
213 m_audioInputsAdded =
true;
215 audioInputsToRemove.removeOne(deviceId);
216 }
else if (deviceKind == std::string(
"audiooutput")) {
217 if (!m_audioOutputs.contains(deviceId)) {
218 isDefault = !m_audioOutputsAdded;
219 m_audioOutputs.insert(
221 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
222 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Output)));
224 m_audioOutputsAdded =
true;
226 audioOutputsToRemove.removeOne(deviceId);
233 for (; j < cameraDevicesToRemove.count(); j++) {
234 m_cameraDevices.remove(cameraDevicesToRemove.at(j));
236 m_videoInputsRemoved = !cameraDevicesToRemove.isEmpty();
238 for (j = 0; j < audioInputsToRemove.count(); j++) {
239 m_audioInputs.remove(audioInputsToRemove.at(j));
241 m_audioInputsRemoved = !audioInputsToRemove.isEmpty();
243 for (j = 0; j < audioOutputsToRemove.count(); j++) {
244 m_audioOutputs.remove(audioOutputsToRemove.at(j));
246 m_audioOutputsRemoved = !audioOutputsToRemove.isEmpty();
248 if (m_videoInputsAdded || m_videoInputsRemoved) {
249 auto videoDevices =
static_cast<QWasmCameraDevices*>(QPlatformMediaIntegration::instance()->videoDevices());
250 videoDevices->onVideoInputsChanged();
252 if (m_audioInputsAdded || m_audioInputsRemoved) {
253 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
254 audioDevices->onAudioInputsChanged();
256 if (!m_audioOutputsAdded) {
261 m_audioOutputs.insert(
263 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
264 "",
"System output",
true, QAudioDevice::Output)));
265 m_audioOutputsAdded =
true;
267 if (m_audioOutputsAdded || m_audioOutputsRemoved) {
268 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
269 audioDevices->onAudioOutputsChanged();
276 emscripten::val navigator = emscripten::val::global(
"navigator");
277 m_jsMediaDevicesInterface = navigator[
"mediaDevices"];
279 if (m_jsMediaDevicesInterface.isNull() || m_jsMediaDevicesInterface.isUndefined()) {
280 qWarning() <<
"No media devices found";
284 if (qstdweb::haveAsyncify()) {
286#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
287 auto asyncEnumerate = [](
void *arg){
288 QWasmMediaDevices *mediaDevices =
static_cast<QWasmMediaDevices *>(arg);
289 mediaDevices->devicesList = mediaDevices->m_jsMediaDevicesInterface.call<emscripten::val>(
"enumerateDevices").await();
290 if (mediaDevices->devicesList.isNull() || mediaDevices->devicesList.isUndefined()) {
291 qWarning() <<
"devices list error";
294 mediaDevices->parseDevices(mediaDevices->devicesList);
297 asyncEnumerate(
this);
299 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
300 m_jsMediaDevicesInterface,
"devicechange",
301 [
this, asyncEnumerate](emscripten::val) {
302 asyncEnumerate(
this);
308 qstdweb::PromiseCallbacks enumerateDevicesCallback{
310 [&](emscripten::val devices) {
311 parseDevices(devices);
314 [
this](emscripten::val error) {
315 qWarning() <<
"mediadevices enumerateDevices fail"
316 << QString::fromStdString(error[
"name"].as<std::string>())
317 << QString::fromStdString(error[
"message"].as<std::string>());
322 qstdweb::Promise::make(m_jsMediaDevicesInterface,
323 QStringLiteral(
"enumerateDevices"),
324 std::move(enumerateDevicesCallback));
327 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
328 m_jsMediaDevicesInterface,
"devicechange",
329 [
this, enumerateDevicesCallback](emscripten::val) {
330 qstdweb::Promise::make(m_jsMediaDevicesInterface,
331 QStringLiteral(
"enumerateDevices"),
332 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.