--------------Boundary-00=_81IIGUOW7DLTSHJYAWMU Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit Hi list, I've updated patch a little bit, after having talked to Stefan Westerfeld a little who explained the magic of synchronous data streams in arts to me. The result is that the patches to arts ( suspend()/resume() support ) are no longer necessary. So what's new in this version: * the kio_audiocd patch was sent for review but is now yet included, so I still include it. * the kaboodle patch got merged into CVS, so I no longer include it. * instead I have a patch for noatun so that it relies on the kplayobject factory finding out the correct mimetype and providing the correct playobject. You can now listen to Ogg Vorbis streams with noatun, too. * little tweaks to the buffering logic of kioinputstream, making it look a little simpler and also work a little better. * changed the DecoderBaseObject so that it no longer relies on suspend()/resume() but makes use of the flow control that's build into arts synchronous data streams. The solution is a little ugly because it introduces yet another queue to just convert beween different data representations. However, it's quite cost efficient because it only stores pointers to DataPackets. I use a std::queue, which will hopefully exist on other systems, too. Efficiency is an issue, though. Data is copied multiple times on its' way from the IO-Job into the Playobject and into mpeglib - for now I don't care, it doesn't matter for low bitrate stuff, but for video streaming there are quite some improvements to be made. KNOWN BUGS * if you kill kaboodle or noatun with Ctrl-C, the IO-Job is not terminated and the slave continues to download the stream from the server. But where is the data going? And how to make sure the IO-Job is killed? help! * the crash-on-every-other-ogg-vorbis-stream bug is back. In fact I think it was never really fixed (as Martin Vogt already suspected). help! have fun, Matze --------------Boundary-00=_81IIGUOW7DLTSHJYAWMU Content-Type: text/x-diff; charset="iso-8859-1"; name="kio_audiocd.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kio_audiocd.patch" Index: audiocd.cpp =================================================================== RCS file: /home/kde/kdebase/kioslave/audiocd/audiocd.cpp,v retrieving revision 1.44 diff -u -3 -p -r1.44 audiocd.cpp --- audiocd.cpp 2002/02/28 16:34:40 1.44 +++ audiocd.cpp 2002/03/05 17:57:52 @@ -755,24 +755,30 @@ AudioCDProtocol::get(const KURL & url) #ifdef HAVE_LAME if ( initLameLib() == true ){ - if (filetype == "mp3") + if (filetype == "mp3") { totalSize((time_secs * d->bitrate * 1000)/8); + mimeType("audio/x-mp3"); + } }; #endif #ifdef HAVE_VORBIS if (filetype == "ogg") { totalSize((time_secs * d->vorbis_bitrate)/8); + mimeType("audio/x-ogg"); } #endif if (filetype == "wav") { totalSize(44 + totalByteCount); // Include RIFF header length. writeHeader(totalByteCount); // Write RIFF header. + mimeType("audio/x-wav"); } - if (filetype == "cda") + if (filetype == "cda") { totalSize(totalByteCount); // CDA is raw interleaved PCM Data with SampleRate 44100 and 16 Bit res. + mimeType("audio/x-cda"); + } paranoiaRead(drive, firstSector, lastSector, filetype); --------------Boundary-00=_81IIGUOW7DLTSHJYAWMU Content-Type: text/x-diff; charset="iso-8859-1"; name="kplayobject.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kplayobject.patch" ? kde/kplayobject-mimetype.patch Index: kde/kioinputstream_impl.cpp =================================================================== RCS file: /home/kde/kdelibs/arts/kde/kioinputstream_impl.cpp,v retrieving revision 1.23 diff -u -3 -p -r1.23 kioinputstream_impl.cpp --- kde/kioinputstream_impl.cpp 2002/01/30 16:20:29 1.23 +++ kde/kioinputstream_impl.cpp 2002/03/05 17:27:59 @@ -49,7 +49,9 @@ KIOInputStream_impl::KIOInputStream_impl m_data = 0; m_finished = false; m_firstBuffer = false; - m_packetBuffer = 20; + m_packetBuffer = 16; + m_streamStarted = false; + m_streamSuspended = false; } KIOInputStream_impl::~KIOInputStream_impl() @@ -60,32 +62,51 @@ KIOInputStream_impl::~KIOInputStream_imp void KIOInputStream_impl::streamStart() { + // prevent kill/reconnect + if (m_streamStarted) { + kdDebug() << "not restarting stream!\n"; + if (m_job->isSuspended()) + m_job->resume(); + return; + } + + kdDebug() << "(re)starting stream\n"; + if(m_job != 0) m_job->kill(); m_job = KIO::get(m_url, false, false); - m_job->addMetaData("accept", "audio/x-mp3"); + m_job->addMetaData("accept", "audio/x-mp3, video/mpeg"); m_job->addMetaData("UserAgent", QString::fromLatin1("aRts/") + QString::fromLatin1(ARTS_VERSION)); QObject::connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &))); QObject::connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *))); + QObject::connect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)), + this, SLOT(slotScanMimeType(KIO::Job *, const QString &))); + + m_streamStarted = true; } void KIOInputStream_impl::streamEnd() { + kdDebug() << "streamEnd()\n"; + if(m_job != 0) { QObject::disconnect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &))); QObject::disconnect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *))); + QObject::disconnect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)), + this, SLOT(slotScanMimeType(KIO::Job *, const QString &))); m_job->kill(); m_job = 0; } outdata.endPull(); + m_streamStarted = false; } bool KIOInputStream_impl::openURL(const std::string& url) @@ -110,12 +131,23 @@ void KIOInputStream_impl::slotResult(KIO { // jobs delete themselves after emitting their result m_finished = true; + m_streamStarted = false; m_job = 0; - if(job->error()) - job->showErrorDialog(); + if(job->error()) { + // break out of the event loop in case of + // connection error + emit mimeTypeFound("application/x-zerosize"); + job->showErrorDialog(); + } } +void KIOInputStream_impl::slotScanMimeType(KIO::Job *, const QString &mimetype) +{ + kdDebug() << "got mimetype: " << mimetype << endl; + emit mimeTypeFound(mimetype); +} + bool KIOInputStream_impl::eof() { return (m_finished && m_data.size() == 0); @@ -143,24 +175,23 @@ void KIOInputStream_impl::processQueue() if(m_data.size() > (m_packetBuffer * m_packetSize * 2) && !m_job->isSuspended()) { kdDebug() << "STREAMING: suspend job" << endl; - m_job->suspend(); + m_job->suspend(); } else if(m_data.size() < (m_packetBuffer * m_packetSize) && m_job->isSuspended()) { kdDebug() << "STREAMING: resume job" << endl; - m_job->resume(); + m_job->resume(); } } - if(m_data.size() < (m_packetBuffer * m_packetSize) && !m_firstBuffer) - { - kdDebug() << "STREAMING: Buffering in progress... (Needed bytes before it starts to play: " << ((m_packetBuffer * m_packetSize) - m_data.size()) << ")" << endl; - return; - } - else if( !m_firstBuffer ) - { - m_firstBuffer = true; - outdata.setPull(PACKET_COUNT, m_packetSize); + if (!m_firstBuffer) { + if(m_data.size() < (m_packetBuffer * m_packetSize * 2) ) { + kdDebug() << "STREAMING: Buffering in progress... (Needed bytes before it starts to play: " << ((m_packetBuffer * m_packetSize) - m_data.size()) << ")" << endl; + return; + } else { + m_firstBuffer = true; + outdata.setPull(PACKET_COUNT, m_packetSize); + } } } @@ -170,12 +201,15 @@ void KIOInputStream_impl::request_outdat packet->size = std::min(m_packetSize, m_data.size()); //kdDebug() << "STREAMING: Filling one DataPacket with " << packet->size << " bytes of the stream!" << endl; - if((unsigned)packet->size < m_packetSize || ! m_firstBuffer) - { - m_firstBuffer = false; - packet->size = 0; + if (!m_finished) { + if( (unsigned)packet->size < m_packetSize || ! m_firstBuffer) { + m_firstBuffer = false; + packet->size = 0; + outdata.endPull(); + } } - else + + if (packet->size > 0) { memcpy(packet->contents, m_data.data(), packet->size); memmove(m_data.data(), m_data.data() + packet->size, m_data.size() - packet->size); Index: kde/kioinputstream_impl.h =================================================================== RCS file: /home/kde/kdelibs/arts/kde/kioinputstream_impl.h,v retrieving revision 1.16 diff -u -3 -p -r1.16 kioinputstream_impl.h --- kde/kioinputstream_impl.h 2002/01/30 16:20:30 1.16 +++ kde/kioinputstream_impl.h 2002/03/05 17:27:59 @@ -54,10 +54,14 @@ public: void bufferPackets(long i) { m_packetBuffer = i; } long packetSize() { return m_packetSize; } + +signals: + void mimeTypeFound(const QString & mimetype); private slots: void slotData(KIO::Job *, const QByteArray &); void slotResult(KIO::Job *); + void slotScanMimeType(KIO::Job *, const QString &mimetype); private: KURL m_url; @@ -65,6 +69,8 @@ private: QByteArray m_data; bool m_finished; bool m_firstBuffer; + bool m_streamStarted; + bool m_streamSuspended; unsigned int m_packetBuffer; const unsigned int m_packetSize; @@ -73,3 +79,5 @@ private: }; }; + + Index: kde/kplayobjectfactory.cc =================================================================== RCS file: /home/kde/kdelibs/arts/kde/kplayobjectfactory.cc,v retrieving revision 1.16 diff -u -3 -p -r1.16 kplayobjectfactory.cc --- kde/kplayobjectfactory.cc 2001/10/29 20:57:36 1.16 +++ kde/kplayobjectfactory.cc 2002/03/05 17:28:00 @@ -23,9 +23,14 @@ #include "kplayobject.h" #include "artskde.h" #include "kplayobjectfactory.h" +#include "kplayobjectfactory.moc" +#include "kioinputstream_impl.h" #include +#include +#include + using namespace std; KPlayObjectFactory::KPlayObjectFactory(Arts::SoundServerV2 server) @@ -41,14 +46,75 @@ KPlayObjectFactory::~KPlayObjectFactory( KPlayObject *KPlayObjectFactory::createPlayObject(const KURL& url, bool createBUS) { + + // no need to go any further, and I hate deep indentation + if (m_server.isNull()) + return new KPlayObject(); + + // check if streaming is allowed or the URL is a local file + if (m_allowStreaming && !url.isLocalFile()) + { + // This is the RightWay(tm) according to stw + Arts::KIOInputStream_impl* instream_impl = new Arts::KIOInputStream_impl(); + Arts::KIOInputStream instream = Arts::KIOInputStream::_from_base(instream_impl); + + // signal will be called once the ioslave knows the mime-type of the stream + QObject::connect(instream_impl, SIGNAL(mimeTypeFound(const QString &)), + this, SLOT(slotMimeType(const QString &))); + + // GO! + instream.openURL(url.url().latin1()); + instream.streamStart(); + + m_eventLoopEntered = true; + // FIXME: need to handle timeouts? + // this is UGLY, but I cannot do anything else without changing the interface + // the application blocks here, and restarts once slotMimeType() is called. + kapp->enter_loop(); + + // wb :D + // some error occoured + if (m_mimeType == "application/x-zerosize") + return new KPlayObject(); + + // ok, now we know the mimetype of the stream + m_stream = true; + return new KPlayObject(m_server.createPlayObjectForStream(instream, + string(m_mimeType.latin1()), + createBUS), true); + } + kdDebug() << "stream is local file: " << url.url() << endl; + + // usual stuff if we have a local file KMimeType::Ptr mimetype = KMimeType::findByURL(url); - return createPlayObject(url, mimetype->name(), createBUS); + return new KPlayObject(m_server.createPlayObjectForURL(string(QFile::encodeName(url.path())), + string(mimetype->name().latin1()), + createBUS), + false); +} + +void KPlayObjectFactory::slotMimeType(const QString& mimetype) +{ + + kdDebug() << "slotMimeType called: " << mimetype << endl; + + if ( mimetype == "application/octet-stream" ) + m_mimeType = "audio/x-mp3"; + else + m_mimeType = mimetype; + + if (m_eventLoopEntered) { + m_eventLoopEntered = false; + kapp->exit_loop(); + } } KPlayObject *KPlayObjectFactory::createPlayObject(const KURL& url, const QString &mimetype, bool createBUS) { if(!m_server.isNull()) { + kdDebug() << "createPlayObject: mimetype is " << mimetype << endl; + if(mimetype == "application/octet-stream" && m_allowStreaming) { Arts::KIOInputStream instream; @@ -58,6 +124,15 @@ KPlayObject *KPlayObjectFactory::createP // TODO: what else than hardcoding audio/x-mp3 ? return new KPlayObject(m_server.createPlayObjectForStream(instream, string("audio/x-mp3"), createBUS), true); + } + else if(mimetype == "video/mpeg" && m_allowStreaming) + { + Arts::KIOInputStream instream; + instream.openURL(url.url().latin1()); + + m_stream = true; + + return new KPlayObject(m_server.createPlayObjectForStream(instream, string("video/mpeg"), createBUS), true); } else return new KPlayObject(m_server.createPlayObjectForURL(string(QFile::encodeName(url.path())), string(mimetype.latin1()), createBUS), false); Index: kde/kplayobjectfactory.h =================================================================== RCS file: /home/kde/kdelibs/arts/kde/kplayobjectfactory.h,v retrieving revision 1.9 diff -u -3 -p -r1.9 kplayobjectfactory.h --- kde/kplayobjectfactory.h 2001/10/29 20:57:36 1.9 +++ kde/kplayobjectfactory.h 2002/03/05 17:28:00 @@ -23,11 +23,13 @@ #define KPLAYOBJECTFACTORY_H #include +#include #include "soundserver.h" #include "kplayobject.h" -class KPlayObjectFactory +class KPlayObjectFactory : public QObject { +Q_OBJECT public: KPlayObjectFactory(Arts::SoundServerV2 server); ~KPlayObjectFactory(); @@ -39,11 +41,16 @@ public: bool allowStreaming() { return m_allowStreaming; } bool isAStream() { return m_stream; } - + +private slots: + void slotMimeType(const QString &mimetype); + private: Arts::SoundServerV2 m_server; bool m_allowStreaming; bool m_stream; + bool m_eventLoopEntered; + QString m_mimeType; }; #endif --------------Boundary-00=_81IIGUOW7DLTSHJYAWMU Content-Type: text/x-diff; charset="iso-8859-1"; name="mpeglib-bis.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="mpeglib-bis.patch" ? example/splay/mp3framing Index: lib/input/bufferInputStream.cpp =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib/lib/input/bufferInputStream.cpp,v retrieving revision 1.3 diff -u -3 -p -r1.3 bufferInputStream.cpp --- lib/input/bufferInputStream.cpp 2000/09/13 02:18:26 1.3 +++ lib/input/bufferInputStream.cpp 2002/03/05 17:30:37 @@ -108,11 +108,13 @@ int BufferInputStream::write(char* ptr,i int canWrite=n; char* writePtr; - lockBuffer(); - long key; - key=bytePos+fillgrade; - InputStream::insertTimeStamp(stamp,key,len); - unlockBuffer(); + if (stamp) { + lockBuffer(); + long key; + key=bytePos+fillgrade; + InputStream::insertTimeStamp(stamp,key,len); + unlockBuffer(); + } // if eof is set we do not insert any more data // we do not call eof() !!! while((leof==false) && (n > 0)) { @@ -146,11 +148,13 @@ int BufferInputStream::write(InputStream int didWrite; char* writePtr; - lockBuffer(); - long key; - key=bytePos+fillgrade; - InputStream::insertTimeStamp(stamp,key,len); - unlockBuffer(); + if (stamp) { + lockBuffer(); + long key; + key=bytePos+fillgrade; + InputStream::insertTimeStamp(stamp,key,len); + unlockBuffer(); + } // if eof is set we do not insert any more data // we do not call eof() !!! while((leof==false) && (n > 0)) { --------------Boundary-00=_81IIGUOW7DLTSHJYAWMU Content-Type: text/x-diff; charset="iso-8859-1"; name="mpeglib_artsplug-streaming.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="mpeglib_artsplug-streaming.patch" Index: MP3PlayObject.mcopclass =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/MP3PlayObject.mcopclass,v retrieving revision 1.5 diff -u -3 -p -r1.5 MP3PlayObject.mcopclass --- MP3PlayObject.mcopclass 2002/02/21 16:54:55 1.5 +++ MP3PlayObject.mcopclass 2002/03/05 17:33:04 @@ -1,4 +1,4 @@ -Interface=MP3PlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object +Interface=MP3PlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object Author="Martin Vogt " URL="http://mpeglib.sourceforge.net" Extension=mp3,mp1,mp2 Index: MPGPlayObject.mcopclass =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/MPGPlayObject.mcopclass,v retrieving revision 1.6 diff -u -3 -p -r1.6 MPGPlayObject.mcopclass --- MPGPlayObject.mcopclass 2002/02/21 16:54:55 1.6 +++ MPGPlayObject.mcopclass 2002/03/05 17:33:04 @@ -1,4 +1,4 @@ -Interface=MPGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object +Interface=MPGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object Author="Martin Vogt " URL="http://mpeglib.sourceforge.net" Extension=mpg,dat,mpeg Index: OGGPlayObject.mcopclass =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/OGGPlayObject.mcopclass,v retrieving revision 1.6 diff -u -3 -p -r1.6 OGGPlayObject.mcopclass --- OGGPlayObject.mcopclass 2002/02/21 16:54:55 1.6 +++ OGGPlayObject.mcopclass 2002/03/05 17:33:04 @@ -1,4 +1,4 @@ -Interface=OGGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object +Interface=OGGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object Author="Martin Vogt " URL="http://mpeglib.sourceforge.net" Extension=ogg Index: WAVPlayObject.mcopclass =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/WAVPlayObject.mcopclass,v retrieving revision 1.6 diff -u -3 -p -r1.6 WAVPlayObject.mcopclass --- WAVPlayObject.mcopclass 2002/02/25 13:25:57 1.6 +++ WAVPlayObject.mcopclass 2002/03/05 17:33:04 @@ -1,4 +1,4 @@ -Interface=WAVPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object +Interface=WAVPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object Author="Martin Vogt " URL="http://mpeglib.sourceforge.net" Extension=wav,au Index: decoderBaseObject.idl =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/decoderBaseObject.idl,v retrieving revision 1.8 diff -u -3 -p -r1.8 decoderBaseObject.idl --- decoderBaseObject.idl 2002/03/01 22:10:12 1.8 +++ decoderBaseObject.idl 2002/03/05 17:33:04 @@ -4,10 +4,12 @@ /* the interfaces below are not kept binary compatible */ interface DecoderBaseObject : - Arts::PlayObject, + Arts::StreamPlayObject, Arts::SynthModule, Arts::PitchablePlayObject { + + async in byte stream indata; /** * blocking flag - defaults to false - when set to true, mpeglib will not * try to minimize latencies by generating answers (i.e. empty blocks) Index: decoderBaseObject_impl.cpp =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/decoderBaseObject_impl.cpp,v retrieving revision 1.23 diff -u -3 -p -r1.23 decoderBaseObject_impl.cpp --- decoderBaseObject_impl.cpp 2001/08/08 12:05:07 1.23 +++ decoderBaseObject_impl.cpp 2002/03/05 17:33:05 @@ -10,9 +10,13 @@ */ +#include + +#include + #include "decoderBaseObject_impl.h" #include "../mpeglib/lib/decoder/decoderPlugin.h" -#include "../mpeglib/lib/decoder/splayPlugin.h" +//#include "../mpeglib/lib/frame/frameQueue.h" #include "debug.h" // define this to run the playobject without the @@ -29,19 +33,22 @@ DecoderBaseObject_impl::DecoderBaseObjec flpos=0.0; _blocking = false; + #ifdef _STRIP_ZERO outputStream=NULL; #else - outputStream=new ArtsOutputStream(NULL); + m_outputStream=new ArtsOutputStream(NULL); arts_debug("outputStream created"); decoderPlugin=NULL; #endif startTime=0.0; - inputStream=NULL; + m_inputStream=NULL; setStreamState(_THREADSTATE_INIT); _state=posIdle; instance=instanceCnt; instanceCnt++; + + m_packetQueue = new std::queue*>; } DecoderBaseObject_impl::~DecoderBaseObject_impl() { @@ -53,11 +60,16 @@ DecoderBaseObject_impl::~DecoderBaseObje delete decoderPlugin; decoderPlugin=NULL; } - if (outputStream != NULL) { + if (m_outputStream != NULL) { arts_debug("delete outputStream"); - delete outputStream; - outputStream=NULL; + delete m_outputStream; + m_outputStream=NULL; } + + if (m_streaming) + m_artsInputStream.streamEnd(); + + delete m_packetQueue; } @@ -74,10 +86,12 @@ DecoderPlugin* DecoderBaseObject_impl::c bool DecoderBaseObject_impl::loadMedia(const string &filename) { + arts_debug("loadMedia"); int back=true; + m_streaming = false; - if ( inputStream != NULL ) { + if ( m_inputStream != NULL ) { arts_fatal("remove resources first with a call to: halt()"); } if (decoderPlugin == NULL) { @@ -99,26 +113,95 @@ bool DecoderBaseObject_impl::loadMedia(c return true; #endif - inputStream=createInputStream(filename.c_str()); + m_inputStream=createInputStream(filename.c_str()); // the plugin does not open the stream! // we do it. - back=inputStream->open((char*)filename.c_str()); + back=m_inputStream->open((char*)filename.c_str()); setStreamState(_THREADSTATE_OPENED); // we are still in posIdle here - outputStream->audioOpen(); + m_outputStream->audioOpen(); // watch the order! - decoderPlugin->setOutputPlugin(outputStream); - decoderPlugin->setInputPlugin(inputStream); + decoderPlugin->setOutputPlugin(m_outputStream); + decoderPlugin->setInputPlugin(m_inputStream); - return back; } +#define INPUT_BUFFER_SIZE 32768 + +bool DecoderBaseObject_impl::streamMedia(Arts::InputStream instream) { + arts_debug("DecoderBaseObject_impl::streamMedia -s"); + + bool back = true; + + if (m_inputStream != NULL) { + arts_fatal("resource in use, call halt() first"); + } + if (decoderPlugin == NULL) { + decoderPlugin = createPlugin(); + if (doFloat()) + decoderPlugin->config("dofloat", 0, 0); + // streaming, don't know the length + decoderPlugin->config("-c", 0, 0); + } + + flpos = 0.0; + startTime = 0.0; + m_streaming = true; + lastAudioBufferSize = -1; + m_artsInputStream = instream; + m_inputStream = new BufferInputStream(INPUT_BUFFER_SIZE, 4096, (char*)"InputStream"); + m_inputStream->open((char*)"InputStream"); + + // connect the stream now + StreamPlayObject self = StreamPlayObject::_from_base(_copy()); + connect(m_artsInputStream, "outdata", self); + + setStreamState(_THREADSTATE_OPENED); + + m_outputStream->audioOpen(); + + decoderPlugin->setOutputPlugin(m_outputStream); + decoderPlugin->setInputPlugin(m_inputStream); + + arts_debug("DecoderBaseObject_impl::streamMedia -e"); + + return back; +} + +void DecoderBaseObject_impl::process_indata(DataPacket *inpacket) { + + m_packetQueue->push(inpacket); + processQueue(); +} + +void DecoderBaseObject_impl::processQueue() { + + // early exit if no packets in the queue + if (m_packetQueue->empty()) + return; + + // see how much space we have in the stream + BufferInputStream* stream = (BufferInputStream*)m_inputStream; + + int length = stream->getByteLength(); + int freeSpace = INPUT_BUFFER_SIZE - length; + + DataPacket *inpacket; + inpacket = m_packetQueue->front(); + + if (freeSpace >= inpacket->size) { + stream->write((char*)inpacket->contents, inpacket->size, 0); + m_packetQueue->pop(); + inpacket->processed(); + } +} + string DecoderBaseObject_impl::description() { arts_debug("description"); string back; @@ -141,7 +224,7 @@ poTime DecoderBaseObject_impl::currentTi #ifdef _STRIP_ZERO return time; #endif - AudioTime* audioTime=outputStream->getAudioTime(); + AudioTime* audioTime=m_outputStream->getAudioTime(); float currentTime=audioTime->getTime()+(float)startTime; time.seconds=(long)(currentTime); time.ms=(long) (1000.0*(currentTime-(float)time.seconds)); @@ -190,10 +273,10 @@ poState DecoderBaseObject_impl::state() void DecoderBaseObject_impl::play() { arts_debug("play: %d", (int)streamState); if (streamState == _THREADSTATE_OPENED) { - decoderPlugin->play(); + decoderPlugin->play(); } else { - Command cmd(_COMMAND_PLAY); - decoderPlugin->insertAsyncCommand(&cmd); + Command cmd(_COMMAND_PLAY); + decoderPlugin->insertAsyncCommand(&cmd); } setStreamState(_THREADSTATE_PLAYING); _state = posPlaying; @@ -214,11 +297,11 @@ void DecoderBaseObject_impl::seek(const // if the thread blocks on the artsOutputstream: kick him out // the next command will the the seek command - outputStream->audioClose(); + m_outputStream->audioClose(); // thread blocking allowed - outputStream->audioOpen(); + m_outputStream->audioOpen(); arts_debug("************ reopen"); // now set a new startTime startTime=sec; @@ -255,13 +338,14 @@ void DecoderBaseObject_impl::streamInit( void DecoderBaseObject_impl::streamStart() { + arts_debug("DecoderBaseObject_impl::streamStart"); } int DecoderBaseObject_impl::fillArts(unsigned long samples, float* left , float* right) { unsigned long haveSamples = 0; - AudioTime* audioTime=outputStream->getAudioTime(); + AudioTime* audioTime=m_outputStream->getAudioTime(); int wav_samplingRate=audioTime->getSpeed(); int wav_sampleWidth=audioTime->getSampleSize(); int wav_channelCount=audioTime->getStereo()+1; @@ -269,7 +353,10 @@ int DecoderBaseObject_impl::fillArts(uns if(doFloat()) wav_sampleWidth = sizeof(float)*8; // here seems to be an error, I have clicks sometimes in the stream - int byteMultiplikator=(wav_sampleWidth/8)*wav_channelCount; + //int byteMultiplikator=(wav_sampleWidth/8)*wav_channelCount; + + // maybe first multiply, then divide? + int byteMultiplikator = wav_channelCount * wav_sampleWidth / 8; char* buffer; int hasBytes = 0; @@ -277,7 +364,7 @@ int DecoderBaseObject_impl::fillArts(uns int bufferSize=getBufferSize(); if (bufferSize != lastAudioBufferSize) { lastAudioBufferSize=bufferSize; - outputStream->setAudioBufferSize(bufferSize); + m_outputStream->setAudioBufferSize(bufferSize); } /* difference between the sampling rates in percent */ @@ -291,7 +378,7 @@ int DecoderBaseObject_impl::fillArts(uns */ if(_state == posPlaying && doFloat() && diff < 0.0005) { wantBytes = sizeof(float) * wav_channelCount * samples; - hasBytes = outputStream->read(&buffer,wantBytes); + hasBytes = m_outputStream->read(&buffer,wantBytes); float *flptr = (float *)buffer; if(wav_channelCount == 1) @@ -311,7 +398,7 @@ int DecoderBaseObject_impl::fillArts(uns haveSamples++; } } - outputStream->forwardReadPtr(haveSamples*sizeof(float)*wav_channelCount); + m_outputStream->forwardReadPtr(haveSamples*sizeof(float)*wav_channelCount); } else if(_state == posPlaying) { // @@ -330,7 +417,7 @@ int DecoderBaseObject_impl::fillArts(uns // convert that into bytes and try to read that many bytes wantBytes=(int) (wantWavSamples*byteMultiplikator); - hasBytes=outputStream->read(&buffer,wantBytes); + hasBytes=m_outputStream->read(&buffer,wantBytes); int format = doFloat()?uni_convert_float_ne:wav_sampleWidth; @@ -354,7 +441,7 @@ int DecoderBaseObject_impl::fillArts(uns flpos = flpos - floor(flpos); - outputStream->forwardReadPtr(forward); + m_outputStream->forwardReadPtr(forward); } if(haveSamples != samples) { @@ -374,9 +461,10 @@ void DecoderBaseObject_impl::calculateBl #ifndef _STRIP_ZERO - int audioState=outputStream->waitStreamState(_OUTPUT_WAIT_METHOD_POLL, + int audioState=m_outputStream->waitStreamState(_OUTPUT_WAIT_METHOD_POLL, _STREAM_MASK_ALL, _STREAMTYPE_AUDIO); + if (audioState & _STREAM_MASK_IS_INIT) { // now check if we already have enough data int lenough=false; @@ -388,13 +476,27 @@ void DecoderBaseObject_impl::calculateBl lenough=true; } - if (outputStream->getBufferFillgrade() >= 0) { + if (m_outputStream->getBufferFillgrade() >= 4096) { lenough=true; - } - if ( ((lenough) || _blocking) && (_state == posPlaying) ) { - fillArts(samples,left,right); - return; } + + if (_state == posPlaying) { + if (m_streaming) { + // produce more data + processQueue(); + // check for stream end + if ( m_inputStream->getByteLength() == 0 ) { + if ( m_artsInputStream.eof() ) { + m_inputStream->close(); + m_artsInputStream.streamEnd(); + } + } + } + if (lenough || _blocking) { + fillArts(samples, left, right); + return; + } + } } #endif @@ -406,9 +508,11 @@ void DecoderBaseObject_impl::calculateBl } void DecoderBaseObject_impl::streamEnd() { + arts_debug("streamEnd"); #ifdef _STRIP_ZERO return; #endif + halt(); } @@ -432,6 +536,7 @@ int DecoderBaseObject_impl::getBufferSiz void DecoderBaseObject_impl::shudownPlugins() { + arts_debug("shudownPlugins -s"); /** The order here is important. First we close the audio so that the thread never blocks @@ -443,25 +548,36 @@ void DecoderBaseObject_impl::shudownPlug */ // this should theoretically be faster - Command cmd(_COMMAND_CLOSE); - decoderPlugin->insertAsyncCommand(&cmd); - - if (outputStream != NULL) { - outputStream->audioClose(); + if (decoderPlugin != NULL) { + Command cmd(_COMMAND_CLOSE); + decoderPlugin->insertAsyncCommand(&cmd); + } + arts_debug("shudownPlugins -s 1"); + if (m_outputStream != NULL) { + m_outputStream->audioClose(); } + arts_debug("shudownPlugins -s 2"); // very likely the thread already is closed // because of the asyncCommand above. if (decoderPlugin != NULL) { decoderPlugin->close(); } + arts_debug("shudownPlugins -s 3"); - if (inputStream != NULL) { - delete inputStream; - inputStream=NULL; + if (m_inputStream != NULL) { + delete m_inputStream; + m_inputStream=NULL; } + arts_debug("shudownPlugins -s 4"); + + if (m_streaming) + m_artsInputStream.streamEnd(); + setStreamState(_THREADSTATE_CLOSED); + + arts_debug("shudownPlugins -e"); } void DecoderBaseObject_impl::setStreamState(int state) { Index: decoderBaseObject_impl.h =================================================================== RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/decoderBaseObject_impl.h,v retrieving revision 1.11 diff -u -3 -p -r1.11 decoderBaseObject_impl.h --- decoderBaseObject_impl.h 2001/08/08 12:05:07 1.11 +++ decoderBaseObject_impl.h 2002/03/05 17:33:05 @@ -25,32 +25,35 @@ #include #include +#include + #define _THREADSTATE_INIT 0 #define _THREADSTATE_OPENED 1 #define _THREADSTATE_PAUSED 2 #define _THREADSTATE_PLAYING 3 #define _THREADSTATE_CLOSED 4 - +#include class DecoderPlugin; class InputStream; class ArtsOutputStream; - using namespace std; using Arts::poState; using Arts::poTime; using Arts::poCapabilities; - +using Arts::DataPacket; +using Arts::mcopbyte; class DecoderBaseObject_impl : virtual public Arts::StdSynthModule, virtual public DecoderBaseObject_skel { poState _state; - InputStream* inputStream; - ArtsOutputStream* outputStream; + InputStream* m_inputStream; + Arts::InputStream m_artsInputStream; + ArtsOutputStream* m_outputStream; double flpos; float startTime; @@ -60,6 +63,10 @@ class DecoderBaseObject_impl : bool _blocking; float _speed; + bool m_streaming; + + queue*> *m_packetQueue; + public: DecoderBaseObject_impl(); @@ -70,6 +77,10 @@ public: virtual bool doFloat() { return false; } bool loadMedia(const string &filename); + bool streamMedia(Arts::InputStream instream); + void process_indata(DataPacket* inpacket); + Arts::InputStream inputStream() { return m_artsInputStream; } + string description(); void description(const string &); @@ -102,6 +113,7 @@ public: int getBufferSize(); int fillArts(unsigned long samples,float* left , float* right); void setStreamState(int state); + void processQueue(); }; --------------Boundary-00=_81IIGUOW7DLTSHJYAWMU Content-Type: text/x-diff; charset="iso-8859-1"; name="noatun-streaming.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="noatun-streaming.patch" Index: engine.cpp =================================================================== RCS file: /home/kde/kdemultimedia/noatun/library/engine.cpp,v retrieving revision 1.77 diff -u -3 -p -r1.77 engine.cpp --- engine.cpp 2002/03/03 00:36:38 1.77 +++ engine.cpp 2002/03/05 17:29:28 @@ -290,7 +290,9 @@ bool Engine::open(const PlaylistItem &fi if (file.isProperty("stream_")) { - d->playobj=factory.createPlayObject(file.property("stream_"), file.mimetype(), false); + // let the factory decide + // d->playobj=factory.createPlayObject(file.property("stream_"), file.mimetype(), false); + d->playobj=factory.createPlayObject(file.property("stream_"), false); } else { Index: playlistsaver.cpp =================================================================== RCS file: /home/kde/kdemultimedia/noatun/library/playlistsaver.cpp,v retrieving revision 1.17 diff -u -3 -p -r1.17 playlistsaver.cpp --- playlistsaver.cpp 2002/03/02 19:49:26 1.17 +++ playlistsaver.cpp 2002/03/05 17:29:29 @@ -67,7 +67,7 @@ bool PlaylistSaver::metalist(const KURL if (type!="application/octet-stream") return false; QMap map; - map["playObject"]="SplayPlayObject"; + map["playObject"]="Arts::StreamPlayObject"; map["title"] = i18n("Stream from %1").arg(url.host()); KURL u(url); --------------Boundary-00=_81IIGUOW7DLTSHJYAWMU-- _______________________________________________ kde-multimedia mailing list kde-multimedia@mail.kde.org http://mail.kde.org/mailman/listinfo/kde-multimedia