PageRenderTime 607ms CodeModel.GetById 100ms app.highlight 323ms RepoModel.GetById 144ms app.codeStats 1ms

/src/libtomahawk/network/BufferIoDevice.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 326 lines | 211 code | 82 blank | 33 comment | 14 complexity | 052b3a6b76c9caef03f359e68476b9aa MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  5 *   Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
  6 *
  7 *   Tomahawk is free software: you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation, either version 3 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   Tomahawk is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 19 */
 20
 21#include "BufferIoDevice_p.h"
 22
 23#include <QCoreApplication>
 24#include <QMutexLocker>
 25#include <QThread>
 26
 27#include "utils/Logger.h"
 28
 29// Msgs are framed, this is the size each msg we send containing audio data:
 30#define BLOCKSIZE 4096
 31
 32
 33BufferIODevice::BufferIODevice( unsigned int size, QObject* parent )
 34    : QIODevice( parent )
 35    , d_ptr( new BufferIODevicePrivate( this, size ) )
 36{
 37}
 38
 39
 40BufferIODevice::~BufferIODevice()
 41{
 42    delete d_ptr;
 43}
 44
 45
 46bool
 47BufferIODevice::open( OpenMode mode )
 48{
 49    Q_D( BufferIODevice );
 50    Q_UNUSED( mode );
 51    QMutexLocker lock( &d->mut );
 52
 53    qDebug() << Q_FUNC_INFO;
 54    QIODevice::open( QIODevice::ReadOnly | QIODevice::Unbuffered ); // FIXME?
 55    return true;
 56}
 57
 58
 59void
 60BufferIODevice::close()
 61{
 62    Q_D( BufferIODevice );
 63    QMutexLocker lock( &d->mut );
 64
 65    qDebug() << Q_FUNC_INFO;
 66    QIODevice::close();
 67}
 68
 69
 70bool
 71BufferIODevice::seek( qint64 pos )
 72{
 73    Q_D( BufferIODevice );
 74    qDebug() << Q_FUNC_INFO << pos << d->size;
 75
 76    if ( pos >= d->size )
 77        return false;
 78
 79    int block = blockForPos( pos );
 80    if ( isBlockEmpty( block ) )
 81        emit blockRequest( block );
 82
 83    d->pos = pos;
 84    qDebug() << "Finished seeking";
 85
 86    return true;
 87}
 88
 89
 90void
 91BufferIODevice::seeked( int block )
 92{
 93    Q_D( BufferIODevice );
 94    qDebug() << Q_FUNC_INFO << block << d->size;
 95}
 96
 97
 98void
 99BufferIODevice::inputComplete( const QString& errmsg )
