File indexing completed on 2024-05-12 04:51:02
0001 /* 0002 SPDX-FileCopyrightText: 2005-2008 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0004 SPDX-FileCopyrightText: 1998-2010 Sebastian Trueg <trueg@k3b.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "k3baudiotrackreader.h" 0010 #include "k3baudiodatasource.h" 0011 #include "k3baudiotrack.h" 0012 0013 #include <QList> 0014 #include <QMutex> 0015 #include <QMutexLocker> 0016 0017 namespace K3b { 0018 0019 namespace { 0020 typedef QList< QIODevice* > IODevices; 0021 } 0022 0023 class AudioTrackReader::Private 0024 { 0025 public: 0026 Private( AudioTrackReader& audioTrackReader, AudioTrack& t ); 0027 void slotSourceAdded( int position ); 0028 void slotSourceAboutToBeRemoved( int position ); 0029 0030 AudioTrackReader& q; 0031 AudioTrack& track; 0032 IODevices readers; 0033 int current; 0034 0035 // used to make sure that no seek and read operation occur in parallel 0036 QMutex mutex; 0037 }; 0038 0039 0040 AudioTrackReader::Private::Private( AudioTrackReader& audioTrackReader, AudioTrack& t ) 0041 : 0042 q( audioTrackReader ), 0043 track( t ), 0044 current( -1 ) 0045 { 0046 } 0047 0048 0049 void AudioTrackReader::Private::slotSourceAdded( int position ) 0050 { 0051 if( q.isOpen() ) { 0052 QMutexLocker locker( &mutex ); 0053 if( position >= 0 && position <= readers.size() ) { // No mistake here, "position" can have size() value 0054 if( AudioDataSource* source = track.getSource( position ) ) { 0055 readers.insert( position, source->createReader() ); 0056 readers.at( position )->open( q.openMode() ); 0057 if( position == current ) 0058 readers.at( position )->seek( 0 ); 0059 } 0060 } 0061 } 0062 } 0063 0064 0065 void AudioTrackReader::Private::slotSourceAboutToBeRemoved( int position ) 0066 { 0067 if( q.isOpen() ) { 0068 QMutexLocker locker( &mutex ); 0069 if( position >= 0 && position < readers.size() ) { 0070 if( position == current ) 0071 ++current; 0072 readers.removeAt( position ); 0073 } 0074 } 0075 } 0076 0077 0078 AudioTrackReader::AudioTrackReader( AudioTrack& track, QObject* parent ) 0079 : QIODevice( parent ), 0080 d( new Private( *this, track ) ) 0081 { 0082 connect( &track, SIGNAL(sourceAdded(int)), 0083 this, SLOT(slotSourceAdded(int)) ); 0084 connect( &track, SIGNAL(sourceAboutToBeRemoved(int)), 0085 this, SLOT(slotSourceAboutToBeRemoved(int)) ); 0086 connect( &track, SIGNAL(changed()), 0087 this, SLOT(slotTrackChanged()) ); 0088 } 0089 0090 0091 AudioTrackReader::~AudioTrackReader() 0092 { 0093 close(); 0094 d->current = -1; 0095 } 0096 0097 0098 const AudioTrack& AudioTrackReader::track() const 0099 { 0100 return d->track; 0101 } 0102 0103 0104 AudioTrack& AudioTrackReader::track() 0105 { 0106 return d->track; 0107 } 0108 0109 0110 bool AudioTrackReader::open( QIODevice::OpenMode mode ) 0111 { 0112 if( !mode.testFlag( QIODevice::WriteOnly ) && d->readers.empty() && d->track.numberSources() > 0 ) { 0113 0114 for( AudioDataSource* source = d->track.firstSource(); source != 0; source = source->next() ) { 0115 d->readers.push_back( source->createReader() ); 0116 if( !d->readers.back()->open( mode ) ) { 0117 d->readers.clear(); 0118 return false; 0119 } 0120 } 0121 0122 QIODevice::seek( 0 ); 0123 if( !d->readers.isEmpty() ) { 0124 d->current = 0; 0125 d->readers.at( d->current )->seek( 0 ); 0126 } 0127 0128 return QIODevice::open( mode ); 0129 } 0130 else { 0131 return false; 0132 } 0133 } 0134 0135 0136 void AudioTrackReader::close() 0137 { 0138 qDeleteAll( d->readers ); 0139 d->readers.clear(); 0140 d->current = -1; 0141 QIODevice::close(); 0142 } 0143 0144 0145 bool AudioTrackReader::isSequential() const 0146 { 0147 return false; 0148 } 0149 0150 0151 qint64 AudioTrackReader::size() const 0152 { 0153 return d->track.length().audioBytes(); 0154 } 0155 0156 0157 bool AudioTrackReader::seek( qint64 pos ) 0158 { 0159 QMutexLocker locker( &d->mutex ); 0160 0161 int next = 0; 0162 qint64 curPos = 0; 0163 0164 for( ; next < d->readers.size() && curPos + d->readers.at( next )->size() < pos; ++next ) { 0165 curPos += d->readers.at( next )->size(); 0166 } 0167 0168 if( next < d->readers.size() ) { 0169 d->current = next; 0170 d->readers.at( next )->seek( pos - curPos ); 0171 return QIODevice::seek( pos ); 0172 } 0173 else { 0174 return false; 0175 } 0176 } 0177 0178 0179 qint64 AudioTrackReader::writeData( const char* /*data*/, qint64 /*len*/ ) 0180 { 0181 return -1; 0182 } 0183 0184 0185 qint64 AudioTrackReader::readData( char* data, qint64 maxlen ) 0186 { 0187 QMutexLocker locker( &d->mutex ); 0188 0189 while( d->current >= 0 && d->current < d->readers.size() ) { 0190 qint64 readData = d->readers.at( d->current )->read( data, maxlen ); 0191 0192 if( readData >= 0 ) { 0193 return readData; 0194 } 0195 else { 0196 ++d->current; 0197 if( d->current >= 0 && d->current < d->readers.size() ) { 0198 d->readers.at( d->current )->seek( 0 ); 0199 } 0200 } 0201 } 0202 0203 return -1; 0204 } 0205 0206 0207 void AudioTrackReader::slotTrackChanged() 0208 { 0209 QMutexLocker locker( &d->mutex ); 0210 if( pos() >= size() && pos() > 0 ) { 0211 QIODevice::seek( size() - 1LL ); 0212 } 0213 } 0214 0215 } // namespace K3b 0216 0217 #include "moc_k3baudiotrackreader.cpp"