diff options
author | Lorn Potter <lorn.potter@gmail.com> | 2023-01-16 14:21:04 +1000 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-02-24 01:49:35 +0000 |
commit | 42ae5cca5781435f02d62d34f9e0d76ac4d4e008 (patch) | |
tree | 906345cbca05cc81862eb2a6304989221852dedb | |
parent | d00db71624981534e5ba8bf04da4c28dce44583f (diff) | |
download | qtmultimedia-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>
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; |