CSS-TS Servers

Module: dvbcss.protocol.server.ts

The TSServer class implements a CSS-TS server that can be plugged into the cherrypy web server engine.

To create a CSS-TS Server, first create and mount the server in a cherrypy web server. Then you can start the cherrypy server and the CSS-TS server will start to accept connections from clients.

The CSS-TS Server needs a timeline source to be given to it in order for it to serve these to clients. A timeline source provides the Control Timestamps given a particular timeline selector. A CSS-TS server can have multiple timelines sources plugged into it, and they can be added or removed dynamically while the server is running.

An example server is provided in this package.

Using TSServer and Timeline Sources

1. Imports and initialisation

To run a CSS-TS server, you must import both ws4py’s cherrypy server and the dvbcss.protocol.server.ts module. When the dvbcss.protocol.server.ts module is imported, it will register as a “tool” with cherrypy, so it must be imported after cherrypy is imported.

Next, subscribe the ws4py websocket plugin to cherrypy.

import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin
from dvbcss.protocol.server.ts import TSServer

# initialise the ws4py websocket plugin
WebSocketPlugin(cherrypy.engine).subscribe()

2. Create and mount the TS server

You can now create an instance of a TSServer and mount it into the cherrypy server at a path of your choosing.

The configuration for that path (see example code below) must turn on the “dvb_ts” tool and pass a “handler_cls” argument whose value is the handler class that the TS Server instance provides via the TSServer.handler attribute.

The TS Server needs, at initialisation, to be told the initial contentId that it is providing timelines for and it also needs to be provided with a clock object representing the Wall Clock (ticking at the correct rate of 1e9 ticks per second). It needs the WallClock so it can set the WallClockTime property in Control Timestamps that notify clients of a timeline being unavailable.

For example, to create a TS Server mounted at the URL path “/ts”:

# create a Wall Clock
from dvbcss.clock import SysClock, CorrelatedClock
sysClock = SysClock()
wallClock = CorrelatedClock(parentClock=sysClock, tickRate=1000000000)

# create TS Server
tsServer = TSServer(contentId="dvb://1004", wallClock=wallClock, maxConnectionsAllowed=10)

# bind it to the URL path /ts in the cherrypy server
class Root(object):
    @cherrypy.expose
    def ts(self):
        pass

# construct the configuration for this path, providing the handler and turning on the tool hook
cfg = {"/ts": {'tools.dvb_ts.on': True,
                'tools.dvb_ts.handler_cls': tsServer.handler
               }
      }

cherrypy.tree.mount(Root(), "/", config=cfg)    

3. Start cherrypy running

Start cherrypy running and our TS server will start to accept connections from clients:

# configure cherrypy to serve on port 7681
cherrypy.config.update({"server.socket_port":7682})

# activate cherrypy web server (non blocking)
cherrypy.engine.start()

The cherrypy engine runs in a background thread when the cherrypy engine is started. Callbacks from the TSServer happen on the ws4py websocket library’s thread(s) for handling received messages.

4. Providing timelines through the TS Server

To make a timeline available to clients, we create a source for that timeline. For example, a SimpleClockTimelineSource based on a clock object that corresponds to the ticking of progress on the timeline. We also decide the timeline selector that clients must use to obtain that timeline.

For example, we might create a Timeline Source to represent ticking of a PTS timeline:

from dvbcss.protocol.server.ts import SimpleClockTimelineSource
from dvbcss.clock import Correlation

ptsClock = CorrelatedClock(parentClock=wallClock, tickRate=90000)
ptsTimelineSrc = SimpleClockTimelineSource(timelineSelector="urn:dvb:css:timeline:pts", wallClock=wallClock, clock=ptsClock)

# set that ptsClock to start counting from zero starting NOW:
ptsClock.correlation = Correlation(wallClock.ticks, 0)

When we want that timeline to become available to connected clients we add it to the TS Server:

tsServer.attachTimelineSource(ptsTimelineSrc)
tsServer.updateAllClients()

When we make any change (adding or removing timlelines, or changing a timeline in any way) then we must call TSServer.updateAllClients() to ensure Control Timestamp messages are sent immediately to all connected clients to notify them of any changes.

Any new client connections or existing connections, that ask for that timeline (using the timeline selector and matching the content id) will have the timeline made available to them.

If at some point the relationship between PTS and wall clock changes, or the clock availability changes, then we must instruct the TS Server to send new Control Timestamps out if needed:

# lets reset the pts timeline position to zero again
ptsClock.correlation = Correlation(wallClock.ticks, 0)
tsServer.updateAllClients()

When we want to make the timeline unavailable, we can simply update the availability of the clock:

