Skip to content

Writing codecserver modules

Jakob Ketterl edited this page Jun 21, 2021 · 3 revisions

Codecserver comes with a C++ API that allows developers to add support for new codecs by simply registering additional drivers and devices. This page describes the basic structure and the classes involved in the interaction.

The Registry

The registry is the central means of coordination when it comes to serving client requests. It keeps a list of the available drivers and devices.

The one basic interaction that any module has to initiate to announce its presence is to call the static Registry::registerDriver(). All other interaction will be initiated by the codecserver itself, so all you have to do is to implement the methods of the Driver, Device and Session classes.

The Driver class

Your module should extend this class and flesh it out according to the properties of your Codec.

getIdentifier()

This method must return a string that uniquely identifies your driver. This string can be used to configure your driver by placing a [driver:${identifier}] section in the configuration, and it is used to resolve the type=${identifier} lines of the respective device config sections.

scanForDevices()

You can optionally implement this method if your driver is capable of automatically detecting devices at start-up time. This method will be called upon driver registration. It may return an empty vector. The default implementation is unconditionally returning an empty vector.

buildFromCVOnfiguration()

This method should build a new Device instance from the configuration it is passed. It can return nullptr if the configuration is not appropriate or contains errors.

configure()

This method should can optionally receive driver-wide configuration, if present in the configuration file. The default implementation is to ignore the configuration.

The Device class

A Device is an abstract concept and does not necessarily correlate to an actual physical device. A device can handle any number of codecs and sessions in parallel, but a single device must correlate to a single configuration section.

getCodecs()

This method must return the identifier strings of the codes this device can handle. The return type of this method is a vector<string> as to support multiple codecs, so if your device only supports one codec, this vector should contain a single item.

startSession()

This method will be called whenever a new client request is received (and hasn't been handled by any preceding device). When this method is called, the class should take any necessary preparatory steps to determine whether or not it can handle the request. If the device cannot handle this request for any reason, it must return a nullptr, otherwise it should return a corresponding Session that will receive the client data.

The Session class

A session object describes an ongoing decoding and/or encoding process, as negotiated in startSession(). Any data received by the client will be dispatched here. Any data to be dispatched to the client will be received here.

start()

This method can be implemented if the session needs to take any preparatory steps beyond startSession(). The default implementation is an empty method.

decode()

This method will receive any data that should be decoded by the underlying codec. The decoding process can be asynchronous, so this method does not receive an immediate answer. Data should be retrieved through read() at a later time.

encode()

Same as decode(), but the intention is to have this data encoded.

read()

This method retrieves the available output from the device. This method should block if no data is available. Reading from this method is best handled in a thread so as not to create any interlocking situations between writing and reading data.

end()

This method is called when a session is terminated, and can be used optionally to shut down any associated parts of the program. Its default implementation is empty.

getFraming()

This method should provide framing information to the connected client. Framing describes how many bits / bytes should be sent during one request, and how many samples / bytes will be received per frame on the output. It is optional, but highly recommended to implement this method.

renegotiate()

This method can be called by the client during the encoding / decoding process if it wants to change the parameters of the codec.