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.
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/METADATA +2 -2
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/RECORD +38 -24
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/WHEEL +1 -1
- pytgcalls/__version__.py +1 -1
- pytgcalls/exceptions.py +0 -7
- pytgcalls/methods/__init__.py +2 -0
- pytgcalls/methods/internal/__init__.py +35 -0
- pytgcalls/methods/internal/clear_cache.py +8 -0
- pytgcalls/methods/internal/clear_call.py +20 -0
- pytgcalls/methods/internal/connect_call.py +133 -0
- pytgcalls/methods/internal/emit_sig_data.py +9 -0
- pytgcalls/methods/internal/handle_connection_changed.py +27 -0
- pytgcalls/methods/internal/handle_mtproto_updates.py +175 -0
- pytgcalls/methods/internal/handle_stream_ended.py +23 -0
- pytgcalls/methods/internal/handle_stream_frame.py +41 -0
- pytgcalls/methods/internal/join_presentation.py +58 -0
- pytgcalls/methods/internal/request_broadcast_part.py +42 -0
- pytgcalls/methods/internal/request_broadcast_timestamp.py +25 -0
- pytgcalls/methods/internal/switch_connection.py +35 -0
- pytgcalls/methods/internal/update_status.py +22 -0
- pytgcalls/methods/stream/play.py +6 -107
- pytgcalls/methods/stream/record.py +0 -6
- pytgcalls/methods/utilities/__init__.py +0 -6
- pytgcalls/methods/utilities/start.py +23 -296
- pytgcalls/mtproto/bridged_client.py +28 -7
- pytgcalls/mtproto/client_cache.py +0 -1
- pytgcalls/mtproto/hydrogram_client.py +57 -0
- pytgcalls/mtproto/mtproto_client.py +33 -2
- pytgcalls/mtproto/pyrogram_client.py +61 -4
- pytgcalls/mtproto/telethon_client.py +57 -0
- pytgcalls/scaffold.py +79 -0
- pytgcalls/types/__init__.py +2 -0
- pytgcalls/types/calls/__init__.py +2 -0
- pytgcalls/types/calls/pending_connection.py +17 -0
- pytgcalls/methods/utilities/join_presentation.py +0 -50
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/licenses/LICENSE +0 -0
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/top_level.txt +0 -0
- /pytgcalls/methods/{utilities → internal}/log_retries.py +0 -0
- /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}')
|
pytgcalls/methods/stream/play.py
CHANGED
|
@@ -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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|