From 8c1cbee767d2c57e628aa1ab36b60f8119d8292a Mon Sep 17 00:00:00 2001 From: "craig.p.drummond" Date: Wed, 2 Jan 2013 19:50:58 +0000 Subject: [PATCH] Fix playing of FLAC files external to MPD database via Cantata's simple HTTP server. --- ChangeLog | 2 + devices/tags.cpp | 4 -- http/httpserver.cpp | 10 +---- http/httpsocket.cpp | 106 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 104 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 99910ad3c..db0159e4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -52,6 +52,8 @@ 6. Fix decoding of Cantata HTTP stream URLs. 7. Work-around issue of non display of main window when using transparent QtCurve theme. +8. Fix playing of FLAC files external to MPD database via Cantata's simple HTTP + server. 0.9.1 ----- diff --git a/devices/tags.cpp b/devices/tags.cpp index 49d3e7ed9..6e2be650f 100644 --- a/devices/tags.cpp +++ b/devices/tags.cpp @@ -23,9 +23,7 @@ #include "tags.h" #include "config.h" -#ifdef ENABLE_KDE_SUPPORT #include "filetyperesolver.h" -#endif #include "utils.h" #include #include @@ -168,9 +166,7 @@ static void ensureFileTypeResolvers() TagLib::FileRef::addFileTypeResolver(new AudibleFileTypeResolver); TagLib::FileRef::addFileTypeResolver(new RealMediaFileTypeResolver); #endif - #ifdef ENABLE_KDE_SUPPORT TagLib::FileRef::addFileTypeResolver(new Meta::Tag::FileTypeResolver()); - #endif } } diff --git a/http/httpserver.cpp b/http/httpserver.cpp index d1e5b2a36..ee7f8dd4d 100644 --- a/http/httpserver.cpp +++ b/http/httpserver.cpp @@ -140,9 +140,6 @@ QByteArray HttpServer::encodeUrl(const Song &s) const if (s.track) { url.addQueryItem("track", QString::number(s.track)); } - if (!s.file.isEmpty()) { - url.addQueryItem("file", s.file); - } url.addQueryItem("cantata", "song"); return url.toEncoded(); } @@ -151,6 +148,7 @@ QByteArray HttpServer::encodeUrl(const QString &file) const { Song s=Tags::read(file); s.fillEmptyFields(); + s.file=file; return encodeUrl(s); } @@ -187,11 +185,7 @@ Song HttpServer::decodeUrl(const QString &url) const if (u.hasQueryItem("track")) { s.track=u.queryItemValue("track").toInt(); } - if (u.hasQueryItem("file")) { - s.file=u.queryItemValue("file"); - } else { - s.file=u.path(); - } + s.file=u.path(); } return s; diff --git a/http/httpsocket.cpp b/http/httpsocket.cpp index 0361d97e7..ccf936738 100644 --- a/http/httpsocket.cpp +++ b/http/httpsocket.cpp @@ -21,6 +21,7 @@ * Boston, MA 02110-1301, USA. */ +#include "config.h" #include "httpsocket.h" #include #include @@ -28,6 +29,67 @@ #include #include #include +#ifdef ENABLE_KDE_SUPPORT +#include +#else +#include +#ifdef TAGLIB_FOUND +#include +#include +#include +#endif +#endif + +static QString detectMimeType(const QString &file) +{ + #ifdef ENABLE_KDE_SUPPORT + return KMimeType::findByPath(file)->name(); + #else + QString suffix = QFileInfo(file).suffix(); + if (suffix == QLatin1String("mp3")) { + return "audio/mpeg"; + } + #ifdef TAGLIB_FOUND + if (suffix == QLatin1String("ogg")) { + #ifdef Q_OS_WIN32 + const wchar_t *encodedName = reinterpret_cast< const wchar_t * >(file.utf16()); + #elif defined COMPLEX_TAGLIB_FILENAME + const wchar_t *encodedName = reinterpret_cast< const wchar_t * >(file.utf16()); + #else + QByteArray fileName = QFile::encodeName(file); + const char *encodedName = fileName.constData(); // valid as long as fileName exists + #endif + + QString mime; + TagLib::File *result = new TagLib::Ogg::Vorbis::File(encodedName, false, TagLib::AudioProperties::Fast); + if (result->isValid()) { + mime="audio/x-vorbis+ogg"; + } + delete result; + if (mime.isEmpty()) { + result = new TagLib::Ogg::FLAC::File(encodedName, false, TagLib::AudioProperties::Fast); + if (result->isValid()) { + mime="audio/x-flac+ogg"; + } + delete result; + } + return mime; + } + #endif + else if (suffix == QLatin1String("flac")) { + return "audio/x-flac"; + } else if (suffix == QLatin1String("wma")) { + return "audio/x-ms-wma"; + } + else if (suffix == QLatin1String("m4a") || suffix == QLatin1String("m4b") || suffix == QLatin1String("m4p") || suffix == QLatin1String("mp4")) { + return "audio/mp4"; + } + else if (suffix == QLatin1String("wav")) { + return "audio/x-wav"; + } + #endif + return QString(); +} // static int level(const QString &s) // { @@ -115,15 +177,47 @@ void HttpSocket::readClient() QFile f(url.path()); if (f.open(QIODevice::ReadOnly)) { + QString mimeType=detectMimeType(url.path()); + if (!mimeType.isEmpty()) { + QTextStream os(socket); + os.setAutoDetectUnicode(true); + os << "HTTP/1.0 200 OK\r\nContent-Type: " << mimeType << "\r\n\r\n"; + } + ok=true; - for(; !terminated;) { - QByteArray buffer=f.read(4096); - if (buffer.size()>0) { - socket->write(buffer); - } else { + static const int constChunkSize=8192; + char buffer[constChunkSize]; + qint64 totalBytes = f.size(); + qint64 readPos = 0; + qint64 bytesRead = 0; + + do { + if (terminated) { break; } - } + bytesRead = f.read(buffer, constChunkSize); + readPos+=bytesRead; + if (bytesRead<0 || terminated) { + break; + } + + qint64 writePos=0; + do { + qint64 bytesWritten = socket->write(&buffer[writePos], bytesRead - writePos); + if (terminated) { + break; + } + if (-1==bytesWritten) { + ok=false; + break; + } + writePos+=bytesWritten; + } while (writePos