Mercurial > libervia-backend
comparison libervia/cli/call_webrtc.py @ 4210:9218d4331bb2
cli (call): `tui` output implementation:
- Moved original UI to a separated class, and use if with the `simple` output
- By default, best output is automatically selected. For now `gui` is selected if possible,
and `simple` is used as fallback.
- The new `tui` output can be used to have the videos directly embedded in the terminal,
either with real videos for compatible terminal emulators, or with Unicode blocks.
- Text contrôls are used for both `simple` and `tui` outputs
- several options can be used with `--oo` (will be documented in next commit).
rel 428
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 16 Feb 2024 18:46:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4209:fe29fbdabce6 | 4210:9218d4331bb2 |
---|---|
1 #!/usr/bin/env python3 | |
2 | |
3 # Libervia CLI | |
4 # Copyright (C) 2009-2024 Jérôme Poisson (goffi@goffi.org) | |
5 | |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 from dataclasses import dataclass | |
20 | |
21 from libervia.backend.tools.common import data_format | |
22 from libervia.frontends.tools import aio, jid | |
23 | |
24 | |
25 @dataclass | |
26 class CallData: | |
27 callee: jid.JID | |
28 sid: str | None = None | |
29 action_id: str | None = None | |
30 | |
31 | |
32 class WebRTCCall: | |
33 def __init__(self, host, profile: str, callee: jid.JID, **kwargs): | |
34 """Create and setup a webRTC instance | |
35 | |
36 @param profile: profile making or receiving the call | |
37 @param callee: peer jid | |
38 @param kwargs: extra kw args to use when instantiating WebRTC | |
39 """ | |
40 from libervia.frontends.tools import webrtc | |
41 | |
42 aio.install_glib_asyncio_iteration() | |
43 self.host = host | |
44 self.profile = profile | |
45 self.webrtc = webrtc.WebRTC(host.bridge, profile, **kwargs) | |
46 self.webrtc.callee = callee | |
47 host.bridge.register_signal( | |
48 "ice_candidates_new", self.on_ice_candidates_new, "plugin" | |
49 ) | |
50 host.bridge.register_signal("call_setup", self.on_call_setup, "plugin") | |
51 host.bridge.register_signal("call_ended", self.on_call_ended, "plugin") | |
52 | |
53 @classmethod | |
54 async def make_webrtc_call( | |
55 cls, | |
56 host, | |
57 profile: str, | |
58 call_data: CallData, | |
59 **kwargs | |
60 ) -> "WebRTCCall": | |
61 """Create the webrtc_call instance | |
62 | |
63 @param call_data: Call data of the command | |
64 @param kwargs: extra args used to instanciate WebRTCCall | |
65 | |
66 """ | |
67 webrtc_call = cls(host, profile, call_data.callee, **kwargs) | |
68 if call_data.sid is None: | |
69 # we are making the call | |
70 await webrtc_call.start() | |
71 else: | |
72 # we are receiving the call | |
73 webrtc_call.sid = call_data.sid | |
74 if call_data.action_id is not None: | |
75 await host.bridge.action_launch( | |
76 call_data.action_id, | |
77 data_format.serialise({"cancelled": False}), | |
78 profile | |
79 ) | |
80 return webrtc_call | |
81 | |
82 @property | |
83 def sid(self) -> str | None: | |
84 return self.webrtc.sid | |
85 | |
86 @sid.setter | |
87 def sid(self, new_sid: str | None) -> None: | |
88 self.webrtc.sid = new_sid | |
89 | |
90 async def on_ice_candidates_new( | |
91 self, sid: str, candidates_s: str, profile: str | |
92 ) -> None: | |
93 if sid != self.webrtc.sid or profile != self.profile: | |
94 return | |
95 self.webrtc.on_ice_candidates_new( | |
96 data_format.deserialise(candidates_s), | |
97 ) | |
98 | |
99 async def on_call_setup(self, sid: str, setup_data_s: str, profile: str) -> None: | |
100 if sid != self.webrtc.sid or profile != self.profile: | |
101 return | |
102 setup_data = data_format.deserialise(setup_data_s) | |
103 try: | |
104 role = setup_data["role"] | |
105 sdp = setup_data["sdp"] | |
106 except KeyError: | |
107 self.host.disp(f"Invalid setup data received: {setup_data}", error=True) | |
108 return | |
109 if role == "initiator": | |
110 self.webrtc.on_accepted_call(sdp, profile) | |
111 elif role == "responder": | |
112 await self.webrtc.answer_call(sdp, profile) | |
113 else: | |
114 self.host.disp( | |
115 f"Invalid role received during setup: {setup_data}", error=True | |
116 ) | |
117 # we want to be sure that call is ended if user presses `Ctrl + c` or anything | |
118 # else stops the session. | |
119 self.host.add_on_quit_callback( | |
120 lambda: self.host.bridge.call_end(sid, "", profile) | |
121 ) | |
122 | |
123 async def on_call_ended(self, sid: str, data_s: str, profile: str) -> None: | |
124 if sid != self.webrtc.sid or profile != self.profile: | |
125 return | |
126 await self.webrtc.end_call() | |
127 await self.host.a_quit() | |
128 | |
129 async def start(self): | |
130 """Start a call. | |
131 | |
132 To be used only if we are initiator | |
133 """ | |
134 await self.webrtc.setup_call("initiator") | |
135 self.webrtc.start_pipeline() |