ptsClock.setAvailability(False)
tsServer.updateAllClients()

Or if we wish to stop more permanently, we can instead detatch the timeline source from the TS Server:

tsServer.removeTimelineSource(ptsTimelineSrc)
tsServer.updateAllClients()

If there are clients connected that have asked for that timeline, then the update call will cause Control Timestamps to be sent to them that indicate that the timeline is no longer available.

We can also change the contentId for which the timelines are being provided. If we do this, then again, it may change whether timelines are available to any currently connected clients:

5. Changing content id

tsServer.contentId = "http://myservice.com/new-content-id"
tsServer.updateAllClients()

What does TSServer do for you and what does it not?

TSServer handles the connection and disconnection of clients without requiring any further intervention. It handles the initial setup-data message and uses the information in that to determine which TimelineSource it should obtain Control Timestamps from. It will also automatically ensure ‘null’ Control Timestamp messages are sent if there is no suitable timeline source.

Your code (or a TimelineSource that you create) must call the updateClient() or updateAllClients() to notify the TSServer that it needs to potentialy send updated Control Timestamps to clients.

More about Timeline Sources

A timeline source is any object that implements the methods defined by the TimelineSource base class.

Exising timeline source implementations

Two implementations are provided:

  • SimpleTimelineSource is a timeline source where you directly specify the Control Timestamp that will be sent to clients.
  • SimpleClockTimelineSource is a timeline source where Control Timestamps are generated from Clock objects representing the position of the timeline and the Wall Clock.

The CSS-TS server does not automatically push out new Control Timestamps to connected clients. It will only do so when the updateAllClients() or updateClient() methods are called. This allows you to do things like swap out and replace a timeline source object without causing spurious Control Timestamps to be sent.

Creating new Timeline Sources

Create new Timeline Source types by subclasing TimelineSource and, at minimum, implementing the stubs recognisesTimelineSelector() and getControlTimestamp().

For example, here is a timeline source that recognises a timeline selector “urn:pretend-timeline:N” where N is the ticks per second of the timeline. The progress of this timeline is controlled by the code outside of this object periodcally calling the setTimelinePositionNow method. It needs a clock object representing the WallClock to be passed to it. It can serve different tick rates to different clients.

from dvbcss.protocol.server.ts import TimelineSource
from dvbcss.protocol.ts import ControlTimestamp, Timestamp
from dvbcss.clock import Correlation
import re

class PretendTimelineSource(TimelineSource):
    def __init__(self, wallClock):
        super(PretendTimelineSource,self).__init__()
        self.wallClock = wallClock
        self.correlation = Correlation(0,0)
                
    def recognisesTimelineSelector(self, timelineSelector):
        return re.match("^urn:pretend-timeline:([0-9]+)$", timelineSelector)
    
    def getControlTimestamp(self, timelineSelector):
        match = re.match("^urn:pretend-timeline:([0-9]+)$", timelineSelector)
        if not match:
            raise RuntimeError("This should never happen.")
        elif self.correlation is None:
            # timeline not yet available, so return 'null' control timestamp
            return ControlTimestamp(Timestamp(None, self.wallClock.ticks), None)
        else:
            tickRate = int(match.group(1))
            contentTime = tickRate * self.correlation.childTicks
            wallClockTime = self.correlation.parentTicks
            speed = 1
            return ControlTimestamp(Timestamp(contentTime, wallClockTime), speed)

    def setTimelinePositionNow(self, timelineSecondsNow):
        self.correlation = Correlation(self.wallClock.nanos, timelineSecondsNow)

The base class also has stub methods to support notification of when a sink is attached to the timeline source and also methods to notify of when a particular timeline selector is being requested by at least one client and when it is no longer required by any clients. See the documentation for TimelineSource for more details.

Classes

TSServer

class dvbcss.protocol.server.ts.TSServer(contentId, wallClock, maxConnectionsAllowed=-1, enabled=True)[source]

Implements a server for the CSS-TS protocol that serves timelines provided by sources that are plugged into this server object.

Use by instantiating. You may subclass if you wish to optionally override the following methods:

When the server is “disabled” it will refuse attempts to connect by sending the HTTP status response 403 “Forbidden”.

When the server has reached its connection limit, it will refuse attempts to connect by sending the HTTP status response 503 “Service unavailable”.

This object has the following properties:

  • enabled (read/write) controls whether the server is enabled
  • contentId (read/write) controls the contentId that timelines are being served for
  • handler (read) the class that must be passed as part of the cherrypy configuration for the URL path this server is attached to.

