agora-python-server-sdk 2.2.1__tar.gz → 2.2.2__tar.gz

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.

Potentially problematic release.


This version of agora-python-server-sdk might be problematic. Click here for more details.

Files changed (42) hide show
  1. {agora_python_server_sdk-2.2.1/agora_python_server_sdk.egg-info → agora_python_server_sdk-2.2.2}/PKG-INFO +15 -8
  2. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/README.md +13 -0
  3. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/__init__.py +10 -0
  4. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_ctypes_handle/_ctypes_data.py +38 -2
  5. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_ctypes_handle/_local_user_observer.py +4 -4
  6. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_ctypes_handle/_rtc_connection_observer.py +8 -1
  7. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/agora_base.py +8 -1
  8. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/agora_service.py +7 -1
  9. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/local_user_observer.py +5 -4
  10. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/rtc_connection.py +22 -0
  11. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/rtc_connection_observer.py +2 -0
  12. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2/agora_python_server_sdk.egg-info}/PKG-INFO +15 -8
  13. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/setup.py +9 -1
  14. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/MANIFEST.in +0 -0
  15. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_ctypes_handle/_audio_frame_observer.py +0 -0
  16. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_ctypes_handle/_video_encoded_frame_observer.py +0 -0
  17. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_ctypes_handle/_video_frame_observer.py +0 -0
  18. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/_utils/globals.py +0 -0
  19. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/agora_parameter.py +0 -0
  20. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/audio_encoded_frame_sender.py +0 -0
  21. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/audio_frame_observer.py +0 -0
  22. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/audio_pcm_data_sender.py +0 -0
  23. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/audio_sessionctrl.py +0 -0
  24. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/audio_vad_manager.py +0 -0
  25. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/local_audio_track.py +0 -0
  26. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/local_user.py +0 -0
  27. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/local_video_track.py +0 -0
  28. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/media_node_factory.py +0 -0
  29. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/remote_audio_track.py +0 -0
  30. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/remote_video_track.py +0 -0
  31. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/utils/audio_consumer.py +0 -0
  32. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/utils/vad_dump.py +0 -0
  33. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/video_encoded_frame_observer.py +0 -0
  34. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/video_encoded_image_sender.py +0 -0
  35. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/video_frame_observer.py +0 -0
  36. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/video_frame_sender.py +0 -0
  37. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora/rtc/voice_detection.py +0 -0
  38. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora_python_server_sdk.egg-info/SOURCES.txt +0 -0
  39. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora_python_server_sdk.egg-info/dependency_links.txt +0 -0
  40. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/agora_python_server_sdk.egg-info/top_level.txt +0 -0
  41. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/pyproject.toml +0 -0
  42. {agora_python_server_sdk-2.2.1 → agora_python_server_sdk-2.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: agora_python_server_sdk
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: A Python SDK for Agora Server
5
5
  Home-page: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK
6
6
  Classifier: Intended Audience :: Developers
@@ -12,12 +12,6 @@ Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3 :: Only
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
- Dynamic: classifier
16
- Dynamic: description
17
- Dynamic: description-content-type
18
- Dynamic: home-page
19
- Dynamic: requires-python
20
- Dynamic: summary
21
15
 
22
16
  # Note
23
17
  - This is a Python SDK wrapper for the Agora RTC SDK.
@@ -56,6 +50,19 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
56
50
  ```
57
51
 
58
52
  # Change log
53
+ 2025.04.10 Release 2.2.2
54
+ -- Additions:
55
+ - Added push_video_encoded_file.py to support pushing mp4 files and h264 encoded h.264 files. Includes conversion from mp4 file avformat to raw 264 stream in annex B format.
56
+ -- Additions:
57
+ - Added set_log_file_filter function to set the log filter level.
58
+ -- Additions:
59
+ - Added support for arm64 version, but currently this version does not support audio label algorithm. Therefore, it is not supported on arm64!
60
+ -- Changes:
61
+ - Modified localuserstats, local video stats, local audio stats, remote video stats, remote audio stats.
62
+ -- Additions:
63
+ - Added connection::agora_rtc_conn_enable_encryption.
64
+ -- Additions:
65
+ - Added connectionObserver::on_encryption_error (but not working for now, need to fix in the next monthly version 4.4.32).
59
66
  2025.02.26 Release 2.2.1
60
67
  --Update:
61
68
  ​- Reduced buffer size from ​180ms​ to ​100ms​ to minimize latency.
@@ -35,6 +35,19 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
35
35
  ```
36
36
 
37
37
  # Change log
38
+ 2025.04.10 Release 2.2.2
39
+ -- Additions:
40
+ - Added push_video_encoded_file.py to support pushing mp4 files and h264 encoded h.264 files. Includes conversion from mp4 file avformat to raw 264 stream in annex B format.
41
+ -- Additions:
42
+ - Added set_log_file_filter function to set the log filter level.
43
+ -- Additions:
44
+ - Added support for arm64 version, but currently this version does not support audio label algorithm. Therefore, it is not supported on arm64!
45
+ -- Changes:
46
+ - Modified localuserstats, local video stats, local audio stats, remote video stats, remote audio stats.
47
+ -- Additions:
48
+ - Added connection::agora_rtc_conn_enable_encryption.
49
+ -- Additions:
50
+ - Added connectionObserver::on_encryption_error (but not working for now, need to fix in the next monthly version 4.4.32).
38
51
  2025.02.26 Release 2.2.1
39
52
  --Update:
40
53
  ​- Reduced buffer size from ​180ms​ to ​100ms​ to minimize latency.
@@ -8,6 +8,7 @@ from urllib import request
8
8
  import ctypes
9
9
  import os
10
10
  import sys
11
+ import platform
11
12
  import logging
12
13
  logger = logging.getLogger(__name__)
13
14
  ssl._create_default_https_context = ssl._create_unverified_context
@@ -26,6 +27,12 @@ def _check_download_and_extract_sdk():
26
27
  sdk_dir = os.path.join(agora_service_path, "agora_sdk")
27
28
  zip_path = os.path.join(agora_service_path, "agora_rtc_sdk.zip")
28
29
 
30
+ # for diff os and arch
31
+ arch = platform.machine()
32
+ os_type = platform.system()
33
+
34
+
35
+
29
36
  #url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.30-20241024_101940-398537.zip"
30
37
  # version 2.2.0 for linux
31
38
  url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.31-20241223_111509-491956.zip"
@@ -42,6 +49,9 @@ def _check_download_and_extract_sdk():
42
49
  libagora_rtc_sdk_path = os.path.join(sdk_dir, "libAgoraRtcKit.dylib")
43
50
  #rtc_md5 = "ca3ca14f9e2b7d97eb2594d1f32dab9f"
44
51
  rtc_md5 = "6821cae218c8f31f8d720ac0c77edab0"
52
+ if arch == "aarch64" and sys.platform == 'linux':
53
+ url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.31-20250307_175457-603878.zip"
54
+ rtc_md5 = "41d200483e2e2e913a617c59b9d922b0"
45
55
 
46
56
 
47
57
  if os.path.exists(libagora_rtc_sdk_path) and get_file_md5(libagora_rtc_sdk_path) == rtc_md5:
@@ -267,7 +267,7 @@ class LocalAudioStatsInner(ctypes.Structure):
267
267
  ]
