diff options
Diffstat (limited to 'src/plugins')
15 files changed, 464 insertions, 63 deletions
diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm index d657dc17d..0b31bd0bc 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm @@ -49,6 +49,7 @@ #include "avfmediacontainercontrol.h" #include "avfcamerautility.h" +#include <QtCore/qmath.h> #include <QtCore/qdebug.h> QT_USE_NAMESPACE @@ -273,14 +274,11 @@ void AVFMediaRecorderControlIOS::setState(QMediaRecorder::State state) else rotation = (screenOrientation + (360 - cameraInfo.orientation)) % 360; - // convert to radians - rotation *= M_PI / 180.f; - if ([m_writer setupWithFileURL:nsFileURL cameraService:m_service audioSettings:m_audioSettings videoSettings:m_videoSettings - transform:CGAffineTransformMakeRotation(rotation)]) { + transform:CGAffineTransformMakeRotation(qDegreesToRadians(rotation))]) { m_state = QMediaRecorder::RecordingState; m_lastStatus = QMediaRecorder::StartingStatus; diff --git a/src/plugins/gstreamer/common.pri b/src/plugins/gstreamer/common.pri index cbe87be4f..d0c5c7bdd 100644 --- a/src/plugins/gstreamer/common.pri +++ b/src/plugins/gstreamer/common.pri @@ -1,12 +1,10 @@ -QT += core-private multimedia-private network +QT += core-private multimedia-private multimediagsttools-private network qtHaveModule(widgets) { QT += widgets multimediawidgets-private DEFINES += HAVE_WIDGETS } -LIBS += -lqgsttools_p - QMAKE_USE += gstreamer qtConfig(resourcepolicy): \ diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp index d08d01e6d..c4c09f543 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp @@ -43,19 +43,24 @@ #include <private/qaudiohelpers_p.h> +#pragma GCC diagnostic ignored "-Wvla" + QT_BEGIN_NAMESPACE QnxAudioOutput::QnxAudioOutput() - : m_source(0), - m_pushSource(false), - m_notifyInterval(1000), - m_error(QAudio::NoError), - m_state(QAudio::StoppedState), - m_volume(1.0), - m_periodSize(0), - m_pcmHandle(0), - m_bytesWritten(0), - m_intervalOffset(0) + : m_source(0) + , m_pushSource(false) + , m_notifyInterval(1000) + , m_error(QAudio::NoError) + , m_state(QAudio::StoppedState) + , m_volume(1.0) + , m_periodSize(0) + , m_pcmHandle(0) + , m_bytesWritten(0) + , m_intervalOffset(0) +#if _NTO_VERSION >= 700 + , m_pcmNotifier(0) +#endif { m_timer.setSingleShot(false); m_timer.setInterval(20); @@ -124,20 +129,16 @@ void QnxAudioOutput::reset() void QnxAudioOutput::suspend() { - m_timer.stop(); snd_pcm_playback_pause(m_pcmHandle); - setState(QAudio::SuspendedState); + if (state() != QAudio::InterruptedState) + suspendInternal(QAudio::SuspendedState); } void QnxAudioOutput::resume() { snd_pcm_playback_resume(m_pcmHandle); - if (m_pushSource) - setState(QAudio::IdleState); - else { - setState(QAudio::ActiveState); - m_timer.start(); - } + if (state() != QAudio::InterruptedState) + resumeInternal(); } int QnxAudioOutput::bytesFree() const @@ -146,6 +147,7 @@ int QnxAudioOutput::bytesFree() const return 0; snd_pcm_channel_status_t status; + memset(&status, 0, sizeof(status)); status.channel = SND_PCM_CHANNEL_PLAYBACK; const int errorCode = snd_pcm_plugin_status(m_pcmHandle, &status); @@ -214,9 +216,21 @@ qreal QnxAudioOutput::volume() const return m_volume; } +void QnxAudioOutput::setCategory(const QString &category) +{ + m_category = category; +} + +QString QnxAudioOutput::category() const +{ + return m_category; +} + void QnxAudioOutput::pullData() { - if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState) + if (m_state == QAudio::StoppedState + || m_state == QAudio::SuspendedState + || m_state == QAudio::InterruptedState) return; const int bytesAvailable = bytesFree(); @@ -290,6 +304,8 @@ bool QnxAudioOutput::open() return false; } + addPcmEventFilter(); + // Necessary so that bytesFree() which uses the "free" member of the status struct works snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_MMAP); @@ -303,6 +319,7 @@ bool QnxAudioOutput::open() } snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format, QAudio::AudioOutput, info.max_fragment_size); + setTypeName(¶ms); if ((errorCode = snd_pcm_plugin_params(m_pcmHandle, ¶ms)) < 0) { qWarning("QnxAudioOutput: open error, couldn't set channel params (0x%x)", -errorCode); @@ -331,6 +348,8 @@ bool QnxAudioOutput::open() m_intervalOffset = 0; m_bytesWritten = 0; + createPcmNotifiers(); + return true; } @@ -338,6 +357,8 @@ void QnxAudioOutput::close() { m_timer.stop(); + destroyPcmNotifiers(); + if (m_pcmHandle) { snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK); snd_pcm_close(m_pcmHandle); @@ -400,6 +421,109 @@ qint64 QnxAudioOutput::write(const char *data, qint64 len) } } +void QnxAudioOutput::suspendInternal(QAudio::State suspendState) +{ + m_timer.stop(); + setState(suspendState); +} + +void QnxAudioOutput::resumeInternal() +{ + if (m_pushSource) { + setState(QAudio::IdleState); + } else { + setState(QAudio::ActiveState); + m_timer.start(); + } +} + +#if _NTO_VERSION >= 700 + +QAudio::State suspendState(const snd_pcm_event_t &event) +{ + Q_ASSERT(event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS); + Q_ASSERT(event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED); + return event.data.audiomgmt_status.flags & SND_PCM_STATUS_EVENT_HARD_SUSPEND + ? QAudio::InterruptedState : QAudio::SuspendedState; +} + +void QnxAudioOutput::addPcmEventFilter() +{ + /* Enable PCM events */ + snd_pcm_filter_t filter; + memset(&filter, 0, sizeof(filter)); + filter.enable = (1<<SND_PCM_EVENT_AUDIOMGMT_STATUS) | + (1<<SND_PCM_EVENT_AUDIOMGMT_MUTE) | + (1<<SND_PCM_EVENT_OUTPUTCLASS); + snd_pcm_set_filter(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &filter); +} + +void QnxAudioOutput::createPcmNotifiers() +{ + // QSocketNotifier::Read for poll based event dispatcher. Exception for + // select based event dispatcher. + m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle, + SND_PCM_CHANNEL_PLAYBACK), + QSocketNotifier::Read, this); + connect(m_pcmNotifier, &QSocketNotifier::activated, + this, &QnxAudioOutput::pcmNotifierActivated); +} + +void QnxAudioOutput::destroyPcmNotifiers() +{ + if (m_pcmNotifier) { + delete m_pcmNotifier; + m_pcmNotifier = 0; + } +} + +void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *params) +{ + if (m_category.isEmpty()) + return; + + QByteArray latin1Category = m_category.toLatin1(); + + if (QString::fromLatin1(latin1Category) != m_category) { + qWarning("QnxAudioOutput: audio category name isn't a Latin1 string."); + return; + } + + if (latin1Category.size() >= static_cast<int>(sizeof(params->audio_type_name))) { + qWarning("QnxAudioOutput: audio category name too long."); + return; + } + + strcpy(params->audio_type_name, latin1Category.constData()); +} + +void QnxAudioOutput::pcmNotifierActivated(int socket) +{ + Q_UNUSED(socket); + + snd_pcm_event_t pcm_event; + memset(&pcm_event, 0, sizeof(pcm_event)); + while (snd_pcm_channel_read_event(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &pcm_event) == 0) { + if (pcm_event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS) { + if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED) + suspendInternal(suspendState(pcm_event)); + else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_RUNNING) + resumeInternal(); + else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_PAUSED) + suspendInternal(QAudio::SuspendedState); + } + } +} + +#else + +void QnxAudioOutput::addPcmEventFilter() {} +void QnxAudioOutput::createPcmNotifiers() {} +void QnxAudioOutput::destroyPcmNotifiers() {} +void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *) {} + +#endif + QnxPushIODevice::QnxPushIODevice(QnxAudioOutput *output) : QIODevice(output), m_output(output) diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.h b/src/plugins/qnx-audio/audio/qnxaudiooutput.h index 5ee69b542..85aadf4b9 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.h +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.h @@ -45,8 +45,10 @@ #include <QTime> #include <QTimer> #include <QIODevice> +#include <QSocketNotifier> #include <sys/asoundlib.h> +#include <sys/neutrino.h> QT_BEGIN_NAMESPACE @@ -80,6 +82,8 @@ public: QAudioFormat format() const Q_DECL_OVERRIDE; void setVolume(qreal volume) Q_DECL_OVERRIDE; qreal volume() const Q_DECL_OVERRIDE; + void setCategory(const QString &category) Q_DECL_OVERRIDE; + QString category() const Q_DECL_OVERRIDE; private slots: void pullData(); @@ -90,6 +94,14 @@ private: void setError(QAudio::Error error); void setState(QAudio::State state); + void addPcmEventFilter(); + void createPcmNotifiers(); + void destroyPcmNotifiers(); + void setTypeName(snd_pcm_channel_params_t *params); + + void suspendInternal(QAudio::State suspendState); + void resumeInternal(); + friend class QnxPushIODevice; qint64 write(const char *data, qint64 len); @@ -102,6 +114,7 @@ private: QAudio::State m_state; QAudioFormat m_format; qreal m_volume; + QString m_category; int m_periodSize; snd_pcm_t *m_pcmHandle; @@ -109,6 +122,13 @@ private: QTime m_startTimeStamp; QTime m_intervalTimeStamp; qint64 m_intervalOffset; + +#if _NTO_VERSION >= 700 + QSocketNotifier *m_pcmNotifier; + +private slots: + void pcmNotifierActivated(int socket); +#endif }; class QnxPushIODevice : public QIODevice diff --git a/src/plugins/qnx/mediaplayer/mediaplayer.pri b/src/plugins/qnx/mediaplayer/mediaplayer.pri index 756857cce..0871f34bc 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 \ @@ -10,6 +11,7 @@ HEADERS += \ $$PWD/mmrenderervideowindowcontrol.h \ $$PWD/ppsmediaplayercontrol.h SOURCES += \ + $$PWD/mmrendereraudiorolecontrol.cpp \ $$PWD/mmrenderermediaplayercontrol.cpp \ $$PWD/mmrenderermediaplayerservice.cpp \ $$PWD/mmrenderermetadata.cpp \ 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..7458d3512 --- /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 Q_DECL_OVERRIDE; + void setAudioRole(QAudio::Role role) Q_DECL_OVERRIDE; + + QList<QAudio::Role> supportedAudioRoles() const Q_DECL_OVERRIDE; + +private: + QAudio::Role m_role; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp index 5cd3bc3d2..0350958de 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -36,6 +36,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "mmrendereraudiorolecontrol.h" #include "mmrenderermediaplayercontrol.h" #include "mmrenderermetadatareadercontrol.h" #include "mmrendererplayervideorenderercontrol.h" @@ -70,7 +71,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,30 +109,12 @@ void MmRendererMediaPlayerControl::openConnection() startMonitoring(m_id, m_contextName); } -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); } @@ -197,6 +179,17 @@ void MmRendererMediaPlayerControl::attach() return; } + if (m_audioId != -1 && m_audioRoleControl) { + QString audioType = qnxAudioType(m_audioRoleControl->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 +203,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); @@ -351,7 +339,6 @@ void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand) if (m_state != QMediaPlayer::StoppedState) { if (stopCommand == StopMmRenderer) { - ++m_stopEventsToIgnore; mmr_stop(m_context); } @@ -524,7 +511,6 @@ void MmRendererMediaPlayerControl::play() return; } - m_stopEventsToIgnore = 0; // once playing, stop events must be proccessed setState( QMediaPlayer::PlayingState); } @@ -561,6 +547,11 @@ void MmRendererMediaPlayerControl::setMetaDataReaderControl(MmRendererMetaDataRe m_metaDataReaderControl = metaDataReaderControl; } +void MmRendererMediaPlayerControl::setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl) +{ + m_audioRoleControl = audioRoleControl; +} + void MmRendererMediaPlayerControl::setMmPosition(qint64 newPosition) { if (newPosition != 0 && newPosition != m_position) { diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h index 00f70db34..655570656 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h @@ -51,6 +51,7 @@ typedef struct mmrenderer_monitor mmrenderer_monitor_t; QT_BEGIN_NAMESPACE +class MmRendererAudioRoleControl; class MmRendererMetaDataReaderControl; class MmRendererPlayerVideoRendererControl; class MmRendererVideoWindowControl; @@ -102,6 +103,7 @@ public: MmRendererVideoWindowControl *videoWindowControl() const; void setVideoWindowControl(MmRendererVideoWindowControl *videoControl); void setMetaDataReaderControl(MmRendererMetaDataReaderControl *metaDataReaderControl); + void setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl); protected: virtual void startMonitoring(int contextId, const QString &contextName) = 0; @@ -115,7 +117,6 @@ protected: void setMmBufferStatus(const QString &bufferStatus); void setMmBufferLevel(const QString &bufferLevel); void handleMmStopped(); - void handleMmStatusUpdate(qint64 position); // must be called from subclass dtors (calls virtual function stopMonitoring()) void destroy(); @@ -154,13 +155,13 @@ private: QPointer<MmRendererPlayerVideoRendererControl> m_videoRendererControl; QPointer<MmRendererVideoWindowControl> m_videoWindowControl; QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + QPointer<MmRendererAudioRoleControl> m_audioRoleControl; MmRendererMetaData m_metaData; int m_id; 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 e253c68d8..6136f9465 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "mmrenderermediaplayerservice.h" +#include "mmrendereraudiorolecontrol.h" #include "mmrenderermediaplayercontrol.h" #include "mmrenderermetadatareadercontrol.h" #include "mmrendererplayervideorenderercontrol.h" @@ -66,6 +67,7 @@ MmRendererMediaPlayerService::~MmRendererMediaPlayerService() delete m_videoWindowControl; delete m_mediaPlayerControl; delete m_metaDataReaderControl; + delete m_audioRoleControl; } QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) @@ -76,15 +78,19 @@ 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, QVideoRendererControl_iid) == 0) { if (!m_appHasDrmPermissionChecked) { m_appHasDrmPermission = checkForDrmPermission(); m_appHasDrmPermissionChecked = true; @@ -102,8 +108,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 +128,8 @@ void MmRendererMediaPlayerService::releaseControl(QMediaControl *control) m_mediaPlayerControl = 0; if (control == m_metaDataReaderControl) m_metaDataReaderControl = 0; + if (control == m_audioRoleControl) + m_audioRoleControl = 0; delete control; } @@ -136,6 +143,9 @@ void MmRendererMediaPlayerService::updateControls() if (m_metaDataReaderControl && m_mediaPlayerControl) m_mediaPlayerControl->setMetaDataReaderControl(m_metaDataReaderControl); + + if (m_audioRoleControl && m_mediaPlayerControl) + m_mediaPlayerControl->setAudioRoleControl(m_audioRoleControl); } QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h index de85293cb..9434b85b2 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h @@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE +class MmRendererAudioRoleControl; class MmRendererMediaPlayerControl; class MmRendererMetaDataReaderControl; class MmRendererPlayerVideoRendererControl; @@ -66,6 +67,7 @@ private: QPointer<MmRendererVideoWindowControl> m_videoWindowControl; QPointer<MmRendererMediaPlayerControl> m_mediaPlayerControl; QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + QPointer<MmRendererAudioRoleControl> m_audioRoleControl; bool m_appHasDrmPermission : 1; bool m_appHasDrmPermissionChecked : 1; diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.cpp b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp index 239d9d52e..7a9f6393b 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,91 @@ static const MmError mmErrors[] = { }; static const unsigned int numMmErrors = sizeof(mmErrors) / sizeof(MmError); +static QBasicMutex roleMapMutex; +static bool roleMapInitialized = false; +static QString roleMap[QAudio::GameRole + 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); + } +#undef loadRoleMapping +#pragma GCC diagnostic pop + } + + 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 +214,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/ppsmediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp index de5e3e0cf..402461331 100644 --- a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp @@ -151,7 +151,7 @@ void PpsMediaPlayerControl::ppsReadyRead(int fd) // nread is the real space necessary, not the amount read. if (static_cast<size_t>(nread) > bufferSize - 1) { //TODO emit error? - qCritical("BBMediaPlayerControl: PPS buffer size too short; need %u.", nread + 1); + qCritical("PpsMediaPlayerControl: PPS buffer size too short; need %zd.", nread + 1); return; } diff --git a/src/plugins/wmf/player/mfmetadatacontrol.cpp b/src/plugins/wmf/player/mfmetadatacontrol.cpp index 01be95e84..ac57ccfb5 100644 --- a/src/plugins/wmf/player/mfmetadatacontrol.cpp +++ b/src/plugins/wmf/player/mfmetadatacontrol.cpp @@ -193,6 +193,11 @@ QVariant MFMetaDataControl::metaData(const QString &key) const if (m_content && SUCCEEDED(m_content->GetValue(PKEY_Video_FrameWidth, &var))) res.setWidth(convertValue(var).toUInt()); value = res; + } else if (key == QMediaMetaData::Orientation) { + uint orientation = 0; + if (m_content && SUCCEEDED(m_content->GetValue(PKEY_Video_Orientation, &var))) + orientation = convertValue(var).toUInt(); + value = orientation; } else if (key == QMediaMetaData::PixelAspectRatio) { QSize aspectRatio; aspectRatio.setWidth(value.toUInt()); @@ -352,6 +357,8 @@ void MFMetaDataControl::updateSource(IMFPresentationDescriptor* sourcePD, IMFMed m_availableMetaDatas.push_back(QMediaMetaData::ThumbnailImage); } else if (key == PKEY_Video_FrameHeight) { m_availableMetaDatas.push_back(QMediaMetaData::Resolution); + } else if (key == PKEY_Video_Orientation) { + m_availableMetaDatas.push_back(QMediaMetaData::Orientation); } else if (key == PKEY_Video_HorizontalAspectRatio) { m_availableMetaDatas.push_back(QMediaMetaData::PixelAspectRatio); } else if (key == PKEY_Video_FrameRate) { |