agora-python-server-sdk 2.3.4__tar.gz → 2.4.0__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.
- {agora_python_server_sdk-2.3.4/agora_python_server_sdk.egg-info → agora_python_server_sdk-2.4.0}/PKG-INFO +20 -1
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/README.md +19 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/__init__.py +19 -10
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/__init__.py +6 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_ctypes_handle/_local_user_observer.py +2 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/agora_base.py +63 -1
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/agora_service.py +53 -1
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_user.py +4 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/rtc_connection.py +27 -1
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/utils/vad_dump.py +78 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/voice_detection.py +55 -21
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0/agora_python_server_sdk.egg-info}/PKG-INFO +20 -1
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/setup.py +7 -1
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/MANIFEST.in +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_ctypes_handle/_audio_frame_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_ctypes_handle/_ctypes_data.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_ctypes_handle/_rtc_connection_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_ctypes_handle/_video_encoded_frame_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_ctypes_handle/_video_frame_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/_utils/globals.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/agora_parameter.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_encoded_frame_sender.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_frame_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_pcm_data_sender.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_sessionctrl.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_vad_manager.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_audio_track.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_user_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_video_track.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/media_node_factory.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/remote_audio_track.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/remote_video_track.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/rtc_connection_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/utils/audio_consumer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/video_encoded_frame_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/video_encoded_image_sender.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/video_frame_observer.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/video_frame_sender.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtm/__init__.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtm/_ctypes_handle/_ctypes_data.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtm/rtm_base.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtm/rtm_client.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtm/rtm_event_handler.py +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora_python_server_sdk.egg-info/SOURCES.txt +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora_python_server_sdk.egg-info/dependency_links.txt +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora_python_server_sdk.egg-info/top_level.txt +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/pyproject.toml +0 -0
- {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: agora_python_server_sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -64,6 +64,25 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
|
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
# Change log
|
|
67
|
+
## 2025.11.18 Release version 2.4.0
|
|
68
|
+
-- Update SDK to APM version: 4.4.32/1025
|
|
69
|
+
-- Add configure support for enabling/disabling APM
|
|
70
|
+
-- Update methods in setup.py and __init__.py, ok, including version/URL, md5, etc.
|
|
71
|
+
-- Overall code pipeline ok, needs testing?? ok
|
|
72
|
+
-- Add support to rtm, one single sdk supports both rtm and rtc, ok
|
|
73
|
+
-- todo:
|
|
74
|
+
-[] Need to add VAD algorithm update ok
|
|
75
|
+
-[] Need to add vad_dump modifications ok
|
|
76
|
+
-[] Modify APM algorithm to support VAD switch, ok
|
|
77
|
+
-[] Add VAD configure parameter settings, ok
|
|
78
|
+
-[] Download every time, check md5 mismatch?? ok
|
|
79
|
+
NOTE:
|
|
80
|
+
APM features, i.e., server-side echo cancellation, noise suppression, automatic gain control, background voice removal, etc.
|
|
81
|
+
Normally, AEC/AINS/AGC, etc., are already implemented on the client side, and the server side does not need to implement them again, unless there are special requirements.
|
|
82
|
+
If you want to enable APM features, please contact Agora technical support.
|
|
83
|
+
NOTE:
|
|
84
|
+
How to use rtc,please ref to: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/examples
|
|
85
|
+
Hot to use rtm,please ref to ://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/rtm_examples
|
|
67
86
|
# 2025.11.07 release 2.3.3
|
|
68
87
|
-- update: to support rtm
|
|
69
88
|
-- adjust sdk's directory structure
|
|
@@ -49,6 +49,25 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
# Change log
|
|
52
|
+
## 2025.11.18 Release version 2.4.0
|
|
53
|
+
-- Update SDK to APM version: 4.4.32/1025
|
|
54
|
+
-- Add configure support for enabling/disabling APM
|
|
55
|
+
-- Update methods in setup.py and __init__.py, ok, including version/URL, md5, etc.
|
|
56
|
+
-- Overall code pipeline ok, needs testing?? ok
|
|
57
|
+
-- Add support to rtm, one single sdk supports both rtm and rtc, ok
|
|
58
|
+
-- todo:
|
|
59
|
+
-[] Need to add VAD algorithm update ok
|
|
60
|
+
-[] Need to add vad_dump modifications ok
|
|
61
|
+
-[] Modify APM algorithm to support VAD switch, ok
|
|
62
|
+
-[] Add VAD configure parameter settings, ok
|
|
63
|
+
-[] Download every time, check md5 mismatch?? ok
|
|
64
|
+
NOTE:
|
|
65
|
+
APM features, i.e., server-side echo cancellation, noise suppression, automatic gain control, background voice removal, etc.
|
|
66
|
+
Normally, AEC/AINS/AGC, etc., are already implemented on the client side, and the server side does not need to implement them again, unless there are special requirements.
|
|
67
|
+
If you want to enable APM features, please contact Agora technical support.
|
|
68
|
+
NOTE:
|
|
69
|
+
How to use rtc,please ref to: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/examples
|
|
70
|
+
Hot to use rtm,please ref to ://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/rtm_examples
|
|
52
71
|
# 2025.11.07 release 2.3.3
|
|
53
72
|
-- update: to support rtm
|
|
54
73
|
-- adjust sdk's directory structure
|
|
@@ -122,11 +122,20 @@ def _check_download_and_extract_sdk():
|
|
|
122
122
|
#fusion version: 20251023
|
|
123
123
|
|
|
124
124
|
url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.32-20250829_160340-860733-aed_20251107_1642.zip"
|
|
125
|
-
|
|
125
|
+
#20251110 Fusion version: with apm filter
|
|
126
|
+
mac_sdk="https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.30_25869_FULL_20251030_1836_953684-aed.zip"
|
|
127
|
+
linux_sdk = "https://download.agora.io/sdk/release/agora_rtc_sdk_x86_64-linux-gnu-v4.4.32.150_26715_SERVER_20251030_1807-aed.zip"
|
|
128
|
+
|
|
126
129
|
|
|
127
|
-
|
|
130
|
+
linux_libfile_path = os.path.join(sdk_library_dir, "libagora_rtc_sdk.so")
|
|
131
|
+
mac_libfile_path = os.path.join(sdk_library_dir, "libAgoraRtcKit.dylib")
|
|
132
|
+
linux_md5 = "821cb1a388279648fcb204ca795e6476"
|
|
133
|
+
mac_md5 = "5b9940d3fca033a53ac30216d5c39be6"
|
|
134
|
+
|
|
128
135
|
#rtc_md5 = "7031dd10d1681cd88fd89d68c5b54282"
|
|
129
|
-
|
|
136
|
+
url = linux_sdk
|
|
137
|
+
rtc_md5 = linux_md5
|
|
138
|
+
rtc_libfile_path = linux_libfile_path
|
|
130
139
|
if sys.platform == 'darwin':
|
|
131
140
|
#url = "https://download.agora.io/sdk/release/agora_rtc_sdk_mac_rel.v4.4.30_22472_FULL_20241024_1224_398653.zip"
|
|
132
141
|
# version 2.2.0 for mac
|
|
@@ -134,13 +143,12 @@ def _check_download_and_extract_sdk():
|
|
|
134
143
|
#url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_24915_FULL_20250715_1710_791284.zip"
|
|
135
144
|
#url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_25418_FULL_20250829_1647_860754.zip"
|
|
136
145
|
#20251023 Fusion version: one sdk package include rtc and rtm
|
|
137
|
-
url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_25418_FULL_20250829_1647_860754-aed_20251107_1639.zip"
|
|
146
|
+
#url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_25418_FULL_20250829_1647_860754-aed_20251107_1639.zip"
|
|
147
|
+
url = mac_sdk
|
|
138
148
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
rtc_libfile_path = os.path.join(sdk_library_dir, "libAgoraRtcKit.dylib")
|
|
149
|
+
rtc_libfile_path = mac_libfile_path
|
|
142
150
|
#rtc_md5 = "ca3ca14f9e2b7d97eb2594d1f32dab9f"
|
|
143
|
-
rtc_md5 =
|
|
151
|
+
rtc_md5 = mac_md5
|
|
144
152
|
if arch == "aarch64" and sys.platform == 'linux':
|
|
145
153
|
#url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.31-20250307_175457-603878.zip"
|
|
146
154
|
#url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.32-20250425_150503-675674.zip"
|
|
@@ -198,5 +206,6 @@ else:
|
|
|
198
206
|
if not os.path.exists(rtc_libfile_path):
|
|
199
207
|
logger.error(f"library {rtc_libfile_path} not found")
|
|
200
208
|
sys.exit(1)
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
|
|
210
|
+
# 显式导出这些变量,确保子模块可以导入
|
|
211
|
+
__all__ = ['sdk_library_dir', 'sdk_rtc_dir', 'sdk_rtm_dir', 'sdk_root_dir']
|
|
@@ -22,11 +22,17 @@ try:
|
|
|
22
22
|
if sys.platform == 'darwin':
|
|
23
23
|
lib_agora_rtc_path = os.path.join(lib_dir, 'libAgoraRtcKit.dylib')
|
|
24
24
|
agora_lib = ctypes.CDLL(lib_agora_rtc_path)
|
|
25
|
+
ctypes.CDLL(os.path.join(lib_dir, 'libAgoraAiNoiseSuppressionExtension.dylib'))
|
|
25
26
|
|
|
26
27
|
elif sys.platform == 'linux':
|
|
27
28
|
lib_agora_rtc_path = os.path.join(lib_dir, 'libagora_rtc_sdk.so')
|
|
28
29
|
ctypes.CDLL(os.path.join(lib_dir, 'libagora-fdkaac.so'))
|
|
30
|
+
#ctypes.CDLL(os.path.join(lib_dir, 'libagora_ai_noise_suppression_extension.so'))
|
|
31
|
+
ctypes.CDLL(os.path.join(lib_dir, 'libagora-ffmpeg.so'))
|
|
32
|
+
ctypes.CDLL(os.path.join(lib_dir, 'libagora-soundtouch.so'))
|
|
29
33
|
agora_lib = ctypes.CDLL(lib_agora_rtc_path)
|
|
34
|
+
# should load it or the ains can not work
|
|
35
|
+
ctypes.CDLL(os.path.join(lib_dir, 'libagora_ai_noise_suppression_extension.so'))
|
|
30
36
|
except OSError as e:
|
|
31
37
|
logger.error(f"Error loading the library: {e}")
|
|
32
38
|
logger.error(f"Attempted to load from: {lib_agora_rtc_path}")
|
|
@@ -186,6 +186,8 @@ class RTCLocalUserObserverInner(ctypes.Structure):
|
|
|
186
186
|
def _on_user_audio_track_subscribed(self, local_user_handle, user_id, remote_audio_track_handle):
|
|
187
187
|
logger.debug(f"LocalUserCB _on_user_audio_track_subscribed: {local_user_handle}, {user_id}, {remote_audio_track_handle}")
|
|
188
188
|
user_id_str = user_id.decode('utf-8') if user_id else ""
|
|
189
|
+
#add apm filter for remote audio track
|
|
190
|
+
self.local_user._set_apm_filter_properties(remote_audio_track_handle,user_id_str)
|
|
189
191
|
# note: this is a pointer to agora::rtc::IRemoteAudioTrack
|
|
190
192
|
remote_audio_track = RemoteAudioTrack(remote_audio_track_handle, user_id_str)
|
|
191
193
|
# map to localuser to save reference
|
|
@@ -297,6 +297,63 @@ class VideoFrame():
|
|
|
297
297
|
alpha_buffer: bytearray = None
|
|
298
298
|
alpha_mode: int = 0
|
|
299
299
|
|
|
300
|
+
@dataclass(kw_only=True)
|
|
301
|
+
class AiNsConfig:
|
|
302
|
+
ns_enabled: bool = True
|
|
303
|
+
ai_ns_enabled: bool = True
|
|
304
|
+
ai_ns_model_pref: int = 10
|
|
305
|
+
nsng_alg_route: int = 12
|
|
306
|
+
nsng_predef_agg: int = 11
|
|
307
|
+
@dataclass(kw_only=True)
|
|
308
|
+
class AiAecConfig:
|
|
309
|
+
enabled: bool = False
|
|
310
|
+
split_srate_for_48k: int = 16000
|
|
311
|
+
|
|
312
|
+
@dataclass(kw_only=True)
|
|
313
|
+
class BghvsCConfig:
|
|
314
|
+
enabled: bool = True
|
|
315
|
+
vad_thr: float = 0.8
|
|
316
|
+
|
|
317
|
+
@dataclass(kw_only=True)
|
|
318
|
+
class AgcConfig:
|
|
319
|
+
enabled: bool = False
|
|
320
|
+
|
|
321
|
+
@dataclass(kw_only=True)
|
|
322
|
+
class APMConfig:
|
|
323
|
+
ai_ns_config: AiNsConfig = field(default_factory=AiNsConfig)
|
|
324
|
+
ai_aec_config: AiAecConfig = field(default_factory=AiAecConfig)
|
|
325
|
+
bghvs_c_config: BghvsCConfig = field(default_factory=BghvsCConfig)
|
|
326
|
+
agc_config: AgcConfig = field(default_factory=AgcConfig)
|
|
327
|
+
enable_dump: bool = False
|
|
328
|
+
|
|
329
|
+
def _to_json_string(self):
|
|
330
|
+
import json
|
|
331
|
+
config_dict = {
|
|
332
|
+
"aec": {
|
|
333
|
+
"enabled": self.ai_aec_config.enabled,
|
|
334
|
+
"split_srate_for_48k": self.ai_aec_config.split_srate_for_48k
|
|
335
|
+
},
|
|
336
|
+
"bghvs": {
|
|
337
|
+
"enabled": self.bghvs_c_config.enabled,
|
|
338
|
+
"vadThr": self.bghvs_c_config.vad_thr
|
|
339
|
+
},
|
|
340
|
+
"agc": {
|
|
341
|
+
"enabled": self.agc_config.enabled
|
|
342
|
+
},
|
|
343
|
+
"ans": {
|
|
344
|
+
"enabled": self.ai_ns_config.ns_enabled
|
|
345
|
+
},
|
|
346
|
+
"sf_st_cfg": {
|
|
347
|
+
"enabled": self.ai_ns_config.ai_ns_enabled,
|
|
348
|
+
"ainsModelPref": self.ai_ns_config.ai_ns_model_pref
|
|
349
|
+
},
|
|
350
|
+
"sf_ext_cfg": {
|
|
351
|
+
"nsngAlgRoute": self.ai_ns_config.nsng_alg_route,
|
|
352
|
+
"nsngPredefAgg": self.ai_ns_config.nsng_predef_agg
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return json.dumps(config_dict, separators=(',', ':'))
|
|
356
|
+
|
|
300
357
|
|
|
301
358
|
@dataclass(kw_only=True)
|
|
302
359
|
class AgoraServiceConfig:
|
|
@@ -324,6 +381,11 @@ class AgoraServiceConfig:
|
|
|
324
381
|
log_file_size_kb: int = 5*1024
|
|
325
382
|
data_dir: str = ""
|
|
326
383
|
config_dir: str = "" #format like: "./agora_rtc_log"
|
|
384
|
+
#20251110 Fusion version: with apm filter
|
|
385
|
+
enable_apm: bool = False
|
|
386
|
+
apm_config: APMConfig = None
|
|
387
|
+
|
|
388
|
+
|
|
327
389
|
|
|
328
390
|
|
|
329
391
|
@dataclass(kw_only=True)
|
|
@@ -566,4 +628,4 @@ class CapabilityItemMap:
|
|
|
566
628
|
@dataclass(kw_only=True)
|
|
567
629
|
class Capabilities:
|
|
568
630
|
item_map: CapabilityItemMap = None
|
|
569
|
-
capability_type: int = 0
|
|
631
|
+
capability_type: int = 0
|
|
@@ -65,6 +65,14 @@ agora_service_set_log_filter = agora_lib.agora_service_set_log_filter
|
|
|
65
65
|
agora_service_set_log_filter.restype = AGORA_API_C_INT
|
|
66
66
|
agora_service_set_log_filter.argtypes = [AGORA_HANDLE, ctypes.c_uint]
|
|
67
67
|
|
|
68
|
+
agora_audio_track_enable_audio_filter = agora_lib.agora_audio_track_enable_audio_filter
|
|
69
|
+
agora_audio_track_enable_audio_filter.restype = ctypes.c_int
|
|
70
|
+
agora_audio_track_enable_audio_filter.argtypes = [AGORA_HANDLE, ctypes.c_char_p, ctypes.c_int, ctypes.c_int]
|
|
71
|
+
|
|
72
|
+
agora_audio_track_set_filter_property = agora_lib.agora_audio_track_set_filter_property
|
|
73
|
+
agora_audio_track_set_filter_property.restype = ctypes.c_int
|
|
74
|
+
agora_audio_track_set_filter_property.argtypes = [AGORA_HANDLE, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
|
|
75
|
+
|
|
68
76
|
|
|
69
77
|
class AgoraService:
|
|
70
78
|
def __init__(self) -> None:
|
|
@@ -74,6 +82,8 @@ class AgoraService:
|
|
|
74
82
|
self.inited = False
|
|
75
83
|
#default to None, and never create it manually by developer from ver2.3.0
|
|
76
84
|
self.media_node_factory = None
|
|
85
|
+
self.enable_apm = False
|
|
86
|
+
self.apm_config = None
|
|
77
87
|
|
|
78
88
|
def initialize(self, config: AgoraServiceConfig):
|
|
79
89
|
if self.inited == True:
|
|
@@ -101,7 +111,14 @@ class AgoraService:
|
|
|
101
111
|
|
|
102
112
|
# force audio vad v2 to be enabled
|
|
103
113
|
agora_parameter.set_parameters("{\"che.audio.label.enable\": true}")
|
|
104
|
-
|
|
114
|
+
# for apm filter: to enable apm filter
|
|
115
|
+
generator = "audio_processing_remote_playback"
|
|
116
|
+
cgenerator = generator.encode('utf-8')
|
|
117
|
+
ctrak = ctypes.c_char_p(None)
|
|
118
|
+
result = agora_service_enable_extension(self.service_handle, cprovider, cgenerator, ctrak, 1)
|
|
119
|
+
if result != 0:
|
|
120
|
+
logger.error(f"Failed to enable audio processing remote playback filter. Error code: {result}")
|
|
121
|
+
|
|
105
122
|
#versio 2.2.0 for callback when muted
|
|
106
123
|
if config.should_callbck_when_muted > 0:
|
|
107
124
|
agora_parameter.set_parameters("{\"rtc.audio.enable_user_silence_packet\": true}")
|
|
@@ -112,6 +129,17 @@ class AgoraService:
|
|
|
112
129
|
'''
|
|
113
130
|
agora_parameter.set_parameters("{\"che.video.min_enc_level\": 0}")
|
|
114
131
|
|
|
132
|
+
#keep & save apm config
|
|
133
|
+
self.enable_apm = config.enable_apm
|
|
134
|
+
if self.enable_apm:
|
|
135
|
+
if config.apm_config is None:
|
|
136
|
+
self.apm_config = APMConfig()
|
|
137
|
+
else:
|
|
138
|
+
self.apm_config = config.apm_config
|
|
139
|
+
else:
|
|
140
|
+
self.apm_config = None
|
|
141
|
+
|
|
142
|
+
|
|
115
143
|
return result
|
|
116
144
|
|
|
117
145
|
def release(self):
|
|
@@ -210,3 +238,27 @@ class AgoraService:
|
|
|
210
238
|
else:
|
|
211
239
|
logger.error(f"Failed to set log file. Error code: {result}")
|
|
212
240
|
return result
|
|
241
|
+
#apm related:
|
|
242
|
+
#apm related api
|
|
243
|
+
def _get_audio_filter_position(is_local_track: bool = False) -> int:
|
|
244
|
+
if is_local_track:
|
|
245
|
+
return 3
|
|
246
|
+
return 2
|
|
247
|
+
|
|
248
|
+
def _enable_audio_filter_by_track(track: any, name: str, enable: bool, is_local_track: bool) -> int:
|
|
249
|
+
if track is None:
|
|
250
|
+
return -1000
|
|
251
|
+
c_name = ctypes.c_char_p(name.encode('utf-8'))
|
|
252
|
+
c_enable = ctypes.c_int(0)
|
|
253
|
+
if enable:
|
|
254
|
+
c_enable = ctypes.c_int(1)
|
|
255
|
+
position = _get_audio_filter_position(is_local_track)
|
|
256
|
+
return int(agora_audio_track_enable_audio_filter(track, c_name, c_enable, ctypes.c_int(position)))
|
|
257
|
+
def _set_filter_property_by_track(track: any, name: str, key: str, value: str, is_local_track: bool) -> int:
|
|
258
|
+
if track is None:
|
|
259
|
+
return -1000
|
|
260
|
+
c_name = ctypes.c_char_p(name.encode('utf-8'))
|
|
261
|
+
c_key = ctypes.c_char_p(key.encode('utf-8'))
|
|
262
|
+
c_value = ctypes.c_char_p(value.encode('utf-8'))
|
|
263
|
+
position = _get_audio_filter_position(is_local_track)
|
|
264
|
+
return int(agora_audio_track_set_filter_property(track, c_name, c_key, c_value, ctypes.c_int(position)))
|
|
@@ -624,3 +624,7 @@ class LocalUser:
|
|
|
624
624
|
size = len(data)
|
|
625
625
|
ret = agora_local_user_send_aduio_meta_data(self.user_handle, c_data, ctypes.c_size_t(size))
|
|
626
626
|
return ret
|
|
627
|
+
def _set_apm_filter_properties(self, remote_audio_track_handle, user_id_str)->int:
|
|
628
|
+
ret = self.connection._set_apm_filter_properties(remote_audio_track_handle, user_id_str)
|
|
629
|
+
print(f"**********LocalUser _set_apm_filter_properties: {ret}")
|
|
630
|
+
return ret
|
|
@@ -2,7 +2,7 @@ import time
|
|
|
2
2
|
import ctypes
|
|
3
3
|
|
|
4
4
|
from .agora_base import *
|
|
5
|
-
from .agora_service import AgoraService
|
|
5
|
+
from .agora_service import AgoraService, _set_filter_property_by_track
|
|
6
6
|
from .local_user import LocalUser
|
|
7
7
|
from .rtc_connection_observer import IRTCConnectionObserver
|
|
8
8
|
from ._ctypes_handle._audio_frame_observer import AudioFrameObserverInner
|
|
@@ -514,6 +514,32 @@ class RTCConnection:
|
|
|
514
514
|
if self._capabilities_observer_obj:
|
|
515
515
|
self._capabilities_observer_obj = None
|
|
516
516
|
return 0
|
|
517
|
+
|
|
518
|
+
def _set_apm_filter_properties(self, remote_audio_track_handle, user_id_str)->int:
|
|
519
|
+
ret = -1000
|
|
520
|
+
is_enabled = self.rtc_engine.enable_apm
|
|
521
|
+
if not is_enabled:
|
|
522
|
+
return -1001
|
|
523
|
+
apm_config = self.rtc_engine.apm_config
|
|
524
|
+
if apm_config is None:
|
|
525
|
+
return -1002
|
|
526
|
+
apm_config_json = apm_config._to_json_string()
|
|
527
|
+
if apm_config_json is None:
|
|
528
|
+
return -1003
|
|
529
|
+
#Load AINS resource
|
|
530
|
+
ret = _set_filter_property_by_track(remote_audio_track_handle, "audio_processing_remote_playback", "apm_load_resource", "ains", False)
|
|
531
|
+
|
|
532
|
+
print(f"**********APM: to set apm_load_resource, error: {ret}")
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
#Set APM configuration
|
|
536
|
+
ret = _set_filter_property_by_track(remote_audio_track_handle, "audio_processing_remote_playback", "apm_config", apm_config_json, False)
|
|
537
|
+
print(f"**********APM: to set apm_config, error: {ret}, apm_config_json: {apm_config_json}")
|
|
538
|
+
#Enable dump
|
|
539
|
+
if apm_config.enable_dump:
|
|
540
|
+
ret = _set_filter_property_by_track(remote_audio_track_handle, "audio_processing_remote_playback", "apm_dump", "true", False)
|
|
541
|
+
print(f"**********APM: to enable apm_dump, error: {ret}")
|
|
542
|
+
return ret
|
|
517
543
|
|
|
518
544
|
|
|
519
545
|
|
|
@@ -3,6 +3,7 @@ import time
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
|
+
import struct
|
|
6
7
|
from agora.rtc.agora_base import AudioFrame
|
|
7
8
|
logger = logging.getLogger(__name__)
|
|
8
9
|
|
|
@@ -11,6 +12,42 @@ logger = logging.getLogger(__name__)
|
|
|
11
12
|
"""
|
|
12
13
|
## VadDump helper class
|
|
13
14
|
"""
|
|
15
|
+
#buffer manager for vaddump: high performance buffer manager for vaddump
|
|
16
|
+
|
|
17
|
+
class BufferManager:
|
|
18
|
+
"""High-performance buffer manager using struct.pack
|
|
19
|
+
|
|
20
|
+
Performance benchmarks (320 bytes, 100k iterations):
|
|
21
|
+
- struct.pack: 0.016-0.019 seconds (FASTEST)
|
|
22
|
+
- ctypes.memset: 0.107 seconds (5.6x slower)
|
|
23
|
+
- ctypes loop: 0.686 seconds (36x slower)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, initial_size=320):
|
|
27
|
+
self.size = initial_size
|
|
28
|
+
self.buffer = bytearray(self.size)
|
|
29
|
+
def resize(self, new_size: int):
|
|
30
|
+
if new_size != self.size:
|
|
31
|
+
self.size = new_size
|
|
32
|
+
self.buffer = bytearray(self.size)
|
|
33
|
+
def fill_zero(self):
|
|
34
|
+
self.fill_int16(0)
|
|
35
|
+
|
|
36
|
+
def fill_int16(self, value: int):
|
|
37
|
+
"""Fill buffer with int16 value using struct.pack (fastest method)
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
value: int16 value to fill (-32768 to 32767)
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
bytearray: The filled buffer
|
|
44
|
+
"""
|
|
45
|
+
# Pack value as little-endian int16 and repeat
|
|
46
|
+
pattern = struct.pack('<h', value)
|
|
47
|
+
self.buffer[:] = pattern * (self.size // 2)
|
|
48
|
+
return self.buffer
|
|
49
|
+
|
|
50
|
+
|
|
14
51
|
class VadDump():
|
|
15
52
|
def __init__(self, path: str) -> None:
|
|
16
53
|
self._file_path = path
|
|
@@ -20,6 +57,10 @@ class VadDump():
|
|
|
20
57
|
self._source_file = None
|
|
21
58
|
self._label_file = None
|
|
22
59
|
self._vad_file = None
|
|
60
|
+
self._voice_prob_file = None
|
|
61
|
+
self._rms_file = None
|
|
62
|
+
self._pitch_file = None
|
|
63
|
+
self._buffer_manager = BufferManager(320)
|
|
23
64
|
#check path is existed or not? if not, create new dir
|
|
24
65
|
if self._check_directory_exists(path) is False:
|
|
25
66
|
os.makedirs(path)
|
|
@@ -56,6 +97,16 @@ class VadDump():
|
|
|
56
97
|
#open label file
|
|
57
98
|
label_file_path = self._file_path + "/label.txt"
|
|
58
99
|
self._label_file = open(label_file_path, "w")
|
|
100
|
+
#rms
|
|
101
|
+
rms_file_path = self._file_path + "/rms.pcm"
|
|
102
|
+
self._rms_file = open(rms_file_path, "wb")
|
|
103
|
+
#pitch
|
|
104
|
+
pitch_file_path = self._file_path + "/pitch.pcm"
|
|
105
|
+
self._pitch_file = open(pitch_file_path, "wb")
|
|
106
|
+
#voice prob
|
|
107
|
+
voice_prob_file_path = self._file_path + "/voice_prob.pcm"
|
|
108
|
+
self._voice_prob_file = open(voice_prob_file_path, "wb")
|
|
109
|
+
|
|
59
110
|
#open vad file
|
|
60
111
|
pass
|
|
61
112
|
def write(self, frame:AudioFrame, vad_result_bytes: bytearray, vad_result_state : int) -> None:
|
|
@@ -68,6 +119,20 @@ class VadDump():
|
|
|
68
119
|
if self._label_file:
|
|
69
120
|
label_str = "ct:%d fct:%d state:%d far:%d vop:%d rms:%d pitch:%d mup:%d\n" % (self._count, self._frame_count,vad_result_state, frame.far_field_flag, frame.voice_prob, frame.rms, frame.pitch, frame.music_prob)
|
|
70
121
|
self._label_file.write(label_str)
|
|
122
|
+
#adjut buffer size if needed
|
|
123
|
+
self._buffer_manager.resize(len(frame.buffer))
|
|
124
|
+
#write rms to buffer
|
|
125
|
+
self._buffer_manager.fill_int16(frame.rms*127)
|
|
126
|
+
if self._rms_file:
|
|
127
|
+
self._rms_file.write(self._buffer_manager.buffer)
|
|
128
|
+
#write pitch to buffe
|
|
129
|
+
self._buffer_manager.fill_int16(frame.pitch)
|
|
130
|
+
if self._pitch_file:
|
|
131
|
+
self._pitch_file.write(self._buffer_manager.buffer)
|
|
132
|
+
#write voice prob to buffer
|
|
133
|
+
self._buffer_manager.fill_int16(frame.voice_prob*127*127)
|
|
134
|
+
if self._voice_prob_file:
|
|
135
|
+
self._voice_prob_file.write(self._buffer_manager.buffer)
|
|
71
136
|
#write to vad result
|
|
72
137
|
if vad_result_state == 1: # start speaking
|
|
73
138
|
#open new vad file and write header
|
|
@@ -96,6 +161,19 @@ class VadDump():
|
|
|
96
161
|
self._label_file = None
|
|
97
162
|
self._close_vad_file()
|
|
98
163
|
|
|
164
|
+
if self._source_file:
|
|
165
|
+
self._source_file.close()
|
|
166
|
+
self._source_file = None
|
|
167
|
+
if self._rms_file:
|
|
168
|
+
self._rms_file.close()
|
|
169
|
+
self._rms_file = None
|
|
170
|
+
if self._pitch_file:
|
|
171
|
+
self._pitch_file.close()
|
|
172
|
+
self._pitch_file = None
|
|
173
|
+
if self._voice_prob_file:
|
|
174
|
+
self._voice_prob_file.close()
|
|
175
|
+
self._voice_prob_file = None
|
|
176
|
+
|
|
99
177
|
# assign to None
|
|
100
178
|
self._count = 0
|
|
101
179
|
self._frame_count = 0
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/voice_detection.py
RENAMED
|
@@ -10,8 +10,8 @@ import logging
|
|
|
10
10
|
logger = logging.getLogger(__name__)
|
|
11
11
|
|
|
12
12
|
class AudioVadConfigV2():
|
|
13
|
-
def __init__(self, preStartRecognizeCount:int, startRecognizeCount:int, stopRecognizeCount:int,
|
|
14
|
-
activePercent:float, inactivePercent:float, start_voiceprob: int, stop_voiceporb:int, rmsThreshold:
|
|
13
|
+
def __init__(self, preStartRecognizeCount:int=16, startRecognizeCount:int=30, stopRecognizeCount:int=50,
|
|
14
|
+
activePercent:float=0.7, inactivePercent:float=0.5, start_voiceprob: int=70, stop_voiceporb:int=50, rmsThreshold:int=-50):
|
|
15
15
|
self.start_recognize_count = startRecognizeCount
|
|
16
16
|
self.pre_start_recognize_count = preStartRecognizeCount
|
|
17
17
|
self.stop_recognize_count = stopRecognizeCount
|
|
@@ -31,8 +31,12 @@ class AudioVadConfigV2():
|
|
|
31
31
|
# In a quiet environment, it can be set to -50;
|
|
32
32
|
# in a noisy environment, it can be set to a value between -40 and -30.
|
|
33
33
|
|
|
34
|
-
self.start_rms = rmsThreshold #default to -
|
|
35
|
-
self.stop_rms = rmsThreshold #default to -
|
|
34
|
+
self.start_rms = rmsThreshold #default to -70
|
|
35
|
+
self.stop_rms = rmsThreshold #default to -70
|
|
36
|
+
# for apm mode:
|
|
37
|
+
self.enable_adaptive_rms_threshold : bool = True
|
|
38
|
+
self.adaptive_rms_threshold_factor : float = 0.67 #default to 0.67, and 2/3 to pass
|
|
39
|
+
print(f"vadconfigure start_rms: {self.start_rms}, stop_rms: {self.stop_rms}")
|
|
36
40
|
|
|
37
41
|
pass
|
|
38
42
|
|
|
@@ -63,11 +67,17 @@ class AudioVadV2():
|
|
|
63
67
|
#trend queue: not impl in this version date: 2024-10-29
|
|
64
68
|
self._trend_queue = None #deque(maxlen=self._vad_configure.stop_recognize_count)
|
|
65
69
|
self._trend_window = self._vad_configure.stop_recognize_count//2
|
|
70
|
+
self._voice_count : int = 0
|
|
71
|
+
self._silence_count : int = 0
|
|
72
|
+
self._total_voice_rms : int = 0
|
|
73
|
+
self._ref_avg_rms_in_last_session : int = 0
|
|
74
|
+
|
|
75
|
+
#convert rms from -120, 0 to range from 0 to 127, respond to db: -127db, to 0db
|
|
76
|
+
self._vad_configure.start_rms = 127 + self._vad_configure.start_rms
|
|
77
|
+
self._vad_configure.stop_rms = 127 + self._vad_configure.stop_rms
|
|
78
|
+
print(f"vad instance start_rms: {self._vad_configure.start_rms}, stop_rms: {self._vad_configure.stop_rms}")
|
|
79
|
+
pass
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
81
|
def _push_to_start(self, data: VadDataV2) -> tuple[int,bool]:
|
|
72
82
|
self._start_queue.append(data)
|
|
73
83
|
size = len(self._start_queue)
|
|
@@ -140,19 +150,30 @@ class AudioVadV2():
|
|
|
140
150
|
size, full = self._push_to_start(data)
|
|
141
151
|
state = self._cur_state
|
|
142
152
|
bytes = bytearray()
|
|
153
|
+
|
|
154
|
+
if data._is_activity == True:
|
|
155
|
+
self._voice_count += 1
|
|
156
|
+
self._total_voice_rms += data._audio_frame.rms
|
|
157
|
+
else:
|
|
158
|
+
self._voice_count = 0
|
|
159
|
+
self._total_voice_rms = 0
|
|
160
|
+
|
|
161
|
+
|
|
143
162
|
|
|
144
163
|
|
|
145
164
|
if full == True:
|
|
146
|
-
|
|
147
|
-
#检查start中的比例是否符合阈值,如果符合阈值,zhi,则将start中的数据全部送入到pre中,并且将pre清空,同时将start清空,同时将当前状态设置为speaking
|
|
148
|
-
total, silence_count = self._get_silence_count(self._start_queue, self._vad_configure.pre_start_recognize_count)
|
|
149
|
-
total -= self._vad_configure.pre_start_recognize_count
|
|
150
|
-
if (total - silence_count) / total >= self._vad_configure.activePercent:
|
|
165
|
+
if self._voice_count >= self._vad_configure.start_recognize_count:
|
|
151
166
|
state = self._vad_state_startspeaking
|
|
152
167
|
#move pre & start to a new bytearray
|
|
153
168
|
|
|
154
169
|
self._move_deque(bytes, self._start_queue)
|
|
155
170
|
self._clear_queue(self._start_queue)
|
|
171
|
+
|
|
172
|
+
#update ref
|
|
173
|
+
self._ref_avg_rms_in_last_session = int(self._total_voice_rms / self._voice_count)
|
|
174
|
+
self._voice_count = 0
|
|
175
|
+
self._total_voice_rms = 0
|
|
176
|
+
self._silence_count = 0
|
|
156
177
|
|
|
157
178
|
#and clear pre &start
|
|
158
179
|
self._clear_queue(self._stop_queue)
|
|
@@ -167,16 +188,19 @@ class AudioVadV2():
|
|
|
167
188
|
size, full = self._push_to_stop(data)
|
|
168
189
|
#print(f"stop: {size}, {full}")
|
|
169
190
|
|
|
191
|
+
if data._is_activity == True:
|
|
192
|
+
self._silence_count = 0
|
|
193
|
+
else:
|
|
194
|
+
self._silence_count += 1
|
|
195
|
+
|
|
170
196
|
|
|
171
|
-
if full == True:
|
|
172
|
-
|
|
173
|
-
trend = self._get_trend(self._stop_queue)
|
|
174
|
-
#检查stop中的比例是否符合阈值,
|
|
175
|
-
# 如果符合阈值,同时清空stop 清空,并且将当前状态设置为non-speaking
|
|
176
|
-
total, silence_count = self._get_silence_count(self._stop_queue,0)
|
|
177
|
-
if (silence_count) / total >= (self._vad_configure.inactivePercent):
|
|
197
|
+
if full == True:
|
|
198
|
+
if self._silence_count >= (self._vad_configure.stop_recognize_count):
|
|
178
199
|
state = self._vad_state_stopspeaking
|
|
179
200
|
self._clear_queue(self._stop_queue)
|
|
201
|
+
self._voice_count = 0
|
|
202
|
+
self._total_voice_rms = 0
|
|
203
|
+
self._silence_count = 0
|
|
180
204
|
#print(f"stop speaking: {len(self._start_queue)}, {silence_count}, {total}, {trend}")
|
|
181
205
|
return state, data._audio_frame.buffer
|
|
182
206
|
|
|
@@ -218,6 +242,11 @@ class AudioVadV2():
|
|
|
218
242
|
#default: shoud never happen
|
|
219
243
|
return int(-100), bytearray()
|
|
220
244
|
|
|
245
|
+
def _get_ref_active_avg_rms(self) -> int:
|
|
246
|
+
if self._vad_configure.enable_adaptive_rms_threshold and self._ref_avg_rms_in_last_session > 0:
|
|
247
|
+
return int(float(self._ref_avg_rms_in_last_session)*self._vad_configure.adaptive_rms_threshold_factor) #half of avg as threshold value
|
|
248
|
+
return self._vad_configure.start_rms
|
|
249
|
+
|
|
221
250
|
"""
|
|
222
251
|
def _is_vad_active(self, data: AudioFrame) -> bool:
|
|
223
252
|
"""
|
|
@@ -235,6 +264,11 @@ class AudioVadV2():
|
|
|
235
264
|
#case2
|
|
236
265
|
#if data.far_field_flag == 1 and data.voice_prob > voice_prob :#and data.pitch > 0 : #voice: from 75 to 50
|
|
237
266
|
#case4: rms > -40
|
|
238
|
-
if data.far_field_flag == 1 and data.voice_prob > voice_prob and data.rms > rms_prob :#and data.pitch > 0 : #voice: from 75 to 50
|
|
267
|
+
#if data.far_field_flag == 1 and data.voice_prob > voice_prob and data.rms > rms_prob :#and data.pitch > 0 : #voice: from 75 to 50
|
|
268
|
+
#date: 2025-10-29 for sdk which support apm filter, and in this version, we don't need to use farfield flag to detect speech, so we don't need to use farfield flag to detect speech
|
|
269
|
+
refRms = self._get_ref_active_avg_rms()
|
|
270
|
+
active = (data.voice_prob == 1) or (data.rms > refRms)
|
|
271
|
+
#print(f"active: {active}, voice_prob: {data.voice_prob}, rms: {data.rms}, refRms: {refRms}")
|
|
272
|
+
if active:
|
|
239
273
|
return True
|
|
240
274
|
return False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: agora_python_server_sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -64,6 +64,25 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
|
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
# Change log
|
|
67
|
+
## 2025.11.18 Release version 2.4.0
|
|
68
|
+
-- Update SDK to APM version: 4.4.32/1025
|
|
69
|
+
-- Add configure support for enabling/disabling APM
|
|
70
|
+
-- Update methods in setup.py and __init__.py, ok, including version/URL, md5, etc.
|
|
71
|
+
-- Overall code pipeline ok, needs testing?? ok
|
|
72
|
+
-- Add support to rtm, one single sdk supports both rtm and rtc, ok
|
|
73
|
+
-- todo:
|
|
74
|
+
-[] Need to add VAD algorithm update ok
|
|
75
|
+
-[] Need to add vad_dump modifications ok
|
|
76
|
+
-[] Modify APM algorithm to support VAD switch, ok
|
|
77
|
+
-[] Add VAD configure parameter settings, ok
|
|
78
|
+
-[] Download every time, check md5 mismatch?? ok
|
|
79
|
+
NOTE:
|
|
80
|
+
APM features, i.e., server-side echo cancellation, noise suppression, automatic gain control, background voice removal, etc.
|
|
81
|
+
Normally, AEC/AINS/AGC, etc., are already implemented on the client side, and the server side does not need to implement them again, unless there are special requirements.
|
|
82
|
+
If you want to enable APM features, please contact Agora technical support.
|
|
83
|
+
NOTE:
|
|
84
|
+
How to use rtc,please ref to: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/examples
|
|
85
|
+
Hot to use rtm,please ref to ://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/rtm_examples
|
|
67
86
|
# 2025.11.07 release 2.3.3
|
|
68
87
|
-- update: to support rtm
|
|
69
88
|
-- adjust sdk's directory structure
|
|
@@ -80,6 +80,12 @@ class CustomInstallCommand(install):
|
|
|
80
80
|
url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.32-20250829_160340-860733-aed_20251107_1642.zip"
|
|
81
81
|
if sys.platform == 'darwin':
|
|
82
82
|
url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_25418_FULL_20250829_1647_860754-aed_20251107_1639.zip"
|
|
83
|
+
|
|
84
|
+
#20251110 Fusion version: with apm filter
|
|
85
|
+
mac_sdk="https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.30_25869_FULL_20251030_1836_953684-aed.zip"
|
|
86
|
+
url = "https://download.agora.io/sdk/release/agora_rtc_sdk_x86_64-linux-gnu-v4.4.32.150_26715_SERVER_20251030_1807-aed.zip"
|
|
87
|
+
if sys.platform == 'darwin':
|
|
88
|
+
url = mac_sdk
|
|
83
89
|
|
|
84
90
|
|
|
85
91
|
if arch == "aarch64" and sys.platform == 'linux':
|
|
@@ -107,7 +113,7 @@ class CustomInstallCommand(install):
|
|
|
107
113
|
|
|
108
114
|
setup(
|
|
109
115
|
name='agora_python_server_sdk',
|
|
110
|
-
version='2.
|
|
116
|
+
version='2.4.0',
|
|
111
117
|
description='A Python SDK for Agora Server',
|
|
112
118
|
long_description=open('README.md').read(),
|
|
113
119
|
long_description_content_type='text/markdown',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/agora_parameter.py
RENAMED
|
File without changes
|
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_frame_observer.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_pcm_data_sender.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_sessionctrl.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/audio_vad_manager.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_audio_track.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_user_observer.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/local_video_track.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/media_node_factory.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/remote_audio_track.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/remote_video_track.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/rtc_connection_observer.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/utils/audio_consumer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/video_frame_observer.py
RENAMED
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtc/video_frame_sender.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.0}/agora/rtm/rtm_event_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|