diff --git a/src/kcompactdisc.cpp b/src/kcompactdisc.cpp index 2e297d1..2a4f549 100644 --- a/src/kcompactdisc.cpp +++ b/src/kcompactdisc.cpp @@ -1,558 +1,559 @@ /* * KCompactDisc - A CD drive interface for the KDE Project. * * Copyright (C) 2005 Shaheedur R. Haque * Copyright (C) 2007 Alexander Kern * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcompactdisc.h" #include "kcompactdisc_p.h" #include -#include +#include +#include #include #include #include #include #include static QMap cdromsNameToDeviceUrl; static QMap cdromsNameToUdi; static QString ___null = QString(); static void refreshListOfCdromDevices() { cdromsNameToDeviceUrl.clear(); cdromsNameToUdi.clear(); QString name, type; QUrl url; //get a list of all devices that are Cdrom foreach(const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::OpticalDrive)) { qDebug() << device.udi().toLatin1().constData(); const Solid::Block *b = device.as(); if(!b) { continue; } const Solid::OpticalDrive *o = device.as(); Solid::OpticalDrive::MediumTypes mediumType = o->supportedMedia(); url = QUrl::fromUserInput(QLatin1String( b->device().toLatin1() )); //TODO translate them ? if(mediumType < Solid::OpticalDrive::Cdrw) { type = QLatin1String( "CD-ROM" ); } else if(mediumType < Solid::OpticalDrive::Dvd) { type = QLatin1String( "CDRW" ); } else if(mediumType < Solid::OpticalDrive::Dvdr) { type = QLatin1String( "DVD-ROM" ); } else if(mediumType < Solid::OpticalDrive::Bd) { type = QLatin1String( "DVDRW" ); } else if(mediumType < Solid::OpticalDrive::HdDvd) { type = QLatin1String( "Blu-ray" ); } else { type = QLatin1String( "High Density DVD" ); } if(!device.vendor().isEmpty()) name = (QLatin1Char('[') + type + QLatin1String( " - " ) + device.vendor() + QLatin1String( " - " ) + device.product() + QLatin1Char( ']' )); else name = (QLatin1Char('[') + type + QLatin1String( " - unknown vendor - " ) + device.product() + QLatin1Char( ']' )); cdromsNameToDeviceUrl.insert(name, url); cdromsNameToUdi.insert(name, device.udi()); } #if 0 if(cdromsNameToDeviceUrl.empty()) { cdromsNameToDeviceUrl.insert(QString("Generic CDROM []"), QUrl::fromPath(wm_drive_default_device())); } #endif } static QMap &getListOfCdromDevicesNamesAndUrl() { if(cdromsNameToDeviceUrl.empty()) refreshListOfCdromDevices(); return cdromsNameToDeviceUrl; } static QMap &getListOfCdromDevicesNamesAndUdi() { if(cdromsNameToUdi.empty()) refreshListOfCdromDevices(); return cdromsNameToUdi; } QString KCompactDisc::urlToDevice(const QUrl &deviceUrl) { if(deviceUrl.scheme() == QLatin1String( "media" ) || deviceUrl.scheme() == QLatin1String( "system" )) { qDebug() << "Asking mediamanager for " << deviceUrl.fileName(); QDBusInterface mediamanager( QLatin1String( "org.kde.kded" ), QLatin1String( "/modules/mediamanager" ), QLatin1String( "org.kde.MediaManager" ) ); QDBusReply reply = mediamanager.call(QLatin1String( "properties" ), deviceUrl.fileName()); QStringList properties = reply; if(!reply.isValid() || properties.count() < 6) { qCritical() << "Invalid reply from mediamanager" << endl; return deviceUrl.path(); } else { qDebug() << "Reply from mediamanager " << properties[5]; return properties[5]; } } else if(deviceUrl.scheme() == QLatin1String( "file" )) { return deviceUrl.path(); } else { return QString(); } } const QStringList KCompactDisc::audioSystems() { QStringList list; list << QLatin1String( "phonon" ) #if defined(HAVE_ALSA) << QLatin1String( "alsa" ) #endif #if defined(sun) || defined(__sun__) << QLatin1String( "sun" ) #endif ; return list; } const QStringList KCompactDisc::cdromDeviceNames() { return getListOfCdromDevicesNamesAndUrl().keys(); } const QString KCompactDisc::defaultCdromDeviceName() { const QStringList names = getListOfCdromDevicesNamesAndUrl().keys(); if (!names.isEmpty()) return names[0]; else return QString(); } const QUrl KCompactDisc::defaultCdromDeviceUrl() { const QList urls = getListOfCdromDevicesNamesAndUrl().values(); if (!urls.isEmpty()) return urls[0]; else return QUrl(); } const QUrl KCompactDisc::cdromDeviceUrl(const QString &cdromDeviceName) { const QMap &nameUrls = getListOfCdromDevicesNamesAndUrl(); QUrl result = nameUrls.value(cdromDeviceName); if (!result.isValid()) { const QUrl passedUrl(cdromDeviceName); foreach(const QUrl &url, nameUrls) { if (url == passedUrl) { return passedUrl; } } result = KCompactDisc::defaultCdromDeviceUrl(); } return result; } const QString KCompactDisc::defaultCdromDeviceUdi() { const QStringList udis = getListOfCdromDevicesNamesAndUdi().values(); if (!udis.isEmpty()) return udis[0]; else return QString(); } const QString KCompactDisc::cdromDeviceUdi(const QString &cdromDeviceName) { return getListOfCdromDevicesNamesAndUdi().value(cdromDeviceName, KCompactDisc::defaultCdromDeviceUdi()); } KCompactDisc::KCompactDisc(InformationMode infoMode) : d_ptr(new KCompactDiscPrivate(this, KCompactDisc::defaultCdromDeviceName())) { Q_D(KCompactDisc); d->m_infoMode = infoMode; } KCompactDisc::~KCompactDisc() { stop(); delete d_ptr; } const QString &KCompactDisc::deviceVendor() { Q_D(KCompactDisc); return d->m_deviceVendor; } const QString &KCompactDisc::deviceModel() { Q_D(KCompactDisc); return d->m_deviceModel; } const QString &KCompactDisc::deviceRevision() { Q_D(KCompactDisc); return d->m_deviceRevision; } const QString &KCompactDisc::deviceName() { Q_D(KCompactDisc); return d->m_deviceName; } const QUrl KCompactDisc::deviceUrl() { Q_D(KCompactDisc); return KCompactDisc::cdromDeviceUrl(d->m_deviceName); } unsigned KCompactDisc::discId() { Q_D(KCompactDisc); return d->m_discId; } const QList &KCompactDisc::discSignature() { Q_D(KCompactDisc); return d->m_trackStartFrames; } const QString &KCompactDisc::discArtist() { Q_D(KCompactDisc); if (!d->m_tracks) return ___null; return d->m_trackArtists[0]; } const QString &KCompactDisc::discTitle() { Q_D(KCompactDisc); if (!d->m_tracks) return ___null; return d->m_trackTitles[0]; } unsigned KCompactDisc::discLength() { Q_D(KCompactDisc); if (!d->m_tracks) return 0; return d->m_discLength; } unsigned KCompactDisc::discPosition() { Q_D(KCompactDisc); return d->m_discPosition; } KCompactDisc::DiscStatus KCompactDisc::discStatus() { Q_D(KCompactDisc); return d->m_status; } QString KCompactDisc::discStatusString(KCompactDisc::DiscStatus status) { return KCompactDiscPrivate::discStatusI18n(status); } QString KCompactDisc::trackArtist() { Q_D(KCompactDisc); return trackArtist(d->m_track); } QString KCompactDisc::trackArtist(unsigned track) { Q_D(KCompactDisc); if (!track) return QString(); return d->m_trackArtists[track]; } QString KCompactDisc::trackTitle() { Q_D(KCompactDisc); return trackTitle(d->m_track); } QString KCompactDisc::trackTitle(unsigned track) { Q_D(KCompactDisc); if (!track) return QString(); return d->m_trackTitles[track]; } unsigned KCompactDisc::trackLength() { Q_D(KCompactDisc); return trackLength(d->m_track); } unsigned KCompactDisc::trackLength(unsigned track) { Q_D(KCompactDisc); if (!track) return 0; return d->trackLength(track); } unsigned KCompactDisc::track() { Q_D(KCompactDisc); return d->m_track; } unsigned KCompactDisc::trackPosition() { Q_D(KCompactDisc); return d->m_trackPosition; } unsigned KCompactDisc::tracks() { Q_D(KCompactDisc); return d->m_tracks; } bool KCompactDisc::isPlaying() { Q_D(KCompactDisc); return (d->m_status == KCompactDisc::Playing); } bool KCompactDisc::isPaused() { Q_D(KCompactDisc); return (d->m_status == KCompactDisc::Paused); } bool KCompactDisc::isNoDisc() { Q_D(KCompactDisc); return (d->m_status == KCompactDisc::NoDisc); } bool KCompactDisc::isAudio(unsigned track) { Q_D(KCompactDisc); if (!track) return 0; return d->isTrackAudio(track); } void KCompactDisc::playTrack(unsigned track) { Q_D(KCompactDisc); d->m_statusExpected = KCompactDisc::Playing; d->m_trackExpectedPosition = 0; d->m_seek = abs(int(d->m_trackExpectedPosition - trackPosition())); d->playTrackPosition(track, 0); } void KCompactDisc::playPosition(unsigned position) { Q_D(KCompactDisc); d->m_statusExpected = Playing; d->m_trackExpectedPosition = position; d->m_seek = abs(int(d->m_trackExpectedPosition - trackPosition())); d->playTrackPosition(d->m_track, position); } void KCompactDisc::play() { doCommand(KCompactDisc::Play); } void KCompactDisc::next() { doCommand(KCompactDisc::Next); } void KCompactDisc::prev() { doCommand(KCompactDisc::Prev); } void KCompactDisc::pause() { doCommand(KCompactDisc::Pause); } void KCompactDisc::stop() { doCommand(KCompactDisc::Stop); } void KCompactDisc::eject() { doCommand(KCompactDisc::Eject); } void KCompactDisc::loop() { doCommand(KCompactDisc::Loop); } void KCompactDisc::random() { doCommand(KCompactDisc::Random); } void KCompactDisc::doCommand(KCompactDisc::DiscCommand cmd) { Q_D(KCompactDisc); unsigned track; switch(cmd) { case Play: if(d->m_status == KCompactDisc::Playing) return; next(); break; case Next: track = d->getNextTrackInPlaylist(); if(track) playTrack(track); break; case Prev: track = d->getPrevTrackInPlaylist(); if(track) playTrack(track); break; case Pause: if(d->m_status == KCompactDisc::Paused) d->m_statusExpected = KCompactDisc::Playing; else d->m_statusExpected = KCompactDisc::Paused; d->pause(); break; case Stop: d->m_statusExpected = KCompactDisc::Stopped; d->stop(); break; case Eject: if(d->m_status != KCompactDisc::Ejected) { if(d->m_status != KCompactDisc::Stopped) { d->m_statusExpected = KCompactDisc::Ejected; d->stop(); } else { d->eject(); } } else { d->m_statusExpected = KCompactDisc::Stopped; d->closetray(); } break; case Loop: setLoopPlaylist(!d->m_loopPlaylist); break; case Random: setRandomPlaylist(!d->m_randomPlaylist); break; } } void KCompactDisc::metadataLookup() { Q_D(KCompactDisc); d->queryMetadata(); } void KCompactDisc::setRandomPlaylist(bool random) { Q_D(KCompactDisc); d->m_randomPlaylist = random; d->make_playlist(); emit randomPlaylistChanged(d->m_randomPlaylist); } void KCompactDisc::setLoopPlaylist(bool loop) { Q_D(KCompactDisc); d->m_loopPlaylist = loop; emit loopPlaylistChanged(d->m_loopPlaylist); } void KCompactDisc::setAutoMetadataLookup(bool autoMetadata) { Q_D(KCompactDisc); d->m_autoMetadata = autoMetadata; if(d->m_autoMetadata) metadataLookup(); } bool KCompactDisc::setDevice(const QString &deviceName, unsigned volume, bool digitalPlayback, const QString &audioSystem, const QString &audioDevice) { const QString as = digitalPlayback ? audioSystem : QLatin1String("cdin"); const QString ad = digitalPlayback ? audioDevice : QString(); qDebug() << "Device init: " << deviceName << ", " << as << ", " << ad; if(d_ptr->moveInterface(deviceName, as, ad)) { setVolume(volume); return 1; } else { // Severe (OS-level) error. return 0; } } void KCompactDisc::setVolume(unsigned volume) { Q_D(KCompactDisc); qDebug() << "change volume: " << volume; d->setVolume(volume); } void KCompactDisc::setBalance(unsigned balance) { Q_D(KCompactDisc); qDebug() << "change balance: " << balance; d->setBalance(balance); } #include "kcompactdisc.moc" diff --git a/src/kcompactdisc.h b/src/kcompactdisc.h index 6c15a87..eda54cd 100644 --- a/src/kcompactdisc.h +++ b/src/kcompactdisc.h @@ -1,536 +1,536 @@ /* * KCompactDisc - A CD drive interface for the KDE Project. * * Copyright (C) 2005 Shaheedur R. Haque * Copyright (C) 2007 Alexander Kern * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KCOMPACTDISC_H #define KCOMPACTDISC_H #include #include #include #include #include "kcompactdisc_export.h" class KCompactDiscPrivate; /** * KCompactDisc - A CD drive interface for the KDE Project. * * The disc interface is modelled by these slots: * * @see #playoutTrack(unsigned track): Play specified track. * @see #playoutPosition(unsigned position): seek to specified position. * @see #playNext(): Play next track in the playlist. * @see #playPrev(): Play previous track in the playlist. * @see #pauseResumePlayout(): Toggle between pause/resume. * @see #stopPlayout(): Stop playout: * @see #eject(): Stop playout and eject disc or Close * tray and try to read TOC from disc. * * The progress of playout is modelled by these signals: * * @see #playoutPositionChanged(unsigned position): A position in a track. * @see #playoutTrackChanged(unsigned track): A playout of this track is started. * * * The shape of playlist is controlled by these accessors. * * @see #setRandomPlaylist(bool): Shuffle the playlist. * @see #setLoopPlaylist(bool): Couple begin and end of playlist. * * * The disc lifecycle is modelled by these signals: * * @see #discChanged(...): A new disc was inserted. * @see #discStatusChanged(KCompactDisc::Playing): A disc started playout. * @see #discStatusChanged(KCompactDisc::Paused): A disc was paused. * @see #discStatusChanged(KCompactDisc::Stopped): The disc stopped. * @see #discStatusChanged(KCompactDisc::NoDisc): The disc is removed. No disc in tray or data disc. * @see #discStatusChanged(KCompactDisc::NotReady): The disc is present. But playout is not possible. * @see #discInformation(QStringList info): A content for disc information is arrived. * * * The volume control is modelled by these slots: * * @see #setVolume(unsigned): A new volume value. * @see #setBalance(unsigned): A new balance value. * * * And these signals: * * @see #volumeChanged(unsigned): A current volume value. * @see #balanceChanged(unsigned): A current balance value. * * * All times in this interface are in seconds. Valid track numbers are * positive numbers; zero is not a valid track number. */ class KCOMPACTDISC_EXPORT KCompactDisc : public QObject { Q_OBJECT /* Q_CLASSINFO("D-Bus Interface", "org.kde.KSCD") public Q_SLOTS: Q_SCRIPTABLE bool playing(); Q_SCRIPTABLE void play() { play(); } Q_SCRIPTABLE void stop() { stop(); } Q_SCRIPTABLE void previous() { prev(); } Q_SCRIPTABLE void next() { next(); } Q_SCRIPTABLE void jumpTo(int seconds) { jumpToTime(seconds); } Q_SCRIPTABLE void eject() { eject(); } Q_SCRIPTABLE void toggleLoop() { loop(); } Q_SCRIPTABLE void toggleShuffle() { random(); } Q_SCRIPTABLE void toggleTimeDisplay() { cycleplaytimemode(); } Q_SCRIPTABLE void cddbDialog() { CDDialogSelected(); } Q_SCRIPTABLE void optionDialog() { showConfig(); } Q_SCRIPTABLE void setTrack(int t) { trackSelected(t > 0 ? t - 1 : 0); } Q_SCRIPTABLE void volumeDown() { decVolume(); } Q_SCRIPTABLE void volumeUp() { incVolume(); } Q_SCRIPTABLE void setVolume(int v); Q_SCRIPTABLE void setDevice(const QString& dev); Q_SCRIPTABLE int getVolume() { return Prefs::volume(); } Q_SCRIPTABLE int currentTrack(); Q_SCRIPTABLE int currentTrackLength(); Q_SCRIPTABLE int currentPosition(); Q_SCRIPTABLE int getStatus(); Q_SCRIPTABLE QString currentTrackTitle(); Q_SCRIPTABLE QString currentAlbum(); Q_SCRIPTABLE QString currentArtist(); Q_SCRIPTABLE QStringList trackList(); */ public: enum InformationMode { Synchronous, // Return and emit signal when cdrom and cddb information arrives. - Asynchronous // Block until cdrom and cddb infromation has been obtained + Asynchronous // Block until cdrom and cddb information has been obtained }; enum DiscCommand { Play, Pause, Next, Prev, Stop, Eject, Loop, Random }; enum DiscStatus { Playing, Paused, Stopped, Ejected, NoDisc, NotReady, Error }; enum DiscInfo { Cdtext, Cddb, PhononMetadata }; - KCompactDisc(InformationMode = KCompactDisc::Synchronous); + explicit KCompactDisc(InformationMode = KCompactDisc::Synchronous); virtual ~KCompactDisc(); /** * @param device Name of CD device, e.g. /dev/cdrom. * @param digitalPlayback Select digital or analog playback. * @param audioSystem For digital playback, system to use, e.g. "phonon". * @param audioDevice For digital playback, device to use. * @return true if the device seemed usable. */ bool setDevice( const QString &device, unsigned volume = 50, bool digitalPlayback = true, const QString &audioSystem = QString(), const QString &audioDevice = QString()); /** * If the url is a media:/ or system:/ URL returns * the device it represents, otherwise returns device */ static QString urlToDevice(const QUrl& url); /** * All installed audio backends. */ static const QStringList audioSystems(); /** * All present CDROM devices. */ static const QStringList cdromDeviceNames(); /** * The default CDROM device for this system. */ static const QString defaultCdromDeviceName(); /** * The Url of default CDROM device for this system. */ static const QUrl defaultCdromDeviceUrl(); /** * The Url of named CDROM device for this system. */ static const QUrl cdromDeviceUrl(const QString &); /** * The Udi of default CDROM device for this system. */ static const QString defaultCdromDeviceUdi(); /** * The Udi of named CDROM device for this system. */ static const QString cdromDeviceUdi(const QString &); /** * SCSI parameter VENDOR of current CDROM device. * * @return Null string if no usable device set. */ const QString &deviceVendor(); /** * SCSI parameter MODEL of current CDROM device. * * @return Null string if no usable device set. */ const QString &deviceModel(); /** * SCSI parameter REVISION of current CDROM device. * * @return Null string if no usable device set. */ const QString &deviceRevision(); /** * Current CDROM device. * * @return Null string if no usable device set. */ const QString &deviceName(); /** * Current device as QUrl. */ const QUrl deviceUrl(); /** * Current disc, 0 if no disc or impossible to calculate id. */ unsigned discId(); /** - * CDDB signature of disc, empty if no disc or not possible to deliever. + * CDDB signature of disc, empty if no disc or not possible to deliver. */ const QList &discSignature(); /** * Artist for whole disc. * * @return Disc artist or null string. */ const QString &discArtist(); /** * Title of disc. * * @return Disc title or null string. */ const QString &discTitle(); /** * Known length of disc. * * @return Disc length in seconds. */ unsigned discLength(); /** * Current position on the disc. * * @return Position in seconds. */ unsigned discPosition(); /** * Current status. * * @return Current status. */ KCompactDisc::DiscStatus discStatus(); /** * Status as string. * * @return Status as QString. */ QString discStatusString(KCompactDisc::DiscStatus status); /** * Artist of current track. * * @return Track artist or null string. */ QString trackArtist(); /** * Artist of given track. * * @return Track artist or null string. */ QString trackArtist(unsigned track); /** * Title of current track. * * @return Track title or null string. */ QString trackTitle(); /** * Title of given track. * * @return Track title or null string. */ QString trackTitle(unsigned track); /** * Length of current track. * * @return Track length in seconds. */ unsigned trackLength(); /** * Length of given track. * * @param track Track number. * @return Track length in seconds. */ unsigned trackLength(unsigned track); /** * Current track. * * @return Track number. */ unsigned track(); /** * Current track position. * * @return Track position in seconds. */ unsigned trackPosition(); /** * Number of tracks. */ unsigned tracks(); /** * Is status playing. */ bool isPlaying(); /** * Is status pausing. */ bool isPaused(); /** * Is status no disc. */ bool isNoDisc(); /** * @return if the track is actually an audio track. */ bool isAudio(unsigned track); public Q_SLOTS: /** * Start playout of track. */ void playTrack(unsigned int track); /** * Start playout or seek to given position of track. */ void playPosition(unsigned int position); /* GUI bindings */ /** * Start playout. */ void play(); /** * Start playout of next track. */ void next(); /** * Start playout of previous track. */ void prev(); /** * Pause/resume playout. */ void pause(); /** * Stop playout. */ void stop(); /** * Open/close tray. */ void eject(); /** * Switch endless playout on/off. */ void loop(); /** * Switch random playout on/off. */ void random(); /** * Pipe GUI command. */ void doCommand(KCompactDisc::DiscCommand); void metadataLookup(); Q_SIGNALS: /** * A new position in a track. This signal is delivered at * approximately 1 second intervals while a track is playing. At first sight, * this might seem overzealous, but it is likely that any CD player UI will use * this to track the second-by-second position, so we may as well do it for * them. * * @param position Position within track in seconds. */ void playoutPositionChanged(unsigned int position); /** * A new track is started. * * @param track Track number. */ void playoutTrackChanged(unsigned int track); public Q_SLOTS: void setRandomPlaylist(bool); void setLoopPlaylist(bool); void setAutoMetadataLookup(bool); Q_SIGNALS: void randomPlaylistChanged(bool); void loopPlaylistChanged(bool); Q_SIGNALS: /** * A new Disc is inserted * */ void discChanged(unsigned int tracks); /** * A new Disc information is arrived * */ void discInformation(KCompactDisc::DiscInfo info); /** * A Disc status changed * */ void discStatusChanged(KCompactDisc::DiscStatus status); public Q_SLOTS: /** * Set volume */ void setVolume(unsigned int volume); /** * Set balance */ void setBalance(unsigned int balance); Q_SIGNALS: /** * New volume */ void volumeChanged(unsigned int volume); /** * New balance */ void balanceChanged(unsigned int balance); protected: KCompactDiscPrivate * d_ptr; KCompactDisc(KCompactDiscPrivate &dd, QObject *parent); private: Q_DECLARE_PRIVATE(KCompactDisc) #ifdef USE_WMLIB friend class KWMLibCompactDiscPrivate; #endif friend class KPhononCompactDiscPrivate; }; #endif diff --git a/src/kcompactdisc_p.cpp b/src/kcompactdisc_p.cpp index 4bf2af8..823702d 100644 --- a/src/kcompactdisc_p.cpp +++ b/src/kcompactdisc_p.cpp @@ -1,309 +1,309 @@ /* * KCompactDisc - A CD drive interface for the KDE Project. * * Copyright (C) 2007 Alexander Kern * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcompactdisc_p.h" #include "wmlib_interface.h" #include "phonon_interface.h" #include #include Q_LOGGING_CATEGORY(CD_PLAYLIST, "cd.playlist") KCompactDiscPrivate::KCompactDiscPrivate(KCompactDisc *p, const QString& dev) : m_infoMode(KCompactDisc::Synchronous), m_deviceName(dev), m_status(KCompactDisc::NoDisc), m_statusExpected(KCompactDisc::NoDisc), m_discId(0), m_discLength(0), m_track(0), m_tracks(0), m_trackPosition(0), m_discPosition(0), m_trackExpectedPosition(0), m_seek(0), m_randSequence(0), m_loopPlaylist(false), m_randomPlaylist(false), m_autoMetadata(true), m_deviceVendor(QString()), m_deviceModel(QString()), m_deviceRevision(QString()), q_ptr(p) { m_interface = QLatin1String("dummy"); m_trackStartFrames.clear(); m_trackArtists.clear(); m_trackTitles.clear(); m_playlist.clear(); } bool KCompactDiscPrivate::moveInterface(const QString &deviceName, const QString &audioSystem, const QString &audioDevice) { Q_Q(KCompactDisc); KCompactDiscPrivate *pOld, *pNew; qDebug() << "switch from " << q->d_ptr->m_interface << " on " << q->d_ptr->m_deviceName; qDebug() << " to " << audioSystem << " on " << deviceName; /* switch temporary to dummy implementation */ if(q->d_ptr != this) { pOld = q->d_ptr; q->d_ptr = this; delete pOld; } #ifdef USE_WMLIB if(audioSystem == QLatin1String("phonon")) #endif pNew = new KPhononCompactDiscPrivate(q, deviceName); #ifdef USE_WMLIB else pNew = new KWMLibCompactDiscPrivate(q, deviceName, audioSystem, audioDevice); #endif pNew->m_infoMode = m_infoMode; if(pNew->createInterface()) { q->d_ptr = pNew; return true; } else { delete pNew; return false; } } bool KCompactDiscPrivate::createInterface() { return true; } void KCompactDiscPrivate::make_playlist() { /* koz: 15/01/00. I want a random list that does not repeat tracks. Ie, */ /* a list is created in which each track is listed only once. The tracks */ /* are picked off one by one until the end of the list */ unsigned selected = 0, size = m_tracks; bool rejected = false; qCDebug(CD_PLAYLIST) << "Playlist has " << size << " entries\n"; m_playlist.clear(); - for(unsigned i = 0; i < size; i++) { + for(unsigned i = 0; i < size; ++i) { if(m_randomPlaylist) { do { selected = 1 + m_randSequence.getLong(size); rejected = (m_playlist.indexOf(selected) != -1); } while(rejected == true); } else { selected = 1 + i; } m_playlist.append(selected); } qCDebug(CD_PLAYLIST) << "dump playlist"; QList::const_iterator it; - for(it = m_playlist.constBegin(); it != m_playlist.constEnd(); it++) { + for(it = m_playlist.constBegin(); it != m_playlist.constEnd(); ++it) { qCDebug(CD_PLAYLIST) << " " << *it; } qCDebug(CD_PLAYLIST) << "dump playlist end"; } unsigned KCompactDiscPrivate::getNextTrackInPlaylist() { int current_index, min_index, max_index; if(m_playlist.empty()) return 0; min_index = 0; max_index = m_playlist.size() - 1; current_index = m_playlist.indexOf(m_track); if(current_index < 0) current_index = min_index; else if(current_index >= max_index) { if(m_loopPlaylist) { //wrap around if(m_randomPlaylist) make_playlist(); current_index = min_index; } else { return 0; } } else { ++current_index; } return m_playlist[current_index]; } unsigned KCompactDiscPrivate::getPrevTrackInPlaylist() { int current_index, min_index, max_index; if(m_playlist.empty()) return 0; min_index = 0; max_index = m_playlist.size() - 1; current_index = m_playlist.indexOf(m_track); if(current_index < 0) current_index = min_index; else if(current_index <= min_index) { if(m_loopPlaylist) { //wrap around if(m_randomPlaylist) make_playlist(); current_index = max_index; } else { return 0; } } else { --current_index; } return m_playlist[current_index]; } bool KCompactDiscPrivate::skipStatusChange(KCompactDisc::DiscStatus status) { Q_Q(KCompactDisc); if(m_status != status) { if(status == KCompactDisc::Stopped) { if(m_statusExpected == KCompactDisc::Ejected) { eject(); } else if(m_statusExpected != KCompactDisc::Stopped) { unsigned track = getNextTrackInPlaylist(); if(track) { playTrackPosition(track, 0); return true; } } } emit q->discStatusChanged(status); } return false; } const QString KCompactDiscPrivate::discStatusI18n(KCompactDisc::DiscStatus status) { switch (status) { case KCompactDisc::Playing: return i18n("Playing"); case KCompactDisc::Paused: return i18n("Paused"); case KCompactDisc::Stopped: return i18n("Stopped"); case KCompactDisc::Ejected: return i18n("Ejected"); case KCompactDisc::NoDisc: return i18n("No Disc"); case KCompactDisc::NotReady: return i18n("Not Ready"); case KCompactDisc::Error: default: return i18n("Error"); } } void KCompactDiscPrivate::clearDiscInfo() { Q_Q(KCompactDisc); m_discId = 0; m_discLength = 0; m_seek = 0; m_track = 0; m_tracks = 0; m_trackArtists.clear(); m_trackTitles.clear(); m_trackStartFrames.clear(); emit q->discChanged(m_tracks); } unsigned KCompactDiscPrivate::trackLength(unsigned) { return 0; } bool KCompactDiscPrivate::isTrackAudio(unsigned) { return false; } void KCompactDiscPrivate::playTrackPosition(unsigned, unsigned) { } void KCompactDiscPrivate::pause() { } void KCompactDiscPrivate::stop() { } void KCompactDiscPrivate::eject() { } void KCompactDiscPrivate::closetray() { } void KCompactDiscPrivate::setVolume(unsigned) { } void KCompactDiscPrivate::setBalance(unsigned) { } unsigned KCompactDiscPrivate::volume() { return 0; } unsigned KCompactDiscPrivate::balance() { return 50; } void KCompactDiscPrivate::queryMetadata() { } #include "kcompactdisc_p.moc" diff --git a/src/phonon_interface.cpp b/src/phonon_interface.cpp index 5fe9526..e3b44e9 100644 --- a/src/phonon_interface.cpp +++ b/src/phonon_interface.cpp @@ -1,354 +1,354 @@ /* * * Copyright (C) 2004-2007 Matthias Kretz * Copyright (C) by Alexander Kern * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * CDDA version taken from guitest in phonon test directory */ #include "phonon_interface.h" #include #include #include #include #include #include #include #include #include #include #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM using namespace Phonon; class ProducerWidget : public QObject { public: ProducerWidget(KPhononCompactDiscPrivate *, const QString &); ~ProducerWidget(); public: MediaObject *m_media; AudioOutput *m_output; MediaController *m_mediaController; }; ProducerWidget::ProducerWidget(KPhononCompactDiscPrivate *p, const QString &Udi) : m_media(0), m_output(0), m_mediaController(0) { m_media = new MediaObject(this); connect(m_media, SIGNAL(metaDataChanged()), SLOT(updateMetaData())); m_media->setTickInterval(1000); m_output = new AudioOutput(Phonon::MusicCategory, this); Phonon::createPath(m_media, m_output); connect(m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), p, SLOT(stateChanged(Phonon::State,Phonon::State))); connect(m_media, SIGNAL(tick(qint64)), p, SLOT(tick(qint64))); MediaSource *m_mediaSource = new MediaSource(Phonon::Cd, Udi); m_media->setCurrentSource(*m_mediaSource); m_mediaController = new MediaController(m_media); } ProducerWidget::~ProducerWidget() { delete(m_mediaController); delete(m_output); delete(m_media); } KPhononCompactDiscPrivate::KPhononCompactDiscPrivate(KCompactDisc *p, const QString &dev) : KCompactDiscPrivate(p, dev), m_producerWidget(NULL), m_udi(KCompactDisc::cdromDeviceUdi(dev)) { m_interface = QLatin1String("phonon"); } KPhononCompactDiscPrivate::~KPhononCompactDiscPrivate() { delete m_producerWidget; m_producerWidget = NULL; } bool KPhononCompactDiscPrivate::createInterface() { qDebug() << "createInterface called"; Solid::Device opticalDevice(m_udi); Solid::OpticalDrive *opticalDrive = opticalDevice.as(); if(opticalDrive) { Q_Q(KCompactDisc); m_deviceVendor = opticalDevice.vendor(); m_deviceModel = opticalDevice.product(); emit q->discChanged(0); producer(); return true; } return false; } ProducerWidget *KPhononCompactDiscPrivate::producer() { //try to create if(!m_producerWidget) { Solid::Device opticalDevice(m_udi); Solid::OpticalDrive *opticalDrive = opticalDevice.as(); qDebug() << "producer called, opticalDrive is " << opticalDrive; if(opticalDrive) { Solid::OpticalDisc *opticalDisc = opticalDevice.as(); qDebug() << "opticalDisc " << opticalDisc; //if(opticalDisc && (opticalDisc->availableContent() == Solid::OpticalDisc::Audio)) { m_producerWidget = new ProducerWidget(this, m_udi); stateChanged(m_producerWidget->m_media->state(), Phonon::StoppedState); //} } } return m_producerWidget; } unsigned KPhononCompactDiscPrivate::trackLength(unsigned track) { if(!producer() || m_producerWidget->m_mediaController->currentTitle() != track) return 0; return MS2SEC(m_producerWidget->m_media->totalTime()); } bool KPhononCompactDiscPrivate::isTrackAudio(unsigned) { return true; } void KPhononCompactDiscPrivate::playTrackPosition(unsigned track, unsigned position) { if(!producer()) return; qDebug() << "play track " << track << " position " << position; m_producerWidget->m_mediaController->setCurrentTitle(track); m_producerWidget->m_media->seek(SEC2MS(position)); emit m_producerWidget->m_media->play(); } void KPhononCompactDiscPrivate::pause() { if(!producer()) return; emit m_producerWidget->m_media->pause(); } void KPhononCompactDiscPrivate::stop() { if(!producer()) return; emit m_producerWidget->m_media->stop(); } void KPhononCompactDiscPrivate::eject() { Solid::Device opticalDevice(m_udi); Solid::OpticalDrive *opticalDrive = opticalDevice.as(); Solid::OpticalDisc *opticalDisc = opticalDevice.as(); if(!opticalDrive || !opticalDisc) return; opticalDrive->eject(); } void KPhononCompactDiscPrivate::closetray() { Solid::Device opticalDevice(m_udi); Solid::OpticalDrive *opticalDrive = opticalDevice.as(); Solid::OpticalDisc *opticalDisc = opticalDevice.as(); if(!opticalDrive || opticalDisc) return; opticalDrive->eject(); } void KPhononCompactDiscPrivate::setVolume(unsigned volume) { if(!producer()) return; /* 1.0 = 100% */ m_producerWidget->m_output->setVolume(volume * 0.01); } void KPhononCompactDiscPrivate::setBalance(unsigned) { } unsigned KPhononCompactDiscPrivate::volume() { if(!producer()) return 0; return (unsigned)(m_producerWidget->m_output->volume() * 100.0); } unsigned KPhononCompactDiscPrivate::balance() { return 50; } void KPhononCompactDiscPrivate::queryMetadata() { Q_Q(KCompactDisc); if(!producer()) return; QMultiMap data = m_producerWidget->m_media->metaData(); qDebug() << "METADATA"; //qDebug() << data; m_trackArtists[0] = data.take(QLatin1String( "ARTIST" )); m_trackTitles[0] = data.take(QLatin1String( "ALBUM" )); m_trackArtists[m_track] = data.take(QLatin1String( "ARTIST" )); m_trackTitles[m_track] = data.take(QLatin1String( "TITLE" )); emit q->discInformation(KCompactDisc::PhononMetadata); } KCompactDisc::DiscStatus KPhononCompactDiscPrivate::discStatusTranslate(Phonon::State state) { switch (state) { case Phonon::PlayingState: return KCompactDisc::Playing; case Phonon::PausedState: return KCompactDisc::Paused; case Phonon::StoppedState: return KCompactDisc::Stopped; case Phonon::ErrorState: return KCompactDisc::NoDisc; case Phonon::LoadingState: case Phonon::BufferingState: return KCompactDisc::NotReady; default: return KCompactDisc::Error; } } void KPhononCompactDiscPrivate::tick(qint64 t) { unsigned track; Q_Q(KCompactDisc); track = m_producerWidget->m_mediaController->currentTitle(); if(track != m_track) { m_track = track; m_discLength = trackLength(m_track); emit q->playoutTrackChanged(m_track); /* phonon gives us Metadata only per Track */ if(m_autoMetadata) queryMetadata(); } m_trackPosition = MS2SEC(t); m_discPosition = m_trackPosition; // Update the current playing position. if(m_seek) { qDebug() << "seek: " << m_seek << " trackPosition " << m_trackPosition; if(abs((long)(m_trackExpectedPosition - m_trackPosition)) > m_seek) m_seek = 0; else m_seek = abs((long)(m_trackExpectedPosition - m_trackPosition)); } if(!m_seek) { emit q->playoutPositionChanged(m_trackPosition); } } void KPhononCompactDiscPrivate::stateChanged(Phonon::State newstate, Phonon::State) { qDebug() << "stateChanged with state " << newstate; KCompactDisc::DiscStatus status; Q_Q(KCompactDisc); status = discStatusTranslate(newstate); if(m_status != status) { if(skipStatusChange(status)) return; m_status = status; switch(m_status) { case KCompactDisc::Ejected: case KCompactDisc::NoDisc: clearDiscInfo(); break; default: if(m_tracks == 0) { m_tracks = m_producerWidget->m_mediaController->availableTitles(); qDebug() << "Got " << m_tracks << " tracks from media controller"; if(m_tracks > 0) { qDebug() << "New disc with " << m_tracks << " tracks"; make_playlist(); m_trackArtists.append(i18n("Unknown Artist")); m_trackTitles.append(i18n("Unknown Title")); - for(unsigned i = 1; i <= m_tracks; i++) { + for(unsigned i = 1; i <= m_tracks; ++i) { m_trackArtists.append(i18n("Unknown Artist")); m_trackTitles.append(ki18n("Track %1").subs(i, 2).toString()); } emit q->discChanged(m_tracks); if(m_autoMetadata) queryMetadata(); } } break; } } } #include "phonon_interface.moc" diff --git a/src/wmlib/include/wm_cdtext.h b/src/wmlib/include/wm_cdtext.h index bf97caa..013370e 100644 --- a/src/wmlib/include/wm_cdtext.h +++ b/src/wmlib/include/wm_cdtext.h @@ -1,106 +1,106 @@ #ifndef WM_CDTEXT_H #define WM_CDTEXT_H /* * This file is part of WorkMan, the civilized CD player library * Copyright (C) Alexander Kern * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * cdtext base structure and defines */ #define MAX_LENGHT_OF_CDTEXT_STRING 162 /* max 160 bytes + 2 * 0x00 by UNICODES */ #define DATAFIELD_LENGHT_IN_PACK 12 #define MAX_LANGUAGE_BLOCKS 8 struct cdtext_pack_data_header { unsigned char header_field_id1_typ_of_pack; unsigned char header_field_id2_tracknumber; unsigned char header_field_id3_sequence; unsigned char header_field_id4_block_no; unsigned char text_data_field[DATAFIELD_LENGHT_IN_PACK]; unsigned char crc_byte1; unsigned char crc_byte2; }; typedef unsigned char cdtext_string[MAX_LENGHT_OF_CDTEXT_STRING]; /* meke it more generic it can be up to 8 blocks with different encoding */ struct cdtext_info_block { /* management */ unsigned char block_code; unsigned char block_unicode; /* 0 - single chars, 1 - doublebytes */ unsigned char block_encoding; /* orange book -? */ cdtext_string* block_encoding_text; /* variable part of cdtext */ cdtext_string* name; cdtext_string* performer; cdtext_string* songwriter; cdtext_string* composer; cdtext_string* arranger; cdtext_string* message; cdtext_string* UPC_EAN_ISRC_code; /* fix part of cdtext */ unsigned char binary_disc_identification_info[DATAFIELD_LENGHT_IN_PACK]; unsigned char binary_genreidentification_info[DATAFIELD_LENGHT_IN_PACK]; unsigned char binary_size_information[DATAFIELD_LENGHT_IN_PACK]; }; struct cdtext_info { - /* somethimes i get hunderts of bytes, without anyone valid pack + /* sometimes i get hundreds of bytes, without anyone valid pack my CDU-561 for example */ int count_of_entries; /* one more because album need one too */ int count_of_valid_packs; int count_of_invalid_packs; int valid; struct cdtext_info_block *blocks[MAX_LANGUAGE_BLOCKS]; }; #ifndef IGNORE_FEATURE_LIST struct feature_list_header { unsigned char lenght_msb; unsigned char lenght_1sb; unsigned char lenght_2sb; unsigned char lenght_lsb; unsigned char reserved1; unsigned char reserved2; unsigned char profile_msb; unsigned char profile_lsb; }; struct feature_descriptor_cdread { unsigned char feature_code_msb; unsigned char feature_code_lsb; unsigned char settings; unsigned char add_lenght; unsigned char add_settings; unsigned char reserved1; unsigned char reserved2; unsigned char reserved3; }; #endif /* IGNORE_FEATURE_LIST */ struct cdtext_info* wm_cd_get_cdtext(void *p); #endif /* WM_CDTEXT_H */ diff --git a/src/wmlib/include/wm_platform.h b/src/wmlib/include/wm_platform.h index d8ca5e1..e5288ce 100644 --- a/src/wmlib/include/wm_platform.h +++ b/src/wmlib/include/wm_platform.h @@ -1,62 +1,62 @@ #ifndef WM_PLATFORM_H #define WM_PLATFORM_H /* * This file is part of WorkMan, the civilized CD player library * Copyright (C) 1991-1997 by Steven Grimm * Copyright (C) by Dirk Försterling * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * The platform interface * * This is just one more step to a more modular and understandable code. */ #define WM_CDS_ERROR(status) ((status) < 0 ||\ (status) == WM_CDM_UNKNOWN) #define WM_CDS_NO_DISC(status) ((status) < 0 ||\ (status) == WM_CDM_UNKNOWN ||\ (status) == WM_CDM_EJECTED ||\ (status) == WM_CDM_NO_DISC) #define WM_CDS_DISC_READY(status) ((status) == WM_CDM_TRACK_DONE ||\ (status) == WM_CDM_PLAYING ||\ (status) == WM_CDM_FORWARD ||\ (status) == WM_CDM_PAUSED ||\ (status) == WM_CDM_STOPPED ||\ (status) == WM_CDM_LOADING ||\ (status) == WM_CDM_BUFFERING) #define WM_CDS_DISC_PLAYING(status) ((status) == WM_CDM_TRACK_DONE ||\ (status) == WM_CDM_PLAYING ||\ (status) == WM_CDM_FORWARD ||\ (status) == WM_CDM_PAUSED) #define WM_CDM_BACK 1 #define WM_CDM_TRACK_DONE 1 #define WM_CDM_PLAYING 2 #define WM_CDM_FORWARD 3 #define WM_CDM_PAUSED 4 #define WM_CDM_STOPPED 5 #define WM_CDM_EJECTED 6 #define WM_CDM_DEVICECHANGED 9 /* deprecated */ #define WM_CDM_NO_DISC 10 #define WM_CDM_UNKNOWN 11 #define WM_CDM_CDDAERROR 12 -#define WM_CDM_LOADING 13 /* tribute to phonon state mashine */ -#define WM_CDM_BUFFERING 14 /* tribute to phonon state mashine */ +#define WM_CDM_LOADING 13 /* tribute to phonon state machine */ +#define WM_CDM_BUFFERING 14 /* tribute to phonon state machine */ #define WM_CDM_CDDAACK 0xF0 #endif /* WM_PLATFORM_H */ diff --git a/src/wmlib/include/wm_struct.h b/src/wmlib/include/wm_struct.h index 2f94755..acae14d 100644 --- a/src/wmlib/include/wm_struct.h +++ b/src/wmlib/include/wm_struct.h @@ -1,187 +1,187 @@ #ifndef WM_STRUCT_H #define WM_STRUCT_H /* * This file is part of WorkMan, the civilized CD player library * Copyright (C) 1991-1997 by Steven Grimm * Copyright (C) by Dirk Försterling * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "wm_platform.h" #define WM_STR_GENVENDOR "Generic" #define WM_STR_GENMODEL "drive" #define WM_STR_GENREV "type" struct wm_drive; /* * Structure for a single track. This is pretty much self-explanatory -- * one of these exists for each track on the current CD. */ struct wm_trackinfo { int length; /* Length of track in seconds or Kbytes */ int start; /* Starting position (f+s*75+m*60*75) */ int track; /* Physical track number */ int data; /* Flag: data track */ }; struct wm_cdinfo { int ntracks; /* Number of tracks on the disc */ int curtrack; int curtracklen; int cur_cdmode; int cur_index; /* Current index mark */ int cur_pos_rel; /* Current track-relative position in seconds */ int cur_pos_abs; /* Current absolute position in seconds */ int cur_frame; /* Current frame number */ int length; /* Total running time in seconds */ int cd_cur_balance; struct wm_trackinfo *trk; /* struct wm_trackinfo[ntracks] */ }; /* * Each platform has to define generic functions, so may as well declare * them all here to save space. * These functions should never be seen outside libworkman. So I don't care * about the wm_ naming convention here. */ struct wm_drive_proto { int (*open)(struct wm_drive *d); int (*close)(struct wm_drive *d); int (*get_trackcount)(struct wm_drive *d, int *tracks); int (*get_cdlen)(struct wm_drive *d, int *frames); int (*get_trackinfo)(struct wm_drive *d, int track, int *data, int *startframe); int (*get_drive_status)(struct wm_drive *d, int oldmode, int *mode, int *pos, int *track, int *ind); int (*pause)(struct wm_drive *d); int (*resume)(struct wm_drive *d); int (*stop)(struct wm_drive *d); int (*play)(struct wm_drive *d, int start, int end); int (*eject)(struct wm_drive *d); int (*closetray)(struct wm_drive *d); int (*scsi)(struct wm_drive *d, unsigned char *cdb, int cdb_len, void *ret_buf, int ret_buflen, int get_reply); int (*set_volume)(struct wm_drive *d, int left, int right); int (*get_volume)(struct wm_drive *d, int *left, int *right); int (*scale_volume)(int *left, int *right); int (*unscale_volume)(int *left, int *right); }; /* forward declaration */ int gen_init(struct wm_drive *d); int gen_open(struct wm_drive *d); int gen_close(struct wm_drive *d); int gen_get_trackcount(struct wm_drive *d, int *tracks); int gen_get_cdlen(struct wm_drive *d, int *frames); int gen_get_trackinfo(struct wm_drive *d, int track, int *data, int *startframe); int gen_get_drive_status(struct wm_drive *d, int oldmode, int *mode, int *pos, int *track, int *ind); int gen_pause(struct wm_drive *d); int gen_resume(struct wm_drive *d); int gen_stop(struct wm_drive *d); int gen_play(struct wm_drive *d, int start, int end); int gen_eject(struct wm_drive *d); int gen_closetray(struct wm_drive *d); int gen_scsi(struct wm_drive *d, unsigned char *cdb, int cdb_len, void *ret_buf, int ret_buflen, int get_reply); int gen_set_volume(struct wm_drive *d, int left, int right); int gen_get_volume(struct wm_drive *d, int *left, int *right); int gen_scale_volume(int *left, int *right); int gen_unscale_volume(int *left, int *right); /* * Information about a particular block of CDDA data. */ struct wm_cdda_block { unsigned char status; unsigned char track; unsigned char index; unsigned char reserved; int frame; char *buf; long buflen; }; #ifdef WMLIB_CDDA_BUILD int gen_cdda_init(struct wm_drive *d); int gen_cdda_open(struct wm_drive* d); int gen_cdda_read(struct wm_drive* d, struct wm_cdda_block *block); int gen_cdda_close(struct wm_drive* d); #else #define gen_cdda_init(x) (-1) #define gen_cdda_open(x) (-1) #define gen_cdda_read(x, y) (-1) #define gen_cdda_close(x) (-1) #endif /* * Drive descriptor structure. Used for access to low-level routines. */ struct wm_drive { int cdda; /* cdda 1, cdin 0 */ - /* commpn section */ + /* common section */ char *cd_device; char *soundsystem; char *sounddevice; char *ctldevice; char vendor[9]; /* Vendor name */ char model[17]; /* Drive model */ char revision[5]; /* Revision of the drive */ void *aux; /* Pointer to optional platform-specific info */ struct wm_cdinfo thiscd; int cur_cdmode; /* cdin section */ int fd; /* file descriptor */ void *daux; /* Pointer to optional drive-specific info etc. */ struct wm_drive_proto proto; /* cdda section */ unsigned char status; unsigned char track; unsigned char index; unsigned char command; int current_position; int ending_position; int frame; int frames_at_once; struct wm_cdda_block *blocks; int numblocks; void *cddax; /* Pointer to optional drive-specific info etc. */ int oldmode; }; int toshiba_fixup(struct wm_drive *d); int sony_fixup(struct wm_drive *d); struct cdtext_info* get_glob_cdtext(struct wm_drive*, int); void free_cdtext(void); int wm_cdda_init(struct wm_drive *d); int wm_cdda_destroy(struct wm_drive *d); #endif /* WM_STRUCT_H */ diff --git a/src/wmlib/plat_linux.c b/src/wmlib/plat_linux.c index 2a7a178..2b68960 100644 --- a/src/wmlib/plat_linux.c +++ b/src/wmlib/plat_linux.c @@ -1,756 +1,755 @@ /* * This file is part of WorkMan, the civilized CD player library * Copyright (C) 1991-1997 by Steven Grimm * Copyright (C) by Dirk Försterling * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Linux-specific drive control routines. Very similar to the Sun module. */ #if defined(__linux__) #include "include/wm_config.h" #include "include/wm_struct.h" #include "include/wm_cdtext.h" #include "include/wm_cdda.h" -#include "include/wm_struct.h" #include "include/wm_platform.h" #include "include/wm_cdrom.h" #include "include/wm_scsi.h" #include "include/wm_helpers.h" #include #include #include #include #include #include #include #include #include #include #include /* Try to get around bug #29274 */ #include #if 0 /* this breaks the build on ia64 and s390 for example. sys/types.h is already included and should provide __u64. please tell where we really need this and let's try to find a working #if case for everyone ... adrian@suse.de */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,50)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) #undef __GNUC__ typedef unsigned long long __u64; #endif #endif #if defined(BSD_MOUNTTEST) #include #else /* * this is for glibc 2.x which defines ust structure in * ustat.h not stat.h */ #ifdef __GLIBC__ #include #endif #endif #include #include #ifndef __GNUC__ #define __GNUC__ 1 #endif /* needed for vanilla kernel headers, which do provide __u64 only for ansi */ #undef __STRICT_ANSI__ /* needed for non-ansi kernel headers */ #define asm __asm__ #define inline __inline__ #include #include #undef asm #undef inline #ifdef OSS_SUPPORT #include #define CD_CHANNEL SOUND_MIXER_CD #endif #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM #ifdef LINUX_SCSI_PASSTHROUGH /* this is from */ # define SCSI_IOCTL_SEND_COMMAND 1 #endif /*-------------------------------------------------------* * * * CD-ROM drive functions. * * *-------------------------------------------------------*/ int gen_init(struct wm_drive *d) { return 0; } int gen_open(struct wm_drive *d) { if(d->fd > -1) { wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "plat_open(): [device is open (fd=%d)]\n", d->fd); return 0; } d->fd = open(d->cd_device, O_RDONLY | O_NONBLOCK); wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "plat_open(): device=%s fd=%d\n", d->cd_device, d->fd); if(d->fd < 0) return -errno; return 0; } int gen_close(struct wm_drive *d) { wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "linux_close(): closing the device\n"); close(d->fd); d->fd = -1; return 0; } /*--------------------------------------------------------------------------* * Get the current status of the drive: the current play mode, the absolute * position from start of disc (in frames), and the current track and index * numbers if the CD is playing or paused. *--------------------------------------------------------------------------*/ int gen_get_drive_status(struct wm_drive *d, int oldmode, int *mode, int *pos, int *track, int *ind) { struct cdrom_subchnl sc; int ret; #ifdef SBPCD_HACK static int prevpos = 0; #endif /* Is the device open? */ if (d->fd > -1) { ret = d->proto.open(d); if(ret < 0) /* error */ return ret; if(ret == 1) { /* retry */ *mode = WM_CDM_UNKNOWN; return 0; } } /* Try to get rid of the door locking */ /* Don't care about return value. If it */ /* works - fine. If not - ... */ ioctl(d->fd, CDROM_LOCKDOOR, 0); *mode = WM_CDM_UNKNOWN; sc.cdsc_format = CDROM_MSF; if(!ioctl(d->fd, CDROMSUBCHNL, &sc)) { switch (sc.cdsc_audiostatus) { case CDROM_AUDIO_PLAY: *mode = WM_CDM_PLAYING; *track = sc.cdsc_trk; *ind = sc.cdsc_ind; *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 + sc.cdsc_absaddr.msf.second * 75 + sc.cdsc_absaddr.msf.frame; #ifdef SBPCD_HACK if( *pos < prevpos ) { if( (prevpos - *pos) < 75 ) { *mode = WM_CDM_TRACK_DONE; } } prevpos = *pos; #endif break; case CDROM_AUDIO_PAUSED: if (oldmode == WM_CDM_PLAYING || oldmode == WM_CDM_PAUSED) { *mode = WM_CDM_PAUSED; *track = sc.cdsc_trk; *ind = sc.cdsc_ind; *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 + sc.cdsc_absaddr.msf.second * 75 + sc.cdsc_absaddr.msf.frame; } else *mode = WM_CDM_STOPPED; break; case CDROM_AUDIO_NO_STATUS: *mode = WM_CDM_STOPPED; break; case CDROM_AUDIO_COMPLETED: *mode = WM_CDM_TRACK_DONE; /* waiting for next track. */ break; case CDROM_AUDIO_INVALID: /**/ default: *mode = WM_CDM_UNKNOWN; break; } } if(WM_CDS_NO_DISC(*mode)) { /* verify status of drive */ ret = ioctl(d->fd, CDROM_DRIVE_STATUS, 0/* slot */); if(ret == CDS_DISC_OK) ret = ioctl(d->fd, CDROM_DISC_STATUS, 0); switch(ret) { case CDS_NO_DISC: *mode = WM_CDM_NO_DISC; break; case CDS_TRAY_OPEN: *mode = WM_CDM_EJECTED; break; case CDS_AUDIO: case CDS_MIXED: *mode = WM_CDM_STOPPED; break; case CDS_DRIVE_NOT_READY: case CDS_NO_INFO: case CDS_DATA_1: case CDS_DATA_2: case CDS_XA_2_1: case CDS_XA_2_2: default: *mode = WM_CDM_UNKNOWN; } } return 0; } /*-------------------------------------* * Get the number of tracks on the CD. *-------------------------------------*/ int gen_get_trackcount(struct wm_drive *d, int *tracks) { struct cdrom_tochdr hdr; if(ioctl(d->fd, CDROMREADTOCHDR, &hdr)) return -1; *tracks = hdr.cdth_trk1; return 0; } /*---------------------------------------------------------* * Get the start time and mode (data or audio) of a track. *---------------------------------------------------------*/ int gen_get_trackinfo(struct wm_drive *d, int track, int *data, int *startframe) { struct cdrom_tocentry entry; entry.cdte_track = track; entry.cdte_format = CDROM_MSF; if(ioctl(d->fd, CDROMREADTOCENTRY, &entry)) return -1; *startframe = entry.cdte_addr.msf.minute * 60 * 75 + entry.cdte_addr.msf.second * 75 + entry.cdte_addr.msf.frame; *data = entry.cdte_ctrl & CDROM_DATA_TRACK ? 1 : 0; return 0; } /*-------------------------------------* * Get the number of frames on the CD. *-------------------------------------*/ int gen_get_cdlen(struct wm_drive *d, int *frames) { int tmp; return d->proto.get_trackinfo(d, CDROM_LEADOUT, &tmp, frames); } /*------------------------------------------------------------* * Play the CD from one position to another (both in frames.) *------------------------------------------------------------*/ int gen_play(struct wm_drive *d, int start, int end) { struct cdrom_msf msf; msf.cdmsf_min0 = start / (60*75); msf.cdmsf_sec0 = (start % (60*75)) / 75; msf.cdmsf_frame0 = start % 75; msf.cdmsf_min1 = end / (60*75); msf.cdmsf_sec1 = (end % (60*75)) / 75; msf.cdmsf_frame1 = end % 75; if(ioctl(d->fd, CDROMPLAYMSF, &msf)) { if(ioctl(d->fd, CDROMSTART)) return -1; if(ioctl(d->fd, CDROMPLAYMSF, &msf)) return -2; } return 0; } /*---------------* * Pause the CD. *---------------*/ int gen_pause(struct wm_drive *d) { return ioctl(d->fd, CDROMPAUSE); } /*-------------------------------------------------* * Resume playing the CD (assuming it was paused.) *-------------------------------------------------*/ int gen_resume(struct wm_drive *d) { return ioctl(d->fd, CDROMRESUME); } /*--------------* * Stop the CD. *--------------*/ int gen_stop(struct wm_drive *d) { return ioctl(d->fd, CDROMSTOP); } /*----------------------------------------* * Eject the current CD, if there is one. *----------------------------------------*/ int gen_eject(struct wm_drive *d) { struct stat stbuf; #if !defined(BSD_MOUNTTEST) struct ustat ust; #else struct mntent *mnt; FILE *fp; #endif wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "ejecting?\n"); if(fstat(d->fd, &stbuf) != 0) { wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "that weird fstat() thingy\n"); return -2; } /* Is this a mounted filesystem? */ #if !defined(BSD_MOUNTTEST) if (ustat(stbuf.st_rdev, &ust) == 0) return -3; #else /* * This is the same test as in the WorkBone interface. * I should eliminate it there, because there is no need * for it in the UI */ /* check if drive is mounted (from Mark Buckaway's cdplayer code) */ /* Changed it again (look at XPLAYCD from ???? */ /* It's better to check the device name rather than one device is */ /* mounted as iso9660. That prevents "no playing" if you have more*/ /* than one CD-ROM, and one of them is mounted, but it's not the */ /* audio CD -dirk */ if((fp = setmntent (MOUNTED, "r")) == NULL) { wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "Could not open %s: %s\n", MOUNTED, strerror (errno)); return -3; } while((mnt = getmntent (fp)) != NULL) { if(strcmp (mnt->mnt_fsname, d->cd_device) == 0) { wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "CDROM already mounted (according to mtab). Operation aborted.\n"); endmntent (fp); return -3; } } endmntent (fp); #endif /* BSD_MOUNTTEST */ ioctl(d->fd, CDROM_LOCKDOOR, 0); if(ioctl(d->fd, CDROMEJECT)) { wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "eject failed (%s).\n", strerror(errno)); return -1; } /*------------------ * Things in "foobar_one" are left over from 1.4b3 * I put them here for further observation. In 1.4b3, however, * that workaround didn't help at least for /dev/sbpcd * (The tray closed just after ejecting because re-opening the * device causes the tray to close) *------------------*/ #ifdef foobar_one extern int intermittent_dev /* * Some drives (drivers?) won't recognize a new CD if we leave the * device open. */ if(intermittent_dev) d->proto.close(d); #endif return 0; } int gen_closetray(struct wm_drive *d) { #ifdef CDROMCLOSETRAY wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "CDROMCLOSETRAY closing tray...\n"); return ioctl(d->fd, CDROMCLOSETRAY); #else return -1; #endif /* CDROMCLOSETRAY */ } static int min_volume = 0, max_volume = 255; /*------------------------------------------------------------------------* * scale_volume(vol, max) * * Return a volume value suitable for passing to the CD-ROM drive. "vol" * is a volume slider setting; "max" is the slider's maximum value. * This is not used if sound card support is enabled. * *------------------------------------------------------------------------*/ static int scale_volume(int vol, int max) { #ifdef CURVED_VOLUME return ((max * max - (max - vol) * (max - vol)) * track_info_status(max_volume - min_volume) / (max * max) + min_volume); #else return ((vol * (max_volume - min_volume)) / max + min_volume); #endif } static int unscale_volume(int vol, int max) { #ifdef CURVED_VOLUME /* FIXME do it simpler */ int tmp = (((max_volume - min_volume - vol) * max * max) - (vol + min_volume)); return max - sqrt((tmp/(max_volume - min_volume))); #else return (((vol - min_volume) * max) / (max_volume - min_volume)); #endif } /*---------------------------------------------------------------------* * Set the volume level for the left and right channels. Their values * range from 0 to 100. *---------------------------------------------------------------------*/ int gen_set_volume(struct wm_drive *d, int left, int right) { struct cdrom_volctrl v; v.channel0 = v.channel2 = left < 0 ? 0 : left > 255 ? 255 : left; v.channel1 = v.channel3 = right < 0 ? 0 : right > 255 ? 255 : right; return (ioctl(d->fd, CDROMVOLCTRL, &v)); } /*---------------------------------------------------------------------* * Read the volume from the drive, if available. Each channel * ranges from 0 to 100, with -1 indicating data not available. *---------------------------------------------------------------------*/ int gen_get_volume(struct wm_drive *d, int *left, int *right) { struct cdrom_volctrl v; #if defined(CDROMVOLREAD) if(!ioctl(d->fd, CDROMVOLREAD, &v)) { *left = (v.channel0 + v.channel2)/2; *right = (v.channel1 + v.channel3)/2; } else #endif /* Suns, HPs, Linux, NEWS can't read the volume; oh well */ *left = *right = -1; return 0; } int gen_scale_volume(int *left, int *right) { /* Adjust the volume to make up for the CD-ROM drive's weirdness. */ *left = scale_volume(*left, 100); *right = scale_volume(*right, 100); return 0; } int gen_unscale_volume(int *left, int *right) { *left = unscale_volume(*left, 100); *right = unscale_volume(*right, 100); return 0; } /*---------------------------------------------* * Send an arbitrary SCSI command to a device. *---------------------------------------------*/ int gen_scsi(struct wm_drive *d, unsigned char *cdb, int cdblen, void *retbuf, int retbuflen, int getreply) { int ret; #ifdef LINUX_SCSI_PASSTHROUGH char *cmd; int cmdsize; cmdsize = 2 * sizeof(int); if(retbuf) { if (getreply) cmdsize += max(cdblen, retbuflen); else cmdsize += (cdblen + retbuflen); } else { cmdsize += cdblen; } cmd = malloc(cmdsize); if(cmd == NULL) { return -ENOMEM; } ((int*)cmd)[0] = cdblen + ((retbuf && !getreply) ? retbuflen : 0); ((int*)cmd)[1] = ((retbuf && getreply) ? retbuflen : 0); memcpy(cmd + 2*sizeof(int), cdb, cdblen); if(retbuf && !getreply) memcpy(cmd + 2*sizeof(int) + cdblen, retbuf, retbuflen); if(ioctl(d->fd, SCSI_IOCTL_SEND_COMMAND, cmd)) { wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "%s: ioctl(SCSI_IOCTL_SEND_COMMAND) failure\n", __FILE__); wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "command buffer is:\n"); wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "%02x %02x %02x %02x %02x %02x\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]); free(cmd); return -1; } if(retbuf && getreply) memcpy(retbuf, cmd + 2*sizeof(int), retbuflen); free(cmd); return 0; #else /* Linux SCSI passthrough*/ /*----------------------------------------* * send packet over cdrom interface * kernel >= 2.2.16 *----------------------------------------*/ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,15)) struct cdrom_generic_command cdc; struct request_sense sense; int capability; wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "wm_scsi over CDROM_SEND_PACKET entered\n"); capability = ioctl(d->fd, CDROM_GET_CAPABILITY); if(!(capability & CDC_GENERIC_PACKET)) { wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "your CDROM or/and kernel does not support CDC_GENERIC_PACKET ...\n"); return -1; } memset(&cdc, 0, sizeof(struct cdrom_generic_command)); memset(&sense, 0, sizeof(struct request_sense)); memcpy(cdc.cmd, cdb, cdblen); cdc.buffer = retbuf; cdc.buflen = retbuflen; cdc.stat = 0; cdc.sense = &sense; cdc.data_direction = getreply?CGC_DATA_READ:CGC_DATA_WRITE; /* sendpacket_over_cdrom_interface() */ if((ret = ioctl(d->fd, CDROM_SEND_PACKET, &cdc))) wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "ERROR: CDROM_SEND_PACKET %s\n", strerror(errno)); return ret; #endif /* CDROM_SEND_PACKET */ wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "ERROR: this binary was compiled without CDROM GENERIC PACKET SUPPORT. kernel version < 2.2.16?\n"); wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, "ERROR: if you have a SCSI CDROM, rebuild it with a #define LINUX_SCSI_PASSTHROUGH\n"); return -1; #endif } #if 0 #define CDROM_LBA 0x01 /* "logical block": first frame is #0 */ #define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ #define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ /* This struct is used by the CDROMREADAUDIO ioctl */ struct cdrom_read_audio { union { struct { unsigned char minute; unsigned char second; unsigned char frame; } msf; signed int lba; } addr; /* frame address */ unsigned char addr_format; /* CDROM_LBA or CDROM_MSF */ signed int nframes; /* number of 2352-byte-frames to read at once */ unsigned char *buf; /* frame buffer (size: nframes*2352 bytes) */ }; #define CDDABLKSIZE 2352 #endif int gen_cdda_init(struct wm_drive *d) { return 0; } /* * Initialize the CDDA data buffer and open the appropriate device. * */ int gen_cdda_open(struct wm_drive *d) { int i; struct cdrom_read_audio cdda; if (d->fd > -1) return -1; for (i = 0; i < d->numblocks; i++) { d->blocks[i].buflen = d->frames_at_once * CD_FRAMESIZE_RAW; d->blocks[i].buf = malloc(d->blocks[i].buflen); if (!d->blocks[i].buf) { ERRORLOG("plat_cdda_open: ENOMEM\n"); return -ENOMEM; } } cdda.addr_format = CDROM_LBA; cdda.addr.lba = 200; cdda.nframes = 1; cdda.buf = (unsigned char *)d->blocks[0].buf; d->status = WM_CDM_STOPPED; if((ioctl(d->fd, CDROMREADAUDIO, &cdda) < 0)) { if (errno == ENXIO) { /* CD ejected! */ d->status = WM_CDM_EJECTED; } else { /* Sometimes it fails once, dunno why */ d->status = WM_CDM_CDDAERROR; } } else { d->status = WM_CDM_UNKNOWN; } return 0; } /* * Read some blocks from the CD. Stop if we hit the end of the current region. * * Returns number of bytes read, -1 on error, 0 if stopped for a benign reason. */ int gen_cdda_read(struct wm_drive *d, struct wm_cdda_block *block) { struct cdrom_read_audio cdda; if (d->fd < 0) return -1; /* Hit the end of the CD, probably. */ if (d->current_position >= d->ending_position) { block->status = WM_CDM_TRACK_DONE; return 0; } cdda.addr_format = CDROM_LBA; cdda.addr.lba = d->current_position - CD_MSF_OFFSET; if (d->ending_position && d->current_position + d->frames_at_once > d->ending_position) cdda.nframes = d->ending_position - d->current_position; else cdda.nframes = d->frames_at_once; cdda.buf = (unsigned char*)block->buf; if (ioctl(d->fd, CDROMREADAUDIO, &cdda) < 0) { if (errno == ENXIO) { /* CD ejected! */ block->status = WM_CDM_EJECTED; return 0; } else { /* Sometimes it fails once, dunno why */ block->status = WM_CDM_CDDAERROR; return 0; } } block->track = -1; block->index = 0; block->frame = d->current_position; block->status = WM_CDM_PLAYING; block->buflen = cdda.nframes * CD_FRAMESIZE_RAW; d->current_position = d->current_position + cdda.nframes; return block->buflen; } /* * Close the CD-ROM device in preparation for exiting. */ int gen_cdda_close(struct wm_drive *d) { int i; if (d->fd < 0) return -1; for (i = 0; i < d->numblocks; i++) { free(d->blocks[i].buf); d->blocks[i].buf = 0; d->blocks[i].buflen = 0; } return 0; } #endif /* __linux__ */ diff --git a/src/wmlib/plat_openbsd.c b/src/wmlib/plat_openbsd.c index f6c4caf..93e8f92 100644 --- a/src/wmlib/plat_openbsd.c +++ b/src/wmlib/plat_openbsd.c @@ -1,480 +1,479 @@ /* * This file is part of WorkMan, the civilized CD player library * Copyright (C) 1991-1997 by Steven Grimm * Copyright (C) by Dirk Försterling * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * OpenBSD-specific drive control routines. (Based on plat_freebsd.c) * * Michael Shalayeff, 7/24/96 * Todd Pfaff, 3/20/94 * */ #if defined(__OpenBSD__) || defined(__OpenBSD) #include #include #include #include #include #include -#include #include #include "include/wm_config.h" #include "include/wm_cdrom.h" #include "include/wm_helpers.h" /* this is for glibc 2.x which defines the ust structure in ustat.h not stat.h */ #ifdef __GLIBC__ #include #endif #include #include #include #include #include #include #include #include #include "include/wm_struct.h" #include "include/wm_cdtext.h" #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM void *malloc(); int min_volume = 10; int max_volume = 255; const char* find_cdrom() { if (access("/dev/rcd0c", F_OK) == 0) { return "/dev/rcd0c"; } else if (access("/dev/rcd1c", F_OK) == 0) { return "/dev/rcd1c"; } else if (access("/dev/acd0c", F_OK) == 0) { return "/dev/acd0c"; } else { fprintf(stderr, "Could not find a CD device!\n"); return NULL; } } /* find_cdrom() */ /* * Initialize the drive. A no-op for the generic driver. */ int gen_init(struct wm_drive *d) { return (0); } /* gen_init() */ /* * Open the CD device and figure out what kind of drive is attached. */ int gen_open(struct wm_drive *d) { if (d->fd >= 0) { /* Device already open? */ wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "gen_open(): [device is open (fd=%d)]\n", d->fd); return 0; } d->fd = open(d->cd_device, O_RDONLY); if (d->fd < 0) { if (errno == EIO) /* No CD in drive. */ return 1; else return -errno; } return 0; } /* gen_open() */ /* * Send an arbitrary SCSI command to a device. * */ int gen_scsi(struct wm_drive *d, unsigned char *cdb, int cdblen, void *retbuf, int retbuflen, int getreply) { return -1; } /* gen_scsi() */ int gen_close( struct wm_drive *d ) { if(d->fd > -1) { wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "closing the device\n"); close(d->fd); } d->fd = -1; return 0; } /* * Get the current status of the drive: the current play mode, the absolute * position from start of disc (in frames), and the current track and index * numbers if the CD is playing or paused. */ int gen_get_drive_status(struct wm_drive *d, int oldmode, int *mode, int *pos, int *track, int *index) { struct ioc_read_subchannel sc; struct cd_sub_channel_info scd; /* If we can't get status, the CD is ejected, so default to that. */ *mode = WM_CDM_EJECTED; sc.address_format = CD_MSF_FORMAT; sc.data_format = CD_CURRENT_POSITION; sc.track = 0; sc.data_len = sizeof(scd); sc.data = (struct cd_sub_channel_info *)&scd; /* Is the device open? */ if (d->fd < 0) { switch (d->proto.open(d)) { case -1: /* error */ return -1; case 1: /* retry */ return 0; } } if (ioctl(d->fd, CDIOCREADSUBCHANNEL, &sc)) { /* we need to release the device so the kernel will notice reloaded media */ d->proto.close(d); return 0; /* ejected */ } switch (scd.header.audio_status) { case CD_AS_PLAY_IN_PROGRESS: *mode = WM_CDM_PLAYING; break; case CD_AS_PLAY_PAUSED: if (oldmode == WM_CDM_PLAYING || oldmode == WM_CDM_PAUSED) *mode = WM_CDM_PAUSED; else *mode = WM_CDM_STOPPED; break; case CD_AS_PLAY_COMPLETED: *mode = WM_CDM_TRACK_DONE; /* waiting for next track. */ break; case CD_AS_NO_STATUS: case 0: *mode = WM_CDM_STOPPED; break; } switch(*mode) { case WM_CDM_PLAYING: case WM_CDM_PAUSED: *pos = scd.what.position.absaddr.msf.minute * 60 * 75 + scd.what.position.absaddr.msf.second * 75 + scd.what.position.absaddr.msf.frame; *track = scd.what.position.track_number; *index = scd.what.position.index_number; break; } return 0; } /* gen_get_drive_status() */ /* * Get the number of tracks on the CD. */ int gen_get_trackcount(struct wm_drive *d, int *tracks) { struct ioc_toc_header hdr; if (ioctl(d->fd, CDIOREADTOCHEADER, &hdr) == -1) return (-1); *tracks = hdr.ending_track - hdr.starting_track + 1; return (0); } /* gen_get_trackcount() */ /* * Get the start time and mode (data or audio) of a track. * * XXX - this should get cached, but that means keeping track of ejects. */ int gen_get_trackinfo(struct wm_drive *d, int track, int *data, int *startframe) { struct ioc_read_toc_entry toc; struct cd_toc_entry toc_buffer; bzero((char *)&toc_buffer, sizeof(toc_buffer)); toc.address_format = CD_MSF_FORMAT; toc.starting_track = track; toc.data_len = sizeof(toc_buffer); toc.data = &toc_buffer; if (ioctl(d->fd, CDIOREADTOCENTRYS, &toc)) return (-1); *data = ((toc_buffer.control & 0x4) != 0); *startframe = toc_buffer.addr.msf.minute*60*75 + toc_buffer.addr.msf.second * 75 + toc_buffer.addr.msf.frame; return (0); } /* gen_get_trackinfo() */ /* * Get the number of frames on the CD. */ int gen_get_cdlen(struct wm_drive *d, int *frames) { int tmp; struct ioc_toc_header hdr; int status; #define LEADOUT 0xaa /* see scsi.c. what a hack! */ return gen_get_trackinfo(d, LEADOUT, &tmp, frames); } /* gen_get_cdlen() */ /* * Play the CD from one position to another (both in frames.) */ int gen_play(struct wm_drive *d, int start, int end) { struct ioc_play_msf msf; msf.start_m = start / (60*75); msf.start_s = (start % (60*75)) / 75; msf.start_f = start % 75; msf.end_m = end / (60*75); msf.end_s = (end % (60*75)) / 75; msf.end_f = end % 75; if (ioctl(d->fd, CDIOCSTART)) return (-1); if (ioctl(d->fd, CDIOCPLAYMSF, &msf)) return (-2); return (0); } /* gen_play() */ /* * Pause the CD. */ int gen_pause(struct wm_drive *d) { return (ioctl(d->fd, CDIOCPAUSE)); } /* gen_pause() */ /* * Resume playing the CD (assuming it was paused.) */ int gen_resume(struct wm_drive *d) { return (ioctl(d->fd, CDIOCRESUME)); } /* gen_resume() */ /* * Stop the CD. */ int gen_stop(struct wm_drive *d) { return (ioctl(d->fd, CDIOCSTOP)); } /* gen_stop() */ /* * Eject the current CD, if there is one. */ int gen_eject(struct wm_drive *d) { /* On some systems, we can check to see if the CD is mounted. */ struct stat stbuf; struct statfs buf; int rval; if (fstat(d->fd, &stbuf) != 0) return (-2); /* Is this a mounted filesystem? */ if (fstatfs(stbuf.st_rdev, &buf) == 0) return (-3); rval = ioctl(d->fd, CDIOCALLOW); if (rval == 0) rval = ioctl(d->fd, CDIOCEJECT); if (rval == 0) rval = ioctl(d->fd, CDIOCPREVENT); if (rval == 0) rval = close(d->fd); if (rval == 0) d->fd = -1; return rval; } /* gen_eject() */ /*----------------------------------------* * Close the CD tray * * Please edit and send changes to * milliByte@DeathsDoor.com *----------------------------------------*/ int gen_closetray(struct wm_drive *d) { return -1; } /* gen_closetray() */ /* * scale_volume(vol, max) * * Return a volume value suitable for passing to the CD-ROM drive. "vol" * is a volume slider setting; "max" is the slider's maximum value. * * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack * increases much faster toward the top end of the volume scale than it * does at the bottom. To make up for this, we make the volume scale look * sort of logarithmic (actually an upside-down inverse square curve) so * that the volume value passed to the drive changes less and less as you * approach the maximum slider setting. The actual formula looks like * * (max^2 - (max - vol)^2) * (max_volume - min_volume) * v = --------------------------------------------------- + min_volume * max^2 * * If your system's volume settings aren't broken in this way, something * like the following should work: * * return ((vol * (max_volume - min_volume)) / max + min_volume); */ static int scale_volume(int vol, int max) { return ((vol * (max_volume - min_volume)) / max + min_volume); } /* scale_volume() */ /* * unscale_volume(cd_vol, max) * * Given a value between min_volume and max_volume, return the volume slider * value needed to achieve that value. * * Rather than perform floating-point calculations to reverse the above * formula, we simply do a binary search of scale_volume()'s return values. */ static int unscale_volume(int cd_vol, int max) { int vol = 0, top = max, bot = 0, scaled; while (bot <= top) { vol = (top + bot) / 2; scaled = scale_volume(vol, max); if (cd_vol == scaled) break; if (cd_vol < scaled) top = vol - 1; else bot = vol + 1; } if (vol < 0) vol = 0; else if (vol > max) vol = max; return (vol); } /* unscale_volume() */ /* * Set the volume level for the left and right channels. Their values * range from 0 to 100. */ int gen_set_volume(struct wm_drive *d, int left, int right) { struct ioc_vol vol; if (left < 0) /* don't laugh, I saw this happen once! */ left = 0; if (right < 0) right = 0; left = scale_volume(left, 100); right = scale_volume(right, 100); bzero((char *)&vol, sizeof(vol)); vol.vol[LEFT_PORT] = left; vol.vol[RIGHT_PORT] = right; if (ioctl(d->fd, CDIOCSETVOL, &vol)) return (-1); return (0); } /* gen_set_volume() */ /* * Read the initial volume from the drive, if available. Each channel * ranges from 0 to 100, with -1 indicating data not available. */ int gen_get_volume(struct wm_drive *d, int *left, int *right) { struct ioc_vol vol; if (d->fd >= 0) { bzero((char *)&vol, sizeof(vol)); if (ioctl(d->fd, CDIOCGETVOL, &vol)) *left = *right = -1; else { *left = unscale_volume(vol.vol[LEFT_PORT], 100); *right = unscale_volume(vol.vol[RIGHT_PORT], 100); } } else *left = *right = -1; return (0); } /* gen_get_volume() */ #endif diff --git a/src/wmlib/plat_sun_cdda.c b/src/wmlib/plat_sun_cdda.c index 4f34d6a..8349d88 100644 --- a/src/wmlib/plat_sun_cdda.c +++ b/src/wmlib/plat_sun_cdda.c @@ -1,375 +1,374 @@ /* * This file is part of WorkMan, the civilized CD player library * Copyright (C) 1991-1997 by Steven Grimm * Copyright (C) by Dirk Försterling * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Sun (really Solaris) CDDA functions. */ #include "include/wm_cdda.h" #if defined(sun) || defined(__sun__) && defined(SYSV) #include "include/wm_struct.h" -#include "include/wm_cdda.h" /* types.h and cdio.h are included by wm_cdda.h */ #include #include #include #include #include #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM #define CDDABLKSIZE 2368 #define SAMPLES_PER_BLK 588 /* Address of next block to read. */ int current_position = 0; /* Address of first and last blocks to read. */ int starting_position = 0; int ending_position = 0; /* Playback direction. */ int direction = 1; /* Number of blocks to read at once; initialize to the maximum. */ /* (was 30. Set to 15 for INTeL. Maybe config option? */ int numblocks = 15; /* * This is the fastest way to convert from BCD to 8-bit. */ unsigned char unbcd[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,0,0,0,0,0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0,0,0,0,0,0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0,0,0,0,0,0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0,0,0,0,0,0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0,0,0,0,0,0, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0,0,0,0,0,0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,0,0,0,0,0, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0,0,0,0,0,0, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0,0,0,0,0,0, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static long wmcdda_normalize(struct cdda_block *block); /* * Initialize the CDDA data buffer and open the appropriate device. * * NOTE: We allocate twice as much space as we need to actually read a block; * this lets us do audio manipulations without bothering to malloc a second * buffer. * * Also, test to see if we can actually *do* CDDA on this drive; if not, we * need to exit right away so the UI doesn't show the user any CDDA controls. */ int wmcdda_init(struct cdda_device* pdev, struct cdda_block *block) { struct cdrom_cdda cdda; int i; if (pdev->fd > -1) return -1; for (i = 0; i < pdev->numblocks; i++) { /* in Linux const */ pdev->blocks[i].buflen = pdev->frames_at_once * CDDABLKSIZE; pdev->blocks[i].buf = malloc(pdev->blocks[i].buflen); if (!pdev->blocks[i].buf) return -ENOMEM; } pdev->fd = open(pdev->devname, 0); if (pdev->fd == -1) pdev->fd = open("/dev/rdsk/c0t6d0s2", 0); if (pdev->fd > -1) { cdda.cdda_addr = 200; cdda.cdda_length = 1; cdda.cdda_data = pdev->blocks[0].buf; cdda.cdda_subcode = CDROM_DA_SUBQ; if (ioctl(pdev->fd, CDROMCDDA, &cdda) < 0) { block->status = WM_CDM_STOPPED; return -1; } else { block->status = WM_CDM_STOPPED; return 0; } } else { block->status = WM_CDM_EJECTED; return -1; } } /* * Close the CD-ROM device in preparation for exiting. */ int wmcdda_close(struct cdda_device* pdev) { int i; if(-1 == pdev->fd) return -1; close(pdev->fd); pdev->fd = -1; for (i = 0; i < pdev->numblocks; i++) { free(pdev->blocks[i].buf); pdev->blocks[i].buf = 0; pdev->blocks[i].buflen = 0; } return 0; } /* * Set up for playing the CD. Actually this doesn't play a thing, just sets a * couple variables so we'll know what to do when we're called. */ int wmcdda_setup(int start, int end) { current_position = start - 150; ending_position = end - 150; /* * Special case: don't start at the "end" of a track if we're * playing backwards! */ if (direction == -1) current_position = ending_position - numblocks; return 0; } /* * Read some blocks from the CD. Stop if we hit the end of the current region. * * Returns number of bytes read, -1 on error, 0 if stopped for a benign reason. */ long wmcdda_read(struct cdda_device* pdev, struct cdda_block *block) { struct cdrom_cdda cdda; int blk; unsigned char *q; extern int speed; unsigned char* rawbuf = block->buf; if(pdev->fd < 0 && (wmcdda_init(pdev, block) < 0)) { return -1; } /* * Hit the end of the CD, probably. */ if ((direction > 0 && current_position >= ending_position) || (direction < 0 && current_position < starting_position)) { block->status = WM_CDM_TRACK_DONE; return (0); } cdda.cdda_addr = current_position; if (ending_position && current_position + pdev->frames_at_once > ending_position) cdda.cdda_length = ending_position - current_position; else cdda.cdda_length = pdev->frames_at_once; cdda.cdda_data = (unsigned char*)block->buf; cdda.cdda_subcode = CDROM_DA_SUBQ; if (ioctl(pdev->fd, CDROMCDDA, &cdda) < 0) { if (errno == ENXIO) /* CD ejected! */ { block->status = WM_CDM_EJECTED; return (-1); } /* Sometimes it fails once, dunno why */ if (ioctl(pdev->fd, CDROMCDDA, &cdda) < 0) { if (ioctl(pdev->fd, CDROMCDDA, &cdda) < 0) { if (ioctl(pdev->fd, CDROMCDDA, &cdda) < 0) { perror("CDROMCDDA"); block->status = WM_CDM_CDDAERROR; return (-1); } } } } if (speed > 148) { /* * We want speed=148 to advance by cdda_length, but * speed=256 to advance cdda_length * 4. */ current_position = current_position + (cdda.cdda_length * direction * (speed - 112)) / 36; } else current_position = current_position + cdda.cdda_length * direction; for (blk = 0; blk < numblocks; blk++) { /* * New valid Q-subchannel information? Update the block * status. */ q = &rawbuf[blk * CDDABLKSIZE + SAMPLES_PER_BLK * 4]; if (*q == 1) { block->track = unbcd[q[1]]; block->index = unbcd[q[2]]; /*block->minute = unbcd[q[7]]; block->second = unbcd[q[8]];*/ block->frame = unbcd[q[9]]; block->status = WM_CDM_PLAYING; block->buflen = cdda.cdda_length; } } return wmcdda_normalize(block); } /* * Normalize a bunch of CDDA data. Basically this means ripping out the * Q subchannel data and doing byte-swapping, since the CD audio is in * littleendian format. * * Scanning is handled here too. * * XXX - do byte swapping on Intel boxes? */ long wmcdda_normalize(struct cdda_block *block) { int i, nextq; long buflen = block->buflen; int blocks = buflen / CDDABLKSIZE; unsigned char *rawbuf = block->buf; unsigned char *dest = rawbuf; unsigned char tmp; long *buf32 = (long *)rawbuf, tmp32; /* * this was #ifndef LITTLEENDIAN * in wmcdda it was called LITTLE_ENDIAN. Was this a flaw? */ #if WM_BIG_ENDIAN if (blocks--) for (i = 0; i < SAMPLES_PER_BLK * 2; i++) { /* Only need to use temp buffer on first block. */ tmp = *rawbuf++; *dest++ = *rawbuf++; *dest++ = tmp; } #endif while (blocks--) { /* Skip over Q data. */ rawbuf += 16; for (i = 0; i < SAMPLES_PER_BLK * 2; i++) { #if WM_LITTLE_ENDIAN *dest++ = *rawbuf++; *dest++ = *rawbuf++; #else *dest++ = rawbuf[1]; *dest++ = rawbuf[0]; rawbuf += 2; #endif } } buflen -= ((buflen / CDDABLKSIZE) * 16); /* * Reverse the data here if we're playing backwards. * XXX - ideally this should be done above. */ if (direction < 0) { buflen /= 4; /* we can move 32 bits at a time. */ for (i = 0; i < buflen / 2; i++) { tmp32 = buf32[i]; buf32[i] = buf32[buflen - i - 1]; buf32[buflen - i - 1] = tmp32; } buflen *= 4; } return (buflen); } /* * Set the playback direction. */ void wmcdda_direction(int newdir) { if (newdir == 0) { numblocks = 20; direction = 1; } else { numblocks = 30; direction = -1; } } /* * Do system-specific stuff to get ready to play at a particular speed. */ void wmcdda_speed(int speed) { if (speed > 128) numblocks = 12; else numblocks = direction > 0 ? 20 : 30; } #endif /* } */ diff --git a/src/wmlib_interface.cpp b/src/wmlib_interface.cpp index 60a3ae8..82609fc 100644 --- a/src/wmlib_interface.cpp +++ b/src/wmlib_interface.cpp @@ -1,328 +1,328 @@ /* * KCompactDisc - A CD drive interface for the KDE Project. * * Copyright (C) 2007 Alexander Kern * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "wmlib_interface.h" #include #include extern "C" { // We don't have libWorkMan installed already, so get everything // from within our own directory #include "wmlib/include/wm_cdrom.h" #include "wmlib/include/wm_cdtext.h" #include "wmlib/include/wm_helpers.h" } #define TRACK_VALID(track) ((track) && (track <= m_tracks)) KWMLibCompactDiscPrivate::KWMLibCompactDiscPrivate(KCompactDisc *p, const QString &dev, const QString &audioSystem, const QString &audioDevice) : KCompactDiscPrivate(p, dev), m_handle(NULL), m_audioSystem(audioSystem), m_audioDevice(audioDevice) { m_interface = m_audioSystem; } KWMLibCompactDiscPrivate::~KWMLibCompactDiscPrivate() { if (m_handle) { wm_cd_destroy(m_handle); } } bool KWMLibCompactDiscPrivate::createInterface() { QString devicePath; devicePath = KCompactDisc::cdromDeviceUrl(m_deviceName).path(); // Debug. //wm_cd_set_verbosity(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS_ALL); int status = wm_cd_init( devicePath.toLatin1().data(), m_audioSystem.toLatin1().data(), m_audioDevice.toLatin1().data(), NULL, &m_handle); if(!WM_CDS_ERROR(status)) { m_deviceVendor = QLatin1String(wm_drive_vendor(m_handle)); m_deviceModel = QLatin1String(wm_drive_model(m_handle)); m_deviceRevision = QLatin1String(wm_drive_revision(m_handle)); Q_Q(KCompactDisc); emit q->discChanged(0); if (m_infoMode == KCompactDisc::Asynchronous) { timerExpired(); } else { QTimer::singleShot(1000, this, SLOT(timerExpired())); } return true; } m_handle = NULL; return false; } unsigned KWMLibCompactDiscPrivate::trackLength(unsigned track) { return (unsigned)wm_cd_gettracklen(m_handle, track); } bool KWMLibCompactDiscPrivate::isTrackAudio(unsigned track) { return !wm_cd_gettrackdata(m_handle, track); } void KWMLibCompactDiscPrivate::playTrackPosition(unsigned track, unsigned position) { unsigned firstTrack, lastTrack; firstTrack = TRACK_VALID(track) ? track : 1; lastTrack = firstTrack + 1; lastTrack = TRACK_VALID(lastTrack) ? lastTrack : WM_ENDTRACK; qDebug() << "play track " << firstTrack << " position " << position << endl; wm_cd_play(m_handle, firstTrack, position, lastTrack); } void KWMLibCompactDiscPrivate::pause() { wm_cd_pause(m_handle); } void KWMLibCompactDiscPrivate::stop() { wm_cd_stop(m_handle); } void KWMLibCompactDiscPrivate::eject() { wm_cd_eject(m_handle); } void KWMLibCompactDiscPrivate::closetray() { wm_cd_closetray(m_handle); } /* WM_VOLUME_MUTE ... WM_VOLUME_MAXIMAL */ /* WM_BALANCE_ALL_LEFTS .WM_BALANCE_SYMMETRED. WM_BALANCE_ALL_RIGHTS */ #define RANGE2PERCENT(x, min, max) (((x) - (min)) * 100)/ ((max) - (min)) #define PERCENT2RANGE(x, min, max) ((((x) * ((max) - (min))) / 100 ) + (min)) void KWMLibCompactDiscPrivate::setVolume(unsigned volume) { int vol, bal; vol = PERCENT2RANGE(volume, WM_VOLUME_MUTE, WM_VOLUME_MAXIMAL); bal = wm_cd_getbalance(m_handle); wm_cd_volume(m_handle, vol, bal); } void KWMLibCompactDiscPrivate::setBalance(unsigned balance) { int vol, bal; vol = wm_cd_getvolume(m_handle); bal = PERCENT2RANGE(balance, WM_BALANCE_ALL_LEFTS, WM_BALANCE_ALL_RIGHTS); wm_cd_volume(m_handle, vol, bal); } unsigned KWMLibCompactDiscPrivate::volume() { int vol = wm_cd_getvolume(m_handle); unsigned volume = RANGE2PERCENT(vol, WM_VOLUME_MUTE, WM_VOLUME_MAXIMAL); return volume; } unsigned KWMLibCompactDiscPrivate::balance() { int bal = wm_cd_getbalance(m_handle); unsigned balance = RANGE2PERCENT(bal, WM_BALANCE_ALL_LEFTS, WM_BALANCE_ALL_RIGHTS); return balance; } void KWMLibCompactDiscPrivate::queryMetadata() { cdtext(); //cddb(); } KCompactDisc::DiscStatus KWMLibCompactDiscPrivate::discStatusTranslate(int status) { switch (status) { case WM_CDM_TRACK_DONE: case WM_CDM_PLAYING: case WM_CDM_FORWARD: return KCompactDisc::Playing; case WM_CDM_PAUSED: return KCompactDisc::Paused; case WM_CDM_STOPPED: return KCompactDisc::Stopped; case WM_CDM_EJECTED: return KCompactDisc::Ejected; case WM_CDM_NO_DISC: case WM_CDM_UNKNOWN: return KCompactDisc::NoDisc; case WM_CDM_CDDAERROR: case WM_CDM_LOADING: case WM_CDM_BUFFERING: return KCompactDisc::NotReady; default: return KCompactDisc::Error; } } void KWMLibCompactDiscPrivate::timerExpired() { KCompactDisc::DiscStatus status; unsigned track, i; Q_Q(KCompactDisc); status = discStatusTranslate(wm_cd_status(m_handle)); if(m_status != status) { if(skipStatusChange(status)) goto timerExpiredExit; m_status = status; switch(m_status) { case KCompactDisc::Ejected: case KCompactDisc::NoDisc: clearDiscInfo(); break; default: if(m_tracks == 0) { m_tracks = wm_cd_getcountoftracks(m_handle); if(m_tracks > 0) { qDebug() << "New disc with " << m_tracks << " tracks"; m_discId = wm_cddb_discid(m_handle); - for(i = 1; i <= m_tracks; i++) { + for(i = 1; i <= m_tracks; ++i) { m_trackStartFrames.append(wm_cd_gettrackstart(m_handle, i)); } m_trackStartFrames.append(wm_cd_gettrackstart(m_handle, i)); m_discLength = FRAMES2SEC(m_trackStartFrames[m_tracks] - m_trackStartFrames[0]); make_playlist(); m_trackArtists.append(i18n("Unknown Artist")); m_trackTitles.append(i18n("Unknown Title")); - for(i = 1; i <= m_tracks; i++) { + for(i = 1; i <= m_tracks; ++i) { m_trackArtists.append(i18n("Unknown Artist")); m_trackTitles.append(ki18n("Track %1").subs(i, 2).toString()); } qDebug() << "m_tracks " << m_tracks; qDebug() << "m_trackStartFrames " << m_trackStartFrames; qDebug() << "m_trackArtists " << m_trackArtists; qDebug() << "m_trackTitles " << m_trackTitles; emit q->discChanged(m_tracks); if(m_autoMetadata) queryMetadata(); } } break; } } switch(m_status) { case KCompactDisc::Playing: m_trackPosition = wm_get_cur_pos_rel(m_handle); m_discPosition = wm_get_cur_pos_abs(m_handle) - FRAMES2SEC(m_trackStartFrames[0]); // Update the current playing position. if(m_seek) { qDebug() << "seek: " << m_seek << " trackPosition " << m_trackPosition; if(abs((long)(m_trackExpectedPosition - m_trackPosition)) > m_seek) m_seek = 0; else m_seek = abs((long)(m_trackExpectedPosition - m_trackPosition)); } if(!m_seek) { emit q->playoutPositionChanged(m_trackPosition); //emit q->playoutDiscPositionChanged(m_discPosition); } // Per-event processing. track = wm_cd_getcurtrack(m_handle); if(m_track != track) { m_track = track; emit q->playoutTrackChanged(m_track); } break; case KCompactDisc::Stopped: m_seek = 0; m_track = 0; break; default: break; } timerExpiredExit: // Now that we have incurred any delays caused by the signals, we'll start the timer. QTimer::singleShot(1000, this, SLOT(timerExpired())); } void KWMLibCompactDiscPrivate::cdtext() { struct cdtext_info *info; unsigned i; Q_Q(KCompactDisc); info = wm_cd_get_cdtext(m_handle); if(!info || !info->valid || (unsigned)info->count_of_entries != (m_tracks + 1)) { qDebug() << "no or invalid CDTEXT"; return; } m_trackArtists[0] = QLatin1String( reinterpret_cast(info->blocks[0]->performer[0]) ); m_trackTitles[0] = QLatin1String( reinterpret_cast(info->blocks[0]->name[0]) ); - for(i = 1; i <= m_tracks; i++) { + for(i = 1; i <= m_tracks; ++i) { m_trackArtists[i] = QLatin1String( reinterpret_cast(info->blocks[0]->performer[i]) ); m_trackTitles[i] =QLatin1String( reinterpret_cast(info->blocks[0]->name[i]) ); } qDebug() << "CDTEXT"; qDebug() << "m_trackArtists " << m_trackArtists; qDebug() << "m_trackTitles " << m_trackTitles; emit q->discInformation(KCompactDisc::Cdtext); } #include "wmlib_interface.moc"