py-tgcalls 2.0.5__py3-none-any.whl → 2.1.0.dev1__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.0.5.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/METADATA +6 -8
- {py_tgcalls-2.0.5.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/RECORD +41 -35
- {py_tgcalls-2.0.5.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/WHEEL +1 -1
- pytgcalls/__init__.py +2 -0
- pytgcalls/__version__.py +1 -1
- pytgcalls/filters.py +49 -8
- pytgcalls/media_devices/__init__.py +6 -2
- pytgcalls/media_devices/device_info.py +8 -15
- pytgcalls/media_devices/input_device.py +11 -0
- pytgcalls/media_devices/media_devices.py +41 -92
- pytgcalls/media_devices/screen_device.py +10 -0
- pytgcalls/media_devices/speaker_device.py +10 -0
- pytgcalls/methods/stream/__init__.py +4 -2
- pytgcalls/methods/stream/play.py +73 -11
- pytgcalls/methods/stream/record.py +41 -0
- pytgcalls/methods/stream/{played_time.py → time.py} +5 -3
- pytgcalls/methods/utilities/call_holder.py +5 -2
- pytgcalls/methods/utilities/start.py +118 -13
- pytgcalls/methods/utilities/stream_params.py +63 -22
- pytgcalls/mtproto/bridged_client.py +34 -2
- pytgcalls/mtproto/client_cache.py +46 -16
- pytgcalls/mtproto/hydrogram_client.py +53 -11
- pytgcalls/mtproto/mtproto_client.py +30 -4
- pytgcalls/mtproto/pyrogram_client.py +53 -11
- pytgcalls/mtproto/telethon_client.py +61 -19
- pytgcalls/scaffold.py +6 -0
- pytgcalls/types/__init__.py +10 -4
- pytgcalls/types/calls/call.py +5 -3
- pytgcalls/types/chats/group_call_participant.py +21 -0
- pytgcalls/types/raw/audio_stream.py +3 -3
- pytgcalls/types/raw/stream.py +8 -4
- pytgcalls/types/raw/video_stream.py +3 -3
- pytgcalls/types/stream/__init__.py +10 -4
- pytgcalls/types/stream/device.py +24 -0
- pytgcalls/types/stream/direction.py +18 -0
- pytgcalls/types/stream/media_stream.py +35 -29
- pytgcalls/types/stream/record_stream.py +93 -0
- pytgcalls/types/stream/stream_ended.py +32 -0
- pytgcalls/types/stream/stream_frame.py +35 -0
- pytgcalls/media_devices/screen_info.py +0 -45
- pytgcalls/types/stream/stream_audio_ended.py +0 -9
- pytgcalls/types/stream/stream_video_ended.py +0 -9
- {py_tgcalls-2.0.5.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/LICENSE +0 -0
- {py_tgcalls-2.0.5.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/top_level.txt +0 -0
|
@@ -46,23 +46,52 @@ class ClientCache:
|
|
|
46
46
|
pass
|
|
47
47
|
return None
|
|
48
48
|
|
|
49
|
-
def
|
|
49
|
+
def set_participants_cache_call(
|
|
50
50
|
self,
|
|
51
51
|
input_id: int,
|
|
52
52
|
participant: GroupCallParticipant,
|
|
53
53
|
) -> Optional[GroupCallParticipant]:
|
|
54
54
|
chat_id = self.get_chat_id(input_id)
|
|
55
55
|
if chat_id is not None:
|
|
56
|
-
|
|
57
|
-
ParticipantList
|
|
58
|
-
] = self._call_participants_cache.get(
|
|
56
|
+
return self._internal_set_participants_cache(
|
|
59
57
|
chat_id,
|
|
58
|
+
participant,
|
|
60
59
|
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def set_participants_cache_chat(
|
|
63
|
+
self,
|
|
64
|
+
chat_id: int,
|
|
65
|
+
call_id: int,
|
|
66
|
+
participant: GroupCallParticipant,
|
|
67
|
+
) -> Optional[GroupCallParticipant]:
|
|
68
|
+
if self._call_participants_cache.get(chat_id) is None:
|
|
69
|
+
self._call_participants_cache.put(
|
|
70
|
+
chat_id,
|
|
71
|
+
ParticipantList(
|
|
72
|
+
call_id,
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
return self._internal_set_participants_cache(
|
|
76
|
+
chat_id,
|
|
77
|
+
participant,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def _internal_set_participants_cache(
|
|
81
|
+
self,
|
|
82
|
+
chat_id: int,
|
|
83
|
+
participant: GroupCallParticipant,
|
|
84
|
+
) -> Optional[GroupCallParticipant]:
|
|
85
|
+
participants: Optional[
|
|
86
|
+
ParticipantList
|
|
87
|
+
] = self._call_participants_cache.get(
|
|
88
|
+
chat_id,
|
|
89
|
+
)
|
|
90
|
+
if participants is not None:
|
|
91
|
+
participants.last_mtproto_update = (
|
|
92
|
+
int(time()) + self._cache_duration
|
|
93
|
+
)
|
|
94
|
+
return participants.update_participant(participant)
|
|
66
95
|
return None
|
|
67
96
|
|
|
68
97
|
async def get_participant_list(
|
|
@@ -90,7 +119,7 @@ class ClientCache:
|
|
|
90
119
|
input_call,
|
|
91
120
|
)
|
|
92
121
|
for participant in list_participants:
|
|
93
|
-
self.
|
|
122
|
+
self.set_participants_cache_call(
|
|
94
123
|
input_call.id,
|
|
95
124
|
participant,
|
|
96
125
|
)
|
|
@@ -122,12 +151,13 @@ class ClientCache:
|
|
|
122
151
|
input_call,
|
|
123
152
|
self._cache_duration,
|
|
124
153
|
)
|
|
125
|
-
self._call_participants_cache.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
if self._call_participants_cache.get(chat_id) is None:
|
|
155
|
+
self._call_participants_cache.put(
|
|
156
|
+
chat_id,
|
|
157
|
+
ParticipantList(
|
|
158
|
+
input_call.id,
|
|
159
|
+
),
|
|
160
|
+
)
|
|
131
161
|
|
|
132
162
|
def drop_cache(
|
|
133
163
|
self,
|
|
@@ -19,7 +19,9 @@ from hydrogram.raw.functions.phone import EditGroupCallParticipant
|
|
|
19
19
|
from hydrogram.raw.functions.phone import GetGroupCall
|
|
20
20
|
from hydrogram.raw.functions.phone import GetGroupParticipants
|
|
21
21
|
from hydrogram.raw.functions.phone import JoinGroupCall
|
|
22
|
+
from hydrogram.raw.functions.phone import JoinGroupCallPresentation
|
|
22
23
|
from hydrogram.raw.functions.phone import LeaveGroupCall
|
|
24
|
+
from hydrogram.raw.functions.phone import LeaveGroupCallPresentation
|
|
23
25
|
from hydrogram.raw.functions.phone import RequestCall
|
|
24
26
|
from hydrogram.raw.functions.phone import SendSignalingData
|
|
25
27
|
from hydrogram.raw.types import Channel
|
|
@@ -166,7 +168,7 @@ class HydrogramClient(BridgedClient):
|
|
|
166
168
|
):
|
|
167
169
|
participants = update.participants
|
|
168
170
|
for participant in participants:
|
|
169
|
-
result = self._cache.
|
|
171
|
+
result = self._cache.set_participants_cache_call(
|
|
170
172
|
update.call.id,
|
|
171
173
|
self.parse_participant(participant),
|
|
172
174
|
)
|
|
@@ -319,15 +321,22 @@ class HydrogramClient(BridgedClient):
|
|
|
319
321
|
).full_chat.call
|
|
320
322
|
|
|
321
323
|
if input_call is not None:
|
|
322
|
-
|
|
324
|
+
raw_call = (
|
|
323
325
|
await self._app.invoke(
|
|
324
326
|
GetGroupCall(
|
|
325
327
|
call=input_call,
|
|
326
328
|
limit=-1,
|
|
327
329
|
),
|
|
328
330
|
)
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
+
)
|
|
332
|
+
call: GroupCall = raw_call.call
|
|
333
|
+
participants: List[GroupCallParticipant] = raw_call.participants
|
|
334
|
+
for participant in participants:
|
|
335
|
+
self._cache.set_participants_cache_chat(
|
|
336
|
+
chat_id,
|
|
337
|
+
call.id,
|
|
338
|
+
self.parse_participant(participant),
|
|
339
|
+
)
|
|
331
340
|
if call.schedule_date is not None:
|
|
332
341
|
return None
|
|
333
342
|
|
|
@@ -395,12 +404,12 @@ class HydrogramClient(BridgedClient):
|
|
|
395
404
|
)
|
|
396
405
|
for update in result.updates:
|
|
397
406
|
if isinstance(
|
|
398
|
-
|
|
399
|
-
|
|
407
|
+
update,
|
|
408
|
+
UpdateGroupCallParticipants,
|
|
400
409
|
):
|
|
401
410
|
participants = update.participants
|
|
402
411
|
for participant in participants:
|
|
403
|
-
self._cache.
|
|
412
|
+
self._cache.set_participants_cache_call(
|
|
404
413
|
update.call.id,
|
|
405
414
|
self.parse_participant(participant),
|
|
406
415
|
)
|
|
@@ -409,6 +418,37 @@ class HydrogramClient(BridgedClient):
|
|
|
409
418
|
|
|
410
419
|
return json.dumps({'transport': None})
|
|
411
420
|
|
|
421
|
+
async def join_presentation(
|
|
422
|
+
self,
|
|
423
|
+
chat_id: int,
|
|
424
|
+
json_join: str,
|
|
425
|
+
):
|
|
426
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
427
|
+
if chat_call is not None:
|
|
428
|
+
result: Updates = await self._app.invoke(
|
|
429
|
+
JoinGroupCallPresentation(
|
|
430
|
+
call=chat_call,
|
|
431
|
+
params=DataJSON(data=json_join),
|
|
432
|
+
),
|
|
433
|
+
)
|
|
434
|
+
for update in result.updates:
|
|
435
|
+
if isinstance(update, UpdateGroupCallConnection):
|
|
436
|
+
return update.params.data
|
|
437
|
+
|
|
438
|
+
return json.dumps({'transport': None})
|
|
439
|
+
|
|
440
|
+
async def leave_presentation(
|
|
441
|
+
self,
|
|
442
|
+
chat_id: int,
|
|
443
|
+
):
|
|
444
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
445
|
+
if chat_call is not None:
|
|
446
|
+
await self._app.invoke(
|
|
447
|
+
LeaveGroupCallPresentation(
|
|
448
|
+
call=chat_call,
|
|
449
|
+
),
|
|
450
|
+
)
|
|
451
|
+
|
|
412
452
|
async def request_call(
|
|
413
453
|
self,
|
|
414
454
|
user_id: int,
|
|
@@ -554,8 +594,9 @@ class HydrogramClient(BridgedClient):
|
|
|
554
594
|
self,
|
|
555
595
|
chat_id: int,
|
|
556
596
|
muted_status: Optional[bool],
|
|
557
|
-
|
|
558
|
-
|
|
597
|
+
video_paused: Optional[bool],
|
|
598
|
+
video_stopped: Optional[bool],
|
|
599
|
+
presentation_paused: Optional[bool],
|
|
559
600
|
participant: InputPeer,
|
|
560
601
|
):
|
|
561
602
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
@@ -565,8 +606,9 @@ class HydrogramClient(BridgedClient):
|
|
|
565
606
|
call=chat_call,
|
|
566
607
|
participant=participant,
|
|
567
608
|
muted=muted_status,
|
|
568
|
-
|
|
569
|
-
|
|
609
|
+
video_paused=video_paused,
|
|
610
|
+
video_stopped=video_stopped,
|
|
611
|
+
presentation_paused=presentation_paused,
|
|
570
612
|
),
|
|
571
613
|
)
|
|
572
614
|
|
|
@@ -69,6 +69,30 @@ class MtProtoClient:
|
|
|
69
69
|
else:
|
|
70
70
|
raise InvalidMTProtoClient()
|
|
71
71
|
|
|
72
|
+
async def join_presentation(
|
|
73
|
+
self,
|
|
74
|
+
chat_id: int,
|
|
75
|
+
json_join: str,
|
|
76
|
+
):
|
|
77
|
+
if self._bind_client is not None:
|
|
78
|
+
return await self._bind_client.join_presentation(
|
|
79
|
+
chat_id,
|
|
80
|
+
json_join,
|
|
81
|
+
)
|
|
82
|
+
else:
|
|
83
|
+
raise InvalidMTProtoClient()
|
|
84
|
+
|
|
85
|
+
async def leave_presentation(
|
|
86
|
+
self,
|
|
87
|
+
chat_id: int,
|
|
88
|
+
):
|
|
89
|
+
if self._bind_client is not None:
|
|
90
|
+
return await self._bind_client.leave_presentation(
|
|
91
|
+
chat_id,
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
raise InvalidMTProtoClient()
|
|
95
|
+
|
|
72
96
|
async def request_call(
|
|
73
97
|
self,
|
|
74
98
|
user_id: int,
|
|
@@ -187,16 +211,18 @@ class MtProtoClient:
|
|
|
187
211
|
self,
|
|
188
212
|
chat_id: int,
|
|
189
213
|
muted_status: Optional[bool],
|
|
190
|
-
|
|
191
|
-
|
|
214
|
+
video_paused: Optional[bool],
|
|
215
|
+
video_stopped: Optional[bool],
|
|
216
|
+
presentation_paused: Optional[bool],
|
|
192
217
|
participant: Any,
|
|
193
218
|
):
|
|
194
219
|
if self._bind_client is not None:
|
|
195
220
|
await self._bind_client.set_call_status(
|
|
196
221
|
chat_id,
|
|
197
222
|
muted_status,
|
|
198
|
-
|
|
199
|
-
|
|
223
|
+
video_paused,
|
|
224
|
+
video_stopped,
|
|
225
|
+
presentation_paused,
|
|
200
226
|
participant,
|
|
201
227
|
)
|
|
202
228
|
else:
|
|
@@ -21,7 +21,9 @@ from pyrogram.raw.functions.phone import EditGroupCallParticipant
|
|
|
21
21
|
from pyrogram.raw.functions.phone import GetGroupCall
|
|
22
22
|
from pyrogram.raw.functions.phone import GetGroupParticipants
|
|
23
23
|
from pyrogram.raw.functions.phone import JoinGroupCall
|
|
24
|
+
from pyrogram.raw.functions.phone import JoinGroupCallPresentation
|
|
24
25
|
from pyrogram.raw.functions.phone import LeaveGroupCall
|
|
26
|
+
from pyrogram.raw.functions.phone import LeaveGroupCallPresentation
|
|
25
27
|
from pyrogram.raw.functions.phone import RequestCall
|
|
26
28
|
from pyrogram.raw.functions.phone import SendSignalingData
|
|
27
29
|
from pyrogram.raw.types import Channel
|
|
@@ -174,7 +176,7 @@ class PyrogramClient(BridgedClient):
|
|
|
174
176
|
):
|
|
175
177
|
participants = update.participants
|
|
176
178
|
for participant in participants:
|
|
177
|
-
result = self._cache.
|
|
179
|
+
result = self._cache.set_participants_cache_call(
|
|
178
180
|
update.call.id,
|
|
179
181
|
self.parse_participant(participant),
|
|
180
182
|
)
|
|
@@ -327,15 +329,22 @@ class PyrogramClient(BridgedClient):
|
|
|
327
329
|
).full_chat.call
|
|
328
330
|
|
|
329
331
|
if input_call is not None:
|
|
330
|
-
|
|
332
|
+
raw_call = (
|
|
331
333
|
await self._app.send(
|
|
332
334
|
GetGroupCall(
|
|
333
335
|
call=input_call,
|
|
334
336
|
limit=-1,
|
|
335
337
|
),
|
|
336
338
|
)
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
+
)
|
|
340
|
+
call: GroupCall = raw_call.call
|
|
341
|
+
participants: List[GroupCallParticipant] = raw_call.participants
|
|
342
|
+
for participant in participants:
|
|
343
|
+
self._cache.set_participants_cache_chat(
|
|
344
|
+
chat_id,
|
|
345
|
+
call.id,
|
|
346
|
+
self.parse_participant(participant),
|
|
347
|
+
)
|
|
339
348
|
if call.schedule_date is not None:
|
|
340
349
|
return None
|
|
341
350
|
|
|
@@ -403,12 +412,12 @@ class PyrogramClient(BridgedClient):
|
|
|
403
412
|
)
|
|
404
413
|
for update in result.updates:
|
|
405
414
|
if isinstance(
|
|
406
|
-
|
|
407
|
-
|
|
415
|
+
update,
|
|
416
|
+
UpdateGroupCallParticipants,
|
|
408
417
|
):
|
|
409
418
|
participants = update.participants
|
|
410
419
|
for participant in participants:
|
|
411
|
-
self._cache.
|
|
420
|
+
self._cache.set_participants_cache_call(
|
|
412
421
|
update.call.id,
|
|
413
422
|
self.parse_participant(participant),
|
|
414
423
|
)
|
|
@@ -417,6 +426,37 @@ class PyrogramClient(BridgedClient):
|
|
|
417
426
|
|
|
418
427
|
return json.dumps({'transport': None})
|
|
419
428
|
|
|
429
|
+
async def join_presentation(
|
|
430
|
+
self,
|
|
431
|
+
chat_id: int,
|
|
432
|
+
json_join: str,
|
|
433
|
+
):
|
|
434
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
435
|
+
if chat_call is not None:
|
|
436
|
+
result: Updates = await self._app.send(
|
|
437
|
+
JoinGroupCallPresentation(
|
|
438
|
+
call=chat_call,
|
|
439
|
+
params=DataJSON(data=json_join),
|
|
440
|
+
),
|
|
441
|
+
)
|
|
442
|
+
for update in result.updates:
|
|
443
|
+
if isinstance(update, UpdateGroupCallConnection):
|
|
444
|
+
return update.params.data
|
|
445
|
+
|
|
446
|
+
return json.dumps({'transport': None})
|
|
447
|
+
|
|
448
|
+
async def leave_presentation(
|
|
449
|
+
self,
|
|
450
|
+
chat_id: int,
|
|
451
|
+
):
|
|
452
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
453
|
+
if chat_call is not None:
|
|
454
|
+
await self._app.send(
|
|
455
|
+
LeaveGroupCallPresentation(
|
|
456
|
+
call=chat_call,
|
|
457
|
+
),
|
|
458
|
+
)
|
|
459
|
+
|
|
420
460
|
async def request_call(
|
|
421
461
|
self,
|
|
422
462
|
user_id: int,
|
|
@@ -562,8 +602,9 @@ class PyrogramClient(BridgedClient):
|
|
|
562
602
|
self,
|
|
563
603
|
chat_id: int,
|
|
564
604
|
muted_status: Optional[bool],
|
|
565
|
-
|
|
566
|
-
|
|
605
|
+
video_paused: Optional[bool],
|
|
606
|
+
video_stopped: Optional[bool],
|
|
607
|
+
presentation_paused: Optional[bool],
|
|
567
608
|
participant: InputPeer,
|
|
568
609
|
):
|
|
569
610
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
@@ -573,8 +614,9 @@ class PyrogramClient(BridgedClient):
|
|
|
573
614
|
call=chat_call,
|
|
574
615
|
participant=participant,
|
|
575
616
|
muted=muted_status,
|
|
576
|
-
|
|
577
|
-
|
|
617
|
+
video_paused=video_paused,
|
|
618
|
+
video_stopped=video_stopped,
|
|
619
|
+
presentation_paused=presentation_paused,
|
|
578
620
|
),
|
|
579
621
|
)
|
|
580
622
|
|
|
@@ -17,7 +17,9 @@ from telethon.tl.functions.phone import DiscardCallRequest
|
|
|
17
17
|
from telethon.tl.functions.phone import EditGroupCallParticipantRequest
|
|
18
18
|
from telethon.tl.functions.phone import GetGroupCallRequest
|
|
19
19
|
from telethon.tl.functions.phone import GetGroupParticipantsRequest
|
|
20
|
+
from telethon.tl.functions.phone import JoinGroupCallPresentationRequest
|
|
20
21
|
from telethon.tl.functions.phone import JoinGroupCallRequest
|
|
22
|
+
from telethon.tl.functions.phone import LeaveGroupCallPresentationRequest
|
|
21
23
|
from telethon.tl.functions.phone import LeaveGroupCallRequest
|
|
22
24
|
from telethon.tl.functions.phone import RequestCallRequest
|
|
23
25
|
from telethon.tl.functions.phone import SendSignalingDataRequest
|
|
@@ -164,7 +166,7 @@ class TelethonClient(BridgedClient):
|
|
|
164
166
|
):
|
|
165
167
|
participants = update.participants
|
|
166
168
|
for participant in participants:
|
|
167
|
-
result = self._cache.
|
|
169
|
+
result = self._cache.set_participants_cache_call(
|
|
168
170
|
update.call.id,
|
|
169
171
|
self.parse_participant(participant),
|
|
170
172
|
)
|
|
@@ -294,20 +296,27 @@ class TelethonClient(BridgedClient):
|
|
|
294
296
|
GetFullChatRequest(chat_id),
|
|
295
297
|
)
|
|
296
298
|
).full_chat.call
|
|
299
|
+
|
|
297
300
|
if input_call is not None:
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
301
|
+
raw_call = (
|
|
302
|
+
await self._app(
|
|
303
|
+
GetGroupCallRequest(
|
|
304
|
+
call=input_call,
|
|
305
|
+
limit=-1,
|
|
306
|
+
),
|
|
307
|
+
)
|
|
308
|
+
)
|
|
309
|
+
call: GroupCall = raw_call.call
|
|
310
|
+
participants: List[GroupCallParticipant] = raw_call.participants
|
|
311
|
+
for participant in participants:
|
|
312
|
+
self._cache.set_participants_cache_chat(
|
|
313
|
+
chat_id,
|
|
314
|
+
call.id,
|
|
315
|
+
self.parse_participant(participant),
|
|
316
|
+
)
|
|
317
|
+
if call.schedule_date is not None:
|
|
318
|
+
return None
|
|
319
|
+
|
|
311
320
|
return input_call
|
|
312
321
|
|
|
313
322
|
async def get_dhc(self) -> DhConfig:
|
|
@@ -377,7 +386,7 @@ class TelethonClient(BridgedClient):
|
|
|
377
386
|
):
|
|
378
387
|
participants = update.participants
|
|
379
388
|
for participant in participants:
|
|
380
|
-
self._cache.
|
|
389
|
+
self._cache.set_participants_cache_call(
|
|
381
390
|
update.call.id,
|
|
382
391
|
self.parse_participant(participant),
|
|
383
392
|
)
|
|
@@ -386,6 +395,37 @@ class TelethonClient(BridgedClient):
|
|
|
386
395
|
|
|
387
396
|
return json.dumps({'transport': None})
|
|
388
397
|
|
|
398
|
+
async def join_presentation(
|
|
399
|
+
self,
|
|
400
|
+
chat_id: int,
|
|
401
|
+
json_join: str,
|
|
402
|
+
):
|
|
403
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
404
|
+
if chat_call is not None:
|
|
405
|
+
result: Updates = await self._app(
|
|
406
|
+
JoinGroupCallPresentationRequest(
|
|
407
|
+
call=chat_call,
|
|
408
|
+
params=DataJSON(data=json_join),
|
|
409
|
+
),
|
|
410
|
+
)
|
|
411
|
+
for update in result.updates:
|
|
412
|
+
if isinstance(update, UpdateGroupCallConnection):
|
|
413
|
+
return update.params.data
|
|
414
|
+
|
|
415
|
+
return json.dumps({'transport': None})
|
|
416
|
+
|
|
417
|
+
async def leave_presentation(
|
|
418
|
+
self,
|
|
419
|
+
chat_id: int,
|
|
420
|
+
):
|
|
421
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
422
|
+
if chat_call is not None:
|
|
423
|
+
await self._app(
|
|
424
|
+
LeaveGroupCallPresentationRequest(
|
|
425
|
+
call=chat_call,
|
|
426
|
+
),
|
|
427
|
+
)
|
|
428
|
+
|
|
389
429
|
async def request_call(
|
|
390
430
|
self,
|
|
391
431
|
user_id: int,
|
|
@@ -531,8 +571,9 @@ class TelethonClient(BridgedClient):
|
|
|
531
571
|
self,
|
|
532
572
|
chat_id: int,
|
|
533
573
|
muted_status: Optional[bool],
|
|
534
|
-
|
|
535
|
-
|
|
574
|
+
video_paused: Optional[bool],
|
|
575
|
+
video_stopped: Optional[bool],
|
|
576
|
+
presentation_paused: Optional[bool],
|
|
536
577
|
participant: TypeInputPeer,
|
|
537
578
|
):
|
|
538
579
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
@@ -542,8 +583,9 @@ class TelethonClient(BridgedClient):
|
|
|
542
583
|
call=chat_call,
|
|
543
584
|
participant=participant,
|
|
544
585
|
muted=muted_status,
|
|
545
|
-
|
|
546
|
-
|
|
586
|
+
video_paused=video_paused,
|
|
587
|
+
video_stopped=video_stopped,
|
|
588
|
+
presentation_paused=presentation_paused,
|
|
547
589
|
),
|
|
548
590
|
)
|
|
549
591
|
|
pytgcalls/scaffold.py
CHANGED
|
@@ -22,7 +22,10 @@ class Scaffold(HandlersHolder):
|
|
|
22
22
|
self.loop = None
|
|
23
23
|
self._need_unmute = set()
|
|
24
24
|
self._p2p_configs = dict()
|
|
25
|
+
self._videos_id = dict()
|
|
26
|
+
self._presentations_id = dict()
|
|
25
27
|
self._wait_connect = dict()
|
|
28
|
+
self._presentations = set()
|
|
26
29
|
|
|
27
30
|
def _handle_mtproto(self):
|
|
28
31
|
pass
|
|
@@ -36,5 +39,8 @@ class Scaffold(HandlersHolder):
|
|
|
36
39
|
async def start(self):
|
|
37
40
|
pass
|
|
38
41
|
|
|
42
|
+
async def play(self, chat_id: Union[int, str], stream=None, config=None):
|
|
43
|
+
pass
|
|
44
|
+
|
|
39
45
|
def on_update(self, filters=None):
|
|
40
46
|
pass
|
pytgcalls/types/__init__.py
CHANGED
|
@@ -10,14 +10,19 @@ from .chats import ChatUpdate
|
|
|
10
10
|
from .chats import GroupCallParticipant
|
|
11
11
|
from .chats import UpdatedGroupCallParticipant
|
|
12
12
|
from .stream import AudioQuality
|
|
13
|
+
from .stream import Device
|
|
14
|
+
from .stream import Direction
|
|
13
15
|
from .stream import MediaStream
|
|
14
|
-
from .stream import
|
|
15
|
-
from .stream import
|
|
16
|
+
from .stream import RecordStream
|
|
17
|
+
from .stream import StreamEnded
|
|
18
|
+
from .stream import StreamFrame
|
|
16
19
|
from .stream import VideoQuality
|
|
17
20
|
from .update import Update
|
|
18
21
|
|
|
19
22
|
__all__ = (
|
|
20
23
|
'AudioQuality',
|
|
24
|
+
'Device',
|
|
25
|
+
'Direction',
|
|
21
26
|
'Browsers',
|
|
22
27
|
'Cache',
|
|
23
28
|
'ChatUpdate',
|
|
@@ -28,9 +33,10 @@ __all__ = (
|
|
|
28
33
|
'RawCallUpdate',
|
|
29
34
|
'GroupCallConfig',
|
|
30
35
|
'GroupCallParticipant',
|
|
36
|
+
'RecordStream',
|
|
31
37
|
'MediaStream',
|
|
32
|
-
'
|
|
33
|
-
'
|
|
38
|
+
'StreamEnded',
|
|
39
|
+
'StreamFrame',
|
|
34
40
|
'Update',
|
|
35
41
|
'UpdatedGroupCallParticipant',
|
|
36
42
|
'VideoQuality',
|
pytgcalls/types/calls/call.py
CHANGED
|
@@ -6,7 +6,7 @@ from ..flag import Flag
|
|
|
6
6
|
|
|
7
7
|
class Call(PyObject):
|
|
8
8
|
class Status(Flag):
|
|
9
|
-
|
|
9
|
+
ACTIVE = auto()
|
|
10
10
|
PAUSED = auto()
|
|
11
11
|
IDLE = auto()
|
|
12
12
|
|
|
@@ -17,8 +17,10 @@ class Call(PyObject):
|
|
|
17
17
|
def __init__(
|
|
18
18
|
self,
|
|
19
19
|
chat_id: int,
|
|
20
|
-
|
|
20
|
+
playback: Status,
|
|
21
|
+
capture: Status,
|
|
21
22
|
):
|
|
22
23
|
self.call_type = Call.Type.GROUP \
|
|
23
24
|
if chat_id < 0 else Call.Type.PRIVATE
|
|
24
|
-
self.
|
|
25
|
+
self.playback = playback
|
|
26
|
+
self.capture = capture
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
from enum import auto
|
|
2
|
+
from typing import List
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from ntgcalls import SsrcGroup
|
|
2
6
|
|
|
3
7
|
from ...types.py_object import PyObject
|
|
4
8
|
from ..flag import Flag
|
|
@@ -10,6 +14,15 @@ class GroupCallParticipant(PyObject):
|
|
|
10
14
|
LEFT = auto()
|
|
11
15
|
UPDATED = auto()
|
|
12
16
|
|
|
17
|
+
class SourceInfo(PyObject):
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
endpoint: str,
|
|
21
|
+
sources: List[SsrcGroup],
|
|
22
|
+
):
|
|
23
|
+
self.endpoint: str = endpoint
|
|
24
|
+
self.sources: List[SsrcGroup] = sources
|
|
25
|
+
|
|
13
26
|
def __init__(
|
|
14
27
|
self,
|
|
15
28
|
user_id: int,
|
|
@@ -22,6 +35,8 @@ class GroupCallParticipant(PyObject):
|
|
|
22
35
|
volume: int,
|
|
23
36
|
joined: bool,
|
|
24
37
|
left: bool,
|
|
38
|
+
video_info: Optional[SourceInfo],
|
|
39
|
+
presentation_info: Optional[SourceInfo],
|
|
25
40
|
):
|
|
26
41
|
self.user_id: int = user_id
|
|
27
42
|
self.muted: bool = muted
|
|
@@ -37,3 +52,9 @@ class GroupCallParticipant(PyObject):
|
|
|
37
52
|
self.action = self.Action.LEFT
|
|
38
53
|
else:
|
|
39
54
|
self.action = self.Action.UPDATED
|
|
55
|
+
self.video_info: Optional[
|
|
56
|
+
GroupCallParticipant.SourceInfo
|
|
57
|
+
] = video_info
|
|
58
|
+
self.presentation_info: Optional[
|
|
59
|
+
GroupCallParticipant.SourceInfo
|
|
60
|
+
] = presentation_info
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from ntgcalls import
|
|
1
|
+
from ntgcalls import MediaSource
|
|
2
2
|
|
|
3
3
|
from ...statictypes import statictypes
|
|
4
4
|
from ..py_object import PyObject
|
|
@@ -9,10 +9,10 @@ class AudioStream(PyObject):
|
|
|
9
9
|
@statictypes
|
|
10
10
|
def __init__(
|
|
11
11
|
self,
|
|
12
|
-
|
|
12
|
+
media_source: MediaSource,
|
|
13
13
|
path: str,
|
|
14
14
|
parameters: AudioParameters = AudioParameters(),
|
|
15
15
|
):
|
|
16
|
-
self.
|
|
16
|
+
self.media_source: MediaSource = media_source
|
|
17
17
|
self.path: str = path
|
|
18
18
|
self.parameters: AudioParameters = parameters
|
pytgcalls/types/raw/stream.py
CHANGED
|
@@ -10,8 +10,12 @@ class Stream(PyObject):
|
|
|
10
10
|
@statictypes
|
|
11
11
|
def __init__(
|
|
12
12
|
self,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
microphone: Optional[AudioStream] = None,
|
|
14
|
+
speaker: Optional[AudioStream] = None,
|
|
15
|
+
camera: Optional[VideoStream] = None,
|
|
16
|
+
screen: Optional[VideoStream] = None,
|
|
15
17
|
):
|
|
16
|
-
self.
|
|
17
|
-
self.
|
|
18
|
+
self.microphone: Optional[AudioStream] = microphone
|
|
19
|
+
self.speaker: Optional[AudioStream] = speaker
|
|
20
|
+
self.camera: Optional[VideoStream] = camera
|
|
21
|
+
self.screen: Optional[VideoStream] = screen
|