File indexing completed on 2022-09-27 14:37:21

0001 /*
0002  *  KCompactDisc - A CD drive interface for the KDE Project.
0003  *
0004  *  Copyright (C) 2005 Shaheedur R. Haque <srhaque@iee.org>
0005  *  Copyright (C) 2007 Alexander Kern <alex.kern@gmx.de>
0006  *
0007  *  This program is free software; you can redistribute it and/or modify
0008  *  it under the terms of the GNU General Public License as published by
0009  *  the Free Software Foundation; either version 2, or (at your option)
0010  *  any later version.
0011  *
0012  *  This program is distributed in the hope that it will be useful,
0013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  *  GNU General Public License for more details.
0016  *
0017  *  You should have received a copy of the GNU General Public License
0018  *  along with this program; if not, write to the Free Software
0019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "kcompactdisc.h"
0023 #include "kcompactdisc_p.h"
0024 
0025 #include <config-alsa.h>
0026 
0027 #include <QDBusInterface>
0028 #include <QDBusReply>
0029 #include <QUrl>
0030 #include <QtGlobal>
0031 
0032 #include <Solid/Device>
0033 #include <Solid/Block>
0034 #include <Solid/OpticalDrive>
0035 
0036 static QMap<QString, QUrl> cdromsNameToDeviceUrl;
0037 static QMap<QString, QString> cdromsNameToUdi;
0038 static QString ___null = QString();
0039 
0040 static void refreshListOfCdromDevices()
0041 {
0042     cdromsNameToDeviceUrl.clear();
0043     cdromsNameToUdi.clear();
0044     QString name, type;
0045     QUrl url;
0046 
0047     //get a list of all devices that are Cdrom
0048     const auto devices = Solid::Device::listFromType(Solid::DeviceInterface::OpticalDrive);
0049     for (const Solid::Device &device : devices) {
0050         qDebug() << device.udi().toLatin1().constData();
0051         const Solid::Block *b = device.as<Solid::Block>();
0052         
0053         if(!b) {
0054             continue;
0055         }
0056 
0057         const Solid::OpticalDrive *o = device.as<Solid::OpticalDrive>();
0058         Solid::OpticalDrive::MediumTypes mediumType = o->supportedMedia();
0059 
0060         url = QUrl::fromUserInput(QLatin1String( b->device().toLatin1() ));
0061         //TODO translate them ?
0062         if(mediumType < Solid::OpticalDrive::Cdrw) {
0063             type = QLatin1String( "CD-ROM" );
0064         } else if(mediumType < Solid::OpticalDrive::Dvd) {
0065             type = QLatin1String( "CDRW" );
0066         } else if(mediumType < Solid::OpticalDrive::Dvdr) {
0067             type = QLatin1String( "DVD-ROM" );
0068         } else if(mediumType < Solid::OpticalDrive::Bd) {
0069             type = QLatin1String( "DVDRW" );
0070         } else if(mediumType < Solid::OpticalDrive::HdDvd) {
0071             type = QLatin1String( "Blu-ray" );
0072         } else {
0073             type = QLatin1String( "High Density DVD" );
0074         }
0075 
0076         if(!device.vendor().isEmpty())
0077             name = (QLatin1Char('[') + type + QLatin1String( " - " ) + device.vendor() + QLatin1String( " - " ) + device.product() + QLatin1Char( ']' ));
0078         else
0079             name = (QLatin1Char('[') + type + QLatin1String( " - unknown vendor - " ) + device.product() + QLatin1Char( ']' ));
0080 
0081         cdromsNameToDeviceUrl.insert(name, url);
0082         cdromsNameToUdi.insert(name, device.udi());
0083     }
0084 #if 0
0085     if(cdromsNameToDeviceUrl.empty()) {
0086         cdromsNameToDeviceUrl.insert(QString("Generic CDROM []"), QUrl::fromPath(wm_drive_default_device()));
0087     }
0088 #endif
0089 }
0090 
0091 static QMap<QString, QUrl> &getListOfCdromDevicesNamesAndUrl()
0092 {
0093     if(cdromsNameToDeviceUrl.empty())
0094         refreshListOfCdromDevices();
0095 
0096     return cdromsNameToDeviceUrl;
0097 }
0098 
0099 static QMap<QString, QString> &getListOfCdromDevicesNamesAndUdi()
0100 {
0101     if(cdromsNameToUdi.empty())
0102         refreshListOfCdromDevices();
0103 
0104     return cdromsNameToUdi;
0105 }
0106 
0107 QString KCompactDisc::urlToDevice(const QUrl &deviceUrl)
0108 {
0109     if(deviceUrl.scheme() == QLatin1String( "media" ) || deviceUrl.scheme() == QLatin1String( "system" )) {
0110         qDebug() << "Asking mediamanager for " << deviceUrl.fileName();
0111 
0112         QDBusInterface mediamanager( QLatin1String( "org.kde.kded" ), QLatin1String( "/modules/mediamanager" ), QLatin1String( "org.kde.MediaManager" ) );
0113         QDBusReply<QStringList> reply = mediamanager.call(QLatin1String( "properties" ), deviceUrl.fileName());
0114 
0115         QStringList properties = reply;
0116         if(!reply.isValid() || properties.count() < 6) {
0117             qCritical() << "Invalid reply from mediamanager";
0118             return deviceUrl.path();
0119         } else {
0120             qDebug() << "Reply from mediamanager " << properties[5];
0121             return properties[5];
0122         }
0123     } else if(deviceUrl.scheme() == QLatin1String( "file" )) {
0124         return deviceUrl.path();
0125     } else {
0126         return QString();
0127     }
0128 }
0129 
0130 const QStringList KCompactDisc::audioSystems()
0131 {
0132     QStringList list;
0133 
0134     list << QLatin1String( "phonon" )
0135 #if defined(HAVE_ALSA)
0136         << QLatin1String( "alsa" )
0137 #endif
0138 #if defined(sun) || defined(__sun__)
0139         << QLatin1String( "sun" )
0140 #endif
0141     ;
0142     return list;
0143 }
0144 
0145 const QStringList KCompactDisc::cdromDeviceNames()
0146 {
0147     return getListOfCdromDevicesNamesAndUrl().keys();
0148 }
0149 
0150 const QString KCompactDisc::defaultCdromDeviceName()
0151 {
0152     const QStringList names = getListOfCdromDevicesNamesAndUrl().keys();
0153     if (!names.isEmpty()) return names[0];
0154     else return QString();
0155 }
0156 
0157 const QUrl KCompactDisc::defaultCdromDeviceUrl()
0158 {
0159     const QList<QUrl> urls = getListOfCdromDevicesNamesAndUrl().values();
0160     if (!urls.isEmpty()) return urls[0];
0161     else return QUrl();
0162 }
0163 
0164 const QUrl KCompactDisc::cdromDeviceUrl(const QString &cdromDeviceName)
0165 {
0166     const QMap<QString, QUrl> &nameUrls = getListOfCdromDevicesNamesAndUrl();
0167     QUrl result = nameUrls.value(cdromDeviceName);
0168     if (!result.isValid())
0169     {
0170         const QUrl passedUrl = QUrl::fromLocalFile(cdromDeviceName);
0171         for (const QUrl &url : nameUrls) {
0172             if (url == passedUrl)
0173             {
0174                 return passedUrl;
0175             }
0176         }
0177         result = KCompactDisc::defaultCdromDeviceUrl();
0178     }
0179     return result;
0180 }
0181 
0182 const QString KCompactDisc::defaultCdromDeviceUdi()
0183 {
0184     const QStringList udis = getListOfCdromDevicesNamesAndUdi().values();
0185     if (!udis.isEmpty()) return udis[0];
0186     else return QString();
0187 }
0188 
0189 const QString KCompactDisc::cdromDeviceUdi(const QString &cdromDeviceName)
0190 {
0191     return getListOfCdromDevicesNamesAndUdi().value(cdromDeviceName, KCompactDisc::defaultCdromDeviceUdi());
0192 }
0193 
0194 KCompactDisc::KCompactDisc(InformationMode infoMode) :
0195     d_ptr(new KCompactDiscPrivate(this, KCompactDisc::defaultCdromDeviceName()))
0196 {
0197     Q_D(KCompactDisc);
0198     d->m_infoMode = infoMode;
0199 }
0200 
0201 KCompactDisc::~KCompactDisc()
0202 {
0203     stop();
0204     delete d_ptr;
0205 }
0206 
0207 const QString &KCompactDisc::deviceVendor()
0208 {
0209     Q_D(KCompactDisc);
0210     return d->m_deviceVendor;
0211 }
0212 
0213 const QString &KCompactDisc::deviceModel()
0214 {
0215     Q_D(KCompactDisc);
0216     return d->m_deviceModel;
0217 }
0218 
0219 const QString &KCompactDisc::deviceRevision()
0220 {
0221     Q_D(KCompactDisc);
0222     return d->m_deviceRevision;
0223 }
0224 
0225 const QString &KCompactDisc::deviceName()
0226 {
0227     Q_D(KCompactDisc);
0228     return d->m_deviceName;
0229 }
0230 
0231 const QUrl KCompactDisc::deviceUrl()
0232 {
0233     Q_D(KCompactDisc);
0234     return KCompactDisc::cdromDeviceUrl(d->m_deviceName);
0235 }
0236 
0237 unsigned KCompactDisc::discId()
0238 {
0239     Q_D(KCompactDisc);
0240     return d->m_discId;
0241 }
0242 
0243 const QList<unsigned> &KCompactDisc::discSignature()
0244 {
0245     Q_D(KCompactDisc);
0246     return d->m_trackStartFrames;
0247 }
0248 
0249 const QString &KCompactDisc::discArtist()
0250 {
0251     Q_D(KCompactDisc);
0252     if (!d->m_tracks)
0253         return ___null;
0254     return d->m_trackArtists[0];
0255 }
0256 
0257 const QString &KCompactDisc::discTitle()
0258 {
0259     Q_D(KCompactDisc);
0260     if (!d->m_tracks)
0261         return ___null;
0262     return d->m_trackTitles[0];
0263 }
0264 
0265 unsigned KCompactDisc::discLength()
0266 {
0267     Q_D(KCompactDisc);
0268     if (!d->m_tracks)
0269         return 0;
0270     return d->m_discLength;
0271 }
0272 
0273 unsigned KCompactDisc::discPosition()
0274 {
0275     Q_D(KCompactDisc);
0276     return d->m_discPosition;
0277 }
0278 
0279 KCompactDisc::DiscStatus KCompactDisc::discStatus()
0280 {
0281     Q_D(KCompactDisc);
0282     return d->m_status;
0283 }
0284 
0285 QString KCompactDisc::discStatusString(KCompactDisc::DiscStatus status)
0286 {
0287     return KCompactDiscPrivate::discStatusI18n(status);
0288 }
0289 
0290 QString KCompactDisc::trackArtist()
0291 {
0292     Q_D(KCompactDisc);
0293     return trackArtist(d->m_track);
0294 }
0295 
0296 QString KCompactDisc::trackArtist(unsigned track)
0297 {
0298     Q_D(KCompactDisc);
0299     if (!track)
0300         return QString();
0301     return d->m_trackArtists[track];
0302 }
0303 
0304 QString KCompactDisc::trackTitle()
0305 {
0306     Q_D(KCompactDisc);
0307     return trackTitle(d->m_track);
0308 }
0309 
0310 QString KCompactDisc::trackTitle(unsigned track)
0311 {
0312     Q_D(KCompactDisc);
0313     if (!track)
0314         return QString();
0315     return d->m_trackTitles[track];
0316 }
0317 
0318 unsigned KCompactDisc::trackLength()
0319 {
0320     Q_D(KCompactDisc);
0321     return trackLength(d->m_track);
0322 }
0323 
0324 unsigned KCompactDisc::trackLength(unsigned track)
0325 {
0326     Q_D(KCompactDisc);
0327     if (!track)
0328         return 0;
0329     return d->trackLength(track);
0330 }
0331 
0332 unsigned KCompactDisc::track()
0333 {
0334     Q_D(KCompactDisc);
0335     return d->m_track;
0336 }
0337 
0338 unsigned KCompactDisc::trackPosition()
0339 {
0340     Q_D(KCompactDisc);
0341     return d->m_trackPosition;
0342 }
0343 
0344 unsigned KCompactDisc::tracks()
0345 {
0346     Q_D(KCompactDisc);
0347     return d->m_tracks;
0348 }
0349 
0350 bool KCompactDisc::isPlaying()
0351 {
0352     Q_D(KCompactDisc);
0353     return (d->m_status == KCompactDisc::Playing);
0354 }
0355 
0356 bool KCompactDisc::isPaused()
0357 {
0358     Q_D(KCompactDisc);
0359     return (d->m_status == KCompactDisc::Paused);
0360 }
0361 
0362 bool KCompactDisc::isNoDisc()
0363 {
0364     Q_D(KCompactDisc);
0365     return (d->m_status == KCompactDisc::NoDisc);
0366 }
0367 
0368 bool KCompactDisc::isAudio(unsigned track)
0369 {
0370     Q_D(KCompactDisc);
0371     if (!track)
0372         return 0;
0373     return d->isTrackAudio(track);
0374 }
0375 
0376 void KCompactDisc::playTrack(unsigned track)
0377 {
0378     Q_D(KCompactDisc);
0379 
0380     d->m_statusExpected = KCompactDisc::Playing;
0381     d->m_trackExpectedPosition = 0;
0382     d->m_seek = abs(int(d->m_trackExpectedPosition - trackPosition()));
0383 
0384     d->playTrackPosition(track, 0);
0385 }
0386 
0387 void KCompactDisc::playPosition(unsigned position)
0388 {
0389     Q_D(KCompactDisc);
0390 
0391     d->m_statusExpected = Playing;
0392     d->m_trackExpectedPosition = position;
0393     d->m_seek = abs(int(d->m_trackExpectedPosition - trackPosition()));
0394 
0395     d->playTrackPosition(d->m_track, position);
0396 }
0397 
0398 void KCompactDisc::play()
0399 {
0400     doCommand(KCompactDisc::Play);
0401 }
0402 
0403 void KCompactDisc::next()
0404 {
0405     doCommand(KCompactDisc::Next);
0406 }
0407 
0408 void KCompactDisc::prev()
0409 {
0410     doCommand(KCompactDisc::Prev);
0411 }
0412 
0413 void KCompactDisc::pause()
0414 {
0415     doCommand(KCompactDisc::Pause);
0416 }
0417 
0418 void KCompactDisc::stop()
0419 {
0420     doCommand(KCompactDisc::Stop);
0421 }
0422 
0423 void KCompactDisc::eject()
0424 {
0425     doCommand(KCompactDisc::Eject);
0426 }
0427 
0428 void KCompactDisc::loop()
0429 {
0430     doCommand(KCompactDisc::Loop);
0431 }
0432 
0433 void KCompactDisc::random()
0434 {
0435     doCommand(KCompactDisc::Random);
0436 }
0437 
0438 void KCompactDisc::doCommand(KCompactDisc::DiscCommand cmd)
0439 {
0440     Q_D(KCompactDisc);
0441     unsigned track;
0442 
0443     switch(cmd) {
0444     case Play:
0445         if(d->m_status == KCompactDisc::Playing)
0446             return;
0447         next();
0448         break;
0449 
0450     case Next:
0451         track = d->getNextTrackInPlaylist();
0452         if(track)
0453             playTrack(track);
0454         break;
0455 
0456     case Prev:
0457         track = d->getPrevTrackInPlaylist();
0458         if(track)
0459             playTrack(track);
0460         break;
0461 
0462     case Pause:
0463         if(d->m_status == KCompactDisc::Paused)
0464             d->m_statusExpected = KCompactDisc::Playing;
0465         else
0466             d->m_statusExpected = KCompactDisc::Paused;
0467 
0468         d->pause();
0469         break;
0470 
0471     case Stop:
0472         d->m_statusExpected = KCompactDisc::Stopped;
0473         d->stop();
0474         break;
0475 
0476     case Eject:
0477         if(d->m_status != KCompactDisc::Ejected) {
0478             if(d->m_status != KCompactDisc::Stopped) {
0479                 d->m_statusExpected = KCompactDisc::Ejected;
0480                 d->stop();
0481             } else {
0482                 d->eject();
0483             }
0484         } else {
0485             d->m_statusExpected = KCompactDisc::Stopped;
0486             d->closetray();
0487         }
0488         break;
0489 
0490     case Loop:
0491         setLoopPlaylist(!d->m_loopPlaylist);
0492         break;
0493 
0494     case Random:
0495         setRandomPlaylist(!d->m_randomPlaylist);
0496         break;
0497     }
0498 }
0499 
0500 void KCompactDisc::metadataLookup()
0501 {
0502     Q_D(KCompactDisc);
0503     d->queryMetadata();
0504 }
0505 
0506 void KCompactDisc::setRandomPlaylist(bool random)
0507 {
0508     Q_D(KCompactDisc);
0509     d->m_randomPlaylist = random;
0510     d->make_playlist();
0511     Q_EMIT randomPlaylistChanged(d->m_randomPlaylist);
0512 }
0513 
0514 void KCompactDisc::setLoopPlaylist(bool loop)
0515 {
0516     Q_D(KCompactDisc);
0517     d->m_loopPlaylist = loop;
0518     Q_EMIT loopPlaylistChanged(d->m_loopPlaylist);
0519 }
0520 
0521 void KCompactDisc::setAutoMetadataLookup(bool autoMetadata)
0522 {
0523     Q_D(KCompactDisc);
0524     d->m_autoMetadata = autoMetadata;
0525     if(d->m_autoMetadata)
0526         metadataLookup();
0527 }
0528 
0529 bool KCompactDisc::setDevice(const QString &deviceName, unsigned volume,
0530     bool digitalPlayback, const QString &audioSystem, const QString &audioDevice)
0531 {
0532     const QString as = digitalPlayback ? audioSystem : QLatin1String("cdin");
0533     const QString ad = digitalPlayback ? audioDevice : QString();
0534     qDebug() << "Device init: " << deviceName << ", " << as << ", " << ad;
0535 
0536     if(d_ptr->moveInterface(deviceName, as, ad)) {
0537         setVolume(volume);
0538         return 1;
0539     } else {
0540         // Severe (OS-level) error.
0541         return 0;
0542     }
0543 }
0544 
0545 void KCompactDisc::setVolume(unsigned volume)
0546 {
0547     Q_D(KCompactDisc);
0548     qDebug() << "change volume: " << volume;
0549     d->setVolume(volume);
0550 }
0551 
0552 void KCompactDisc::setBalance(unsigned balance)
0553 {
0554     Q_D(KCompactDisc);
0555     qDebug() << "change balance: " << balance;
0556     d->setBalance(balance);
0557 }