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 fromClock
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 enabledcontentId
(read/write) controls the contentId that timelines are being served forhandler
(read) the class that must be passed as part of the cherrypy configuration for the URL path this server is attached to.
The
contentId
andenabled
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()
andremoveTimelineSource()
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:
-
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:
attachSink()
(see note)removeSink()
(see note)
The
attachSink()
andremoveSink()
methods will be called by parties interested in the TimelineSource (such as aTSServer
) when they wish to use the timeline source. The base class implementations of these methods maintain thesinks
attribute as a dictionary indexed by sink.Note: When subclassing
attachSink()
andremoveSink()
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 clientReturns: 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 clientReturns: 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.
- timelineSelector – (
SimpleClockTimelineSource¶
-
class
dvbcss.protocol.server.ts.
SimpleClockTimelineSource
(timelineSelector, wallClock, clock, speedSource=None, autoUpdateClients=False)[source]¶ Simple subclass of
TimelineSource
that is based on aclock
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.
- timelineSelector – (
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: 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: - prev –
None
or a previousControlTimestamp
- latest – A new
ControlTimestamp
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
- prev –