Mercurial > code > home > repos > light9
changeset 944:3b3cc5f98a03
vidref use async http client for talking to asco and CC. No more blocking the gst thread to learn curvecalc time
Ignore-this: d6564b13cb68581b3416fd4efaaf261b
author | drewp@bigasterisk.com |
---|---|
date | Thu, 13 Jun 2013 02:21:37 +0000 |
parents | 3aae87f6777a |
children | 85ccda959170 |
files | light9/vidref/musictime.py light9/vidref/videorecorder.py |
diffstat | 2 files changed, 71 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/light9/vidref/musictime.py Thu Jun 13 01:44:05 2013 +0000 +++ b/light9/vidref/musictime.py Thu Jun 13 02:21:37 2013 +0000 @@ -1,6 +1,7 @@ import restkit, time, json, logging from light9 import networking -from threading import Thread +from twisted.internet import reactor +from cyclone.httpclient import fetch from restkit.errors import ResourceNotFound import http_parser.http log = logging.getLogger() @@ -21,18 +22,20 @@ end of a song) """ self.period = period + self.hoverPeriod = .05 self.onChange = onChange self.musicResource = restkit.Resource(networking.musicPlayer.url) - self.curveCalc = restkit.Resource(networking.curveCalc.url) - t = Thread(target=self._timeUpdate) - t.setDaemon(True) - t.start() + + self.position = {} + self.lastHoverTime = None # None means "no recent value" + self.pollMusicTime() + self.pollCurvecalcTime() def getLatest(self): """ dict with 't' and 'song', etc. - Note that this may be called in a gst camera capture thread. + Note that this may be called in a gst camera capture thread. Very often. """ if not hasattr(self, 'position'): return {'t' : 0, 'song' : None} @@ -40,34 +43,73 @@ if pos['playing']: pos['t'] = pos['t'] + (time.time() - self.positionFetchTime) else: - try: - # todo: this is blocking for a long while if CC is - # down. Either make a tiny timeout, or go async - r = self.curveCalc.get("hoverTime") - except (ResourceNotFound, http_parser.http.NoMoreData, Exception): - pass - else: - pos['hoverTime'] = json.loads(r.body_string())['hoverTime'] + if self.lastHoverTime is not None: + pos['hoverTime'] = self.lastHoverTime return pos - def _timeUpdate(self): - while True: - try: - position = json.loads(self.musicResource.get("time").body_string()) + def pollMusicTime(self): + def cb(response): + + if response.code != 200: + raise ValueError("%s %s", response.code, response.body) + + position = json.loads(response.body) + + # this is meant to be the time when the server gave me its + # report, and I don't know if that's closer to the + # beginning of my request or the end of it (or some + # fraction of the way through) + self.positionFetchTime = time.time() + + self.position = position + self.onChange(position) + + reactor.callLater(self.period, self.pollMusicTime) + + def eb(err): + log.warn("talking to ascoltami: %s", err.getErrorMessage()) + reactor.callLater(2, self.pollMusicTime) + + d = fetch(networking.musicPlayer.path("time")) + d.addCallback(cb) + d.addErrback(eb) # note this includes errors in cb() + + def pollCurvecalcTime(self): + """ + poll the curvecalc position when music isn't playing, so replay + can track it. - # this is meant to be the time when the server gave me its - # report, and I don't know if that's closer to the - # beginning of my request or the end of it (or some - # fraction of the way through) - self.positionFetchTime = time.time() + This would be better done via rdfdb sync, where changes to the + curvecalc position are written to the curvecalc session and we + can pick them up in here + """ + if self.position.get('playing'): + # don't need this position during playback + self.lastHoverTime = None + reactor.callLater(.2, self.pollCurvecalcTime) + return + + def cb(response): + if response.code == 404: + # not hovering + self.lastHoverTime = None + reactor.callLater(.2, self.pollCurvecalcTime) + return + if response.code != 200: + raise ValueError("%s %s" % (response.code, response.body)) + self.lastHoverTime = json.loads(response.body)['hoverTime'] - self.position = position - self.onChange(position) - except restkit.RequestError, e: - log.error(e) - time.sleep(1) - time.sleep(self.period) + reactor.callLater(self.hoverPeriod, self.pollCurvecalcTime) + def eb(err): + log.warn("talking to curveCalc: %s", err.getErrorMessage()) + self.lastHoverTime = None + reactor.callLater(2, self.pollCurvecalcTime) + + d = fetch(networking.curveCalc.path("hoverTime")) + d.addCallback(cb) + d.addErrback(eb) # note this includes errors in cb() + def sendTime(self, t): """request that the player go to this time""" self.musicResource.post("time", payload=json.dumps({"t" : t}),