File indexing completed on 2024-04-14 04:43:56

0001 /*
0002    SPDX-FileCopyrightText: 2017 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003 
0004    SPDX-License-Identifier: LGPL-3.0-or-later
0005  */
0006 
0007 #include "audiowrapper.h"
0008 #include "powermanagementinterface.h"
0009 
0010 #include "qtMultimediaLogging.h"
0011 
0012 #include <QTimer>
0013 #include <QAudio>
0014 #include <QAudioOutput>
0015 
0016 #include "config-upnp-qt.h"
0017 
0018 class AudioWrapperPrivate
0019 {
0020 
0021 public:
0022 
0023     PowerManagementInterface mPowerInterface;
0024 
0025     QMediaPlayer mPlayer;
0026 
0027     QAudioOutput mOutput;
0028 
0029     qint64 mSavedPosition = 0.0;
0030 
0031     qint64 mUndoSavedPosition = 0.0;
0032 
0033     bool mHasSavedPosition = false;
0034 
0035 };
0036 
0037 AudioWrapper::AudioWrapper(QObject *parent) : QObject(parent), d(std::make_unique<AudioWrapperPrivate>())
0038 {
0039     d->mPlayer.setAudioOutput(&d->mOutput);
0040     connect(&d->mOutput, &QAudioOutput::mutedChanged, this, &AudioWrapper::playerMutedChanged);
0041     connect(&d->mOutput, &QAudioOutput::volumeChanged, this, &AudioWrapper::playerVolumeChanged);
0042     connect(&d->mPlayer, &QMediaPlayer::sourceChanged, this, &AudioWrapper::sourceChanged);
0043     connect(&d->mPlayer, &QMediaPlayer::playbackStateChanged, this, &AudioWrapper::playbackStateChanged);
0044     connect(&d->mPlayer, &QMediaPlayer::playbackStateChanged, this, &AudioWrapper::playerStateChanged);
0045     connect(&d->mPlayer, QOverload<QMediaPlayer::Error, const QString &>::of(&QMediaPlayer::errorOccurred), this, &AudioWrapper::errorChanged);
0046     connect(&d->mPlayer, &QMediaPlayer::mediaStatusChanged, this, &AudioWrapper::statusChanged);
0047     connect(&d->mPlayer, &QMediaPlayer::mediaStatusChanged, this, &AudioWrapper::mediaStatusChanged);
0048     connect(&d->mPlayer, &QMediaPlayer::durationChanged, this, &AudioWrapper::durationChanged);
0049     connect(&d->mPlayer, &QMediaPlayer::positionChanged, this, &AudioWrapper::positionChanged);
0050     connect(&d->mPlayer, &QMediaPlayer::seekableChanged, this, &AudioWrapper::seekableChanged);
0051 }
0052 
0053 AudioWrapper::~AudioWrapper()
0054 {
0055     d->mPowerInterface.setPreventSleep(false);
0056 }
0057 
0058 bool AudioWrapper::muted() const
0059 {
0060     return d->mOutput.isMuted();
0061 }
0062 
0063 qreal AudioWrapper::volume() const
0064 {
0065     auto realVolume = static_cast<qreal>(d->mOutput.volume() / 100.0);
0066     auto userVolume = static_cast<qreal>(QAudio::convertVolume(realVolume, QAudio::LinearVolumeScale, QAudio::LogarithmicVolumeScale));
0067 
0068     return userVolume * 100.0;
0069 }
0070 
0071 QUrl AudioWrapper::source() const
0072 {
0073     return d->mPlayer.source();
0074 }
0075 
0076 QMediaPlayer::Error AudioWrapper::error() const
0077 {
0078     if (d->mPlayer.error() != QMediaPlayer::NoError) {
0079         qDebug() << "AudioWrapper::error" << d->mPlayer.errorString();
0080     }
0081 
0082     return d->mPlayer.error();
0083 }
0084 
0085 qint64 AudioWrapper::duration() const
0086 {
0087     return d->mPlayer.duration();
0088 }
0089 
0090 qint64 AudioWrapper::position() const
0091 {
0092     return d->mPlayer.position();
0093 }
0094 
0095 bool AudioWrapper::seekable() const
0096 {
0097     return d->mPlayer.isSeekable();
0098 }
0099 
0100 QMediaPlayer::PlaybackState AudioWrapper::playbackState() const
0101 {
0102     return d->mPlayer.playbackState();
0103 }
0104 
0105 QMediaPlayer::MediaStatus AudioWrapper::status() const
0106 {
0107     return d->mPlayer.mediaStatus();
0108 }
0109 
0110 void AudioWrapper::setMuted(bool muted)
0111 {
0112     d->mOutput.setMuted(muted);
0113 }
0114 
0115 void AudioWrapper::setVolume(qreal volume)
0116 {
0117     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::setVolume" << volume;
0118 
0119     auto realVolume = static_cast<qreal>(QAudio::convertVolume(volume / 100.0, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale));
0120     d->mOutput.setVolume(qRound(realVolume * 100));
0121 }
0122 
0123 void AudioWrapper::setSource(const QUrl &source)
0124 {
0125     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::setSource" << source;
0126     d->mPlayer.setSource({source});
0127 }
0128 
0129 void AudioWrapper::setPosition(qint64 position)
0130 {
0131     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::setPosition" << position;
0132 
0133     if (d->mPlayer.duration() <= 0) {
0134         savePosition(position);
0135         return;
0136     }
0137 
0138     d->mPlayer.setPosition(position);
0139 }
0140 
0141 void AudioWrapper::play()
0142 {
0143     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::play";
0144 
0145     d->mPlayer.play();
0146 
0147     if (d->mHasSavedPosition) {
0148         qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerDurationSignalChanges" << "restore old position" << d->mSavedPosition;
0149 
0150         setPosition(d->mSavedPosition);
0151         d->mHasSavedPosition = false;
0152     }
0153 }
0154 
0155 void AudioWrapper::pause()
0156 {
0157     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::pause";
0158 
0159     d->mPlayer.pause();
0160 }
0161 
0162 void AudioWrapper::stop()
0163 {
0164     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::stop";
0165 
0166     d->mPlayer.stop();
0167 }
0168 
0169 void AudioWrapper::seek(qint64 position)
0170 {
0171     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::seek" << position;
0172 
0173     d->mPlayer.setPosition(position);
0174 }
0175 
0176 void AudioWrapper::mediaStatusChanged()
0177 {
0178     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::mediaStatusChanged" << d->mPlayer.mediaStatus();
0179 }
0180 
0181 void AudioWrapper::playerStateChanged()
0182 {
0183     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerStateChanged" << d->mPlayer.playbackState();
0184 
0185     switch(d->mPlayer.playbackState())
0186     {
0187     case QMediaPlayer::PlaybackState::StoppedState:
0188         Q_EMIT stopped();
0189         d->mPowerInterface.setPreventSleep(false);
0190         break;
0191     case QMediaPlayer::PlaybackState::PlayingState:
0192         Q_EMIT playing();
0193         d->mPowerInterface.setPreventSleep(true);
0194         break;
0195     case QMediaPlayer::PlaybackState::PausedState:
0196         Q_EMIT paused();
0197         d->mPowerInterface.setPreventSleep(false);
0198         break;
0199     }
0200 }
0201 
0202 void AudioWrapper::playerVolumeChanged()
0203 {
0204     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerVolumeChanged" << d->mOutput.volume();
0205 
0206     QTimer::singleShot(0, [this]() {Q_EMIT volumeChanged();});
0207 }
0208 
0209 void AudioWrapper::playerMutedChanged()
0210 {
0211     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerMutedChanged";
0212 
0213     QTimer::singleShot(0, [this]() {Q_EMIT mutedChanged(muted());});
0214 }
0215 
0216 void AudioWrapper::playerStateSignalChanges(QMediaPlayer::PlaybackState newState)
0217 {
0218     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerStateSignalChanges" << newState;
0219 
0220     QMetaObject::invokeMethod(this, [this, newState]() {Q_EMIT playbackStateChanged(newState);}, Qt::QueuedConnection);
0221 }
0222 
0223 void AudioWrapper::mediaStatusSignalChanges(QMediaPlayer::MediaStatus newStatus)
0224 {
0225     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::mediaStatusSignalChanges" << newStatus;
0226 
0227     QMetaObject::invokeMethod(this, [this, newStatus]() {Q_EMIT statusChanged(newStatus);}, Qt::QueuedConnection);
0228 }
0229 
0230 void AudioWrapper::playerDurationSignalChanges(qint64 newDuration)
0231 {
0232     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerDurationSignalChanges" << newDuration;
0233 
0234     QMetaObject::invokeMethod(this, [this, newDuration]() {Q_EMIT durationChanged(newDuration);}, Qt::QueuedConnection);
0235 }
0236 
0237 void AudioWrapper::playerPositionSignalChanges(qint64 newPosition)
0238 {
0239     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerPositionSignalChanges" << newPosition;
0240 
0241     QMetaObject::invokeMethod(this, [this, newPosition]() {Q_EMIT positionChanged(newPosition);}, Qt::QueuedConnection);
0242 }
0243 
0244 void AudioWrapper::playerVolumeSignalChanges()
0245 {
0246     QMetaObject::invokeMethod(this, [this]() {Q_EMIT volumeChanged();}, Qt::QueuedConnection);
0247 }
0248 
0249 void AudioWrapper::playerMutedSignalChanges(bool isMuted)
0250 {
0251     QMetaObject::invokeMethod(this, [this, isMuted]() {Q_EMIT mutedChanged(isMuted);}, Qt::QueuedConnection);
0252 }
0253 
0254 void AudioWrapper::playerSeekableSignalChanges(bool isSeekable)
0255 {
0256     QMetaObject::invokeMethod(this, [this, isSeekable]() {Q_EMIT seekableChanged(isSeekable);}, Qt::QueuedConnection);
0257 }
0258 
0259 void AudioWrapper::saveUndoPosition(qint64 position)
0260 {
0261     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::saveUndoPosition" << position;
0262 
0263     d->mUndoSavedPosition = position;
0264 }
0265 
0266 void AudioWrapper::restoreUndoPosition()
0267 {
0268     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::restoreUndoPosition";
0269 
0270     d->mHasSavedPosition = true;
0271     d->mSavedPosition = d->mUndoSavedPosition;
0272 }
0273 
0274 void AudioWrapper::savePosition(qint64 position)
0275 {
0276     qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::savePosition" << position;
0277 
0278     if (!d->mHasSavedPosition) {
0279         d->mHasSavedPosition = true;
0280         d->mSavedPosition = position;
0281         qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::savePosition" << "restore old position" << d->mSavedPosition;
0282     }
0283 }
0284 
0285 
0286 #include "moc_audiowrapper.cpp"