annotate libervia/pages/calls/_browser/__init__.py @ 1517:b8ed9726525b

browser: "calls" implementation, first draft: Basic page to make a call. Call are automatically accepted for the moment. fix 422
author Goffi <goffi@goffi.org>
date Thu, 01 Jun 2023 21:42:02 +0200
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1517
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 import json
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 import re
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 from bridge import AsyncBridge as Bridge
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
5 from browser import aio, console as log, document, timer, window
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6 import errors
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 import loading
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 log.warning = log.warn
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 profile = window.profile or ""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11 bridge = Bridge()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 GATHER_TIMEOUT = 10000
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 class WebRTCCall:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 def __init__(self):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 self.reset_instance()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 def reset_instance(self):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 """Inits or resets the instance variables to their default state."""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 self._peer_connection = None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 self._media_types = None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 self.sid = None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 self.local_candidates = None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 self.remote_stream = None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 self.candidates_buffer = {
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 "audio": {"candidates": []},
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 "video": {"candidates": []},
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 }
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 self.media_candidates = {}
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 self.candidates_gathered = aio.Future()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
33
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34 @property
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 def media_types(self):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 if self._media_types is None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 raise Exception("self._media_types should not be None!")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 return self._media_types
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
39
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 def get_sdp_mline_index(self, media_type):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 """Gets the sdpMLineIndex for a given media type.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
42
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 @param media_type: The type of the media.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 for index, m_type in self.media_types.items():
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 if m_type == media_type:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 return index
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 raise ValueError(f"Media type '{media_type}' not found")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
49
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 def extract_pwd_ufrag(self, sdp):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 """Retrieves ICE password and user fragment for SDP offer.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 @param sdp: The Session Description Protocol offer string.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 ufrag_line = re.search(r"ice-ufrag:(\S+)", sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 pwd_line = re.search(r"ice-pwd:(\S+)", sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 if ufrag_line and pwd_line:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 return ufrag_line.group(1), pwd_line.group(1)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 log.error(f"SDP with missing ice-ufrag or ice-pwd:\n{sdp}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 raise ValueError("Can't extract ice-ufrag and ice-pwd from SDP")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 def extract_fingerprint_data(self, sdp):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 """Retrieves fingerprint data from an SDP offer.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 @param sdp: The Session Description Protocol offer string.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 @return: A dictionary containing the fingerprint data.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 fingerprint_line = re.search(r"a=fingerprint:(\S+)\s+(\S+)", sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 if fingerprint_line:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 algorithm, fingerprint = fingerprint_line.groups()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 fingerprint_data = {
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 "hash": algorithm,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 "fingerprint": fingerprint
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 }
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
77
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 setup_line = re.search(r"a=setup:(\S+)", sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 if setup_line:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 setup = setup_line.group(1)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 fingerprint_data["setup"] = setup
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 return fingerprint_data
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 raise ValueError("fingerprint should not be missing")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 def parse_ice_candidate(self, candidate_string):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 """Parses the ice candidate string.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
89
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 @param candidate_string: The ice candidate string to be parsed.
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 pattern = re.compile(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 r"candidate:(?P<foundation>\S+) (?P<component_id>\d+) (?P<transport>\S+) "
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 r"(?P<priority>\d+) (?P<address>\S+) (?P<port>\d+) typ "
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 r"(?P<type>\S+)(?: raddr (?P<rel_addr>\S+) rport "
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 r"(?P<rel_port>\d+))?(?: generation (?P<generation>\d+))?"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 match = pattern.match(candidate_string)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 if match:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 candidate_dict = match.groupdict()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 # Apply the correct types to the dictionary values
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 candidate_dict["component_id"] = int(candidate_dict["component_id"])
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 candidate_dict["priority"] = int(candidate_dict["priority"])
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 candidate_dict["port"] = int(candidate_dict["port"])
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 if candidate_dict["rel_port"]:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 candidate_dict["rel_port"] = int(candidate_dict["rel_port"])
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
109
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 if candidate_dict["generation"]:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 candidate_dict["generation"] = candidate_dict["generation"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
112
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 # Remove None values
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 return {k: v for k, v in candidate_dict.items() if v is not None}
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 log.warning(f"can't parse candidate: {candidate_string!r}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 return None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
118
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 def build_ice_candidate(self, parsed_candidate):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
120 """Builds ICE candidate
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
121
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
122 @param parsed_candidate: Dictionary containing parsed ICE candidate
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
124 base_format = (
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 "candidate:{foundation} {component_id} {transport} {priority} "
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 "{address} {port} typ {type}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
128
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
129 if ((parsed_candidate.get('rel_addr')
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
130 and parsed_candidate.get('rel_port'))):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 base_format += " raddr {rel_addr} rport {rel_port}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
132
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 if parsed_candidate.get('generation'):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 base_format += " generation {generation}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
135
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 return base_format.format(**parsed_candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
137
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 def on_ice_candidate(self, event):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 """Handles ICE candidate event
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
140
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 @param event: Event containing the ICE candidate
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
142 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 log.debug(f"on ice candidate {event.candidate=}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 if event.candidate and event.candidate.candidate:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 window.last_event = event
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 parsed_candidate = self.parse_ice_candidate(event.candidate.candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 if parsed_candidate is None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 try:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 media_type = self.media_types[event.candidate.sdpMLineIndex]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 except (TypeError, IndexError):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 log.error(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 f"Can't find media type.\n{event.candidate=}\n{self._media_types=}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
156 self.media_candidates.setdefault(media_type, []).append(parsed_candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 log.debug(f"ICE candidate [{media_type}]: {event.candidate.candidate}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 log.debug("All ICE candidates gathered")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
160
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 def _set_media_types(self, offer):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 """Sets media types from offer SDP
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
163
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 @param offer: RTC session description containing the offer
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
165 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 sdp_lines = offer.sdp.splitlines()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 media_types = {}
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 mline_index = 0
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
169
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
170 for line in sdp_lines:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 if line.startswith("m="):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 media_types[mline_index] = line[2:line.find(" ")]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 mline_index += 1
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
174
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 self._media_types = media_types
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
176
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 def on_ice_gathering_state_change(self, event):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 """Handles ICE gathering state change
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
179
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 @param event: Event containing the ICE gathering state change
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
181 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 connection = event.target
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
183 log.debug(f"on_ice_gathering_state_change {connection.iceGatheringState=}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 if connection.iceGatheringState == "complete":
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 log.info("ICE candidates gathering done")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
186 self.candidates_gathered.set_result(None)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
187
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 async def _create_peer_connection(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 self,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 ):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 """Creates peer connection"""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 if self._peer_connection is not None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 raise Exception("create_peer_connection can't be called twice!")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
194
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
195 external_disco = json.loads(await bridge.external_disco_get(""))
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 ice_servers = []
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
197
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 for server in external_disco:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 ice_server = {}
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 if server["type"] == "stun":
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 ice_server["urls"] = f"stun:{server['host']}:{server['port']}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 elif server["type"] == "turn":
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 ice_server["urls"] = (
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
204 f"turn:{server['host']}:{server['port']}?transport={server['transport']}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 ice_server["username"] = server["username"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 ice_server["credential"] = server["password"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 ice_servers.append(ice_server)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
209
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 rtc_configuration = {"iceServers": ice_servers}
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
211
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 peer_connection = window.RTCPeerConnection.new(rtc_configuration)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
213 peer_connection.addEventListener("track", self.on_track)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 peer_connection.addEventListener("negotiationneeded", self.on_negotiation_needed)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
215 peer_connection.addEventListener("icecandidate", self.on_ice_candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
216 peer_connection.addEventListener("icegatheringstatechange", self.on_ice_gathering_state_change)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
217
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 self._peer_connection = peer_connection
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 window.pc = self._peer_connection
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
220
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 async def _get_user_media(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 self,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 audio: bool = True,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
224 video: bool = True
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 ):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 """Gets user media
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
227
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 @param audio: True if an audio flux is required
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
229 @param video: True if a video flux is required
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 media_constraints = {'audio': audio, 'video': video}
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 local_stream = await window.navigator.mediaDevices.getUserMedia(media_constraints)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 document["local_video"].srcObject = local_stream
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
234
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 for track in local_stream.getTracks():
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 self._peer_connection.addTrack(track)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
237
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 async def _gather_ice_candidates(self, is_initiator: bool, remote_candidates=None):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 """Get ICE candidates and wait to have them all before returning them
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
240
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 @param is_initiator: Boolean indicating if the user is the initiator of the connection
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 @param remote_candidates: Remote ICE candidates, if any
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 if self._peer_connection is None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 raise Exception("The peer connection must be created before gathering ICE candidates!")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
246
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 self.media_candidates.clear()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 gather_timeout = timer.set_timeout(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 lambda: self.candidates_gathered.set_exception(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 errors.TimeoutError("ICE gathering time out")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
251 ),
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
252 GATHER_TIMEOUT
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
253 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
254
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
255 if is_initiator:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
256 offer = await self._peer_connection.createOffer()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
257 self._set_media_types(offer)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
258 await self._peer_connection.setLocalDescription(offer)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
259 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
260 answer = await self._peer_connection.createAnswer()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
261 self._set_media_types(answer)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
262 await self._peer_connection.setLocalDescription(answer)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
263
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
264 if not is_initiator:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
265 log.debug(self._peer_connection.localDescription.sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
266 await self.candidates_gathered
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
267 log.debug(self._peer_connection.localDescription.sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
268 timer.clear_timeout(gather_timeout)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
269 ufrag, pwd = self.extract_pwd_ufrag(self._peer_connection.localDescription.sdp)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
270 return {
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
271 "ufrag": ufrag,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
272 "pwd": pwd,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
273 "candidates": self.media_candidates,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
274 }
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
275
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
276 def on_action_new(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
277 self, action_data_s: str, action_id: str, security_limit: int, profile: str
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
278 ) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
279 """Called when a call is received
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
280
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 @param action_data_s: Action data serialized
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
282 @param action_id: Unique identifier for the action
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
283 @param security_limit: Security limit for the action
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
284 @param profile: Profile associated with the action
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
285 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
286 action_data = json.loads(action_data_s)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
287 if action_data.get("type") != "call":
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
288 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
289 peer_jid = action_data["from_jid"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
290 log.info(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
291 f"{peer_jid} wants to start a call ({action_data['sub_type']})"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
292 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
293 if self.sid is not None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
294 log.warning(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
295 f"already in a call ({self.sid}), can't receive a new call from "
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
296 f"{peer_jid}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
297 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
298 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
299 self.sid = action_data["session_id"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
300 log.debug(f"Call SID: {self.sid}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
301
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
302 # Answer the call
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
303 offer_sdp = action_data["sdp"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
304 aio.run(self.answer_call(offer_sdp, action_id))
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
305
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
306 def _on_call_accepted(self, session_id: str, sdp: str, profile: str) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
307 """Called when we have received answer SDP from responder
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
308
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
309 @param session_id: Session identifier
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
310 @param sdp: Session Description Protocol data
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
311 @param profile: Profile associated with the action
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
312 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
313 aio.run(self.on_call_accepted(session_id, sdp, profile))
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
314
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
315 def _on_call_ended(self, session_id: str, data_s: str, profile: str) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
316 """Call has been terminated
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
317
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
318 @param session_id: Session identifier
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
319 @param data_s: Serialised additional data on why the call has ended
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
320 @param profile: Profile associated
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
321 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
322 if self.sid is None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
323 log.debug("there are no calls in progress")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
324 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
325 if session_id != self.sid:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
326 log.debug(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
327 f"ignoring call_ended not linked to our call ({self.sid}): {session_id}"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
328 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
329 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
330 aio.run(self.end_call())
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
331
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
332 async def on_call_accepted(self, session_id: str, sdp: str, profile: str) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
333 """Call has been accepted, connection can be established
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
334
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
335 @param session_id: Session identifier
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
336 @param sdp: Session Description Protocol data
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
337 @param profile: Profile associated
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
338 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
339 if self.sid != session_id:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
340 log.debug(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
341 f"Call ignored due to different session ID ({self.sid=} {session_id=})"
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
342 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
343 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
344 await self._peer_connection.setRemoteDescription({
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
345 "type": "answer",
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
346 "sdp": sdp
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
347 })
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
348 await self.on_ice_candidates_new(self.candidates_buffer)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
349 self.candidates_buffer.clear()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
350
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
351 def _on_ice_candidates_new(self, sid: str, candidates_s: str, profile: str) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
352 """Called when new ICE candidates are received
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
353
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
354 @param sid: Session identifier
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
355 @param candidates_s: ICE candidates serialized
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
356 @param profile: Profile associated with the action
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
357 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
358 if sid != self.sid:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
359 log.debug(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
360 f"ignoring peer ice candidates for {sid=} ({self.sid=})."
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
361 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
362 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
363 candidates = json.loads(candidates_s)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
364 aio.run(self.on_ice_candidates_new(candidates))
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
365
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
366 async def on_ice_candidates_new(self, candidates: dict) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
367 """Called when new ICE canidates are received from peer
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
368
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
369 @param candidates: Dictionary containing new ICE candidates
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
370 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
371 log.debug(f"new peer candidates received: {candidates}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
372 if (
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
373 self._peer_connection is None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
374 or self._peer_connection.remoteDescription is None
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
375 ):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
376 for media_type in ("audio", "video"):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
377 media_candidates = candidates.get(media_type)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
378 if media_candidates:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
379 buffer = self.candidates_buffer[media_type]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
380 buffer["candidates"].extend(media_candidates["candidates"])
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
381 return
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
382 for media_type, ice_data in candidates.items():
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
383 for candidate in ice_data["candidates"]:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
384 candidate_sdp = self.build_ice_candidate(candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
385 try:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
386 sdp_mline_index = self.get_sdp_mline_index(media_type)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
387 except Exception as e:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
388 log.warning(e)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
389 continue
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
390 ice_candidate = window.RTCIceCandidate.new({
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
391 "candidate": candidate_sdp,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
392 "sdpMLineIndex": sdp_mline_index
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
393 }
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
394 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
395 await self._peer_connection.addIceCandidate(ice_candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
396
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
397 def on_track(self, event):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
398 """New track has been received from peer
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
399
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
400 @param event: Event associated with the new track
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
401 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
402 if event.streams and event.streams[0]:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
403 remote_stream = event.streams[0]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
404 document["remote_video"].srcObject = remote_stream
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
405 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
406 if self.remote_stream is None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
407 self.remote_stream = window.MediaStream.new()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
408 document["remote_video"].srcObject = self.remote_stream
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
409 self.remote_stream.addTrack(event.track)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
410
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
411 document["call_btn"].classList.add("is-hidden")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
412 document["hangup_btn"].classList.remove("is-hidden")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
413
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
414 def on_negotiation_needed(self, event) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
415 log.debug(f"on_negotiation_needed {event=}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
416 # TODO
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
417
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
418 async def answer_call(self, offer_sdp: str, action_id: str):
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
419 """We respond to the call"""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
420 log.debug("answering call")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
421 await self._create_peer_connection()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
422
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
423 await self._peer_connection.setRemoteDescription({
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
424 "type": "offer",
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
425 "sdp": offer_sdp
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
426 })
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
427 await self.on_ice_candidates_new(self.candidates_buffer)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
428 self.candidates_buffer.clear()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
429 await self._get_user_media()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
430
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
431 # Gather local ICE candidates
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
432 local_ice_data = await self._gather_ice_candidates(False)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
433 self.local_candidates = local_ice_data["candidates"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
434
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
435 await bridge.action_launch(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
436 action_id,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
437 json.dumps({
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
438 "sdp": self._peer_connection.localDescription.sdp,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
439 })
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
440 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
441
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
442 async def make_call(self, audio: bool = True, video: bool = True) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
443 """Start a WebRTC call
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
444
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
445 @param audio: True if an audio flux is required
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
446 @param video: True if a video flux is required
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
447 """
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
448 await self._create_peer_connection()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
449 await self._get_user_media(audio, video)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
450 await self._gather_ice_candidates(True)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
451 callee_jid = document["callee_jid"].value
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
452
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
453 call_data = {
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
454 "sdp": self._peer_connection.localDescription.sdp
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
455 }
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
456 log.info(f"calling {callee_jid!r}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
457 self.sid = await bridge.call_start(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
458 callee_jid,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
459 json.dumps(call_data)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
460 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
461 log.debug(f"Call SID: {self.sid}")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
462
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
463 async def end_call(self) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
464 """Stop streaming and clean instance"""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
465 document["hangup_btn"].classList.add("is-hidden")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
466 document["call_btn"].classList.remove("is-hidden")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
467 if self._peer_connection is None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
468 log.debug("There is currently no call to end.")
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
469 else:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
470 self._peer_connection.removeEventListener("track", self.on_track)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
471 self._peer_connection.removeEventListener("negotiationneeded", self.on_negotiation_needed)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
472 self._peer_connection.removeEventListener("icecandidate", self.on_ice_candidate)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
473 self._peer_connection.removeEventListener("icegatheringstatechange", self.on_ice_gathering_state_change)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
474
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
475 local_video = document["local_video"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
476 remote_video = document["remote_video"]
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
477 if local_video.srcObject:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
478 for track in local_video.srcObject.getTracks():
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
479 track.stop()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
480 if remote_video.srcObject:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
481 for track in remote_video.srcObject.getTracks():
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
482 track.stop()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
483
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
484 self._peer_connection.close()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
485 self.reset_instance()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
486
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
487 async def hand_up(self) -> None:
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
488 """Terminate the call"""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
489 session_id = self.sid
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
490 await self.end_call()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
491 await bridge.call_end(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
492 session_id,
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
493 ""
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
494 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
495
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
496
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
497 webrtc_call = WebRTCCall()
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
498
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
499 document["call_btn"].bind(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
500 "click",
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
501 lambda __: aio.run(webrtc_call.make_call())
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
502 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
503 document["hangup_btn"].bind(
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
504 "click",
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
505 lambda __: aio.run(webrtc_call.hand_up())
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
506 )
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
507
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
508 bridge.register_signal("action_new", webrtc_call.on_action_new)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
509 bridge.register_signal("call_accepted", webrtc_call._on_call_accepted)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
510 bridge.register_signal("call_ended", webrtc_call._on_call_ended)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
511 bridge.register_signal("ice_candidates_new", webrtc_call._on_ice_candidates_new)
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
512
b8ed9726525b browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
513 loading.remove_loading_screen()