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

0001 /*
0002  *  KCompactDisc - A CD drive interface for the KDE Project.
0003  *
0004  *  Copyright (C) 2007 Alexander Kern <alex.kern@gmx.de>
0005  *
0006  *  This program is free software; you can redistribute it and/or modify
0007  *  it under the terms of the GNU General Public License as published by
0008  *  the Free Software Foundation; either version 2, or (at your option)
0009  *  any later version.
0010  *
0011  *  This program 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
0014  *  GNU General Public License for more details.
0015  *
0016  *  You should have received a copy of the GNU General Public License
0017  *  along with this program; if not, write to the Free Software
0018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "wmlib_interface.h"
0022 
0023 #include <QtGlobal>
0024 
0025 #include <KLocalizedString>
0026 
0027 extern "C"
0028 {
0029     // We don't have libWorkMan installed already, so get everything
0030     // from within our own directory
0031     #include "wmlib/include/wm_cdrom.h"
0032     #include "wmlib/include/wm_cdtext.h"
0033     #include "wmlib/include/wm_helpers.h"
0034 }
0035 
0036 #define TRACK_VALID(track) ((track) && (track <= m_tracks))
0037 
0038 KWMLibCompactDiscPrivate::KWMLibCompactDiscPrivate(KCompactDisc *p,
0039     const QString &dev, const QString &audioSystem, const QString &audioDevice) :
0040     KCompactDiscPrivate(p, dev),
0041     m_handle(nullptr),
0042     m_audioSystem(audioSystem),
0043     m_audioDevice(audioDevice)
0044 {
0045     m_interface = m_audioSystem;
0046 }
0047 
0048 KWMLibCompactDiscPrivate::~KWMLibCompactDiscPrivate()
0049 {
0050     if (m_handle) {
0051         wm_cd_destroy(m_handle);
0052     }
0053 }
0054 
0055 bool KWMLibCompactDiscPrivate::createInterface()
0056 {
0057     const QString devicePath = KCompactDisc::cdromDeviceUrl(m_deviceName).path();
0058 
0059     // Debug.
0060     if (qEnvironmentVariableIsSet("KCOMPACTDISC_WMLIB_DEBUG")) {
0061         wm_cd_set_verbosity(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS_ALL);
0062     }
0063 
0064     int status = wm_cd_init(
0065         devicePath.toLatin1().data(),
0066         m_audioSystem.toLatin1().data(),
0067         m_audioDevice.toLatin1().data(),
0068         nullptr,
0069         &m_handle);
0070 
0071     if(!WM_CDS_ERROR(status)) {
0072         m_deviceVendor = QLatin1String(wm_drive_vendor(m_handle));
0073         m_deviceModel = QLatin1String(wm_drive_model(m_handle));
0074         m_deviceRevision = QLatin1String(wm_drive_revision(m_handle));
0075 
0076         Q_Q(KCompactDisc);
0077         Q_EMIT q->discChanged(0);
0078 
0079         if (m_infoMode == KCompactDisc::Asynchronous) {
0080             timerExpired();
0081         } else {
0082             QTimer::singleShot(1000, this, SLOT(timerExpired()));
0083         }
0084 
0085         return true;
0086     }
0087     m_handle = nullptr;
0088     return false;
0089 }
0090 
0091 unsigned KWMLibCompactDiscPrivate::trackLength(unsigned track)
0092 {
0093     return (unsigned)wm_cd_gettracklen(m_handle, track);
0094 }
0095 
0096 bool KWMLibCompactDiscPrivate::isTrackAudio(unsigned track)
0097 {
0098     return !wm_cd_gettrackdata(m_handle, track);
0099 }
0100 
0101 void KWMLibCompactDiscPrivate::playTrackPosition(unsigned track, unsigned position)
0102 {
0103     unsigned firstTrack, lastTrack;
0104 
0105     firstTrack = TRACK_VALID(track) ? track : 1;
0106     lastTrack = firstTrack + 1;
0107     lastTrack = TRACK_VALID(lastTrack) ? lastTrack : WM_ENDTRACK;
0108 
0109     qDebug() << "play track " << firstTrack << " position "
0110                  << position;
0111 
0112     wm_cd_play(m_handle, firstTrack, position, lastTrack);
0113 }
0114 
0115 void KWMLibCompactDiscPrivate::pause()
0116 {
0117     wm_cd_pause(m_handle);
0118 }
0119 
0120 void KWMLibCompactDiscPrivate::stop()
0121 {
0122     wm_cd_stop(m_handle);
0123 }
0124 
0125 void KWMLibCompactDiscPrivate::eject()
0126 {
0127     wm_cd_eject(m_handle);
0128 }
0129 
0130 void KWMLibCompactDiscPrivate::closetray()
0131 {
0132     wm_cd_closetray(m_handle);
0133 }
0134 
0135 /* WM_VOLUME_MUTE ... WM_VOLUME_MAXIMAL */
0136 /* WM_BALANCE_ALL_LEFTS .WM_BALANCE_SYMMETRED. WM_BALANCE_ALL_RIGHTS */
0137 #define RANGE2PERCENT(x, min, max) (((x) - (min)) * 100)/ ((max) - (min))
0138 #define PERCENT2RANGE(x, min, max) ((((x) * ((max) - (min))) / 100 ) + (min))
0139 void KWMLibCompactDiscPrivate::setVolume(unsigned volume)
0140 {
0141     int vol, bal;
0142     vol = PERCENT2RANGE(volume, WM_VOLUME_MUTE, WM_VOLUME_MAXIMAL);
0143     bal = wm_cd_getbalance(m_handle);
0144     wm_cd_volume(m_handle, vol, bal);
0145 }
0146 
0147 void KWMLibCompactDiscPrivate::setBalance(unsigned balance)
0148 {
0149     int vol, bal;
0150     vol = wm_cd_getvolume(m_handle);
0151     bal = PERCENT2RANGE(balance, WM_BALANCE_ALL_LEFTS, WM_BALANCE_ALL_RIGHTS);
0152     wm_cd_volume(m_handle, vol, bal);
0153 }
0154 
0155 unsigned KWMLibCompactDiscPrivate::volume()
0156 {
0157     int vol = wm_cd_getvolume(m_handle);
0158     unsigned volume = RANGE2PERCENT(vol, WM_VOLUME_MUTE, WM_VOLUME_MAXIMAL);
0159     return volume;
0160 }
0161 
0162 unsigned KWMLibCompactDiscPrivate::balance()
0163 {
0164     int bal = wm_cd_getbalance(m_handle);
0165     unsigned balance = RANGE2PERCENT(bal, WM_BALANCE_ALL_LEFTS, WM_BALANCE_ALL_RIGHTS);
0166 
0167     return balance;
0168 }
0169 
0170 void KWMLibCompactDiscPrivate::queryMetadata()
0171 {
0172     cdtext();
0173     //cddb();
0174 }
0175 
0176 KCompactDisc::DiscStatus KWMLibCompactDiscPrivate::discStatusTranslate(int status)
0177 {
0178     switch (status) {
0179     case WM_CDM_TRACK_DONE:
0180     case WM_CDM_PLAYING:
0181     case WM_CDM_FORWARD:
0182         return KCompactDisc::Playing;
0183     case WM_CDM_PAUSED:
0184         return KCompactDisc::Paused;
0185     case WM_CDM_STOPPED:
0186         return KCompactDisc::Stopped;
0187     case WM_CDM_EJECTED:
0188         return KCompactDisc::Ejected;
0189     case WM_CDM_NO_DISC:
0190     case WM_CDM_UNKNOWN:
0191         return KCompactDisc::NoDisc;
0192     case WM_CDM_CDDAERROR:
0193     case WM_CDM_LOADING:
0194     case WM_CDM_BUFFERING:
0195         return KCompactDisc::NotReady;
0196     default:
0197         return KCompactDisc::Error;
0198     }
0199 }
0200 
0201 void KWMLibCompactDiscPrivate::timerExpired()
0202 {
0203     KCompactDisc::DiscStatus status;
0204     unsigned track, i;
0205     Q_Q(KCompactDisc);
0206 
0207     status = discStatusTranslate(wm_cd_status(m_handle));
0208 
0209     if(m_status != status) {
0210         if(skipStatusChange(status))
0211             goto timerExpiredExit;
0212 
0213         m_status = status;
0214 
0215         switch(m_status) {
0216         case KCompactDisc::Ejected:
0217         case KCompactDisc::NoDisc:
0218             clearDiscInfo();
0219             break;
0220         default:
0221             if(m_tracks == 0) {
0222                 m_tracks = wm_cd_getcountoftracks(m_handle);
0223                 if(m_tracks > 0) {
0224                     qDebug() << "New disc with " << m_tracks << " tracks";
0225                     m_discId = wm_cddb_discid(m_handle);
0226 
0227                     for(i = 1; i <= m_tracks; ++i) {
0228                         m_trackStartFrames.append(wm_cd_gettrackstart(m_handle, i));
0229                     }
0230                     m_trackStartFrames.append(wm_cd_gettrackstart(m_handle, i));
0231 
0232                     m_discLength = FRAMES2SEC(m_trackStartFrames[m_tracks] -
0233                         m_trackStartFrames[0]);
0234 
0235                     make_playlist();
0236 
0237                     m_trackArtists.append(i18n("Unknown Artist"));
0238                     m_trackTitles.append(i18n("Unknown Title"));
0239                     for(i = 1; i <= m_tracks; ++i) {
0240                         m_trackArtists.append(i18n("Unknown Artist"));
0241                         m_trackTitles.append(ki18n("Track %1").subs(i, 2).toString());
0242                     }
0243 
0244 qDebug() << "m_tracks " << m_tracks;
0245 qDebug() << "m_trackStartFrames " << m_trackStartFrames;
0246 qDebug() << "m_trackArtists " << m_trackArtists;
0247 qDebug() << "m_trackTitles " << m_trackTitles;
0248 
0249                     Q_EMIT q->discChanged(m_tracks);
0250 
0251                     if(m_autoMetadata)
0252                         queryMetadata();
0253                 }
0254             }
0255             break;
0256         }
0257     }
0258 
0259     switch(m_status) {
0260     case KCompactDisc::Playing:
0261         m_trackPosition = wm_get_cur_pos_rel(m_handle);
0262         m_discPosition = wm_get_cur_pos_abs(m_handle) - FRAMES2SEC(m_trackStartFrames[0]);
0263         // Update the current playing position.
0264         if(m_seek) {
0265             qDebug() << "seek: " << m_seek << " trackPosition " << m_trackPosition;
0266             if(abs((long)(m_trackExpectedPosition - m_trackPosition)) > m_seek)
0267                 m_seek = 0;
0268             else
0269                 m_seek = abs((long)(m_trackExpectedPosition - m_trackPosition));
0270         }
0271 
0272         if(!m_seek) {
0273             Q_EMIT q->playoutPositionChanged(m_trackPosition);
0274             //Q_EMIT q->playoutDiscPositionChanged(m_discPosition);
0275         }
0276 
0277         // Per-event processing.
0278         track = wm_cd_getcurtrack(m_handle);
0279 
0280         if(m_track != track) {
0281             m_track = track;
0282             Q_EMIT q->playoutTrackChanged(m_track);
0283         }
0284         break;
0285 
0286     case KCompactDisc::Stopped:
0287         m_seek = 0;
0288         m_track = 0;
0289         break;
0290 
0291     default:
0292         break;
0293     }
0294 
0295 timerExpiredExit:
0296     // Now that we have incurred any delays caused by the signals, we'll start the timer.
0297     QTimer::singleShot(1000, this, SLOT(timerExpired()));
0298 }
0299 
0300 void KWMLibCompactDiscPrivate::cdtext()
0301 {
0302     struct cdtext_info *info;
0303     unsigned i;
0304     Q_Q(KCompactDisc);
0305 
0306     info = wm_cd_get_cdtext(m_handle);
0307 
0308     if(!info || !info->valid || (unsigned)info->count_of_entries != (m_tracks + 1)) {
0309         qDebug() << "no or invalid CDTEXT";
0310         return;
0311     }
0312 
0313     m_trackArtists[0] = QLatin1String( reinterpret_cast<char*>(info->blocks[0]->performer[0]) );
0314     m_trackTitles[0] = QLatin1String( reinterpret_cast<char*>(info->blocks[0]->name[0]) );
0315 
0316     for(i = 1; i <= m_tracks; ++i) {
0317             m_trackArtists[i] = QLatin1String( reinterpret_cast<char*>(info->blocks[0]->performer[i]) );
0318             m_trackTitles[i] =QLatin1String( reinterpret_cast<char*>(info->blocks[0]->name[i]) );
0319     }
0320 
0321     qDebug() << "CDTEXT";
0322     qDebug() << "m_trackArtists " << m_trackArtists;
0323     qDebug() << "m_trackTitles " << m_trackTitles;
0324 
0325     Q_EMIT q->discInformation(KCompactDisc::Cdtext);
0326 }