py-tgcalls 2.1.0rc7__py3-none-any.whl → 2.1.2b1__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.2b1.dist-info/METADATA +126 -0
- {py_tgcalls-2.1.0rc7.dist-info → py_tgcalls-2.1.2b1.dist-info}/RECORD +44 -29
- {py_tgcalls-2.1.0rc7.dist-info → py_tgcalls-2.1.2b1.dist-info}/WHEEL +1 -1
- pytgcalls/__version__.py +1 -1
- pytgcalls/exceptions.py +7 -31
- pytgcalls/methods/__init__.py +2 -0
- pytgcalls/methods/calls/leave_call.py +1 -1
- 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 +7 -106
- pytgcalls/methods/stream/record.py +0 -6
- pytgcalls/methods/utilities/__init__.py +0 -6
- pytgcalls/methods/utilities/start.py +23 -289
- pytgcalls/mtproto/bridged_client.py +30 -8
- pytgcalls/mtproto/hydrogram_client.py +77 -5
- pytgcalls/mtproto/mtproto_client.py +37 -4
- pytgcalls/mtproto/pyrogram_client.py +81 -9
- pytgcalls/mtproto/telethon_client.py +77 -5
- pytgcalls/mutex.py +13 -1
- pytgcalls/pytgcalls.py +3 -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/types/chats/chat_update.py +8 -1
- pytgcalls/types/py_object.py +9 -10
- pytgcalls/types/stream/media_stream.py +1 -1
- pytgcalls/wait_counter_lock.py +20 -0
- py_tgcalls-2.1.0rc7.dist-info/METADATA +0 -292
- pytgcalls/methods/utilities/join_presentation.py +0 -50
- {py_tgcalls-2.1.0rc7.dist-info → py_tgcalls-2.1.2b1.dist-info/licenses}/LICENSE +0 -0
- {py_tgcalls-2.1.0rc7.dist-info → py_tgcalls-2.1.2b1.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,175 @@
|
|
|
1
|
+
from ntgcalls import ConnectionError
|
|
2
|
+
from ntgcalls import ConnectionNotFound
|
|
3
|
+
|
|
4
|
+
from ...exceptions import CallBusy
|
|
5
|
+
from ...exceptions import CallDeclined
|
|
6
|
+
from ...exceptions import CallDiscarded
|
|
7
|
+
from ...mtproto import BridgedClient
|
|
8
|
+
from ...scaffold import Scaffold
|
|
9
|
+
from ...types import CallData
|
|
10
|
+
from ...types import ChatUpdate
|
|
11
|
+
from ...types import GroupCallParticipant
|
|
12
|
+
from ...types import RawCallUpdate
|
|
13
|
+
from ...types import Update
|
|
14
|
+
from ...types import UpdatedGroupCallParticipant
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HandleMTProtoUpdates(Scaffold):
|
|
18
|
+
async def _handle_mtproto_updates(self, update: Update):
|
|
19
|
+
chat_id = update.chat_id
|
|
20
|
+
if update.chat_id in self._p2p_configs:
|
|
21
|
+
p2p_config = self._p2p_configs[chat_id]
|
|
22
|
+
if not p2p_config.wait_data.done():
|
|
23
|
+
if isinstance(update, RawCallUpdate):
|
|
24
|
+
if update.status & RawCallUpdate.Type.UPDATED_CALL:
|
|
25
|
+
p2p_config.wait_data.set_result(
|
|
26
|
+
update,
|
|
27
|
+
)
|
|
28
|
+
if isinstance(update, ChatUpdate) and \
|
|
29
|
+
p2p_config.outgoing:
|
|
30
|
+
if update.status & ChatUpdate.Status.DISCARDED_CALL:
|
|
31
|
+
self._wait_connect.pop(chat_id, None)
|
|
32
|
+
p2p_config.wait_data.set_exception(
|
|
33
|
+
CallBusy(
|
|
34
|
+
chat_id,
|
|
35
|
+
) if update.status &
|
|
36
|
+
ChatUpdate.Status.BUSY_CALL else
|
|
37
|
+
CallDeclined(
|
|
38
|
+
chat_id,
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
if chat_id in self._wait_connect and \
|
|
42
|
+
not self._wait_connect[chat_id].done():
|
|
43
|
+
if isinstance(update, ChatUpdate):
|
|
44
|
+
if update.status & ChatUpdate.Status.DISCARDED_CALL:
|
|
45
|
+
self._wait_connect[chat_id].set_exception(
|
|
46
|
+
CallDiscarded(
|
|
47
|
+
chat_id,
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
if isinstance(update, RawCallUpdate):
|
|
51
|
+
if update.status & RawCallUpdate.Type.REQUESTED:
|
|
52
|
+
self._p2p_configs[chat_id] = CallData(
|
|
53
|
+
await self._app.get_dhc(),
|
|
54
|
+
self.loop,
|
|
55
|
+
update.g_a_or_b,
|
|
56
|
+
)
|
|
57
|
+
update = ChatUpdate(
|
|
58
|
+
chat_id,
|
|
59
|
+
ChatUpdate.Status.INCOMING_CALL,
|
|
60
|
+
)
|
|
61
|
+
if isinstance(update, RawCallUpdate):
|
|
62
|
+
if update.status & RawCallUpdate.Type.SIGNALING_DATA:
|
|
63
|
+
try:
|
|
64
|
+
await self._binding.send_signaling(
|
|
65
|
+
update.chat_id,
|
|
66
|
+
update.signaling_data,
|
|
67
|
+
)
|
|
68
|
+
except (ConnectionNotFound, ConnectionError):
|
|
69
|
+
pass
|
|
70
|
+
if isinstance(update, ChatUpdate):
|
|
71
|
+
if update.status & ChatUpdate.Status.LEFT_CALL:
|
|
72
|
+
await self._clear_call(chat_id)
|
|
73
|
+
if isinstance(update, UpdatedGroupCallParticipant):
|
|
74
|
+
participant = update.participant
|
|
75
|
+
action = participant.action
|
|
76
|
+
chat_peer = self._cache_user_peer.get(chat_id)
|
|
77
|
+
user_id = participant.user_id
|
|
78
|
+
if chat_id in self._call_sources:
|
|
79
|
+
call_sources = self._call_sources[chat_id]
|
|
80
|
+
was_camera = user_id in call_sources.camera
|
|
81
|
+
was_screen = user_id in call_sources.presentation
|
|
82
|
+
|
|
83
|
+
if was_camera != participant.video_camera:
|
|
84
|
+
if participant.video_info:
|
|
85
|
+
self._call_sources[chat_id].camera[
|
|
86
|
+
user_id
|
|
87
|
+
] = participant.video_info.endpoint
|
|
88
|
+
try:
|
|
89
|
+
await self._binding.add_incoming_video(
|
|
90
|
+
chat_id,
|
|
91
|
+
participant.video_info.endpoint,
|
|
92
|
+
participant.video_info.sources,
|
|
93
|
+
)
|
|
94
|
+
except (ConnectionNotFound, ConnectionError):
|
|
95
|
+
pass
|
|
96
|
+
elif user_id in self._call_sources[chat_id].camera:
|
|
97
|
+
try:
|
|
98
|
+
await self._binding.remove_incoming_video(
|
|
99
|
+
chat_id,
|
|
100
|
+
self._call_sources[
|
|
101
|
+
chat_id
|
|
102
|
+
].camera[user_id],
|
|
103
|
+
)
|
|
104
|
+
except (ConnectionNotFound, ConnectionError):
|
|
105
|
+
pass
|
|
106
|
+
self._call_sources[chat_id].camera.pop(
|
|
107
|
+
user_id, None,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if was_screen != participant.screen_sharing:
|
|
111
|
+
if participant.presentation_info:
|
|
112
|
+
self._call_sources[chat_id].presentation[
|
|
113
|
+
user_id
|
|
114
|
+
] = participant.presentation_info.endpoint
|
|
115
|
+
try:
|
|
116
|
+
await self._binding.add_incoming_video(
|
|
117
|
+
chat_id,
|
|
118
|
+
participant.presentation_info.endpoint,
|
|
119
|
+
participant.presentation_info.sources,
|
|
120
|
+
)
|
|
121
|
+
except (ConnectionNotFound, ConnectionError):
|
|
122
|
+
pass
|
|
123
|
+
elif user_id in self._call_sources[
|
|
124
|
+
chat_id
|
|
125
|
+
].presentation:
|
|
126
|
+
try:
|
|
127
|
+
await self._binding.remove_incoming_video(
|
|
128
|
+
chat_id,
|
|
129
|
+
self._call_sources[
|
|
130
|
+
chat_id
|
|
131
|
+
].presentation[user_id],
|
|
132
|
+
)
|
|
133
|
+
except (ConnectionNotFound, ConnectionError):
|
|
134
|
+
pass
|
|
135
|
+
self._call_sources[chat_id].presentation.pop(
|
|
136
|
+
user_id, None,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if chat_peer:
|
|
140
|
+
is_self = BridgedClient.chat_id(
|
|
141
|
+
chat_peer,
|
|
142
|
+
) == participant.user_id if chat_peer else False
|
|
143
|
+
if is_self:
|
|
144
|
+
if action == GroupCallParticipant.Action.LEFT:
|
|
145
|
+
if await self._clear_call(chat_id):
|
|
146
|
+
await self._propagate(
|
|
147
|
+
ChatUpdate(
|
|
148
|
+
chat_id,
|
|
149
|
+
ChatUpdate.Status.KICKED,
|
|
150
|
+
),
|
|
151
|
+
self,
|
|
152
|
+
)
|
|
153
|
+
if (
|
|
154
|
+
chat_id in self._need_unmute and
|
|
155
|
+
action == GroupCallParticipant.Action.UPDATED and
|
|
156
|
+
not participant.muted_by_admin
|
|
157
|
+
):
|
|
158
|
+
await self._update_status(
|
|
159
|
+
chat_id,
|
|
160
|
+
await self._binding.get_state(chat_id),
|
|
161
|
+
)
|
|
162
|
+
await self._switch_connection(chat_id)
|
|
163
|
+
|
|
164
|
+
if (
|
|
165
|
+
participant.muted_by_admin and
|
|
166
|
+
action != GroupCallParticipant.Action.LEFT
|
|
167
|
+
):
|
|
168
|
+
self._need_unmute.add(chat_id)
|
|
169
|
+
else:
|
|
170
|
+
self._need_unmute.discard(chat_id)
|
|
171
|
+
if not isinstance(update, RawCallUpdate):
|
|
172
|
+
await self._propagate(
|
|
173
|
+
update,
|
|
174
|
+
self,
|
|
175
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from ntgcalls import StreamDevice
|
|
2
|
+
from ntgcalls import StreamType
|
|
3
|
+
|
|
4
|
+
from ...scaffold import Scaffold
|
|
5
|
+
from ...types import Device
|
|
6
|
+
from ...types import StreamEnded
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HandleStreamEnded(Scaffold):
|
|
10
|
+
async def _handle_stream_ended(
|
|
11
|
+
self,
|
|
12
|
+
chat_id: int,
|
|
13
|
+
stream_type: StreamType,
|
|
14
|
+
device: StreamDevice,
|
|
15
|
+
):
|
|
16
|
+
await self._propagate(
|
|
17
|
+
StreamEnded(
|
|
18
|
+
chat_id,
|
|
19
|
+
StreamEnded.Type.from_raw(stream_type),
|
|
20
|
+
Device.from_raw(device),
|
|
21
|
+
),
|
|
22
|
+
self,
|
|
23
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from ntgcalls import Frame as RawFrame
|
|
4
|
+
from ntgcalls import StreamDevice
|
|
5
|
+
from ntgcalls import StreamMode
|
|
6
|
+
|
|
7
|
+
from ...scaffold import Scaffold
|
|
8
|
+
from ...types import Device
|
|
9
|
+
from ...types import Direction
|
|
10
|
+
from ...types import Frame
|
|
11
|
+
from ...types import StreamFrames
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HandleStreamFrame(Scaffold):
|
|
15
|
+
async def _handle_stream_frame(
|
|
16
|
+
self,
|
|
17
|
+
chat_id: int,
|
|
18
|
+
mode: StreamMode,
|
|
19
|
+
device: StreamDevice,
|
|
20
|
+
frames: List[RawFrame],
|
|
21
|
+
):
|
|
22
|
+
await self._propagate(
|
|
23
|
+
StreamFrames(
|
|
24
|
+
chat_id,
|
|
25
|
+
Direction.from_raw(mode),
|
|
26
|
+
Device.from_raw(device),
|
|
27
|
+
[
|
|
28
|
+
Frame(
|
|
29
|
+
x.ssrc,
|
|
30
|
+
x.data,
|
|
31
|
+
Frame.Info(
|
|
32
|
+
x.frame_data.absolute_capture_timestamp_ms,
|
|
33
|
+
x.frame_data.width,
|
|
34
|
+
x.frame_data.height,
|
|
35
|
+
x.frame_data.rotation,
|
|
36
|
+
),
|
|
37
|
+
) for x in frames
|
|
38
|
+
],
|
|
39
|
+
),
|
|
40
|
+
self,
|
|
41
|
+
)
|
|
@@ -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
|
|
|
@@ -29,9 +21,9 @@ py_logger = logging.getLogger('pytgcalls')
|
|
|
29
21
|
|
|
30
22
|
|
|
31
23
|
class Play(Scaffold):
|
|
32
|
-
@mutex
|
|
33
24
|
@statictypes
|
|
34
25
|
@mtproto_required
|
|
26
|
+
@mutex
|
|
35
27
|
async def play(
|
|
36
28
|
self,
|
|
37
29
|
chat_id: Union[int, str],
|
|
@@ -79,101 +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
|
-
)
|
|
129
|
-
|
|
130
|
-
try:
|
|
131
|
-
result: RawCallUpdate = await asyncio.wait_for(
|
|
132
|
-
data.wait_data,
|
|
133
|
-
timeout=config.timeout,
|
|
134
|
-
)
|
|
135
|
-
auth_params = await self._binding.exchange_keys(
|
|
136
|
-
chat_id,
|
|
137
|
-
result.g_a_or_b,
|
|
138
|
-
result.fingerprint,
|
|
139
|
-
)
|
|
140
|
-
if result.status & RawCallUpdate.Type.ACCEPTED:
|
|
141
|
-
result.protocol = await self._app.confirm_call(
|
|
142
|
-
chat_id,
|
|
143
|
-
auth_params.g_a_or_b,
|
|
144
|
-
auth_params.key_fingerprint,
|
|
145
|
-
self._binding.get_protocol(),
|
|
146
|
-
)
|
|
147
|
-
await self._binding.connect_p2p(
|
|
148
|
-
chat_id,
|
|
149
|
-
result.protocol.rtc_servers,
|
|
150
|
-
result.protocol.library_versions,
|
|
151
|
-
result.protocol.p2p_allowed,
|
|
152
|
-
)
|
|
153
|
-
except asyncio.TimeoutError:
|
|
154
|
-
try:
|
|
155
|
-
await self._binding.stop(chat_id)
|
|
156
|
-
except ConnectionNotFound:
|
|
157
|
-
pass
|
|
158
|
-
await self._app.discard_call(chat_id, True)
|
|
159
|
-
raise TimedOutAnswer()
|
|
160
|
-
finally:
|
|
161
|
-
self._p2p_configs.pop(chat_id, None)
|
|
162
|
-
await self._wait_connect[chat_id]
|
|
163
|
-
break
|
|
164
|
-
except TelegramServerError:
|
|
165
|
-
if retries == 3 or is_p2p:
|
|
166
|
-
raise
|
|
167
|
-
self._log_retries(retries)
|
|
168
|
-
except Exception:
|
|
169
|
-
try:
|
|
170
|
-
await self._binding.stop(chat_id)
|
|
171
|
-
except ConnectionNotFound:
|
|
172
|
-
pass
|
|
173
|
-
raise
|
|
174
|
-
finally:
|
|
175
|
-
self._wait_connect.pop(chat_id, None)
|
|
176
|
-
|
|
74
|
+
await self._connect_call(
|
|
75
|
+
chat_id, # type: ignore
|
|
76
|
+
media_description,
|
|
77
|
+
config,
|
|
78
|
+
None,
|
|
79
|
+
)
|
|
177
80
|
if isinstance(config, GroupCallConfig):
|
|
178
81
|
await self._join_presentation(
|
|
179
82
|
chat_id,
|
|
@@ -182,8 +85,6 @@ class Play(Scaffold):
|
|
|
182
85
|
await self._update_sources(chat_id)
|
|
183
86
|
except FileError as e:
|
|
184
87
|
raise FileNotFoundError(e)
|
|
185
|
-
except TransportParseException:
|
|
186
|
-
raise UnMuteNeeded()
|
|
187
88
|
except Exception:
|
|
188
89
|
if isinstance(config, GroupCallConfig):
|
|
189
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
|