268
268
 
269
269
  def get(self):
270
- return LocalAudioStats(
270
+ return LocalAudioTrackStats(
271
271
  num_channels=self.num_channels,
272
272
  sent_sample_rate=self.sent_sample_rate,
273
273
  sent_bitrate=self.sent_bitrate,
@@ -276,7 +276,7 @@ class LocalAudioStatsInner(ctypes.Structure):
276
276
  )
277
277
 
278
278
  @staticmethod
279
- def create(stats: LocalAudioStats) -> 'LocalAudioStatsInner':
279
+ def create(stats: LocalAudioTrackStats) -> 'LocalAudioStatsInner':
280
280
  return LocalAudioStatsInner(
281
281
  stats.num_channels,
282
282
  stats.sent_sample_rate,
@@ -1210,3 +1210,39 @@ class EncodedVideoFrameInfoInner(ctypes.Structure):
1210
1210
  info.uid,
1211
1211
  info.stream_type
1212
1212
  )
1213
+
1214
+
1215
+
1216
+ class EncryptionConfigInner(ctypes.Structure):
1217
+ _fields_ = [
1218
+ ("encryption_mode", ctypes.c_int),
1219
+ ("encryption_key", ctypes.c_char_p),
1220
+ ("encryption_kdf_salt", ctypes.c_uint8 * 32)
1221
+ ]
1222
+
1223
+ def get(self):
1224
+ return EncryptionConfig(
1225
+ encryption_mode=self.encryption_mode,
1226
+ encryption_key=self.encryption_key.decode() if self.encryption_key else "",
1227
+ encryption_kdf_salt=bytearray(bytes(self.encryption_kdf_salt))
1228
+ )
1229
+
1230
+ @staticmethod
1231
+ def create(config: EncryptionConfig) -> 'EncryptionConfigInner':
1232
+ length = len(config.encryption_kdf_salt) if config.encryption_kdf_salt else 0
1233
+ # 如果length大于32,则设置为32
1234
+ if length > 32:
1235
+ length = 32
1236
+ #change bytearray to uint8 * length
1237
+ if length > 0:
1238
+ encryption_kdf_salt = (ctypes.c_uint8 * length)(*config.encryption_kdf_salt)
1239
+ else:
1240
+ encryption_kdf_salt = (ctypes.c_uint8 * 32)() # 32 bytes,empty array
1241
+ # change encryption_key to c_char_p
1242
+ encryption_key = config.encryption_key.encode('utf-8') if config.encryption_key else None
1243
+ #change None to c_char_p
1244
+ return EncryptionConfigInner(
1245
+ config.encryption_mode,
1246
+ encryption_key,
1247
+ encryption_kdf_salt
1248
+ )
@@ -180,7 +180,7 @@ class RTCLocalUserObserverInner(ctypes.Structure):
180
180
  self.local_user_observer.on_local_audio_track_state_changed(self.local_user, audio_track, state, error)
181
181
 
182
182
  def _on_local_audio_track_statistics(self, local_user_handle, stats):
183
- local_audio_stats = stats.contents
183
+ local_audio_stats = stats.contents.get() if stats else None
184
184
  self.local_user_observer.on_local_audio_track_statistics(self.local_user, local_audio_stats)
185
185
 
186
186
  def _on_user_audio_track_subscribed(self, local_user_handle, user_id, remote_audio_track_handle):
@@ -194,7 +194,7 @@ class RTCLocalUserObserverInner(ctypes.Structure):
194
194
 
195
195
  def _on_remote_audio_track_statistics(self, local_user_handle, remote_audio_track_handle, stats):
196
196
  logger.debug(f"LocalUserCB _on_remote_audio_track_statistics: {local_user_handle}, {remote_audio_track_handle}, {stats}")
197
- audio_stats = stats.contents # RemoteAudioTrackStats
197
+ audio_stats = stats.contents.get() if stats else None
198
198
  remote_audio_track = self.local_user.get_remote_audio_map(remote_audio_track_handle)
199
199
  self.local_user_observer.on_remote_audio_track_statistics(self.local_user, remote_audio_track, audio_stats)
200
200
 
@@ -246,7 +246,7 @@ class RTCLocalUserObserverInner(ctypes.Structure):
246
246
  logger.debug(f"LocalUserCB _on_local_video_track_statistics: {local_user_handle}, {local_video_track_handle}, {stats}")
247
247
  # stats: ctypes.pointer to LocalVideoTrackStats
248
248
  local_video_track = self.local_user.get_video_map(local_video_track_handle)
249
- video_stats = stats.contents
249
+ video_stats = stats.contents.get() if stats else None
250
250
  self.local_user_observer.on_local_video_track_statistics(self.local_user, local_video_track, video_stats)
251
251
 
252
252
  def _on_user_video_track_subscribed(self, local_user_handle, user_id, video_track_info, remote_video_track_handle):
@@ -269,7 +269,7 @@ class RTCLocalUserObserverInner(ctypes.Structure):
269
269
 
270
270
  def _on_remote_video_track_statistics(self, local_user_handle, remote_video_track_handle, stats_ptr):
271
271
  logger.debug(f"LocalUserCB _on_remote_video_track_statistics: {local_user_handle}, {remote_video_track_handle}, {stats_ptr}")
272
- remote_stats = stats_ptr.contents # RemoteVideoTrackStats
272
+ remote_stats = stats_ptr.contents.get() if stats_ptr else None
273
273
  video_track = self.local_user.get_remote_video_map(remote_video_track_handle)
274
274
  self.local_user_observer.on_remote_video_track_statistics(self.local_user, video_track, remote_stats)
275
275
 
@@ -44,6 +44,7 @@ ON_STREAM_MESSAGE_ERROR_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, user_id_
44
44
  ON_ENCRYPTION_ERROR_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, ctypes.c_int)
