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 &currentTrack)
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"