File indexing completed on 2024-05-19 04:49:36
0001 /*********************************************************************** 0002 * Copyright 2010 Canonical Ltd 0003 * (author: Aurelien Gateau <aurelien.gateau@canonical.com>) 0004 * Copyright 2012 Eike Hein <hein@kde.org> 0005 * Copyright 2012 Alex Merry <alex.merry@kdemail.net> 0006 * 0007 * This program is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU General Public License as 0009 * published by the Free Software Foundation; either version 2 of 0010 * the License or (at your option) version 3 or any later version 0011 * accepted by the membership of KDE e.V. (or its successor approved 0012 * by the membership of KDE e.V.), which shall act as a proxy 0013 * defined in Section 14 of version 3 of the license. 0014 * 0015 * This program is distributed in the hope that it will be useful, 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0018 * GNU General Public License for more details. 0019 * 0020 * You should have received a copy of the GNU General Public License 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0022 ***********************************************************************/ 0023 0024 #include "MediaPlayer2Player.h" 0025 0026 #include "EngineController.h" 0027 #include "amarokconfig.h" 0028 #include "core/meta/Meta.h" 0029 #include "core/meta/support/MetaUtility.h" 0030 #include "core/support/Debug.h" 0031 #include "playlist/PlaylistActions.h" 0032 #include "playlist/PlaylistController.h" 0033 #include "playlist/PlaylistModelStack.h" 0034 0035 #include <QUrl> 0036 0037 static QDBusObjectPath mprisTrackId(quint64 playlistTrackId) 0038 { 0039 QString path; 0040 if( playlistTrackId > 0 ) { 0041 path = QStringLiteral( "/org/kde/amarok/Track/%1" ).arg( playlistTrackId ); 0042 } else { 0043 // dropped out of the playlist 0044 path = QStringLiteral( "/org/kde/amarok/OrphanTrack" ); 0045 } 0046 return QDBusObjectPath( path ); 0047 } 0048 0049 static QDBusObjectPath activeMprisTrackId() 0050 { 0051 return mprisTrackId( The::playlist()->activeId() ); 0052 } 0053 0054 using namespace Amarok; 0055 0056 MediaPlayer2Player::MediaPlayer2Player(QObject* parent) 0057 : DBusAbstractAdaptor(parent) 0058 , m_lastPosition(-1) 0059 { 0060 connect( The::engineController(), &EngineController::trackPositionChanged, 0061 this, &MediaPlayer2Player::trackPositionChanged ); 0062 // it is important that we receive this signal *after* the playlist code 0063 // has dealt with it, in order to get the right value for mpris:trackid 0064 connect( The::engineController(), &EngineController::trackChanged, 0065 this, &MediaPlayer2Player::trackChanged, 0066 Qt::QueuedConnection ); 0067 connect( The::engineController(), &EngineController::trackMetadataChanged, 0068 this, &MediaPlayer2Player::trackMetadataChanged ); 0069 connect( The::engineController(), &EngineController::albumMetadataChanged, 0070 this, &MediaPlayer2Player::albumMetadataChanged ); 0071 connect( The::engineController(), &EngineController::seekableChanged, 0072 this, &MediaPlayer2Player::seekableChanged ); 0073 connect( The::engineController(), &EngineController::volumeChanged, 0074 this, &MediaPlayer2Player::volumeChanged ); 0075 connect( The::engineController(), &EngineController::trackLengthChanged, 0076 this, &MediaPlayer2Player::trackLengthChanged ); 0077 connect( The::engineController(), &EngineController::playbackStateChanged, 0078 this, &MediaPlayer2Player::playbackStateChanged ); 0079 connect( The::playlistActions(), &Playlist::Actions::navigatorChanged, 0080 this, &MediaPlayer2Player::playlistNavigatorChanged ); 0081 connect( The::playlist()->qaim(), &QAbstractItemModel::rowsInserted, 0082 this, &MediaPlayer2Player::playlistRowsInserted ); 0083 connect( The::playlist()->qaim(), &QAbstractItemModel::rowsMoved, 0084 this, &MediaPlayer2Player::playlistRowsMoved ); 0085 connect( The::playlist()->qaim(), &QAbstractItemModel::rowsRemoved, 0086 this, &MediaPlayer2Player::playlistRowsRemoved ); 0087 connect( The::playlist()->qaim(), &QAbstractItemModel::modelReset, 0088 this, &MediaPlayer2Player::playlistReplaced ); 0089 connect( qobject_cast<Playlist::ProxyBase*>(The::playlist()->qaim()), 0090 &Playlist::ProxyBase::activeTrackChanged, 0091 this, &MediaPlayer2Player::playlistActiveTrackChanged ); 0092 } 0093 0094 MediaPlayer2Player::~MediaPlayer2Player() 0095 { 0096 } 0097 0098 bool MediaPlayer2Player::CanGoNext() const 0099 { 0100 if ( AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatPlaylist ) 0101 { 0102 return The::playlist()->qaim()->rowCount() > 0; 0103 } 0104 else 0105 { 0106 int activeRow = The::playlist()->activeRow(); 0107 return activeRow < The::playlist()->qaim()->rowCount() - 1; 0108 } 0109 } 0110 0111 void MediaPlayer2Player::Next() const 0112 { 0113 The::playlistActions()->next(); 0114 } 0115 0116 bool MediaPlayer2Player::CanGoPrevious() const 0117 { 0118 if ( AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatPlaylist ) 0119 { 0120 return The::playlist()->qaim()->rowCount() > 0; 0121 } 0122 else 0123 { 0124 return The::playlist()->activeRow() > 0; 0125 } 0126 } 0127 0128 void MediaPlayer2Player::Previous() const 0129 { 0130 The::playlistActions()->back(); 0131 } 0132 0133 bool MediaPlayer2Player::CanPause() const 0134 { 0135 return The::engineController()->currentTrack(); 0136 } 0137 0138 void MediaPlayer2Player::Pause() const 0139 { 0140 The::engineController()->pause(); 0141 } 0142 0143 void MediaPlayer2Player::PlayPause() const 0144 { 0145 The::engineController()->playPause(); 0146 } 0147 0148 void MediaPlayer2Player::Stop() const 0149 { 0150 The::engineController()->stop(); 0151 } 0152 0153 bool MediaPlayer2Player::CanPlay() const 0154 { 0155 return The::playlist()->qaim()->rowCount() > 0; 0156 } 0157 0158 void MediaPlayer2Player::Play() const 0159 { 0160 The::engineController()->play(); 0161 } 0162 0163 void MediaPlayer2Player::SetPosition( const QDBusObjectPath& TrackId, qlonglong position ) const 0164 { 0165 QDBusObjectPath activeTrackId = activeMprisTrackId(); 0166 if( TrackId == activeTrackId ) 0167 The::engineController()->seekTo( position / 1000 ); 0168 else 0169 debug() << "SetPosition() called with a trackId (" << TrackId.path() << ") which is not for the active track (" << activeTrackId.path() << ")"; 0170 } 0171 0172 void MediaPlayer2Player::OpenUri( const QString &Uri ) const 0173 { 0174 QUrl url( Uri ); 0175 The::playlistController()->insertOptioned( url, Playlist::OnPlayMediaAction ); 0176 } 0177 0178 QString MediaPlayer2Player::PlaybackStatus() const 0179 { 0180 if( The::engineController()->isPlaying() ) 0181 return QStringLiteral( "Playing" ); 0182 else if ( The::engineController()->isPaused() ) 0183 return QStringLiteral( "Paused" ); 0184 else 0185 return QStringLiteral( "Stopped" ); 0186 } 0187 0188 QString MediaPlayer2Player::LoopStatus() const 0189 { 0190 switch( AmarokConfig::trackProgression() ) 0191 { 0192 case AmarokConfig::EnumTrackProgression::Normal: 0193 case AmarokConfig::EnumTrackProgression::OnlyQueue: 0194 case AmarokConfig::EnumTrackProgression::RandomTrack: 0195 case AmarokConfig::EnumTrackProgression::RandomAlbum: 0196 return QStringLiteral( "None" ); 0197 case AmarokConfig::EnumTrackProgression::RepeatTrack: 0198 return QStringLiteral( "Track" ); 0199 case AmarokConfig::EnumTrackProgression::RepeatAlbum: 0200 case AmarokConfig::EnumTrackProgression::RepeatPlaylist: 0201 return QStringLiteral( "Playlist" ); 0202 default: 0203 Q_ASSERT( false ); 0204 return QStringLiteral( "None" ); 0205 } 0206 } 0207 0208 void MediaPlayer2Player::setLoopStatus( const QString& status ) const 0209 { 0210 AmarokConfig::EnumTrackProgression::type progression; 0211 if( status == QLatin1String( "None" ) ) 0212 progression = AmarokConfig::EnumTrackProgression::Normal; 0213 else if( status == QLatin1String( "Track" ) ) 0214 progression = AmarokConfig::EnumTrackProgression::RepeatTrack; 0215 else if( status == QLatin1String( "Playlist" ) ) 0216 progression = AmarokConfig::EnumTrackProgression::RepeatPlaylist; 0217 else 0218 { 0219 debug() << "Unknown loop status:" << status; 0220 return; 0221 } 0222 0223 AmarokConfig::setTrackProgression( progression ); 0224 The::playlistActions()->playlistModeChanged(); 0225 } 0226 0227 double MediaPlayer2Player::Rate() const 0228 { 0229 return 1.0; 0230 } 0231 0232 void MediaPlayer2Player::setRate( double rate ) const 0233 { 0234 Q_UNUSED(rate) 0235 } 0236 0237 bool MediaPlayer2Player::Shuffle() const 0238 { 0239 switch( AmarokConfig::trackProgression() ) 0240 { 0241 case AmarokConfig::EnumTrackProgression::RandomAlbum: 0242 case AmarokConfig::EnumTrackProgression::RandomTrack: 0243 return true; 0244 default: 0245 return false; 0246 } 0247 } 0248 0249 void MediaPlayer2Player::setShuffle( bool shuffle ) const 0250 { 0251 AmarokConfig::EnumTrackProgression::type progression; 0252 if( shuffle ) 0253 progression = AmarokConfig::EnumTrackProgression::RandomTrack; 0254 else 0255 progression = AmarokConfig::EnumTrackProgression::Normal; 0256 0257 AmarokConfig::setTrackProgression( progression ); 0258 The::playlistActions()->playlistModeChanged(); 0259 } 0260 0261 QVariantMap MediaPlayer2Player::metadataForTrack( const Meta::TrackPtr &track ) const 0262 { 0263 if ( !track ) 0264 return QVariantMap(); 0265 0266 QVariantMap metaData = Meta::Field::mpris20MapFromTrack( track ); 0267 if ( track == The::playlist()->activeTrack() ) 0268 metaData[QStringLiteral("mpris:trackid")] = QVariant::fromValue<QDBusObjectPath>( activeMprisTrackId() ); 0269 else { 0270 // we should be updated shortly 0271 QString path = QStringLiteral( "/org/kde/amarok/PendingTrack" ); 0272 metaData[QStringLiteral("mpris:trackid")] = QVariant::fromValue<QDBusObjectPath>( QDBusObjectPath( path ) ); 0273 } 0274 return metaData; 0275 } 0276 0277 QVariantMap MediaPlayer2Player::Metadata() const 0278 { 0279 return metadataForTrack( The::engineController()->currentTrack() ); 0280 } 0281 0282 double MediaPlayer2Player::Volume() const 0283 { 0284 return static_cast<double>(The::engineController()->volume()) / 100.0; 0285 } 0286 0287 void MediaPlayer2Player::setVolume( double volume ) const 0288 { 0289 if (volume < 0.0) 0290 volume = 0.0; 0291 if (volume > 1.0) 0292 volume = 1.0; 0293 The::engineController()->setVolume( volume * 100 ); 0294 } 0295 0296 qlonglong MediaPlayer2Player::Position() const 0297 { 0298 return The::engineController()->trackPositionMs() * 1000; 0299 } 0300 0301 double MediaPlayer2Player::MinimumRate() const 0302 { 0303 return 1.0; 0304 } 0305 0306 double MediaPlayer2Player::MaximumRate() const 0307 { 0308 return 1.0; 0309 } 0310 0311 bool MediaPlayer2Player::CanSeek() const 0312 { 0313 return The::engineController()->isSeekable(); 0314 } 0315 0316 void MediaPlayer2Player::Seek( qlonglong Offset ) const 0317 { 0318 qlonglong offsetMs = Offset / 1000; 0319 int position = The::engineController()->trackPositionMs() + offsetMs; 0320 if( position < 0 ) 0321 Previous(); 0322 else if( position > The::engineController()->trackLength() ) 0323 Next(); 0324 else 0325 The::engineController()->seekTo( position ); 0326 } 0327 0328 bool MediaPlayer2Player::CanControl() const 0329 { 0330 return true; 0331 } 0332 0333 void MediaPlayer2Player::trackPositionChanged( qint64 position, bool userSeek ) 0334 { 0335 if ( userSeek ) 0336 Q_EMIT Seeked( position * 1000 ); 0337 m_lastPosition = position; 0338 } 0339 0340 void MediaPlayer2Player::trackChanged( const Meta::TrackPtr &track ) 0341 { 0342 signalPropertyChange( QStringLiteral("CanPause"), CanPause() ); 0343 signalPropertyChange( QStringLiteral("Metadata"), metadataForTrack( track ) ); 0344 } 0345 0346 void MediaPlayer2Player::trackMetadataChanged( const Meta::TrackPtr &track ) 0347 { 0348 signalPropertyChange( QStringLiteral("Metadata"), metadataForTrack( track ) ); 0349 } 0350 0351 void MediaPlayer2Player::albumMetadataChanged( const Meta::AlbumPtr &album ) 0352 { 0353 Q_UNUSED( album ) 0354 signalPropertyChange( QStringLiteral("Metadata"), Metadata() ); 0355 } 0356 0357 void MediaPlayer2Player::seekableChanged( bool seekable ) 0358 { 0359 signalPropertyChange( QStringLiteral("CanSeek"), seekable ); 0360 } 0361 0362 void MediaPlayer2Player::volumeChanged( int percent ) 0363 { 0364 DEBUG_BLOCK 0365 signalPropertyChange( QStringLiteral("Volume"), static_cast<double>(percent) / 100.0 ); 0366 } 0367 0368 void MediaPlayer2Player::trackLengthChanged( qint64 milliseconds ) 0369 { 0370 // milliseconds < 0 is not a helpful value, and generally happens 0371 // when the track changes or playback is stopped; these cases are 0372 // dealt with better by other signal handlers 0373 if ( milliseconds >= 0 ) 0374 signalPropertyChange( QStringLiteral("Metadata"), Metadata() ); 0375 } 0376 0377 void MediaPlayer2Player::playbackStateChanged() 0378 { 0379 signalPropertyChange( QStringLiteral("PlaybackStatus"), PlaybackStatus() ); 0380 } 0381 0382 void MediaPlayer2Player::playlistNavigatorChanged() 0383 { 0384 signalPropertyChange( QStringLiteral("CanGoNext"), CanGoNext() ); 0385 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0386 signalPropertyChange( QStringLiteral("LoopStatus"), LoopStatus() ); 0387 signalPropertyChange( QStringLiteral("Shuffle"), Shuffle() ); 0388 } 0389 0390 void MediaPlayer2Player::playlistRowsInserted( const QModelIndex&, int, int ) 0391 { 0392 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0393 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0394 } 0395 0396 void MediaPlayer2Player::playlistRowsMoved( const QModelIndex&, int, int, const QModelIndex&, int ) 0397 { 0398 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0399 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0400 } 0401 0402 void MediaPlayer2Player::playlistRowsRemoved( const QModelIndex&, int, int ) 0403 { 0404 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0405 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0406 } 0407 0408 void MediaPlayer2Player::playlistReplaced() 0409 { 0410 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0411 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0412 } 0413 0414 void MediaPlayer2Player::playlistActiveTrackChanged( quint64 ) 0415 { 0416 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0417 signalPropertyChange( QStringLiteral("CanGoPrevious"), CanGoPrevious() ); 0418 } 0419 0420