Ticket #849: sound-autotune-queue.patch
File sound-autotune-queue.patch, 7.7 KB (added by , 6 years ago) |
---|
-
xpra/sound/sink.py
4 4 # Xpra is released under the terms of the GNU GPL v2, or, at your option, any 5 5 # later version. See the file COPYING for details. 6 6 7 import sys, os , time7 import sys, os 8 8 9 9 from xpra.sound.sound_pipeline import SoundPipeline, gobject, one_arg_signal 10 10 from xpra.sound.pulseaudio_util import has_pa … … 46 46 DEFAULT_SINK = SINKS[0] 47 47 QUEUE_SILENT = 0 48 48 QUEUE_TIME = get_queue_time(450) 49 QUEUE_MIN_TIME = get_queue_time(QUEUE_TIME//10//MS_TO_NS, "MIN")50 assert QUEUE_MIN_TIME<=QUEUE_TIME51 49 52 VARIABLE_MIN_QUEUE = os.environ.get("XPRA_VARIABLE_MIN_QUEUE", "1")=="1"53 54 55 50 GST_FORMAT_BUFFERS = 4 56 51 57 52 def sink_has_device_attribute(sink): … … 94 89 pipeline_els.append("volume name=volume volume=%s" % volume) 95 90 queue_el = ["queue", 96 91 "name=queue", 97 "min-threshold-time= %s" % QUEUE_MIN_TIME,92 "min-threshold-time=0", 98 93 "max-size-buffers=0", 99 94 "max-size-bytes=0", 100 95 "max-size-time=%s" % QUEUE_TIME, … … 131 126 def queue_pushing(self, *args): 132 127 ltime = self.queue.get_property("current-level-time")/MS_TO_NS 133 128 log("queue pushing: level=%i", ltime) 129 self.check_levels() 134 130 self.queue_state = "pushing" 135 self.emit_info() 131 #self.emit_info() 132 return 0 136 133 137 134 def queue_running(self, *args): 138 135 ltime = self.queue.get_property("current-level-time")/MS_TO_NS 139 136 log("queue running: level=%s", ltime) 140 if self.queue_state=="underrun" and VARIABLE_MIN_QUEUE: 137 self.check_levels() 138 self.queue_state = "running" 139 return 0 140 141 def check_levels(self): 142 if True: 143 return 144 if self.queue_state=="underrun": 141 145 #lift min time restrictions: 142 146 self.queue.set_property("min-threshold-time", 0) 143 147 elif self.queue_state == "overrun": 144 148 clt = self.queue.get_property("current-level-time") 145 149 qpct = min(QUEUE_TIME, clt)*100//QUEUE_TIME 146 log ("resetting max-size-time back to %ims (level=%ims, %i%%)", QUEUE_TIME//MS_TO_NS, clt//MS_TO_NS, qpct)150 log.info("resetting max-size-time back to %ims (level=%ims, %i%%)", QUEUE_TIME//MS_TO_NS, clt//MS_TO_NS, qpct) 147 151 self.queue.set_property("max-size-time", QUEUE_TIME) 148 152 self.queue_state = "running" 149 153 self.emit_info() 150 154 155 151 156 def queue_underrun(self, *args): 157 if self.queue_state=="underrun" or self.queue_state=="starting": 158 return 152 159 ltime = self.queue.get_property("current-level-time")/MS_TO_NS 153 log("queue underrun: level=%i", ltime) 154 if self.queue_state!="underrun" and VARIABLE_MIN_QUEUE: 155 #lift min time restrictions: 156 self.queue.set_property("min-threshold-time", QUEUE_MIN_TIME) 160 log.info("queue underrun: level=%i, previous state=%s", ltime, self.queue_state) 157 161 self.queue_state = "underrun" 158 self.emit_info() 162 MIN_QUEUE = QUEUE_TIME//2 163 mts = self.queue.get_property("min-threshold-time") 164 if mts==MIN_QUEUE: 165 return 0 166 #set min time restrictions to fill up queue: 167 log.info("increasing the min-threshold-time to %ims", MIN_QUEUE//MS_TO_NS) 168 self.queue.set_property("min-threshold-time", MIN_QUEUE) 169 def restore(): 170 if self.queue.get_property("min-threshold-time")==0: 171 log.info("min-threshold-time already restored!") 172 return False 173 ltime = self.queue.get_property("current-level-time")//MS_TO_NS 174 if ltime==0: 175 log.info("not restored! (still underrun: %ims)", ltime) 176 return True 177 log.info("resetting the min-threshold-time back to %ims", 0) 178 self.queue.set_property("min-threshold-time", 0) 179 self.queue_state = "running" 180 return False 181 import glib 182 glib.timeout_add(1000, restore) 183 #self.emit_info() 184 return 0 159 185 160 186 def queue_overrun(self, *args): 187 if self.queue_state=="overrun": 188 return 161 189 ltime = self.queue.get_property("current-level-time")//MS_TO_NS 162 pqs = self.queue_state190 log("queue overrun: level=%i, previous state=%s", ltime, self.queue_state) 163 191 self.queue_state = "overrun" 164 #no overruns for the first 2 seconds: 165 if ltime<QUEUE_TIME//MS_TO_NS//2*75//100: 166 elapsed = time.time()-self.start_time 167 log("queue overrun ignored: level=%i, elapsed time=%.1f", ltime, elapsed) 168 return 169 log("queue overrun: level=%i, previous state=%s", ltime//MS_TO_NS, pqs) 170 if pqs!="overrun": 171 log("halving the max-size-time to %ims", QUEUE_TIME//2//MS_TO_NS) 172 self.queue.set_property("max-size-time", QUEUE_TIME//2) 173 self.overruns += 1 174 self.emit("overrun", ltime) 175 self.emit_info() 192 REDUCED_QT = QUEUE_TIME//2 193 #empty the queue by reducing its max size: 194 log.info("queue overrun: halving the max-size-time to %ims", REDUCED_QT//MS_TO_NS) 195 self.queue.set_property("max-size-time", REDUCED_QT) 196 self.overruns += 1 197 self.emit("overrun", ltime) 198 def restore(): 199 if self.queue.get_property("max-size-time")==QUEUE_TIME: 200 log.info("max-size-time already restored!") 201 return False 202 ltime = self.queue.get_property("current-level-time")//MS_TO_NS 203 if ltime>=REDUCED_QT: 204 log.info("max-size-time not restored! (still overrun: %ims)", ltime) 205 return True 206 log.info("raising the max-size-time back to %ims", QUEUE_TIME//MS_TO_NS) 207 self.queue.set_property("max-size-time", QUEUE_TIME) 208 self.queue_state = "running" 209 return False 210 import glib 211 glib.timeout_add(1000, restore) 212 #self.emit_info() 213 return 0 176 214 177 215 def eos(self): 178 216 log("eos()") … … 179 217 if self.src: 180 218 self.src.emit('end-of-stream') 181 219 self.cleanup() 220 return 0 182 221 183 222 def get_info(self): 184 223 info = SoundPipeline.get_info(self) … … 186 225 clt = self.queue.get_property("current-level-time") 187 226 updict(info, "queue", { 188 227 "time" : QUEUE_TIME//MS_TO_NS, 189 "min_time" : QUEUE_MIN_TIME//MS_TO_NS,190 228 "used_pct" : min(QUEUE_TIME, clt)*100//QUEUE_TIME, 191 229 "used" : clt//MS_TO_NS, 192 230 "overruns" : self.overruns, … … 197 235 if not self.src: 198 236 log("add_data(..) dropped") 199 237 return 238 if self.queue_state=="overrun": 239 log.info("add_data(..) queue in overrun, data dropped") 240 return 200 241 #having a timestamp causes problems with the queue and overruns: 201 242 if "timestamp" in metadata: 202 243 del metadata["timestamp"] -
xpra/sound/src.py
16 16 from xpra.log import Logger 17 17 log = Logger("sound") 18 18 19 APPSINK = os.environ.get("XPRA_SOURCE_APPSINK", "appsink name=sink emit-signals=true max-buffers=10 drop=true sync= false async=false qos=false")19 APPSINK = os.environ.get("XPRA_SOURCE_APPSINK", "appsink name=sink emit-signals=true max-buffers=10 drop=true sync=true async=false qos=false") 20 20 21 21 22 22 class SoundSource(SoundPipeline):