00001
00002 #include <unistd.h>
00003 #include <stdio.h>
00004 #include <assert.h>
00005
00006
00007 #include <QApplication>
00008 #include <QUrl>
00009 #include <QFileInfo>
00010
00011
00012 #include <mythdownloadmanager.h>
00013 #include <mythdirs.h>
00014 #include <mythlogging.h>
00015 #include <compat.h>
00016 #include <remotefile.h>
00017 #include <mythcorecontext.h>
00018
00019
00020 #include "decoderhandler.h"
00021 #include "decoder.h"
00022 #include "metadata.h"
00023 #include "streaminput.h"
00024 #include "shoutcast.h"
00025
00026
00027
00028 QEvent::Type DecoderHandlerEvent::Ready = (QEvent::Type) QEvent::registerEventType();
00029 QEvent::Type DecoderHandlerEvent::Meta = (QEvent::Type) QEvent::registerEventType();
00030 QEvent::Type DecoderHandlerEvent::Info = (QEvent::Type) QEvent::registerEventType();
00031 QEvent::Type DecoderHandlerEvent::OperationStart = (QEvent::Type) QEvent::registerEventType();
00032 QEvent::Type DecoderHandlerEvent::OperationStop = (QEvent::Type) QEvent::registerEventType();
00033 QEvent::Type DecoderHandlerEvent::Error = (QEvent::Type) QEvent::registerEventType();
00034
00035 DecoderHandlerEvent::DecoderHandlerEvent(Type t, const Metadata &meta)
00036 : MythEvent(t), m_msg(NULL), m_meta(NULL)
00037 {
00038 m_meta = new Metadata(meta);
00039 }
00040
00041 DecoderHandlerEvent::~DecoderHandlerEvent(void)
00042 {
00043 if (m_msg)
00044 delete m_msg;
00045
00046 if (m_meta)
00047 delete m_meta;
00048 }
00049
00050 MythEvent* DecoderHandlerEvent::clone(void) const
00051 {
00052 DecoderHandlerEvent *result = new DecoderHandlerEvent(*this);
00053
00054 if (m_msg)
00055 result->m_msg = new QString(*m_msg);
00056
00057 if (m_meta)
00058 result->m_meta = new Metadata(*m_meta);
00059
00060 return result;
00061 }
00062
00063
00064
00065 DecoderIOFactory::DecoderIOFactory(DecoderHandler *parent)
00066 {
00067 m_handler = parent;
00068 }
00069
00070 DecoderIOFactory::~DecoderIOFactory(void)
00071 {
00072 }
00073
00074 void DecoderIOFactory::doConnectDecoder(const QString &format)
00075 {
00076 m_handler->doOperationStop();
00077 m_handler->doConnectDecoder(getUrl(), format);
00078 }
00079
00080 Decoder *DecoderIOFactory::getDecoder(void)
00081 {
00082 return m_handler->getDecoder();
00083 }
00084
00085 void DecoderIOFactory::doFailed(const QString &message)
00086 {
00087 m_handler->doOperationStop();
00088 m_handler->doFailed(getUrl(), message);
00089 }
00090
00091 void DecoderIOFactory::doInfo(const QString &message)
00092 {
00093 m_handler->doInfo(message);
00094 }
00095
00096 void DecoderIOFactory::doOperationStart(const QString &name)
00097 {
00098 m_handler->doOperationStart(name);
00099 }
00100
00101 void DecoderIOFactory::doOperationStop(void)
00102 {
00103 m_handler->doOperationStop();
00104 }
00105
00106
00107
00108 DecoderIOFactoryFile::DecoderIOFactoryFile(DecoderHandler *parent)
00109 : DecoderIOFactory(parent), m_input (NULL)
00110 {
00111 }
00112
00113 DecoderIOFactoryFile::~DecoderIOFactoryFile(void)
00114 {
00115 if (m_input)
00116 delete m_input;
00117 }
00118
00119 QIODevice* DecoderIOFactoryFile::takeInput(void)
00120 {
00121 QIODevice *result = m_input;
00122 m_input = NULL;
00123 return result;
00124 }
00125
00126 void DecoderIOFactoryFile::start(void)
00127 {
00128 QString sourcename = getMetadata().Filename();
00129
00130 LOG(VB_PLAYBACK, LOG_INFO,
00131 QString("DecoderIOFactory: Opening Local File %1").arg(sourcename));
00132
00133 m_input = new QFile(sourcename);
00134 doConnectDecoder(getUrl().toLocalFile());
00135 }
00136
00137
00138
00139 DecoderIOFactorySG::DecoderIOFactorySG(DecoderHandler *parent)
00140 : DecoderIOFactory(parent), m_input(NULL)
00141 {
00142 }
00143
00144 DecoderIOFactorySG::~DecoderIOFactorySG(void)
00145 {
00146 if (m_input)
00147 delete m_input;
00148 }
00149
00150 QIODevice* DecoderIOFactorySG::takeInput(void)
00151 {
00152 QIODevice *result = m_input;
00153 m_input = NULL;
00154 return result;
00155 }
00156
00157 void DecoderIOFactorySG::start(void)
00158 {
00159 QString url = getUrl().toString();
00160 LOG(VB_PLAYBACK, LOG_INFO,
00161 QString("DecoderIOFactorySG: Opening Myth URL %1").arg(url));
00162 m_input = new MusicSGIODevice(url);
00163 doConnectDecoder(getUrl().path());
00164 }
00165
00166
00167
00168 DecoderIOFactoryUrl::DecoderIOFactoryUrl(DecoderHandler *parent) : DecoderIOFactory(parent)
00169 {
00170 m_accessManager = new QNetworkAccessManager(this);
00171 m_input = new MusicIODevice();
00172 connect(m_input, SIGNAL(freeSpaceAvailable()), SLOT(readyRead()));
00173
00174 m_input->open(QIODevice::ReadWrite);
00175
00176 m_bytesWritten = 0;
00177 m_redirectCount = 0;
00178 }
00179
00180 DecoderIOFactoryUrl::~DecoderIOFactoryUrl(void)
00181 {
00182 doClose();
00183
00184 m_accessManager->deleteLater();
00185
00186 if (m_input)
00187 delete m_input;
00188 }
00189
00190 QIODevice* DecoderIOFactoryUrl::takeInput(void)
00191 {
00192 QIODevice *result = m_input;
00193
00194 return result;
00195 }
00196
00197 void DecoderIOFactoryUrl::start(void)
00198 {
00199 LOG(VB_PLAYBACK, LOG_INFO,
00200 QString("DecoderIOFactory: Url %1").arg(getUrl().toString()));
00201
00202 m_started = false;
00203
00204 doOperationStart("Fetching remote file");
00205
00206 m_reply = m_accessManager->get(QNetworkRequest(getUrl()));
00207
00208 connect(m_reply, SIGNAL(readyRead()), this, SLOT(readyRead()));
00209 connect(m_accessManager, SIGNAL(finished(QNetworkReply*)),
00210 this, SLOT(replyFinished(QNetworkReply*)));
00211 }
00212
00213 void DecoderIOFactoryUrl::stop(void)
00214 {
00215 doClose();
00216 }
00217
00218 void DecoderIOFactoryUrl::replyFinished(QNetworkReply *reply)
00219 {
00220 if (reply->error() != QNetworkReply::NoError)
00221 {
00222 doFailed("Cannot retrieve remote file.");
00223 return;
00224 }
00225
00226 QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
00227
00228 if (!possibleRedirectUrl.isEmpty() && (m_redirectedURL != possibleRedirectUrl))
00229 {
00230 LOG(VB_PLAYBACK, LOG_INFO,
00231 QString("DecoderIOFactory: Got redirected to %1")
00232 .arg(possibleRedirectUrl.toString()));
00233
00234 m_redirectCount++;
00235
00236 if (m_redirectCount > MaxRedirects)
00237 {
00238 doFailed("Too many redirects");
00239 }
00240 else
00241 {
00242 setUrl(possibleRedirectUrl);
00243 m_redirectedURL = possibleRedirectUrl;
00244 start();
00245 }
00246
00247 return;
00248 }
00249
00250 m_redirectedURL.clear();
00251
00252 if (!m_started)
00253 doStart();
00254 }
00255
00256 void DecoderIOFactoryUrl::readyRead(void)
00257 {
00258 int available = DecoderIOFactory::DefaultBufferSize - m_input->bytesAvailable();
00259 QByteArray data = m_reply->read(available);
00260
00261 m_bytesWritten += data.size();
00262 m_input->writeData(data.data(), data.size());
00263
00264 if (!m_started && m_bytesWritten > DecoderIOFactory::DefaultPrebufferSize)
00265 {
00266 m_reply->setReadBufferSize(DecoderIOFactory::DefaultPrebufferSize);
00267 doStart();
00268 }
00269
00270 #if 0
00271 LOG(VB_GENERAL, LOG_DEBUG,
00272 QString("DecoderIOFactoryUrl::readyRead file size: %1")
00273 .arg(m_bytesWritten));
00274 #endif
00275 }
00276
00277 void DecoderIOFactoryUrl::doStart(void)
00278 {
00279 doConnectDecoder(getUrl().toString());
00280 m_started = true;
00281 }
00282
00283 void DecoderIOFactoryUrl::doClose(void)
00284 {
00285 if (m_input && m_input->isOpen())
00286 m_input->close();
00287 }
00288
00289
00290
00291 DecoderHandler::DecoderHandler(void) :
00292 m_state(STOPPED),
00293 m_playlist_pos(0),
00294 m_io_factory(NULL),
00295 m_decoder(NULL),
00296 m_meta(NULL),
00297 m_op(false),
00298 m_redirects(0)
00299 {
00300 }
00301
00302 DecoderHandler::~DecoderHandler(void)
00303 {
00304 stop();
00305 }
00306
00307 void DecoderHandler::start(Metadata *mdata)
00308 {
00309 m_state = LOADING;
00310
00311 m_playlist.clear();
00312 m_meta = mdata;
00313 m_playlist_pos = -1;
00314 m_redirects = 0;
00315
00316 QUrl url;
00317 if (QFileInfo(mdata->Filename()).isAbsolute())
00318 url = QUrl::fromLocalFile(mdata->Filename());
00319 else
00320 url.setUrl(mdata->Filename());
00321
00322 bool result = createPlaylist(url);
00323 if (m_state == LOADING && result)
00324 {
00325 for (int ii = 0; ii < m_playlist.size(); ii++)
00326 LOG(VB_PLAYBACK, LOG_INFO, QString("Track %1 = %2")
00327 .arg(ii) .arg(m_playlist.get(ii)->File()));
00328 next();
00329 }
00330 else
00331 {
00332 if (m_state != STOPPED)
00333 {
00334 doFailed(url, "Could not get playlist");
00335 }
00336 }
00337 }
00338
00339 void DecoderHandler::error(const QString &e)
00340 {
00341 QString *str = new QString(e);
00342 DecoderHandlerEvent ev(DecoderHandlerEvent::Error, str);
00343 dispatch(ev);
00344 }
00345
00346 bool DecoderHandler::done(void)
00347 {
00348 if (m_state == STOPPED)
00349 return true;
00350
00351 if (m_playlist_pos + 1 >= m_playlist.size())
00352 {
00353 m_state = STOPPED;
00354 return true;
00355 }
00356
00357 return false;
00358 }
00359
00360 bool DecoderHandler::next(void)
00361 {
00362 if (done())
00363 return false;
00364
00365 if (m_meta && m_meta->Format() == "cast")
00366 {
00367 m_playlist_pos = random() % m_playlist.size();
00368 }
00369 else
00370 {
00371 m_playlist_pos++;
00372 }
00373
00374 PlayListFileEntry *entry = m_playlist.get(m_playlist_pos);
00375
00376 QUrl url;
00377 if (QFileInfo(entry->File()).isAbsolute())
00378 url = QUrl::fromLocalFile(entry->File());
00379 else
00380 url.setUrl(entry->File());
00381
00382 LOG(VB_PLAYBACK, LOG_INFO, QString("Now playing '%1'").arg(url.toString()));
00383
00384 deleteIOFactory();
00385 createIOFactory(url);
00386
00387 if (! haveIOFactory())
00388 return false;
00389
00390 getIOFactory()->addListener(this);
00391 getIOFactory()->setUrl(url);
00392 getIOFactory()->setMeta(m_meta);
00393 getIOFactory()->start();
00394 m_state = ACTIVE;
00395
00396 return true;
00397 }
00398
00399 void DecoderHandler::stop(void)
00400 {
00401 LOG(VB_PLAYBACK, LOG_INFO, QString("DecoderHandler: Stopping decoder"));
00402
00403 if (m_decoder && m_decoder->isRunning())
00404 {
00405 m_decoder->lock();
00406 m_decoder->stop();
00407 m_decoder->unlock();
00408 }
00409
00410 if (m_decoder)
00411 {
00412 m_decoder->lock();
00413 m_decoder->cond()->wakeAll();
00414 m_decoder->unlock();
00415 }
00416
00417 if (m_decoder)
00418 {
00419 m_decoder->wait();
00420
00421 delete m_decoder;
00422 m_decoder = NULL;
00423 }
00424
00425 deleteIOFactory();
00426 doOperationStop();
00427
00428 m_state = STOPPED;
00429 }
00430
00431 void DecoderHandler::customEvent(QEvent *e)
00432 {
00433 if (class DecoderHandlerEvent *event = dynamic_cast<DecoderHandlerEvent*>(e))
00434 {
00435
00436 return dispatch(*event);
00437 }
00438 }
00439
00440 bool DecoderHandler::createPlaylist(const QUrl &url)
00441 {
00442 QString extension = QFileInfo(url.path()).suffix();
00443 LOG(VB_NETWORK, LOG_INFO,
00444 QString("File %1 has extension %2")
00445 .arg(QFileInfo(url.path()).fileName()).arg(extension));
00446
00447 if (extension == "pls" || extension == "m3u")
00448 {
00449 if (url.scheme() == "file" || QFileInfo(url.toString()).isAbsolute())
00450 return createPlaylistFromFile(url);
00451 else
00452 return createPlaylistFromRemoteUrl(url);
00453 }
00454
00455 return createPlaylistForSingleFile(url);
00456 }
00457
00458 bool DecoderHandler::createPlaylistForSingleFile(const QUrl &url)
00459 {
00460 PlayListFileEntry *entry = new PlayListFileEntry;
00461
00462 if (url.scheme() == "file" || QFileInfo(url.toString()).isAbsolute())
00463 entry->setFile(url.toLocalFile());
00464 else
00465 entry->setFile(url.toString());
00466
00467 m_playlist.add(entry);
00468
00469 return m_playlist.size() > 0;
00470 }
00471
00472 bool DecoderHandler::createPlaylistFromFile(const QUrl &url)
00473 {
00474 QFile f(QFileInfo(url.path()).absolutePath() + "/" + QFileInfo(url.path()).fileName());
00475 f.open(QIODevice::ReadOnly);
00476 QTextStream stream(&f);
00477
00478 QString extension = QFileInfo(url.path()).suffix().toLower();
00479
00480 if (PlayListFile::parse(&m_playlist, &stream, extension) <= 0)
00481 return false;
00482
00483 return m_playlist.size() > 0;
00484 }
00485
00486 bool DecoderHandler::createPlaylistFromRemoteUrl(const QUrl &url)
00487 {
00488 LOG(VB_NETWORK, LOG_INFO,
00489 QString("Retrieving playlist from '%1'").arg(url.toString()));
00490
00491 doOperationStart("Retrieving playlist");
00492
00493 QByteArray data;
00494
00495 if (!GetMythDownloadManager()->download(url.toString(), &data))
00496 {
00497 LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler:: Failed to download playlist from: %1").arg(url.toString()));
00498 doOperationStop();
00499 return false;
00500 }
00501
00502 doOperationStop();
00503
00504 QTextStream stream(&data, QIODevice::ReadOnly);
00505
00506 QString extension = QFileInfo(url.path()).suffix().toLower();
00507
00508 bool result = PlayListFile::parse(&m_playlist, &stream, extension) > 0;
00509
00510 return result;
00511 }
00512
00513 void DecoderHandler::doConnectDecoder(const QUrl &url, const QString &format)
00514 {
00515 if (m_decoder && !m_decoder->factory()->supports(format))
00516 {
00517 delete m_decoder;
00518 m_decoder = NULL;
00519 }
00520
00521 if (!m_decoder)
00522 {
00523 if ((m_decoder = Decoder::create(format, NULL, NULL, true)) == NULL)
00524 {
00525 doFailed(url, QString("No decoder for this format '%1'").arg(format));
00526 return;
00527 }
00528 }
00529
00530 m_decoder->setInput(getIOFactory()->takeInput());
00531 m_decoder->setFilename(url.toString());
00532
00533 DecoderHandlerEvent ev(DecoderHandlerEvent::Ready);
00534 dispatch(ev);
00535 }
00536
00537 void DecoderHandler::doFailed(const QUrl &url, const QString &message)
00538 {
00539 LOG(VB_NETWORK, LOG_ERR,
00540 QString("DecoderHandler: Unsupported file format: '%1' - %2")
00541 .arg(url.toString()).arg(message));
00542 DecoderHandlerEvent ev(DecoderHandlerEvent::Error, new QString(message));
00543 dispatch(ev);
00544 }
00545
00546 void DecoderHandler::doInfo(const QString &message)
00547 {
00548 DecoderHandlerEvent ev(DecoderHandlerEvent::Info, new QString(message));
00549 dispatch(ev);
00550 }
00551
00552 void DecoderHandler::doOperationStart(const QString &name)
00553 {
00554 m_op = true;
00555 DecoderHandlerEvent ev(DecoderHandlerEvent::OperationStart, new QString(name));
00556 dispatch(ev);
00557 }
00558
00559 void DecoderHandler::doOperationStop(void)
00560 {
00561 if (!m_op)
00562 return;
00563
00564 m_op = false;
00565 DecoderHandlerEvent ev(DecoderHandlerEvent::OperationStop);
00566 dispatch(ev);
00567 }
00568
00569 void DecoderHandler::createIOFactory(const QUrl &url)
00570 {
00571 if (haveIOFactory())
00572 deleteIOFactory();
00573
00574 if (url.scheme() == "myth")
00575 m_io_factory = new DecoderIOFactorySG(this);
00576 else if (m_meta && m_meta->Format() == "cast")
00577 m_io_factory = new DecoderIOFactoryShoutCast(this);
00578 else if (url.scheme() == "http")
00579 m_io_factory = new DecoderIOFactoryUrl(this);
00580 else
00581 m_io_factory = new DecoderIOFactoryFile(this);
00582 }
00583
00584 void DecoderHandler::deleteIOFactory(void)
00585 {
00586 if (!haveIOFactory())
00587 return;
00588
00589 if (m_state == ACTIVE)
00590 m_io_factory->stop();
00591
00592 m_io_factory->removeListener(this);
00593 m_io_factory->disconnect();
00594 m_io_factory->deleteLater();
00595 m_io_factory = NULL;
00596 }
00597
00598
00599
00600 qint64 MusicBuffer::read(char *data, qint64 max, bool doRemove)
00601 {
00602 QMutexLocker holder (&m_mutex);
00603 const char *buffer_data = m_buffer.data();
00604
00605 if (max > m_buffer.size())
00606 max = m_buffer.size();
00607
00608 memcpy(data, buffer_data, max);
00609
00610 if (doRemove)
00611 m_buffer.remove(0, max);
00612
00613 return max;
00614 }
00615
00616 qint64 MusicBuffer::read(QByteArray &data, qint64 max, bool doRemove)
00617 {
00618 QMutexLocker holder (&m_mutex);
00619 const char *buffer_data = m_buffer.data();
00620
00621 if (max > m_buffer.size())
00622 max = m_buffer.size();
00623
00624 data.append(buffer_data, max);
00625
00626 if (doRemove)
00627 m_buffer.remove(0, max);
00628
00629 return max;
00630 }
00631
00632 void MusicBuffer::write(const char *data, uint sz)
00633 {
00634 if (sz == 0)
00635 return;
00636
00637 QMutexLocker holder(&m_mutex);
00638 m_buffer.append(data, sz);
00639 }
00640
00641 void MusicBuffer::write(QByteArray &array)
00642 {
00643 if (array.size() == 0)
00644 return;
00645
00646 QMutexLocker holder(&m_mutex);
00647 m_buffer.append(array);
00648 }
00649
00650 void MusicBuffer::remove(int index, int len)
00651 {
00652 QMutexLocker holder(&m_mutex);
00653 m_buffer.remove(index, len);
00654 }
00655
00656
00657
00658 MusicIODevice::MusicIODevice(void)
00659 {
00660 m_buffer = new MusicBuffer;
00661 setOpenMode(ReadWrite);
00662 }
00663
00664 MusicIODevice::~MusicIODevice(void)
00665 {
00666 delete m_buffer;
00667 }
00668
00669 bool MusicIODevice::open(int)
00670 {
00671 return true;
00672 }
00673
00674 qint64 MusicIODevice::size(void) const
00675 {
00676 return m_buffer->readBufAvail();
00677 }
00678
00679 qint64 MusicIODevice::readData(char *data, qint64 maxlen)
00680 {
00681 qint64 res = m_buffer->read(data, maxlen);
00682 emit freeSpaceAvailable();
00683 return res;
00684 }
00685
00686 qint64 MusicIODevice::writeData(const char *data, qint64 sz)
00687 {
00688 m_buffer->write(data, sz);
00689 return sz;
00690 }
00691
00692 qint64 MusicIODevice::bytesAvailable(void) const
00693 {
00694 return m_buffer->readBufAvail();
00695 }
00696
00697 int MusicIODevice::getch(void)
00698 {
00699 assert(0);
00700 return -1;
00701 }
00702
00703 int MusicIODevice::putch(int)
00704 {
00705 assert(0);
00706 return -1;
00707 }
00708
00709 int MusicIODevice::ungetch(int)
00710 {
00711 assert(0);
00712 return -1;
00713 }
00714
00715
00716
00717 MusicSGIODevice::MusicSGIODevice(const QString &url)
00718 {
00719 m_remotefile = new RemoteFile(url);
00720 m_remotefile->Open();
00721
00722 setOpenMode(ReadWrite);
00723 }
00724
00725 MusicSGIODevice::~MusicSGIODevice(void)
00726 {
00727 m_remotefile->Close();
00728 delete m_remotefile;
00729 }
00730
00731 bool MusicSGIODevice::open(int)
00732 {
00733 return true;
00734 }
00735
00736 bool MusicSGIODevice::seek(qint64 pos)
00737 {
00738 long int newPos = -1;
00739
00740 if (m_remotefile)
00741 newPos = m_remotefile->Seek(pos, 0);
00742
00743 return (newPos == pos);
00744 }
00745
00746 qint64 MusicSGIODevice::size(void) const
00747 {
00748 return m_remotefile->GetFileSize();
00749 }
00750
00751 qint64 MusicSGIODevice::readData(char *data, qint64 maxlen)
00752 {
00753 qint64 res = m_remotefile->Read(data, maxlen);
00754 return res;
00755 }
00756
00757 qint64 MusicSGIODevice::writeData(const char *data, qint64 sz)
00758 {
00759 m_remotefile->Write(data, sz);
00760 return sz;
00761 }
00762
00763 qint64 MusicSGIODevice::bytesAvailable(void) const
00764 {
00765 return m_remotefile->GetFileSize();
00766 }
00767
00768 int MusicSGIODevice::getch(void)
00769 {
00770 assert(0);
00771 return -1;
00772 }
00773
00774 int MusicSGIODevice::putch(int)
00775 {
00776 assert(0);
00777 return -1;
00778 }
00779
00780 int MusicSGIODevice::ungetch(int)
00781 {
00782 assert(0);
00783 return -1;
00784 }