1 /*
2 SPDX-FileCopyrightText: 2017 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
3
4 SPDX-License-Identifier: LGPL-3.0-or-later
5 */
6
7 #include "audiowrapper.h"
8 #include "powermanagementinterface.h"
9
10 #include "qtMultimediaLogging.h"
11
12 #include <QTimer>
13 #include <QAudio>
14
15 #include "config-upnp-qt.h"
16
17 class AudioWrapperPrivate
18 {
19
20 public:
21
22 PowerManagementInterface mPowerInterface;
23
24 QMediaPlayer mPlayer;
25
26 qint64 mSavedPosition = 0.0;
27
28 qint64 mUndoSavedPosition = 0.0;
29
30 bool mHasSavedPosition = false;
31
32 };
33
AudioWrapper(QObject * parent)34 AudioWrapper::AudioWrapper(QObject *parent) : QObject(parent), d(std::make_unique<AudioWrapperPrivate>())
35 {
36 connect(&d->mPlayer, &QMediaPlayer::mutedChanged, this, &AudioWrapper::playerMutedChanged);
37 connect(&d->mPlayer, &QMediaPlayer::volumeChanged, this, &AudioWrapper::playerVolumeChanged);
38 connect(&d->mPlayer, &QMediaPlayer::mediaChanged, this, &AudioWrapper::sourceChanged);
39 connect(&d->mPlayer, &QMediaPlayer::mediaStatusChanged, this, &AudioWrapper::statusChanged);
40 connect(&d->mPlayer, &QMediaPlayer::mediaStatusChanged, this, &AudioWrapper::mediaStatusChanged);
41 connect(&d->mPlayer, &QMediaPlayer::stateChanged, this, &AudioWrapper::playbackStateChanged);
42 connect(&d->mPlayer, &QMediaPlayer::stateChanged, this, &AudioWrapper::playerStateChanged);
43 connect(&d->mPlayer, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), this, &AudioWrapper::errorChanged);
44 connect(&d->mPlayer, &QMediaPlayer::durationChanged, this, &AudioWrapper::durationChanged);
45 connect(&d->mPlayer, &QMediaPlayer::positionChanged, this, &AudioWrapper::positionChanged);
46 connect(&d->mPlayer, &QMediaPlayer::seekableChanged, this, &AudioWrapper::seekableChanged);
47 }
48
~AudioWrapper()49 AudioWrapper::~AudioWrapper()
50 {
51 d->mPowerInterface.setPreventSleep(false);
52 }
53
muted() const54 bool AudioWrapper::muted() const
55 {
56 return d->mPlayer.isMuted();
57 }
58
volume() const59 qreal AudioWrapper::volume() const
60 {
61 auto realVolume = static_cast<qreal>(d->mPlayer.volume() / 100.0);
62 auto userVolume = static_cast<qreal>(QAudio::convertVolume(realVolume, QAudio::LinearVolumeScale, QAudio::LogarithmicVolumeScale));
63
64 return userVolume * 100.0;
65 }
66
source() const67 QUrl AudioWrapper::source() const
68 {
69 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
70 return d->mPlayer.media().request().url();
71 #else
72 return d->mPlayer.media().canonicalUrl();
73 #endif
74 }
75
error() const76 QMediaPlayer::Error AudioWrapper::error() const
77 {
78 if (d->mPlayer.error() != QMediaPlayer::NoError) {
79 qDebug() << "AudioWrapper::error" << d->mPlayer.errorString();
80 }
81
82 return d->mPlayer.error();
83 }
84
duration() const85 qint64 AudioWrapper::duration() const
86 {
87 return d->mPlayer.duration();
88 }
89
position() const90 qint64 AudioWrapper::position() const
91 {
92 return d->mPlayer.position();
93 }
94
seekable() const95 bool AudioWrapper::seekable() const
96 {
97 return d->mPlayer.isSeekable();
98 }
99
playbackState() const100 QMediaPlayer::State AudioWrapper::playbackState() const
101 {
102 return d->mPlayer.state();
103 }
104
status() const105 QMediaPlayer::MediaStatus AudioWrapper::status() const
106 {
107 return d->mPlayer.mediaStatus();
108 }
109
setMuted(bool muted)110 void AudioWrapper::setMuted(bool muted)
111 {
112 d->mPlayer.setMuted(muted);
113 }
114
setVolume(qreal volume)115 void AudioWrapper::setVolume(qreal volume)
116 {
117 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::setVolume" << volume;
118
119 auto realVolume = static_cast<qreal>(QAudio::convertVolume(volume / 100.0, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale));
120 d->mPlayer.setVolume(qRound(realVolume * 100));
121 }
122
setSource(const QUrl & source)123 void AudioWrapper::setSource(const QUrl &source)
124 {
125 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::setSource" << source;
126
127 d->mPlayer.setMedia({source});
128 }
129
setPosition(qint64 position)130 void AudioWrapper::setPosition(qint64 position)
131 {
132 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::setPosition" << position;
133
134 if (d->mPlayer.duration() <= 0) {
135 savePosition(position);
136 return;
137 }
138
139 d->mPlayer.setPosition(position);
140 }
141
play()142 void AudioWrapper::play()
143 {
144 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::play";
145
146 d->mPlayer.play();
147
148 if (d->mHasSavedPosition) {
149 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerDurationSignalChanges" << "restore old position" << d->mSavedPosition;
150
151 setPosition(d->mSavedPosition);
152 d->mHasSavedPosition = false;
153 }
154 }
155
pause()156 void AudioWrapper::pause()
157 {
158 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::pause";
159
160 d->mPlayer.pause();
161 }
162
stop()163 void AudioWrapper::stop()
164 {
165 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::stop";
166
167 d->mPlayer.stop();
168 }
169
seek(qint64 position)170 void AudioWrapper::seek(qint64 position)
171 {
172 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::seek" << position;
173
174 d->mPlayer.setPosition(position);
175 }
176
mediaStatusChanged()177 void AudioWrapper::mediaStatusChanged()
178 {
179 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::mediaStatusChanged" << d->mPlayer.mediaStatus();
180 }
181
playerStateChanged()182 void AudioWrapper::playerStateChanged()
183 {
184 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerStateChanged" << d->mPlayer.state();
185
186 switch(d->mPlayer.state())
187 {
188 case QMediaPlayer::State::StoppedState:
189 Q_EMIT stopped();
190 d->mPowerInterface.setPreventSleep(false);
191 break;
192 case QMediaPlayer::State::PlayingState:
193 Q_EMIT playing();
194 d->mPowerInterface.setPreventSleep(true);
195 break;
196 case QMediaPlayer::State::PausedState:
197 Q_EMIT paused();
198 d->mPowerInterface.setPreventSleep(false);
199 break;
200 }
201 }
202
playerVolumeChanged()203 void AudioWrapper::playerVolumeChanged()
204 {
205 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerVolumeChanged" << d->mPlayer.volume();
206
207 QTimer::singleShot(0, [this]() {Q_EMIT volumeChanged();});
208 }
209
playerMutedChanged()210 void AudioWrapper::playerMutedChanged()
211 {
212 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerMutedChanged";
213
214 QTimer::singleShot(0, [this]() {Q_EMIT mutedChanged(muted());});
215 }
216
playerStateSignalChanges(QMediaPlayer::State newState)217 void AudioWrapper::playerStateSignalChanges(QMediaPlayer::State newState)
218 {
219 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerStateSignalChanges" << newState;
220
221 QMetaObject::invokeMethod(this, [this, newState]() {Q_EMIT playbackStateChanged(newState);}, Qt::QueuedConnection);
222 }
223
mediaStatusSignalChanges(QMediaPlayer::MediaStatus newStatus)224 void AudioWrapper::mediaStatusSignalChanges(QMediaPlayer::MediaStatus newStatus)
225 {
226 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::mediaStatusSignalChanges" << newStatus;
227
228 QMetaObject::invokeMethod(this, [this, newStatus]() {Q_EMIT statusChanged(newStatus);}, Qt::QueuedConnection);
229 }
230
playerDurationSignalChanges(qint64 newDuration)231 void AudioWrapper::playerDurationSignalChanges(qint64 newDuration)
232 {
233 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerDurationSignalChanges" << newDuration;
234
235 QMetaObject::invokeMethod(this, [this, newDuration]() {Q_EMIT durationChanged(newDuration);}, Qt::QueuedConnection);
236 }
237
playerPositionSignalChanges(qint64 newPosition)238 void AudioWrapper::playerPositionSignalChanges(qint64 newPosition)
239 {
240 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::playerPositionSignalChanges" << newPosition;
241
242 QMetaObject::invokeMethod(this, [this, newPosition]() {Q_EMIT positionChanged(newPosition);}, Qt::QueuedConnection);
243 }
244
playerVolumeSignalChanges()245 void AudioWrapper::playerVolumeSignalChanges()
246 {
247 QMetaObject::invokeMethod(this, [this]() {Q_EMIT volumeChanged();}, Qt::QueuedConnection);
248 }
249
playerMutedSignalChanges(bool isMuted)250 void AudioWrapper::playerMutedSignalChanges(bool isMuted)
251 {
252 QMetaObject::invokeMethod(this, [this, isMuted]() {Q_EMIT mutedChanged(isMuted);}, Qt::QueuedConnection);
253 }
254
playerSeekableSignalChanges(bool isSeekable)255 void AudioWrapper::playerSeekableSignalChanges(bool isSeekable)
256 {
257 QMetaObject::invokeMethod(this, [this, isSeekable]() {Q_EMIT seekableChanged(isSeekable);}, Qt::QueuedConnection);
258 }
259
saveUndoPosition(qint64 position)260 void AudioWrapper::saveUndoPosition(qint64 position)
261 {
262 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::saveUndoPosition" << position;
263
264 d->mUndoSavedPosition = position;
265 }
266
restoreUndoPosition()267 void AudioWrapper::restoreUndoPosition()
268 {
269 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::restoreUndoPosition";
270
271 d->mHasSavedPosition = true;
272 d->mSavedPosition = d->mUndoSavedPosition;
273 }
274
savePosition(qint64 position)275 void AudioWrapper::savePosition(qint64 position)
276 {
277 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::savePosition" << position;
278
279 if (!d->mHasSavedPosition) {
280 d->mHasSavedPosition = true;
281 d->mSavedPosition = position;
282 qCDebug(orgKdeElisaPlayerQtMultimedia) << "AudioWrapper::savePosition" << "restore old position" << d->mSavedPosition;
283 }
284 }
285
286
287 #include "moc_audiowrapper.cpp"
288