Mercurial > libervia-web
annotate libervia/web/pages/calls/_browser/__init__.py @ 1545:be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 06 Jul 2023 12:10:25 +0200 |
parents | eb00d593801d |
children | e47c24204449 |
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() |