Sienda Time Sensitive Network Stack

Library Overview and API reference

Updated: January 2016

Author: Kieran Tyrrell
Sienda Multimedia Ltd
www.sienda.com
kieran@sienda.com

Content subject to change. Content Copyright (c) 2016 Sienda Multimedia Ltd.

Introduction

The Sienda Time Sensitive Network Stack is a software library written in C++ (with C wrappers) that can provide full protocol support for the IEEE Time Sensitive Networking (TSN) standards defined in IEEE 802.1BA.

It can be used to implement Audio Video Bridging (AVB) or TSN endpoints, and supports the following standards:

The library can be deployed on a variety of architectures, including ARM Cortex M MCUs, Cortex A MPUs, and desktop environments (OSX, Windows, Linux). The library is portable and should deploy on any system with a C++11 compliant gcc or clang/llvm compiler, floating point support and 64 bit integer (uint64_t) support.

The library is fully encapsulated and interfaces with the external environment (hardware) via a few simple function calls and callbacks that provide:

The library is generally synchronous in operation and non-reentrant, so the host application must ensure that library functions are not called simultaneously from multiple threads/tasks. There are two exceptions to this rule, where ethernet packets may be passed to a high priority packet handler function asynchronously, and audio data may be sent to the library, to ensure that the strict timing requirements of audio data packets are met.

The library provides full AVDECC 1722.1 support. The entity model may be described by an XML file.

API Reference

Library interface

For C++ applications the following class provides the interface to the library:

class AVBStack
{
public:
    AVBStack();
    ~AVBStack();
    
    bool    init(AppCallbacks_t *pAppCallbacks,
                 std::vector<uint64_t> sourceMacAddresses, 
                 uint16_t vlanID, 
                 char* aemXML, size_t xmlStringLength,
                 std::vector<AVBStackMemoryObject> memoryObjects,
                 float **pMixBuf, uint32_t mixBufChannels, uint32_t mixBufFrames,
                 float **pRecBuf, uint32_t recBufChannels, uint32_t recBufFrames,
                 uint8_t **pListenerFrameBuffers, uint32_t nbListenerFrameBuffers, 
                        uint32_t frameBufferSize);
    
    bool    processPriorityPacket(uint8_t *pPacket, int packetSize, int interfaceIndex);
    bool    processPacket(uint8_t *pPacket, int packetSize, int interfaceIndex);
    void    processPTPTimestamp(PTPTimestampEvent event, uint64_t timestamp, 
                                        uint8_t portNb, uint16_t seqNb);
    void    timerElapsed();
    
    void    setPlayheadPosition(uint64_t streamPos, uint64_t expectedPlayoutTime);
    void    setRecordheadPosition(uint64_t streamPos, uint64_t recordedTime);
    
    void    sendVideoFrame(uint8_t *pFrameBuffer, uint32_t frameBufferSize, uint64_t originTime);
    void    sendVideoLines(uint8_t *pLineBuffer, uint32_t lineBufferSize, uint32_t nbLines, 
                                uint64_t originTime);
}

For C applications the following functions provide the interface to the library:

void AVBStack_init(AppCallbacks_t *pAppCallbacks,
                   int nbPorts, uint64_t *sourceMacAddresses, 
                   uint16_t vlanID, 
                   char* aemXML, size_t xmlStringLength,
                   int nbMemoryObjects, AVBStackMemoryObject *pMemoryObjects,
                   float **pMixBuf, uint32_t mixBufChannels, uint32_t mixBufFrames,
                   float **pRecBuf, uint32_t recBufChannels, uint32_t recBufFrames,
                   uint8_t **pListenerFrameBuffers, uint32_t nbListenerFrameBuffers, 
                        uint32_t frameBufferSize);
                       
bool AVBStack_processPriorityPacket(uint8_t *pPacket, int packetSize, int interfaceIndex);
bool AVBStack_processPacket(uint8_t *pPacket, int packetSize, int interfaceIndex);
void AVBStack_processPTPTimestamp(PTPTimestampEvent event, uint64_t timestamp, 
                                        uint8_t portNb, uint16_t seqNb);
void AVBStack_timerElapsed();
    
void AVBStack_setPlayheadPosition(uint64_t streamPos, uint64_t expectedPlayoutTime);
void AVBStack_setRecordheadPosition(uint64_t streamPos, uint64_t recordedTime);

