py-tgcalls 2.1.1__py3-none-any.whl → 2.1.2b2__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 (39) hide show
  1. {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/METADATA +2 -2
  2. {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/RECORD +38 -24
  3. {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/WHEEL +1 -1
  4. pytgcalls/__version__.py +1 -1
  5. pytgcalls/exceptions.py +0 -7
  6. pytgcalls/methods/__init__.py +2 -0
  7. pytgcalls/methods/internal/__init__.py +35 -0
  8. pytgcalls/methods/internal/clear_cache.py +8 -0
  9. pytgcalls/methods/internal/clear_call.py +20 -0
  10. pytgcalls/methods/internal/connect_call.py +133 -0
  11. pytgcalls/methods/internal/emit_sig_data.py +9 -0
  12. pytgcalls/methods/internal/handle_connection_changed.py +27 -0
  13. pytgcalls/methods/internal/handle_mtproto_updates.py +175 -0
  14. pytgcalls/methods/internal/handle_stream_ended.py +23 -0
  15. pytgcalls/methods/internal/handle_stream_frame.py +41 -0
  16. pytgcalls/methods/internal/join_presentation.py +58 -0
  17. pytgcalls/methods/internal/request_broadcast_part.py +42 -0
  18. pytgcalls/methods/internal/request_broadcast_timestamp.py +25 -0
  19. pytgcalls/methods/internal/switch_connection.py +35 -0
  20. pytgcalls/methods/internal/update_status.py +22 -0
  21. pytgcalls/methods/stream/play.py +6 -107
  22. pytgcalls/methods/stream/record.py +0 -6
  23. pytgcalls/methods/utilities/__init__.py +0 -6
  24. pytgcalls/methods/utilities/start.py +23 -296
  25. pytgcalls/mtproto/bridged_client.py +28 -7
  26. pytgcalls/mtproto/client_cache.py +0 -1
  27. pytgcalls/mtproto/hydrogram_client.py +57 -0
  28. pytgcalls/mtproto/mtproto_client.py +33 -2
  29. pytgcalls/mtproto/pyrogram_client.py +61 -4
  30. pytgcalls/mtproto/telethon_client.py +57 -0
  31. pytgcalls/scaffold.py +79 -0
  32. pytgcalls/types/__init__.py +2 -0
  33. pytgcalls/types/calls/__init__.py +2 -0
  34. pytgcalls/types/calls/pending_connection.py +17 -0
  35. pytgcalls/methods/utilities/join_presentation.py +0 -50
  36. {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/licenses/LICENSE +0 -0
  37. {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/top_level.txt +0 -0
  38. /pytgcalls/methods/{utilities → internal}/log_retries.py +0 -0
  39. /pytgcalls/methods/{utilities → internal}/update_sources.py +0 -0
@@ -0,0 +1,58 @@
1
+ from typing import Union
2
+
3
+ from ntgcalls import ConnectionError
4
+ from ntgcalls import ConnectionMode
5
+ from ntgcalls import TelegramServerError
6
+
7
+ from ...scaffold import Scaffold
8
+
9
+
10
+ class JoinPresentation(Scaffold):
11
+ async def _join_presentation(
12
+ self,
13
+ chat_id: Union[int, str],
14
+ join: bool,
15
+ ):
16
+ connection_mode = await self._binding.get_connection_mode(
17
+ chat_id,
18
+ )
19
+ if connection_mode == ConnectionMode.STREAM:
20
+ if chat_id in self._pending_connections:
21
+ self._pending_connections[chat_id].presentation = join
22
+ elif connection_mode == ConnectionMode.RTC:
23
+ if join:
24
+ if chat_id in self._presentations:
25
+ return
26
+ for retries in range(4):
27
+ try:
28
+ self._wait_connect[
29
+ chat_id
30
+ ] = self.loop.create_future()
31
+ payload = await self._binding.init_presentation(
32
+ chat_id,
33
+ )
34
+ result_params = await self._app.join_presentation(
35
+ chat_id,
36
+ payload,
37
+ )
38
+ await self._binding.connect(
39
+ chat_id,
40
+ result_params,
41
+ True,
42
+ )
43
+ await self._wait_connect[chat_id]
44
+ self._presentations.add(chat_id)
45
+ break
46
+ except TelegramServerError:
47
+ if retries == 3:
48
+ raise
49
+ self._log_retries(retries)
50
+ finally:
51
+ self._wait_connect.pop(chat_id, None)
52
+ elif chat_id in self._presentations:
53
+ try:
54
+ await self._binding.stop_presentation(chat_id)
55
+ await self._app.leave_presentation(chat_id)
56
+ except ConnectionError:
57
+ pass
58
+ self._presentations.discard(chat_id)
@@ -0,0 +1,42 @@
1
+ from ntgcalls import ConnectionError
2
+ from ntgcalls import ConnectionNotFound
3
+ from ntgcalls import MediaSegmentStatus
4
+ from ntgcalls import SegmentPartRequest
5
+
6
+ from ...scaffold import Scaffold
7
+
8
+
9
+ class RequestBroadcastPart(Scaffold):
10
+ async def _request_broadcast_part(
11
+ self,
12
+ chat_id: int,
13
+ part_request: SegmentPartRequest,
14
+ ):
15
+ part_status = MediaSegmentStatus.NOT_READY
16
+ # noinspection PyBroadException
17
+ try:
18
+ part = await self._app.download_stream(
19
+ chat_id,
20
+ part_request.timestamp,
21
+ part_request.limit,
22
+ part_request.channel_id
23
+ if part_request.channel_id > 0 else None,
24
+ part_request.quality,
25
+ )
26
+ if part is not None:
27
+ part_status = MediaSegmentStatus.SUCCESS
28
+ except Exception:
29
+ part = None
30
+ part_status = MediaSegmentStatus.RESYNC_NEEDED
31
+
32
+ try:
33
+ await self._binding.send_broadcast_part(
34
+ chat_id,
35
+ part_request.segment_id,
36
+ part_request.part_id,
37
+ part_status,
38
+ part_request.quality_update,
39
+ part,
40
+ )
41
+ except (ConnectionError, ConnectionNotFound):
42
+ pass
@@ -0,0 +1,25 @@
1
+ from ntgcalls import ConnectionError
2
+ from ntgcalls import ConnectionNotFound
3
+
4
+ from ...scaffold import Scaffold
5
+
6
+
7
+ class RequestBroadcastTimestamp(Scaffold):
8
+ async def _request_broadcast_timestamp(
9
+ self,
10
+ chat_id: int,
11
+ ):
12
+ # noinspection PyBroadException
13
+ try:
14
+ time = await self._app.get_stream_timestamp(
15
+ chat_id,
16
+ )
17
+ except Exception:
18
+ time = 0
19
+ try:
20
+ await self._binding.send_broadcast_timestamp(
21
+ chat_id,
22
+ time,
23
+ )
24
+ except (ConnectionError, ConnectionNotFound):
25
+ pass
@@ -0,0 +1,35 @@
1
+ import logging
2
+
3
+ from ntgcalls import ConnectionMode
4
+
5
+ from ...scaffold import Scaffold
6
+ from ...types.calls import CallSources
7
+
8
+ py_logger = logging.getLogger('pytgcalls')
9
+
10
+
11
+ class SwitchConnection(Scaffold):
12
+ async def _switch_connection(self, chat_id: int):
13
+ try:
14
+ connection_mode = await self._binding.get_connection_mode(
15
+ chat_id,
16
+ )
17
+ if connection_mode == ConnectionMode.STREAM and \
18
+ chat_id in self._pending_connections:
19
+ connection = self._pending_connections[chat_id]
20
+ await self._connect_call(
21
+ chat_id,
22
+ connection.media_description,
23
+ connection.config,
24
+ connection.payload,
25
+ )
26
+ if connection.presentation:
27
+ await self._join_presentation(
28
+ chat_id,
29
+ True,
30
+ )
31
+ self._call_sources[chat_id] = CallSources()
32
+ await self._update_sources(chat_id)
33
+ self._pending_connections.pop(chat_id)
34
+ except Exception as e:
35
+ py_logger.debug(f'SetPresentationStatus: {e}')
@@ -0,0 +1,22 @@
1
+ import logging
2
+
3
+ from ntgcalls import MediaState
4
+
5
+ from ...scaffold import Scaffold
6
+
7
+ py_logger = logging.getLogger('pytgcalls')
8
+
9
+
10
+ class UpdateStatus(Scaffold):
11
+ async def _update_status(self, chat_id: int, state: MediaState):
12
+ try:
13
+ await self._app.set_call_status(
14
+ chat_id,
15
+ state.muted,
16
+ state.video_paused,
17
+ state.video_stopped,
18
+ state.presentation_paused,
19
+ self._cache_user_peer.get(chat_id),
20
+ )
21
+ except Exception as e:
22
+ py_logger.debug(f'SetVideoCallStatus: {e}')
@@ -1,27 +1,19 @@
1
- import asyncio
2
1
  import logging
3
2
  from pathlib import Path
4
3
  from typing import Optional
5
4
  from typing import Union
6
5
 
7
- from ntgcalls import ConnectionNotFound
8
6
  from ntgcalls import FileError
9
7
  from ntgcalls import StreamMode
10
- from ntgcalls import TelegramServerError
11
- from ntgcalls import TransportParseException
12
8
 
13
9
  from ...exceptions import NoActiveGroupCall
14
- from ...exceptions import TimedOutAnswer
15
- from ...exceptions import UnMuteNeeded
16
10
  from ...media_devices.input_device import InputDevice
17
11
  from ...mtproto_required import mtproto_required
18
12
  from ...mutex import mutex
19
13
  from ...scaffold import Scaffold
20
14
  from ...statictypes import statictypes
21
15
  from ...types import CallConfig
22
- from ...types import CallData
23
16
  from ...types import GroupCallConfig
24
- from ...types import RawCallUpdate
25
17
  from ...types.raw import Stream
26
18
  from ..utilities.stream_params import StreamParams
27
19
 
@@ -79,103 +71,12 @@ class Play(Scaffold):
79
71
  raise NoActiveGroupCall()
80
72
 
81
73
  try:
82
- for retries in range(4):
83
- try:
84
- self._wait_connect[chat_id] = self.loop.create_future()
85
- if isinstance(config, GroupCallConfig):
86
- payload: str = await self._binding.create_call(
87
- chat_id,
88
- media_description,
89
- )
90
- result_params = await self._app.join_group_call(
91
- chat_id,
92
- payload,
93
- config.invite_hash,
94
- media_description.camera is None and
95
- media_description.screen is None,
96
- self._cache_user_peer.get(chat_id),
97
- )
98
- await self._binding.connect(
99
- chat_id,
100
- result_params,
101
- False,
102
- )
103
- else:
104
- data = self._p2p_configs.setdefault(
105
- chat_id,
106
- CallData(await self._app.get_dhc(), self.loop),
107
- )
108
- await self._binding.create_p2p_call(
109
- chat_id,
110
- media_description,
111
- )
112
- data.g_a_or_b = await self._binding.init_exchange(
113
- chat_id,
114
- data.dh_config,
115
- data.g_a_or_b,
116
- )
117
- if not data.outgoing:
118
- await self._app.accept_call(
119
- chat_id,
120
- data.g_a_or_b,
121
- self._binding.get_protocol(),
122
- )
123
- else:
124
- await self._app.request_call(
125
- chat_id,
126
- data.g_a_or_b,
127
- self._binding.get_protocol(),
128
- media_description.camera is not None or
129
- media_description.screen is not None,
130
- )
131
-
132
- try:
133
- result: RawCallUpdate = await asyncio.wait_for(
134
- data.wait_data,
135
- timeout=config.timeout,
136
- )
137
- auth_params = await self._binding.exchange_keys(
138
- chat_id,
139
- result.g_a_or_b,
140
- result.fingerprint,
141
- )
142
- if result.status & RawCallUpdate.Type.ACCEPTED:
143
- result.protocol = await self._app.confirm_call(
144
- chat_id,
145
- auth_params.g_a_or_b,
146
- auth_params.key_fingerprint,
147
- self._binding.get_protocol(),
148
- )
149
- await self._binding.connect_p2p(
150
- chat_id,
151
- result.protocol.rtc_servers,
152
- result.protocol.library_versions,
153
- result.protocol.p2p_allowed,
154
- )
155
- except asyncio.TimeoutError:
156
- try:
157
- await self._binding.stop(chat_id)
158
- except ConnectionNotFound:
159
- pass
160
- await self._app.discard_call(chat_id, True)
161
- raise TimedOutAnswer()
162
- finally:
163
- self._p2p_configs.pop(chat_id, None)
164
- await self._wait_connect[chat_id]
165
- break
166
- except TelegramServerError:
167
- if retries == 3 or is_p2p:
168
- raise
169
- self._log_retries(retries)
170
- except Exception:
171
- try:
172
- await self._binding.stop(chat_id)
173
- except ConnectionNotFound:
174
- pass
175
- raise
176
- finally:
177
- self._wait_connect.pop(chat_id, None)
178
-
74
+ await self._connect_call(
75
+ chat_id, # type: ignore
76
+ media_description,
77
+ config,
78
+ None,
79
+ )
179
80
  if isinstance(config, GroupCallConfig):
180
81
  await self._join_presentation(
181
82
  chat_id,
@@ -184,8 +85,6 @@ class Play(Scaffold):
184
85
  await self._update_sources(chat_id)
185
86
  except FileError as e:
186
87
  raise FileNotFoundError(e)
187
- except TransportParseException:
188
- raise UnMuteNeeded()
189
88
  except Exception:
190
89
  if isinstance(config, GroupCallConfig):
191
90
  self._cache_user_peer.pop(chat_id)
@@ -39,11 +39,5 @@ class Record(Scaffold):
39
39
  StreamMode.PLAYBACK,
40
40
  media_description,
41
41
  )
42
- if isinstance(chat_id, int) and chat_id < 0:
43
- await self._join_presentation(
44
- chat_id,
45
- media_description.screen is not None,
46
- )
47
- await self._update_sources(chat_id)
48
42
  except FileError as e:
49
43
  raise FileNotFoundError(e)
@@ -1,25 +1,19 @@
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
6
4
  from .ping import Ping
7
5
  from .resolve_chat_id import ResolveChatID
8
6
  from .run import Run
9
7
  from .start import Start
10
- from .update_sources import UpdateSources
11
8
 
12
9
 
13
10
  class Utilities(
14
11
  CachePeer,
15
12
  CallHolder,
16
13
  CpuUsage,
17
- JoinPresentation,
18
- LogRetries,
19
14
  Ping,
20
15
  ResolveChatID,
21
16
  Run,
22
17
  Start,
23
- UpdateSources,
24
18
  ):
25
19
  pass