45
45
  ON_UPLOAD_LOG_RESULT_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, ctypes.c_char_p, ctypes.c_int, ctypes.c_int)
46
46
 
47
+ ON_ENCRYPTION_ERROR_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, ctypes.c_int)
47
48
 
48
49
  class RTCConnectionObserverInner(ctypes.Structure):
49
50
  _fields_ = [
@@ -81,7 +82,8 @@ class RTCConnectionObserverInner(ctypes.Structure):
81
82
  ("on_user_account_updated", ON_USER_ACCOUNT_UPDATED_CALLBACK),
82
83
  ("on_stream_message_error", ON_STREAM_MESSAGE_ERROR_CALLBACK),
83
84
  ("on_encryption_error", ON_ENCRYPTION_ERROR_CALLBACK),
84
- ("on_upload_log_result", ON_UPLOAD_LOG_RESULT_CALLBACK)
85
+ ("on_upload_log_result", ON_UPLOAD_LOG_RESULT_CALLBACK),
86
+ ("on_encryption_error", ON_ENCRYPTION_ERROR_CALLBACK)
85
87
  ]
86
88
 
87
89
  def __init__(self, conn_observer: IRTCConnectionObserver, connection: 'RTCConnection') -> None:
@@ -118,6 +120,7 @@ class RTCConnectionObserverInner(ctypes.Structure):
118
120
  self.on_stream_message_error = ON_STREAM_MESSAGE_ERROR_CALLBACK(self._on_stream_message_error)