void AVBStack_sendVideoFrame(uint8_t *pFrameBuffer, uint32_t frameBufferSize, uint64_t originTime);
void AVBStack_sendVideoLines(uint8_t *pLineBuffer, uint32_t lineBufferSize, uint32_t nbLines, 
                                uint64_t originTime);

Function reference

init

bool init(AppCallbacks_t *pAppCallbacks,
                 std::vector<uint64_t> sourceMacAddresses, 
                 uint16_t vlanID, 
                 char* aemXML, size_t xmlStringLength,
                 std::vector<AVBStackMemoryObject> memoryObjects,
                 float **pMixBuf, uint32_t mixBufChannels, uint32_t mixBufFrames,
                 float **pRecBuf, uint32_t recBufChannels, uint32_t recBufFrames,
                 uint8_t **pListenerFrameBuffers, uint32_t nbListenerFrameBuffers, 
                        uint32_t frameBufferSize);

The initialisation functions init (C++) and AVBStack_init (C) are used to pass required data to the library and to initialise the library. This function must be called before any other.

Parameters:

name type description
pAppCallbacks AppCallbacks_t* a structure containing pointers to callback functions Callback Functions
sourceMacAddresses std::vector<uint64_t> list of the MAC addresses of the ethernet interfaces
vlanID uint16_t vlan to use for 1722 transport streams, or 0 if the domain default is to be used
aemXML char* the AVDECC entity model XML string
xmlStringLength size_t the length of the entity model XML string (the string doesn't have to be zero terminated)
memoryObjects std::vector<AVBStackMemoryObject> list of memory objects for AVDECC, such as firmware images, manufacturer icon, product icon etc. This list shall match the MEMORY_OBJECTS descriptors described in the entity model XML
pMixBuf float** pointer to an array of buffers for the incoming (listener) audio
mixBufChannels uint32_t number of channels in the mixbuffer
mixBufFrames uint32_t number of frames in the mixbuffer
pRecBuf float** pointer to an array of buffers for the record (outgoing - talker) audio
recBufChannels uint32_t number of channels in the record buffer
recBufFrames uint32_t number of frames in the record buffer
pListenerFrameBuffers uint8_t** pointer to an array of framebuffers for the incoming (listener) video. These framebuffers will be used sequentially for incoming video frames, and passed to the AVBStackOnVideoFrameReceivedFunction callback function when a video frame has been received
nbListenerFrameBuffers uint32_t number of framebuffers in the pListenerFrameBuffers array
frameBufferSize uint32_t size of each framebuffer in bytes

Return value:

returns true if the initialisation was sucessful, false otherwise. Please check the debug console for error messages in the case of failure.

processPriorityPacket

bool    processPriorityPacket(uint8_t *pPacket, int packetSize, int interfaceIndex);

The processPriorityPacket function should be called whenever an ethernet packet is received on an ethernet interface. The function will check if the packet is an AVBTP (1722) stream packet containing media, and if so it will process the packet and return true. If the packet is any other type of packet (MAAP, PTP, AVDECC, Layer 3 etc) the function will return false, indicating that the packet has not been processed and should be passed synchronously to the processPacket function at a later time. This mechanism allows the priority 1722 packets to be processed immediately from an interrupt handler or high priority task.

Parameters:

type name description
uint8_t* pPacket a pointer to a buffer containing the ethernet packet data Ethernet Packet Buffers
int packetSize the size of the packet data Ethernet Packet Buffers
int interfaceIndex the interface index of the interface that the packet was received on

Return value:

returns true if the packet was handled, false otherwise.

processPacket

bool    processPacket(uint8_t *pPacket, int packetSize, int interfaceIndex);

The processPacket function should be called whenever a non priority ethernet packet has been received on an ethernet interface, and it has not been processed by processPriorityPacket. The function will handle the processing of any non-priority TSN/AVB packet (MAAP, PTP, MSRP, AVDECC etc). If the packet is not a valid TSN/AVB packet then the function will return false, indicating that the packet was not handled and may be passed up to a higher level network stack such as IP/TCP/UDP.

Parameters:

type name description
uint8_t* pPacket a pointer to a buffer containing the ethernet packet data Ethernet Packet Buffers
int packetSize the size of the packet data Ethernet Packet Buffers
int interfaceIndex the interface index of the interface that the packet was received on

Return value:

returns true if the packet was handled, false otherwise.

processPTPTimestamp

void processPTPTimestamp(PTPTimestampEvent event, uint64_t timestamp, 
                                uint8_t interfaceNdx, uint16_t seqNb);

The processPTPTimestamp function should be called whenever an ethernet packet tx/rx timestamp is received from the ethernet hardware/driver for a PTP packet. This function can be called before or after processPacket is called for the received packet.

Parameters:

type name description
PTPTimestampEvent event the type of ptp event
uint64_t timestamp the timestamp, in nanoseconds
uint8_t interfaceIndex the interface index of the interface that the timestamp is valid for
uint16_t seqNb the sequence number of the PTP message that the timestamp is valid for

valid events are:

event description
PTPTimestampEventpdelayreq_tx timestamp refers to a PTP pdelay request transmit message
PTPTimestampEventpdelayresp_tx timestamp refers to a PTP pdelay response transmit message
PTPTimestampEventpdelayreq_rx timestamp refers to a PTP pdelay request received message
PTPTimestampEventpdelayresp_rx timestamp refers to a PTP pdelay response received message
PTPTimestampEventsynctx timestamp refers to a PTP sync transmit message
PTPTimestampEventsyncrx timestamp refers to a PTP sync receive message

timerElapsed

void    timerElapsed();

The timerElapsed function should be called whenever the application's timer fires. The library will use the application provided callback function AVBStackSetTimerFunction to set the time that the timer should fire.

setPlayheadPosition

void setPlayheadPosition(uint64_t streamPos, uint64_t expectedPlayoutTime);

The ** setPlayheadPosition** function should be called whenever the application's audio playback stream position has advanced. This may be triggered by an audio DMA completion handler, DAC clock counter, or other application defined event. This notifies the library that the audio in the mix buffer before streamPos has been delivered by the application for playback, and the expectedPlayoutTime timestamp allows the library to perform local media clock measurement, which it uses along with the network media clock recovery to adjust the local media clock rate to ensure media synchronisation.

Parameters:

type name description
uint64_t streamPos the stream position of the local media (playback) stream
uint64_t expectedPlayoutTime the timestamp, in nanoseconds, that the media sample identified by streamPos has, or will, be played out

setRecordheadPosition

void setRecordheadPosition(uint64_t streamPos, uint64_t recordedTime);

The setRecordheadPosition function should be called whenever the application's audio recording stream position has advanced. This may be triggered by an audio DMA completion handler, ADC clock counter, or other application defined event. This notifies the library that new audio is available in the record buffer, and the recordedTime timestamp allows the library to set the presentation timestamp in 1722 media packets to ensure media synchronisation.

Parameters:

type name description
uint64_t streamPos the stream position of the local media (record) stream
uint64_t recordedTime the timestamp, in nanoseconds, that the media sample identified by streamPos was recorded

sendVideoFrame

void sendVideoFrame(uint8_t *pFrameBuffer, uint32_t frameBufferSize, uint64_t originTime);

The sendVideoFrame function should be called whenever the application has a video frame ready for delivery. This may be triggered by a DMA completion handler, video line counter, or other application defined event. This notifies the library that a new video frame is available in the provided frame buffer, and the originTime timestamp allows the library to set the presentation timestamp in 1722 media packets to ensure media synchronisation.

Parameters:

type name description
uint8_t* pFrameBuffer the framebuffer for the video frame
uint32_t frameBufferSize the size of the framebuffer in bytes. Note that this is the size of the active data in the framebuffer, which may be less than the total buffersize allocated for the buffer
uint64_t originTime the timestamp, in nanoseconds, that the video frame in pFrameBuffer originated

sendVideoLines

void sendVideoLines(uint8_t *pLineBuffer, uint32_t lineBufferSize, uint32_t nbLines, 
                        uint64_t originTime);

The sendVideoLines function should be called whenever the application has a video line (or lines) ready for delivery. This may be triggered by a DMA completion handler, video line counter, or other application defined event. This notifies the library that new video line(s) are available in the provided line buffer, and the originTime timestamp allows the library to set the presentation timestamp in 1722 media packets to ensure media synchronisation.

Parameters:

type name description
uint8_t* pLineBuffer the linebuffer for the video line(s)
uint32_t lineBufferSize the size of the linebuffer in bytes. Note that this is the size of the active data in the linebuffer, which may be less than the total buffersize allocated for the buffer
uint32_t nbLines the number of lines contained in pLineBuffer
uint64_t originTime the timestamp, in nanoseconds, that the video frame or line in pLineBuffer originated. Please note that this can be a timestamp for either the frame, or the line, depending on the type of AVBTP stream being sent.

Miscellaneous

Ethernet Packet Buffers

The library expects (and delivers) all ethernet packets (frames) stripped of any preamble and CRC, but with all layer 2 headers intact. For the majority of embedded systems and raw ethernet drivers this is how the packet/frame will be delivered/expected by the driver layer.

Debug console output

The library will report error messages and useful status messages to the debug console. The library uses the standard library function printf for all console output. In an embedded environment the application may redirect stdout to a serial console (UART or similar) by overriding the standard library function _write().

Timer funcionality

The library requires the use of a system timer, preferably a high resolution hardware timer. The application provides a callback function AVBStackSetTimerFunction which the library will use to set the absolute (system) time that it requests to be called at. When the system timer fires, the application should call the library's timerElapsed() function. The library works at nanosecond precision, and so all timestamps are in nanoseconds, and are thus of type uint64_t. The datum for the system time is not important. Nanoseconds from system boot is commonly used.

Callback Functions

The library requires several callback functions to be registered for correct operation. These callback functions are passed into the init function at library initialisation. Not all the callbacks are required for correct operation. Each callback function has an associated context variable that is application defined. If no application context is required when the callbacks are called, then the context variables may be set null.

The callback function prototypes are as follows:

typedef bool (*AVBStackSendPacketFunction)
                (uint8_t *pPacket, int packetSize, int interfaceNdx, void *pContext);
                
typedef void (*AVBStackSetTimerFunction)
                (uint64_t timeNanos, uint8_t timerId, void *pContext);
                
typedef uint64_t (*AVBStackGetCurrentTimeFunction)
                (void *pContext);
                
typedef void (*AVBStackPTPGrandmasterChanged)
                (uint64_t grandmasterId, void *pContext);
                
typedef void (*AVBStackAdjustAudioClockFrequencyFunction)
                (double adjust, void *pContext);
                
typedef bool (*AVBStackOperationFunction)
                (uint8_t entityIndex, uint16_t operation, uint16_t operationId, void *pContext);
                
typedef bool (*AVBStackAddressAccessFunction)
                (uint8_t entityIndex, uint8_t operation, uint64_t address, 
                uint16_t size, uint8_t *pData, void *pContext);
                
typedef bool (*AVBStackSwitchConfigFunction)
                (SwitchConfigCommand command, uint64_t macAddress, uint16_t vlan, void *pContext);
                
typedef void (*AVBStackOnVideoFrameReceivedFunction)
                (uint8_t *pFrameBuffer, uint64_t presentationTimestamp, void *pContext);

The callback function list structure (as passed to the init function) is as follows:

typedef struct AppCallbacks
{
    AVBStackSendPacketFunction                  sendPacketFunction;
    void                                        *pSendPacketFunctionContext;
    AVBStackSetTimerFunction                    setTimerFunction;
    void                                        *pSetTimerFunctionContext;
    AVBStackGetCurrentTimeFunction              getCurrentTimeFunction;
    void                                        *pGetCurrentTimeFunctionContext;
    AVBStackAdjustAudioClockFrequencyFunction   adjustAudioClockFrequencyFunction;
    void                                        *pAdjustAudioClockFrequencyFunctionContext;
    AVBStackAddressAccessFunction               addressAccessFunction;
    void                                        *pAddressAccessFunctionContext;
    AVBStackOperationFunction                   operationFunction;
    void                                        *pOperationFunctionContext;
    AVBStackSwitchConfigFunction                switchConfigFunction;
    void                                        *pSwitchConfigFunctionContext;
    AVBStackOnVideoFrameReceivedFunction        onVideoFrameReceivedFunction;
    void                                        *pOnVideoFrameReceivedFunctionContext;
    AVBStackPTPGrandmasterChanged               ptpGrandmasterChangedFunction;
    void                                        *pPTPGrandmasterChangedFunctionContext;
}AppCallbacks_t;