The contentId and enabled attributes can be changed at runtime. Whether the contentId matches that provided by a client when it initially connects is part of determining whether the timeline is available to the client.

Use attachTimelineSource() and removeTimelineSource() to add and remove sources of timelines. Adding or removing a source of a timeline will affect availablilty of a timeline to a client.

This server does not automatically send Control Timestamp messages to clients. After you make a change (e.g. to the contentId or a state change in a timeline source or attaching or removing a timeline source) then you must call updateAllClients() to cause messages to be sent.

The only exception to this is changes to the enabled state which takes effect immediately.

Initialisation takes the following parameters:

Parameters:
  • contentId (str) – The content-id for which timelines will be made available.
  • wallClock (clock) – The wall clock
  • maxConnectionsAllowed (int) – (int, default=-1) Maximum number of concurrent connections to be allowed, or -1 to allow as many connections as resources allow.
  • enabled (bool) – Whether this server starts off enabled or disabled.
contentId[source]

(read/write str) The content ID for all timelines currently being served. Can be changed at runtime.

handler[source]

Handler class for new connections.

When mounting the CII server with cherrypy, include in the config dict a key ‘tools.dvb_cii.handler_cls’ with this handler class as the value.

attachTimelineSource(timelineSource)[source]

Attach (add) a source of a timeline to this CSS-TS server. This causes the timeline to become available immediately to any connected clients that might be requesting it.

This causes the addSink() method of the timeline source to be called, to notify it that this CSS-TS server is now a recipient (sink) for this timeline.

Parameters:timelineSource – Any object implementing the methods of the TimelineSource base class
enabled[source]

(read/write bool) Whether this server endpoint is enabled (True) or disabled (False).

Set this property enable or disable the endpoint.

When disabled, existing connections are closed with WebSocket closure reason code 1001 and new attempts to connect will be refused with HTTP response status code 403 “Forbidden”.

getConnections()[source]
Returns dict:mapping a WebSocket object to connection related data for all connections to this server. This is a snapshot of the connections at the moment the call is made. The dictionary is not updated later if new clients connect or existing ones disconnect.
getDefaultConnectionData()[source]

Internal method. Creates empty ‘connection data’ for the connection consisting of: a dict: { "setup":None, "prevCt":None, "aptEptLpt":None }

This reflects that no setup-data has been received yet, and no Control Timestamps have been sent, and no AptEptLpt has been received either

onClientAptEptLpt(webSock, apteptlpt)[source]

Called when a client has sent an updated AptEptLpt message

This is a stub for this method. Sub-classes should implement it.

Parameters:
  • webSock – The connection from the client.
  • aptEptLpt – (AptEptLpt) object representing the received timestamp message.
onClientConnect(webSock)[source]

Called when a client establishes a connection.

If you override, make sure you call the superclass implementation of this method.

Parameters:webSock – The connection from the client.
onClientDisconnect(webSock, connectionData)[source]

Called when a client disconnects.

If you override, make sure you call the superclass implementation of this method.

Parameters:
  • webSock – The connection from the client.
  • connectionData – A dict containing data relating to this (now closed) connection
onClientMessage(webSock, message)[source]

Called when a message is received from a client.

If you override, make sure you call the superclass implementation of this method.

Parameters:
  • webSock – The connection from the client.
  • msg – (Message) WebSocket message that has been received. Will be either a Text or a Binary message.
onClientSetup(webSock)[source]

Called when a client has connected and submitted its SetupData message to provide context for the connection.

This is a stub for this method. Sub-classes should implement it.

Parameters:webSock – The connection from the client.
removeTimelineSource(timelineSource)[source]

Remove a source of a timeline from this CSS-TS server. This causes the timeline to become unavailable immediately to any connected clients that are using it.

This causes the removeSink() method of the timeline source to be called, to notify it that this CSS-TS server is no longer a customer (sink) for this timeline.

Parameters:timelineSource – Any object implementing the methods of the TimelineSource base class
updateAllClients()[source]

Causes an update to be sent to all clients that need it (i.e. if the ControlTimestamp that would be sent now is different to the one most recently sent to that client)

updateClient(webSock)[source]

Causes an updated ControlTimestamp to be sent to the WebSocket connection specified.

The ControlTimestamp is only sent if it is different to the last time this was done for this connection.

The value of the Control Timestamp is determined by searching all attached timeline sources to find one that can supply a Control Timestamp for this connection.

TimelineSource

class dvbcss.protocol.server.ts.TimelineSource[source]

Base class for timeline sources.

Subclass and implement the stub methods to create Timeline Source:

If your source needs to be informed of when a timeline is needed and when it becomes no longer needed (e.g. so you can allocate/deallocate resources needed to extract it) then also implement these stub methods:

