kioinputstream_impl.cpp

00001     /*
00002 
00003     Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009   
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 
00020     */
00021 
00022 /*
00023  * How does it work?
00024  * -----------------
00025  *
00026  * First the buffer has to be filled. When it reaches a defined size the outdata
00027  * stream has to start pulling packets. If the buffer reaches a size of zero the
00028  * stream has to stop. If the buffer gets to big the job has to be suspended
00029  * until the buffer is small enough again.
00030  */
00031 
00032 #include <kapplication.h>
00033 #include <kdebug.h>
00034 #include <kio/job.h>
00035 #include <kio/kmimetype.h>
00036 #include <kio/jobclasses.h>
00037 #include <qtimer.h>
00038 #include <qdatastream.h>
00039 #include "artsversion.h"
00040 #include "kioinputstream_impl.moc"
00041 
00042 using namespace Arts;
00043 
00044 const unsigned int KIOInputStream_impl::PACKET_COUNT = 10;
00045 
00046 KIOInputStream_impl::KIOInputStream_impl() : m_packetSize(2048)
00047 {
00048     m_job = 0;
00049     m_finished = false;
00050     m_firstBuffer = false;
00051     m_packetBuffer = 16;
00052     m_streamStarted = false;
00053     m_streamSuspended = false;
00054     m_streamPulled = false;
00055     m_size = 0;
00056 }
00057 
00058 KIOInputStream_impl::~KIOInputStream_impl()
00059 {
00060     if(m_job != 0)
00061         m_job->kill();
00062 }
00063 
00064 void KIOInputStream_impl::streamStart()
00065 {
00066     // prevent kill/reconnect
00067     if (m_streamStarted) {
00068         kdDebug( 400 ) << "not restarting stream!\n";
00069         if (m_job->isSuspended())
00070             m_job->resume();
00071         return;
00072     }
00073 
00074     kdDebug( 400 ) << "(re)starting stream\n";
00075 
00076     if(m_job != 0)
00077         m_job->kill();
00078     m_job = KIO::get(m_url, false, false);
00079 
00080     m_job->addMetaData("accept", "audio/x-mp3, video/mpeg, application/ogg");
00081     m_job->addMetaData("UserAgent", QString::fromLatin1("aRts/") + QString::fromLatin1(ARTS_VERSION));
00082 
00083     QObject::connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
00084              this, SLOT(slotData(KIO::Job *, const QByteArray &)));          
00085     QObject::connect(m_job, SIGNAL(result(KIO::Job *)),
00086              this, SLOT(slotResult(KIO::Job *)));            
00087     QObject::connect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)),
00088              this, SLOT(slotScanMimeType(KIO::Job *, const QString &)));
00089     QObject::connect(m_job, SIGNAL(totalSize( KIO::Job *, KIO::filesize_t)),
00090              this, SLOT(slotTotalSize(KIO::Job *, KIO::filesize_t)));
00091 
00092     m_streamStarted = true;
00093 }
00094 
00095 void KIOInputStream_impl::streamEnd()
00096 {
00097     kdDebug( 400 ) << "streamEnd()\n";
00098 
00099     if(m_job != 0)
00100     {
00101         QObject::disconnect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
00102                         this, SLOT(slotData(KIO::Job *, const QByteArray &)));
00103         QObject::disconnect(m_job, SIGNAL(result(KIO::Job *)),
00104                         this, SLOT(slotResult(KIO::Job *)));             
00105         QObject::disconnect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)),
00106                  this, SLOT(slotScanMimeType(KIO::Job *, const QString &)));
00107         QObject::disconnect(m_job, SIGNAL(totalSize( KIO::Job *, KIO::filesize_t)),
00108                  this, SLOT(slotTotalSize(KIO::Job *, KIO::filesize_t)));
00109 
00110         if ( m_streamPulled )
00111             outdata.endPull();
00112 
00113         m_job->kill();
00114         m_job = 0;
00115     }   
00116 
00117     m_streamStarted = false;
00118 }
00119 
00120 bool KIOInputStream_impl::openURL(const std::string& url)
00121 {
00122     m_url = KURL(url.c_str());
00123     m_size = 0;
00124     return true;
00125 }
00126 
00127 void KIOInputStream_impl::slotData(KIO::Job *, const QByteArray &data)
00128 {
00129     if(m_finished)
00130         m_finished = false;
00131 
00132     QDataStream dataStream(m_data, IO_WriteOnly | IO_Append);
00133     dataStream.writeRawBytes(data.data(), data.size());
00134     //kdDebug( 400 ) << "STREAMING: buffersize = " << m_data.size() << " bytes" << endl;
00135     
00136     processQueue();
00137 }
00138 
00139 void KIOInputStream_impl::slotResult(KIO::Job *job)
00140 {
00141     // jobs delete themselves after emitting their result
00142     m_finished = true;
00143     m_streamStarted = false;
00144     m_job = 0;
00145 
00146     if(job->error()) {
00147         // break out of the event loop in case of
00148         // connection error
00149             emit mimeTypeFound("application/x-zerosize");
00150         job->showErrorDialog();
00151     }
00152 }
00153 
00154 void KIOInputStream_impl::slotScanMimeType(KIO::Job *, const QString &mimetype)
00155 {
00156     kdDebug( 400 ) << "got mimetype: " << mimetype << endl;
00157     emit mimeTypeFound(mimetype);
00158 }
00159 
00160 void KIOInputStream_impl::slotTotalSize(KIO::Job *, KIO::filesize_t size)
00161 {
00162     m_size = size;
00163 }
00164 
00165 bool KIOInputStream_impl::eof()
00166 {
00167     return (m_finished && m_data.size() == 0);
00168 }
00169 
00170 bool KIOInputStream_impl::seekOk()
00171 {
00172     return false;
00173 }
00174 
00175 long KIOInputStream_impl::size()
00176 {
00177     return m_size ? m_size : m_data.size();
00178 }
00179 
00180 long KIOInputStream_impl::seek(long)
00181 {
00182     return -1;
00183 }
00184 
00185 void KIOInputStream_impl::processQueue()
00186 {
00187     if(m_job != 0)
00188     {
00189         if(m_data.size() > (m_packetBuffer * m_packetSize * 2) && !m_job->isSuspended())
00190         {
00191             kdDebug( 400 ) << "STREAMING: suspend job" << endl;
00192             m_job->suspend();
00193         }
00194         else if(m_data.size() < (m_packetBuffer * m_packetSize) && m_job->isSuspended())
00195         {
00196             kdDebug( 400 ) << "STREAMING: resume job" << endl;
00197             m_job->resume();
00198         }
00199     }
00200 
00201     if (!m_firstBuffer) {
00202         if(m_data.size() < (m_packetBuffer * m_packetSize * 2) ) {
00203             kdDebug( 400 ) << "STREAMING: Buffering in progress... (Needed bytes before it starts to play: " << ((m_packetBuffer * m_packetSize * 2) - m_data.size()) << ")" << endl;
00204             return;
00205         } else {
00206             m_firstBuffer = true;
00207             m_streamPulled = true;
00208             outdata.setPull(PACKET_COUNT, m_packetSize);
00209         } 
00210     }
00211 }
00212 
00213 void KIOInputStream_impl::request_outdata(DataPacket<mcopbyte> *packet)
00214 {
00215     processQueue();
00216     packet->size = std::min(m_packetSize, m_data.size());
00217     kdDebug( 400 ) << "STREAMING: Filling one DataPacket with " << packet->size << " bytes of the stream!" << endl;
00218 
00219     if (!m_finished) {
00220         if( (unsigned)packet->size < m_packetSize || ! m_firstBuffer) {
00221             m_firstBuffer = false;
00222             packet->size = 0;
00223             outdata.endPull();
00224         }
00225     }
00226     
00227     if (packet->size > 0)
00228     {
00229         memcpy(packet->contents, m_data.data(), packet->size);
00230         memmove(m_data.data(), m_data.data() + packet->size, m_data.size() - packet->size);
00231         m_data.resize(m_data.size() - packet->size);
00232     }
00233     packet->send();
00234 }
00235 
00236 REGISTER_IMPLEMENTATION(KIOInputStream_impl);
KDE Home | KDE Accessibility Home | Description of Access Keys