Hide keyboard shortcuts

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. 

6 

7from xpra.util import envint, typedict 

8from xpra.server.source.stub_source_mixin import StubSourceMixin 

9from xpra.log import Logger 

10 

11log = Logger("av-sync") 

12 

13AV_SYNC_DELTA = envint("XPRA_AV_SYNC_DELTA", 0) 

14DEFAULT_AV_SYNC_DELAY = envint("XPRA_DEFAULT_AV_SYNC_DELAY", 150) 

15 

16 

17class AVSyncMixin(StubSourceMixin): 

18 

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") 

25 

26 

27 def __init__(self): 

28 self.av_sync = False 

29 

30 def init_from(self, _protocol, server): 

31 self.av_sync = server.av_sync 

32 

33 def cleanup(self): 

34 self.init_state() 

35 

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 

41 

42 

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 } 

53 

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) 

60 

61 

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() 

66 

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() 

71 

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) 

83 

84 

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 

91 

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