Mercurial > libervia-web
annotate libervia/web/pages/calls/_browser/webrtc.py @ 1616:6bfeb9f0fb84
browser (calls): conferences implementation:
- Handle A/V conferences calls creation/joining by entering a conference room JID in the
search box.
- Group call box has been improved and is used both for group calls (small number of
participants) and A/V conferences (larger number of participants).
- Fullscreen button for group call is working.
- Avatar/user nickname are shown in group call on peer user, as an overlay on video
stream.
- Use `user` metadata when present to display the right user avatar/name when receiving a
stream from SFU (i.e. A/V conference).
- Peer user have a new 3 dots menu with a `pin` item to (un)pin it (i.e. display it on
full container with on top).
- Updated webrtc to handle unidirectional streams correctly and to adapt to A/V conference
specification.
rel 448
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 07 Aug 2024 00:01:57 +0200 |
parents | 4a9679369856 |
children |
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 |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
5 from browser import aio, console as log, document, window, DOMNode |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
6 import dialog |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
7 from javascript import JSObject, NULL |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
8 import jid |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
9 from js_modules.cbor_x import CBOR |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
10 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
11 log.warning = log.warn |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
12 profile = window.profile or "" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
13 bridge = Bridge() |
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 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
16 class FileSender: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
17 CHUNK_SIZE = 64 * 1024 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
18 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
19 def __init__(self, session_id, file, data_channel): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
20 self.session_id = session_id |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
21 self.file = file |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
22 self.data_channel = data_channel |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
23 data_channel.bind("open", self._on_open) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
24 self.offset = 0 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
25 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
26 def _on_open(self, __): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
27 log.info(f"Data channel open, starting to send {self.file.name}.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
28 self.send_file() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
29 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
30 def _on_reader_load(self, event): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
31 self.data_channel.send(event.target.result) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
32 self.offset += self.CHUNK_SIZE |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
33 self.send_file() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
34 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
35 def send_file(self): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
36 if self.offset < self.file.size: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
37 chunk = self.file.slice(self.offset, self.offset + self.CHUNK_SIZE) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
38 reader = window.FileReader.new() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
39 reader.onload = self._on_reader_load |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
40 reader.readAsArrayBuffer(chunk) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
41 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
42 log.info(f"file {self.file.name} sent.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
43 self.data_channel.close() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
44 if self.session_id is not None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
45 aio.run(bridge.call_end(self.session_id, "")) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
46 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
47 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
48 class FileReceiver: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
49 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
50 def __init__(self, session_id: str, data_channel, extra_data: dict) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
51 """Initializes the file receiver with a data channel. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
52 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
53 @param data_channel: The RTCDataChannel through which file data is received. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
54 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
55 self.session_id = session_id |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
56 self.data_channel = data_channel |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
57 self.received_chunks = [] |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
58 self.file_data = extra_data.get("file_data", {}) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
59 data_channel.bind("message", self._on_message) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
60 data_channel.bind("close", self._on_close) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
61 log.debug("File receiver created.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
62 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
63 def _on_message(self, event) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
64 """Handles incoming message events from the data channel. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
65 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
66 @param event: The event containing the data chunk. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
67 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
68 self.received_chunks.append(event.data) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
69 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
70 def _on_close(self, __) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
71 """Handles the data channel's close event. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
72 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
73 Assembles the received chunks into a Blob and triggers a file download. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
74 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
75 # The file is complete, we assemble the chunks in a blob |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
76 blob = window.Blob.new(self.received_chunks) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
77 url = window.URL.createObjectURL(blob) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
78 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
79 # and create the <a> element to download the file. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
80 a = document.createElement("a") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
81 a.href = url |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
82 a.download = self.file_data.get("name", "received_file") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
83 document.body.appendChild(a) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
84 a.click() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
85 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
86 # We now clean up. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
87 document.body.removeChild(a) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
88 window.URL.revokeObjectURL(url) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
89 log.info("File received.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
90 aio.run(bridge.call_end(self.session_id, "")) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
91 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
92 |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
93 class RemoteControler: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
94 """Send input events to controlled device""" |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
95 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
96 def __init__( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
97 self, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
98 session_id: str, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
99 capture_elt: DOMNode, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
100 data_channel: JSObject, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
101 simulate_mouse: bool = True |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
102 ) -> None: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
103 """Initialize a RemoteControler instance. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
104 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
105 @param session_id: ID of the Jingle Session |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
106 @param capture_elt: element where the input events are captured. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
107 @param data_channel: WebRTCDataChannel instance linking to controlled device. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
108 @simulate_mouse: if True, touch event will be converted to mouse events. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
109 """ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
110 self.session_id = session_id |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
111 self.capture_elt = capture_elt |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
112 self.capture_elt.bind("click", self._on_capture_elt_click) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
113 self.data_channel = data_channel |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
114 data_channel.bind("open", self._on_open) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
115 self.simulate_mouse = simulate_mouse |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
116 self.last_mouse_position = (0, 0) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
117 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
118 def _on_capture_elt_click(self, __): |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
119 self.capture_elt.focus() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
120 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
121 def _on_open(self, __): |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
122 log.info(f"Data channel open, starting to send inputs.") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
123 self.start_capture() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
124 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
125 def start_capture(self) -> None: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
126 """Start capturing input events to send them to the controlled device.""" |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
127 for event_name in [ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
128 "mousedown", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
129 "mouseup", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
130 "mousemove", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
131 "keydown", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
132 "keyup", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
133 "touchstart", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
134 "touchend", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
135 "touchmove", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
136 "wheel", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
137 ]: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
138 self.capture_elt.bind(event_name, self._send_event) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
139 self.capture_elt.focus() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
140 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
141 def get_stream_coordinates(self, client_x: float, client_y: float) -> tuple[float, float]: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
142 """Calculate coordinates relative to the actual video stream. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
143 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
144 This method calculates the coordinates relative to the video content inside the <video> |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
145 element, considering any scaling or letterboxing due to aspect ratio differences. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
146 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
147 @param client_x: The clientX value from the event, relative to the viewport. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
148 @param client_y: The clientY value from the event, relative to the viewport. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
149 @return: The x and y coordinates relative to the actual video stream. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
150 """ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
151 video_element = self.capture_elt |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
152 video_rect = video_element.getBoundingClientRect() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
153 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
154 # Calculate offsets relative to the capture element |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
155 element_x = client_x - video_rect.left |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
156 element_y = client_y - video_rect.top |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
157 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
158 element_width, element_height = video_rect.width, video_rect.height |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
159 stream_width, stream_height = video_element.videoWidth, video_element.videoHeight |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
160 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
161 if not all((element_width, element_height, stream_width, stream_height)): |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
162 log.warning("Invalid dimensions for video or element, using offsets.") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
163 return element_x, element_y |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
164 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
165 element_aspect_ratio = element_width / element_height |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
166 stream_aspect_ratio = stream_width / stream_height |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
167 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
168 # Calculate scale and offset based on aspect ratio comparison |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
169 if stream_aspect_ratio > element_aspect_ratio: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
170 # Video is more "wide" than the element: letterboxes will be top and bottom |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
171 scale = element_width / stream_width |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
172 scaled_height = stream_height * scale |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
173 offset_x, offset_y = 0, (element_height - scaled_height) / 2 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
174 else: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
175 # Video is more "tall" than the element: letterboxes will be on the sides |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
176 scale = element_height / stream_height |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
177 scaled_width = stream_width * scale |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
178 offset_x, offset_y = (element_width - scaled_width) / 2, 0 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
179 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
180 # Mouse coordinates relative to the video stream |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
181 x = (element_x - offset_x) / scale |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
182 y = (element_y - offset_y) / scale |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
183 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
184 # Ensure the coordinates are within the bounds of the video stream |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
185 x = max(0.0, min(x, stream_width)) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
186 y = max(0.0, min(y, stream_height)) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
187 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
188 return x, y |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
189 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
190 def _send_event(self, event: JSObject) -> None: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
191 """Serialize and send the event to the controlled device through the data channel.""" |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
192 event.preventDefault() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
193 serialized_event = self._serialize_event(event) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
194 # TODO: we should join events instead |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
195 self.data_channel.send(CBOR.encode(serialized_event)) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
196 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
197 def _serialize_event(self, event: JSObject) -> dict[str, object]: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
198 """Serialize event data for transmission. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
199 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
200 @param event: an input event. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
201 @return: event data to send to peer. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
202 """ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
203 if event.type.startswith("key"): |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
204 ret = { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
205 "type": event.type, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
206 "key": event.key, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
207 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
208 if event.location: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
209 ret["location"] = event.location |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
210 return ret |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
211 elif event.type.startswith("mouse"): |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
212 x, y = self.get_stream_coordinates(event.clientX, event.clientY) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
213 return { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
214 "type": event.type, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
215 "buttons": event.buttons, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
216 "x": x, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
217 "y": y, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
218 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
219 elif event.type.startswith("touch"): |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
220 touches = [ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
221 { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
222 "identifier": touch.identifier, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
223 **dict(zip(["x", "y"], self.get_stream_coordinates( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
224 touch.clientX, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
225 touch.clientY |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
226 ))), |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
227 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
228 for touch in event.touches |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
229 ] |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
230 if self.simulate_mouse: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
231 # In simulate mouse mode, we send mouse events. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
232 if touches: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
233 touch_data = touches[0] |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
234 x, y = touch_data["x"], touch_data["y"] |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
235 self.last_mouse_position = (x, y) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
236 else: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
237 x, y = self.last_mouse_position |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
238 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
239 mouse_event: dict[str, object] = { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
240 "x": x, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
241 "y": y, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
242 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
243 if event.type == "touchstart": |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
244 mouse_event.update({ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
245 "type": "mousedown", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
246 "buttons": 1, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
247 }) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
248 elif event.type == "touchend": |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
249 mouse_event.update({ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
250 "type": "mouseup", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
251 "buttons": 1, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
252 }) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
253 elif event.type == "touchmove": |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
254 mouse_event.update({ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
255 "type": "mousemove", |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
256 }) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
257 return mouse_event |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
258 else: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
259 # Normal mode, with send touch events. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
260 return { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
261 "type": event.type, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
262 "touches": touches |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
263 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
264 elif event.type == "wheel": |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
265 return { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
266 "type": event.type, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
267 "deltaX": event.deltaX, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
268 "deltaY": event.deltaY, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
269 "deltaZ": event.deltaZ, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
270 "deltaMode": event.deltaMode, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
271 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
272 else: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
273 raise Exception(f"Internal Error: unexpected event {event.type=}") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
274 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
275 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
276 class WebRTC: |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
277 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
278 def __init__( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
279 self, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
280 screen_sharing_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
281 on_connection_established_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
282 on_reconnect_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
283 on_connection_lost_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
284 on_video_devices=None, |
1565
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
285 on_reset_cb=None, |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
286 file_only: bool = False, |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
287 extra_data: dict | None = None, |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
288 local_video_elt = None, |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
289 remote_video_elt = None, |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
290 local_stream = None |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
291 ): |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
292 """Initialise WebRTC instance. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
293 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
294 @param screen_sharing_cb: callable function for screen sharing event |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
295 @param on_connection_established_cb: callable function for connection established |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
296 event |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
297 @param on_reconnect_cb: called when a reconnection is triggered. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
298 @param on_connection_lost_cb: called when the connection is lost. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
299 @param on_video_devices: called when new video devices are set. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
300 @param on_reset_cb: called on instance reset. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
301 @param file_only: indicates a file transfer only session. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
302 @param extra_data: optional dictionary containing additional data. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
303 Notably used for file transfer, where ``file_data`` key is used. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
304 """ |
1565
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
305 # reset |
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
306 self.on_reset_cb = on_reset_cb |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
307 self.reset_instance() |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
308 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
309 # ICE events |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
310 bridge.register_signal("ice_candidates_new", self._on_ice_candidates_new) |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
311 bridge.register_signal("ice_restart", self._on_ice_restart) |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
312 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
313 # connection events callbacks |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
314 self.on_connection_established_cb = on_connection_established_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
315 self.on_reconnect_cb = on_reconnect_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
316 self.on_connection_lost_cb = on_connection_lost_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
317 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
318 # video devices |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
319 self.on_video_devices = on_video_devices |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
320 self.video_devices = [] |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
321 self.has_multiple_cameras = False |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
322 self.current_camera = None |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
323 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
324 self.file_only = file_only |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
325 if not file_only: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
326 # Initially populate the video devices list |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
327 aio.run(self._populate_video_devices()) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
328 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
329 # video elements |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
330 self.local_video_elt = local_video_elt |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
331 assert remote_video_elt is not None |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
332 self.remote_video_elt = remote_video_elt |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
333 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
334 self.file_sender = None |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
335 |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
336 self.local_stream = local_stream |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
337 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
338 # muting |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
339 self.is_audio_muted = None |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
340 self.is_video_muted = None |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
341 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
342 # screen sharing |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
343 self._is_sharing_screen = False |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
344 self.screen_sharing_cb = screen_sharing_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
345 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
346 # extra |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
347 if extra_data is None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
348 extra_data = {} |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
349 self.extra_data = extra_data |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
350 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
351 @property |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
352 def is_sharing_screen(self) -> bool: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
353 return self._is_sharing_screen |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
354 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
355 @is_sharing_screen.setter |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
356 def is_sharing_screen(self, sharing: bool) -> None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
357 if sharing != self._is_sharing_screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
358 self._is_sharing_screen = sharing |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
359 if self.screen_sharing_cb is not None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
360 self.screen_sharing_cb(sharing) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
361 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
362 def reset_instance(self): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
363 """Inits or resets the instance variables to their default state.""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
364 self._peer_connection = None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
365 self._media_types = None |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
366 self._media_types_inv = None |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
367 self.ufrag = None |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
368 self.pwd = None |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
369 self.sid = None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
370 self.local_candidates = None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
371 self.remote_stream = None |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
372 self.remote_candidates_buffer = { |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
373 "audio": {"candidates": []}, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
374 "video": {"candidates": []}, |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
375 "application": {"candidates": []}, |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
376 } |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
377 self.local_candidates_buffer = {} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
378 self.media_candidates = {} |
1565
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
379 if self.on_reset_cb is not None: |
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
380 self.on_reset_cb() |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
381 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
382 async def _populate_video_devices(self): |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
383 devices = await window.navigator.mediaDevices.enumerateDevices() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
384 devices_ids = set() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
385 self.video_devices.clear() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
386 for device in devices: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
387 if device.kind != "videoinput": |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
388 continue |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
389 # we can have multiple devices with same IDs in some corner cases (e.g. |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
390 # infrared camera) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
391 device_id = device.deviceId |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
392 if device_id in devices_ids: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
393 continue |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
394 devices_ids.add(device_id) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
395 self.video_devices.append(device) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
396 self.has_multiple_cameras = len(self.video_devices) > 1 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
397 if self.on_video_devices is not None: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
398 self.on_video_devices(self.has_multiple_cameras) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
399 # Set the initial camera to the default (usually front on mobile) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
400 if self.video_devices: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
401 self.current_camera = self.video_devices[0].deviceId |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
402 log.debug( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
403 f"devices populated: {self.video_devices=} {self.has_multiple_cameras=}" |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
404 ) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
405 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
406 @property |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
407 def media_types(self): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
408 if self._media_types is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
409 raise Exception("self._media_types should not be None!") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
410 return self._media_types |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
411 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
412 @media_types.setter |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
413 def media_types(self, new_media_types: dict) -> None: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
414 self._media_types = new_media_types |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
415 self._media_types_inv = {v: k for k, v in new_media_types.items()} |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
416 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
417 @property |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
418 def media_types_inv(self) -> dict: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
419 if self._media_types_inv is None: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
420 raise Exception("self._media_types_inv should not be None!") |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
421 return self._media_types_inv |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
422 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
423 def get_sdp_mline_index(self, media_type): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
424 """Gets the sdpMLineIndex for a given media type. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
425 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
426 @param media_type: The type of the media. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
427 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
428 for index, m_type in self.media_types.items(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
429 if m_type == media_type: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
430 return index |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
431 raise ValueError(f"Media type '{media_type}' not found") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
432 |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
433 def extract_ufrag_pwd(self, sdp: str) -> tuple[str, str]: |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
434 """Retrieves ICE password and user fragment for SDP offer. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
435 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
436 @param sdp: The Session Description Protocol offer string. |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
437 @return: ufrag and pwd |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
438 @raise ValueError: Can't extract ufrag and password |
1517
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 ufrag_line = re.search(r"ice-ufrag:(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
441 pwd_line = re.search(r"ice-pwd:(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
442 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
443 if ufrag_line and pwd_line: |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
444 ufrag = self.ufrag = ufrag_line.group(1) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
445 pwd = self.pwd = pwd_line.group(1) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
446 return ufrag, pwd |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
447 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
448 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
|
449 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
|
450 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
451 def extract_fingerprint_data(self, sdp): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
452 """Retrieves fingerprint data from an SDP offer. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
453 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
454 @param sdp: The Session Description Protocol offer string. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
455 @return: A dictionary containing the fingerprint data. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
456 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
457 fingerprint_line = re.search(r"a=fingerprint:(\S+)\s+(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
458 if fingerprint_line: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
459 algorithm, fingerprint = fingerprint_line.groups() |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
460 fingerprint_data = {"hash": algorithm, "fingerprint": fingerprint} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
461 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
462 setup_line = re.search(r"a=setup:(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
463 if setup_line: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
464 setup = setup_line.group(1) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
465 fingerprint_data["setup"] = setup |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
466 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
467 return fingerprint_data |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
468 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
469 raise ValueError("fingerprint should not be missing") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
470 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
471 def parse_ice_candidate(self, candidate_string): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
472 """Parses the ice candidate string. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
473 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
474 @param candidate_string: The ice candidate string to be parsed. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
475 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
476 pattern = re.compile( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
477 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
|
478 r"(?P<priority>\d+) (?P<address>\S+) (?P<port>\d+) typ " |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
479 r"(?P<type>\S+)(?: raddr (?P<rel_addr>\S+) rport " |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
480 r"(?P<rel_port>\d+))?(?: generation (?P<generation>\d+))?" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
481 ) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
482 match = pattern.match(candidate_string) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
483 if match: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
484 candidate_dict = match.groupdict() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
485 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
486 # Apply the correct types to the dictionary values |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
487 candidate_dict["component_id"] = int(candidate_dict["component_id"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
488 candidate_dict["priority"] = int(candidate_dict["priority"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
489 candidate_dict["port"] = int(candidate_dict["port"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
490 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
491 if candidate_dict["rel_port"]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
492 candidate_dict["rel_port"] = int(candidate_dict["rel_port"]) |
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 if candidate_dict["generation"]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
495 candidate_dict["generation"] = candidate_dict["generation"] |
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 # Remove None values |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
498 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
|
499 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
500 log.warning(f"can't parse candidate: {candidate_string!r}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
501 return None |
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 def build_ice_candidate(self, parsed_candidate): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
504 """Builds ICE candidate |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
505 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
506 @param parsed_candidate: Dictionary containing parsed ICE candidate |
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 base_format = ( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
509 "candidate:{foundation} {component_id} {transport} {priority} " |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
510 "{address} {port} typ {type}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
511 ) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
512 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
513 if parsed_candidate.get("rel_addr") and parsed_candidate.get("rel_port"): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
514 base_format += " raddr {rel_addr} rport {rel_port}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
515 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
516 if parsed_candidate.get("generation"): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
517 base_format += " generation {generation}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
518 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
519 return base_format.format(**parsed_candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
520 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
521 def on_ice_candidate(self, event): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
522 """Handles ICE candidate event |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
523 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
524 @param event: Event containing the ICE candidate |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
525 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
526 log.debug(f"on ice candidate {event.candidate=}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
527 if event.candidate and event.candidate.candidate: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
528 parsed_candidate = self.parse_ice_candidate(event.candidate.candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
529 if parsed_candidate is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
530 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
531 try: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
532 media_type = self.media_types[event.candidate.sdpMLineIndex] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
533 except (TypeError, IndexError): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
534 log.error( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
535 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
|
536 ) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
537 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
538 self.media_candidates.setdefault(media_type, []).append(parsed_candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
539 log.debug(f"ICE candidate [{media_type}]: {event.candidate.candidate}") |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
540 if self.sid is None: |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
541 log.debug("buffering candidate") |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
542 self.local_candidates_buffer.setdefault(media_type, []).append( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
543 parsed_candidate |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
544 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
545 else: |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
546 ufrag, pwd = self.extract_ufrag_pwd( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
547 self._peer_connection.localDescription.sdp |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
548 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
549 |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
550 ice_data = {"ufrag": ufrag, "pwd": pwd, "candidates": [parsed_candidate]} |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
551 aio.run( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
552 bridge.ice_candidates_add( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
553 self.sid, json.dumps({media_type: ice_data}) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
554 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
555 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
556 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
557 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
558 log.debug("All ICE candidates gathered") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
559 |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
560 def on_ice_connection_state_change(self, event): |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
561 """Log ICE connection change, mainly used for debugging""" |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
562 state = self._peer_connection.iceConnectionState |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
563 log.info(f"ICE Connection State changed to: {state}") |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
564 |
1561
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
565 if state == "connected": |
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
566 if self.on_connection_established_cb is not None: |
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
567 self.on_connection_established_cb() |
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
568 elif state == "failed": |
1563
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
569 log.error( |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
570 "ICE connection failed. Check network connectivity and ICE" |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
571 " configurations." |
1563
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
572 ) |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
573 elif state == "disconnected": |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
574 log.warning("ICE connection was disconnected.") |
1561
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
575 if self.on_connection_lost_cb is not None: |
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
576 self.on_connection_lost_cb() |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
577 |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
578 def on_ice_candidate_error(self, event): |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
579 """Log ICE error, useful for debugging""" |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
580 log.error(f"ICE Candidate Error: {event.errorText} (Code: {event.errorCode})") |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
581 log.debug( |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
582 f"URL: {event.url}, Host candidate: {event.hostCandidate}, Port: {event.port}" |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
583 ) |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
584 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
585 def _set_media_types(self, offer): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
586 """Sets media types from offer SDP |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
587 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
588 @param offer: RTC session description containing the offer |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
589 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
590 sdp_lines = offer.sdp.splitlines() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
591 media_types = {} |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
592 mline_index = 0 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
593 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
594 for line in sdp_lines: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
595 if line.startswith("m="): |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
596 media_types[mline_index] = line[2 : line.find(" ")] |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
597 mline_index += 1 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
598 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
599 self.media_types = media_types |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
600 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
601 def on_ice_gathering_state_change(self, event): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
602 """Handles ICE gathering state change |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
603 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
604 @param event: Event containing the ICE gathering state change |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
605 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
606 connection = event.target |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
607 log.debug(f"on_ice_gathering_state_change {connection.iceGatheringState=}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
608 if connection.iceGatheringState == "complete": |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
609 log.info("ICE candidates gathering done") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
610 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
611 async def _create_peer_connection( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
612 self, |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
613 ) -> JSObject: |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
614 """Creates peer connection""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
615 if self._peer_connection is not None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
616 raise Exception("create_peer_connection can't be called twice!") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
617 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
618 external_disco = json.loads(await bridge.external_disco_get("")) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
619 ice_servers = [] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
620 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
621 for server in external_disco: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
622 ice_server = {} |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
623 if server["type"] == "stun": |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
624 ice_server["urls"] = f"stun:{server['host']}:{server['port']}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
625 elif server["type"] == "turn": |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
626 ice_server["urls"] = ( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
627 f"turn:{server['host']}:{server['port']}?transport={server['transport']}" |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
628 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
629 ice_server["username"] = server["username"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
630 ice_server["credential"] = server["password"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
631 ice_servers.append(ice_server) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
632 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
633 rtc_configuration = {"iceServers": ice_servers} |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
634 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
635 peer_connection = window.RTCPeerConnection.new(rtc_configuration) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
636 peer_connection.addEventListener("track", self.on_track) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
637 peer_connection.addEventListener("negotiationneeded", self.on_negotiation_needed) |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
638 peer_connection.addEventListener( |
1563
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
639 "iceconnectionstatechange", self.on_ice_connection_state_change |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
640 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
641 peer_connection.addEventListener("icecandidate", self.on_ice_candidate) |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
642 peer_connection.addEventListener("icecandidateerror", self.on_ice_candidate_error) |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
643 peer_connection.addEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
644 "icegatheringstatechange", self.on_ice_gathering_state_change |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
645 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
646 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
647 self._peer_connection = peer_connection |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
648 window.pc = self._peer_connection |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
649 return peer_connection |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
650 |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
651 async def _get_user_media( |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
652 self, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
653 audio: bool = True, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
654 video: bool = True, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
655 direction: str = "sendrecv" |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
656 ) -> None: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
657 """ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
658 Gets user media (camera and microphone). |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
659 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
660 @param audio: True if an audio flux is required. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
661 @param video: True if a video flux is required. |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
662 @param direction: The direction of the stream ('sendonly', 'recvonly', 'sendrecv', |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
663 or 'inactive') |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
664 """ |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
665 media_constraints = {"audio": audio, "video": video} |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
666 if self.local_stream is None: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
667 self.local_stream = await window.navigator.mediaDevices.getUserMedia( |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
668 media_constraints |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
669 ) |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
670 |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
671 if not self.local_stream: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
672 log.error("Failed to get the media stream.") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
673 return |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
674 |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
675 if self.local_video_elt is not None: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
676 self.local_video_elt.srcObject = self.local_stream |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
677 |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
678 if direction != "recvonly": |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
679 for track in self.local_stream.getTracks(): |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
680 sender = self._peer_connection.addTransceiver(track, { |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
681 'direction': direction, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
682 'streams': [self.local_stream] |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
683 }) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
684 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
685 async def _replace_user_video( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
686 self, |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
687 screen: bool = False, |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
688 ) -> JSObject | None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
689 """Replaces the user video track with either a camera or desktop sharing track. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
690 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
691 @param screen: True if desktop sharing is required. False will use the camera. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
692 @return: The local media stream or None if failed. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
693 """ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
694 if screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
695 media_constraints = {"video": {"cursor": "always"}} |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
696 new_stream = await window.navigator.mediaDevices.getDisplayMedia( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
697 media_constraints |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
698 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
699 else: |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
700 if self.local_video_elt is not None and self.local_video_elt.srcObject: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
701 for track in self.local_video_elt.srcObject.getTracks(): |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
702 if track.kind == "video": |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
703 track.stop() |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
704 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
705 media_constraints = { |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
706 "video": ( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
707 {"deviceId": self.current_camera} if self.current_camera else True |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
708 ) |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
709 } |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
710 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
711 new_stream = await window.navigator.mediaDevices.getUserMedia( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
712 media_constraints |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
713 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
714 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
715 if not new_stream: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
716 log.error("Failed to get the media stream.") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
717 return None |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
718 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
719 new_video_tracks = [ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
720 track for track in new_stream.getTracks() if track.kind == "video" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
721 ] |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
722 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
723 if not new_video_tracks: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
724 log.error("Failed to retrieve the video track from the new stream.") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
725 return None |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
726 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
727 # Retrieve the current local stream's video track. |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
728 if self.local_video_elt is None: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
729 local_stream = None |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
730 else: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
731 local_stream = self.local_video_elt.srcObject |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
732 if local_stream: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
733 local_video_tracks = [ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
734 track for track in local_stream.getTracks() if track.kind == "video" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
735 ] |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
736 if local_video_tracks: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
737 # Remove the old video track and add the new one to the local stream. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
738 local_stream.removeTrack(local_video_tracks[0]) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
739 local_stream.addTrack(new_video_tracks[0]) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
740 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
741 video_sender = next( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
742 ( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
743 sender |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
744 for sender in self._peer_connection.getSenders() |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
745 if sender.track and sender.track.kind == "video" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
746 ), |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
747 None, |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
748 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
749 if video_sender: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
750 await video_sender.replaceTrack(new_video_tracks[0]) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
751 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
752 if screen: |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
753 # For screen sharing, we track the end event to properly stop the sharing |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
754 # when the user clicks on the browser's stop sharing dialog. |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
755 def on_track_ended(event): |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
756 aio.run(self.toggle_screen_sharing()) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
757 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
758 new_video_tracks[0].bind("ended", on_track_ended) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
759 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
760 self.is_sharing_screen = screen |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
761 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
762 return local_stream |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
763 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
764 async def switch_camera(self) -> None: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
765 """Switches to the next available camera. |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
766 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
767 This method cycles through the list of available video devices, replaces the |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
768 current video track with the next one in the user's local video element, and then |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
769 updates the sender's track in the peer connection. If there's only one camera or |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
770 if an error occurs while switching, the method logs the error and does nothing. |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
771 """ |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
772 log.info("switching camera") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
773 if not self.has_multiple_cameras: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
774 log.error("No multiple cameras to switch.") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
775 return |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
776 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
777 current_camera_index = -1 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
778 for i, device_info in enumerate(self.video_devices): |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
779 if device_info.deviceId == self.current_camera: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
780 current_camera_index = i |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
781 break |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
782 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
783 if current_camera_index == -1: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
784 log.error("Current camera not found in available devices.") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
785 return |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
786 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
787 # Switch to the next camera in the list |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
788 next_camera_index = (current_camera_index + 1) % len(self.video_devices) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
789 self.current_camera = self.video_devices[next_camera_index].deviceId |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
790 log.debug(f"{next_camera_index=} {self.current_camera=}") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
791 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
792 new_stream = await window.navigator.mediaDevices.getUserMedia( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
793 {"video": {"deviceId": self.current_camera}} |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
794 ) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
795 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
796 new_video_tracks = [ |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
797 track for track in new_stream.getTracks() if track.kind == "video" |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
798 ] |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
799 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
800 if not new_video_tracks: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
801 log.error("Failed to retrieve the video track from the new stream.") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
802 return |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
803 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
804 # Update local video element's stream |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
805 if self.local_video_elt is None: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
806 local_stream = None |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
807 else: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
808 local_stream = self.local_video_elt.srcObject |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
809 if local_stream: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
810 local_video_tracks = [ |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
811 track for track in local_stream.getTracks() if track.kind == "video" |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
812 ] |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
813 if local_video_tracks: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
814 local_video_tracks[0].stop() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
815 local_stream.removeTrack(local_video_tracks[0]) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
816 local_stream.addTrack(new_video_tracks[0]) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
817 self.local_video_elt.srcObject = local_stream |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
818 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
819 # update remove video stream |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
820 video_sender = next( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
821 ( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
822 sender |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
823 for sender in self._peer_connection.getSenders() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
824 if sender.track and sender.track.kind == "video" |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
825 ), |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
826 None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
827 ) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
828 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
829 if video_sender: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
830 await video_sender.replaceTrack(new_video_tracks[0]) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
831 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
832 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
|
833 """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
|
834 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
835 @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
|
836 @param remote_candidates: Remote ICE candidates, if any |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
837 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
838 if self._peer_connection is None: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
839 raise Exception( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
840 "The peer connection must be created before gathering ICE candidates!" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
841 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
842 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
843 self.media_candidates.clear() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
844 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
845 if is_initiator: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
846 offer = await self._peer_connection.createOffer() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
847 self._set_media_types(offer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
848 await self._peer_connection.setLocalDescription(offer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
849 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
850 answer = await self._peer_connection.createAnswer() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
851 self._set_media_types(answer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
852 await self._peer_connection.setLocalDescription(answer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
853 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
854 if not is_initiator: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
855 log.debug(self._peer_connection.localDescription.sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
856 log.debug(self._peer_connection.localDescription.sdp) |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
857 ufrag, pwd = self.extract_ufrag_pwd(self._peer_connection.localDescription.sdp) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
858 return { |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
859 "ufrag": ufrag, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
860 "pwd": pwd, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
861 "candidates": self.media_candidates, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
862 } |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
863 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
864 async def accept_call(self, session_id: str, sdp: str, profile: str) -> None: |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
865 """Call has been accepted, connection can be established |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
866 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
867 @param session_id: Session identifier |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
868 @param sdp: Session Description Protocol data |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
869 @param profile: Profile associated |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
870 """ |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
871 await self._peer_connection.setRemoteDescription({"type": "answer", "sdp": sdp}) |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
872 await self.on_ice_candidates_new(self.remote_candidates_buffer) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
873 self.remote_candidates_buffer.clear() |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
874 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
875 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
|
876 """Called when new ICE candidates are received |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
877 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
878 @param sid: Session identifier |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
879 @param candidates_s: ICE candidates serialized |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
880 @param profile: Profile associated with the action |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
881 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
882 if sid != self.sid: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
883 log.debug(f"ignoring peer ice candidates for {sid=} ({self.sid=}).") |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
884 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
885 candidates = json.loads(candidates_s) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
886 aio.run(self.on_ice_candidates_new(candidates)) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
887 |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
888 def _on_ice_restart(self, sid: str, side: str, profile: str): |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
889 if sid != self.sid: |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
890 log.debug(f"ignoring peer ice candidates for {sid=} ({self.sid=}).") |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
891 return |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
892 log.debug("ICE has been restarted") |
1561
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
893 if self.on_reconnect_cb is not None: |
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
894 self.on_reconnect_cb() |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
895 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
896 async def on_ice_candidates_new(self, candidates: dict) -> None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
897 """Called when new ICE canidates are received from peer |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
898 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
899 @param candidates: Dictionary containing new ICE candidates |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
900 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
901 log.debug(f"new peer candidates received: {candidates}") |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
902 |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
903 # try: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
904 # # FIXME: javascript.NULL must be used here, once we move to Brython 3.12.3+ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
905 # remoteDescription_is_none = self._peer_connection.remoteDescription is None |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
906 # except Exception as e: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
907 # # FIXME: should be fine in Brython 3.12.3+ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
908 # log.debug("Workaround for Brython bug activated.") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
909 # remoteDescription_is_none = True |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
910 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
911 if ( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
912 self._peer_connection is None |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
913 or self._peer_connection.remoteDescription is NULL |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
914 ): |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
915 for media_type in ("audio", "video", "application"): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
916 media_candidates = candidates.get(media_type) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
917 if media_candidates: |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
918 buffer = self.remote_candidates_buffer[media_type] |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
919 buffer["candidates"].extend(media_candidates["candidates"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
920 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
921 for media_type, ice_data in candidates.items(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
922 for candidate in ice_data["candidates"]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
923 candidate_sdp = self.build_ice_candidate(candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
924 try: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
925 sdp_mline_index = self.get_sdp_mline_index(media_type) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
926 except Exception as e: |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
927 log.warning(f"Can't get sdp_mline_index: {e}") |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
928 continue |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
929 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
930 ice_candidate = window.RTCIceCandidate.new( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
931 {"candidate": candidate_sdp, "sdpMLineIndex": sdp_mline_index} |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
932 ) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
933 await self._peer_connection.addIceCandidate(ice_candidate) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
934 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
935 def on_track(self, event): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
936 """New track has been received from peer |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
937 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
938 @param event: Event associated with the new track |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
939 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
940 if event.streams and event.streams[0]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
941 remote_stream = event.streams[0] |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
942 self.remote_video_elt.srcObject = remote_stream |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
943 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
944 if self.remote_stream is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
945 self.remote_stream = window.MediaStream.new() |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
946 self.remote_video_elt.srcObject = self.remote_stream |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
947 self.remote_stream.addTrack(event.track) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
948 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
949 def on_negotiation_needed(self, event) -> None: |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
950 log.debug("on_negotiation_needed") |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
951 # TODO |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
952 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
953 def _on_data_channel(self, event) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
954 """Handles the data channel event from the peer connection. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
955 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
956 @param event: The event associated with the opening of a data channel. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
957 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
958 data_channel = event.channel |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
959 self.file_receiver = FileReceiver(self.sid, data_channel, self.extra_data) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
960 |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
961 async def answer_call( |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
962 self, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
963 sid: str, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
964 offer_sdp: str, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
965 profile: str, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
966 conference: bool = False |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
967 ): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
968 """We respond to the call""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
969 log.debug("answering call") |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
970 if sid != self.sid: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
971 raise Exception(f"Internal Error: unexpected sid: {sid=} {self.sid=}") |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
972 await self._create_peer_connection() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
973 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
974 await self._peer_connection.setRemoteDescription( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
975 {"type": "offer", "sdp": offer_sdp} |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
976 ) |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
977 await self.on_ice_candidates_new(self.remote_candidates_buffer) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
978 self.remote_candidates_buffer.clear() |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
979 if self.file_only: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
980 self._peer_connection.bind("datachannel", self._on_data_channel) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
981 else: |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
982 await self._get_user_media( |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
983 direction="recvonly" if conference else "sendrecv" |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
984 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
985 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
986 # Gather local ICE candidates |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
987 local_ice_data = await self._gather_ice_candidates(False) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
988 self.local_candidates = local_ice_data["candidates"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
989 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
990 await bridge.call_answer_sdp(sid, self._peer_connection.localDescription.sdp) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
991 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
992 async def _get_call_data(self) -> dict: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
993 """Start a WebRTC call""" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
994 await self._gather_ice_candidates(True) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
995 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
996 return {"sdp": self._peer_connection.localDescription.sdp} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
997 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
998 async def _send_buffered_local_candidates(self) -> None: |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
999 if self.local_candidates_buffer: |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1000 log.debug( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1001 f"sending buffered local ICE candidates: {self.local_candidates_buffer}" |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1002 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1003 assert self.pwd is not None |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1004 ice_data = {} |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1005 for media_type, candidates in self.local_candidates_buffer.items(): |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1006 ice_data[media_type] = { |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1007 "ufrag": self.ufrag, |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1008 "pwd": self.pwd, |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1009 "candidates": candidates, |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1010 } |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1011 await bridge.ice_candidates_add( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1012 self.sid, |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1013 json.dumps(ice_data), |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1014 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1015 self.local_candidates_buffer.clear() |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1016 |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1017 async def prepare_call( |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1018 self, |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1019 audio: bool = True, |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1020 video: bool = True, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1021 direction: str = "sendrecv" |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1022 ) -> dict: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1023 """Prepare a call. |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1024 |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1025 Create RTCPeerConnection instance, and get use media. |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1026 |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1027 @param audio: True if an audio flux is required |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1028 @param video: True if a video flux is required |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1029 @return: Call Data |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1030 """ |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1031 await self._create_peer_connection() |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1032 await self._get_user_media(audio, video, direction) |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1033 return await self._get_call_data() |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1034 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1035 async def make_call( |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1036 self, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1037 callee_jid: jid.JID, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1038 audio: bool = True, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1039 video: bool = True, |
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1040 direction: str = "sendrecv" |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1041 ) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1042 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1043 @param audio: True if an audio flux is required |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1044 @param video: True if a video flux is required |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1045 """ |
1616
6bfeb9f0fb84
browser (calls): conferences implementation:
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1046 call_data = await self.prepare_call(audio, video, direction) |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1047 log.info(f"calling {callee_jid!r}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1048 self.sid = await bridge.call_start(str(callee_jid), json.dumps(call_data)) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1049 log.debug(f"Call SID: {self.sid}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1050 await self._send_buffered_local_candidates() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1051 |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1052 async def start_remote_control( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1053 self, callee_jid: jid.JID, audio: bool = True, video: bool = True |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1054 ) -> None: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1055 """Starts a Remote Control session. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1056 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1057 If both audio and video are False, no screenshare will be done, the input will be |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1058 sent without feedback. |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1059 @param audio: True if an audio flux is required |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1060 @param video: True if a video flux is required |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1061 """ |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1062 if audio or not video: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1063 raise NotImplementedError("Only video screenshare is supported for now.") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1064 peer_connection = await self._create_peer_connection() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1065 if video: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1066 peer_connection.addTransceiver("video", {"direction": "recvonly"}) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1067 data_channel = peer_connection.createDataChannel("remote-control") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1068 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1069 call_data = await self._get_call_data() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1070 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1071 try: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1072 remote_control_data = json.loads( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1073 await bridge.remote_control_start( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1074 str(callee_jid), |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1075 json.dumps( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1076 { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1077 "devices": { |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1078 "keyboard": {}, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1079 "mouse": {}, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1080 "wheel": {} |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1081 }, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1082 "call_data": call_data, |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1083 } |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1084 ), |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1085 ) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1086 ) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1087 except Exception as e: |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1088 dialog.notification.show(f"Can't start remote control: {e}", level="error") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1089 return |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1090 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1091 self.sid = remote_control_data["session_id"] |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1092 |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1093 log.debug(f"Remote Control SID: {self.sid}") |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1094 await self._send_buffered_local_candidates() |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1095 self.remote_controller = RemoteControler( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1096 self.sid, self.remote_video_elt, data_channel |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1097 ) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1098 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1099 def _on_opened_data_channel(self, event): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1100 log.info("Datachannel has been opened.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1101 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1102 async def send_file(self, callee_jid: jid.JID, file: JSObject) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1103 assert self.file_only |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1104 peer_connection = await self._create_peer_connection() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1105 data_channel = peer_connection.createDataChannel("file") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1106 call_data = await self._get_call_data() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1107 log.info(f"sending file to {callee_jid!r}") |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1108 file_meta = {"size": file.size} |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1109 if file.type: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1110 file_meta["media_type"] = file.type |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1111 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1112 try: |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1113 file_data = json.loads( |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1114 await bridge.file_jingle_send( |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1115 str(callee_jid), |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1116 "", |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1117 file.name, |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1118 "", |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1119 json.dumps({"webrtc": True, "call_data": call_data, **file_meta}), |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1120 ) |
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1121 ) |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1122 except Exception as e: |
1602
6feac4a25e60
browser: Remote Control implementation:
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
1123 dialog.notification.show(f"Can't send file: {e}", level="error") |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1124 return |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1125 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1126 self.sid = file_data["session_id"] |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1127 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1128 log.debug(f"File Transfer SID: {self.sid}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1129 await self._send_buffered_local_candidates() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1130 self.file_sender = FileSender(self.sid, file, data_channel) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
1131 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1132 async def end_call(self) -> None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1133 """Stop streaming and clean instance""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1134 if self._peer_connection is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1135 log.debug("There is currently no call to end.") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1136 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1137 self._peer_connection.removeEventListener("track", self.on_track) |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1138 self._peer_connection.removeEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1139 "negotiationneeded", self.on_negotiation_needed |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1140 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1141 self._peer_connection.removeEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1142 "icecandidate", self.on_ice_candidate |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1143 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1144 self._peer_connection.removeEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1145 "icegatheringstatechange", self.on_ice_gathering_state_change |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1146 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1147 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1148 # Base64 encoded 1x1 black pixel image |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1149 # this is a trick to reset the image displayed, so we don't see last image of |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1150 # last stream |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1151 black_image_data = ( |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1152 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0" |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1153 "lEQVR42mP8/wcAAwAB/uzNq7sAAAAASUVORK5CYII=" |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1154 ) |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1155 |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1156 remote_video = self.remote_video_elt |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1157 local_video = self.local_video_elt |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1158 if local_video is not None: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1159 if local_video.srcObject: |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1160 for track in local_video.srcObject.getTracks(): |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1161 track.stop() |
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1162 local_video.src = black_image_data |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1163 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1164 if remote_video.srcObject: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1165 for track in remote_video.srcObject.getTracks(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1166 track.stop() |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1167 remote_video.src = black_image_data |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1168 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1169 self._peer_connection.close() |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1170 self.reset_instance() |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1171 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1172 def toggle_media_mute(self, media_type: str) -> bool: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1173 """Toggle mute/unmute for media tracks. |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1174 |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1175 @param media_type: "audio" or "video". Determines which media tracks |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
1176 to process. |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1177 """ |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1178 assert media_type in ("audio", "video"), "Invalid media type" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1179 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1180 local_video = self.local_video_elt |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1181 is_muted_attr = f"is_{media_type}_muted" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1182 |
1604
4a9679369856
browser (call): implements group calls:
Goffi <goffi@goffi.org>
parents:
1602
diff
changeset
|
1183 if local_video is not None and local_video.srcObject: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1184 track_getter = getattr( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1185 local_video.srcObject, f"get{media_type.capitalize()}Tracks" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1186 ) |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1187 for track in track_getter(): |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1188 track.enabled = not track.enabled |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1189 setattr(self, is_muted_attr, not track.enabled) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1190 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1191 media_name = self.media_types_inv.get(media_type) |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1192 if media_name is not None: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1193 extra = {"name": str(media_name)} |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1194 aio.run( |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1195 bridge.call_info( |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1196 self.sid, |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1197 "mute" if getattr(self, is_muted_attr) else "unmute", |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1198 json.dumps(extra), |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1199 ) |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1200 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1201 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1202 return getattr(self, is_muted_attr) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1203 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1204 def toggle_audio_mute(self) -> bool: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1205 """Toggle mute/unmute for audio tracks.""" |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1206 return self.toggle_media_mute("audio") |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1207 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1208 def toggle_video_mute(self) -> bool: |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1209 """Toggle mute/unmute for video tracks.""" |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
1210 return self.toggle_media_mute("video") |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1211 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1212 async def toggle_screen_sharing(self): |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1213 log.debug(f"toggle_screen_sharing {self._is_sharing_screen=}") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1214 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1215 if self._is_sharing_screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1216 await self._replace_user_video(screen=False) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1217 else: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
1218 await self._replace_user_video(screen=True) |