py-tgcalls 2.0.6__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.
Files changed (44) hide show
  1. {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/METADATA +6 -8
  2. {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/RECORD +41 -35
  3. {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/WHEEL +1 -1
  4. pytgcalls/__init__.py +2 -0
  5. pytgcalls/__version__.py +1 -1
  6. pytgcalls/filters.py +46 -7
  7. pytgcalls/media_devices/__init__.py +6 -2
  8. pytgcalls/media_devices/device_info.py +8 -15
  9. pytgcalls/media_devices/input_device.py +11 -0
  10. pytgcalls/media_devices/media_devices.py +41 -92
  11. pytgcalls/media_devices/screen_device.py +10 -0
  12. pytgcalls/media_devices/speaker_device.py +10 -0
  13. pytgcalls/methods/stream/__init__.py +4 -2
  14. pytgcalls/methods/stream/play.py +73 -11
  15. pytgcalls/methods/stream/record.py +41 -0
  16. pytgcalls/methods/stream/{played_time.py → time.py} +5 -3
  17. pytgcalls/methods/utilities/call_holder.py +5 -2
  18. pytgcalls/methods/utilities/start.py +118 -13
  19. pytgcalls/methods/utilities/stream_params.py +63 -22
  20. pytgcalls/mtproto/bridged_client.py +34 -2
  21. pytgcalls/mtproto/client_cache.py +46 -16
  22. pytgcalls/mtproto/hydrogram_client.py +53 -11
  23. pytgcalls/mtproto/mtproto_client.py +30 -4
  24. pytgcalls/mtproto/pyrogram_client.py +53 -11
  25. pytgcalls/mtproto/telethon_client.py +61 -19
  26. pytgcalls/scaffold.py +6 -0
  27. pytgcalls/types/__init__.py +10 -4
  28. pytgcalls/types/calls/call.py +5 -3
  29. pytgcalls/types/chats/group_call_participant.py +21 -0
  30. pytgcalls/types/raw/audio_stream.py +3 -3
  31. pytgcalls/types/raw/stream.py +8 -4
  32. pytgcalls/types/raw/video_stream.py +3 -3
  33. pytgcalls/types/stream/__init__.py +10 -4
  34. pytgcalls/types/stream/device.py +24 -0
  35. pytgcalls/types/stream/direction.py +18 -0
  36. pytgcalls/types/stream/media_stream.py +35 -29
  37. pytgcalls/types/stream/record_stream.py +93 -0
  38. pytgcalls/types/stream/stream_ended.py +32 -0
  39. pytgcalls/types/stream/stream_frame.py +35 -0
  40. pytgcalls/media_devices/screen_info.py +0 -45
  41. pytgcalls/types/stream/stream_audio_ended.py +0 -9
  42. pytgcalls/types/stream/stream_video_ended.py +0 -9
  43. {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dev1.dist-info}/LICENSE +0 -0
  44. {py_tgcalls-2.0.6.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 set_participants_cache(
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
- participants: Optional[
57
- ParticipantList
58
- ] = self._call_participants_cache.get(
56
+ return self._internal_set_participants_cache(
59
57
  chat_id,
58
+ participant,
60
59
  )
61
- if participants is not None:
62
- participants.last_mtproto_update = (
63
- int(time()) + self._cache_duration
64
- )
65
- return participants.update_participant(participant)
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.set_participants_cache(
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.put(
126
- chat_id,
127
- ParticipantList(
128
- input_call.id,
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.set_participants_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
- call: GroupCall = (
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
- ).call
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
- update,
399
- UpdateGroupCallParticipants,
407
+ update,
408
+ UpdateGroupCallParticipants,
400
409
  ):
401
410
  participants = update.participants
402
411
  for participant in participants:
403
- self._cache.set_participants_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
- paused_status: Optional[bool],
558
- stopped_status: Optional[bool],
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
- video_stopped=stopped_status,
569
- video_paused=paused_status,
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
- paused_status: Optional[bool],
191
- stopped_status: Optional[bool],
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
- paused_status,
199
- stopped_status,
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.set_participants_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
- call: GroupCall = (
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
- ).call
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
- update,
407
- UpdateGroupCallParticipants,
415
+ update,
416
+ UpdateGroupCallParticipants,
408
417
  ):
409
418
  participants = update.participants
410
419
  for participant in participants:
411
- self._cache.set_participants_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
- paused_status: Optional[bool],
566
- stopped_status: Optional[bool],
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
- video_stopped=stopped_status,
577
- video_paused=paused_status,
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.set_participants_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
- try:
299
- call: GroupCall = (
300
- await self._app(
301
- GetGroupCallRequest(
302
- call=input_call,
303
- limit=-1,
304
- ),
305
- )
306
- ).call
307
- if call.schedule_date is not None:
308
- return None
309
- except Exception as e:
310
- print(e)
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.set_participants_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
- paused_status: Optional[bool],
535
- stopped_status: Optional[bool],
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
- video_stopped=stopped_status,
546
- video_paused=paused_status,
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
@@ -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 StreamAudioEnded
15
- from .stream import StreamVideoEnded
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
- 'StreamAudioEnded',
33
- 'StreamVideoEnded',
38
+ 'StreamEnded',
39
+ 'StreamFrame',
34
40
  'Update',
35
41
  'UpdatedGroupCallParticipant',
36
42
  'VideoQuality',
@@ -6,7 +6,7 @@ from ..flag import Flag
6
6
 
7
7
  class Call(PyObject):
8
8
  class Status(Flag):
9
- PLAYING = auto()
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
- status: Status,
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.status = status
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 InputMode
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
- input_mode: InputMode,
12
+ media_source: MediaSource,
13
13
  path: str,
14
14
  parameters: AudioParameters = AudioParameters(),
15
15
  ):
16
- self.input_mode: InputMode = input_mode
16
+ self.media_source: MediaSource = media_source
17
17
  self.path: str = path
18
18
  self.parameters: AudioParameters = parameters
@@ -10,8 +10,12 @@ class Stream(PyObject):
10
10
  @statictypes
11
11
  def __init__(
12
12
  self,
13
- stream_audio: Optional[AudioStream] = None,
14
- stream_video: Optional[VideoStream] = None,
13
+ microphone: Optional[AudioStream] = None,
14
+ speaker: Optional[AudioStream] = None,
15
+ camera: Optional[VideoStream] = None,
16
+ screen: Optional[VideoStream] = None,
15
17
  ):
16
- self.stream_audio: Optional[AudioStream] = stream_audio
17
- self.stream_video: Optional[VideoStream] = stream_video
18
+ self.microphone: Optional[AudioStream] = microphone
19
+ self.speaker: Optional[AudioStream] = speaker
20
+ self.camera: Optional[VideoStream] = camera
21
+ self.screen: Optional[VideoStream] = screen