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}),
--- a/light9/vidref/videorecorder.py	Thu Jun 13 01:44:05 2013 +0000
+++ b/light9/vidref/videorecorder.py	Thu Jun 13 02:21:37 2013 +0000
@@ -159,7 +159,6 @@
 
     def saveImg(self, position, img, bufferTimestamp):
         if not position['song']:
-            print "no song"
             return 
         
         t1 = time.time()