From 12f87d19a7320bfef3a2e6319e4e3a0277d4aa67 Mon Sep 17 00:00:00 2001 From: "craig.p.drummond" Date: Thu, 14 Mar 2013 19:32:27 +0000 Subject: [PATCH] Playback of AudioCDs via HTTP server --- TODO | 3 --- devices/audiocddevice.h | 3 --- devices/cdparanoia.cpp | 7 +++++-- devices/cdparanoia.h | 2 +- devices/devicespage.cpp | 3 +++ http/httpsocket.cpp | 41 +++++++++++++++++------------------------ models/devicesmodel.cpp | 5 +---- 7 files changed, 27 insertions(+), 37 deletions(-) diff --git a/TODO b/TODO index 3de5768dd..339045f3e 100644 --- a/TODO +++ b/TODO @@ -33,9 +33,6 @@ - RemoteFsDevices - Cantata hangs if smb service is stopped before its un-mounted - Re-enable covers in sync dialog? - - Playback of tracks from CD - - Tried, could not get to work - no sound! - - If stop playback, HTTP server continues with track extraction. - Lyrics - Add support for reading via tags in mp4, flac, and ogg files. diff --git a/devices/audiocddevice.h b/devices/audiocddevice.h index 5bdf6405a..cf788f163 100644 --- a/devices/audiocddevice.h +++ b/devices/audiocddevice.h @@ -74,10 +74,7 @@ public: void saveOptions() { } QString subText() { return album; } quint32 totalTime(); - #ifdef CDDB_PLAYBACK bool canPlaySongs() const { return true; } - #endif - QString albumName() const { return album; } QString albumArtist() const { return artist; } QString albumGenre() const { return genre; } diff --git a/devices/cdparanoia.cpp b/devices/cdparanoia.cpp index 06987e58c..92d733200 100644 --- a/devices/cdparanoia.cpp +++ b/devices/cdparanoia.cpp @@ -29,7 +29,7 @@ static QSet lockedDevices; static QMutex mutex; -CdParanoia::CdParanoia(const QString &device, bool full, bool noSkip) +CdParanoia::CdParanoia(const QString &device, bool full, bool noSkip, bool playback) : drive(0) , paranoia(0) , paranoiaMode(0) @@ -50,7 +50,10 @@ CdParanoia::CdParanoia(const QString &device, bool full, bool noSkip) if (!dev.isEmpty()) { setFullParanoiaMode(full); - setMaxRetries(20); + if (playback) { + maxRetries=1; + paranoia_cachemodel_size(paranoia, 24); + } } } diff --git a/devices/cdparanoia.h b/devices/cdparanoia.h index 40d585fd8..cc0ba6e96 100644 --- a/devices/cdparanoia.h +++ b/devices/cdparanoia.h @@ -34,7 +34,7 @@ extern "C" { class CdParanoia { public: - CdParanoia(const QString &device, bool full, bool noSkip); + CdParanoia(const QString &device, bool full, bool noSkip, bool playback=false); ~CdParanoia(); inline operator bool() const { return !dev.isEmpty(); } diff --git a/devices/devicespage.cpp b/devices/devicespage.cpp index 30f1b364d..e36710c9c 100644 --- a/devices/devicespage.cpp +++ b/devices/devicespage.cpp @@ -51,6 +51,7 @@ #include "trackorganiser.h" #include "preferencesdialog.h" #include "coverdialog.h" +#include "mpdconnection.h" #if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND #include "audiocddevice.h" #include "albumdetailsdialog.h" @@ -90,6 +91,8 @@ DevicesPage::DevicesPage(QWidget *p) sep->setSeparator(true); view->addAction(sep); view->addAction(StdActions::self()->deleteSongsAction); + connect(this, SIGNAL(add(const QStringList &, bool, quint8)), MPDConnection::self(), SLOT(add(const QStringList &, bool, quint8))); + connect(this, SIGNAL(addSongsToPlaylist(const QString &, const QStringList &)), MPDConnection::self(), SLOT(addToPlaylist(const QString &, const QStringList &))); connect(genreCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(searchItems())); connect(DevicesModel::self(), SIGNAL(updateGenres(const QSet &)), genreCombo, SLOT(update(const QSet &))); connect(DevicesModel::self(), SIGNAL(updated(QModelIndex)), this, SLOT(updated(QModelIndex))); diff --git a/http/httpsocket.cpp b/http/httpsocket.cpp index 5ef4e2411..6b056973e 100644 --- a/http/httpsocket.cpp +++ b/http/httpsocket.cpp @@ -25,6 +25,10 @@ #include "httpsocket.h" #include "httpserver.h" #include "settings.h" +#if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND +#include "cdparanoia.h" +#include "extractjob.h" +#endif #include #include #include @@ -45,11 +49,6 @@ #include #endif -#ifdef CDDB_PLAYBACK -#include "cdparanoia.h" -#include "extractjob.h" -#endif - static QString detectMimeType(const QString &file) { #ifdef ENABLE_KDE_SUPPORT @@ -255,14 +254,13 @@ void HttpSocket::readClient() bool ok=false; if (q.hasQueryItem("cantata")) { - #ifdef CDDB_PLAYBACK - // Not working :-( No sound is played, plus thi seems to continue until Cantata is stopped?? Song song=HttpServer::self()->decodeUrl(url); if (song.file.startsWith(QLatin1String("cdda:/"))) { + #if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND QStringList parts=song.file.split("/", QString::SkipEmptyParts); if (parts.length()>=3) { QString dev=QLatin1Char('/')+parts.at(1)+QLatin1Char('/')+parts.at(2); - CdParanoia cdparanoia(dev, false, false); + CdParanoia cdparanoia(dev, false, false, true); if (cdparanoia) { int firstSector = cdparanoia.firstSectorOfTrack(song.id); @@ -272,28 +270,29 @@ void HttpSocket::readClient() ok=true; writeMimeType(QLatin1String("audio/x-wav"), socket); ExtractJob::writeWavHeader(*socket); - while (!terminated && (firstSector+count) <= lastSector) { + bool stop=false; + while (!terminated && (firstSector+count) <= lastSector && !stop) { qint16 *buf = cdparanoia.read(); if (!buf) { - ok=false; break; } char *buffer=(char *)buf; qint64 writePos=0; do { qint64 bytesWritten = socket->write(&buffer[writePos], CD_FRAMESIZE_RAW - writePos); - if (-1==bytesWritten) { - ok=false; + if (terminated || -1==bytesWritten) { + stop=true; break; } + socket->flush(); writePos+=bytesWritten; } while (!terminated && writePoswrite(&buffer[writePos], bytesRead - writePos); - if (terminated) { - break; - } - if (-1==bytesWritten) { - ok=false; + if (terminated || -1==bytesWritten) { + stop=true; break; } + socket->flush(); writePos+=bytesWritten; } while (writePos actions; if (Device::AudioCd!=static_cast(item)->devType()) { actions << configureAction; - } - #ifdef CDDB_PLAYBACK - else if (HttpServer::self()->isAlive()) { + } else if (HttpServer::self()->isAlive()) { actions << StdActions::self()->replacePlayQueueAction; } - #endif actions << refreshAction; if (static_cast(item)->supportsDisconnect()) { actions << (static_cast(item)->isConnected() ? disconnectAction : connectAction);