You can also optionally override the following methods, provided your code still calls through to the base class implementations:

The attachSink() and removeSink() methods will be called by parties interested in the TimelineSource (such as a TSServer) when they wish to use the timeline source. The base class implementations of these methods maintain the sinks attribute as a dictionary indexed by sink.

Note: When subclassing attachSink() and removeSink() remember to call the base class implementations of these methods.

attachSink(sink)[source]

Called to notify this Timeline Source that there is a sink (such as a TSServer) that wishes to use this timeline source.

Parameters:sink – The sink object (e.g. a TSServer)

A TimelineSource implementation can use knowledge of what sinks are attached in whatever way it wishes. For example: it might use this to proactively call updateAllClients() on the attached TSServer when its Timeline’s relationship to wall clock changes in some way. It is up to the individual implementation whether it chooses to do this or not.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

getControlTimestamp(timelineSelector)[source]

Get the Control Timestamp from this Timeline Source given the supplied timeline selector.

This method will only be called with timelineSelectors for which the recognisesTimelineSelector() method returned True.

This is a stub for this method. Sub-classes should implement it.

The return value should be a ControlTimestamp object. If the timeline is known to be unavailable, then the contentTime and speed properties of that Control Timestamp must be None.

If, however, you want the TS Server to not send any Control Timestamp to clients at all, then return None instead of a Control Timestamp object. Use this when, for example, you are still awaiting an result from code that has only just started to try to extract the timeline and doesn’t yet know if there is one available or not.

Parameters:timelineSelector – (str) A timeline selector supplied by a CSS-TS client
Returns:A ControlTimestamp object for this timeline source appropriate to the timeline selector, or None if the timleine is recognised no Control Timestamp should yet be provided.
recognisesTimelineSelector(timelineSelector)[source]

This is a stub for this method. Sub-classes should implement it.

Parameters:timelineSelector – (str) A timeline selector supplied by a CSS-TS client
Returns:True if this Timeline Source can provide a Control Timestamp given the specified timeline selector
removeSink(sink)[source]

Called to notify this Timeline Source that there is a sink that no longer wishes to use this timeline source.

Parameters:sink – The sink object

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

timelineSelectorNeeded(timelineSelector)[source]

Called to notify this Timeline Source that there is a need to provide a timeline for the specified timeline selector.

Parameters:timelineSelector – (str) A timeline selector supplied by a CSS-TS client that has not been specified by any other currently connected clients.

This is useful to, for example, initiate processes needed to extract the timeline for the specified timeline selector. You will not receive repeats of the same notification.

If the timeline is no longer needed then the timelineSelectorNotNeeded() function will be called to notify of this. After this, then you might be notified again in future if a timeline for the timeline selector becomes needed again.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

timelineSelectorNotNeeded(timelineSelector)[source]

Called to notify this Timeline Source that there is no longer a need to provide a timeline for the specified timeline selector.

Parameters:timelineSelector – (str) A timeline selector that was previously needed by one or more CSS-TS client(s) but which is no longer needed by any.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

SimpleTimelineSource

class dvbcss.protocol.server.ts.SimpleTimelineSource(timelineSelector, controlTimestamp, *args, **kwargs)[source]

A simple Timeline Source implementation for a fixed timeline selector and where the Control Timestamp is specified manually.

Initialisation takes the following parameters:

Parameters:
  • timelineSelector – (str) The exact timeline selector that this Timeline Source will provide Control Timestamps for.
  • controlTimestamp – (ControlTimestamp) The initial value of the Control Timestamp
attachSink(sink)[source]

Called to notify this Timeline Source that there is a sink (such as a TSServer) that wishes to use this timeline source.

Parameters:sink – The sink object (e.g. a TSServer)

A TimelineSource implementation can use knowledge of what sinks are attached in whatever way it wishes. For example: it might use this to proactively call updateAllClients() on the attached TSServer when its Timeline’s relationship to wall clock changes in some way. It is up to the individual implementation whether it chooses to do this or not.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

removeSink(sink)[source]

Called to notify this Timeline Source that there is a sink that no longer wishes to use this timeline source.

Parameters:sink – The sink object

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

timelineSelectorNeeded(timelineSelector)[source]

Called to notify this Timeline Source that there is a need to provide a timeline for the specified timeline selector.

Parameters:timelineSelector – (str) A timeline selector supplied by a CSS-TS client that has not been specified by any other currently connected clients.

This is useful to, for example, initiate processes needed to extract the timeline for the specified timeline selector. You will not receive repeats of the same notification.

