annotate libervia/web/pages/calls/_browser/webrtc.py @ 1566:e65d2ef1ded4

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