Mercurial > libervia-web
annotate libervia/web/pages/calls/_browser/webrtc.py @ 1601:d07838fc9d99
minor updates
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 11 May 2024 13:57:49 +0200 |
parents | 0a4433a343a3 |
children | 6feac4a25e60 |
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 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
5 from browser import aio, console as log, document, window |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
6 import dialog |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
7 from javascript import JSObject |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
8 import jid |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
9 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
10 log.warning = log.warn |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
11 profile = window.profile or "" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
12 bridge = Bridge() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
13 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
14 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
15 class FileSender: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
16 CHUNK_SIZE = 64 * 1024 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
17 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
18 def __init__(self, session_id, file, data_channel): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
19 self.session_id = session_id |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
20 self.file = file |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
21 self.data_channel = data_channel |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
22 data_channel.bind("open", self._on_open) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
23 self.offset = 0 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
24 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
25 def _on_open(self, __): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
26 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
|
27 self.send_file() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
28 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
29 def _on_reader_load(self, event): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
30 self.data_channel.send(event.target.result) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
31 self.offset += self.CHUNK_SIZE |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
32 self.send_file() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
33 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
34 def send_file(self): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
35 if self.offset < self.file.size: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
36 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
|
37 reader = window.FileReader.new() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
38 reader.onload = self._on_reader_load |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
39 reader.readAsArrayBuffer(chunk) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
40 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
41 log.info(f"file {self.file.name} sent.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
42 self.data_channel.close() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
43 if self.session_id is not None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
44 aio.run(bridge.call_end(self.session_id, "")) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
45 |
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 class FileReceiver: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
48 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
49 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
|
50 """Initializes the file receiver with a data channel. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
51 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
52 @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
|
53 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
54 self.session_id = session_id |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
55 self.data_channel = data_channel |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
56 self.received_chunks = [] |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
57 self.file_data = extra_data.get("file_data", {}) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
58 data_channel.bind("message", self._on_message) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
59 data_channel.bind("close", self._on_close) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
60 log.debug("File receiver created.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
61 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
62 def _on_message(self, event) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
63 """Handles incoming message events from the data channel. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
64 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
65 @param event: The event containing the data chunk. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
66 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
67 self.received_chunks.append(event.data) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
68 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
69 def _on_close(self, __) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
70 """Handles the data channel's close event. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
71 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
72 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
|
73 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
74 # 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
|
75 blob = window.Blob.new(self.received_chunks) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
76 url = window.URL.createObjectURL(blob) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
77 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
78 # and create the <a> element to download the file. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
79 a = document.createElement("a") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
80 a.href = url |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
81 a.download = self.file_data.get("name", "received_file") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
82 document.body.appendChild(a) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
83 a.click() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
84 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
85 # We now clean up. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
86 document.body.removeChild(a) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
87 window.URL.revokeObjectURL(url) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
88 log.info("File received.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
89 aio.run(bridge.call_end(self.session_id, "")) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
90 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
91 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
92 class WebRTC: |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
93 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
94 def __init__( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
95 self, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
96 screen_sharing_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
97 on_connection_established_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
98 on_reconnect_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
99 on_connection_lost_cb=None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
100 on_video_devices=None, |
1565
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
101 on_reset_cb=None, |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
102 file_only: bool = False, |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
103 extra_data: dict|None = None |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
104 ): |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
105 """Initialise WebRTC instance. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
106 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
107 @param screen_sharing_cb: callable function for screen sharing event |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
108 @param on_connection_established_cb: callable function for connection established event |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
109 @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
|
110 @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
|
111 @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
|
112 @param on_reset_cb: called on instance reset. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
113 @param file_only: indicates a file transfer only session. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
114 @param extra_data: optional dictionary containing additional data. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
115 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
|
116 """ |
1565
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
117 # reset |
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
118 self.on_reset_cb = on_reset_cb |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
119 self.reset_instance() |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
120 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
121 # 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
|
122 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
|
123 bridge.register_signal("ice_restart", self._on_ice_restart) |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
124 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
125 # connection events callbacks |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
126 self.on_connection_established_cb = on_connection_established_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
127 self.on_reconnect_cb = on_reconnect_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
128 self.on_connection_lost_cb = on_connection_lost_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
129 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
130 # video devices |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
131 self.on_video_devices = on_video_devices |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
132 self.video_devices = [] |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
133 self.has_multiple_cameras = False |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
134 self.current_camera = None |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
135 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
136 self.file_only = file_only |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
137 if not file_only: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
138 # Initially populate the video devices list |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
139 aio.run(self._populate_video_devices()) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
140 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
141 # video elements |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
142 self.local_video_elt = document["local_video"] |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
143 self.remote_video_elt = document["remote_video"] |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
144 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
145 self.file_sender = None |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
146 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
147 # muting |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
148 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
|
149 self.is_video_muted = None |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
150 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
151 # screen sharing |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
152 self._is_sharing_screen = False |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
153 self.screen_sharing_cb = screen_sharing_cb |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
154 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
155 # extra |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
156 if extra_data is None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
157 extra_data = {} |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
158 self.extra_data = extra_data |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
159 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
160 @property |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
161 def is_sharing_screen(self) -> bool: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
162 return self._is_sharing_screen |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
163 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
164 @is_sharing_screen.setter |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
165 def is_sharing_screen(self, sharing: bool) -> None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
166 if sharing != self._is_sharing_screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
167 self._is_sharing_screen = sharing |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
168 if self.screen_sharing_cb is not None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
169 self.screen_sharing_cb(sharing) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
170 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
171 def reset_instance(self): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
172 """Inits or resets the instance variables to their default state.""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
173 self._peer_connection = None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
174 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
|
175 self._media_types_inv = None |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
176 self.ufrag = None |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
177 self.pwd = None |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
178 self.sid = None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
179 self.local_candidates = None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
180 self.remote_stream = None |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
181 self.remote_candidates_buffer = { |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
182 "audio": {"candidates": []}, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
183 "video": {"candidates": []}, |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
184 "application": {"candidates": []}, |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
185 } |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
186 self.local_candidates_buffer = {} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
187 self.media_candidates = {} |
1565
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
188 if self.on_reset_cb is not None: |
d282dbdd5ffd
browser (calls): restore UI state on reset:
Goffi <goffi@goffi.org>
parents:
1564
diff
changeset
|
189 self.on_reset_cb() |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
190 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
191 async def _populate_video_devices(self): |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
192 devices = await window.navigator.mediaDevices.enumerateDevices() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
193 devices_ids = set() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
194 self.video_devices.clear() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
195 for device in devices: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
196 if device.kind != "videoinput": |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
197 continue |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
198 # 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
|
199 # infrared camera) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
200 device_id = device.deviceId |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
201 if device_id in devices_ids: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
202 continue |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
203 devices_ids.add(device_id) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
204 self.video_devices.append(device) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
205 self.has_multiple_cameras = len(self.video_devices) > 1 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
206 if self.on_video_devices is not None: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
207 self.on_video_devices(self.has_multiple_cameras) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
208 # 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
|
209 if self.video_devices: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
210 self.current_camera = self.video_devices[0].deviceId |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
211 log.debug( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
212 f"devices populated: {self.video_devices=} {self.has_multiple_cameras=}" |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
213 ) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
214 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
215 @property |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
216 def media_types(self): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
217 if self._media_types is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
218 raise Exception("self._media_types should not be None!") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
219 return self._media_types |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
220 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
221 @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
|
222 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
|
223 self._media_types = new_media_types |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
224 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
|
225 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
226 @property |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
227 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
|
228 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
|
229 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
|
230 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
|
231 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
232 def get_sdp_mline_index(self, media_type): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
233 """Gets the sdpMLineIndex for a given media type. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
234 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
235 @param media_type: The type of the media. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
236 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
237 for index, m_type in self.media_types.items(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
238 if m_type == media_type: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
239 return index |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
240 raise ValueError(f"Media type '{media_type}' not found") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
241 |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
242 def extract_ufrag_pwd(self, sdp: str) -> tuple[str, str]: |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
243 """Retrieves ICE password and user fragment for SDP offer. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
244 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
245 @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
|
246 @return: ufrag and pwd |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
247 @raise ValueError: Can't extract ufrag and password |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
248 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
249 ufrag_line = re.search(r"ice-ufrag:(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
250 pwd_line = re.search(r"ice-pwd:(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
251 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
252 if ufrag_line and pwd_line: |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
253 ufrag = self.ufrag = ufrag_line.group(1) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
254 pwd = self.pwd = pwd_line.group(1) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
255 return ufrag, pwd |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
256 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
257 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
|
258 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
|
259 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
260 def extract_fingerprint_data(self, sdp): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
261 """Retrieves fingerprint data from an SDP offer. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
262 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
263 @param sdp: The Session Description Protocol offer string. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
264 @return: A dictionary containing the fingerprint data. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
265 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
266 fingerprint_line = re.search(r"a=fingerprint:(\S+)\s+(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
267 if fingerprint_line: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
268 algorithm, fingerprint = fingerprint_line.groups() |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
269 fingerprint_data = {"hash": algorithm, "fingerprint": fingerprint} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
270 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
271 setup_line = re.search(r"a=setup:(\S+)", sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
272 if setup_line: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
273 setup = setup_line.group(1) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
274 fingerprint_data["setup"] = setup |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
275 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
276 return fingerprint_data |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
277 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
278 raise ValueError("fingerprint should not be missing") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
279 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
280 def parse_ice_candidate(self, candidate_string): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
281 """Parses the ice candidate string. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
282 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
283 @param candidate_string: The ice candidate string to be parsed. |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
284 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
285 pattern = re.compile( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
286 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
|
287 r"(?P<priority>\d+) (?P<address>\S+) (?P<port>\d+) typ " |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
288 r"(?P<type>\S+)(?: raddr (?P<rel_addr>\S+) rport " |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
289 r"(?P<rel_port>\d+))?(?: generation (?P<generation>\d+))?" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
290 ) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
291 match = pattern.match(candidate_string) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
292 if match: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
293 candidate_dict = match.groupdict() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
294 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
295 # Apply the correct types to the dictionary values |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
296 candidate_dict["component_id"] = int(candidate_dict["component_id"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
297 candidate_dict["priority"] = int(candidate_dict["priority"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
298 candidate_dict["port"] = int(candidate_dict["port"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
299 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
300 if candidate_dict["rel_port"]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
301 candidate_dict["rel_port"] = int(candidate_dict["rel_port"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
302 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
303 if candidate_dict["generation"]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
304 candidate_dict["generation"] = candidate_dict["generation"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
305 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
306 # Remove None values |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
307 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
|
308 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
309 log.warning(f"can't parse candidate: {candidate_string!r}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
310 return None |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
311 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
312 def build_ice_candidate(self, parsed_candidate): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
313 """Builds ICE candidate |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
314 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
315 @param parsed_candidate: Dictionary containing parsed ICE candidate |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
316 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
317 base_format = ( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
318 "candidate:{foundation} {component_id} {transport} {priority} " |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
319 "{address} {port} typ {type}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
320 ) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
321 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
322 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
|
323 base_format += " raddr {rel_addr} rport {rel_port}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
324 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
325 if parsed_candidate.get("generation"): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
326 base_format += " generation {generation}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
327 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
328 return base_format.format(**parsed_candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
329 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
330 def on_ice_candidate(self, event): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
331 """Handles ICE candidate event |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
332 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
333 @param event: Event containing the ICE candidate |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
334 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
335 log.debug(f"on ice candidate {event.candidate=}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
336 if event.candidate and event.candidate.candidate: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
337 parsed_candidate = self.parse_ice_candidate(event.candidate.candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
338 if parsed_candidate is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
339 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
340 try: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
341 media_type = self.media_types[event.candidate.sdpMLineIndex] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
342 except (TypeError, IndexError): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
343 log.error( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
344 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
|
345 ) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
346 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
347 self.media_candidates.setdefault(media_type, []).append(parsed_candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
348 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
|
349 if self.sid is None: |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
350 log.debug("buffering candidate") |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
351 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
|
352 parsed_candidate |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
353 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
354 else: |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
355 ufrag, pwd = self.extract_ufrag_pwd( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
356 self._peer_connection.localDescription.sdp |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
357 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
358 |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
359 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
|
360 aio.run( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
361 bridge.ice_candidates_add( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
362 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
|
363 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
364 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
365 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
366 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
367 log.debug("All ICE candidates gathered") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
368 |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
369 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
|
370 """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
|
371 state = self._peer_connection.iceConnectionState |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
372 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
|
373 |
1561
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
374 if state == "connected": |
7dbb131bbb9e
browser (calls): update status on various events (connection established, connection lost, etc.)
Goffi <goffi@goffi.org>
parents:
1559
diff
changeset
|
375 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
|
376 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
|
377 elif state == "failed": |
1563
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
378 log.error( |
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
379 "ICE connection failed. Check network connectivity and ICE configurations." |
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
380 ) |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
381 elif state == "disconnected": |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
382 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
|
383 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
|
384 self.on_connection_lost_cb() |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
385 |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
386 def on_ice_candidate_error(self, event): |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
387 """Log ICE error, useful for debugging""" |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
388 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
|
389 log.debug( |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
390 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
|
391 ) |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
392 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
393 def _set_media_types(self, offer): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
394 """Sets media types from offer SDP |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
395 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
396 @param offer: RTC session description containing the offer |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
397 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
398 sdp_lines = offer.sdp.splitlines() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
399 media_types = {} |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
400 mline_index = 0 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
401 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
402 for line in sdp_lines: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
403 if line.startswith("m="): |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
404 media_types[mline_index] = line[2 : line.find(" ")] |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
405 mline_index += 1 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
406 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
407 self.media_types = media_types |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
408 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
409 def on_ice_gathering_state_change(self, event): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
410 """Handles ICE gathering state change |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
411 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
412 @param event: Event containing the ICE gathering state change |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
413 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
414 connection = event.target |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
415 log.debug(f"on_ice_gathering_state_change {connection.iceGatheringState=}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
416 if connection.iceGatheringState == "complete": |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
417 log.info("ICE candidates gathering done") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
418 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
419 async def _create_peer_connection( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
420 self, |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
421 ) -> JSObject: |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
422 """Creates peer connection""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
423 if self._peer_connection is not None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
424 raise Exception("create_peer_connection can't be called twice!") |
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 external_disco = json.loads(await bridge.external_disco_get("")) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
427 ice_servers = [] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
428 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
429 for server in external_disco: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
430 ice_server = {} |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
431 if server["type"] == "stun": |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
432 ice_server["urls"] = f"stun:{server['host']}:{server['port']}" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
433 elif server["type"] == "turn": |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
434 ice_server[ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
435 "urls" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
436 ] = f"turn:{server['host']}:{server['port']}?transport={server['transport']}" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
437 ice_server["username"] = server["username"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
438 ice_server["credential"] = server["password"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
439 ice_servers.append(ice_server) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
440 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
441 rtc_configuration = {"iceServers": ice_servers} |
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 peer_connection = window.RTCPeerConnection.new(rtc_configuration) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
444 peer_connection.addEventListener("track", self.on_track) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
445 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
|
446 peer_connection.addEventListener( |
1563
e3449beac8d8
browser (calls): Add clear search + formatting
Goffi <goffi@goffi.org>
parents:
1561
diff
changeset
|
447 "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
|
448 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
449 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
|
450 peer_connection.addEventListener("icecandidateerror", self.on_ice_candidate_error) |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
451 peer_connection.addEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
452 "icegatheringstatechange", self.on_ice_gathering_state_change |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
453 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
454 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
455 self._peer_connection = peer_connection |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
456 window.pc = self._peer_connection |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
457 return peer_connection |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
458 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
459 async def _get_user_media(self, audio: bool = True, video: bool = True) -> None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
460 """ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
461 Gets user media (camera and microphone). |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
462 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
463 @param audio: True if an audio flux is required. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
464 @param video: True if a video flux is required. |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
465 """ |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
466 media_constraints = {"audio": audio, "video": video} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
467 local_stream = await window.navigator.mediaDevices.getUserMedia(media_constraints) |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
468 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
469 if not local_stream: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
470 log.error("Failed to get the media stream.") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
471 return |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
472 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
473 self.local_video_elt.srcObject = local_stream |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
474 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
475 for track in local_stream.getTracks(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
476 self._peer_connection.addTrack(track) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
477 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
478 async def _replace_user_video( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
479 self, |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
480 screen: bool = False, |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
481 ) -> JSObject | None: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
482 """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
|
483 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
484 @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
|
485 @return: The local media stream or None if failed. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
486 """ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
487 if screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
488 media_constraints = {"video": {"cursor": "always"}} |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
489 new_stream = await window.navigator.mediaDevices.getDisplayMedia( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
490 media_constraints |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
491 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
492 else: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
493 if self.local_video_elt.srcObject: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
494 for track in self.local_video_elt.srcObject.getTracks(): |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
495 if track.kind == "video": |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
496 track.stop() |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
497 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
498 media_constraints = { |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
499 "video": {"deviceId": self.current_camera} |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
500 if self.current_camera |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
501 else True |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
502 } |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
503 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
504 new_stream = await window.navigator.mediaDevices.getUserMedia( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
505 media_constraints |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
506 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
507 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
508 if not new_stream: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
509 log.error("Failed to get the media stream.") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
510 return None |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
511 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
512 new_video_tracks = [ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
513 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
|
514 ] |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
515 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
516 if not new_video_tracks: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
517 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
|
518 return None |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
519 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
520 # Retrieve the current local stream's video track. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
521 local_stream = self.local_video_elt.srcObject |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
522 if local_stream: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
523 local_video_tracks = [ |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
524 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
|
525 ] |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
526 if local_video_tracks: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
527 # 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
|
528 local_stream.removeTrack(local_video_tracks[0]) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
529 local_stream.addTrack(new_video_tracks[0]) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
530 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
531 video_sender = next( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
532 ( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
533 sender |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
534 for sender in self._peer_connection.getSenders() |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
535 if sender.track and sender.track.kind == "video" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
536 ), |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
537 None, |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
538 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
539 if video_sender: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
540 await video_sender.replaceTrack(new_video_tracks[0]) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
541 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
542 if screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
543 # For screen sharing, we track the end event to properly stop the sharing when |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
544 # the user clicks on the browser's stop sharing dialog. |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
545 def on_track_ended(event): |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
546 aio.run(self.toggle_screen_sharing()) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
547 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
548 new_video_tracks[0].bind("ended", on_track_ended) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
549 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
550 self.is_sharing_screen = screen |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
551 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
552 return local_stream |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
553 |
1564
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
554 async def switch_camera(self) -> None: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
555 """Switches to the next available camera. |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
556 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
557 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
|
558 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
|
559 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
|
560 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
|
561 """ |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
562 log.info("switching camera") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
563 if not self.has_multiple_cameras: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
564 log.error("No multiple cameras to switch.") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
565 return |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
566 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
567 current_camera_index = -1 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
568 for i, device_info in enumerate(self.video_devices): |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
569 if device_info.deviceId == self.current_camera: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
570 current_camera_index = i |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
571 break |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
572 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
573 if current_camera_index == -1: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
574 log.error("Current camera not found in available devices.") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
575 return |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
576 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
577 # Switch to the next camera in the list |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
578 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
|
579 self.current_camera = self.video_devices[next_camera_index].deviceId |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
580 log.debug(f"{next_camera_index=} {self.current_camera=}") |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
581 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
582 new_stream = await window.navigator.mediaDevices.getUserMedia( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
583 {"video": {"deviceId": self.current_camera}} |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
584 ) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
585 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
586 new_video_tracks = [ |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
587 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
|
588 ] |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
589 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
590 if not new_video_tracks: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
591 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
|
592 return |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
593 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
594 # Update local video element's stream |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
595 local_stream = self.local_video_elt.srcObject |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
596 if local_stream: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
597 local_video_tracks = [ |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
598 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
|
599 ] |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
600 if local_video_tracks: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
601 local_video_tracks[0].stop() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
602 local_stream.removeTrack(local_video_tracks[0]) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
603 local_stream.addTrack(new_video_tracks[0]) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
604 self.local_video_elt.srcObject = local_stream |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
605 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
606 # update remove video stream |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
607 video_sender = next( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
608 ( |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
609 sender |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
610 for sender in self._peer_connection.getSenders() |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
611 if sender.track and sender.track.kind == "video" |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
612 ), |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
613 None, |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
614 ) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
615 |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
616 if video_sender: |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
617 await video_sender.replaceTrack(new_video_tracks[0]) |
bd3c880f4a47
browser (calls): add camera switching:
Goffi <goffi@goffi.org>
parents:
1563
diff
changeset
|
618 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
619 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
|
620 """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
|
621 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
622 @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
|
623 @param remote_candidates: Remote ICE candidates, if any |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
624 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
625 if self._peer_connection is None: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
626 raise Exception( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
627 "The peer connection must be created before gathering ICE candidates!" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
628 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
629 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
630 self.media_candidates.clear() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
631 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
632 if is_initiator: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
633 offer = await self._peer_connection.createOffer() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
634 self._set_media_types(offer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
635 await self._peer_connection.setLocalDescription(offer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
636 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
637 answer = await self._peer_connection.createAnswer() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
638 self._set_media_types(answer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
639 await self._peer_connection.setLocalDescription(answer) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
640 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
641 if not is_initiator: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
642 log.debug(self._peer_connection.localDescription.sdp) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
643 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
|
644 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
|
645 return { |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
646 "ufrag": ufrag, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
647 "pwd": pwd, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
648 "candidates": self.media_candidates, |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
649 } |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
650 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
651 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
|
652 """Call has been accepted, connection can be established |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
653 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
654 @param session_id: Session identifier |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
655 @param sdp: Session Description Protocol data |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
656 @param profile: Profile associated |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
657 """ |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
658 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
|
659 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
|
660 self.remote_candidates_buffer.clear() |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
661 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
662 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
|
663 """Called when new ICE candidates are received |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
664 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
665 @param sid: Session identifier |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
666 @param candidates_s: ICE candidates serialized |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
667 @param profile: Profile associated with the action |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
668 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
669 if sid != self.sid: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
670 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
|
671 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
672 candidates = json.loads(candidates_s) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
673 aio.run(self.on_ice_candidates_new(candidates)) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
674 |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
675 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
|
676 if sid != self.sid: |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
677 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
|
678 return |
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
679 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
|
680 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
|
681 self.on_reconnect_cb() |
1559
410064b31dca
browser (calls): add some logs useful for debugging
Goffi <goffi@goffi.org>
parents:
1553
diff
changeset
|
682 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
683 async def on_ice_candidates_new(self, candidates: dict) -> None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
684 """Called when new ICE canidates are received from peer |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
685 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
686 @param candidates: Dictionary containing new ICE candidates |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
687 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
688 log.debug(f"new peer candidates received: {candidates}") |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
689 |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
690 try: |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
691 # FIXME: javascript.NULL must be used here, once we move to Brython 3.12.3+ |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
692 remoteDescription_is_none = self._peer_connection.remoteDescription is None |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
693 except Exception as e: |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
694 # FIXME: should be fine in Brython 3.12.3+ |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
695 log.debug("Workaround for Brython bug activated.") |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
696 remoteDescription_is_none = True |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
697 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
698 if ( |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
699 self._peer_connection is None |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
700 # or self._peer_connection.remoteDescription is NULL |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
701 or remoteDescription_is_none |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
702 ): |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
703 for media_type in ("audio", "video", "application"): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
704 media_candidates = candidates.get(media_type) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
705 if media_candidates: |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
706 buffer = self.remote_candidates_buffer[media_type] |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
707 buffer["candidates"].extend(media_candidates["candidates"]) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
708 return |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
709 for media_type, ice_data in candidates.items(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
710 for candidate in ice_data["candidates"]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
711 candidate_sdp = self.build_ice_candidate(candidate) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
712 try: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
713 sdp_mline_index = self.get_sdp_mline_index(media_type) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
714 except Exception as e: |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
715 log.warning(f"Can't get sdp_mline_index: {e}") |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
716 continue |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
717 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
718 ice_candidate = window.RTCIceCandidate.new( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
719 {"candidate": candidate_sdp, "sdpMLineIndex": sdp_mline_index} |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
720 ) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
721 await self._peer_connection.addIceCandidate(ice_candidate) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
722 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
723 def on_track(self, event): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
724 """New track has been received from peer |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
725 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
726 @param event: Event associated with the new track |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
727 """ |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
728 if event.streams and event.streams[0]: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
729 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
|
730 self.remote_video_elt.srcObject = remote_stream |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
731 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
732 if self.remote_stream is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
733 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
|
734 self.remote_video_elt.srcObject = self.remote_stream |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
735 self.remote_stream.addTrack(event.track) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
736 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
737 def on_negotiation_needed(self, event) -> None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
738 log.debug(f"on_negotiation_needed {event=}") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
739 # TODO |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
740 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
741 def _on_data_channel(self, event) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
742 """Handles the data channel event from the peer connection. |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
743 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
744 @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
|
745 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
746 data_channel = event.channel |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
747 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
|
748 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
749 async def answer_call(self, sid: str, offer_sdp: str, profile: str): |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
750 """We respond to the call""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
751 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
|
752 if sid != self.sid: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
753 raise Exception(f"Internal Error: unexpected sid: {sid=} {self.sid=}") |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
754 await self._create_peer_connection() |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
755 |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
756 await self._peer_connection.setRemoteDescription( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
757 {"type": "offer", "sdp": offer_sdp} |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
758 ) |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
759 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
|
760 self.remote_candidates_buffer.clear() |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
761 if self.file_only: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
762 self._peer_connection.bind("datachannel", self._on_data_channel) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
763 else: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
764 await self._get_user_media() |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
765 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
766 # Gather local ICE candidates |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
767 local_ice_data = await self._gather_ice_candidates(False) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
768 self.local_candidates = local_ice_data["candidates"] |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
769 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
770 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
|
771 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
772 async def _get_call_data(self) -> dict: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
773 """Start a WebRTC call""" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
774 await self._gather_ice_candidates(True) |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
775 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
776 return {"sdp": self._peer_connection.localDescription.sdp} |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
777 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
778 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
|
779 if self.local_candidates_buffer: |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
780 log.debug( |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
781 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
|
782 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
783 assert self.pwd is not None |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
784 ice_data = {} |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
785 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
|
786 ice_data[media_type] = { |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
787 "ufrag": self.ufrag, |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
788 "pwd": self.pwd, |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
789 "candidates": candidates |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
790 } |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
791 await bridge.ice_candidates_add( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
792 self.sid, |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
793 json.dumps( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
794 ice_data |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
795 ), |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
796 ) |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
797 self.local_candidates_buffer.clear() |
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
798 |
1600
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
799 async def make_call( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
800 self, callee_jid: jid.JID, audio: bool = True, video: bool = True |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
801 ) -> None: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
802 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
803 @param audio: True if an audio flux is required |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
804 @param video: True if a video flux is required |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
805 """ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
806 await self._create_peer_connection() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
807 await self._get_user_media(audio, video) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
808 call_data = await self._get_call_data() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
809 log.info(f"calling {callee_jid!r}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
810 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
|
811 log.debug(f"Call SID: {self.sid}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
812 await self._send_buffered_local_candidates() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
813 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
814 def _on_opened_data_channel(self, event): |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
815 log.info("Datachannel has been opened.") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
816 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
817 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
|
818 assert self.file_only |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
819 peer_connection = await self._create_peer_connection() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
820 data_channel = peer_connection.createDataChannel("file") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
821 call_data = await self._get_call_data() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
822 log.info(f"sending file to {callee_jid!r}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
823 file_meta = { |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
824 "size": file.size |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
825 } |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
826 if file.type: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
827 file_meta["media_type"] = file.type |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
828 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
829 try: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
830 file_data = json.loads(await bridge.file_jingle_send( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
831 str(callee_jid), |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
832 "", |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
833 file.name, |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
834 "", |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
835 json.dumps({ |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
836 "webrtc": True, |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
837 "call_data": call_data, |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
838 **file_meta |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
839 }) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
840 )) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
841 except Exception as e: |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
842 dialog.notification.show( |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
843 f"Can't send file: {e}", level="error" |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
844 ) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
845 return |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
846 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
847 self.sid = file_data["session_id"] |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
848 |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
849 log.debug(f"File Transfer SID: {self.sid}") |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
850 await self._send_buffered_local_candidates() |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
851 self.file_sender = FileSender(self.sid, file, data_channel) |
0a4433a343a3
browser (calls): implement WebRTC file sharing:
Goffi <goffi@goffi.org>
parents:
1577
diff
changeset
|
852 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
853 async def end_call(self) -> None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
854 """Stop streaming and clean instance""" |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
855 if self._peer_connection is None: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
856 log.debug("There is currently no call to end.") |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
857 else: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
858 self._peer_connection.removeEventListener("track", self.on_track) |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
859 self._peer_connection.removeEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
860 "negotiationneeded", self.on_negotiation_needed |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
861 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
862 self._peer_connection.removeEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
863 "icecandidate", self.on_ice_candidate |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
864 ) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
865 self._peer_connection.removeEventListener( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
866 "icegatheringstatechange", self.on_ice_gathering_state_change |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
867 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
868 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
869 # 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
|
870 # 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
|
871 # last stream |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
872 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
|
873 "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
|
874 "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
|
875 ) |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
876 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
877 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
|
878 remote_video = self.remote_video_elt |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
879 if local_video.srcObject: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
880 for track in local_video.srcObject.getTracks(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
881 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
|
882 local_video.src = 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
|
883 |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
884 if remote_video.srcObject: |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
885 for track in remote_video.srcObject.getTracks(): |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
886 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
|
887 remote_video.src = black_image_data |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
888 |
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
889 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
|
890 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
|
891 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
892 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
|
893 """Toggle mute/unmute for media tracks. |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
894 |
1566
e65d2ef1ded4
browser (calls/webrtc): send ICE candidates when received:
Goffi <goffi@goffi.org>
parents:
1565
diff
changeset
|
895 @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
|
896 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
|
897 """ |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
898 assert media_type in ("audio", "video"), "Invalid media type" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
899 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
900 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
|
901 is_muted_attr = f"is_{media_type}_muted" |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
902 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
903 if local_video.srcObject: |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
904 track_getter = getattr( |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
905 local_video.srcObject, f"get{media_type.capitalize()}Tracks" |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
906 ) |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
907 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
|
908 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
|
909 setattr(self, is_muted_attr, not track.enabled) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
910 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
911 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
|
912 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
|
913 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
|
914 aio.run( |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
915 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
|
916 self.sid, |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
917 "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
|
918 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
|
919 ) |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
920 ) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
921 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
922 return getattr(self, is_muted_attr) |
1517
b8ed9726525b
browser: "calls" implementation, first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
923 |
1549
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
924 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
|
925 """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
|
926 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
|
927 |
e47c24204449
browser (calls): update call to handle search, control buttons, and better UI/UX:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
928 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
|
929 """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
|
930 return self.toggle_media_mute("video") |
1553
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
931 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
932 async def toggle_screen_sharing(self): |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
933 log.debug(f"toggle_screen_sharing {self._is_sharing_screen=}") |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
934 |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
935 if self._is_sharing_screen: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
936 await self._replace_user_video(screen=False) |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
937 else: |
83c2a6faa2ae
browser (calls): screen sharing implementation:
Goffi <goffi@goffi.org>
parents:
1549
diff
changeset
|
938 await self._replace_user_video(screen=True) |