/src/libtomahawk/network/BufferIoDevice.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 326 lines · 211 code · 82 blank · 33 comment · 15 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. #include "BufferIoDevice_p.h"
  21. #include <QCoreApplication>
  22. #include <QMutexLocker>
  23. #include <QThread>
  24. #include "utils/Logger.h"
  25. // Msgs are framed, this is the size each msg we send containing audio data:
  26. #define BLOCKSIZE 4096
  27. BufferIODevice::BufferIODevice( unsigned int size, QObject* parent )
  28. : QIODevice( parent )
  29. , d_ptr( new BufferIODevicePrivate( this, size ) )
  30. {
  31. }
  32. BufferIODevice::~BufferIODevice()
  33. {
  34. delete d_ptr;
  35. }
  36. bool
  37. BufferIODevice::open( OpenMode mode )
  38. {
  39. Q_D( BufferIODevice );
  40. Q_UNUSED( mode );
  41. QMutexLocker lock( &d->mut );
  42. qDebug() << Q_FUNC_INFO;
  43. QIODevice::open( QIODevice::ReadOnly | QIODevice::Unbuffered ); // FIXME?
  44. return true;
  45. }
  46. void
  47. BufferIODevice::close()
  48. {
  49. Q_D( BufferIODevice );
  50. QMutexLocker lock( &d->mut );
  51. qDebug() << Q_FUNC_INFO;
  52. QIODevice::close();
  53. }
  54. bool
  55. BufferIODevice::seek( qint64 pos )
  56. {
  57. Q_D( BufferIODevice );
  58. qDebug() << Q_FUNC_INFO << pos << d->size;
  59. if ( pos >= d->size )
  60. return false;
  61. int block = blockForPos( pos );
  62. if ( isBlockEmpty( block ) )
  63. emit blockRequest( block );
  64. d->pos = pos;
  65. qDebug() << "Finished seeking";
  66. return true;
  67. }
  68. void
  69. BufferIODevice::seeked( int block )
  70. {
  71. Q_D( BufferIODevice );
  72. qDebug() << Q_FUNC_INFO << block << d->size;
  73. }
  74. void
  75. BufferIODevice::inputComplete( const QString& errmsg )
  76. {
  77. Q_D( BufferIODevice );
  78. qDebug() << Q_FUNC_INFO;
  79. setErrorString( errmsg );
  80. d->size = d->received;
  81. emit readChannelFinished();
  82. }
  83. bool
  84. BufferIODevice::isSequential() const
  85. {
  86. return false;
  87. }
  88. void
  89. BufferIODevice::addData( int block, const QByteArray& ba )
  90. {
  91. Q_D( BufferIODevice );
  92. {
  93. QMutexLocker lock( &d->mut );
  94. while ( d->buffer.count() <= block )
  95. d->buffer << QByteArray();
  96. d->buffer.replace( block, ba );
  97. }
  98. // If this was the last block of the transfer, check if we need to fill up gaps
  99. if ( block + 1 == maxBlocks() )
  100. {
  101. if ( nextEmptyBlock() >= 0 )
  102. {
  103. emit blockRequest( nextEmptyBlock() );
  104. }
  105. }
  106. d->received += ba.count();
  107. emit bytesWritten( ba.count() );
  108. emit readyRead();
  109. }
  110. qint64
  111. BufferIODevice::bytesAvailable() const
  112. {
  113. Q_D( const BufferIODevice );
  114. return d->size - d->pos;
  115. }
  116. qint64
  117. BufferIODevice::readData( char* data, qint64 maxSize )
  118. {
  119. Q_D( BufferIODevice );
  120. // qDebug() << Q_FUNC_INFO << m_pos << maxSize << 1;
  121. if ( atEnd() )
  122. return 0;
  123. QByteArray ba;
  124. ba.append( getData( d->pos, maxSize ) );
  125. d->pos += ba.count();
  126. // qDebug() << Q_FUNC_INFO << maxSize << ba.count() << 2;
  127. memcpy( data, ba.data(), ba.count() );
  128. return ba.count();
  129. }
  130. qint64
  131. BufferIODevice::writeData( const char* data, qint64 maxSize )
  132. {
  133. Q_UNUSED( data );
  134. Q_UNUSED( maxSize );
  135. // call addData instead
  136. Q_ASSERT( false );
  137. return 0;
  138. }
  139. qint64
  140. BufferIODevice::size() const
  141. {
  142. Q_D( const BufferIODevice );
  143. qDebug() << Q_FUNC_INFO << d->size;
  144. return d->size;
  145. }
  146. bool
  147. BufferIODevice::atEnd() const
  148. {
  149. Q_D( const BufferIODevice );
  150. // qDebug() << Q_FUNC_INFO << ( m_size <= m_pos );
  151. return ( d->size <= d->pos );
  152. }
  153. qint64
  154. BufferIODevice::pos() const
  155. {
  156. Q_D( const BufferIODevice );
  157. return d->pos;
  158. }
  159. void
  160. BufferIODevice::clear()
  161. {
  162. Q_D( BufferIODevice );
  163. QMutexLocker lock( &d->mut );
  164. d->pos = 0;
  165. d->buffer.clear();
  166. }
  167. QIODevice::OpenMode
  168. BufferIODevice::openMode() const
  169. {
  170. return QIODevice::ReadOnly | QIODevice::Unbuffered;
  171. }
  172. unsigned int
  173. BufferIODevice::blockSize()
  174. {
  175. return BLOCKSIZE;
  176. }
  177. int
  178. BufferIODevice::blockForPos( qint64 pos ) const
  179. {
  180. // 0 / 4096 -> block 0
  181. // 4095 / 4096 -> block 0
  182. // 4096 / 4096 -> block 1
  183. return pos / BLOCKSIZE;
  184. }
  185. int
  186. BufferIODevice::offsetForPos( qint64 pos ) const
  187. {
  188. // 0 % 4096 -> offset 0
  189. // 4095 % 4096 -> offset 4095
  190. // 4096 % 4096 -> offset 0
  191. return pos % BLOCKSIZE;
  192. }
  193. int
  194. BufferIODevice::nextEmptyBlock() const
  195. {
  196. Q_D( const BufferIODevice );
  197. int i = 0;
  198. foreach( const QByteArray& ba, d->buffer )
  199. {
  200. if ( ba.isEmpty() )
  201. return i;
  202. i++;
  203. }
  204. if ( i == maxBlocks() )
  205. return -1;
  206. return i;
  207. }
  208. int
  209. BufferIODevice::maxBlocks() const
  210. {
  211. Q_D( const BufferIODevice );
  212. int i = d->size / BLOCKSIZE;
  213. if ( ( d->size % BLOCKSIZE ) > 0 )
  214. i++;
  215. return i;
  216. }
  217. bool
  218. BufferIODevice::isBlockEmpty( int block ) const
  219. {
  220. Q_D( const BufferIODevice );
  221. if ( block >= d->buffer.count() )
  222. return true;
  223. return d->buffer.at( block ).isEmpty();
  224. }
  225. QByteArray
  226. BufferIODevice::getData( qint64 pos, qint64 size )
  227. {
  228. Q_D( BufferIODevice );
  229. // qDebug() << Q_FUNC_INFO << pos << size << 1;
  230. QByteArray ba;
  231. int block = blockForPos( pos );
  232. int offset = offsetForPos( pos );
  233. QMutexLocker lock( &d->mut );
  234. while( ba.count() < size )
  235. {
  236. if ( block > maxBlocks() )
  237. break;
  238. if ( isBlockEmpty( block ) )
  239. break;
  240. ba.append( d->buffer.at( block++ ).mid( offset ) );
  241. }
  242. // qDebug() << Q_FUNC_INFO << pos << size << 2;
  243. return ba.left( size );
  244. }