If the timeline is no longer needed then the timelineSelectorNotNeeded() function will be called to notify of this. After this, then you might be notified again in future if a timeline for the timeline selector becomes needed again.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

timelineSelectorNotNeeded(timelineSelector)[source]

Called to notify this Timeline Source that there is no longer a need to provide a timeline for the specified timeline selector.

Parameters:timelineSelector – (str) A timeline selector that was previously needed by one or more CSS-TS client(s) but which is no longer needed by any.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

SimpleClockTimelineSource

class dvbcss.protocol.server.ts.SimpleClockTimelineSource(timelineSelector, wallClock, clock, speedSource=None, autoUpdateClients=False)[source]

Simple subclass of TimelineSource that is based on a clock object.

The Control Timestamp returned by the getControlTimestamp() method reflects the state of the clock.

Note that this does not result in a new Control Timestamp being pushed to clients, unless you set the auto update parameter to True when initialising this object. By default (with no auto-updating), you still have to call updateAllClients() manually yourself to cause that to happen.

Use auto-updating with caution: if you have multiple Timeline Sources driven by a common clock, then a change to that clock will cause each Timeline Source to call updateAllClients(), resulting in multiple unnecessary calls.

The tick rate is fixed to that of the supplied clock and timeline selectors are only matched as an exact match.

The speed property of the clock will be used as the timelineSpeedMultiplier value, unless a different clock is provided as the optional speedSource argument at initialisation. This is useful if the speed of the timeline is set by setting the speed property of a parent clock, and not the speed property of this clock (e.g. in situations where a single clock represents timeline progress but there are multiple clocks as children of that to represent the timeline on different scales - e.g. PTS, TEMI etc).

The availability of the clock is mapped to whether the timeline is available.

SimpleClockTimelineSource generates its correlation by observing the current tick value of the wallClock and the provided clock whenever a ControlTimestamp needs to be provided.

Initialisation takes the following parameters:

Parameters:
  • timelineSelector – (str) The timeline selector that this TimelineSource will provide Control Timestamps for
  • wallClock – (ClockBase) A clock object representing the Wall Clock
  • clock – (ClockBase) A clock object representing the flow of ticks of the timeline.
  • speedSource – (None or ClockBase) A different clock object from which the timelineSpeedMultiplier is determined (from the clock’s speed property), or None if the clock for this is not different.
  • autoUpdateClients – (bool) Automatically call updateAllClients() if there is a change in the clock or wallClock
notify(cause)[source]

Called by clocks to notify of changes (because this class binds itself to the clock object).

If auto-updating is enabled then this will result in a call to updateAllClients() on all sinks.

timelineSelectorNeeded(timelineSelector)[source]

Called to notify this Timeline Source that there is a need to provide a timeline for the specified timeline selector.

Parameters:timelineSelector – (str) A timeline selector supplied by a CSS-TS client that has not been specified by any other currently connected clients.

This is useful to, for example, initiate processes needed to extract the timeline for the specified timeline selector. You will not receive repeats of the same notification.

If the timeline is no longer needed then the timelineSelectorNotNeeded() function will be called to notify of this. After this, then you might be notified again in future if a timeline for the timeline selector becomes needed again.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

timelineSelectorNotNeeded(timelineSelector)[source]

Called to notify this Timeline Source that there is no longer a need to provide a timeline for the specified timeline selector.

Parameters:timelineSelector – (str) A timeline selector that was previously needed by one or more CSS-TS client(s) but which is no longer needed by any.

NOTE: If you override this in your subclass, ensure you still call this implementation in the base class.

Functions

ciMatchesStem

dvbcss.protocol.server.ts.ciMatchesStem(ci, stem)[source]

Checks if a content identifier stem matches a content identifier. A match is when the content identifier starts with the stem and is the same length as the stem, or longer.

Parameters:
  • ci (str or OMIT) – Content identifier
  • stem (str) – Content identifier stem
Returns:

True if the supplied content identifier stem (stem) matches the content identifier. If the ci is OMIT then always returns False.

isControlTimestampChanged

dvbcss.protocol.server.ts.isControlTimestampChanged(prev, latest)[source]

Checks whether a new (latest) Control Timestamp is different when compared to a old (previous) Control Timestamp.

Note that this does not check equivalency (if two Control Timestamps represent the same mapping between Wall clock time and content time) but instead checks if the property values comprising the two timestamps are exact matches.

Parameters:
Returns:

True if the previous Control Timestamp is supplied is None, or if any of its properties differ in value to that of the latest Control Timestamp

Throws ValueError:
 

The new Control Timestamp supplied is None instead of a Control Timetamp