API Documentation

BMediaNode

BMediaNode

The BMediaNode class is the superclass of all participant nodes in the Media Kit. However, you’ll never derive directly from BMediaNode; instead, you’ll derive from one of the system interface classes which in turn are derived from BMediaNode. Look at the documentation for those other classes (such as BBufferProducer and BBufferConsumer) for details on how they’re used, or see “Creating New Node Classes” for discussion on how this is done.

Because of the quirks of virtual inheritance (required by the use of multiple inheritance), your node’s constructor will have to call the BMediaNode constructor. See “About Multiple Virtual Inheritance”.

Note

Applications shouldn’t call a node’s member functions directly; instead, you call the BMediaRoster with a reference to the node and let the request come to the node through the control port. The only exception is if the node is subclassed directly within the application, in which case Acquire(), ID(), Node(), and Release() can be called directly once the node is registered—if you do this, be sure you don’t call them after the node is destroyed.

Calling a node’s member functions directly from outside the node itself can result in the chain of functions involved in coordinating nodes to be called out of order. Worse, deadlock can result. So just don’t do it, even if you think you’ve found a safe way to pull it off.

Creating Your Own Node

Realtime Allocators and Thread Locking

Media nodes are highly timing-sensitive creatures. The slightest delay in performing their work can cause drastic problems in media playback or recording quality. Virtual memory, normally of great benefit to users, can work against them when doing media work. A poorly-timed virtual memory hit can cause breaks in media performances.

The realtime memory allocation and locking functions provide a means for nodes to lock down their memory to prevent it from being cached to disk by the virtual memory system. This avoids situations in which the node has to pause while it or its memory is fetched back from the swap file.

The user can use the Media preference application to configure what types of nodes should use locked memory. Nodes should typically use the realtime memory allocation functions instead of malloc() and free(). rtm_alloc() will automatically handle locking the memory if the B_MEDIA_REALTIME_ALLOCATOR flag is set, so your node doesn’t have to worry about it.

In addition, if the realtime flag corresponding to the type of node you’re writing is set, your node should also call media_realtime_init_thread() to lock down the stacks of its threads. Properly-written nodes can always call media_realtime_init_thread(), without checking the realtime flags, because this function will return B_MEDIA_REALTIME_DISABLED if the corresponding flag isn’t set. You can simply ignore the error and move on.

For example:

int32 *myThreadData = rtm_alloc(4096);
myThread = spawn_thread(myThreadFunction, "Node Thread",
B_NORMAL_PRIORITY, &myThreadData);
status_t err = media_realtime_init_thread(myThread, 32768,
         B_MEDIA_REALTIME_VIDEO);
if (err != B_OK && err != B_MEDIA_REALTIME_DISABLED) {
   printf("Can't lock down the thread.n");
}
...

If your node requires realtime performance from an add-on or shared library, you can use the media_realtime_init_image() function to lock down that image in memory. Note, however, that any uses of malloc() by that image won’t allocate locked memory; you can’t control that. Still, locking down the image itself can help performance even further.

Note

Standard BeOS system libraries are Be’s responsibility. If it’s appropriate for them to be locked, they’re locked for you. Don’t lock them yourself. Both libmedia.so and libroot.so have media_realtime_init_image() called on them.

Negotiating a Connection

Establishing a connection between two nodes is a multi-step process. The nodes need to agree upon a data format they both support before the connection can even be established.

Special Considerations

If the node you’re writing could be connected by the system mixer (using the Audio preference application, for example) as the default output, the node needs to be as flexible as possible in terms of the formats it accepts on its free inputs in the GetNextInput() function. The format your node returns from GetNextInput() will be used as the starting poing in the negotiation process; the more wildcards you support, the better.

An application that wants to establish a connection between some other node and your node will determine the format from the inputs into your node and the outputs from the other node, then call BMediaRoster::Connect() with that format.

If there are any wildcards in the format passed to BMediaRoster::Format(), the media roster will call BBufferProducer::ProposeFormat() in the node being connected to your output node; the producer will specialize the wildcards to construct the least-specific format that will guarantee that any remaining wildcards can be specialized by your node without becoming incompatible with the producer.

The resulting format may have some wildcards left (or, if the producer is particularly picky, there may be none at all). The media roster will then pass this format to your consumer node’s BBufferConsumer::AcceptFormat() function. This function should be implemented to specialize the remaining wildcards and return this format, which should describe a specific format. This format will be used to establish the connection.