100{
101    Q_D( BufferIODevice );
102    qDebug() << Q_FUNC_INFO;
103    setErrorString( errmsg );
104    d->size = d->received;
105    emit readChannelFinished();
106}
107
108
109bool
110BufferIODevice::isSequential() const
111{
112    return false;
113}
114
115
116void
117BufferIODevice::addData( int block, const QByteArray& ba )
118{
119    Q_D( BufferIODevice );
120    {
121        QMutexLocker lock( &d->mut );
122
123        while ( d->buffer.count() <= block )
124            d->buffer << QByteArray();
125
126        d->buffer.replace( block, ba );
127    }
128
129    // If this was the last block of the transfer, check if we need to fill up gaps
130    if ( block + 1 == maxBlocks() )
131    {
132        if ( nextEmptyBlock() >= 0 )
133        {
134            emit blockRequest( nextEmptyBlock() );
135        }
136    }
137
138    d->received += ba.count();
139    emit bytesWritten( ba.count() );
140    emit readyRead();
141}
142
143
144qint64
145BufferIODevice::bytesAvailable() const
146{
147    Q_D( const BufferIODevice );
148
149    return d->size - d->pos;
150}
151
152
153qint64
154BufferIODevice::readData( char* data, qint64 maxSize )
155{
156    Q_D( BufferIODevice );
157//    qDebug() << Q_FUNC_INFO << m_pos << maxSize << 1;
158
159    if ( atEnd() )
160        return 0;
161
162    QByteArray ba;
163    ba.append( getData( d->pos, maxSize ) );
164    d->pos += ba.count();
165
166//    qDebug() << Q_FUNC_INFO << maxSize << ba.count() << 2;
167    memcpy( data, ba.data(), ba.count() );
168
169    return ba.count();
170}
171
172
173qint64
174BufferIODevice::writeData( const char* data, qint64 maxSize )
175{
176    Q_UNUSED( data );
177    Q_UNUSED( maxSize );
178    // call addData instead
179    Q_ASSERT( false );
180    return 0;
181}
182
183
184qint64
185BufferIODevice::size() const
186{
187    Q_D( const BufferIODevice );
188    qDebug() << Q_FUNC_INFO << d->size;
189    return d->size;
190}
191
192
193bool
194BufferIODevice::atEnd() const
195{
196    Q_D( const BufferIODevice );
197//    qDebug() << Q_FUNC_INFO << ( m_size <= m_pos );
198    return ( d->size <= d->pos );
199}
200
201
202qint64
203BufferIODevice::pos() const
204{
205    Q_D( const BufferIODevice );
206    return d->pos;
207}
208
209
210void
211BufferIODevice::clear()
212{
213    Q_D( BufferIODevice );
214    QMutexLocker lock( &d->mut );
215
216    d->pos = 0;
217    d->buffer.clear();
218}
219
220
221QIODevice::OpenMode
222BufferIODevice::openMode() const
223{
224    return QIODevice::ReadOnly | QIODevice::Unbuffered;
225}
226
227
228unsigned int
229BufferIODevice::blockSize()
230{
231    return BLOCKSIZE;
232}
233
234
235int
236BufferIODevice::blockForPos( qint64 pos ) const
237{
238    // 0 / 4096 -> block 0
239    // 4095 / 4096 -> block 0
240    // 4096 / 4096 -> block 1
241
242    return pos / BLOCKSIZE;
243}
244
245
246int
247BufferIODevice::offsetForPos( qint64 pos ) const
248{
249    // 0 % 4096 -> offset 0
250    // 4095 % 4096 -> offset 4095
251    // 4096 % 4096 -> offset 0
252
253    return pos % BLOCKSIZE;
254}
255
256
257int
258BufferIODevice::nextEmptyBlock() const
259{
260    Q_D( const BufferIODevice );
261
262    int i = 0;
263    foreach( const QByteArray& ba, d->buffer )
264    {
265        if ( ba.isEmpty() )
266            return i;
267
268        i++;
269    }
270
271    if ( i == maxBlocks() )
272        return -1;
273
274    return i;
275}
276
277
278int
279BufferIODevice::maxBlocks() const
280{
281    Q_D( const BufferIODevice );
282
283    int i = d->size / BLOCKSIZE;
284
285    if ( ( d->size % BLOCKSIZE ) > 0 )
286        i++;
287
288    return i;
289}
290
291
292bool
293BufferIODevice::isBlockEmpty( int block ) const
294{
295    Q_D( const BufferIODevice );
296    if ( block >= d->buffer.count() )
297        return true;
298
299    return d->buffer.at( block ).isEmpty();
300}
301
302
303QByteArray
304BufferIODevice::getData( qint64 pos, qint64 size )
305{
306    Q_D( BufferIODevice );
307//    qDebug() << Q_FUNC_INFO << pos << size << 1;
308    QByteArray ba;
309    int block = blockForPos( pos );
310    int offset = offsetForPos( pos );
311
312    QMutexLocker lock( &d->mut );
313    while( ba.count() < size )
314    {
315        if ( block > maxBlocks() )
316            break;
317
318        if ( isBlockEmpty( block ) )
319            break;
320
321        ba.append( d->buffer.at( block++ ).mid( offset ) );
322    }
323
324//    qDebug() << Q_FUNC_INFO << pos << size << 2;
325    return ba.left( size );
326}