diff options
Diffstat (limited to 'src/plugins/qnx/mediaplayer')
16 files changed, 647 insertions, 106 deletions
diff --git a/src/plugins/qnx/mediaplayer/mediaplayer.pri b/src/plugins/qnx/mediaplayer/mediaplayer.pri index 4c4363a91..f39b542cc 100644 --- a/src/plugins/qnx/mediaplayer/mediaplayer.pri +++ b/src/plugins/qnx/mediaplayer/mediaplayer.pri @@ -1,6 +1,7 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/mmrendereraudiorolecontrol.h \ $$PWD/mmrenderermediaplayercontrol.h \ $$PWD/mmrenderermediaplayerservice.h \ $$PWD/mmrenderermetadata.h \ @@ -9,8 +10,10 @@ HEADERS += \ $$PWD/mmrendererutil.h \ $$PWD/mmrenderervideowindowcontrol.h \ $$PWD/mmreventmediaplayercontrol.h \ - $$PWD/mmreventthread.h + $$PWD/mmreventthread.h \ + $$PWD/mmrenderercustomaudiorolecontrol.h SOURCES += \ + $$PWD/mmrendereraudiorolecontrol.cpp \ $$PWD/mmrenderermediaplayercontrol.cpp \ $$PWD/mmrenderermediaplayerservice.cpp \ $$PWD/mmrenderermetadata.cpp \ @@ -19,6 +22,7 @@ SOURCES += \ $$PWD/mmrendererutil.cpp \ $$PWD/mmrenderervideowindowcontrol.cpp \ $$PWD/mmreventmediaplayercontrol.cpp \ - $$PWD/mmreventthread.cpp + $$PWD/mmreventthread.cpp \ + $$PWD/mmrenderercustomaudiorolecontrol.cpp QMAKE_USE += mmrenderer diff --git a/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.cpp b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.cpp new file mode 100644 index 000000000..e470ed4c5 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrendereraudiorolecontrol.h" +#include "mmrendererutil.h" + +QT_BEGIN_NAMESPACE + +MmRendererAudioRoleControl::MmRendererAudioRoleControl(QObject *parent) + : QAudioRoleControl(parent) + , m_role(QAudio::UnknownRole) +{ +} + +QAudio::Role MmRendererAudioRoleControl::audioRole() const +{ + return m_role; +} + +void MmRendererAudioRoleControl::setAudioRole(QAudio::Role role) +{ + if (m_role != role) { + m_role = role; + emit audioRoleChanged(m_role); + } +} + +QList<QAudio::Role> MmRendererAudioRoleControl::supportedAudioRoles() const +{ + return qnxSupportedAudioRoles(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.h b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.h new file mode 100644 index 000000000..d0d2165eb --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERAUDIOROLECONTROL_H +#define MMRENDERERAUDIOROLECONTROL_H + +#include <qaudiorolecontrol.h> + +QT_BEGIN_NAMESPACE + +class MmRendererAudioRoleControl : public QAudioRoleControl +{ + Q_OBJECT +public: + explicit MmRendererAudioRoleControl(QObject *parent = 0); + + QAudio::Role audioRole() const override; + void setAudioRole(QAudio::Role role) override; + + QList<QAudio::Role> supportedAudioRoles() const override; + +private: + QAudio::Role m_role; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderercustomaudiorolecontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderercustomaudiorolecontrol.cpp new file mode 100644 index 000000000..c8971d41c --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderercustomaudiorolecontrol.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrenderercustomaudiorolecontrol.h" +#include "mmrendererutil.h" + +QT_BEGIN_NAMESPACE + +MmRendererCustomAudioRoleControl::MmRendererCustomAudioRoleControl(QObject *parent) + : QCustomAudioRoleControl(parent) +{ +} + +QString MmRendererCustomAudioRoleControl::customAudioRole() const +{ + return m_role; +} + +void MmRendererCustomAudioRoleControl::setCustomAudioRole(const QString &role) +{ + if (m_role != role) { + m_role = role; + emit customAudioRoleChanged(m_role); + } +} + +QStringList MmRendererCustomAudioRoleControl::supportedCustomAudioRoles() const +{ + return QStringList(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderercustomaudiorolecontrol.h b/src/plugins/qnx/mediaplayer/mmrenderercustomaudiorolecontrol.h new file mode 100644 index 000000000..ff16f9355 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderercustomaudiorolecontrol.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERCUSTOMAUDIOROLECONTROL_H +#define MMRENDERERCUSTOMAUDIOROLECONTROL_H + +#include <qcustomaudiorolecontrol.h> + +QT_BEGIN_NAMESPACE + +class MmRendererCustomAudioRoleControl : public QCustomAudioRoleControl +{ + Q_OBJECT +public: + explicit MmRendererCustomAudioRoleControl(QObject *parent = 0); + + QString customAudioRole() const Q_DECL_OVERRIDE; + void setCustomAudioRole(const QString &role) Q_DECL_OVERRIDE; + + QStringList supportedCustomAudioRoles() const Q_DECL_OVERRIDE; + +private: + QString m_role; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp index d8b0a3934..c66ac937d 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -36,6 +36,8 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "mmrendereraudiorolecontrol.h" +#include "mmrenderercustomaudiorolecontrol.h" #include "mmrenderermediaplayercontrol.h" #include "mmrenderermetadatareadercontrol.h" #include "mmrendererplayervideorenderercontrol.h" @@ -70,7 +72,6 @@ MmRendererMediaPlayerControl::MmRendererMediaPlayerControl(QObject *parent) m_mediaStatus(QMediaPlayer::NoMedia), m_playAfterMediaLoaded(false), m_inputAttached(false), - m_stopEventsToIgnore(0), m_bufferLevel(0) { m_loadingTimer.setSingleShot(true); @@ -109,35 +110,51 @@ void MmRendererMediaPlayerControl::openConnection() startMonitoring(); } -void MmRendererMediaPlayerControl::handleMmStatusUpdate(qint64 newPosition) -{ - // Prevent spurious position change events from overriding our own position, for example - // when setting the position to 0 in stop(). - // Also, don't change the position while we're loading the media, as then play() would - // set a wrong initial position. - if (m_state != QMediaPlayer::PlayingState || - m_mediaStatus == QMediaPlayer::LoadingMedia || - m_mediaStatus == QMediaPlayer::NoMedia || - m_mediaStatus == QMediaPlayer::InvalidMedia) - return; - - setMmPosition(newPosition); -} - void MmRendererMediaPlayerControl::handleMmStopped() { // Only react to stop events that happen when the end of the stream is reached and // playback is stopped because of this. - // Ignore other stop event sources, souch as calling mmr_stop() ourselves and - // mmr_input_attach(). - if (m_stopEventsToIgnore > 0) { - --m_stopEventsToIgnore; - } else { + // Ignore other stop event sources, such as calling mmr_stop() ourselves. + if (m_state != QMediaPlayer::StoppedState) { setMediaStatus(QMediaPlayer::EndOfMedia); stopInternal(IgnoreMmRenderer); } } +void MmRendererMediaPlayerControl::handleMmSuspend(const QString &reason) +{ + if (m_state == QMediaPlayer::StoppedState) + return; + + Q_UNUSED(reason); + setMediaStatus(QMediaPlayer::StalledMedia); +} + +void MmRendererMediaPlayerControl::handleMmSuspendRemoval(const QString &bufferStatus) +{ + if (m_state == QMediaPlayer::StoppedState) + return; + + if (bufferStatus == QLatin1String("buffering")) + setMediaStatus(QMediaPlayer::BufferingMedia); + else + setMediaStatus(QMediaPlayer::BufferedMedia); +} + +void MmRendererMediaPlayerControl::handleMmPause() +{ + if (m_state == QMediaPlayer::PlayingState) { + setState(QMediaPlayer::PausedState); + } +} + +void MmRendererMediaPlayerControl::handleMmPlay() +{ + if (m_state == QMediaPlayer::PausedState) { + setState(QMediaPlayer::PlayingState); + } +} + void MmRendererMediaPlayerControl::closeConnection() { stopMonitoring(); @@ -184,6 +201,8 @@ void MmRendererMediaPlayerControl::attach() return; } + resetMonitoring(); + if (m_videoRendererControl) m_videoRendererControl->attachDisplay(m_context); @@ -197,6 +216,20 @@ void MmRendererMediaPlayerControl::attach() return; } + if (m_audioId != -1 && m_audioRoleControl) { + QAudio::Role audioRole = m_audioRoleControl->audioRole(); + QString audioType = (audioRole == QAudio::CustomRole && m_customAudioRoleControl) + ? m_customAudioRoleControl->customAudioRole() + : qnxAudioType(audioRole); + QByteArray latin1AudioType = audioType.toLatin1(); + if (!audioType.isEmpty() && latin1AudioType == audioType) { + strm_dict_t *dict = strm_dict_new(); + dict = strm_dict_set(dict, "audio_type", latin1AudioType.constData()); + if (mmr_output_parameters(m_context, m_audioId, dict) != 0) + emitMmError("mmr_output_parameters: Setting audio_type failed"); + } + } + const QByteArray resourcePath = resourcePathForUrl(m_media.canonicalUrl()); if (resourcePath.isEmpty()) { detach(); @@ -210,11 +243,6 @@ void MmRendererMediaPlayerControl::attach() return; } - // For whatever reason, the mmrenderer sends out a MMR_STOPPED event when calling - // mmr_input_attach() above. Ignore it, as otherwise we'll trigger stopping right after we - // started. - m_stopEventsToIgnore++; - m_inputAttached = true; setMediaStatus(QMediaPlayer::LoadedMedia); @@ -346,12 +374,12 @@ void MmRendererMediaPlayerControl::setState(QMediaPlayer::State state) void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand) { + resetMonitoring(); setPosition(0); if (m_state != QMediaPlayer::StoppedState) { if (stopCommand == StopMmRenderer) { - ++m_stopEventsToIgnore; mmr_stop(m_context); } @@ -509,6 +537,7 @@ void MmRendererMediaPlayerControl::play() if (m_mediaStatus == QMediaPlayer::EndOfMedia) m_position = 0; + resetMonitoring(); setPositionInternal(m_position); setVolumeInternal(m_muted ? 0 : m_volume); setPlaybackRateInternal(m_rate); @@ -519,7 +548,6 @@ void MmRendererMediaPlayerControl::play() return; } - m_stopEventsToIgnore = 0; // once playing, stop events must be proccessed setState( QMediaPlayer::PlayingState); } @@ -556,6 +584,16 @@ void MmRendererMediaPlayerControl::setMetaDataReaderControl(MmRendererMetaDataRe m_metaDataReaderControl = metaDataReaderControl; } +void MmRendererMediaPlayerControl::setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl) +{ + m_audioRoleControl = audioRoleControl; +} + +void MmRendererMediaPlayerControl::setCustomAudioRoleControl(MmRendererCustomAudioRoleControl *customAudioRoleControl) +{ + m_customAudioRoleControl = customAudioRoleControl; +} + void MmRendererMediaPlayerControl::setMmPosition(qint64 newPosition) { if (newPosition != 0 && newPosition != m_position) { @@ -573,18 +611,11 @@ void MmRendererMediaPlayerControl::setMmBufferStatus(const QString &bufferStatus // ignore "idle" buffer status } -void MmRendererMediaPlayerControl::setMmBufferLevel(const QString &bufferLevel) +void MmRendererMediaPlayerControl::setMmBufferLevel(int level, int capacity) { - // buffer level has format level/capacity, e.g. "91319/124402" - const int slashPos = bufferLevel.indexOf('/'); - if (slashPos != -1) { - const int fill = bufferLevel.leftRef(slashPos).toInt(); - const int capacity = bufferLevel.midRef(slashPos + 1).toInt(); - if (capacity != 0) { - m_bufferLevel = fill / static_cast<float>(capacity) * 100.0f; - emit bufferStatusChanged(m_bufferLevel); - } - } + m_bufferLevel = capacity == 0 ? 0 : level / static_cast<float>(capacity) * 100.0f; + m_bufferLevel = qBound(0, m_bufferLevel, 100); + emit bufferStatusChanged(m_bufferLevel); } void MmRendererMediaPlayerControl::updateMetaData(const strm_dict *dict) diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h index 2edbd50e0..3426ef2f2 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h @@ -52,6 +52,8 @@ typedef struct strm_dict strm_dict_t; QT_BEGIN_NAMESPACE +class MmRendererAudioRoleControl; +class MmRendererCustomAudioRoleControl; class MmRendererMetaDataReaderControl; class MmRendererPlayerVideoRendererControl; class MmRendererVideoWindowControl; @@ -62,40 +64,40 @@ class MmRendererMediaPlayerControl : public QMediaPlayerControl, public QAbstrac public: explicit MmRendererMediaPlayerControl(QObject *parent = 0); - QMediaPlayer::State state() const Q_DECL_OVERRIDE; + QMediaPlayer::State state() const override; - QMediaPlayer::MediaStatus mediaStatus() const Q_DECL_OVERRIDE; + QMediaPlayer::MediaStatus mediaStatus() const override; - qint64 duration() const Q_DECL_OVERRIDE; + qint64 duration() const override; - qint64 position() const Q_DECL_OVERRIDE; - void setPosition(qint64 position) Q_DECL_OVERRIDE; + qint64 position() const override; + void setPosition(qint64 position) override; - int volume() const Q_DECL_OVERRIDE; - void setVolume(int volume) Q_DECL_OVERRIDE; + int volume() const override; + void setVolume(int volume) override; - bool isMuted() const Q_DECL_OVERRIDE; - void setMuted(bool muted) Q_DECL_OVERRIDE; + bool isMuted() const override; + void setMuted(bool muted) override; - int bufferStatus() const Q_DECL_OVERRIDE; + int bufferStatus() const override; - bool isAudioAvailable() const Q_DECL_OVERRIDE; - bool isVideoAvailable() const Q_DECL_OVERRIDE; + bool isAudioAvailable() const override; + bool isVideoAvailable() const override; - bool isSeekable() const Q_DECL_OVERRIDE; + bool isSeekable() const override; - QMediaTimeRange availablePlaybackRanges() const Q_DECL_OVERRIDE; + QMediaTimeRange availablePlaybackRanges() const override; - qreal playbackRate() const Q_DECL_OVERRIDE; - void setPlaybackRate(qreal rate) Q_DECL_OVERRIDE; + qreal playbackRate() const override; + void setPlaybackRate(qreal rate) override; - QMediaContent media() const Q_DECL_OVERRIDE; - const QIODevice *mediaStream() const Q_DECL_OVERRIDE; - void setMedia(const QMediaContent &media, QIODevice *stream) Q_DECL_OVERRIDE; + QMediaContent media() const override; + const QIODevice *mediaStream() const override; + void setMedia(const QMediaContent &media, QIODevice *stream) override; - void play() Q_DECL_OVERRIDE; - void pause() Q_DECL_OVERRIDE; - void stop() Q_DECL_OVERRIDE; + void play() override; + void pause() override; + void stop() override; MmRendererPlayerVideoRendererControl *videoRendererControl() const; void setVideoRendererControl(MmRendererPlayerVideoRendererControl *videoControl); @@ -103,19 +105,25 @@ public: MmRendererVideoWindowControl *videoWindowControl() const; void setVideoWindowControl(MmRendererVideoWindowControl *videoControl); void setMetaDataReaderControl(MmRendererMetaDataReaderControl *metaDataReaderControl); + void setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl); + void setCustomAudioRoleControl(MmRendererCustomAudioRoleControl *customAudioRoleControl); protected: virtual void startMonitoring() = 0; virtual void stopMonitoring() = 0; + virtual void resetMonitoring() = 0; void openConnection(); void emitMmError(const QString &msg); void emitPError(const QString &msg); void setMmPosition(qint64 newPosition); void setMmBufferStatus(const QString &bufferStatus); - void setMmBufferLevel(const QString &bufferLevel); + void setMmBufferLevel(int level, int capacity); void handleMmStopped(); - void handleMmStatusUpdate(qint64 position); + void handleMmSuspend(const QString &reason); + void handleMmSuspendRemoval(const QString &bufferStatus); + void handleMmPause(); + void handleMmPlay(); void updateMetaData(const strm_dict_t *dict); // must be called from subclass dtors (calls virtual function stopMonitoring()) @@ -156,12 +164,13 @@ private: QPointer<MmRendererPlayerVideoRendererControl> m_videoRendererControl; QPointer<MmRendererVideoWindowControl> m_videoWindowControl; QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + QPointer<MmRendererAudioRoleControl> m_audioRoleControl; + QPointer<MmRendererCustomAudioRoleControl> m_customAudioRoleControl; MmRendererMetaData m_metaData; qint64 m_position; QMediaPlayer::MediaStatus m_mediaStatus; bool m_playAfterMediaLoaded; bool m_inputAttached; - int m_stopEventsToIgnore; int m_bufferLevel; QTimer m_loadingTimer; }; diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp index 1258d199c..190cb8b80 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp @@ -38,6 +38,8 @@ ****************************************************************************/ #include "mmrenderermediaplayerservice.h" +#include "mmrendereraudiorolecontrol.h" +#include "mmrenderercustomaudiorolecontrol.h" #include "mmrenderermediaplayercontrol.h" #include "mmrenderermetadatareadercontrol.h" #include "mmrendererplayervideorenderercontrol.h" @@ -66,6 +68,8 @@ MmRendererMediaPlayerService::~MmRendererMediaPlayerService() delete m_videoWindowControl; delete m_mediaPlayerControl; delete m_metaDataReaderControl; + delete m_audioRoleControl; + delete m_customAudioRoleControl; } QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) @@ -76,15 +80,25 @@ QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) updateControls(); } return m_mediaPlayerControl; - } - else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { + } else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { if (!m_metaDataReaderControl) { m_metaDataReaderControl = new MmRendererMetaDataReaderControl(); updateControls(); } return m_metaDataReaderControl; - } - else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + } else if (qstrcmp(name, QAudioRoleControl_iid) == 0) { + if (!m_audioRoleControl) { + m_audioRoleControl = new MmRendererAudioRoleControl(); + updateControls(); + } + return m_audioRoleControl; + } else if (qstrcmp(name, QCustomAudioRoleControl_iid) == 0) { + if (!m_customAudioRoleControl) { + m_customAudioRoleControl = new MmRendererCustomAudioRoleControl(); + updateControls(); + } + return m_customAudioRoleControl; + } else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { if (!m_appHasDrmPermissionChecked) { m_appHasDrmPermission = checkForDrmPermission(); m_appHasDrmPermissionChecked = true; @@ -102,8 +116,7 @@ QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) updateControls(); } return m_videoRendererControl; - } - else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { if (!m_videoWindowControl) { m_videoWindowControl = new MmRendererVideoWindowControl(); updateControls(); @@ -123,6 +136,10 @@ void MmRendererMediaPlayerService::releaseControl(QMediaControl *control) m_mediaPlayerControl = 0; if (control == m_metaDataReaderControl) m_metaDataReaderControl = 0; + if (control == m_audioRoleControl) + m_audioRoleControl = 0; + if (control == m_customAudioRoleControl) + m_customAudioRoleControl = 0; delete control; } @@ -136,6 +153,12 @@ void MmRendererMediaPlayerService::updateControls() if (m_metaDataReaderControl && m_mediaPlayerControl) m_mediaPlayerControl->setMetaDataReaderControl(m_metaDataReaderControl); + + if (m_audioRoleControl && m_mediaPlayerControl) + m_mediaPlayerControl->setAudioRoleControl(m_audioRoleControl); + + if (m_customAudioRoleControl && m_mediaPlayerControl) + m_mediaPlayerControl->setCustomAudioRoleControl(m_customAudioRoleControl); } QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h index de85293cb..ab3054af5 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h @@ -44,6 +44,8 @@ QT_BEGIN_NAMESPACE +class MmRendererAudioRoleControl; +class MmRendererCustomAudioRoleControl; class MmRendererMediaPlayerControl; class MmRendererMetaDataReaderControl; class MmRendererPlayerVideoRendererControl; @@ -56,8 +58,8 @@ public: explicit MmRendererMediaPlayerService(QObject *parent = 0); ~MmRendererMediaPlayerService(); - QMediaControl *requestControl(const char *name) Q_DECL_OVERRIDE; - void releaseControl(QMediaControl *control) Q_DECL_OVERRIDE; + QMediaControl *requestControl(const char *name) override; + void releaseControl(QMediaControl *control) override; private: void updateControls(); @@ -66,6 +68,8 @@ private: QPointer<MmRendererVideoWindowControl> m_videoWindowControl; QPointer<MmRendererMediaPlayerControl> m_mediaPlayerControl; QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + QPointer<MmRendererAudioRoleControl> m_audioRoleControl; + QPointer<MmRendererCustomAudioRoleControl> m_customAudioRoleControl; bool m_appHasDrmPermission : 1; bool m_appHasDrmPermissionChecked : 1; diff --git a/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h index 9c000224e..878420460 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h @@ -50,10 +50,10 @@ class MmRendererMetaDataReaderControl : public QMetaDataReaderControl public: explicit MmRendererMetaDataReaderControl(QObject *parent = 0); - bool isMetaDataAvailable() const Q_DECL_OVERRIDE; + bool isMetaDataAvailable() const override; - QVariant metaData(const QString &key) const Q_DECL_OVERRIDE; - QStringList availableMetaData() const Q_DECL_OVERRIDE; + QVariant metaData(const QString &key) const override; + QStringList availableMetaData() const override; void setMetaData(const MmRendererMetaData &data); diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h index 878aa4bb0..c547ef534 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h @@ -56,8 +56,8 @@ public: explicit MmRendererPlayerVideoRendererControl(QObject *parent = 0); ~MmRendererPlayerVideoRendererControl(); - QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE; - void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE; + QAbstractVideoSurface *surface() const override; + void setSurface(QAbstractVideoSurface *surface) override; // Called by media control void attachDisplay(mmr_context_t *context); @@ -65,7 +65,7 @@ public: void pause(); void resume(); - void customEvent(QEvent *) Q_DECL_OVERRIDE; + void customEvent(QEvent *) override; private Q_SLOTS: void updateScene(const QSize &size); diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.cpp b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp index 239d9d52e..d8af4a746 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererutil.cpp +++ b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp @@ -41,6 +41,11 @@ #include <QDebug> #include <QDir> #include <QFile> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonValue> +#include <QMutex> +#include <QMutex> #include <QString> #include <QXmlStreamReader> @@ -85,6 +90,97 @@ static const MmError mmErrors[] = { }; static const unsigned int numMmErrors = sizeof(mmErrors) / sizeof(MmError); +static QBasicMutex roleMapMutex; +static bool roleMapInitialized = false; +static QString roleMap[QAudio::CustomRole + 1]; + +template <typename T, size_t N> +constexpr size_t countof(T (&)[N]) +{ + return N; +} + +constexpr bool inBounds(QAudio::Role r) +{ + return r >= 0 && r < countof(roleMap); +} + +QString keyValueMapsLocation() +{ + QByteArray qtKeyValueMaps = qgetenv("QT_KEY_VALUE_MAPS"); + if (qtKeyValueMaps.isNull()) + return QStringLiteral("/etc/qt/keyvaluemaps"); + else + return qtKeyValueMaps; +} + +QJsonObject loadMapObject(const QString &keyValueMapPath) +{ + QFile mapFile(keyValueMapsLocation() + keyValueMapPath); + if (mapFile.open(QIODevice::ReadOnly)) { + QByteArray mapFileContents = mapFile.readAll(); + QJsonDocument mapDocument = QJsonDocument::fromJson(mapFileContents); + if (mapDocument.isObject()) { + QJsonObject mapObject = mapDocument.object(); + return mapObject; + } + } + return QJsonObject(); +} + +static void loadRoleMap() +{ + QMutexLocker locker(&roleMapMutex); + + if (!roleMapInitialized) { + QJsonObject mapObject = loadMapObject("/QAudio/Role.json"); + if (!mapObject.isEmpty()) { + // Wrapping the loads in a switch like this ensures that anyone adding + // a new enumerator will be notified that this code must be updated. A + // compile error will occur because the enumerator is missing from the + // switch. A compile error will also occur if the enumerator used to + // size the mapping table isn't updated when a new enumerator is added. + // One or more enumerators will be outside the bounds of the array when + // the wrong enumerator is used to size the array. + // + // The code loads a mapping for each enumerator because role is set + // to UnknownRole and all the cases drop through to the next case. +#pragma GCC diagnostic push +#pragma GCC diagnostic error "-Wswitch" +#define loadRoleMapping(r) \ + case QAudio::r: \ + static_assert(inBounds(QAudio::r), #r " out-of-bounds." \ + " Do you need to change the enumerator used to size the mapping table" \ + " because you added new QAudio::Role enumerators?"); \ + roleMap[QAudio::r] = mapObject.value(QLatin1String(#r)).toString(); + + QAudio::Role role = QAudio::UnknownRole; + switch (role) { + loadRoleMapping(UnknownRole); + loadRoleMapping(MusicRole); + loadRoleMapping(VideoRole); + loadRoleMapping(VoiceCommunicationRole); + loadRoleMapping(AlarmRole); + loadRoleMapping(NotificationRole); + loadRoleMapping(RingtoneRole); + loadRoleMapping(AccessibilityRole); + loadRoleMapping(SonificationRole); + loadRoleMapping(GameRole); + loadRoleMapping(CustomRole); + } +#undef loadRoleMapping +#pragma GCC diagnostic pop + + if (!roleMap[QAudio::CustomRole].isEmpty()) { + qWarning("CustomRole mapping ignored"); + roleMap[QAudio::CustomRole].clear(); + } + } + + roleMapInitialized = true; + } +} + QString mmErrorMessage(const QString &msg, mmr_context_t *context, int *errorCode) { const mmr_error_info_t * const mmError = mmr_error_info(context); @@ -124,4 +220,27 @@ bool checkForDrmPermission() return false; } +QString qnxAudioType(QAudio::Role role) +{ + loadRoleMap(); + + if (role >= 0 && role < countof(roleMap)) + return roleMap[role]; + else + return QString(); +} + +QList<QAudio::Role> qnxSupportedAudioRoles() +{ + loadRoleMap(); + + QList<QAudio::Role> result; + for (size_t i = 0; i < countof(roleMap); ++i) { + if (!roleMap[i].isEmpty() || (i == QAudio::UnknownRole)) + result.append(static_cast<QAudio::Role>(i)); + } + + return result; +} + QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.h b/src/plugins/qnx/mediaplayer/mmrendererutil.h index 8017b2690..ac6f73a7d 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererutil.h +++ b/src/plugins/qnx/mediaplayer/mmrendererutil.h @@ -40,6 +40,7 @@ #define MMRENDERERUTIL_H #include <QtCore/qglobal.h> +#include <QtMultimedia/qaudio.h> typedef struct mmr_context mmr_context_t; @@ -51,6 +52,9 @@ QString mmErrorMessage(const QString &msg, mmr_context_t *context, int * errorCo bool checkForDrmPermission(); +QString qnxAudioType(QAudio::Role role); +QList<QAudio::Role> qnxSupportedAudioRoles(); + QT_END_NAMESPACE #endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h index 5bfd192bb..8327e259d 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h @@ -54,33 +54,33 @@ public: explicit MmRendererVideoWindowControl(QObject *parent = 0); ~MmRendererVideoWindowControl(); - WId winId() const Q_DECL_OVERRIDE; - void setWinId(WId id) Q_DECL_OVERRIDE; + WId winId() const override; + void setWinId(WId id) override; - QRect displayRect() const Q_DECL_OVERRIDE; - void setDisplayRect(const QRect &rect) Q_DECL_OVERRIDE; + QRect displayRect() const override; + void setDisplayRect(const QRect &rect) override; - bool isFullScreen() const Q_DECL_OVERRIDE; - void setFullScreen(bool fullScreen) Q_DECL_OVERRIDE; + bool isFullScreen() const override; + void setFullScreen(bool fullScreen) override; - void repaint() Q_DECL_OVERRIDE; + void repaint() override; - QSize nativeSize() const Q_DECL_OVERRIDE; + QSize nativeSize() const override; - Qt::AspectRatioMode aspectRatioMode() const Q_DECL_OVERRIDE; - void setAspectRatioMode(Qt::AspectRatioMode mode) Q_DECL_OVERRIDE; + Qt::AspectRatioMode aspectRatioMode() const override; + void setAspectRatioMode(Qt::AspectRatioMode mode) override; - int brightness() const Q_DECL_OVERRIDE; - void setBrightness(int brightness) Q_DECL_OVERRIDE; + int brightness() const override; + void setBrightness(int brightness) override; - int contrast() const Q_DECL_OVERRIDE; - void setContrast(int contrast) Q_DECL_OVERRIDE; + int contrast() const override; + void setContrast(int contrast) override; - int hue() const Q_DECL_OVERRIDE; - void setHue(int hue) Q_DECL_OVERRIDE; + int hue() const override; + void setHue(int hue) override; - int saturation() const Q_DECL_OVERRIDE; - void setSaturation(int saturation) Q_DECL_OVERRIDE; + int saturation() const override; + void setSaturation(int saturation) override; // // Called by media control diff --git a/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp index a0bac1261..c050c03c5 100644 --- a/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp @@ -42,13 +42,39 @@ #include "mmrenderervideowindowcontrol.h" #include <mm/renderer.h> +#include <tuple> QT_BEGIN_NAMESPACE +static std::tuple<int, int, bool> parseBufferLevel(const QByteArray &value) +{ + const int slashPos = value.indexOf('/'); + if (slashPos <= 0) + return std::make_tuple(0, 0, false); + + bool ok = false; + const int level = value.left(slashPos).toInt(&ok); + if (!ok || level < 0) + return std::make_tuple(0, 0, false); + + const int capacity = value.mid(slashPos + 1).toInt(&ok); + if (!ok || capacity < 0) + return std::make_tuple(0, 0, false); + + return std::make_tuple(level, capacity, true); +} + MmrEventMediaPlayerControl::MmrEventMediaPlayerControl(QObject *parent) : MmRendererMediaPlayerControl(parent) , m_eventThread(nullptr) + , m_bufferStatus("") + , m_bufferLevel(0) + , m_bufferCapacity(0) + , m_position(0) + , m_suspended(false) + , m_suspendedReason("unknown") , m_state(MMR_STATE_IDLE) + , m_speed(0) { openConnection(); } @@ -75,6 +101,18 @@ void MmrEventMediaPlayerControl::stopMonitoring() m_eventThread = nullptr; } +void MmrEventMediaPlayerControl::resetMonitoring() +{ + m_bufferStatus = ""; + m_bufferLevel = 0; + m_bufferCapacity = 0; + m_position = 0; + m_suspended = false; + m_suspendedReason = "unknown"; + m_state = MMR_STATE_IDLE; + m_speed = 0; +} + bool MmrEventMediaPlayerControl::nativeEventFilter(const QByteArray &eventType, void *message, long *result) @@ -102,32 +140,68 @@ void MmrEventMediaPlayerControl::readEvents() if (event->data) { const strm_string_t *value; value = strm_dict_find_rstr(event->data, "bufferstatus"); - if (value) - setMmBufferStatus(QString::fromLatin1(strm_string_get(value))); + if (value) { + m_bufferStatus = QByteArray(strm_string_get(value)); + if (!m_suspended) + setMmBufferStatus(m_bufferStatus); + } value = strm_dict_find_rstr(event->data, "bufferlevel"); - if (value) - setMmBufferLevel(QString::fromLatin1(strm_string_get(value))); + if (value) { + const char *cstrValue = strm_string_get(value); + int level; + int capacity; + bool ok; + std::tie(level, capacity, ok) = parseBufferLevel(QByteArray(cstrValue)); + if (!ok) { + qCritical("Could not parse buffer capacity from '%s'", cstrValue); + } else { + m_bufferLevel = level; + m_bufferCapacity = capacity; + setMmBufferLevel(level, capacity); + } + } + + value = strm_dict_find_rstr(event->data, "suspended"); + if (value) { + if (!m_suspended) { + m_suspended = true; + m_suspendedReason = strm_string_get(value); + handleMmSuspend(m_suspendedReason); + } + } else if (m_suspended) { + m_suspended = false; + handleMmSuspendRemoval(m_bufferStatus); + } } if (event->pos_str) { const QByteArray valueBa = QByteArray(event->pos_str); bool ok; - const qint64 position = valueBa.toLongLong(&ok); + m_position = valueBa.toLongLong(&ok); if (!ok) { qCritical("Could not parse position from '%s'", valueBa.constData()); } else { - setMmPosition(position); + setMmPosition(m_position); } } break; } + case MMR_EVENT_STATE: { + if (event->state == MMR_STATE_PLAYING && m_speed != event->speed) { + m_speed = event->speed; + if (m_speed == 0) + handleMmPause(); + else + handleMmPlay(); + } + break; + } case MMR_EVENT_METADATA: { updateMetaData(event->data); break; } case MMR_EVENT_ERROR: - case MMR_EVENT_STATE: case MMR_EVENT_NONE: case MMR_EVENT_OVERFLOW: case MMR_EVENT_WARNING: diff --git a/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h index e0aa952a7..0e4defc5c 100644 --- a/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class MmrEventThread; -class MmrEventMediaPlayerControl Q_DECL_FINAL : public MmRendererMediaPlayerControl +class MmrEventMediaPlayerControl final : public MmRendererMediaPlayerControl { Q_OBJECT public: @@ -56,6 +56,7 @@ public: void startMonitoring() override; void stopMonitoring() override; + void resetMonitoring() override; bool nativeEventFilter(const QByteArray &eventType, void *message, @@ -66,7 +67,18 @@ private Q_SLOTS: private: MmrEventThread *m_eventThread; + + // status properties. + QByteArray m_bufferStatus; + int m_bufferLevel; + int m_bufferCapacity; + qint64 m_position; + bool m_suspended; + QByteArray m_suspendedReason; + + // state properties. mmr_state_t m_state; + int m_speed; }; QT_END_NAMESPACE |