119
121
  self.on_encryption_error = ON_ENCRYPTION_ERROR_CALLBACK(self._on_encryption_error)
120
122
  self.on_upload_log_result = ON_UPLOAD_LOG_RESULT_CALLBACK(self._on_upload_log_result)
123
+ self.on_encryption_error = ON_ENCRYPTION_ERROR_CALLBACK(self._on_encryption_error)
121
124
 
122
125
  def _on_connected(self, agora_rtc_conn, conn_info_inner, reason):
123
126
  logger.debug(f"ConnCB _on_connected: {agora_rtc_conn}, {conn_info_inner}, {reason}")
@@ -263,3 +266,7 @@ class RTCConnectionObserverInner(ctypes.Structure):
263
266
  logger.debug(f"ConnCB _on_upload_log_result: {agora_rtc_conn}, {request_id}, {success}, {reason}")
264
267
  _request_id_str = request_id.decode("utf-8") if request_id else ""
265
268
  self.conn_observer.on_upload_log_result(self.conn, _request_id_str, success, reason)
269
+
270
+ def _on_encryption_error(self, agora_rtc_conn, error_type):
271
+ logger.debug(f"ConnCB _on_encryption_error: {agora_rtc_conn}, {error_type}")
272
+ self.conn_observer.on_encryption_error(self.conn, error_type)
@@ -145,7 +145,7 @@ class RTCStats:
145
145
 
146
146
 
147
147
  @dataclass(frozen=True, kw_only=True)
148
- class LocalAudioStats:
148
+ class LocalAudioTrackStats:
149
149
  num_channels: int
150
150
  sent_sample_rate: int
151
151
  sent_bitrate: int
@@ -512,3 +512,10 @@ class LocalAudioDetailedStats:
512
512
  typing_noise_detected: int
513
513
  ana_statistics: AnaStats
514
514
  apm_statistics: AudioProcessingStats
515
+
516
+
517
+ @dataclass(kw_only=True)
518
+ class EncryptionConfig:
519
+ encryption_mode: int
520
+ encryption_key: str
521
+ encryption_kdf_salt: bytearray = None
@@ -59,6 +59,11 @@ agora_service_create_custom_video_track_encoded = agora_lib.agora_service_create
59
59
  agora_service_create_custom_video_track_encoded.restype = AGORA_HANDLE
60
60
  agora_service_create_custom_video_track_encoded.argtypes = [AGORA_HANDLE, AGORA_HANDLE, ctypes.POINTER(SenderOptionsInner)]
61
61
 
62
+ #for version 2.2.2
63
+ agora_service_set_log_filter = agora_lib.agora_service_set_log_filter
64
+ agora_service_set_log_filter.restype = AGORA_API_C_INT
65
+ agora_service_set_log_filter.argtypes = [AGORA_HANDLE, ctypes.c_uint]
66
+
62
67
 
63
68
  class AgoraService:
64
69
  def __init__(self) -> None:
@@ -70,6 +75,7 @@ class AgoraService:
70
75
  def initialize(self, config: AgoraServiceConfig):
71
76
  if self.inited == True:
72
77
  return 0
78
+
73
79
  config.app_id = config.appid.encode('utf-8')
