File indexing completed on 2024-04-21 04:48:59
0001 /* 0002 SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #include "manageaudioplayer.h" 0008 0009 #include "mediaplaylist.h" 0010 0011 #include "elisa_settings.h" 0012 0013 #include "playerLogging.h" 0014 0015 #include <QTimer> 0016 #include <QDateTime> 0017 0018 ManageAudioPlayer::ManageAudioPlayer(QObject *parent) : QObject(parent) 0019 { 0020 0021 } 0022 0023 QPersistentModelIndex ManageAudioPlayer::currentTrack() const 0024 { 0025 return mCurrentTrack; 0026 } 0027 0028 QAbstractItemModel *ManageAudioPlayer::playListModel() const 0029 { 0030 return mPlayListModel; 0031 } 0032 0033 int ManageAudioPlayer::urlRole() const 0034 { 0035 return mUrlRole; 0036 } 0037 0038 int ManageAudioPlayer::isPlayingRole() const 0039 { 0040 return mIsPlayingRole; 0041 } 0042 0043 QUrl ManageAudioPlayer::playerSource() const 0044 { 0045 if (!mCurrentTrack.isValid()) { 0046 return QUrl(); 0047 } 0048 0049 return mCurrentTrack.data(mUrlRole).toUrl(); 0050 } 0051 0052 QMediaPlayer::MediaStatus ManageAudioPlayer::playerStatus() const 0053 { 0054 return mPlayerStatus; 0055 } 0056 0057 QMediaPlayer::PlaybackState ManageAudioPlayer::playerPlaybackState() const 0058 { 0059 return mPlayerPlaybackState; 0060 } 0061 0062 QMediaPlayer::Error ManageAudioPlayer::playerError() const 0063 { 0064 return mPlayerError; 0065 } 0066 0067 qint64 ManageAudioPlayer::audioDuration() const 0068 { 0069 return mAudioDuration; 0070 } 0071 0072 bool ManageAudioPlayer::playerIsSeekable() const 0073 { 0074 return mPlayerIsSeekable; 0075 } 0076 0077 qint64 ManageAudioPlayer::playerPosition() const 0078 { 0079 return mPlayerPosition; 0080 } 0081 0082 qint64 ManageAudioPlayer::playControlPosition() const 0083 { 0084 return mPlayerPosition; 0085 } 0086 0087 QVariantMap ManageAudioPlayer::persistentState() const 0088 { 0089 auto persistentStateValue = QVariantMap(); 0090 0091 persistentStateValue[QStringLiteral("isPlaying")] = mPlayingState; 0092 0093 persistentStateValue[QStringLiteral("playerPosition")] = mPlayerPosition; 0094 persistentStateValue[QStringLiteral("playerDuration")] = mAudioDuration; 0095 0096 if (mCurrentTrack.isValid()) { 0097 persistentStateValue[QStringLiteral("audioPlayerCurrentTitle")] = mCurrentTrack.data(mTitleRole); 0098 persistentStateValue[QStringLiteral("audioPlayerCurrentArtistName")] = mCurrentTrack.data(mArtistNameRole); 0099 persistentStateValue[QStringLiteral("audioPlayerCurrentAlbumName")] = mCurrentTrack.data(mAlbumNameRole); 0100 } else { 0101 persistentStateValue[QStringLiteral("audioPlayerCurrentTitle")] = {}; 0102 persistentStateValue[QStringLiteral("audioPlayerCurrentArtistName")] = {}; 0103 persistentStateValue[QStringLiteral("audioPlayerCurrentAlbumName")] = {}; 0104 } 0105 0106 return persistentStateValue; 0107 } 0108 0109 int ManageAudioPlayer::playListPosition() const 0110 { 0111 if (mCurrentTrack.isValid()) { 0112 return mCurrentTrack.row(); 0113 } 0114 0115 return 0; 0116 } 0117 0118 int ManageAudioPlayer::titleRole() const 0119 { 0120 return mTitleRole; 0121 } 0122 0123 int ManageAudioPlayer::artistNameRole() const 0124 { 0125 return mArtistNameRole; 0126 } 0127 0128 int ManageAudioPlayer::albumNameRole() const 0129 { 0130 return mAlbumNameRole; 0131 } 0132 0133 void ManageAudioPlayer::setCurrentTrack(const QPersistentModelIndex ¤tTrack) 0134 { 0135 mOldCurrentTrack = mCurrentTrack; 0136 0137 mCurrentTrack = currentTrack; 0138 0139 if (mCurrentTrack.isValid()) { 0140 restorePreviousState(); 0141 } 0142 0143 mPlayerError = QMediaPlayer::NoError; 0144 0145 if (mOldCurrentTrack != mCurrentTrack || mPlayingState) { 0146 Q_EMIT currentTrackChanged(); 0147 } 0148 0149 switch (mPlayerPlaybackState) { 0150 case QMediaPlayer::StoppedState: 0151 Q_EMIT playerSourceChanged(mCurrentTrack.data(mUrlRole).toUrl()); 0152 break; 0153 case QMediaPlayer::PlayingState: 0154 case QMediaPlayer::PausedState: 0155 triggerStop(); 0156 if (mPlayingState && !mCurrentTrack.isValid()) { 0157 mPlayingState = false; 0158 } 0159 mSkippingCurrentTrack = true; 0160 break; 0161 } 0162 } 0163 0164 void ManageAudioPlayer::saveForUndoClearPlaylist(){ 0165 mUndoPlayingState = mPlayingState; 0166 0167 mUndoPlayerPosition = mPlayerPosition; 0168 Q_EMIT saveUndoPositionInAudioWrapper(mUndoPlayerPosition); 0169 } 0170 0171 void ManageAudioPlayer::restoreForUndoClearPlaylist(){ 0172 mPlayerPosition = mUndoPlayerPosition; 0173 Q_EMIT seek(mPlayerPosition); 0174 0175 mPlayingState = mUndoPlayingState; 0176 Q_EMIT restoreUndoPositionInAudioWrapper(); 0177 } 0178 0179 void ManageAudioPlayer::setPlayListModel(QAbstractItemModel *aPlayListModel) 0180 { 0181 if (mPlayListModel == aPlayListModel) { 0182 return; 0183 } 0184 0185 if (mPlayListModel) { 0186 disconnect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageAudioPlayer::tracksDataChanged); 0187 } 0188 0189 mPlayListModel = aPlayListModel; 0190 0191 if (mPlayListModel) { 0192 connect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageAudioPlayer::tracksDataChanged); 0193 } 0194 0195 Q_EMIT playListModelChanged(); 0196 } 0197 0198 void ManageAudioPlayer::setUrlRole(int value) 0199 { 0200 mUrlRole = value; 0201 Q_EMIT urlRoleChanged(); 0202 notifyPlayerSourceProperty(); 0203 restorePreviousState(); 0204 } 0205 0206 void ManageAudioPlayer::setIsPlayingRole(int value) 0207 { 0208 if (mIsPlayingRole == value) { 0209 return; 0210 } 0211 0212 mIsPlayingRole = value; 0213 Q_EMIT isPlayingRoleChanged(); 0214 } 0215 0216 void ManageAudioPlayer::setPlayerStatus(QMediaPlayer::MediaStatus playerStatus) 0217 { 0218 if (mPlayerStatus == playerStatus) { 0219 return; 0220 } 0221 0222 mPlayerStatus = playerStatus; 0223 Q_EMIT playerStatusChanged(); 0224 0225 switch (mPlayerStatus) { 0226 case QMediaPlayer::NoMedia: 0227 break; 0228 case QMediaPlayer::LoadingMedia: 0229 break; 0230 case QMediaPlayer::LoadedMedia: 0231 if (mPlayingState) { 0232 triggerPlay(); 0233 } 0234 break; 0235 case QMediaPlayer::BufferingMedia: 0236 break; 0237 case QMediaPlayer::StalledMedia: 0238 break; 0239 case QMediaPlayer::BufferedMedia: 0240 break; 0241 case QMediaPlayer::EndOfMedia: 0242 break; 0243 case QMediaPlayer::InvalidMedia: 0244 triggerSkipNextTrack(); 0245 break; 0246 } 0247 } 0248 0249 void ManageAudioPlayer::setPlayerPlaybackState(QMediaPlayer::PlaybackState playerPlaybackState) 0250 { 0251 if (mPlayerPlaybackState == playerPlaybackState) { 0252 return; 0253 } 0254 0255 mPlayerPlaybackState = playerPlaybackState; 0256 Q_EMIT playerPlaybackStateChanged(); 0257 0258 if (!mSkippingCurrentTrack) { 0259 switch(mPlayerPlaybackState) { 0260 case QMediaPlayer::StoppedState: 0261 if (mPlayerStatus == QMediaPlayer::EndOfMedia) { 0262 Q_EMIT finishedPlayingTrack(mCurrentTrack.data(mUrlRole).toUrl(), QDateTime::currentDateTime()); 0263 } 0264 if (mPlayerStatus == QMediaPlayer::EndOfMedia || mPlayerStatus == QMediaPlayer::InvalidMedia) { 0265 triggerSkipNextTrack(); 0266 } 0267 if (mPlayListModel && mCurrentTrack.isValid()) { 0268 mPlayListModel->setData(mCurrentTrack, MediaPlayList::NotPlaying, mIsPlayingRole); 0269 } 0270 break; 0271 case QMediaPlayer::PlayingState: 0272 if (mPlayListModel && mCurrentTrack.isValid()) { 0273 mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPlaying, mIsPlayingRole); 0274 Q_EMIT startedPlayingTrack(mCurrentTrack.data(mUrlRole).toUrl(), QDateTime::currentDateTime()); 0275 } 0276 break; 0277 case QMediaPlayer::PausedState: 0278 if (mPlayListModel && mCurrentTrack.isValid()) { 0279 mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPaused, mIsPlayingRole); 0280 } 0281 break; 0282 } 0283 } else { 0284 switch(mPlayerPlaybackState) { 0285 case QMediaPlayer::StoppedState: 0286 notifyPlayerSourceProperty(); 0287 mSkippingCurrentTrack = false; 0288 if (mPlayListModel && mOldCurrentTrack.isValid()) { 0289 mPlayListModel->setData(mOldCurrentTrack, MediaPlayList::NotPlaying, mIsPlayingRole); 0290 } 0291 break; 0292 case QMediaPlayer::PlayingState: 0293 if (mPlayListModel && mCurrentTrack.isValid()) { 0294 mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPlaying, mIsPlayingRole); 0295 Q_EMIT startedPlayingTrack(mCurrentTrack.data(mUrlRole).toUrl(), QDateTime::currentDateTime()); 0296 } 0297 break; 0298 case QMediaPlayer::PausedState: 0299 if (mPlayListModel && mCurrentTrack.isValid()) { 0300 mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPaused, mIsPlayingRole); 0301 } 0302 break; 0303 } 0304 } 0305 } 0306 0307 void ManageAudioPlayer::setPlayerError(QMediaPlayer::Error playerError) 0308 { 0309 if (mPlayerError == playerError) { 0310 return; 0311 } 0312 0313 mPlayerError = playerError; 0314 Q_EMIT playerErrorChanged(); 0315 0316 if (mPlayerError != QMediaPlayer::NoError) { 0317 auto currentSource = playerSource(); 0318 0319 Q_EMIT sourceInError(currentSource, mPlayerError); 0320 0321 if (currentSource.isLocalFile()) { 0322 Q_EMIT displayTrackError(currentSource.toLocalFile()); 0323 } else { 0324 Q_EMIT displayTrackError(currentSource.toString()); 0325 } 0326 } 0327 } 0328 0329 void ManageAudioPlayer::ensurePause() 0330 { 0331 if (mPlayingState) { 0332 mPlayingState = false; 0333 triggerPause(); 0334 } 0335 } 0336 0337 void ManageAudioPlayer::ensurePlay() 0338 { 0339 if (!mPlayingState) { 0340 mPlayingState = true; 0341 triggerPlay(); 0342 } 0343 } 0344 0345 void ManageAudioPlayer::requestPlay() { 0346 mPlayingState = true; 0347 } 0348 0349 void ManageAudioPlayer::stop() 0350 { 0351 mPlayingState = false; 0352 triggerStop(); 0353 } 0354 0355 void ManageAudioPlayer::playPause() 0356 { 0357 mPlayingState = !mPlayingState; 0358 0359 switch (mPlayerStatus) { 0360 case QMediaPlayer::LoadedMedia: 0361 case QMediaPlayer::BufferingMedia: 0362 case QMediaPlayer::BufferedMedia: 0363 case QMediaPlayer::LoadingMedia: 0364 if (mPlayingState) { 0365 triggerPlay(); 0366 } else { 0367 triggerPause(); 0368 } 0369 break; 0370 case QMediaPlayer::EndOfMedia: 0371 if (mPlayerPlaybackState == QMediaPlayer::PlayingState && !mPlayingState) { 0372 triggerPause(); 0373 } else if (mPlayerPlaybackState == QMediaPlayer::PausedState && mPlayingState) { 0374 triggerPlay(); 0375 } 0376 break; 0377 case QMediaPlayer::NoMedia: 0378 case QMediaPlayer::StalledMedia: 0379 case QMediaPlayer::InvalidMedia: 0380 break; 0381 } 0382 } 0383 0384 void ManageAudioPlayer::setAudioDuration(qint64 audioDuration) 0385 { 0386 if (mAudioDuration == audioDuration) { 0387 return; 0388 } 0389 0390 mAudioDuration = audioDuration; 0391 Q_EMIT audioDurationChanged(); 0392 } 0393 0394 void ManageAudioPlayer::setPlayerIsSeekable(bool playerIsSeekable) 0395 { 0396 if (mPlayerIsSeekable == playerIsSeekable) { 0397 return; 0398 } 0399 0400 mPlayerIsSeekable = playerIsSeekable; 0401 Q_EMIT playerIsSeekableChanged(); 0402 } 0403 0404 void ManageAudioPlayer::setPlayerPosition(qint64 playerPosition) 0405 { 0406 if (mPlayerPosition == playerPosition) { 0407 return; 0408 } 0409 0410 mPlayerPosition = playerPosition; 0411 Q_EMIT playerPositionChanged(); 0412 QTimer::singleShot(0, this, [this]() {Q_EMIT playControlPositionChanged();}); 0413 } 0414 0415 void ManageAudioPlayer::setCurrentPlayingForRadios(const QString &title, const QString &nowPlaying) 0416 { 0417 if (mPlayListModel && mCurrentTrack.isValid()) { 0418 Q_EMIT updateData(mCurrentTrack, title, MediaPlayList::TitleRole); 0419 Q_EMIT updateData(mCurrentTrack, nowPlaying, MediaPlayList::ArtistRole); 0420 } 0421 } 0422 0423 void ManageAudioPlayer::setPlayControlPosition(int playerPosition) 0424 { 0425 qCDebug(orgKdeElisaPlayer()) << "ManageAudioPlayer::setPlayControlPosition" << playerPosition; 0426 Q_EMIT seek(playerPosition); 0427 } 0428 0429 void ManageAudioPlayer::setPersistentState(const QVariantMap &persistentStateValue) 0430 { 0431 if (mPersistentState == persistentStateValue) { 0432 return; 0433 } 0434 0435 mPersistentState = persistentStateValue; 0436 0437 Q_EMIT persistentStateChanged(); 0438 0439 if (mCurrentTrack.isValid()) { 0440 restorePreviousState(); 0441 } 0442 } 0443 0444 void ManageAudioPlayer::playerSeek(int position) 0445 { 0446 qCDebug(orgKdeElisaPlayer()) << "ManageAudioPlayer::playerSeek" << position; 0447 Q_EMIT seek(position); 0448 } 0449 0450 void ManageAudioPlayer::playListFinished() 0451 { 0452 mPlayingState = false; 0453 } 0454 0455 void ManageAudioPlayer::tracksDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) 0456 { 0457 if (!mCurrentTrack.isValid()) { 0458 return; 0459 } 0460 0461 if (mCurrentTrack.row() > bottomRight.row() || mCurrentTrack.row() < topLeft.row()) { 0462 return; 0463 } 0464 0465 if (mCurrentTrack.column() > bottomRight.column() || mCurrentTrack.column() < topLeft.column()) { 0466 return; 0467 } 0468 0469 if (roles.isEmpty()) { 0470 notifyPlayerSourceProperty(); 0471 restorePreviousState(); 0472 } else { 0473 for(auto oneRole : roles) { 0474 if (oneRole == mUrlRole) { 0475 notifyPlayerSourceProperty(); 0476 restorePreviousState(); 0477 } 0478 } 0479 } 0480 } 0481 0482 void ManageAudioPlayer::setTitleRole(int titleRole) 0483 { 0484 if (mTitleRole == titleRole) { 0485 return; 0486 } 0487 0488 mTitleRole = titleRole; 0489 Q_EMIT titleRoleChanged(); 0490 0491 if (mCurrentTrack.isValid()) { 0492 restorePreviousState(); 0493 } 0494 } 0495 0496 void ManageAudioPlayer::setArtistNameRole(int artistNameRole) 0497 { 0498 if (mArtistNameRole == artistNameRole) { 0499 return; 0500 } 0501 0502 mArtistNameRole = artistNameRole; 0503 Q_EMIT artistNameRoleChanged(); 0504 0505 if (mCurrentTrack.isValid()) { 0506 restorePreviousState(); 0507 } 0508 } 0509 0510 void ManageAudioPlayer::setAlbumNameRole(int albumNameRole) 0511 { 0512 if (mAlbumNameRole == albumNameRole) { 0513 return; 0514 } 0515 0516 mAlbumNameRole = albumNameRole; 0517 Q_EMIT albumNameRoleChanged(); 0518 0519 if (mCurrentTrack.isValid()) { 0520 restorePreviousState(); 0521 } 0522 } 0523 0524 void ManageAudioPlayer::notifyPlayerSourceProperty() 0525 { 0526 auto newUrlValue = mCurrentTrack.data(mUrlRole); 0527 if (mSkippingCurrentTrack || mOldPlayerSource != newUrlValue) { 0528 Q_EMIT playerSourceChanged(mCurrentTrack.data(mUrlRole).toUrl()); 0529 0530 mOldPlayerSource = newUrlValue; 0531 } 0532 } 0533 0534 void ManageAudioPlayer::triggerPlay() 0535 { 0536 QTimer::singleShot(0, this, [this]() {Q_EMIT playerPlay();}); 0537 } 0538 0539 void ManageAudioPlayer::triggerPause() 0540 { 0541 QTimer::singleShot(0, this, [this]() {Q_EMIT playerPause();}); 0542 } 0543 0544 void ManageAudioPlayer::triggerStop() 0545 { 0546 QTimer::singleShot(0, this, [this]() {Q_EMIT playerStop();}); 0547 } 0548 0549 void ManageAudioPlayer::triggerSkipNextTrack(ElisaUtils::SkipReason reason /*= SkipReason::Automatic */) 0550 { 0551 QTimer::singleShot(0, this, [this, reason]() {Q_EMIT skipNextTrack(reason);}); 0552 } 0553 0554 void ManageAudioPlayer::restorePreviousState() 0555 { 0556 if (mPersistentState.isEmpty()) { 0557 return; 0558 } 0559 0560 auto itTitle = mPersistentState.find(QStringLiteral("audioPlayerCurrentTitle")); 0561 auto itArtistName = mPersistentState.find(QStringLiteral("audioPlayerCurrentArtistName")); 0562 auto itAlbumName = mPersistentState.find(QStringLiteral("audioPlayerCurrentAlbumName")); 0563 0564 if (itTitle == mPersistentState.end() || itArtistName == mPersistentState.end() || 0565 itAlbumName == mPersistentState.end()) { 0566 return; 0567 } 0568 0569 if (*itTitle != mCurrentTrack.data(mTitleRole) || 0570 (itArtistName->isValid() && *itArtistName != mCurrentTrack.data(mArtistNameRole)) || 0571 (itAlbumName->isValid() && *itAlbumName != mCurrentTrack.data(mAlbumNameRole))) { 0572 if (mCurrentTrack.isValid() && mCurrentTrack.data(mTitleRole).isValid() && mCurrentTrack.data(mArtistNameRole).isValid() && 0573 mCurrentTrack.data(mAlbumNameRole).isValid()) { 0574 mPersistentState.clear(); 0575 } 0576 0577 return; 0578 } 0579 0580 if (!mCurrentTrack.data(mUrlRole).toUrl().isValid()) { 0581 return; 0582 } 0583 0584 auto isPlaying = mPersistentState.find(QStringLiteral("isPlaying")); 0585 auto currentConfiguration = Elisa::ElisaConfiguration::self(); 0586 bool autoPlay = currentConfiguration->playAtStartup(); 0587 if (autoPlay && isPlaying != mPersistentState.end() && mPlayingState != isPlaying->toBool()) { 0588 mPlayingState = isPlaying->toBool(); 0589 } 0590 0591 auto playerPosition = mPersistentState.find(QStringLiteral("playerPosition")); 0592 if (playerPosition != mPersistentState.end()) { 0593 setPlayerPosition(playerPosition->toLongLong()); 0594 Q_EMIT seek(mPlayerPosition); 0595 } 0596 auto playerDuration = mPersistentState.find(QStringLiteral("playerDuration")); 0597 if (playerDuration != mPersistentState.end()) { 0598 setAudioDuration(playerDuration->toInt()); 0599 } 0600 0601 mPersistentState.clear(); 0602 } 0603 0604 0605 #include "moc_manageaudioplayer.cpp"