File indexing completed on 2025-01-05 04:29:50
0001 /** 0002 * SPDX-FileCopyrightText: 2022-2023 Bart De Vries <bart@mogwai.be> 0003 * SPDX-FileCopyrightText: 2017 Matthieu Gallien <matthieu_gallien@yahoo.fr> 0004 * 0005 * SPDX-License-Identifier: LGPL-3.0-or-later 0006 */ 0007 0008 #include "vlcmediabackend.h" 0009 #include "vlcmediabackendlogging.h" 0010 #include "vlcsignalslogging.h" 0011 0012 #include <QAudio> 0013 #include <QDir> 0014 #include <QGuiApplication> 0015 #include <QTimer> 0016 0017 #include "kmediasession.h" 0018 0019 #if defined Q_OS_WIN 0020 #include <basetsd.h> 0021 typedef SSIZE_T ssize_t; 0022 #endif 0023 0024 #include <vlc/vlc.h> 0025 0026 class VlcMediaBackendPrivate 0027 { 0028 public: 0029 KMediaSession *mKMediaSession = nullptr; 0030 0031 VlcMediaBackend *mParent = nullptr; 0032 0033 libvlc_instance_t *mInstance = nullptr; 0034 0035 libvlc_media_player_t *mPlayer = nullptr; 0036 0037 libvlc_event_manager_t *mPlayerEventManager = nullptr; 0038 libvlc_event_manager_t *mMediaEventManager = nullptr; 0039 0040 libvlc_media_t *mMedia = nullptr; 0041 0042 qint64 mMediaDuration = 0; 0043 0044 KMediaSession::PlaybackState mPreviousPlayerState = KMediaSession::StoppedState; 0045 0046 KMediaSession::MediaStatus mPreviousMediaStatus = KMediaSession::NoMedia; 0047 0048 qreal mPreviousVolume = 100.0; 0049 0050 qint64 mPreviousPosition = 0; 0051 0052 KMediaSession::Error mError = KMediaSession::NoError; 0053 0054 bool mIsMuted = false; 0055 0056 bool mIsSeekable = false; 0057 0058 qreal mPlaybackRate = 1.0; 0059 0060 void vlcEventCallback(const struct libvlc_event_t *p_event); 0061 0062 void mediaIsEnded(); 0063 0064 bool signalPlaybackChange(KMediaSession::PlaybackState newPlayerState); 0065 0066 void signalMediaStatusChange(KMediaSession::MediaStatus newMediaStatus); 0067 0068 void signalVolumeChange(int newVolume); 0069 0070 void signalMutedChange(bool isMuted); 0071 0072 void signalDurationChange(libvlc_time_t newDuration); 0073 0074 void signalPositionChange(float newPosition); 0075 0076 void signalSeekableChange(bool isSeekable); 0077 0078 void signalErrorChange(KMediaSession::Error errorCode); 0079 0080 void parseMetaData(); 0081 }; 0082 0083 static void vlc_callback(const struct libvlc_event_t *p_event, void *p_data) 0084 { 0085 reinterpret_cast<VlcMediaBackendPrivate *>(p_data)->vlcEventCallback(p_event); 0086 } 0087 0088 VlcMediaBackend::VlcMediaBackend(QObject *parent) 0089 : AbstractMediaBackend(parent) 0090 , d(std::make_unique<VlcMediaBackendPrivate>()) 0091 { 0092 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::VlcMediaBackend"; 0093 d->mKMediaSession = static_cast<KMediaSession *>(parent); 0094 d->mParent = this; 0095 0096 // TODO: handle video playback 0097 const char *cmdLineOption = "--no-video"; 0098 d->mInstance = libvlc_new(1, &cmdLineOption); 0099 0100 libvlc_set_user_agent(d->mInstance, d->mKMediaSession->playerName().toUtf8().constData(), d->mKMediaSession->playerName().toUtf8().constData()); 0101 libvlc_set_app_id(d->mInstance, d->mKMediaSession->desktopEntryName().toUtf8().constData(), "1.0", d->mKMediaSession->playerName().toUtf8().constData()); 0102 0103 connect(d->mKMediaSession, &KMediaSession::playerNameChanged, this, &VlcMediaBackend::setPlayerName); 0104 connect(d->mKMediaSession, &KMediaSession::desktopEntryNameChanged, this, &VlcMediaBackend::setDesktopEntryName); 0105 0106 d->mPlayer = libvlc_media_player_new(d->mInstance); 0107 0108 if (!d->mPlayer) { 0109 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::VlcMediaBackend" 0110 << "failed creating player" << libvlc_errmsg(); 0111 return; 0112 } 0113 0114 d->mPlayerEventManager = libvlc_media_player_event_manager(d->mPlayer); 0115 0116 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerOpening, &vlc_callback, d.get()); 0117 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerBuffering, &vlc_callback, d.get()); 0118 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPlaying, &vlc_callback, d.get()); 0119 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPaused, &vlc_callback, d.get()); 0120 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerStopped, &vlc_callback, d.get()); 0121 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEndReached, &vlc_callback, d.get()); 0122 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEncounteredError, &vlc_callback, d.get()); 0123 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPositionChanged, &vlc_callback, d.get()); 0124 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerSeekableChanged, &vlc_callback, d.get()); 0125 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerLengthChanged, &vlc_callback, d.get()); 0126 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerMuted, &vlc_callback, d.get()); 0127 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerUnmuted, &vlc_callback, d.get()); 0128 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioVolume, &vlc_callback, d.get()); 0129 libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioDevice, &vlc_callback, d.get()); 0130 } 0131 0132 VlcMediaBackend::~VlcMediaBackend() 0133 { 0134 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::~VlcMediaBackend"; 0135 if (d->mInstance) { 0136 if (d->mPlayer && d->mPreviousPlayerState != KMediaSession::StoppedState) { 0137 libvlc_media_player_stop(d->mPlayer); 0138 } 0139 libvlc_release(d->mInstance); 0140 } 0141 } 0142 0143 KMediaSession::MediaBackends VlcMediaBackend::backend() const 0144 { 0145 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::backend()"; 0146 return KMediaSession::MediaBackends::Vlc; 0147 } 0148 0149 bool VlcMediaBackend::muted() const 0150 { 0151 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::muted()"; 0152 if (!d->mPlayer) { 0153 return false; 0154 } 0155 0156 qCDebug(VlcMediaBackendLog) << "muted" << d->mIsMuted; 0157 return d->mIsMuted; 0158 } 0159 0160 qreal VlcMediaBackend::volume() const 0161 { 0162 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::volume()"; 0163 if (!d->mPlayer) { 0164 return 100.0; 0165 } 0166 0167 qCDebug(VlcMediaBackendLog) << "volume" << d->mPreviousVolume; 0168 return d->mPreviousVolume; 0169 } 0170 0171 QUrl VlcMediaBackend::source() const 0172 { 0173 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::source()"; 0174 if (!d->mPlayer) { 0175 return {}; 0176 } 0177 if (d->mMedia) { 0178 auto filePath = QString::fromUtf8(libvlc_media_get_mrl(d->mMedia)); 0179 return QUrl::fromUserInput(filePath); 0180 } 0181 return {}; 0182 } 0183 0184 KMediaSession::Error VlcMediaBackend::error() const 0185 { 0186 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::error()"; 0187 return d->mError; 0188 } 0189 0190 qint64 VlcMediaBackend::duration() const 0191 { 0192 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::duration()"; 0193 return d->mMediaDuration; 0194 } 0195 0196 qint64 VlcMediaBackend::position() const 0197 { 0198 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::position()"; 0199 if (!d->mPlayer) { 0200 return 0; 0201 } 0202 0203 if (d->mMediaDuration == -1) { 0204 return 0; 0205 } 0206 0207 qint64 currentPosition = qRound64(libvlc_media_player_get_position(d->mPlayer) * d->mMediaDuration); 0208 0209 if (currentPosition < 0) { 0210 return 0; 0211 } 0212 0213 return currentPosition; 0214 } 0215 0216 qreal VlcMediaBackend::playbackRate() const 0217 { 0218 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playbackRate()"; 0219 if (d->mPlayer) { 0220 return libvlc_media_player_get_rate(d->mPlayer); 0221 } 0222 return 1.0; 0223 } 0224 0225 bool VlcMediaBackend::seekable() const 0226 { 0227 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::seekable()"; 0228 return d->mIsSeekable; 0229 } 0230 0231 KMediaSession::PlaybackState VlcMediaBackend::playbackState() const 0232 { 0233 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playbackState()"; 0234 return d->mPreviousPlayerState; 0235 } 0236 0237 KMediaSession::MediaStatus VlcMediaBackend::mediaStatus() const 0238 { 0239 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::mediaStatus()"; 0240 return d->mPreviousMediaStatus; 0241 } 0242 0243 void VlcMediaBackend::setMuted(bool muted) 0244 { 0245 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setMuted(" << muted << ")"; 0246 0247 if (d->mPlayer) { 0248 libvlc_audio_set_mute(d->mPlayer, muted); 0249 } else { 0250 d->mIsMuted = muted; 0251 Q_EMIT mutedChanged(muted); 0252 } 0253 } 0254 0255 void VlcMediaBackend::setVolume(qreal volume) 0256 { 0257 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setVolume(" << volume << ")"; 0258 0259 if (d->mPlayer && d->mPreviousPlayerState != KMediaSession::PlaybackState::StoppedState) { 0260 libvlc_audio_set_volume(d->mPlayer, qRound(volume)); 0261 } 0262 } 0263 0264 void VlcMediaBackend::setSource(const QUrl &source) 0265 { 0266 if (playbackState() != KMediaSession::PlaybackState::StoppedState) { 0267 stop(); 0268 } 0269 0270 d->mMediaDuration = 0; 0271 d->mIsSeekable = false; 0272 d->mPlaybackRate = 1.0; 0273 d->mPreviousPosition = 0; 0274 d->mPreviousPlayerState = KMediaSession::PlaybackState::StoppedState; 0275 0276 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setSource(" << source << ")"; 0277 if (source.isLocalFile()) { 0278 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setSource reading local resource"; 0279 d->mMedia = libvlc_media_new_path(d->mInstance, QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData()); 0280 } else { 0281 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setSource reading remote resource"; 0282 d->mMedia = libvlc_media_new_location(d->mInstance, source.url().toUtf8().constData()); 0283 } 0284 0285 if (!d->mMedia) { 0286 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setSource" 0287 << "failed creating media" << libvlc_errmsg() << QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData(); 0288 0289 d->mMedia = libvlc_media_new_path(d->mInstance, QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData()); 0290 if (!d->mMedia) { 0291 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setSource" 0292 << "failed creating media" << libvlc_errmsg() << QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData(); 0293 return; 0294 } 0295 } 0296 0297 // By default, libvlc caches only next 1000 (ms, 0..60000) of the playback, 0298 // which is unreasonable given our usecase of sequential playback. 0299 libvlc_media_add_option(d->mMedia, ":file-caching=10000"); 0300 libvlc_media_add_option(d->mMedia, ":live-caching=10000"); 0301 libvlc_media_add_option(d->mMedia, ":disc-caching=10000"); 0302 libvlc_media_add_option(d->mMedia, ":network-caching=10000"); 0303 0304 libvlc_media_player_set_media(d->mPlayer, d->mMedia); 0305 0306 d->signalMediaStatusChange(KMediaSession::LoadingMedia); 0307 d->signalMediaStatusChange(KMediaSession::LoadedMedia); 0308 d->signalMediaStatusChange(KMediaSession::BufferedMedia); 0309 0310 d->mMediaEventManager = libvlc_media_event_manager(d->mMedia); 0311 0312 libvlc_event_attach(d->mMediaEventManager, libvlc_MediaParsedChanged, &vlc_callback, d.get()); 0313 libvlc_event_attach(d->mMediaEventManager, libvlc_MediaDurationChanged, &vlc_callback, d.get()); 0314 0315 libvlc_media_parse_with_options( 0316 d->mMedia, 0317 static_cast<libvlc_media_parse_flag_t>(libvlc_media_parse_local | libvlc_media_parse_network | libvlc_media_fetch_local | libvlc_media_fetch_network), 0318 0); 0319 0320 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::sourceChanged(" << source << ")"; 0321 QTimer::singleShot(0, this, [this, source]() { 0322 Q_EMIT sourceChanged(source); 0323 }); 0324 } 0325 0326 void VlcMediaBackend::setPosition(qint64 position) 0327 { 0328 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setPosition(" << position << ")"; 0329 0330 if (!d->mPlayer) { 0331 return; 0332 } 0333 0334 if (d->mMediaDuration == -1 || d->mMediaDuration == 0) { 0335 return; 0336 } 0337 0338 libvlc_media_player_set_position(d->mPlayer, static_cast<float>(position) / d->mMediaDuration); 0339 } 0340 0341 void VlcMediaBackend::setPlaybackRate(qreal rate) 0342 { 0343 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setPlaybackRate(" << rate << ")"; 0344 if (d->mPlayer) { 0345 if (libvlc_media_player_set_rate(d->mPlayer, static_cast<float>(rate)) == 0) { 0346 d->mPlaybackRate = rate; 0347 QTimer::singleShot(0, this, [this, rate]() { 0348 Q_EMIT playbackRateChanged(rate); 0349 }); 0350 } 0351 } 0352 } 0353 0354 void VlcMediaBackend::play() 0355 { 0356 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::play()"; 0357 if (!d->mPlayer) { 0358 return; 0359 } 0360 0361 libvlc_media_player_play(d->mPlayer); 0362 } 0363 0364 void VlcMediaBackend::pause() 0365 { 0366 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::pause()"; 0367 if (!d->mPlayer) { 0368 return; 0369 } 0370 0371 // need to check playback state first, because the pause function will 0372 // actually toggle pause, i.e. it will start playing when the current track 0373 // has already been paused 0374 if (playbackState() == KMediaSession::PlaybackState::PlayingState) { 0375 libvlc_media_player_pause(d->mPlayer); 0376 } 0377 } 0378 0379 void VlcMediaBackend::stop() 0380 { 0381 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::stop()"; 0382 if (!d->mPlayer) { 0383 return; 0384 } 0385 0386 d->mIsSeekable = false; 0387 QTimer::singleShot(0, this, [this]() { 0388 Q_EMIT seekableChanged(d->mIsSeekable); 0389 }); 0390 0391 libvlc_media_player_stop(d->mPlayer); 0392 } 0393 0394 void VlcMediaBackend::playerStateSignalChanges(KMediaSession::PlaybackState newState) 0395 { 0396 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerStateSignalChanges(" << newState << ")"; 0397 QTimer::singleShot(0, this, [this, newState]() { 0398 Q_EMIT playbackStateChanged(newState); 0399 if (newState == KMediaSession::PlaybackState::StoppedState) { 0400 Q_EMIT positionChanged(position()); 0401 } else { 0402 Q_EMIT mutedChanged(muted()); 0403 } 0404 }); 0405 } 0406 0407 void VlcMediaBackend::mediaStatusSignalChanges(KMediaSession::MediaStatus newStatus) 0408 { 0409 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::mediaStatusSignalChanges(" << newStatus << ")"; 0410 QTimer::singleShot(0, this, [this, newStatus]() { 0411 Q_EMIT mediaStatusChanged(newStatus); 0412 }); 0413 } 0414 0415 void VlcMediaBackend::playerErrorSignalChanges(KMediaSession::Error error) 0416 { 0417 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerErrorSignalChanges(" << error << ")"; 0418 QTimer::singleShot(0, this, [this, error]() { 0419 Q_EMIT errorChanged(error); 0420 }); 0421 } 0422 0423 void VlcMediaBackend::playerDurationSignalChanges(qint64 newDuration) 0424 { 0425 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerDurationSignalChanges(" << newDuration << ")"; 0426 d->mMediaDuration = newDuration; 0427 QTimer::singleShot(0, this, [this, newDuration]() { 0428 Q_EMIT durationChanged(newDuration); 0429 }); 0430 } 0431 0432 void VlcMediaBackend::playerPositionSignalChanges(qint64 newPosition) 0433 { 0434 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerPositionSignalChanges(" << newPosition << ")"; 0435 QTimer::singleShot(0, this, [this, newPosition]() { 0436 Q_EMIT positionChanged(newPosition); 0437 }); 0438 } 0439 0440 void VlcMediaBackend::playerVolumeSignalChanges(qreal volume) 0441 { 0442 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerVolumeSignalChanges(" << volume << ")"; 0443 QTimer::singleShot(0, this, [this, volume]() { 0444 Q_EMIT volumeChanged(volume); 0445 }); 0446 } 0447 0448 void VlcMediaBackend::playerMutedSignalChanges(bool isMuted) 0449 { 0450 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerMutedSignalChanges(" << isMuted << ")"; 0451 QTimer::singleShot(0, this, [this, isMuted]() { 0452 Q_EMIT mutedChanged(isMuted); 0453 }); 0454 } 0455 0456 void VlcMediaBackend::playerSeekableSignalChanges(bool isSeekable) 0457 { 0458 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::playerSeekableSignalChanges(" << isSeekable << ")"; 0459 QTimer::singleShot(0, this, [this, isSeekable]() { 0460 Q_EMIT seekableChanged(isSeekable); 0461 }); 0462 } 0463 0464 void VlcMediaBackend::setPlayerName(const QString &name) 0465 { 0466 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setPlayerName(" << name << ")"; 0467 libvlc_set_user_agent(d->mInstance, name.toUtf8().constData(), name.toUtf8().constData()); 0468 libvlc_set_app_id(d->mInstance, d->mKMediaSession->desktopEntryName().toUtf8().constData(), "1.0", name.toUtf8().constData()); 0469 } 0470 0471 void VlcMediaBackend::setDesktopEntryName(const QString &name) 0472 { 0473 qCDebug(VlcMediaBackendLog) << "VlcMediaBackend::setDesktopEntryName(" << name << ")"; 0474 libvlc_set_app_id(d->mInstance, name.toUtf8().constData(), "1.0", d->mKMediaSession->playerName().toUtf8().constData()); 0475 } 0476 0477 void VlcMediaBackendPrivate::vlcEventCallback(const struct libvlc_event_t *p_event) 0478 { 0479 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback()"; 0480 const auto eventType = static_cast<libvlc_event_e>(p_event->type); 0481 0482 switch (eventType) { 0483 case libvlc_MediaPlayerOpening: 0484 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0485 << "libvlc_MediaPlayerOpening"; 0486 signalMediaStatusChange(KMediaSession::LoadedMedia); 0487 break; 0488 case libvlc_MediaPlayerBuffering: 0489 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0490 << "libvlc_MediaPlayerBuffering"; 0491 signalMediaStatusChange(KMediaSession::BufferedMedia); 0492 break; 0493 case libvlc_MediaPlayerPlaying: 0494 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0495 << "libvlc_MediaPlayerPlaying"; 0496 signalPlaybackChange(KMediaSession::PlayingState); 0497 break; 0498 case libvlc_MediaPlayerPaused: 0499 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0500 << "libvlc_MediaPlayerPaused"; 0501 signalPlaybackChange(KMediaSession::PausedState); 0502 break; 0503 case libvlc_MediaPlayerStopped: 0504 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0505 << "libvlc_MediaPlayerStopped"; 0506 signalPlaybackChange(KMediaSession::StoppedState); 0507 break; 0508 case libvlc_MediaPlayerEndReached: 0509 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0510 << "libvlc_MediaPlayerEndReached"; 0511 signalMediaStatusChange(KMediaSession::BufferedMedia); 0512 signalMediaStatusChange(KMediaSession::NoMedia); 0513 signalMediaStatusChange(KMediaSession::EndOfMedia); 0514 mediaIsEnded(); 0515 break; 0516 case libvlc_MediaPlayerEncounteredError: 0517 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0518 << "libvlc_MediaPlayerEncounteredError"; 0519 signalErrorChange(KMediaSession::ResourceError); 0520 mediaIsEnded(); 0521 signalMediaStatusChange(KMediaSession::InvalidMedia); 0522 break; 0523 case libvlc_MediaPlayerPositionChanged: 0524 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0525 << "libvlc_MediaPlayerPositionChanged"; 0526 signalPositionChange(p_event->u.media_player_position_changed.new_position); 0527 break; 0528 case libvlc_MediaPlayerSeekableChanged: 0529 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0530 << "libvlc_MediaPlayerSeekableChanged"; 0531 signalSeekableChange(p_event->u.media_player_seekable_changed.new_seekable); 0532 break; 0533 case libvlc_MediaPlayerLengthChanged: 0534 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0535 << "libvlc_MediaPlayerLengthChanged"; 0536 signalDurationChange(p_event->u.media_player_length_changed.new_length); 0537 break; 0538 case libvlc_MediaPlayerMuted: 0539 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0540 << "libvlc_MediaPlayerMuted"; 0541 signalMutedChange(true); 0542 break; 0543 case libvlc_MediaPlayerUnmuted: 0544 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0545 << "libvlc_MediaPlayerUnmuted"; 0546 signalMutedChange(false); 0547 break; 0548 case libvlc_MediaPlayerAudioVolume: 0549 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0550 << "libvlc_MediaPlayerAudioVolume"; 0551 signalVolumeChange(qRound(p_event->u.media_player_audio_volume.volume * 100)); 0552 break; 0553 case libvlc_MediaPlayerAudioDevice: 0554 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0555 << "libvlc_MediaPlayerAudioDevice"; 0556 break; 0557 case libvlc_MediaDurationChanged: 0558 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0559 << "libvlc_MediaDurationChanged"; 0560 signalDurationChange(p_event->u.media_duration_changed.new_duration); 0561 break; 0562 case libvlc_MediaParsedChanged: 0563 if (p_event->u.media_parsed_changed.new_status == libvlc_media_parsed_status_done) { 0564 parseMetaData(); 0565 } 0566 break; 0567 default: 0568 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::vlcEventCallback" 0569 << "eventType" << eventType; 0570 break; 0571 } 0572 } 0573 0574 void VlcMediaBackendPrivate::mediaIsEnded() 0575 { 0576 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::mediaIsEnded()"; 0577 0578 mIsSeekable = false; 0579 Q_EMIT mParent->seekableChanged(mIsSeekable); 0580 0581 libvlc_media_release(mMedia); 0582 mMedia = nullptr; 0583 } 0584 0585 bool VlcMediaBackendPrivate::signalPlaybackChange(KMediaSession::PlaybackState newPlayerState) 0586 { 0587 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalPlaybackChange(" << newPlayerState << ")"; 0588 if (mPreviousPlayerState != newPlayerState) { 0589 mPreviousPlayerState = newPlayerState; 0590 0591 mParent->playerStateSignalChanges(mPreviousPlayerState); 0592 return true; 0593 } 0594 0595 return false; 0596 } 0597 0598 void VlcMediaBackendPrivate::signalMediaStatusChange(KMediaSession::MediaStatus newMediaStatus) 0599 { 0600 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalMediaStatusChange(" << newMediaStatus << ")"; 0601 if (mPreviousMediaStatus != newMediaStatus) { 0602 mPreviousMediaStatus = newMediaStatus; 0603 0604 mParent->mediaStatusSignalChanges(mPreviousMediaStatus); 0605 } 0606 } 0607 0608 void VlcMediaBackendPrivate::signalVolumeChange(int newVolume) 0609 { 0610 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalVolumeChange(" << newVolume << ")"; 0611 if (newVolume == -100) { 0612 return; 0613 } 0614 0615 if (abs(int(mPreviousVolume - newVolume)) > 0.01) { 0616 mPreviousVolume = newVolume; 0617 0618 mParent->playerVolumeSignalChanges(newVolume); 0619 } 0620 } 0621 0622 void VlcMediaBackendPrivate::signalMutedChange(bool isMuted) 0623 { 0624 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalMutedChange(" << isMuted << ")"; 0625 if (mIsMuted != isMuted) { 0626 mIsMuted = isMuted; 0627 0628 mParent->playerMutedSignalChanges(mIsMuted); 0629 } 0630 } 0631 0632 void VlcMediaBackendPrivate::signalDurationChange(libvlc_time_t newDuration) 0633 { 0634 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalDurationChange(" << newDuration << ")"; 0635 if (mMediaDuration != newDuration) { 0636 mMediaDuration = newDuration; 0637 0638 mParent->playerDurationSignalChanges(mMediaDuration); 0639 } 0640 } 0641 0642 void VlcMediaBackendPrivate::signalPositionChange(float newPosition) 0643 { 0644 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalPositionChange(" << newPosition << ")"; 0645 if (mMediaDuration == -1) { 0646 return; 0647 } 0648 0649 if (newPosition < 0) { 0650 mPreviousPosition = 0; 0651 mParent->playerPositionSignalChanges(mPreviousPosition); 0652 return; 0653 } 0654 0655 auto computedPosition = qRound64(newPosition * mMediaDuration); 0656 0657 if (mPreviousPosition != computedPosition) { 0658 mPreviousPosition = computedPosition; 0659 0660 mParent->playerPositionSignalChanges(mPreviousPosition); 0661 } 0662 } 0663 0664 void VlcMediaBackendPrivate::signalSeekableChange(bool isSeekable) 0665 { 0666 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalSeekableChange(" << isSeekable << ")"; 0667 if (mIsSeekable != isSeekable) { 0668 mIsSeekable = isSeekable; 0669 0670 mParent->playerSeekableSignalChanges(isSeekable); 0671 } 0672 } 0673 0674 void VlcMediaBackendPrivate::signalErrorChange(KMediaSession::Error errorCode) 0675 { 0676 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::signalErrorChange(" << errorCode << ")"; 0677 if (mError != errorCode) { 0678 mError = errorCode; 0679 0680 mParent->playerErrorSignalChanges(errorCode); 0681 } 0682 } 0683 0684 void VlcMediaBackendPrivate::parseMetaData() 0685 { 0686 qCDebug(VlcSignalsLog) << "VlcMediaBackendPrivate::parseMetaData()"; 0687 if (mMedia && mKMediaSession->metaData()->title().isEmpty()) { 0688 mKMediaSession->metaData()->setTitle(QString::fromUtf8(libvlc_media_get_meta(mMedia, libvlc_meta_Title))); 0689 } 0690 if (mMedia && mKMediaSession->metaData()->artist().isEmpty()) { 0691 mKMediaSession->metaData()->setArtist(QString::fromUtf8(libvlc_media_get_meta(mMedia, libvlc_meta_Artist))); 0692 } 0693 if (mMedia && mKMediaSession->metaData()->album().isEmpty()) { 0694 mKMediaSession->metaData()->setAlbum(QString::fromUtf8(libvlc_media_get_meta(mMedia, libvlc_meta_Album))); 0695 } 0696 if (mMedia && mKMediaSession->metaData()->artworkUrl().isEmpty()) { 0697 mKMediaSession->metaData()->setArtworkUrl(QUrl(QString::fromUtf8(libvlc_media_get_meta(mMedia, libvlc_meta_ArtworkURL)))); 0698 } 0699 }