74
80
  result = agora_service_initialize(self.service_handle, ctypes.byref(AgoraServiceConfigInner.create(config=config)))
75
81
  if result == 0:
@@ -96,12 +102,12 @@ class AgoraService:
96
102
  if config.should_callbck_when_muted > 0:
97
103
  agora_parameter.set_parameters("{\"rtc.audio.enable_user_silence_packet\": true}")
98
104
 
105
+
99
106
  if config.log_path:
100
107
  log_size = 512 * 1024
101
108
  if config.log_size > 0:
102
109
  log_size = config.log_size
103
110
  agora_service_set_log_file(self.service_handle, ctypes.create_string_buffer(config.log_path.encode('utf-8')), log_size)
104
-
105
111
  return result
106
112
 
107
113
  def release(self):
@@ -6,6 +6,7 @@
6
6
  # state: int
7
7
  # agora_remote_audio_track: RemoteAudioTrack
8
8
  """
9
+ from agora.rtc.agora_base import *
9
10
 
10
11
 
11
12
  class IRTCLocalUserObserver():
@@ -25,10 +26,10 @@ class IRTCLocalUserObserver():
25
26
  def on_local_audio_track_state_changed(self, agora_local_user, agora_local_audio_track, state, error):
26
27
  pass
27
28
 
28
- def on_local_audio_track_statistics(self, agora_local_user, stats):
29
+ def on_local_audio_track_statistics(self, agora_local_user, stats:LocalAudioTrackStats):
29
30
  pass
30
31
 
31
- def on_remote_audio_track_statistics(self, agora_local_user, agora_remote_audio_track, stats):
32
+ def on_remote_audio_track_statistics(self, agora_local_user, agora_remote_audio_track, stats:RemoteAudioTrackStats):
32
33
  pass
33
34
 
34
35
  def on_user_audio_track_subscribed(self, agora_local_user, user_id, agora_remote_audio_track):
@@ -64,7 +65,7 @@ class IRTCLocalUserObserver():
64
65
  def on_local_video_track_state_changed(self, agora_local_user, agora_local_video_track, state, error):
65
66
  pass
66
67
 
67
- def on_local_video_track_statistics(self, agora_local_user, agora_local_video_track, stats):
68
+ def on_local_video_track_statistics(self, agora_local_user, agora_local_video_track, stats:LocalVideoTrackStats):
68
69
  pass
69
70
 
70
71
  def on_user_video_track_subscribed(self, agora_local_user, user_id, info, agora_remote_video_track):
@@ -73,7 +74,7 @@ class IRTCLocalUserObserver():
73
74
  def on_user_video_track_state_changed(self, agora_local_user, user_id, agora_remote_video_track, state, reason, elapsed):
74
75
  pass
75
76
 
76
- def on_remote_video_track_statistics(self, agora_local_user, agora_remote_video_track, stats):
77
+ def on_remote_video_track_statistics(self, agora_local_user, agora_remote_video_track, stats:RemoteVideoTrackStats):
77
78
  pass
78
79
 
79
80
  def on_audio_volume_indication(self, agora_local_user, speakers_list, speaker_number, total_volume):
@@ -51,6 +51,12 @@ agora_rtc_conn_renew_token = agora_lib.agora_rtc_conn_renew_token
51
51
  agora_rtc_conn_renew_token.restype = AGORA_API_C_INT
52
52
  agora_rtc_conn_renew_token.argtypes = [AGORA_HANDLE, ctypes.c_char_p]
53
53
 
54
+ #AGORA_API_C_INT agora_rtc_conn_enable_encryption(AGORA_HANDLE agora_rtc_conn, int enabled, const encryption_config* config);
55
+
56
+ agora_rtc_conn_enable_encryption = agora_lib.agora_rtc_conn_enable_encryption
57
+ agora_rtc_conn_enable_encryption.restype = AGORA_API_C_INT
58
+ agora_rtc_conn_enable_encryption.argtypes = [AGORA_HANDLE, ctypes.c_int, ctypes.POINTER(EncryptionConfigInner)]
59
+
54
60
 
55
61
  class RTCConnection:
56
62
  def __init__(self, conn_handle, is_low_delay: bool = False) -> None:
@@ -129,6 +135,22 @@ class RTCConnection:
129
135
 
130
136
  def get_local_user(self):
131
137
  return self.local_user
138
+
139
+ def enable_encryption(self, enabled: int, config: EncryptionConfig) -> int:
140
+ """
141
+ Enables or disables encryption for the connection.
142
+
143
+ Args:
144
+ enabled (int): 1 to enable encryption, 0 to disable.
145
+ config (EncryptionConfig): The encryption configuration.
146
+
147
+ Returns:
148
+ int: The result of the operation. 0 if successful, otherwise an error code.
149
+ Note:
150
+ This method must be called before self.connect()
151
+ """
152
+ inner_config = EncryptionConfigInner.create(config)
153
+ return agora_rtc_conn_enable_encryption(self.conn_handle, enabled, ctypes.byref(inner_config))
132
154
 
133
155
  def release(self):
134
156
  # release local user map
@@ -88,3 +88,5 @@ class IRTCConnectionObserver():
88
88
 
89
89
  def on_upload_log_result(self, agora_rtc_conn, request_id_str, success, reason):
90
90
  pass
91
+ def on_encryption_error(self, agora_rtc_conn, error_type: int):
92
+ pass
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: agora_python_server_sdk
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: A Python SDK for Agora Server
5
5
  Home-page: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK
6
6
  Classifier: Intended Audience :: Developers
@@ -12,12 +12,6 @@ Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3 :: Only
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
- Dynamic: classifier
16
- Dynamic: description
17
- Dynamic: description-content-type
18
- Dynamic: home-page
19
- Dynamic: requires-python
20
- Dynamic: summary
21
15
 
22
16
  # Note
23
17
  - This is a Python SDK wrapper for the Agora RTC SDK.
@@ -56,6 +50,19 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
56
50
  ```
57
51
 
58
52
  # Change log
53
+ 2025.04.10 Release 2.2.2
54
+ -- Additions:
55
+ - Added push_video_encoded_file.py to support pushing mp4 files and h264 encoded h.264 files. Includes conversion from mp4 file avformat to raw 264 stream in annex B format.
56
+ -- Additions:
57
+ - Added set_log_file_filter function to set the log filter level.
58
+ -- Additions:
59
+ - Added support for arm64 version, but currently this version does not support audio label algorithm. Therefore, it is not supported on arm64!
60
+ -- Changes:
61
+ - Modified localuserstats, local video stats, local audio stats, remote video stats, remote audio stats.
62
+ -- Additions:
63
+ - Added connection::agora_rtc_conn_enable_encryption.
64
+ -- Additions:
65
+ - Added connectionObserver::on_encryption_error (but not working for now, need to fix in the next monthly version 4.4.32).
59
66
  2025.02.26 Release 2.2.1
60
67
  --Update:
61
68
  ​- Reduced buffer size from ​180ms​ to ​100ms​ to minimize latency.
@@ -7,6 +7,7 @@ import zipfile
7
7
  # import urllib
8
8
  from urllib import request
9
9
  import ssl
10
+ import platform
10
11
  ssl._create_default_https_context = ssl._create_unverified_context
11
12
 
12
13
 
@@ -20,6 +21,9 @@ class CustomInstallCommand(install):
20
21
  agora_service_path = os.path.join(site.getsitepackages()[0], 'agora', 'rtc')
21
22
  sdk_dir = os.path.join(agora_service_path, "agora_sdk")
22
23
  zip_path = os.path.join(agora_service_path, "agora_rtc_sdk.zip")
24
+ arch = platform.machine()
25
+ os_type = platform.system()
26
+
23
27
  '''# version before 2.2.0
24
28
  #url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.30-20241024_101940-398537.zip"
25
29
  #url = "https://download.agora.io/sdk/release/agora_rtc_sdk_mac_rel.v4.4.30_22472_FULL_20241024_1224_398653.zip"
@@ -28,6 +32,10 @@ class CustomInstallCommand(install):
28
32
  url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.31-20241223_111509-491956.zip"
29
33
  if sys.platform == 'darwin':
30
34
  url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.31_23136_FULL_20241223_1245_492039.zip"
35
+ if arch == "aarch64" and sys.platform == 'linux':
36
+ url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.31-20250307_175457-603878.zip"
37
+
38
+
31
39
 
32
40
 
33
41
  if os.path.exists(sdk_dir):
@@ -50,7 +58,7 @@ class CustomInstallCommand(install):
50
58
 
51
59
  setup(
52
60
  name='agora_python_server_sdk',
53
- version='2.2.1',
61
+ version='2.2.2',
54
62
  description='A Python SDK for Agora Server',
55
63
  long_description=open('README.md').read(),
56
64
  long_description_content_type='text/markdown',