Friday, June 09, 2006

The birth of the ByteStreamNode
and its problems

First of all let me explain how Phonon-nmm interaction works.
Suppose a KDE4-NMM user whats to play an url, when behind the scenes the following happens:

  • Phonon looks for a Phonon backend (Phonon-NMM in this case) and loads it

  • The backend configures its media framework (the backend is the Phonon::nmm::Backend object, the framework is NMM)

  • Phonon creates a Phonon:nmm::MediaObject and calls its setUrl()method

  • If the setUrl call fails the MediaObject is destroied and a Phonon:nmm::ByteStream object is created which receives the raw stream data in a writeData() callback method (actually a qt-slot) from a KDE4 KIO::TransferJob instance.

  • After an Phonon::nmm::AbstractMediaProducer subclass, MediaObject or the ByteStream, is setup Phonon assumes the media framework is ready to start

  • The AbstractMediaProducer::play method is called which call the media framework playing functionality


The glue between NMM and Phonon is the NMM::GraphHandler class. This class is meant for creating flowgraph from an URL and for playing it. If NMM cannot understand the url (maybe because the protocol is not supported by NMM) GraphHandler throws an exception that Phonon detects (that functionality is in GraphHandler::stage1() which is called from MediaObject::setUrl() ). If stage1() throws any exception, Phonon (in the ByteStream class) calls GraphHandler::stage1_bs() from the ByteStream::writeData().
The writeData() method is responsible for coping the data packets incoming from the running KIO::TransferJob into a local buffer (actually an NMM::StreamBuffer instance) and for initaliazing the GraphHandler by means of calling its stage1_bs() when the first chunk of stream is available. Basically untill the the GraphHandler is initialized writeData pushes incoming data into the buffer and tries to initalize GraphHandler using that growing buffer.
The GraphHandler initialization in stage1_bs() (whose prototype is void stage1_bs(NMMApplication& app, StreamQueue* sq)) creates a new ByteStreamNode from the rgistry and registers the sq into the ByteStreamNode.
For that purpose ByteStreamNode implements the IByteStreamNode interface which just defines void setStreamQueue(in int sq). As you can see this is really an awfull trick I did.
That interface should take a StreamQueue* as input, but I was not able to define it that way (I need input from Marco here). The other alternative would be to create the the ByteStreamNode from stage1_bs() without using the registry (and without defining any IByteStreamNode) and then getting its INode interface using getInterface(); this way the ByteStreamNode could be compiled with GraphHandler, and not as a plugin. Maybe this is better?

Once the ByteStreamNode is started all it has to do in processBuffer is to get one buffer from the streamQueue filled by KIO and return it.
The only other functionalty of ByteStreamNode is stream type finding, done using the first buffer in the registered streamBuffer and passing its data to libmagic.

No comments: