def algorithm(self): candidateClock = CorrelatedClock(self.clock.getParent(), tickRate=self.clock.tickRate, correlation=self.clock.correlation) while True: update = False cumulativeOffset = None candidate = (yield self.timeoutSecs) t = self.clock.ticks currentDispersion = self.clock.dispersionAtTime(t) if candidate is not None: candidateClock.correlation = candidate.calcCorrelationFor( self.clock, self.localMaxFreqErrorPpm) candidateDispersion = candidateClock.dispersionAtTime(t) update = candidateDispersion < currentDispersion if update: pt = self.clock.toParentTicks(t) adjustment = candidateClock.fromParentTicks(pt) - t if cumulativeOffset is None: cumulativeOffset = 0 else: cumulativeOffset += adjustment self.clock.correlation = candidateClock.correlation self.onClockAdjusted( self.clock.ticks, adjustment, 1000000000 * currentDispersion, 1000000000 * candidateDispersion, self.clock.correlation.errorGrowthRate) else: pass # update worst dispersion seen so far self.worstDispersion = max(self.worstDispersion, currentDispersion, candidateDispersion) co = cumulativeOffset or 0 # convert None to 0 self.log.info( "Old / New dispersion (millis) is %.5f / %.5f ... offset=%20d new best candidate? %s\n" % (1000 * currentDispersion, 1000 * candidateDispersion, co, str(update))) else: self.log.info("Timeout. Dispersion (millis) is %.5f\n" % (1000 * currentDispersion, )) # retry more quickly if we didn't get an improved candidate if update: time.sleep(self.repeatSecs) else: time.sleep(self.timeoutSecs)
def algorithm(self): while True: candidate = (yield self.timeoutSecs) if candidate is not None: self.log.info("Candidate: " + str(candidate) + "\n") self.clock.correlation = candidate.calcCorrelationFor( self.clock, 500) # guess as to local max freq error time.sleep(self.repeatSecs) else: self.log.debug("Response timeout\n")
def test_sleep_works(self): """Check a sleep works""" t=self.t m=self.m start_t = t.time() m.sleep(5) end_t = t.time() diff_t = (end_t - start_t) self.assertLess(abs(5.0-diff_t), 0.05, "Sleep was correct to within 1%")
def test_sleep_works(self): """Check a sleep works""" t = self.t m = self.m start_t = t.time() m.sleep(5) end_t = t.time() diff_t = (end_t - start_t) self.assertLess(abs(5.0 - diff_t), 0.05, "Sleep was correct to within 1%")
def algorithm(self): cumulativeOffset=None self.bestCandidate={"nanos":None,"ticks":None} while True: update=False candidate=(yield self.timeoutSecs) currentDispersion = self.getCurrentDispersion() if candidate is not None: cn=candidate['nanos'] ct=candidate['ticks'] candidateDispersion=self.dispCalc.calc(cn) if currentDispersion >= candidateDispersion: self.bestCandidate = candidate update=True self.clock.adjustTicks(ct.offset) if cumulativeOffset is None: cumulativeOffset=0 else: cumulativeOffset+=ct.offset # notify of the change growthRate = self.dispCalc.getGrowthRate(cn) self.onClockAdjusted(self.clock.ticks, ct.offset, currentDispersion, candidateDispersion, growthRate) else: pass # update worst dispersion seen so far self.worstDispersion = max(self.worstDispersion, currentDispersion, candidateDispersion) self.log.info("Old / New dispersion (millis) is %.5f / %.5f ... offset=%20d new best candidate? %s\n" % (currentDispersion/1000000.0, candidateDispersion/1000000.0, cumulativeOffset, str(update))) else: self.log.info("Timeout. Dispersion (millis) is %.5f\n" % (currentDispersion/1000000.0)) # retry more quickly if we didn't get an improved candidate if update: time.sleep(self.repeatSecs) else: time.sleep(self.timeoutSecs)
def algorithm(self): while True: candidate = (yield self.timeoutSecs) if candidate is not None: # apply filters if None in [f.checkCandidate(candidate) for f in self.filters]: self.log.debug("Candidate filtered out\n") time.sleep(self.repeatSecs) else: # filters passed, so now feed the candidate into the predictor # and retrieve a new estimate of the correlation self.predictor.addCandidate(candidate) self.clock.correlation = self.predictor.predictCorrelation( ) # act on it self.log.debug("Candidate accepted. New Correlation = ", self.clock.correlation) time.sleep(self.repeatSecs) else: self.log.debug("Response timeout\n")
wallClock=wallClock, clock=ptsTimeline, speedSource=ptsTimeline) temiSource = SimpleClockTimelineSource("urn:dvb:css:timeline:temi:1:1", wallClock=wallClock, clock=temiTimeline, speedSource=ptsTimeline) tsServer.attachTimelineSource(ptsSource) tsServer.attachTimelineSource(temiSource) wcServer.start() cherrypy.engine.start() try: while True: time.sleep(30) temiTimeline.setAvailability(False) tsServer.updateAllClients() time.sleep(30) temiTimeline.setAvailability(True) tsServer.updateAllClients() except KeyboardInterrupt: pass finally: cherrypy.engine.exit() wcServer.stop()
def pausePtsClock(): """Pauses the PTS clock and adjusts the correlation to make it as if it paused at the current tick value""" ptsClock.rebaseCorrelationAtTicks(ptsClock.ticks) ptsClock.speed = 0.0 def unpausePtsClock(): """Unpauses the PTS clock and adjusts the correlation so the ticks continue to increase form this point forward.""" ptsClock.correlation = ( ptsClock.getParent().ticks, ptsClock.correlation[1] ) ptsClock.speed = 1.0 try: while True: tsServer.updateAllClients() time.sleep(5) tweakPtsClock() tsServer.updateAllClients() print "Tweaked correlation timestamp for PTS and TEMI." print "PTS clock at %f (units of seconds)" % (float(ptsClock.ticks)/ptsClock.tickRate) time.sleep(5) tsServer.removeTimelineSource(sporadicTimeline) tsServer.updateAllClients() print "Made timeline "+sporadicTimeline._timelineSelector+" unavailable." time.sleep(5) pausePtsClock() tsServer.updateAllClients() print "Paused the PTS and TEMI timelines." print "PTS clock at %f (units of seconds)" % (float(ptsClock.ticks)/ptsClock.tickRate)
def run(self): monotonic_time.sleep(self.sleepArg)
print "Will double clock speed halfway through" threading.Thread(target=threadrun).start() sleepUntil(tClock, tClock.ticks + 500) tClock.speed = 2 print "Speed doubled" sleepUntil(tClock, tClock.ticks + 600) def go(message): print "Scheduled task ran. Message was: "+message print "Scheduling call back in 2 seconds..." args = ["huzzah!"] runAt(tClock, tClock.ticks + 400, go, args) time.sleep(5) print "Now same again, but with all callbacks scheduled in advance" tClock.slew = 0 def doAdjust(amount): tClock.slew = amount print"Adjusted tClock frequency by +100 Hz" now=tClock.ticks for i in range(1,11): args = ["Tick "+str(100*i)] runAt(tClock, now+100*i, go, args) args=[100] runAt(tClock, now+500, doAdjust, args)
cherrypy.engine.start() dummyContentIds = [ "dvb://233a.1004.1044;363a~20130218T0915Z--PT00H45M", "dvb://233a.1168.122a;1aa4~20130218T0910Z--PT00H30M", "dvb://233a.1050.1008;9fd~20130218T0920Z--PT00H50M", ] # we're going to pretend to be hopping channels every few seconds, # going through a brief 2 second "transitioniong" presentationStatus ciiServer.updateClients(sendOnlyDiff=True) try: while True: for contentId in dummyContentIds: ciiServer.cii.contentId = contentId ciiServer.cii.contentIdStatus = "final" ciiServer.cii.presentationStatus = ["transitioning"] ciiServer.updateClients(sendOnlyDiff=True) time.sleep(2) ciiServer.cii.contentIdStatus = "final" ciiServer.cii.presentationStatus = ["okay"] ciiServer.updateClients(sendOnlyDiff=True) time.sleep(5) except KeyboardInterrupt: pass finally: cherrypy.engine.exit()
if args.quiet: logging.disable(logging.CRITICAL) else: logging.basicConfig(level=args.loglevel[0]) cii = CIIClient(ciiUrl) # logger for outputting messages ciiClientLogger = logging.getLogger("CIIClient") # attach callbacks to generate notifications cii.onConnected = makeCallback("connected") cii.onDisconnected = makeCallback("disconnected") cii.onError = makeCallback("error") for name in CII.allProperties(): funcname = "on" + name[0].upper() + name[1:] + "Change" callback = makePropertyChangeCallback(name) setattr(cii, funcname, callback) # specific handler for when a CII 'change' notification callback fires def onChange(changes): ciiClientLogger.info("CII is now: " + str(cii.cii)) cii.onChange = onChange # connect and goto sleep. All callback activity happens in the websocket's own thread cii.connect() while True: time.sleep(1)
if args.quiet: logging.disable(logging.CRITICAL) else: logging.basicConfig(level=args.loglevel[0]) #first we'll create a clock to represent the wall clock sysclock = SysClock(tickRate=1000000000) wallClock = CorrelatedClock(sysclock, tickRate=1000000000) # we'll also create the algorithm object that adjusts the clock and controls # how often requests are made to the server. algorithm = LowestDispersionCandidate(wallClock, repeatSecs=1, timeoutSecs=0.5) # finally we create the client and start it. wc_client = WallClockClient(bind, dest, wallClock, algorithm) wc_client.start() n = 0 while True: time.sleep(0.2) print "Time=%20d microseconds. Dispersion = %15.3f milliseconds" % ( wallClock.ticks * 1000000 / wallClock.tickRate, wc_client.algorithm.getCurrentDispersion() / 1000000) n = n + 1 if n >= 25: print "*** Worst dispersion over previous 5 seconds = %15.3f milliseconds" % ( wc_client.algorithm.getWorstDispersion() / 1000000) n = 0
def FilterAndPredict(clock,repeatSecs=1.0,timeoutSecs=0.2,filters=[],predictor=PredictSimple()): """\ Combines zero, one or more Filters and a Predictor and returns an algorithm for a WallClockClient. :param clock: A :class:`~dvbcss.clock.CorrelatedClock` object that will be adjusted to match the Wall Clock. :param repeatSecs: (:class:`float`) The rate at which Wall Clock protocol requests are to be sent (in seconds). :param timeoutSecs: (:class:`float`) The timeout on waiting for responses to requests (in seconds). :param filters: (:class:`list` of Filters) A list of zero, one or more Filters :param predictor: (Predictor) The Predictor to use. :returns: An algorithm object embodying the filtering and prediction process, that is suitable to be passed to a :class:`~dvbcss.protocol.client.wc.WallClockClient`. This algorithm controls the :class:`~dvbcss.clock.CorrelatedClock` object by settings its :data:`~dvbcss.clock.CorrelatedClock.correlation` property to (0,offset) where `offset` is provided by the predictor. The parent of this clock is the clock used by the :class:`~dvbcss.protocol.client.wc.WallClockClient` in generating the measurement candidates. So the job of the predictor is always to estimate the current absolute offset between that clock and the wall clock of the server. Requests are made at the repetition rate specified. If a response is received within the timeout period it is then it is transformed into a measurement candidate and passed to the filters. Filters are applied in the order you list them. If a candidate survives filtering, then it is passed to the predictor. Every time a candidate is provided to the predictor, the offset returned by the predictor replaces the previous offset. .. note:: The Clock object must be :mod:`~dvbcss.clock.CorrelatedClock` whose parent is the clock object provided to the WallClockClient object with which this algorithm is used. *It must not be the same clock object.* However both must have the same tick rate. If the same clock object is used or different tick rates are used then the Wall Clock will not synchronise correctly.. The tick rate of the Clock can be any tick rate (it does not have to be one tick per nanosecond), but too low a tick rate will limit clock synchronisation precision. """ log=logging.getLogger("dvbcss.protocol.client.wc.algorithm.FilterAndPredict") prevOffset=0 while True: candidate=(yield timeoutSecs) if candidate is not None: # apply filters if None in [f.checkCandidate(candidate['nanos']) for f in filters]: log.debug("Candidate filtered out\n") time.sleep(repeatSecs) else: # filters passed, so now feed the candidate into the predictor # and retrieve a new estimate of the offset predictor.addCandidate(candidate['nanos']) offsetNanos=predictor.predictOffset() offsetTicks=round(offsetNanos * clock.tickRate / 1000000000.0) # act on it log.debug("Candidate accepted. Predicted offset (ticks)=%20d delta (ticks)=%20d\n" % (offsetTicks, offsetTicks-prevOffset)) clock.correlation=(0,offsetTicks) prevOffset=offsetTicks time.sleep(repeatSecs) else: log.debug("Response timeout\n")
timelines = [ TimelineOption("urn:dvb:css:timeline:pts", unitsPerTick=1, unitsPerSecond=90000), TimelineOption("urn:dvb:css:timeline:temi:1:1", unitsPerTick=1, unitsPerSecond=50) ] ) ptsTimeline = CorrelatedClock(parentClock=wallClock, tickRate=90000, correlation=(wallClock.ticks, 0)) temiTimeline = CorrelatedClock(parentClock=ptsTimeline, tickRate=50, correlation=(0,0)) ptsSource = SimpleClockTimelineSource("urn:dvb:css:timeline:pts", wallClock=wallClock, clock=ptsTimeline, speedSource=ptsTimeline) temiSource = SimpleClockTimelineSource("urn:dvb:css:timeline:temi:1:1", wallClock=wallClock, clock=temiTimeline, speedSource=ptsTimeline) tsServer.attachTimelineSource(ptsSource) tsServer.attachTimelineSource(temiSource) wcServer.start() cherrypy.engine.start() try: while True: time.sleep(1) except KeyboardInterrupt: pass finally: cherrypy.engine.exit() wcServer.stop()
print "Connecting, requesting timeline for:" print " Any contentId beginning with:",contentIdStem print " and using timeline selector: ",timelineSelector print ts = TSClientClockController(tsUrl, contentIdStem, timelineSelector, timelineClock, correlationChangeThresholdSecs=0.001) exiting=False tsClientLogger = logging.getLogger("TSClient") def reportCallback(msg,exit=False): def callback(*a,**k): global exiting tsClientLogger.info(msg+"\n") if exit: exiting=True wc_client.stop() sys.exit(0) return callback ts.onConnected = reportCallback("connected") ts.onDisconnected = reportCallback("disconnected",exit=True) ts.onTimelineAvailable = reportCallback("timeline became available") ts.onTimelineUnavailable = reportCallback("timeline became un-available") ts.onTimingChange = reportCallback("change in timing and/or play speed") ts.connect() while not exiting: time.sleep(0.4) print ts.getStatusSummary(), print " Uncertainty (dispersion) = +/- %0.3f milliseconds" % (algorithm.getCurrentDispersion()/1000000.0)
print "Will double clock speed halfway through" threading.Thread(target=threadrun).start() sleepUntil(tClock, tClock.ticks + 500) tClock.speed = 2 print "Speed doubled" sleepUntil(tClock, tClock.ticks + 600) def go(message): print "Scheduled task ran. Message was: " + message print "Scheduling call back in 2 seconds..." args = ["huzzah!"] runAt(tClock, tClock.ticks + 400, go, args) time.sleep(5) print "Now same again, but with all callbacks scheduled in advance" tClock.slew = 0 def doAdjust(amount): tClock.slew = amount print "Adjusted tClock frequency by +100 Hz" now = tClock.ticks for i in range(1, 11): args = ["Tick " + str(100 * i)] runAt(tClock, now + 100 * i, go, args) args = [100] runAt(tClock, now + 500, doAdjust, args)