Permalink
Browse files

MythMusic: Add ice/shoutcast radio stream playback

(cherry picked from commit 9268134)

Conflicts:

	mythplugins/mythmusic/mythmusic/metadata.cpp
	mythplugins/mythmusic/mythmusic/metadata.h
	mythplugins/mythmusic/mythmusic/musicplayer.h

Signed-off-by: Stuart Morgan <smorgan@mythtv.org>
  • Loading branch information...
1 parent a32d5e3 commit cdde562f332ee3b074da1a176b02365cefa1c8ec Paul Harrison committed with stuartm Jun 16, 2012
@@ -11,7 +11,7 @@ using namespace std;
#include "mythtv/mythdb.h"
#include "mythtv/schemawizard.h"
-const QString currentDatabaseVersion = "1019";
+const QString currentDatabaseVersion = "1020";
static bool doUpgradeMusicDatabaseSchema(QString &dbver);
@@ -854,5 +854,28 @@ QString("ALTER DATABASE %1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;")
return false;
}
+ if (dbver == "1019")
+ {
+ const QString updates[] = {
+"DROP TABLE IF EXISTS music_radios;",
+"CREATE TABLE music_radios ("
+" intid INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,"
+" station VARCHAR(128) NOT NULL,"
+" channel VARCHAR(128) NOT NULL,"
+" url VARCHAR(128) NOT NULL,"
+" logourl VARCHAR(128) NOT NULL,"
+" genre VARCHAR(128) NOT NULL,"
+" metaformat VARCHAR(128) NOT NULL,"
+" format VARCHAR(10) NOT NULL,"
+" INDEX (station),"
+" INDEX (channel)"
+");",
+""
+};
+
+ if (!performActualUpdate(updates, "1020", dbver))
+ return false;
+ }
+
return true;
}
@@ -27,13 +27,13 @@
QEvent::Type DecoderHandlerEvent::Ready = (QEvent::Type) QEvent::registerEventType();
QEvent::Type DecoderHandlerEvent::Meta = (QEvent::Type) QEvent::registerEventType();
-QEvent::Type DecoderHandlerEvent::Info = (QEvent::Type) QEvent::registerEventType();
+QEvent::Type DecoderHandlerEvent::BufferStatus = (QEvent::Type) QEvent::registerEventType();
QEvent::Type DecoderHandlerEvent::OperationStart = (QEvent::Type) QEvent::registerEventType();
QEvent::Type DecoderHandlerEvent::OperationStop = (QEvent::Type) QEvent::registerEventType();
QEvent::Type DecoderHandlerEvent::Error = (QEvent::Type) QEvent::registerEventType();
DecoderHandlerEvent::DecoderHandlerEvent(Type t, const Metadata &meta)
- : MythEvent(t), m_msg(NULL), m_meta(NULL)
+ : MythEvent(t), m_msg(NULL), m_meta(NULL), m_available(0), m_maxSize(0)
{
m_meta = new Metadata(meta);
}
@@ -57,9 +57,18 @@ MythEvent* DecoderHandlerEvent::clone(void) const
if (m_meta)
result->m_meta = new Metadata(*m_meta);
+ result->m_available = m_available;
+ result->m_maxSize = m_maxSize;
+
return result;
}
+void DecoderHandlerEvent::getBufferStatus(int *available, int *maxSize) const
+{
+ *available = m_available;
+ *maxSize = m_maxSize;
+}
+
/**********************************************************************/
DecoderIOFactory::DecoderIOFactory(DecoderHandler *parent)
@@ -88,11 +97,6 @@ void DecoderIOFactory::doFailed(const QString &message)
m_handler->doFailed(getUrl(), message);
}
-void DecoderIOFactory::doInfo(const QString &message)
-{
- m_handler->doInfo(message);
-}
-
void DecoderIOFactory::doOperationStart(const QString &name)
{
m_handler->doOperationStart(name);
@@ -201,7 +205,7 @@ void DecoderIOFactoryUrl::start(void)
m_started = false;
- doOperationStart("Fetching remote file");
+ doOperationStart(tr("Fetching remote file"));
m_reply = m_accessManager->get(QNetworkRequest(getUrl()));
@@ -266,12 +270,6 @@ void DecoderIOFactoryUrl::readyRead(void)
m_reply->setReadBufferSize(DecoderIOFactory::DefaultPrebufferSize);
doStart();
}
-
-#if 0
- LOG(VB_GENERAL, LOG_DEBUG,
- QString("DecoderIOFactoryUrl::readyRead file size: %1")
- .arg(m_bytesWritten));
-#endif
}
void DecoderIOFactoryUrl::doStart(void)
@@ -319,7 +317,19 @@ void DecoderHandler::start(Metadata *mdata)
else
url.setUrl(mdata->Filename());
- bool result = createPlaylist(url);
+ createPlaylist(url);
+}
+
+void DecoderHandler::doStart(bool result)
+{
+ doOperationStop();
+
+ QUrl url;
+ if (QFileInfo(m_meta->Filename()).isAbsolute())
+ url = QUrl::fromLocalFile(m_meta->Filename());
+ else
+ url.setUrl(m_meta->Filename());
+
if (m_state == LOADING && result)
{
for (int ii = 0; ii < m_playlist.size(); ii++)
@@ -329,7 +339,7 @@ void DecoderHandler::start(Metadata *mdata)
}
else
{
- if (m_state != STOPPED)
+ if (m_state == STOPPED)
{
doFailed(url, "Could not get playlist");
}
@@ -428,16 +438,55 @@ void DecoderHandler::stop(void)
m_state = STOPPED;
}
-void DecoderHandler::customEvent(QEvent *e)
+void DecoderHandler::customEvent(QEvent *event)
{
- if (class DecoderHandlerEvent *event = dynamic_cast<DecoderHandlerEvent*>(e))
+ if (DecoderHandlerEvent *dhe = dynamic_cast<DecoderHandlerEvent*>(event))
{
// Proxy all DecoderHandlerEvents
- return dispatch(*event);
+ return dispatch(*dhe);
+ }
+ else if (event->type() == MythEvent::MythEventMessage)
+ {
+ MythEvent *me = (MythEvent *)event;
+ QStringList tokens = me->Message().split(" ", QString::SkipEmptyParts);
+
+ if (tokens.isEmpty())
+ return;
+
+ if (tokens[0] == "DOWNLOAD_FILE")
+ {
+ QStringList args = me->ExtraDataList();
+
+ if (tokens[1] == "UPDATE")
+ {
+ }
+ else if (tokens[1] == "FINISHED")
+ {
+ QString downloadUrl = args[0];
+ int fileSize = args[2].toInt();
+ int errorCode = args[4].toInt();
+ QString filename = args[1];
+
+ if ((errorCode != 0) || (fileSize == 0))
+ {
+ LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler: failed to download playlist from '%1'")
+ .arg(downloadUrl));
+ QUrl url(downloadUrl);
+ m_state = STOPPED;
+ doOperationStop();
+ doFailed(url, "Could not get playlist");
+ }
+ else
+ {
+ QUrl fileUrl(filename);
+ createPlaylistFromFile(fileUrl);
+ }
+ }
+ }
}
}
-bool DecoderHandler::createPlaylist(const QUrl &url)
+void DecoderHandler::createPlaylist(const QUrl &url)
{
QString extension = QFileInfo(url.path()).suffix();
LOG(VB_NETWORK, LOG_INFO,
@@ -447,15 +496,17 @@ bool DecoderHandler::createPlaylist(const QUrl &url)
if (extension == "pls" || extension == "m3u")
{
if (url.scheme() == "file" || QFileInfo(url.toString()).isAbsolute())
- return createPlaylistFromFile(url);
+ createPlaylistFromFile(url);
else
- return createPlaylistFromRemoteUrl(url);
+ createPlaylistFromRemoteUrl(url);
+
+ return;
}
- return createPlaylistForSingleFile(url);
+ createPlaylistForSingleFile(url);
}
-bool DecoderHandler::createPlaylistForSingleFile(const QUrl &url)
+void DecoderHandler::createPlaylistForSingleFile(const QUrl &url)
{
PlayListFileEntry *entry = new PlayListFileEntry;
@@ -466,49 +517,51 @@ bool DecoderHandler::createPlaylistForSingleFile(const QUrl &url)
m_playlist.add(entry);
- return m_playlist.size() > 0;
+ doStart((m_playlist.size() > 0));
}
-bool DecoderHandler::createPlaylistFromFile(const QUrl &url)
+void DecoderHandler::createPlaylistFromFile(const QUrl &url)
{
QFile f(QFileInfo(url.path()).absolutePath() + "/" + QFileInfo(url.path()).fileName());
if (!f.open(QIODevice::ReadOnly))
- return false;
+ return;
QTextStream stream(&f);
QString extension = QFileInfo(url.path()).suffix().toLower();
- if (PlayListFile::parse(&m_playlist, &stream, extension) <= 0)
- return false;
+ PlayListFile::parse(&m_playlist, &stream, extension);
- return m_playlist.size() > 0;
+ doStart((m_playlist.size() > 0));
}
-bool DecoderHandler::createPlaylistFromRemoteUrl(const QUrl &url)
+void DecoderHandler::createPlaylistFromRemoteUrl(const QUrl &url)
{
LOG(VB_NETWORK, LOG_INFO,
QString("Retrieving playlist from '%1'").arg(url.toString()));
- doOperationStart("Retrieving playlist");
-
- QByteArray data;
-
- if (!GetMythDownloadManager()->download(url.toString(), &data))
- {
- LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler:: Failed to download playlist from: %1").arg(url.toString()));
- doOperationStop();
- return false;
- }
-
- doOperationStop();
-
- QTextStream stream(&data, QIODevice::ReadOnly);
+ doOperationStart(tr("Retrieving playlist"));
QString extension = QFileInfo(url.path()).suffix().toLower();
+ QString saveFilename = GetConfDir() + "/MythMusic/playlist." + extension;
+ GetMythDownloadManager()->queueDownload(url.toString(), saveFilename, this);
- bool result = PlayListFile::parse(&m_playlist, &stream, extension) > 0;
+ //TODO should find a better way to do this
+ QTime time;
+ time.start();
+ while (m_state == LOADING)
+ {
+ if (time.elapsed() > 30000)
+ {
+ doOperationStop();
+ GetMythDownloadManager()->cancelDownload(url.toString());
+ LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler:: Timed out trying to download playlist from: %1")
+ .arg(url.toString()));
+ m_state = STOPPED;
+ }
- return result;
+ qApp->processEvents();
+ usleep(500);
+ }
}
void DecoderHandler::doConnectDecoder(const QUrl &url, const QString &format)
@@ -538,18 +591,11 @@ void DecoderHandler::doConnectDecoder(const QUrl &url, const QString &format)
void DecoderHandler::doFailed(const QUrl &url, const QString &message)
{
LOG(VB_NETWORK, LOG_ERR,
- QString("DecoderHandler: Unsupported file format: '%1' - %2")
- .arg(url.toString()).arg(message));
+ QString("DecoderHandler error: '%1' - %2").arg(message).arg(url.toString()));
DecoderHandlerEvent ev(DecoderHandlerEvent::Error, new QString(message));
dispatch(ev);
}
-void DecoderHandler::doInfo(const QString &message)
-{
- DecoderHandlerEvent ev(DecoderHandlerEvent::Info, new QString(message));
- dispatch(ev);
-}
-
void DecoderHandler::doOperationStart(const QString &name)
{
m_op = true;
@@ -38,29 +38,36 @@ class DecoderHandlerEvent : public MythEvent
{
public:
DecoderHandlerEvent(Type t)
- : MythEvent(t), m_msg(0), m_meta(0) {}
+ : MythEvent(t), m_msg(0), m_meta(0), m_available(0), m_maxSize(0) {}
DecoderHandlerEvent(Type t, QString *e)
- : MythEvent(t), m_msg(e), m_meta(0) {}
+ : MythEvent(t), m_msg(e), m_meta(0), m_available(0), m_maxSize(0) {}
+
+ DecoderHandlerEvent(Type t, int available, int maxSize)
+ : MythEvent(t), m_msg(0), m_meta(0),
+ m_available(available), m_maxSize(maxSize) {}
DecoderHandlerEvent(Type t, const Metadata &m);
~DecoderHandlerEvent();
QString *getMessage(void) const { return m_msg; }
Metadata *getMetadata(void) const { return m_meta; }
+ void getBufferStatus(int *available, int *maxSize) const;
virtual MythEvent *clone(void) const;
static Type Ready;
static Type Meta;
- static Type Info;
+ static Type BufferStatus;
static Type OperationStart;
static Type OperationStop;
static Type Error;
private:
QString *m_msg;
Metadata *m_meta;
+ int m_available;
+ int m_maxSize;
};
/** \brief Class for starting stream decoding.
@@ -105,13 +112,13 @@ class DecoderHandler : public QObject, public MythObservable
void doOperationStop(void);
void doConnectDecoder(const QUrl &url, const QString &format);
void doFailed(const QUrl &url, const QString &message);
- void doInfo(const QString &message);
+ void doStart(bool result);
private:
- bool createPlaylist(const QUrl &url);
- bool createPlaylistForSingleFile(const QUrl &url);
- bool createPlaylistFromFile(const QUrl &url);
- bool createPlaylistFromRemoteUrl(const QUrl &url);
+ void createPlaylist(const QUrl &url);
+ void createPlaylistForSingleFile(const QUrl &url);
+ void createPlaylistFromFile(const QUrl &url);
+ void createPlaylistFromRemoteUrl(const QUrl &url);
bool haveIOFactory(void) { return m_io_factory != NULL; }
DecoderIOFactory *getIOFactory(void) { return m_io_factory; }
@@ -156,7 +163,6 @@ class DecoderIOFactory : public QObject, public MythObservable
void doConnectDecoder(const QString &format);
Decoder *getDecoder(void);
void doFailed(const QString &message);
- void doInfo(const QString &message);
void doOperationStart(const QString &name);
void doOperationStop(void);
Metadata& getMetadata() { return m_meta; }
@@ -129,7 +129,6 @@ ImportMusicDialog::~ImportMusicDialog()
delete m_tracks;
- // do we need to do a resync
if (m_somethingWasImported)
emit importFinished();
}
Oops, something went wrong.

0 comments on commit cdde562

Please sign in to comment.