summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorn Potter <lorn.potter@gmail.com>2023-01-16 14:21:04 +1000
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-02-24 01:49:35 +0000
commit42ae5cca5781435f02d62d34f9e0d76ac4d4e008 (patch)
tree906345cbca05cc81862eb2a6304989221852dedb
parentd00db71624981534e5ba8bf04da4c28dce44583f (diff)
downloadqtmultimedia-42ae5cca5781435f02d62d34f9e0d76ac4d4e008.tar.gz
wasm: add support for QAudioOutput
This allows QMediaPlayer to play audio Fixes: QTBUG-98373 Change-Id: If6c831081f5e6c4216775d7d7672b8a8e2f85208 Reviewed-by: MikoĊ‚aj Boc <Mikolaj.Boc@qt.io> (cherry picked from commit 6607b3ee062e12dee458b211ddba474c999a0156) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/multimedia/wasm/qwasmaudiodevice.cpp3
-rw-r--r--src/multimedia/wasm/qwasmmediadevices.cpp1
-rw-r--r--src/plugins/multimedia/wasm/common/qwasmaudiooutput.cpp342
-rw-r--r--src/plugins/multimedia/wasm/common/qwasmaudiooutput_p.h66
-rw-r--r--src/plugins/multimedia/wasm/common/qwasmvideooutput.cpp5
-rw-r--r--src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp82
-rw-r--r--src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer_p.h3
7 files changed, 462 insertions, 40 deletions
diff --git a/src/multimedia/wasm/qwasmaudiodevice.cpp b/src/multimedia/wasm/qwasmaudiodevice.cpp
index b8f3532b5..c87a0ad54 100644
--- a/src/multimedia/wasm/qwasmaudiodevice.cpp
+++ b/src/multimedia/wasm/qwasmaudiodevice.cpp
@@ -15,8 +15,8 @@ QWasmAudioDevice::QWasmAudioDevice(const char *device, const char *desc, bool is
: QAudioDevicePrivate(device, mode)
{
description = QString::fromUtf8(desc);
- isDefault = isDef;
+ isDefault = isDef;
minimumChannelCount = 1;
maximumChannelCount = 2;
minimumSampleRate = 8000;
@@ -40,6 +40,7 @@ QWasmAudioDevice::QWasmAudioDevice(const char *device, const char *desc, bool is
audioContext = emscripten::val::global("window")["webkitAudioContext"].new_();
if (audioContext != emscripten::val::undefined()) {
+ audioContext.call<void>("resume");
int sRate = audioContext["sampleRate"].as<int>();
audioContext.call<void>("close");
preferredFormat.setSampleRate(sRate);
diff --git a/src/multimedia/wasm/qwasmmediadevices.cpp b/src/multimedia/wasm/qwasmmediadevices.cpp
index 5c25fc62f..189e8c5b0 100644
--- a/src/multimedia/wasm/qwasmmediadevices.cpp
+++ b/src/multimedia/wasm/qwasmmediadevices.cpp
@@ -31,6 +31,7 @@ QList<QCameraDevice> QWasmCameraDevices::videoDevices() const
QWasmMediaDevices::QWasmMediaDevices() : QPlatformMediaDevices()
{
+ getOpenALAudioDevices();
getMediaDevices(); // asynchronous
}
diff --git a/src/plugins/multimedia/wasm/common/qwasmaudiooutput.cpp b/src/plugins/multimedia/wasm/common/qwasmaudiooutput.cpp
index 5aa6b9658..3d8ff89b0 100644
--- a/src/plugins/multimedia/wasm/common/qwasmaudiooutput.cpp
+++ b/src/plugins/multimedia/wasm/common/qwasmaudiooutput.cpp
@@ -1,13 +1,18 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR
// GPL-2.0-only OR GPL-3.0-only
#include <qaudiodevice.h>
#include <qaudiooutput.h>
#include <qwasmaudiooutput_p.h>
-//#include <qwasmaudiodevice_p.h>
+#include <QMimeDatabase>
#include <QtCore/qloggingcategory.h>
+#include <QMediaDevices>
+#include <QUrl>
+#include <QFile>
+#include <QMimeDatabase>
+#include <QFileInfo>
QT_BEGIN_NAMESPACE
@@ -16,21 +21,338 @@ static Q_LOGGING_CATEGORY(qWasmMediaAudioOutput, "qt.multimedia.wasm.audiooutput
QWasmAudioOutput::QWasmAudioOutput(QAudioOutput *parent)
: QPlatformAudioOutput(parent)
{
- // TODO
}
-QWasmAudioOutput::~QWasmAudioOutput() { }
+QWasmAudioOutput::~QWasmAudioOutput() = default;
-void QWasmAudioOutput::setAudioDevice(const QAudioDevice &device) {
- Q_UNUSED(device);
+void QWasmAudioOutput::setAudioDevice(const QAudioDevice &audioDevice)
+{
+ qCDebug(qWasmMediaAudioOutput) << Q_FUNC_INFO << device.id();
+ device = audioDevice;
}
-void QWasmAudioOutput::setMuted(bool muted) {
- Q_UNUSED(muted);
+void QWasmAudioOutput::setMuted(bool muted)
+{
+ if (m_audio.isUndefined() || m_audio.isNull()) {
+ qCDebug(qWasmMediaAudioOutput) << "Error"
+ << "Audio element could not be created";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Media file could not be opened"));
+ return;
+ }
+ m_audio.set("mute", muted);
+}
+
+void QWasmAudioOutput::setVolume(float volume)
+{
+ if (m_audio.isUndefined() || m_audio.isNull()) {
+ qCDebug(qWasmMediaAudioOutput) << "Error"
+ << "Audio element could not be created";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Media file could not be opened"));
+ return;
+ }
+ volume = qBound(qreal(0.0), volume, qreal(1.0));
+ m_audio.set("volume", volume);
}
-void QWasmAudioOutput::setVolume(float volume) {
- Q_UNUSED(volume);
+void QWasmAudioOutput::setSource(const QUrl &url)
+{
+ qCDebug(qWasmMediaAudioOutput) << Q_FUNC_INFO << url;
+ if (url.isEmpty()) {
+ stop();
+ return;
+ }
+
+ createAudioElement(device.id().toStdString());
+
+ if (m_audio.isUndefined() || m_audio.isNull()) {
+ qCDebug(qWasmMediaAudioOutput) << "Error"
+ << "Audio element could not be created";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Audio element could not be created"));
+ return;
+ }
+
+ emscripten::val document = emscripten::val::global("document");
+ emscripten::val body = document["body"];
+
+ m_audio.set("id", device.id().toStdString());
+
+ body.call<void>("appendChild", m_audio);
+
+
+ if (url.isLocalFile()) { // is localfile
+ qCDebug(qWasmMediaAudioOutput) << "is localfile";
+ m_source = url.toLocalFile();
+
+ QFile mediaFile(m_source);
+ if (!mediaFile.open(QIODevice::ReadOnly)) {
+ qCDebug(qWasmMediaAudioOutput) << "Error"
+ << "Media file could not be opened";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Media file could not be opened"));
+ return;
+ }
+
+ // local files are relatively small due to browser filesystem being restricted
+ QByteArray content = mediaFile.readAll();
+
+ QMimeDatabase db;
+ qCDebug(qWasmMediaAudioOutput) << db.mimeTypeForData(content).name();
+
+ qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(content.constData(), content.size());
+ emscripten::val contentUrl =
+ qstdweb::window()["URL"].call<emscripten::val>("createObjectURL", contentBlob.val());
+
+ emscripten::val audioSourceElement =
+ document.call<emscripten::val>("createElement", std::string("source"));
+
+ audioSourceElement.set("src", contentUrl);
+
+ // work around Safari not being able to read audio from blob URLs.
+ QFileInfo info(m_source);
+ QMimeType mimeType = db.mimeTypeForFile(info);
+
+ audioSourceElement.set("type", mimeType.name().toStdString());
+ m_audio.call<void>("appendChild", audioSourceElement);
+
+ m_audio.call<void>("setAttribute", emscripten::val("srcObject"), contentUrl);
+
+ } else {
+ m_source = url.toString();
+ m_audio.set("src", m_source.toStdString());
+ }
+ m_audio.set("id", device.id().toStdString());
+
+ body.call<void>("appendChild", m_audio);
+ qCDebug(qWasmMediaAudioOutput) << Q_FUNC_INFO << device.id();
+
+ doElementCallbacks();
+}
+
+void QWasmAudioOutput::setSource(QIODevice *stream)
+{
+ m_audioIODevice = stream;
+}
+
+void QWasmAudioOutput::start()
+{
+ if (m_audio.isNull() || m_audio.isUndefined()) {
+ qCDebug(qWasmMediaAudioOutput) << "audio failed to start";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Audio element resource error"));
+ return;
+ }
+
+ m_audio.call<void>("play");
+}
+
+void QWasmAudioOutput::stop()
+{
+ if (m_audio.isNull() || m_audio.isUndefined()) {
+ qCDebug(qWasmMediaAudioOutput) << "audio failed to start";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Audio element resource error"));
+ return;
+ }
+ if (!m_source.isEmpty()) {
+ pause();
+ m_audio.set("currentTime", emscripten::val(0));
+ }
+ if (m_audioIODevice) {
+ m_audioIODevice->close();
+ delete m_audioIODevice;
+ m_audioIODevice = 0;
+ }
+}
+
+void QWasmAudioOutput::pause()
+{
+ if (m_audio.isNull() || m_audio.isUndefined()) {
+ qCDebug(qWasmMediaAudioOutput) << "audio failed to start";
+ emit errorOccured(QMediaPlayer::ResourceError,
+ QStringLiteral("Audio element resource error"));
+ return;
+ }
+ m_audio.call<emscripten::val>("pause");
+}
+
+void QWasmAudioOutput::createAudioElement(const std::string &id)
+{
+ emscripten::val document = emscripten::val::global("document");
+ m_audio = document.call<emscripten::val>("createElement", std::string("audio"));
+
+ // only works in chrome and firefox.
+ // Firefox this feature is behind media.setsinkid.enabled preferences
+ // allows user to choose audio output device
+
+ if (!m_audio.hasOwnProperty("sinkId") || m_audio["sinkId"].isUndefined()) {
+ return;
+ }
+
+ std::string usableId = id;
+ if (usableId.empty())
+ usableId = QMediaDevices::defaultAudioOutput().id();
+
+ qstdweb::PromiseCallbacks sinkIdCallbacks{
+ .thenFunc = [](emscripten::val) { qCWarning(qWasmMediaAudioOutput) << "setSinkId ok"; },
+ .catchFunc =
+ [](emscripten::val) {
+ qCWarning(qWasmMediaAudioOutput) << "Error while trying to setSinkId";
+ }
+ };
+ qstdweb::Promise::make(m_audio, "setSinkId", std::move(sinkIdCallbacks), std::move(usableId));
+
+ m_audio.set("id", usableId.c_str());
+}
+
+void QWasmAudioOutput::doElementCallbacks()
+{
+ // error
+ auto errorCallback = [&](emscripten::val event) {
+ qCDebug(qWasmMediaAudioOutput) << "error";
+ if (event.isUndefined() || event.isNull())
+ return;
+ emit errorOccured(m_audio["error"]["code"].as<int>(),
+ QString::fromStdString(m_audio["error"]["message"].as<std::string>()));
+
+ QString errorMessage =
+ QString::fromStdString(m_audio["error"]["message"].as<std::string>());
+ if (errorMessage.isEmpty()) {
+ switch (m_audio["error"]["code"].as<int>()) {
+ case AudioElementError::MEDIA_ERR_ABORTED:
+ errorMessage = QStringLiteral("aborted by the user agent at the user's request.");
+ break;
+ case AudioElementError::MEDIA_ERR_NETWORK:
+ errorMessage = QStringLiteral("network error.");
+ break;
+ case AudioElementError::MEDIA_ERR_DECODE:
+ errorMessage = QStringLiteral("decoding error.");
+ break;
+ case AudioElementError::MEDIA_ERR_SRC_NOT_SUPPORTED:
+ errorMessage = QStringLiteral("src attribute not suitable.");
+ break;
+ };
+ }
+ qCDebug(qWasmMediaAudioOutput) << m_audio["error"]["code"].as<int>() << errorMessage;
+
+ emit errorOccured(m_audio["error"]["code"].as<int>(), errorMessage);
+ };
+ m_errorChangeEvent.reset(new qstdweb::EventCallback(m_audio, "error", errorCallback));
+
+ // loadeddata
+ auto loadedDataCallback = [&](emscripten::val event) {
+ Q_UNUSED(event)
+ qCDebug(qWasmMediaAudioOutput) << "loaded data";
+ qstdweb::window()["URL"].call<emscripten::val>("revokeObjectURL", m_audio["src"]);
+ };
+ m_loadedDataEvent.reset(new qstdweb::EventCallback(m_audio, "loadeddata", loadedDataCallback));
+
+ // canplay
+ auto canPlayCallback = [&](emscripten::val event) {
+ if (event.isUndefined() || event.isNull())
+ return;
+ qCDebug(qWasmMediaAudioOutput) << "can play";
+ emit readyChanged(true);
+ emit stateChanged(QWasmMediaPlayer::Preparing);
+ };
+ m_canPlayChangeEvent.reset(new qstdweb::EventCallback(m_audio, "canplay", canPlayCallback));
+
+ // canplaythrough
+ auto canPlayThroughCallback = [&](emscripten::val event) {
+ Q_UNUSED(event)
+ emit stateChanged(QWasmMediaPlayer::Prepared);
+ };
+ m_canPlayThroughChangeEvent.reset(
+ new qstdweb::EventCallback(m_audio, "canplaythrough", canPlayThroughCallback));
+
+ // play
+ auto playCallback = [&](emscripten::val event) {
+ Q_UNUSED(event)
+ qCDebug(qWasmMediaAudioOutput) << "play";
+ emit stateChanged(QWasmMediaPlayer::Started);
+ };
+ m_playEvent.reset(new qstdweb::EventCallback(m_audio, "play", playCallback));
+
+ // durationchange
+ auto durationChangeCallback = [&](emscripten::val event) {
+ qCDebug(qWasmMediaAudioOutput) << "durationChange";
+
+ // duration in ms
+ emit durationChanged(event["target"]["duration"].as<double>() * 1000);
+ };
+ m_durationChangeEvent.reset(
+ new qstdweb::EventCallback(m_audio, "durationchange", durationChangeCallback));
+
+ // ended
+ auto endedCallback = [&](emscripten::val event) {
+ Q_UNUSED(event)
+ qCDebug(qWasmMediaAudioOutput) << "ended";
+ m_currentMediaStatus = QMediaPlayer::EndOfMedia;
+ emit statusChanged(m_currentMediaStatus);
+ };
+ m_endedEvent.reset(new qstdweb::EventCallback(m_audio, "ended", endedCallback));
+
+ // progress (buffering progress)
+ auto progesssCallback = [&](emscripten::val event) {
+ if (event.isUndefined() || event.isNull())
+ return;
+ qCDebug(qWasmMediaAudioOutput) << "progress";
+ float duration = event["target"]["duration"].as<int>();
+ if (duration < 0) // track not exactly ready yet
+ return;
+
+ emscripten::val timeRanges = event["target"]["buffered"];
+
+ if ((!timeRanges.isNull() || !timeRanges.isUndefined())
+ && timeRanges["length"].as<int>() == 1) {
+ emscripten::val dVal = timeRanges.call<emscripten::val>("end", 0);
+
+ if (!dVal.isNull() || !dVal.isUndefined()) {
+ double bufferedEnd = dVal.as<double>();
+
+ if (duration > 0 && bufferedEnd > 0) {
+ float bufferedValue = (bufferedEnd / duration * 100);
+ qCDebug(qWasmMediaAudioOutput) << "progress buffered" << bufferedValue;
+
+ emit bufferingChanged(m_currentBufferedValue);
+ if (bufferedEnd == duration)
+ m_currentMediaStatus = QMediaPlayer::BufferedMedia;
+ else
+ m_currentMediaStatus = QMediaPlayer::BufferingMedia;
+
+ emit statusChanged(m_currentMediaStatus);
+ }
+ }
+ }
+ };
+ m_progressChangeEvent.reset(new qstdweb::EventCallback(m_audio, "progress", progesssCallback));
+
+ // timupdate
+ auto timeUpdateCallback = [&](emscripten::val event) {
+ qCDebug(qWasmMediaAudioOutput)
+ << "timeupdate" << (event["target"]["currentTime"].as<double>() * 1000);
+
+ // qt progress is ms
+ emit progressChanged(event["target"]["currentTime"].as<double>() * 1000);
+ };
+ m_timeUpdateEvent.reset(new qstdweb::EventCallback(m_audio, "timeupdate", timeUpdateCallback));
+
+ // pause
+ auto pauseCallback = [&](emscripten::val event) {
+ Q_UNUSED(event)
+ qCDebug(qWasmMediaAudioOutput) << "pause";
+
+ int currentTime = m_audio["currentTime"].as<int>(); // in seconds
+ int duration = m_audio["duration"].as<int>(); // in seconds
+ if ((currentTime > 0 && currentTime < duration)) {
+ emit stateChanged(QWasmMediaPlayer::Paused);
+ } else {
+ emit stateChanged(QWasmMediaPlayer::Stopped);
+ }
+ };
+ m_pauseChangeEvent.reset(new qstdweb::EventCallback(m_audio, "pause", pauseCallback));
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/wasm/common/qwasmaudiooutput_p.h b/src/plugins/multimedia/wasm/common/qwasmaudiooutput_p.h
index b8a79065d..db121783d 100644
--- a/src/plugins/multimedia/wasm/common/qwasmaudiooutput_p.h
+++ b/src/plugins/multimedia/wasm/common/qwasmaudiooutput_p.h
@@ -16,18 +16,76 @@
//
#include <private/qplatformaudiooutput_p.h>
+#include "qwasmmediaplayer_p.h"
+
+#include <emscripten/val.h>
+#include <private/qstdweb_p.h>
+#include <private/qwasmaudiosink_p.h>
+#include <QIODevice>
+#include <QObject>
QT_BEGIN_NAMESPACE
-class Q_MULTIMEDIA_EXPORT QWasmAudioOutput : public QPlatformAudioOutput
+class Q_MULTIMEDIA_EXPORT QWasmAudioOutput : public QObject, public QPlatformAudioOutput
{
+ Q_OBJECT
+
public:
QWasmAudioOutput(QAudioOutput *qq);
~QWasmAudioOutput();
- void setAudioDevice(const QAudioDevice &device);
- void setMuted(bool muted);
- void setVolume(float volume);
+ enum AudioElementError {
+ MEDIA_ERR_ABORTED = 1,
+ MEDIA_ERR_NETWORK,
+ MEDIA_ERR_DECODE,
+ MEDIA_ERR_SRC_NOT_SUPPORTED
+ };
+
+ void setAudioDevice(const QAudioDevice &device) final;
+ void setMuted(bool muted) override;
+ void setVolume(float volume) override;
+
+ void start();
+ void stop();
+ void pause();
+
+ void setSource(const QUrl &url);
+ void setSource(QIODevice *stream);
+
+Q_SIGNALS:
+ void readyChanged(bool);
+ void bufferingChanged(qint32 percent);
+ void errorOccured(qint32 code, const QString &message);
+ void stateChanged(QWasmMediaPlayer::QWasmMediaPlayerState newState);
+ void progressChanged(qint32 position);
+ void durationChanged(qint64 duration);
+ void statusChanged(QMediaPlayer::MediaStatus status);
+ void sizeChange(qint32 width, qint32 height);
+ void metaDataLoaded();
+
+private:
+ void doElementCallbacks();
+ void createAudioElement(const std::string &id);
+
+ QScopedPointer<QWasmAudioSink> m_sink;
+ QScopedPointer<qstdweb::EventCallback> m_playEvent;
+ QScopedPointer<qstdweb::EventCallback> m_endedEvent;
+ QScopedPointer<qstdweb::EventCallback> m_durationChangeEvent;
+ QScopedPointer<qstdweb::EventCallback> m_errorChangeEvent;
+ QScopedPointer<qstdweb::EventCallback> m_canPlayChangeEvent;
+ QScopedPointer<qstdweb::EventCallback> m_canPlayThroughChangeEvent;
+
+ QScopedPointer<qstdweb::EventCallback> m_playingChangeEvent;
+ QScopedPointer<qstdweb::EventCallback> m_progressChangeEvent;
+ QScopedPointer<qstdweb::EventCallback> m_pauseChangeEvent;
+ QScopedPointer<qstdweb::EventCallback> m_timeUpdateEvent;
+ QScopedPointer<qstdweb::EventCallback> m_loadedDataEvent;
+
+ QString m_source;
+ QIODevice *m_audioIODevice = nullptr;
+ emscripten::val m_audio = emscripten::val::undefined();
+ QMediaPlayer::MediaStatus m_currentMediaStatus;
+ qreal m_currentBufferedValue;
};
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/wasm/common/qwasmvideooutput.cpp b/src/plugins/multimedia/wasm/common/qwasmvideooutput.cpp
index 3b0751f1a..4aa133ef9 100644
--- a/src/plugins/multimedia/wasm/common/qwasmvideooutput.cpp
+++ b/src/plugins/multimedia/wasm/common/qwasmvideooutput.cpp
@@ -446,7 +446,10 @@ void QWasmVideoOutput::createVideoElement(const std::string &id)
body.call<void>("appendChild", m_video);
// Create/add video source
- m_video.set("src", m_source.toStdString());
+ emscripten::val videoElementGeometry =
+ document.call<emscripten::val>("createElement", std::string("source"));
+
+ videoElementGeometry.set("src", m_source.toStdString());
// Set position:absolute, which makes it possible to position the video
// element using x,y. coordinates, relative to its parent (the page's <body>
diff --git a/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp b/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp
index 1e30b092e..39074b31d 100644
--- a/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp
+++ b/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp
@@ -20,7 +20,7 @@ QWasmMediaPlayer::QWasmMediaPlayer(QMediaPlayer *parent)
m_State(QWasmMediaPlayer::Idle)
{
qCDebug(lcMediaPlayer) << Q_FUNC_INFO << this;
- initVideo();
+
}
QWasmMediaPlayer::~QWasmMediaPlayer()
@@ -44,7 +44,7 @@ void QWasmMediaPlayer::initVideo()
connect(m_videoOutput, &QWasmVideoOutput::errorOccured, this,
&QWasmMediaPlayer::errorOccured);
connect(m_videoOutput, &QWasmVideoOutput::stateChanged, this,
- &QWasmMediaPlayer::videoStateChanged);
+ &QWasmMediaPlayer::mediaStateChanged);
connect(m_videoOutput, &QWasmVideoOutput::progressChanged, this,
&QWasmMediaPlayer::setPositionChanged);
connect(m_videoOutput, &QWasmVideoOutput::durationChanged, this,
@@ -58,8 +58,32 @@ void QWasmMediaPlayer::initVideo()
connect(m_videoOutput, &QWasmVideoOutput::metaDataLoaded, this,
&QWasmMediaPlayer::videoMetaDataChanged);
+ setVideoAvailable(true);
}
+void QWasmMediaPlayer::initAudio()
+{
+ connect(m_audioOutput->q, &QAudioOutput::deviceChanged,
+ this, &QWasmMediaPlayer::updateAudioDevice);
+ connect(m_audioOutput->q, &QAudioOutput::volumeChanged,
+ this, &QWasmMediaPlayer::volumeChanged);
+ connect(m_audioOutput->q, &QAudioOutput::mutedChanged,
+ this, &QWasmMediaPlayer::mutedChanged);
+
+ connect(m_audioOutput, &QWasmAudioOutput::bufferingChanged, this,
+ &QWasmMediaPlayer::bufferingChanged);
+ connect(m_audioOutput, &QWasmAudioOutput::errorOccured, this,
+ &QWasmMediaPlayer::errorOccured);
+ connect(m_audioOutput, &QWasmAudioOutput::progressChanged, this,
+ &QWasmMediaPlayer::setPositionChanged);
+ connect(m_audioOutput, &QWasmAudioOutput::durationChanged, this,
+ &QWasmMediaPlayer::setDurationChanged);
+ connect(m_audioOutput, &QWasmAudioOutput::statusChanged, this,
+ &QWasmMediaPlayer::onMediaStatusChanged);
+ connect(m_audioOutput, &QWasmAudioOutput::stateChanged, this,
+ &QWasmMediaPlayer::mediaStateChanged);
+ setAudioAvailable(true);
+}
qint64 QWasmMediaPlayer::duration() const
{
@@ -178,17 +202,25 @@ const QIODevice *QWasmMediaPlayer::mediaStream() const
void QWasmMediaPlayer::setMedia(const QUrl &mediaContent, QIODevice *stream)
{
- qDebug() << Q_FUNC_INFO << mediaContent;
+ qDebug() << Q_FUNC_INFO << mediaContent << isVideoAvailable()
+ << isAudioAvailable();
if (mediaContent.isEmpty()) {
if (stream) {
m_mediaStream = stream;
- m_videoOutput->setSource(m_mediaStream);
+ if (isVideoAvailable())
+ m_videoOutput->setSource(m_mediaStream);
+ else
+ m_audioOutput->setSource(m_mediaStream);
} else {
setMediaStatus(QMediaPlayer::NoMedia);
}
} else {
- m_videoOutput->setSource(mediaContent);
+ if (isVideoAvailable())
+ m_videoOutput->setSource(mediaContent);
+ else
+ m_audioOutput->setSource(mediaContent);
}
+
resetBufferingProgress();
}
@@ -202,6 +234,7 @@ void QWasmMediaPlayer::setVideoSink(QVideoSink *sink)
if (!m_videoSink)
return;
+ initVideo();
m_videoOutput->setSurface(sink);
}
@@ -213,22 +246,12 @@ void QWasmMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
if (m_audioOutput)
m_audioOutput->q->disconnect(this);
m_audioOutput = static_cast<QWasmAudioOutput *>(output);
-
- if (!m_audioOutput)
- return;
-
- connect(m_audioOutput->q, &QAudioOutput::deviceChanged, this,
- &QWasmMediaPlayer::updateAudioDevice);
- connect(m_audioOutput->q, &QAudioOutput::volumeChanged, this, &QWasmMediaPlayer::volumeChanged);
- connect(m_audioOutput->q, &QAudioOutput::mutedChanged, this, &QWasmMediaPlayer::mutedChanged);
- updateAudioDevice();
}
void QWasmMediaPlayer::updateAudioDevice()
{
if (m_audioOutput) {
- // we have only one audio device
- // mMediaPlayer->setAudioOutput(m_audioOutput->device.id());
+ m_audioOutput->setAudioDevice(m_audioOutput->q->device());
}
}
@@ -239,6 +262,11 @@ void QWasmMediaPlayer::play()
if (isVideoAvailable()) {
m_videoOutput->start();
m_playWhenReady = true;
+ } else {
+ initAudio();
+ if (isAudioAvailable()) {
+ m_audioOutput->start();
+ }
}
#ifdef DEBUG_AUDIOENGINE
@@ -248,15 +276,17 @@ void QWasmMediaPlayer::play()
void QWasmMediaPlayer::pause()
{
- stateChanged(QMediaPlayer::PausedState);
-
if ((m_State
& (QWasmMediaPlayer::Started | QWasmMediaPlayer::Paused
- | QWasmMediaPlayer::PlaybackCompleted))
- == 0) {
+ | QWasmMediaPlayer::PlaybackCompleted)) == 0) {
return;
}
- m_videoOutput->pause();
+ if (isVideoAvailable()) {
+ m_videoOutput->pause();
+ } else {
+ m_audioOutput->pause();
+ stateChanged(QMediaPlayer::PausedState);
+ }
}
void QWasmMediaPlayer::stop()
@@ -265,10 +295,16 @@ void QWasmMediaPlayer::stop()
if (m_State == QWasmMediaPlayer::Idle || m_State == QWasmMediaPlayer::PlaybackCompleted
|| m_State == QWasmMediaPlayer::Stopped) {
+ qWarning() << Q_FUNC_INFO << __LINE__;
return;
}
- m_videoOutput->stop();
+ if (isVideoAvailable()) {
+ m_videoOutput->stop();
+ } else {
+ m_audioOutput->stop();
+ }
+
}
bool QWasmMediaPlayer::isSeekable() const
@@ -316,7 +352,7 @@ void QWasmMediaPlayer::videoSizeChanged(qint32 width, qint32 height)
m_videoSize = newSize;
}
-void QWasmMediaPlayer::videoStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state)
+void QWasmMediaPlayer::mediaStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state)
{
m_State = state;
QMediaPlayer::PlaybackState m_mediaPlayerState;
diff --git a/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer_p.h b/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer_p.h
index f48b0b42b..9269ecdb6 100644
--- a/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer_p.h
+++ b/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer_p.h
@@ -79,7 +79,7 @@ private Q_SLOTS:
void errorOccured(qint32 code, const QString &message);
void bufferingChanged(qint32 percent);
void videoSizeChanged(qint32 width, qint32 height);
- void videoStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state);
+ void mediaStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state);
void setPositionChanged(qint64 position);
void setDurationChanged(qint64 duration);
void videoMetaDataChanged();
@@ -96,6 +96,7 @@ private:
void setSubtitle(QString subtitle);
void disableTrack(TrackType trackType);
void initVideo();
+ void initAudio();
friend class StateChangeNotifier;