py-tgcalls 2.1.0rc2__py3-none-any.whl → 2.1.0rc4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py_tgcalls-2.1.0rc2.dist-info → py_tgcalls-2.1.0rc4.dist-info}/METADATA +2 -2
- {py_tgcalls-2.1.0rc2.dist-info → py_tgcalls-2.1.0rc4.dist-info}/RECORD +20 -16
- pytgcalls/__version__.py +1 -1
- pytgcalls/methods/calls/leave_call.py +2 -0
- pytgcalls/methods/stream/play.py +7 -64
- pytgcalls/methods/stream/record.py +7 -1
- pytgcalls/methods/utilities/__init__.py +6 -0
- pytgcalls/methods/utilities/join_presentation.py +46 -0
- pytgcalls/methods/utilities/log_retries.py +14 -0
- pytgcalls/methods/utilities/start.py +56 -44
- pytgcalls/methods/utilities/stream_params.py +6 -2
- pytgcalls/methods/utilities/update_sources.py +42 -0
- pytgcalls/scaffold.py +11 -2
- pytgcalls/types/calls/__init__.py +2 -0
- pytgcalls/types/calls/call_sources.py +4 -0
- pytgcalls/types/stream/media_stream.py +0 -1
- pytgcalls/types/stream/record_stream.py +2 -2
- {py_tgcalls-2.1.0rc2.dist-info → py_tgcalls-2.1.0rc4.dist-info}/LICENSE +0 -0
- {py_tgcalls-2.1.0rc2.dist-info → py_tgcalls-2.1.0rc4.dist-info}/WHEEL +0 -0
- {py_tgcalls-2.1.0rc2.dist-info → py_tgcalls-2.1.0rc4.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: py-tgcalls
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.0rc4
|
|
4
4
|
Summary: Async client API for the Telegram Calls.
|
|
5
5
|
Author-email: Laky-64 <iraci.matteo@gmail.com>
|
|
6
6
|
License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
@@ -187,7 +187,7 @@ Requires-Python: >=3.9
|
|
|
187
187
|
Description-Content-Type: text/markdown
|
|
188
188
|
License-File: LICENSE
|
|
189
189
|
Requires-Dist: aiohttp>=3.9.3
|
|
190
|
-
Requires-Dist: ntgcalls<1.4.0,>=1.3.
|
|
190
|
+
Requires-Dist: ntgcalls<1.4.0,>=1.3.0b14
|
|
191
191
|
Requires-Dist: deprecation
|
|
192
192
|
Provides-Extra: pyrogram
|
|
193
193
|
Requires-Dist: pyrogram>=1.2.20; extra == "pyrogram"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
pytgcalls/__init__.py,sha256=qbfwN7rYwIdCegMOzdcbvwazeNjDzgmowgcqLFNqKIM,308
|
|
2
|
-
pytgcalls/__version__.py,sha256=
|
|
2
|
+
pytgcalls/__version__.py,sha256=bQyjq0CUvIVmXyMKMECcV2-QIaZZRwtmrdC0uwmXqC4,26
|
|
3
3
|
pytgcalls/environment.py,sha256=ctCHACvG6l8SdpPewSBhOvc70kbwpv18maC0TwLvZ08,1924
|
|
4
4
|
pytgcalls/exceptions.py,sha256=0MmAktc53ajYAc7ThjD2tJ9PDyibUi0iHZMfUy2IoKs,4109
|
|
5
5
|
pytgcalls/ffmpeg.py,sha256=tm6DBxyNfPh3h3an-b2s9x1UyX-cvkCdov9prlXxVZY,8649
|
|
@@ -8,7 +8,7 @@ pytgcalls/mtproto_required.py,sha256=6B-31p5qH_6oekUgypV4nK3hqPS6Nr-pA8S81wjnbaY
|
|
|
8
8
|
pytgcalls/mutex.py,sha256=Frjji5Ctzlk4AXEBuBLnDK-7HbtreoV6zuyKpFpMNI4,236
|
|
9
9
|
pytgcalls/pytgcalls.py,sha256=oBcWgBwusnXmjHrLEE99VVXARReVyrXdn9SyeBWHbVo,1479
|
|
10
10
|
pytgcalls/pytgcalls_session.py,sha256=_BGJWvf7t3mki2DhlEPjh9cypvYuSFkMSxzTsfepwUk,2719
|
|
11
|
-
pytgcalls/scaffold.py,sha256=
|
|
11
|
+
pytgcalls/scaffold.py,sha256=SwePuT9V8LdOFy0KRlAnRSbsB2zeGQ4fs9ilrq7HZYI,1353
|
|
12
12
|
pytgcalls/statictypes.py,sha256=CdlqgQNhTZ_uTE8-B8m01fJ7TlD2B42EI2QBPxDdAtA,3842
|
|
13
13
|
pytgcalls/sync.py,sha256=IsOH3TD7cxUg_-zdGt12HoS8sBlXvcGayPZAoxxKM48,3396
|
|
14
14
|
pytgcalls/version_manager.py,sha256=egeGgvb66zWlLTMuw2U-b0x8MfnRzMm1xAEVN87HF5c,296
|
|
@@ -27,29 +27,32 @@ pytgcalls/methods/__init__.py,sha256=hk1blAT5u_Isemdrg0nqInLsdRzTTZnak5NdAfkBPAk
|
|
|
27
27
|
pytgcalls/methods/calls/__init__.py,sha256=xg4DZZClEnxwaj-DAq3e8gSR-g-MiYBdUEBth64lSXA,214
|
|
28
28
|
pytgcalls/methods/calls/change_volume_call.py,sha256=viA3yHVxPJ421yE1dfFTh-kNEFTxMlaVFxVjC-PeX-0,719
|
|
29
29
|
pytgcalls/methods/calls/get_participants.py,sha256=gKUAzvha1RpvbtSI_n-GlBQkOONxzibCaCr4aA17Mag,567
|
|
30
|
-
pytgcalls/methods/calls/leave_call.py,sha256=
|
|
30
|
+
pytgcalls/methods/calls/leave_call.py,sha256=ay07za5mNKmXGzmpeU6gJJmHVrLeXRtRmFT4QP94pGA,1475
|
|
31
31
|
pytgcalls/methods/decorators/__init__.py,sha256=TCGaEVZnHjtOwv-3PNfaCVm0kyFhJApUPUNntt6MwyM,78
|
|
32
32
|
pytgcalls/methods/decorators/on_update.py,sha256=ZTL4YcQk0N4Ru56a5WItUvkSN5SAqr6_RDZvXmZMIHs,316
|
|
33
33
|
pytgcalls/methods/stream/__init__.py,sha256=dBx5cqvVyvhqykIuT_2rYCAvIzuPM1J4Hh4sZ083UXU,412
|
|
34
34
|
pytgcalls/methods/stream/mute_stream.py,sha256=auo2aAazfEC90Ab6MzaiPdddiJ1w4fN_9HaORkAeOBY,570
|
|
35
35
|
pytgcalls/methods/stream/pause_stream.py,sha256=z_AIWABrQMHmTwvlah_PrH9EjXbro8gKxZni4Km5ICg,573
|
|
36
|
-
pytgcalls/methods/stream/play.py,sha256
|
|
37
|
-
pytgcalls/methods/stream/record.py,sha256=
|
|
36
|
+
pytgcalls/methods/stream/play.py,sha256=-Ld5TQWLhU_ktKrb7q1Xrym36UGrWhaenIbjj-3mM3k,7524
|
|
37
|
+
pytgcalls/methods/stream/record.py,sha256=28mFK2azDv6gUziwcj4ybvrYka9P9VXnUXnuAa1aQ5w,1466
|
|
38
38
|
pytgcalls/methods/stream/resume_stream.py,sha256=z_DgP4cDExjEqEeX_ZL--50MXQ9lrATK876SIwE71PQ,576
|
|
39
39
|
pytgcalls/methods/stream/send_frame.py,sha256=Kj9R8OqUM-g7pt-FiWP-US7sCFkH5ciPr9S8v-WPtLg,1062
|
|
40
40
|
pytgcalls/methods/stream/time.py,sha256=5y9TMBf_d6YPLbMcGx3yMZQUZdo8zb5fQb9STsh7R3Y,656
|
|
41
41
|
pytgcalls/methods/stream/unmute_stream.py,sha256=KUMhfMbhsPmZsmpF4cGWC1FVW7YwXha2MmQnqrBhM8s,576
|
|
42
|
-
pytgcalls/methods/utilities/__init__.py,sha256=
|
|
42
|
+
pytgcalls/methods/utilities/__init__.py,sha256=HHAkTQEX_23uwo1fxnCIoE2rLBm7fKSQa52SwBLudTI,522
|
|
43
43
|
pytgcalls/methods/utilities/cache_peer.py,sha256=Ylt0wCCJOoNKf1wZEXjfE8aBZKUIIgdRUFOMTGA5DfE,140
|
|
44
44
|
pytgcalls/methods/utilities/call_holder.py,sha256=MhIbwCG6DROd9_bHGa6aqu-rB0y4sngzPBj82zLtAXU,1068
|
|
45
45
|
pytgcalls/methods/utilities/compose.py,sha256=Nzdv8orMmka5NIBZ1SW1nsqXRzArZl4m6FdZU7syaR4,334
|
|
46
46
|
pytgcalls/methods/utilities/cpu_usage.py,sha256=Mbga4MFCIwuh7WC8sqBbv1Pa6ALcp5AIDyfYMH_Bix4,162
|
|
47
47
|
pytgcalls/methods/utilities/idle.py,sha256=MDdzHTv1ws2yBhsvhBUnssGdghkZ2KwR0HUCPOwV38o,814
|
|
48
|
+
pytgcalls/methods/utilities/join_presentation.py,sha256=HLpVjhDkbMB6mIsCwdaGy-Ct7IaV44fM5-zOQ9M7bLU,1551
|
|
49
|
+
pytgcalls/methods/utilities/log_retries.py,sha256=6nD9J3350t82I0PKzK1pVx3ZaCBHATReiXYMs3PuVhQ,342
|
|
48
50
|
pytgcalls/methods/utilities/ping.py,sha256=hhIMSHk2BzMB-IKpwLdZFVrsEvGm2ftJwKLs1k4anh8,244
|
|
49
51
|
pytgcalls/methods/utilities/resolve_chat_id.py,sha256=92x2LHbUlnJMm-kS3fXOYmzYpY2TZbqtQD2rw3eBXDY,382
|
|
50
52
|
pytgcalls/methods/utilities/run.py,sha256=cnYQd2xB5Cr_WS0Q2cXJZPGiN6JOCULzj1r4xXVyrlg,152
|
|
51
|
-
pytgcalls/methods/utilities/start.py,sha256=
|
|
52
|
-
pytgcalls/methods/utilities/stream_params.py,sha256=
|
|
53
|
+
pytgcalls/methods/utilities/start.py,sha256=unc-O5XsUztJY7t7wu40F0uSthgq9YutcXRqcTTzhhA,14393
|
|
54
|
+
pytgcalls/methods/utilities/stream_params.py,sha256=OE673Bt1CiyCBFQGMPtC05zv3nObP3zirrh4OD9USdg,3109
|
|
55
|
+
pytgcalls/methods/utilities/update_sources.py,sha256=ISF6u3rk4IcVrPOEOB-uZUDfnwUp2_y1_2g9GboXpWM,1562
|
|
53
56
|
pytgcalls/mtproto/__init__.py,sha256=X4zvzFG7km7qHyE0fdvA550WcOVO_xl_p__gvIfDGmw,130
|
|
54
57
|
pytgcalls/mtproto/bridged_client.py,sha256=hktnfpfBK7PEL2n7Y0kBZzI7dkLlsdrDwkYliZki8zQ,5915
|
|
55
58
|
pytgcalls/mtproto/client_cache.py,sha256=Mt0827e_T8DXJHOTkXhkIQUT9EUBWjoLcFcXP1gBnZY,5973
|
|
@@ -67,11 +70,12 @@ pytgcalls/types/participant_list.py,sha256=LmGjU63MK1v3SS2_4xNbk04OOjmukNdAXYLRn
|
|
|
67
70
|
pytgcalls/types/py_object.py,sha256=VlazuMP0cFpExKimW8BtWR66LDewnNdQSLC7r_t7JIM,842
|
|
68
71
|
pytgcalls/types/update.py,sha256=wPCzWLhrsScZ3ksRTyt8IuDaaG5YI-ItG_Yw-OqzK2Y,157
|
|
69
72
|
pytgcalls/types/user_agent.py,sha256=sSfeGqUe0v0wqBgdVszNFK0iOC_0Tdyto9CglBXlY4U,1086
|
|
70
|
-
pytgcalls/types/calls/__init__.py,sha256=
|
|
73
|
+
pytgcalls/types/calls/__init__.py,sha256=f0zMKm_mwvNsDRPgs8IopuCEefU3V0-kuHAFsTMBoAc,403
|
|
71
74
|
pytgcalls/types/calls/call.py,sha256=n7LW7FRNT2qJzbYC3D312judOlVUuocQ1eW9l9scGCo,546
|
|
72
75
|
pytgcalls/types/calls/call_config.py,sha256=b6P43YTGF2t7E2CyD1mSYPJDUBvYYeHoxB3hSbTVyOY,120
|
|
73
76
|
pytgcalls/types/calls/call_data.py,sha256=-qPj2QhWv32Xs7LyFQY4hiWDqJ21B8VBvdzREK8bDvY,544
|
|
74
77
|
pytgcalls/types/calls/call_protocol.py,sha256=OVIQs1VgdY-DWbZbNr41hjLA4pGQvHx8Rgom1_NhJxQ,408
|
|
78
|
+
pytgcalls/types/calls/call_sources.py,sha256=sBhumPgEaN8uAKjBwb1Zf_Ag0qrceti2mURXqMhBusg,107
|
|
75
79
|
pytgcalls/types/calls/group_call_config.py,sha256=auKH-hZJWj8PhTkyeQ_VK2z9NpNvNC7Scl_IhEUMnQM,353
|
|
76
80
|
pytgcalls/types/calls/raw_call_update.py,sha256=hpNw6HrTW8Z36Lh2HinS-wzprryRtsIxyIFbIfjGgeI,795
|
|
77
81
|
pytgcalls/types/chats/__init__.py,sha256=v8pUp_vbr2kQpyHtAQc80N-YqzmXHe9SbllUsa6njkU,261
|
|
@@ -90,13 +94,13 @@ pytgcalls/types/stream/device.py,sha256=EdoDg6lPE7fgoZI04Nr0E9zbIk-iRIBgYYAzVqoC
|
|
|
90
94
|
pytgcalls/types/stream/direction.py,sha256=gd10wUmpfsqx87kCAPZt6u8pFiPb09WZfHKcMWAZokU,394
|
|
91
95
|
pytgcalls/types/stream/external_media.py,sha256=RiuSX5tZGdNsQZ8LIRk5Lp4Ksv9oTvaccmInJRZYo4M,114
|
|
92
96
|
pytgcalls/types/stream/frame.py,sha256=TXo5HZVHbbaVNBqulMhTqGODXH3bpBVlN_of1rosNUQ,586
|
|
93
|
-
pytgcalls/types/stream/media_stream.py,sha256=
|
|
94
|
-
pytgcalls/types/stream/record_stream.py,sha256=
|
|
97
|
+
pytgcalls/types/stream/media_stream.py,sha256=jNWNJppX2ji4CrHdkF2b6FFLeiS9KKjVDGvcWPmPrvc,11917
|
|
98
|
+
pytgcalls/types/stream/record_stream.py,sha256=VEKB2rSnb4U1EyoPdNteWxJ65feV58EGu5QmDEJiB2E,3037
|
|
95
99
|
pytgcalls/types/stream/stream_ended.py,sha256=xR_kZwFf03hA6rw_nvI7Be7GwoCKzQf_1MKaGpPDXqY,716
|
|
96
100
|
pytgcalls/types/stream/stream_frames.py,sha256=028ZhNV-mN3BGqMlmxusAV1xDQpXRYCeM0WXBZhRUhA,446
|
|
97
101
|
pytgcalls/types/stream/video_quality.py,sha256=HBfWq005kh-D19MaVE9VzVdnODzrXf4IJUimCfslfiU,231
|
|
98
|
-
py_tgcalls-2.1.
|
|
99
|
-
py_tgcalls-2.1.
|
|
100
|
-
py_tgcalls-2.1.
|
|
101
|
-
py_tgcalls-2.1.
|
|
102
|
-
py_tgcalls-2.1.
|
|
102
|
+
py_tgcalls-2.1.0rc4.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
103
|
+
py_tgcalls-2.1.0rc4.dist-info/METADATA,sha256=H6X5VamKCIuV6ApcU3YNwt8ADVD9FIdBKDxO7-VQA6M,14398
|
|
104
|
+
py_tgcalls-2.1.0rc4.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
105
|
+
py_tgcalls-2.1.0rc4.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
|
|
106
|
+
py_tgcalls-2.1.0rc4.dist-info/RECORD,,
|
pytgcalls/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '2.1.0.
|
|
1
|
+
__version__ = '2.1.0.rc4'
|
pytgcalls/methods/stream/play.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import Optional
|
|
4
5
|
from typing import Union
|
|
5
6
|
|
|
@@ -12,7 +13,7 @@ from ntgcalls import TransportParseException
|
|
|
12
13
|
from ...exceptions import NoActiveGroupCall
|
|
13
14
|
from ...exceptions import TimedOutAnswer
|
|
14
15
|
from ...exceptions import UnMuteNeeded
|
|
15
|
-
from ...
|
|
16
|
+
from ...media_devices.input_device import InputDevice
|
|
16
17
|
from ...mtproto_required import mtproto_required
|
|
17
18
|
from ...mutex import mutex
|
|
18
19
|
from ...scaffold import Scaffold
|
|
@@ -34,14 +35,9 @@ class Play(Scaffold):
|
|
|
34
35
|
async def play(
|
|
35
36
|
self,
|
|
36
37
|
chat_id: Union[int, str],
|
|
37
|
-
stream: Optional[Stream] = None,
|
|
38
|
+
stream: Optional[Union[str, Path, InputDevice, Stream]] = None,
|
|
38
39
|
config: Optional[Union[CallConfig, GroupCallConfig]] = None,
|
|
39
40
|
):
|
|
40
|
-
def log_retries(r: int):
|
|
41
|
-
(py_logger.warning if r >= 1 else py_logger.info)(
|
|
42
|
-
f'Telegram is having some internal server issues. '
|
|
43
|
-
f'Retrying {r + 1} of 3',
|
|
44
|
-
)
|
|
45
41
|
chat_id = await self.resolve_chat_id(chat_id)
|
|
46
42
|
is_p2p = chat_id > 0 # type: ignore
|
|
47
43
|
if config is None:
|
|
@@ -168,7 +164,7 @@ class Play(Scaffold):
|
|
|
168
164
|
except TelegramServerError:
|
|
169
165
|
if retries == 3 or is_p2p:
|
|
170
166
|
raise
|
|
171
|
-
|
|
167
|
+
self._log_retries(retries)
|
|
172
168
|
except Exception:
|
|
173
169
|
try:
|
|
174
170
|
await self._binding.stop(chat_id)
|
|
@@ -179,64 +175,11 @@ class Play(Scaffold):
|
|
|
179
175
|
self._wait_connect.pop(chat_id, None)
|
|
180
176
|
|
|
181
177
|
if isinstance(config, GroupCallConfig):
|
|
182
|
-
|
|
183
|
-
for retries in range(4):
|
|
184
|
-
try:
|
|
185
|
-
self._wait_connect[
|
|
186
|
-
chat_id
|
|
187
|
-
] = self.loop.create_future()
|
|
188
|
-
payload = await self._binding.init_presentation(
|
|
189
|
-
chat_id,
|
|
190
|
-
)
|
|
191
|
-
result_params = await self._app.join_presentation(
|
|
192
|
-
chat_id,
|
|
193
|
-
payload,
|
|
194
|
-
)
|
|
195
|
-
await self._binding.connect(
|
|
196
|
-
chat_id,
|
|
197
|
-
result_params,
|
|
198
|
-
True,
|
|
199
|
-
)
|
|
200
|
-
await self._wait_connect[chat_id]
|
|
201
|
-
self._presentations.add(chat_id)
|
|
202
|
-
except TelegramServerError:
|
|
203
|
-
if retries == 3:
|
|
204
|
-
raise
|
|
205
|
-
log_retries(retries)
|
|
206
|
-
finally:
|
|
207
|
-
self._wait_connect.pop(chat_id, None)
|
|
208
|
-
elif chat_id in self._presentations:
|
|
209
|
-
await self._binding.stop_presentation(chat_id)
|
|
210
|
-
await self._app.leave_presentation(chat_id)
|
|
211
|
-
self._presentations.discard(chat_id)
|
|
212
|
-
|
|
213
|
-
if isinstance(config, GroupCallConfig):
|
|
214
|
-
participants = await self._app.get_group_call_participants(
|
|
178
|
+
await self._join_presentation(
|
|
215
179
|
chat_id,
|
|
180
|
+
media_description.screen is not None,
|
|
216
181
|
)
|
|
217
|
-
|
|
218
|
-
if x.video_info is not None:
|
|
219
|
-
self._videos_id[
|
|
220
|
-
chat_id
|
|
221
|
-
] = x.video_info.endpoint
|
|
222
|
-
self._binding.add_incoming_video(
|
|
223
|
-
chat_id,
|
|
224
|
-
x.video_info.endpoint,
|
|
225
|
-
x.video_info.sources,
|
|
226
|
-
)
|
|
227
|
-
if x.presentation_info is not None:
|
|
228
|
-
self._presentations_id[
|
|
229
|
-
chat_id
|
|
230
|
-
] = x.presentation_info.endpoint
|
|
231
|
-
self._binding.add_incoming_video(
|
|
232
|
-
chat_id,
|
|
233
|
-
x.presentation_info.endpoint,
|
|
234
|
-
x.presentation_info.sources,
|
|
235
|
-
)
|
|
236
|
-
if x.user_id == BridgedClient.chat_id(
|
|
237
|
-
self._cache_local_peer,
|
|
238
|
-
) and x.muted_by_admin:
|
|
239
|
-
self._need_unmute.add(chat_id)
|
|
182
|
+
await self._update_sources(chat_id)
|
|
240
183
|
except FileError as e:
|
|
241
184
|
raise FileNotFoundError(e)
|
|
242
185
|
except TransportParseException:
|
|
@@ -32,10 +32,16 @@ class Record(Scaffold):
|
|
|
32
32
|
if chat_id not in await self._binding.calls():
|
|
33
33
|
await self.play(chat_id, config=config)
|
|
34
34
|
try:
|
|
35
|
-
|
|
35
|
+
await self._binding.set_stream_sources(
|
|
36
36
|
chat_id,
|
|
37
37
|
StreamMode.PLAYBACK,
|
|
38
38
|
media_description,
|
|
39
39
|
)
|
|
40
|
+
if isinstance(chat_id, int) and chat_id < 0:
|
|
41
|
+
await self._join_presentation(
|
|
42
|
+
chat_id,
|
|
43
|
+
media_description.screen is not None,
|
|
44
|
+
)
|
|
45
|
+
await self._update_sources(chat_id)
|
|
40
46
|
except FileError as e:
|
|
41
47
|
raise FileNotFoundError(e)
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
from .cache_peer import CachePeer
|
|
2
2
|
from .call_holder import CallHolder
|
|
3
3
|
from .cpu_usage import CpuUsage
|
|
4
|
+
from .join_presentation import JoinPresentation
|
|
5
|
+
from .log_retries import LogRetries
|
|
4
6
|
from .ping import Ping
|
|
5
7
|
from .resolve_chat_id import ResolveChatID
|
|
6
8
|
from .run import Run
|
|
7
9
|
from .start import Start
|
|
10
|
+
from .update_sources import UpdateSources
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class Utilities(
|
|
11
14
|
CachePeer,
|
|
12
15
|
CallHolder,
|
|
13
16
|
CpuUsage,
|
|
17
|
+
JoinPresentation,
|
|
18
|
+
LogRetries,
|
|
14
19
|
Ping,
|
|
15
20
|
ResolveChatID,
|
|
16
21
|
Run,
|
|
17
22
|
Start,
|
|
23
|
+
UpdateSources,
|
|
18
24
|
):
|
|
19
25
|
pass
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from ntgcalls import TelegramServerError
|
|
4
|
+
|
|
5
|
+
from ...scaffold import Scaffold
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class JoinPresentation(Scaffold):
|
|
9
|
+
async def _join_presentation(
|
|
10
|
+
self,
|
|
11
|
+
chat_id: Union[int, str],
|
|
12
|
+
join: bool,
|
|
13
|
+
):
|
|
14
|
+
if join:
|
|
15
|
+
if chat_id in self._presentations:
|
|
16
|
+
return
|
|
17
|
+
for retries in range(4):
|
|
18
|
+
try:
|
|
19
|
+
self._wait_connect[
|
|
20
|
+
chat_id
|
|
21
|
+
] = self.loop.create_future()
|
|
22
|
+
payload = await self._binding.init_presentation(
|
|
23
|
+
chat_id,
|
|
24
|
+
)
|
|
25
|
+
result_params = await self._app.join_presentation(
|
|
26
|
+
chat_id,
|
|
27
|
+
payload,
|
|
28
|
+
)
|
|
29
|
+
await self._binding.connect(
|
|
30
|
+
chat_id,
|
|
31
|
+
result_params,
|
|
32
|
+
True,
|
|
33
|
+
)
|
|
34
|
+
await self._wait_connect[chat_id]
|
|
35
|
+
self._presentations.add(chat_id)
|
|
36
|
+
break
|
|
37
|
+
except TelegramServerError:
|
|
38
|
+
if retries == 3:
|
|
39
|
+
raise
|
|
40
|
+
self._log_retries(retries)
|
|
41
|
+
finally:
|
|
42
|
+
self._wait_connect.pop(chat_id, None)
|
|
43
|
+
elif chat_id in self._call_sources:
|
|
44
|
+
await self._binding.stop_presentation(chat_id)
|
|
45
|
+
await self._app.leave_presentation(chat_id)
|
|
46
|
+
self._presentations.discard(chat_id)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from ...scaffold import Scaffold
|
|
4
|
+
|
|
5
|
+
py_logger = logging.getLogger('pytgcalls')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LogRetries(Scaffold):
|
|
9
|
+
@staticmethod
|
|
10
|
+
def _log_retries(r: int):
|
|
11
|
+
(py_logger.warning if r >= 1 else py_logger.info)(
|
|
12
|
+
f'Telegram is having some internal server issues. '
|
|
13
|
+
f'Retrying {r + 1} of 3',
|
|
14
|
+
)
|
|
@@ -94,54 +94,66 @@ class Start(Scaffold):
|
|
|
94
94
|
action = participant.action
|
|
95
95
|
chat_peer = self._cache_user_peer.get(chat_id)
|
|
96
96
|
user_id = participant.user_id
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
if chat_id in self._call_sources:
|
|
98
|
+
call_sources = self._call_sources[chat_id]
|
|
99
|
+
was_camera = user_id in call_sources.camera
|
|
100
|
+
was_screen = user_id in call_sources.presentation
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
102
|
+
if was_camera != participant.video_camera:
|
|
103
|
+
if participant.video_info:
|
|
104
|
+
self._call_sources[chat_id].camera[
|
|
105
|
+
user_id
|
|
106
|
+
] = participant.video_info.endpoint
|
|
107
|
+
try:
|
|
108
|
+
await self._binding.add_incoming_video(
|
|
109
|
+
chat_id,
|
|
110
|
+
participant.video_info.endpoint,
|
|
111
|
+
participant.video_info.sources,
|
|
112
|
+
)
|
|
113
|
+
except (ConnectionNotFound, ConnectionError):
|
|
114
|
+
pass
|
|
115
|
+
elif user_id in self._call_sources[chat_id].camera:
|
|
116
|
+
try:
|
|
117
|
+
await self._binding.remove_incoming_video(
|
|
118
|
+
chat_id,
|
|
119
|
+
self._call_sources[
|
|
120
|
+
chat_id
|
|
121
|
+
].camera[user_id],
|
|
122
|
+
)
|
|
123
|
+
except (ConnectionNotFound, ConnectionError):
|
|
124
|
+
pass
|
|
125
|
+
self._call_sources[chat_id].camera.pop(
|
|
126
|
+
user_id, None,
|
|
118
127
|
)
|
|
119
|
-
except ConnectionNotFound:
|
|
120
|
-
pass
|
|
121
|
-
self._videos_id.pop(user_id, None)
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
self.
|
|
129
|
+
if was_screen != participant.screen_sharing:
|
|
130
|
+
if participant.presentation_info:
|
|
131
|
+
self._call_sources[chat_id].presentation[
|
|
132
|
+
user_id
|
|
133
|
+
] = participant.presentation_info.endpoint
|
|
134
|
+
try:
|
|
135
|
+
await self._binding.add_incoming_video(
|
|
136
|
+
chat_id,
|
|
137
|
+
participant.presentation_info.endpoint,
|
|
138
|
+
participant.presentation_info.sources,
|
|
139
|
+
)
|
|
140
|
+
except (ConnectionNotFound, ConnectionError):
|
|
141
|
+
pass
|
|
142
|
+
elif user_id in self._call_sources[
|
|
143
|
+
chat_id
|
|
144
|
+
].presentation:
|
|
145
|
+
try:
|
|
146
|
+
await self._binding.remove_incoming_video(
|
|
147
|
+
chat_id,
|
|
148
|
+
self._call_sources[
|
|
149
|
+
chat_id
|
|
150
|
+
].presentation[user_id],
|
|
151
|
+
)
|
|
152
|
+
except (ConnectionNotFound, ConnectionError):
|
|
153
|
+
pass
|
|
154
|
+
self._call_sources[chat_id].presentation.pop(
|
|
155
|
+
user_id, None,
|
|
141
156
|
)
|
|
142
|
-
except ConnectionNotFound:
|
|
143
|
-
pass
|
|
144
|
-
self._presentations_id.pop(user_id, None)
|
|
145
157
|
|
|
146
158
|
if chat_peer:
|
|
147
159
|
is_self = BridgedClient.chat_id(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
from typing import Optional
|
|
2
3
|
from typing import Union
|
|
3
4
|
|
|
@@ -5,6 +6,7 @@ from ntgcalls import AudioDescription
|
|
|
5
6
|
from ntgcalls import MediaDescription
|
|
6
7
|
from ntgcalls import VideoDescription
|
|
7
8
|
|
|
9
|
+
from ...media_devices.input_device import InputDevice
|
|
8
10
|
from ...types import RecordStream
|
|
9
11
|
from ...types.raw import AudioStream
|
|
10
12
|
from ...types.raw import Stream
|
|
@@ -15,9 +17,11 @@ from ...types.stream.media_stream import MediaStream
|
|
|
15
17
|
class StreamParams:
|
|
16
18
|
@staticmethod
|
|
17
19
|
async def get_stream_params(
|
|
18
|
-
stream: Optional[Stream],
|
|
20
|
+
stream: Optional[Union[str, Path, InputDevice, Stream]],
|
|
19
21
|
) -> MediaDescription:
|
|
20
22
|
if stream is not None:
|
|
23
|
+
if isinstance(stream, (str, Path, InputDevice)):
|
|
24
|
+
stream = MediaStream(stream)
|
|
21
25
|
if isinstance(stream, MediaStream):
|
|
22
26
|
await stream.check_stream()
|
|
23
27
|
elif isinstance(stream, RecordStream):
|
|
@@ -52,7 +56,7 @@ class StreamParams:
|
|
|
52
56
|
|
|
53
57
|
@staticmethod
|
|
54
58
|
def _parse_stream_description(
|
|
55
|
-
stream: Stream,
|
|
59
|
+
stream: Optional[Stream],
|
|
56
60
|
) -> MediaDescription:
|
|
57
61
|
return MediaDescription(
|
|
58
62
|
microphone=StreamParams._parse_media_description(
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from ...mtproto import BridgedClient
|
|
4
|
+
from ...scaffold import Scaffold
|
|
5
|
+
from ...types.calls import CallSources
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UpdateSources(Scaffold):
|
|
9
|
+
async def _update_sources(
|
|
10
|
+
self,
|
|
11
|
+
chat_id: Union[int, str],
|
|
12
|
+
):
|
|
13
|
+
participants = await self._app.get_group_call_participants(
|
|
14
|
+
chat_id,
|
|
15
|
+
)
|
|
16
|
+
if chat_id not in self._call_sources:
|
|
17
|
+
self._call_sources[chat_id] = CallSources()
|
|
18
|
+
for x in participants:
|
|
19
|
+
if x.video_info is not None and \
|
|
20
|
+
x.user_id not in self._call_sources[chat_id].camera:
|
|
21
|
+
self._call_sources[chat_id].camera[
|
|
22
|
+
x.user_id
|
|
23
|
+
] = x.video_info.endpoint
|
|
24
|
+
await self._binding.add_incoming_video(
|
|
25
|
+
chat_id,
|
|
26
|
+
x.video_info.endpoint,
|
|
27
|
+
x.video_info.sources,
|
|
28
|
+
)
|
|
29
|
+
if x.presentation_info is not None and \
|
|
30
|
+
x.user_id not in self._call_sources[chat_id].presentation:
|
|
31
|
+
self._call_sources[chat_id].presentation[
|
|
32
|
+
x.user_id
|
|
33
|
+
] = x.presentation_info.endpoint
|
|
34
|
+
await self._binding.add_incoming_video(
|
|
35
|
+
chat_id,
|
|
36
|
+
x.presentation_info.endpoint,
|
|
37
|
+
x.presentation_info.sources,
|
|
38
|
+
)
|
|
39
|
+
if x.user_id == BridgedClient.chat_id(
|
|
40
|
+
self._cache_local_peer,
|
|
41
|
+
) and x.muted_by_admin:
|
|
42
|
+
self._need_unmute.add(chat_id)
|
pytgcalls/scaffold.py
CHANGED
|
@@ -22,8 +22,7 @@ class Scaffold(HandlersHolder):
|
|
|
22
22
|
self.loop = None
|
|
23
23
|
self._need_unmute = set()
|
|
24
24
|
self._p2p_configs = dict()
|
|
25
|
-
self.
|
|
26
|
-
self._presentations_id = dict()
|
|
25
|
+
self._call_sources = dict()
|
|
27
26
|
self._wait_connect = dict()
|
|
28
27
|
self._presentations = set()
|
|
29
28
|
|
|
@@ -42,5 +41,15 @@ class Scaffold(HandlersHolder):
|
|
|
42
41
|
async def play(self, chat_id: Union[int, str], stream=None, config=None):
|
|
43
42
|
pass
|
|
44
43
|
|
|
44
|
+
async def _update_sources(self, chat_id: Union[int, str]):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
async def _join_presentation(self, chat_id: Union[int, str], join: bool):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def _log_retries(r: int):
|
|
52
|
+
pass
|
|
53
|
+
|
|
45
54
|
def on_update(self, filters=None):
|
|
46
55
|
pass
|
|
@@ -2,6 +2,7 @@ from .call import Call
|
|
|
2
2
|
from .call_config import CallConfig
|
|
3
3
|
from .call_data import CallData
|
|
4
4
|
from .call_protocol import CallProtocol
|
|
5
|
+
from .call_sources import CallSources
|
|
5
6
|
from .group_call_config import GroupCallConfig
|
|
6
7
|
from .raw_call_update import RawCallUpdate
|
|
7
8
|
|
|
@@ -10,6 +11,7 @@ __all__ = (
|
|
|
10
11
|
'CallData',
|
|
11
12
|
'CallConfig',
|
|
12
13
|
'CallProtocol',
|
|
14
|
+
'CallSources',
|
|
13
15
|
'GroupCallConfig',
|
|
14
16
|
'RawCallUpdate',
|
|
15
17
|
)
|
|
@@ -91,7 +91,6 @@ class MediaStream(Stream):
|
|
|
91
91
|
if media_path & ExternalMedia.VIDEO:
|
|
92
92
|
self._is_video_external = True
|
|
93
93
|
elif isinstance(media_path, (InputDevice, ScreenDevice)):
|
|
94
|
-
print('MediaStream', media_path.is_video)
|
|
95
94
|
if media_path.is_video:
|
|
96
95
|
self._media_path = media_path.metadata
|
|
97
96
|
self._is_media_device = True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|