From 03158c3bbcdfd47ecde4ed00f2464b4d3c92a508 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Sun, 1 Sep 2013 15:16:23 +0200 Subject: [PATCH] Buffer HTTP streams to make them seekable --- src/libtomahawk/utils/NetworkReply.cpp | 2 + src/libtomahawk/utils/Qnr_IoDeviceStream.cpp | 122 +++++++++++++------ src/libtomahawk/utils/Qnr_IoDeviceStream.h | 20 ++- 3 files changed, 98 insertions(+), 46 deletions(-) diff --git a/src/libtomahawk/utils/NetworkReply.cpp b/src/libtomahawk/utils/NetworkReply.cpp index bf5ae0005..25085d1f4 100644 --- a/src/libtomahawk/utils/NetworkReply.cpp +++ b/src/libtomahawk/utils/NetworkReply.cpp @@ -118,6 +118,8 @@ NetworkReply::networkLoadFinished() } } else + { emit finished( m_url ); emit finished(); + } } diff --git a/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp b/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp index b60ca3a57..8bb99eeca 100644 --- a/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp +++ b/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp @@ -22,64 +22,106 @@ #include "Qnr_IoDeviceStream.h" -#include +#include "utils/Logger.h" + +#include +#include using namespace Tomahawk; -QNR_IODeviceStream::QNR_IODeviceStream(QIODevice* ioDevice, QObject* parent) - : Phonon::AbstractMediaStream( parent ), - _ioDevice(ioDevice), - _networkReply(0) +// Feed Phonon in 1MiB blocks +#define BLOCK_SIZE 1048576 + +QNR_IODeviceStream::QNR_IODeviceStream( QNetworkReply* reply, QObject* parent ) + : Phonon::AbstractMediaStream( parent ) + , m_networkReply( reply ) + , m_pos( 0 ) + , m_timer( new QTimer( this ) ) { - _ioDevice->reset(); - if (!_ioDevice->isOpen()) { - _ioDevice->open(QIODevice::ReadOnly); + if ( !m_networkReply->isOpen() ) { + m_networkReply->open(QIODevice::ReadOnly); } - Q_ASSERT(ioDevice->isOpen()); - Q_ASSERT(ioDevice->isReadable()); -// streamSize = ioDevice->size(); -// streamSeekable = !ioDevice->isSequential(); -// - // Allow handling of QNetworkReplies WRT its isFinished() function.. - _networkReply = qobject_cast(_ioDevice); + tLog() << Q_FUNC_INFO; + Q_ASSERT( m_networkReply->isOpen() ); + Q_ASSERT( m_networkReply->isReadable() ); + + if ( m_networkReply->isFinished() ) + { + // All data is ready, read it! + m_data = m_networkReply->readAll(); + Q_ASSERT( m_networkReply->atEnd() ); + setStreamSeekable( true ); + setStreamSize( m_data.size() ); + tLog() << Q_FUNC_INFO << "Got data of size:" << m_data.size(); + } + else + { + Q_ASSERT( false ); + // TODO: Connect to finished() signal + } + + m_timer->setInterval( 0 ); + connect( m_timer, SIGNAL( timeout() ), SLOT( moreData() ) ); } QNR_IODeviceStream::~QNR_IODeviceStream() { + tLog() << Q_FUNC_INFO; } -void QNR_IODeviceStream::reset() + +void +QNR_IODeviceStream::enoughData() { - _ioDevice->reset(); - //resetDone(); + tLog() << Q_FUNC_INFO; + m_timer->stop(); } -void QNR_IODeviceStream::needData() + +void +QNR_IODeviceStream::needData() { - quint32 size = 4096; - const QByteArray data = _ioDevice->read(size); -// #ifdef __GNUC__ -// #warning TODO 4.5 - make sure we do not break anything without this, it is preventing IODs from working when they did not yet emit readyRead() -// #endif -// if (data.isEmpty() && !d->ioDevice->atEnd()) { -// error(Phonon::NormalError, d->ioDevice->errorString()); -// } - writeData(data); - if (_ioDevice->atEnd()) { - // If the IO device was identified as QNetworkReply also take its - // isFinished() into account, when triggering EOD. - if (!_networkReply || _networkReply->isFinished()) { - endOfData(); - } + tLog() << Q_FUNC_INFO; + m_timer->start(); + moreData(); +} + +void +QNR_IODeviceStream::reset() +{ + tLog() << Q_FUNC_INFO; + m_pos = 0; +} + + +void +QNR_IODeviceStream::seekStream( qint64 offset ) +{ + tLog() << Q_FUNC_INFO; + m_pos = offset; +} + +void +QNR_IODeviceStream::moreData() +{ + QByteArray data = m_data.mid( m_pos, BLOCK_SIZE ); + tLog() << Q_FUNC_INFO << data.size(); + m_pos += data.size(); + if (m_data.size() == 0 + // && m_networkReply->atEnd() + // && m_networkReply->isFinished() + ) + { + // We're done. + endOfData(); + m_timer->stop(); + } + else + { + writeData( data ); } -} - -void QNR_IODeviceStream::seekStream(qint64 offset) -{ - _ioDevice->seek(offset); - //seekStreamDone(); } diff --git a/src/libtomahawk/utils/Qnr_IoDeviceStream.h b/src/libtomahawk/utils/Qnr_IoDeviceStream.h index 1620916b3..ab8bcd6fa 100644 --- a/src/libtomahawk/utils/Qnr_IoDeviceStream.h +++ b/src/libtomahawk/utils/Qnr_IoDeviceStream.h @@ -26,9 +26,11 @@ #include "DllMacro.h" #include +#include class QNetworkReply; class QIODevice; +class QTimer; namespace Tomahawk { @@ -37,16 +39,22 @@ class DLLEXPORT QNR_IODeviceStream : public Phonon::AbstractMediaStream { Q_OBJECT public: - explicit QNR_IODeviceStream(QIODevice *ioDevice, QObject *parent = 0); + explicit QNR_IODeviceStream( QNetworkReply* reply, QObject *parent = 0 ); ~QNR_IODeviceStream(); - void reset(); - void needData(); - void seekStream(qint64); + virtual void enoughData(); + virtual void needData(); + virtual void reset(); + virtual void seekStream( qint64 offset ); + +private slots: + void moreData(); private: - QIODevice *_ioDevice; - QNetworkReply *_networkReply; + QByteArray m_data; + QNetworkReply *m_networkReply; + qint64 m_pos; + QTimer* m_timer; }; } // namespace Tomahawk