mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-19 12:21:52 +02:00
Buffer HTTP streams to make them seekable
This commit is contained in:
@@ -118,6 +118,8 @@ NetworkReply::networkLoadFinished()
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
emit finished( m_url );
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
@@ -22,64 +22,106 @@
|
||||
|
||||
#include "Qnr_IoDeviceStream.h"
|
||||
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QTimer>
|
||||
|
||||
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<QNetworkReply *>(_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();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -26,9 +26,11 @@
|
||||
#include "DllMacro.h"
|
||||
|
||||
#include <phonon/abstractmediastream.h>
|
||||
#include <QByteArray>
|
||||
|
||||
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
|
||||
|
Reference in New Issue
Block a user