Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/source/avsync_mixin.py : 100%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2010-2020 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7from xpra.util import envint, typedict
8from xpra.server.source.stub_source_mixin import StubSourceMixin
9from xpra.log import Logger
11log = Logger("av-sync")
13AV_SYNC_DELTA = envint("XPRA_AV_SYNC_DELTA", 0)
14DEFAULT_AV_SYNC_DELAY = envint("XPRA_DEFAULT_AV_SYNC_DELAY", 150)
17class AVSyncMixin(StubSourceMixin):
19 @classmethod
20 def is_needed(cls, caps : typedict) -> bool:
21 if not (caps.boolget("sound.send") or caps.boolget("sound.receive")):
22 #no audio!
23 return False
24 return caps.boolget("av-sync") and caps.boolget("windows")
27 def __init__(self):
28 self.av_sync = False
30 def init_from(self, _protocol, server):
31 self.av_sync = server.av_sync
33 def cleanup(self):
34 self.init_state()
36 def init_state(self):
37 self.av_sync_enabled = False
38 self.av_sync_delay = 0
39 self.av_sync_delay_total = 0
40 self.av_sync_delta = AV_SYNC_DELTA
43 def get_info(self) -> dict:
44 return {
45 "av-sync" : {
46 "" : self.av_sync,
47 "enabled" : self.av_sync_enabled,
48 "client" : self.av_sync_delay,
49 "total" : self.av_sync_delay_total,
50 "delta" : self.av_sync_delta,
51 },
52 }
54 def parse_client_caps(self, c : typedict):
55 av_sync = c.boolget("av-sync")
56 self.av_sync_enabled = self.av_sync and av_sync
57 self.set_av_sync_delay(int(self.av_sync_enabled) * c.intget("av-sync.delay.default", DEFAULT_AV_SYNC_DELAY))
58 log("av-sync: server=%s, client=%s, enabled=%s, total=%s",
59 self.av_sync, av_sync, self.av_sync_enabled, self.av_sync_delay_total)
62 def set_av_sync_delta(self, delta):
63 log("set_av_sync_delta(%i)", delta)
64 self.av_sync_delta = delta
65 self.update_av_sync_delay_total()
67 def set_av_sync_delay(self, v):
68 #update all window sources with the given delay
69 self.av_sync_delay = v
70 self.update_av_sync_delay_total()
72 def update_av_sync_delay_total(self):
73 if self.av_sync:
74 encoder_latency = self.get_sound_source_latency()
75 self.av_sync_delay_total = min(1000, max(0, int(self.av_sync_delay) + self.av_sync_delta + encoder_latency))
76 log("av-sync set to %ims (from client queue latency=%s, encoder latency=%s, delta=%s)",
77 self.av_sync_delay_total, self.av_sync_delay, encoder_latency, self.av_sync_delta)
78 else:
79 log("av-sync support is disabled, setting it to 0")
80 self.av_sync_delay_total = 0
81 for ws in self.window_sources.values():
82 ws.set_av_sync_delay(self.av_sync_delay_total)
85 ##########################################################################
86 # sound control commands:
87 def sound_control_sync(self, delay_str):
88 assert self.av_sync, "av-sync is not enabled"
89 self.set_av_sync_delay(int(delay_str))
90 return "av-sync delay set to %ims" % self.av_sync_delay
92 def sound_control_av_sync_delta(self, delta_str):
93 assert self.av_sync, "av-sync is not enabled"
94 self.set_av_sync_delta(int(delta_str))
95 return "av-sync delta set to %ims" % self.av_sync_delta