5#include "private/qcameradevice_p.h"
6#include "private/qplatformmediaintegration_p.h"
16#include <emscripten.h>
22Q_GLOBAL_STATIC(QWasmMediaDevices, s_wasmMediaDevicesInstance);
25 : QPlatformVideoDevices(integration)
36 Q_ASSERT(QThread::isMainThread());
43 const QAudioFormat &fmt,
50 const QAudioFormat &fmt,
53 return new QWasmAudioSink(deviceInfo, fmt, parent);
68 Q_ASSERT(QThread::isMainThread());
79 return s_wasmMediaDevicesInstance();
88 getOpenALAudioDevices();
94 return m_cameraDevices.values();
99 return m_audioInputs.values();
104 return m_audioOutputs.values();
109 if (devices.isNull() || devices.isUndefined()) {
110 qWarning() <<
"Something went wrong enumerating devices";
114 QList<std::string> cameraDevicesToRemove = m_cameraDevices.keys();
115 QList<std::string> audioOutputsToRemove;
116 QList<std::string> audioInputsToRemove;
120 qWarning() <<
"m_audioInputs count" << m_audioInputs.count();
123 audioOutputsToRemove = m_audioOutputs.keys();
124 audioInputsToRemove = m_audioInputs.keys();
125 m_audioInputsAdded =
false;
126 m_audioOutputsAdded =
false;
128 m_videoInputsAdded =
false;
130 bool m_videoInputsRemoved =
false;
131 bool m_audioInputsRemoved =
false;
132 bool m_audioOutputsRemoved =
false;
134 for (
int i = 0; i < devices[
"length"].as<
int>(); i++) {
136 emscripten::val mediaDevice = devices[i];
138 const std::string deviceKind = mediaDevice[
"kind"].as<
std::string>();
139 std::string label = mediaDevice[
"label"].as<
std::string>();
140 std::string deviceId = mediaDevice[
"deviceId"].as<
std::string>();
142 qCDebug(qWasmMediaDevices) << QString::fromStdString(deviceKind)
143 << QString::fromStdString(deviceId)
144 << QString::fromStdString(label);
146 if (deviceId.empty()) {
147 label =
"System " + deviceKind;
150 if (deviceKind.empty())
152 bool isDefault =
false;
154 if (deviceKind == std::string(
"videoinput")) {
155 if (!m_cameraDevices.contains(deviceId)) {
157 camera->id = QString::fromStdString(deviceId).toUtf8();
158 camera->description = QString::fromUtf8(label.c_str());
160 camera->isDefault = !m_videoInputsAdded;
161 m_cameraDevices.insert(deviceId, camera->create());
162 m_videoInputsAdded =
true;
164 cameraDevicesToRemove.removeOne(deviceId);
165 }
else if (deviceKind == std::string(
"audioinput")) {
166 if (!m_audioInputs.contains(deviceId)) {
167 isDefault = !m_audioInputsAdded;
168 m_audioInputs.insert(
170 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
171 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Input)));
173 m_audioInputsAdded =
true;
175 audioInputsToRemove.removeOne(deviceId);
176 }
else if (deviceKind == std::string(
"audiooutput")) {
177 if (!m_audioOutputs.contains(deviceId)) {
178 isDefault = !m_audioOutputsAdded;
179 m_audioOutputs.insert(
181 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
182 deviceId.c_str(), label.c_str(), isDefault, QAudioDevice::Output)));
185 m_audioOutputsAdded =
true;
187 audioOutputsToRemove.removeOne(deviceId);
193 getOpenALAudioDevices();
197 for (; j < cameraDevicesToRemove.count(); j++) {
198 m_cameraDevices.remove(cameraDevicesToRemove.at(j));
200 m_videoInputsRemoved = !cameraDevicesToRemove.isEmpty();
202 for (j = 0; j < audioInputsToRemove.count(); j++) {
203 m_audioInputs.remove(audioInputsToRemove.at(j));
205 m_audioInputsRemoved = !audioInputsToRemove.isEmpty();
207 for (j = 0; j < audioOutputsToRemove.count(); j++) {
208 m_audioOutputs.remove(audioOutputsToRemove.at(j));
210 m_audioOutputsRemoved = !audioOutputsToRemove.isEmpty();
212 if (m_videoInputsAdded || m_videoInputsRemoved) {
213 auto videoDevices =
static_cast<QWasmCameraDevices*>(QPlatformMediaIntegration::instance()->videoDevices());
214 videoDevices->onVideoInputsChanged();
216 if (m_audioInputsAdded || m_audioInputsRemoved) {
217 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
218 audioDevices->onAudioInputsChanged();
220 if (m_audioOutputsAdded || m_audioOutputsRemoved) {
221 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
222 audioDevices->onAudioOutputsChanged();
231 emscripten::val navigator = emscripten::val::global(
"navigator");
232 m_jsMediaDevicesInterface = navigator[
"mediaDevices"];
234 if (m_jsMediaDevicesInterface.isNull() || m_jsMediaDevicesInterface.isUndefined()) {
235 qWarning() <<
"No media devices found";
239 if (qstdweb::haveAsyncify()) {
241#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
242 auto asyncEnumerate = [](
void *arg){
243 QWasmMediaDevices *mediaDevices =
static_cast<QWasmMediaDevices *>(arg);
244 mediaDevices->devicesList = mediaDevices->m_jsMediaDevicesInterface.call<emscripten::val>(
"enumerateDevices").await();
245 if (mediaDevices->devicesList.isNull() || mediaDevices->devicesList.isUndefined()) {
246 qWarning() <<
"devices list error";
249 mediaDevices->parseDevices(mediaDevices->devicesList);
252 asyncEnumerate(
this);
254 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
255 m_jsMediaDevicesInterface,
"devicechange",
256 [
this, asyncEnumerate](emscripten::val) {
257 asyncEnumerate(
this);
263 qstdweb::PromiseCallbacks enumerateDevicesCallback{
265 [&](emscripten::val devices) {
266 parseDevices(devices);
269 [
this](emscripten::val error) {
270 qWarning() <<
"mediadevices enumerateDevices fail"
271 << QString::fromStdString(error[
"name"].as<std::string>())
272 << QString::fromStdString(error[
"message"].as<std::string>());
277 qstdweb::Promise::make(m_jsMediaDevicesInterface,
278 QStringLiteral(
"enumerateDevices"),
279 std::move(enumerateDevicesCallback));
282 m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
283 m_jsMediaDevicesInterface,
"devicechange",
284 [
this, enumerateDevicesCallback](emscripten::val) {
285 qstdweb::Promise::make(m_jsMediaDevicesInterface,
286 QStringLiteral(
"enumerateDevices"),
287 std::move(enumerateDevicesCallback));
297 auto capture = alcGetString(
nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
299 if (capture && !m_audioOutputs.contains(capture)) {
300 m_audioInputs.insert(
302 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
303 capture,
"WebAssembly audio capture device",
true, QAudioDevice::Input)));
304 m_audioInputsAdded =
true;
305 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
306 audioDevices->onAudioInputsChanged();
309 auto playback = alcGetString(
nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
311 if (playback && !m_audioOutputs.contains(capture)) {
312 m_audioOutputs.insert(
314 QAudioDevicePrivate::createQAudioDevice(std::make_unique<QWasmAudioDevice>(
315 playback,
"WebAssembly audio playback device",
true,
316 QAudioDevice::Output)));
317 auto audioDevices =
static_cast<QWasmAudioDevices*>(QPlatformMediaIntegration::instance()->audioDevices());
318 audioDevices->onAudioOutputsChanged();
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
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")