File indexing completed on 2024-04-28 08:41:03

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 
0009 #include "elisa-version.h"
0010 
0011 #include "vlcLogging.h"
0012 #include "powermanagementinterface.h"
0013 
0014 #include <QAudio>
0015 #include <QDir>
0016 #include <QGuiApplication>
0017 
0018 #if defined Q_OS_WIN
0019 
0020 #include <basetsd.h>
0021 typedef SSIZE_T ssize_t;
0022 
0023 #endif
0024 
0025 #include <cmath>
0026 
0027 #include <vlc/vlc.h>
0028 #include <vlc/libvlc_version.h>
0029 
0030 #include "config-upnp-qt.h"
0031 
0032 class AudioWrapperPrivate
0033 {
0034 
0035 public:
0036 
0037     PowerManagementInterface mPowerInterface;
0038 
0039     AudioWrapper *mParent = nullptr;
0040 
0041     libvlc_instance_t *mInstance = nullptr;
0042 
0043     libvlc_media_player_t *mPlayer = nullptr;
0044 
0045     libvlc_event_manager_t *mPlayerEventManager = nullptr;
0046 
0047     libvlc_media_t *mMedia = nullptr;
0048 
0049     qint64 mMediaDuration = 0;
0050 
0051     QMediaPlayer::PlaybackState mPreviousPlayerState = QMediaPlayer::StoppedState;
0052 
0053     QMediaPlayer::MediaStatus mPreviousMediaStatus = QMediaPlayer::NoMedia;
0054 
0055     qreal mPreviousVolume = 100.0;
0056 
0057     qint64 mSavedPosition = 0.0;
0058 
0059     qint64 mUndoSavedPosition = 0.0;
0060 
0061     qint64 mPreviousPosition = 0;
0062 
0063     QMediaPlayer::Error mError = QMediaPlayer::NoError;
0064 
0065     bool mIsMuted = false;
0066 
0067     bool mIsSeekable = false;
0068 
0069     bool mHasSavedPosition = false;
0070 
0071     void vlcEventCallback(const struct libvlc_event_t *p_event);
0072 
0073     void mediaIsEnded();
0074 
0075     bool signalPlaybackChange(QMediaPlayer::PlaybackState newPlayerState);
0076 
0077     void signalMediaStatusChange(QMediaPlayer::MediaStatus newMediaStatus);
0078 
0079     void signalVolumeChange(int newVolume);
0080 
0081     void signalMutedChange(bool isMuted);
0082 
0083     void signalDurationChange(libvlc_time_t newDuration);
0084 
0085     void signalPositionChange(float newPosition);
0086 
0087     void signalSeekableChange(bool isSeekable);
0088 
0089     void signalErrorChange(QMediaPlayer::Error errorCode);
0090 
0091 };
0092 
0093 static void vlc_callback(const struct libvlc_event_t *p_event, void *p_data)
0094 {
0095     reinterpret_cast<AudioWrapperPrivate*>(p_data)->vlcEventCallback(p_event);
0096 }
0097 
0098 AudioWrapper::AudioWrapper(QObject *parent) : QObject(parent), d(std::make_unique<AudioWrapperPrivate>())
0099 {
0100     d->mParent = this;
0101     d->mInstance = libvlc_new(0, nullptr);
0102     libvlc_set_user_agent(d->mInstance, QGuiApplication::applicationDisplayName().toUtf8().constData(), "Elisa Music Player");
0103     libvlc_set_app_id(d->mInstance, "org.kde.elisa", ELISA_VERSION_STRING, "elisa");
0104 
0105     d->mPlayer = libvlc_media_player_new(d->mInstance);
0106 
0107     if (!d->mPlayer) {
0108         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::AudioWrapper" << "failed creating player" << libvlc_errmsg();
0109         return;
0110     }
0111 
0112     d->mPlayerEventManager = libvlc_media_player_event_manager(d->mPlayer);
0113 
0114     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerOpening, &vlc_callback, d.get());
0115     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerBuffering, &vlc_callback, d.get());
0116     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPlaying, &vlc_callback, d.get());
0117     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPaused, &vlc_callback, d.get());
0118     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerStopped, &vlc_callback, d.get());
0119 #if LIBVLC_VERSION_MAJOR >= 4
0120     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerStopping, &vlc_callback, d.get());
0121 #else
0122     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEndReached, &vlc_callback, d.get());
0123 #endif
0124     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEncounteredError, &vlc_callback, d.get());
0125     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPositionChanged, &vlc_callback, d.get());
0126     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerSeekableChanged, &vlc_callback, d.get());
0127     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerLengthChanged, &vlc_callback, d.get());
0128     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerMuted, &vlc_callback, d.get());
0129     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerUnmuted, &vlc_callback, d.get());
0130     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioVolume, &vlc_callback, d.get());
0131     libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioDevice, &vlc_callback, d.get());
0132 }
0133 
0134 AudioWrapper::~AudioWrapper()
0135 {
0136     if (d->mInstance) {
0137         d->mPowerInterface.setPreventSleep(false);
0138         if (d->mPlayer && d->mPreviousPlayerState != QMediaPlayer::StoppedState) {
0139 #if LIBVLC_VERSION_MAJOR >= 4
0140             libvlc_media_player_stop_async(d->mPlayer);
0141 #else
0142             libvlc_media_player_stop(d->mPlayer);
0143 #endif
0144         }
0145         libvlc_release(d->mInstance);
0146     }
0147 }
0148 
0149 bool AudioWrapper::muted() const
0150 {
0151     return d->mIsMuted;
0152 }
0153 
0154 qreal AudioWrapper::volume() const
0155 {
0156     if (!d->mPlayer) {
0157         return 100.0;
0158     }
0159 
0160     return d->mPreviousVolume;
0161 }
0162 
0163 QUrl AudioWrapper::source() const
0164 {
0165     if (!d->mPlayer) {
0166         return {};
0167     }
0168     if (d->mMedia) {
0169         auto filePath = QString::fromUtf8(libvlc_media_get_mrl(d->mMedia));
0170         return QUrl::fromUserInput(filePath);
0171     }
0172     return {};
0173 }
0174 
0175 QMediaPlayer::Error AudioWrapper::error() const
0176 {
0177     return d->mError;
0178 }
0179 
0180 qint64 AudioWrapper::duration() const
0181 {
0182     return d->mMediaDuration;
0183 }
0184 
0185 qint64 AudioWrapper::position() const
0186 {
0187     if (!d->mPlayer) {
0188         return 0;
0189     }
0190 
0191     if (d->mMediaDuration == -1) {
0192         return 0;
0193     }
0194 
0195     return qRound64(libvlc_media_player_get_position(d->mPlayer) * d->mMediaDuration);
0196 }
0197 
0198 bool AudioWrapper::seekable() const
0199 {
0200     return d->mIsSeekable;
0201 }
0202 
0203 QMediaPlayer::PlaybackState AudioWrapper::playbackState() const
0204 {
0205     return d->mPreviousPlayerState;
0206 }
0207 
0208 QMediaPlayer::MediaStatus AudioWrapper::status() const
0209 {
0210     return d->mPreviousMediaStatus;
0211 }
0212 
0213 void AudioWrapper::setMuted(bool muted)
0214 {
0215     if (!d->mPlayer) {
0216         return;
0217     }
0218 
0219     libvlc_audio_set_mute(d->mPlayer, muted);
0220 }
0221 
0222 void AudioWrapper::setVolume(qreal volume)
0223 {
0224     if (!d->mPlayer) {
0225         return;
0226     }
0227 
0228     const int intVolume = std::clamp(qRound(volume), 0, 100);
0229     libvlc_audio_set_volume(d->mPlayer, intVolume);
0230 }
0231 
0232 void AudioWrapper::setSource(const QUrl &source)
0233 {
0234     if (source.isLocalFile()) {
0235         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource reading local resource";
0236 #if LIBVLC_VERSION_MAJOR >= 4
0237         d->mMedia = libvlc_media_new_path(QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData());
0238 #else
0239         d->mMedia = libvlc_media_new_path(d->mInstance, QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData());
0240 #endif
0241     } else {
0242         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource reading remote resource";
0243 #if LIBVLC_VERSION_MAJOR >= 4
0244         d->mMedia = libvlc_media_new_location(source.url().toUtf8().constData());
0245 #else
0246         d->mMedia = libvlc_media_new_location(d->mInstance, source.url().toUtf8().constData());
0247 #endif
0248     }
0249 
0250     if (!d->mMedia) {
0251         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource"
0252                  << "failed creating media"
0253                  << libvlc_errmsg()
0254                  << QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData();
0255 
0256 #if LIBVLC_VERSION_MAJOR >= 4
0257         d->mMedia = libvlc_media_new_path(QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData());
0258 #else
0259         d->mMedia = libvlc_media_new_path(d->mInstance, QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData());
0260 #endif
0261         if (!d->mMedia) {
0262             qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource"
0263                      << "failed creating media"
0264                      << libvlc_errmsg()
0265                      << QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData();
0266             return;
0267         }
0268     }
0269 
0270     // By default, libvlc caches only next 1000 (ms, 0..60000) of the playback,
0271     // which is unreasonable given our usecase of sequential playback.
0272     libvlc_media_add_option(d->mMedia, ":file-caching=10000");
0273     libvlc_media_add_option(d->mMedia, ":live-caching=10000");
0274     libvlc_media_add_option(d->mMedia, ":disc-caching=10000");
0275     libvlc_media_add_option(d->mMedia, ":network-caching=10000");
0276 
0277     libvlc_media_player_set_media(d->mPlayer, d->mMedia);
0278 
0279     if (d->signalPlaybackChange(QMediaPlayer::StoppedState)) {
0280         Q_EMIT stopped();
0281     }
0282 
0283     d->signalMediaStatusChange(QMediaPlayer::LoadingMedia);
0284     d->signalMediaStatusChange(QMediaPlayer::LoadedMedia);
0285     d->signalMediaStatusChange(QMediaPlayer::BufferedMedia);
0286 
0287     d->mHasSavedPosition = false;
0288 }
0289 
0290 void AudioWrapper::setPosition(qint64 position)
0291 {
0292     if (!d->mPlayer) {
0293         return;
0294     }
0295 
0296     if (d->mMediaDuration == -1 || d->mMediaDuration == 0) {
0297         savePosition(position);
0298         return;
0299     }
0300 
0301 #if LIBVLC_VERSION_MAJOR >= 4
0302     libvlc_media_player_set_position(d->mPlayer, static_cast<float>(position) / d->mMediaDuration, true);
0303 #else
0304     libvlc_media_player_set_position(d->mPlayer, static_cast<float>(position) / d->mMediaDuration);
0305 #endif
0306     Q_EMIT positionChanged(position);
0307 }
0308 
0309 void AudioWrapper::savePosition(qint64 position)
0310 {
0311     if (!d->mHasSavedPosition) {
0312         d->mHasSavedPosition = true;
0313         d->mSavedPosition = position;
0314         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::savePosition" << "restore old position" << d->mSavedPosition;
0315     }
0316 }
0317 
0318 void AudioWrapper::saveUndoPosition(qint64 position)
0319 {
0320     d->mUndoSavedPosition = position;
0321 }
0322 
0323 void AudioWrapper::restoreUndoPosition()
0324 {
0325     d->mHasSavedPosition = true;
0326     d->mSavedPosition = d->mUndoSavedPosition;
0327 }
0328 
0329 void AudioWrapper::play()
0330 {
0331     if (!d->mPlayer) {
0332         return;
0333     }
0334 
0335     libvlc_media_player_play(d->mPlayer);
0336 }
0337 
0338 void AudioWrapper::pause()
0339 {
0340     if (!d->mPlayer) {
0341         return;
0342     }
0343 
0344     libvlc_media_player_pause(d->mPlayer);
0345 }
0346 
0347 void AudioWrapper::stop()
0348 {
0349     if (!d->mPlayer) {
0350         return;
0351     }
0352 
0353 #if LIBVLC_VERSION_MAJOR >= 4
0354     libvlc_media_player_stop_async(d->mPlayer);
0355 #else
0356     libvlc_media_player_stop(d->mPlayer);
0357 #endif
0358 }
0359 
0360 void AudioWrapper::seek(qint64 position)
0361 {
0362     setPosition(position);
0363 }
0364 
0365 void AudioWrapper::mediaStatusChanged()
0366 {
0367 }
0368 
0369 void AudioWrapper::playerStateChanged()
0370 {
0371 }
0372 
0373 void AudioWrapper::playerMutedChanged()
0374 {
0375 }
0376 
0377 void AudioWrapper::playerVolumeChanged()
0378 {
0379 }
0380 
0381 void AudioWrapper::playerStateSignalChanges(QMediaPlayer::PlaybackState newState)
0382 {
0383     QMetaObject::invokeMethod(this, [this, newState]() {
0384         Q_EMIT playbackStateChanged(newState);
0385         switch (newState)
0386         {
0387         case QMediaPlayer::StoppedState:
0388             Q_EMIT stopped();
0389             d->mPowerInterface.setPreventSleep(false);
0390             break;
0391         case QMediaPlayer::PlayingState:
0392             Q_EMIT playing();
0393             d->mPowerInterface.setPreventSleep(true);
0394             break;
0395         case QMediaPlayer::PausedState:
0396             Q_EMIT paused();
0397             d->mPowerInterface.setPreventSleep(false);
0398             break;
0399         }
0400     }, Qt::QueuedConnection);
0401 }
0402 
0403 void AudioWrapper::mediaStatusSignalChanges(QMediaPlayer::MediaStatus newStatus)
0404 {
0405     QMetaObject::invokeMethod(this, [this, newStatus]() {Q_EMIT statusChanged(newStatus);}, Qt::QueuedConnection);
0406 }
0407 
0408 void AudioWrapper::playerErrorSignalChanges(QMediaPlayer::Error error)
0409 {
0410     QMetaObject::invokeMethod(this, [this, error]() {Q_EMIT errorChanged(error);}, Qt::QueuedConnection);
0411 }
0412 
0413 void AudioWrapper::playerDurationSignalChanges(qint64 newDuration)
0414 {
0415     QMetaObject::invokeMethod(this, [this, newDuration]() {Q_EMIT durationChanged(newDuration);}, Qt::QueuedConnection);
0416 }
0417 
0418 void AudioWrapper::playerPositionSignalChanges(qint64 newPosition)
0419 {
0420     QMetaObject::invokeMethod(this, [this, newPosition]() {Q_EMIT positionChanged(newPosition);}, Qt::QueuedConnection);
0421 }
0422 
0423 void AudioWrapper::playerVolumeSignalChanges()
0424 {
0425     QMetaObject::invokeMethod(this, [this]() {Q_EMIT volumeChanged();}, Qt::QueuedConnection);
0426 }
0427 
0428 void AudioWrapper::playerMutedSignalChanges(bool isMuted)
0429 {
0430     QMetaObject::invokeMethod(this, [this, isMuted]() {Q_EMIT mutedChanged(isMuted);}, Qt::QueuedConnection);
0431 }
0432 
0433 void AudioWrapper::playerSeekableSignalChanges(bool isSeekable)
0434 {
0435     QMetaObject::invokeMethod(this, [this, isSeekable]() {Q_EMIT seekableChanged(isSeekable);}, Qt::QueuedConnection);
0436 }
0437 
0438 void AudioWrapperPrivate::vlcEventCallback(const struct libvlc_event_t *p_event)
0439 {
0440     const auto eventType = static_cast<libvlc_event_e>(p_event->type);
0441 
0442     switch(eventType)
0443     {
0444     case libvlc_MediaPlayerOpening:
0445         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerOpening";
0446         signalMediaStatusChange(QMediaPlayer::LoadedMedia);
0447         break;
0448     case libvlc_MediaPlayerBuffering:
0449         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerBuffering";
0450         signalMediaStatusChange(QMediaPlayer::BufferedMedia);
0451         break;
0452     case libvlc_MediaPlayerPlaying:
0453         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerPlaying";
0454         signalPlaybackChange(QMediaPlayer::PlayingState);
0455         break;
0456     case libvlc_MediaPlayerPaused:
0457         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerPaused";
0458         signalPlaybackChange(QMediaPlayer::PausedState);
0459         break;
0460     case libvlc_MediaPlayerStopped:
0461         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerStopped";
0462         signalPlaybackChange(QMediaPlayer::StoppedState);
0463         break;
0464 #if LIBVLC_VERSION_MAJOR >= 4
0465     case libvlc_MediaPlayerStopping:
0466         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback"
0467                                       << "libvlc_MediaPlayerStopping";
0468 #else
0469     case libvlc_MediaPlayerEndReached:
0470         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback"
0471                                       << "libvlc_MediaPlayerEndReached";
0472 #endif
0473         signalMediaStatusChange(QMediaPlayer::BufferedMedia);
0474         signalMediaStatusChange(QMediaPlayer::NoMedia);
0475         signalMediaStatusChange(QMediaPlayer::EndOfMedia);
0476         mediaIsEnded();
0477         break;
0478     case libvlc_MediaPlayerEncounteredError:
0479         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerEncounteredError";
0480         signalErrorChange(QMediaPlayer::ResourceError);
0481         mediaIsEnded();
0482         signalMediaStatusChange(QMediaPlayer::InvalidMedia);
0483         break;
0484     case libvlc_MediaPlayerPositionChanged:
0485         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerPositionChanged";
0486         signalPositionChange(p_event->u.media_player_position_changed.new_position);
0487         break;
0488     case libvlc_MediaPlayerSeekableChanged:
0489         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerSeekableChanged";
0490         signalSeekableChange(p_event->u.media_player_seekable_changed.new_seekable);
0491         break;
0492     case libvlc_MediaPlayerLengthChanged:
0493         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerLengthChanged";
0494         signalDurationChange(p_event->u.media_player_length_changed.new_length);
0495         if (mHasSavedPosition) {
0496             mParent->setPosition(mSavedPosition);
0497             mHasSavedPosition = false;
0498         }
0499         break;
0500     case libvlc_MediaPlayerMuted:
0501         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerMuted";
0502         signalMutedChange(true);
0503         break;
0504     case libvlc_MediaPlayerUnmuted:
0505         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerUnmuted";
0506         signalMutedChange(false);
0507         break;
0508     case libvlc_MediaPlayerAudioVolume:
0509         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerAudioVolume";
0510         signalVolumeChange(qRound(p_event->u.media_player_audio_volume.volume * 100));
0511         break;
0512     case libvlc_MediaPlayerAudioDevice:
0513         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "libvlc_MediaPlayerAudioDevice";
0514         break;
0515     default:
0516         qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapperPrivate::vlcEventCallback" << "eventType" << eventType;
0517         break;
0518     }
0519 }
0520 
0521 void AudioWrapperPrivate::mediaIsEnded()
0522 {
0523     libvlc_media_release(mMedia);
0524     mMedia = nullptr;
0525 }
0526 
0527 bool AudioWrapperPrivate::signalPlaybackChange(QMediaPlayer::PlaybackState newPlayerState)
0528 {
0529     if (mPreviousPlayerState != newPlayerState) {
0530         mPreviousPlayerState = newPlayerState;
0531 
0532         mParent->playerStateSignalChanges(mPreviousPlayerState);
0533 
0534         return true;
0535     }
0536 
0537     return false;
0538 }
0539 
0540 void AudioWrapperPrivate::signalMediaStatusChange(QMediaPlayer::MediaStatus newMediaStatus)
0541 {
0542     if (mPreviousMediaStatus != newMediaStatus) {
0543         mPreviousMediaStatus = newMediaStatus;
0544 
0545         mParent->mediaStatusSignalChanges(mPreviousMediaStatus);
0546     }
0547 }
0548 
0549 void AudioWrapperPrivate::signalVolumeChange(int newVolume)
0550 {
0551     if (newVolume == -1) {
0552         return;
0553     }
0554 
0555     if (mPreviousPlayerState == QMediaPlayer::StoppedState) {
0556         return;
0557     }
0558 
0559     if (abs(int(mPreviousVolume - newVolume)) >= 1) {
0560         mPreviousVolume = newVolume;
0561 
0562         mParent->playerVolumeSignalChanges();
0563     }
0564 }
0565 
0566 void AudioWrapperPrivate::signalMutedChange(bool isMuted)
0567 {
0568     if (mIsMuted != isMuted) {
0569         mIsMuted = isMuted;
0570 
0571         mParent->playerMutedSignalChanges(mIsMuted);
0572     }
0573 }
0574 
0575 void AudioWrapperPrivate::signalDurationChange(libvlc_time_t newDuration)
0576 {
0577     if (mMediaDuration != newDuration) {
0578         mMediaDuration = newDuration;
0579 
0580         mParent->playerDurationSignalChanges(mMediaDuration);
0581     }
0582 }
0583 
0584 void AudioWrapperPrivate::signalPositionChange(float newPosition)
0585 {
0586     if (mMediaDuration == -1) {
0587         return;
0588     }
0589 
0590     auto computedPosition = qRound64(newPosition * mMediaDuration);
0591 
0592     if (mPreviousPosition != computedPosition) {
0593         mPreviousPosition = computedPosition;
0594 
0595         mParent->playerPositionSignalChanges(mPreviousPosition);
0596     }
0597 
0598     if (this->mMedia) {
0599         QString title = QLatin1String(libvlc_media_get_meta(this->mMedia, libvlc_meta_Title));
0600         QString nowPlaying = QLatin1String(libvlc_media_get_meta(this->mMedia, libvlc_meta_NowPlaying));
0601 
0602         Q_EMIT mParent->currentPlayingForRadiosChanged(title, nowPlaying);
0603     }
0604 }
0605 
0606 void AudioWrapperPrivate::signalSeekableChange(bool isSeekable)
0607 {
0608     if (mIsSeekable != isSeekable) {
0609         mIsSeekable = isSeekable;
0610 
0611         mParent->playerSeekableSignalChanges(isSeekable);
0612     }
0613 }
0614 
0615 void AudioWrapperPrivate::signalErrorChange(QMediaPlayer::Error errorCode)
0616 {
0617     if (mError != errorCode) {
0618         mError = errorCode;
0619 
0620         mParent->playerErrorSignalChanges(errorCode);
0621     }
0622 }
0623 
0624 
0625 #include "moc_audiowrapper.cpp"