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

0001 /*
0002  *
0003  * Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>
0004  * Copyright (C) by Alexander Kern <alex.kern@gmx.de>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public
0017  * License along with this library; if not, write to the Free
0018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0019  *
0020  *
0021  * CDDA version taken from guitest in phonon test directory
0022  */
0023 
0024 #include "phonon_interface.h"
0025 
0026 #include <QtGlobal>
0027 
0028 #include <KLocalizedString>
0029 
0030 #include <phonon/Global>
0031 #include <phonon/MediaObject>
0032 #include <phonon/AudioOutput>
0033 #include <phonon/Path>
0034 #include <phonon/MediaController>
0035 
0036 #include <Solid/Device>
0037 #include <Solid/OpticalDrive>
0038 #include <Solid/OpticalDisc>
0039 
0040 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
0041 
0042 using namespace Phonon;
0043 
0044 class ProducerWidget : public QObject
0045 {
0046     public:
0047         ProducerWidget(KPhononCompactDiscPrivate *, const QString &);
0048         ~ProducerWidget() override;
0049 
0050     public:
0051         MediaObject *m_media;
0052         AudioOutput *m_output;
0053         MediaController *m_mediaController;
0054 };
0055 
0056 ProducerWidget::ProducerWidget(KPhononCompactDiscPrivate *p, const QString &Udi) :
0057     m_media(nullptr),
0058     m_output(nullptr),
0059     m_mediaController(nullptr)
0060 {
0061     m_media = new MediaObject(this);
0062     connect(m_media, SIGNAL(metaDataChanged()), SLOT(updateMetaData()));
0063     m_media->setTickInterval(1000);
0064 
0065     m_output = new AudioOutput(Phonon::MusicCategory, this);
0066     Phonon::createPath(m_media, m_output);
0067 
0068     connect(m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
0069             p, SLOT(stateChanged(Phonon::State,Phonon::State)));
0070 
0071     connect(m_media, SIGNAL(tick(qint64)), p, SLOT(tick(qint64)));
0072 
0073     MediaSource *m_mediaSource = new MediaSource(Phonon::Cd, Udi);
0074     m_media->setCurrentSource(*m_mediaSource);
0075 
0076     m_mediaController = new MediaController(m_media);
0077 }
0078 
0079 ProducerWidget::~ProducerWidget()
0080 {
0081     delete(m_mediaController);
0082     delete(m_output);
0083     delete(m_media);
0084 }
0085 
0086 KPhononCompactDiscPrivate::KPhononCompactDiscPrivate(KCompactDisc *p,
0087     const QString &dev) :
0088     KCompactDiscPrivate(p, dev),
0089     m_producerWidget(nullptr),
0090     m_udi(KCompactDisc::cdromDeviceUdi(dev))
0091 {
0092     m_interface = QLatin1String("phonon");
0093 }
0094 
0095 KPhononCompactDiscPrivate::~KPhononCompactDiscPrivate()
0096 {
0097     delete m_producerWidget;
0098     m_producerWidget = nullptr;
0099 }
0100 
0101 bool KPhononCompactDiscPrivate::createInterface()
0102 {
0103     qDebug() << "createInterface called";
0104     Solid::Device opticalDevice(m_udi);
0105     Solid::OpticalDrive *opticalDrive = opticalDevice.as<Solid::OpticalDrive>();
0106 
0107     if(opticalDrive) {
0108         Q_Q(KCompactDisc);
0109 
0110         m_deviceVendor = opticalDevice.vendor();
0111         m_deviceModel = opticalDevice.product();
0112 
0113         Q_EMIT q->discChanged(0);
0114 
0115         producer();
0116 
0117         return true;
0118     }
0119 
0120     return false;
0121 }
0122 
0123 ProducerWidget *KPhononCompactDiscPrivate::producer()
0124 {
0125     //try to create
0126     if(!m_producerWidget) {
0127         Solid::Device opticalDevice(m_udi);
0128         Solid::OpticalDrive *opticalDrive = opticalDevice.as<Solid::OpticalDrive>();
0129         qDebug() << "producer called, opticalDrive is " << opticalDrive;
0130 
0131         if(opticalDrive) {
0132             Solid::OpticalDisc *opticalDisc = opticalDevice.as<Solid::OpticalDisc>();
0133             qDebug() << "opticalDisc " << opticalDisc;
0134             //if(opticalDisc && (opticalDisc->availableContent() == Solid::OpticalDisc::Audio)) {
0135                 m_producerWidget = new ProducerWidget(this, m_udi);
0136                 stateChanged(m_producerWidget->m_media->state(), Phonon::StoppedState);
0137             //}
0138         }
0139     }
0140 
0141     return m_producerWidget;
0142 }
0143 
0144 unsigned KPhononCompactDiscPrivate::trackLength(unsigned track)
0145 {
0146     if(!producer() || m_producerWidget->m_mediaController->currentTitle() != track)
0147         return 0;
0148 
0149     return MS2SEC(m_producerWidget->m_media->totalTime());
0150 }
0151 
0152 bool KPhononCompactDiscPrivate::isTrackAudio(unsigned)
0153 {
0154     return true;
0155 }
0156 
0157 void KPhononCompactDiscPrivate::playTrackPosition(unsigned track, unsigned position)
0158 {
0159     if(!producer())
0160         return;
0161 
0162     qDebug() << "play track " << track << " position " << position;
0163 
0164     m_producerWidget->m_mediaController->setCurrentTitle(track);
0165     m_producerWidget->m_media->seek(SEC2MS(position));
0166     Q_EMIT m_producerWidget->m_media->play();
0167 }
0168 
0169 void KPhononCompactDiscPrivate::pause()
0170 {
0171     if(!producer())
0172         return;
0173 
0174     Q_EMIT m_producerWidget->m_media->pause();
0175 }
0176 
0177 void KPhononCompactDiscPrivate::stop()
0178 {
0179     if(!producer())
0180         return;
0181 
0182     Q_EMIT m_producerWidget->m_media->stop();
0183 }
0184 
0185 void KPhononCompactDiscPrivate::eject()
0186 {
0187     Solid::Device opticalDevice(m_udi);
0188     Solid::OpticalDrive *opticalDrive = opticalDevice.as<Solid::OpticalDrive>();
0189     Solid::OpticalDisc *opticalDisc = opticalDevice.as<Solid::OpticalDisc>();
0190 
0191     if(!opticalDrive || !opticalDisc)
0192         return;
0193 
0194     opticalDrive->eject();
0195 }
0196 
0197 void KPhononCompactDiscPrivate::closetray()
0198 {
0199     Solid::Device opticalDevice(m_udi);
0200     Solid::OpticalDrive *opticalDrive = opticalDevice.as<Solid::OpticalDrive>();
0201     Solid::OpticalDisc *opticalDisc = opticalDevice.as<Solid::OpticalDisc>();
0202 
0203     if(!opticalDrive || opticalDisc)
0204         return;
0205 
0206     opticalDrive->eject();
0207 }
0208 
0209 void KPhononCompactDiscPrivate::setVolume(unsigned volume)
0210 {
0211     if(!producer())
0212         return;
0213 
0214     /* 1.0 = 100% */
0215     m_producerWidget->m_output->setVolume(volume * 0.01);
0216 }
0217 
0218 void KPhononCompactDiscPrivate::setBalance(unsigned)
0219 {
0220 }
0221 
0222 unsigned KPhononCompactDiscPrivate::volume()
0223 {
0224     if(!producer())
0225         return 0;
0226 
0227     return (unsigned)(m_producerWidget->m_output->volume() * 100.0);
0228 }
0229 
0230 unsigned KPhononCompactDiscPrivate::balance()
0231 {
0232     return 50;
0233 }
0234 
0235 void KPhononCompactDiscPrivate::queryMetadata()
0236 {
0237     Q_Q(KCompactDisc);
0238 
0239     if(!producer())
0240         return;
0241 
0242     QMultiMap<QString, QString> data = m_producerWidget->m_media->metaData();
0243     qDebug() << "METADATA";
0244     //qDebug() << data;
0245 
0246     m_trackArtists[0] = data.take(QLatin1String( "ARTIST" ));
0247     m_trackTitles[0] = data.take(QLatin1String( "ALBUM" ));
0248 
0249     m_trackArtists[m_track] = data.take(QLatin1String( "ARTIST" ));
0250     m_trackTitles[m_track] = data.take(QLatin1String( "TITLE" ));
0251 
0252     Q_EMIT q->discInformation(KCompactDisc::PhononMetadata);
0253 }
0254 
0255 KCompactDisc::DiscStatus KPhononCompactDiscPrivate::discStatusTranslate(Phonon::State state)
0256 {
0257     switch (state) {
0258     case Phonon::PlayingState:
0259         return KCompactDisc::Playing;
0260     case Phonon::PausedState:
0261         return KCompactDisc::Paused;
0262     case Phonon::StoppedState:
0263         return KCompactDisc::Stopped;
0264     case Phonon::ErrorState:
0265         return KCompactDisc::NoDisc;
0266     case Phonon::LoadingState:
0267     case Phonon::BufferingState:
0268         return KCompactDisc::NotReady;
0269     default:
0270         return KCompactDisc::Error;
0271     }
0272 }
0273 
0274 void KPhononCompactDiscPrivate::tick(qint64 t)
0275 {
0276     unsigned track;
0277     Q_Q(KCompactDisc);
0278 
0279     track = m_producerWidget->m_mediaController->currentTitle();
0280     if(track != m_track) {
0281         m_track = track;
0282         m_discLength = trackLength(m_track);
0283         Q_EMIT q->playoutTrackChanged(m_track);
0284 
0285         /* phonon gives us Metadata only per Track */
0286         if(m_autoMetadata)
0287             queryMetadata();
0288     }
0289 
0290     m_trackPosition = MS2SEC(t);
0291     m_discPosition = m_trackPosition;
0292     // Update the current playing position.
0293     if(m_seek) {
0294         qDebug() << "seek: " << m_seek << " trackPosition " << m_trackPosition;
0295         if(abs((long)(m_trackExpectedPosition - m_trackPosition)) > m_seek)
0296             m_seek = 0;
0297         else
0298             m_seek = abs((long)(m_trackExpectedPosition - m_trackPosition));
0299     }
0300 
0301     if(!m_seek) {
0302         Q_EMIT q->playoutPositionChanged(m_trackPosition);
0303     }
0304 }
0305 
0306 void KPhononCompactDiscPrivate::stateChanged(Phonon::State newstate, Phonon::State)
0307 {
0308     qDebug() << "stateChanged with state " << newstate;
0309     KCompactDisc::DiscStatus status;
0310     Q_Q(KCompactDisc);
0311 
0312     status = discStatusTranslate(newstate);
0313 
0314     if(m_status != status) {
0315         if(skipStatusChange(status))
0316             return;
0317 
0318         m_status = status;
0319 
0320         switch(m_status) {
0321         case KCompactDisc::Ejected:
0322         case KCompactDisc::NoDisc:
0323             clearDiscInfo();
0324             break;
0325         default:
0326             if(m_tracks == 0) {
0327                 m_tracks = m_producerWidget->m_mediaController->availableTitles();
0328                 qDebug() << "Got " << m_tracks << " tracks from media controller";
0329                 if(m_tracks > 0) {
0330                     qDebug() << "New disc with " << m_tracks << " tracks";
0331 
0332                     make_playlist();
0333 
0334                     m_trackArtists.append(i18n("Unknown Artist"));
0335                     m_trackTitles.append(i18n("Unknown Title"));
0336                     for(unsigned i = 1; i <= m_tracks; ++i) {
0337                         m_trackArtists.append(i18n("Unknown Artist"));
0338                         m_trackTitles.append(ki18n("Track %1").subs(i, 2).toString());
0339                     }
0340 
0341                     Q_EMIT q->discChanged(m_tracks);
0342 
0343                     if(m_autoMetadata)
0344                         queryMetadata();
0345                 }
0346             }
0347 
0348             break;
0349         }
0350     }
0351 }