agora-python-server-sdk 2.3.4__tar.gz → 2.4.1__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.
Files changed (49) hide show
  1. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/PKG-INFO +41 -7
  2. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/README.md +40 -6
  3. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/__init__.py +48 -11
  4. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/__init__.py +6 -0
  5. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_ctypes_handle/_ctypes_data.py +46 -1
  6. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_ctypes_handle/_local_user_observer.py +2 -0
  7. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/agora_base.py +63 -1
  8. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/agora_service.py +59 -1
  9. agora_python_server_sdk-2.4.1/agora/rtc/external_audio_processor.py +222 -0
  10. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/local_user.py +8 -4
  11. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/rtc_connection.py +27 -1
  12. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/utils/vad_dump.py +78 -0
  13. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/voice_detection.py +55 -21
  14. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora_python_server_sdk.egg-info/PKG-INFO +41 -7
  15. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora_python_server_sdk.egg-info/SOURCES.txt +1 -0
  16. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/setup.py +20 -1
  17. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/MANIFEST.in +0 -0
  18. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_ctypes_handle/_audio_frame_observer.py +0 -0
  19. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_ctypes_handle/_rtc_connection_observer.py +0 -0
  20. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_ctypes_handle/_video_encoded_frame_observer.py +0 -0
  21. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_ctypes_handle/_video_frame_observer.py +0 -0
  22. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/_utils/globals.py +0 -0
  23. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/agora_parameter.py +0 -0
  24. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/audio_encoded_frame_sender.py +0 -0
  25. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/audio_frame_observer.py +0 -0
  26. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/audio_pcm_data_sender.py +0 -0
  27. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/audio_sessionctrl.py +0 -0
  28. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/audio_vad_manager.py +0 -0
  29. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/local_audio_track.py +0 -0
  30. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/local_user_observer.py +0 -0
  31. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/local_video_track.py +0 -0
  32. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/media_node_factory.py +0 -0
  33. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/remote_audio_track.py +0 -0
  34. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/remote_video_track.py +0 -0
  35. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/rtc_connection_observer.py +0 -0
  36. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/utils/audio_consumer.py +0 -0
  37. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/video_encoded_frame_observer.py +0 -0
  38. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/video_encoded_image_sender.py +0 -0
  39. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/video_frame_observer.py +0 -0
  40. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtc/video_frame_sender.py +0 -0
  41. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtm/__init__.py +0 -0
  42. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtm/_ctypes_handle/_ctypes_data.py +0 -0
  43. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtm/rtm_base.py +0 -0
  44. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtm/rtm_client.py +0 -0
  45. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora/rtm/rtm_event_handler.py +0 -0
  46. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora_python_server_sdk.egg-info/dependency_links.txt +0 -0
  47. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/agora_python_server_sdk.egg-info/top_level.txt +0 -0
  48. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/pyproject.toml +0 -0
  49. {agora_python_server_sdk-2.3.4 → agora_python_server_sdk-2.4.1}/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.4
3
+ Version: 2.4.1
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
@@ -38,7 +38,7 @@ Description-Content-Type: text/markdown
38
38
  # Required Operating Systems and Python Versions
39
39
  - Supported Linux versions:
40
40
  - Ubuntu 18.04 LTS and above
41
- - CentOS 7.0 and above
41
+ - CentOS 8.0 and above
42
42
 
43
43
  - Supported Mac versions:
44
44
  - MacOS 13 and above(only for coding and testing)
@@ -57,21 +57,55 @@ pip install agora_python_server_sdk
57
57
  - Download and unzip [test_data.zip](https://download.agora.io/demo/test/test_data_202408221437.zip) to the Agora-Python-Server-SDK directory.
58
58
 
59
59
  ## Executing Test Script
60
- or linux os, should set env to :/site_packages/agora/agora_sdk/, like:
60
+ for linux os, should set env to :/site_packages/agora/agora_sdk/, like:
61
61
  export LD_LIBRARY_PATH=/site_packages/agora/agora_sdk/
62
62
  ```
63
63
  python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx --userId=xxx --audioFile=./test_data/demo.pcm --sampleRate=16000 --numOfChannels=1
64
64
  ```
65
65
 
66
66
  # Change log
67
+ ## 2025.12.17 Release 2.4.1
68
+
69
+ - Updated RTC SDK to version 154.
70
+ - Added support for VAD (Voice Activity Detection) for external audio sources, including:
71
+ - **Background voice removal**
72
+ - **Noise suppression**
73
+ - **Echo cancellation**
74
+ - **Automatic gain control**
75
+ - **Other 3A algorithms**
76
+ All supported via the `external_Audio_Processor`.
77
+ - Modified LocalUser return values for clearer SDK error code distinction.
78
+ - Added `example_external_Audio_Processor.py` to demonstrate external audio data processing.
79
+
80
+ ---
81
+
82
+ ## 2025.11.18 Release 2.4.0
83
+
84
+ - Updated SDK to APM version: `4.4.32/1025`
85
+ - Added configuration support to enable/disable APM.
86
+ - Updated methods in `setup.py` and `__init__.py`, including version/URL and MD5 processing.
87
+ - Completed main code pipeline (**further testing recommended**).
88
+ - Added RTM support: one SDK now supports both RTC and RTM.
89
+
90
+ **To-Do Items:**
91
+ - [x] Add VAD algorithm update
92
+ - [x] Add vad_dump modifications
93
+ - [x] Add APM algorithm VAD switch support
94
+ - [x] Add VAD configuration parameter setting
95
+ - [x] Download and check for MD5 mismatch on every download
96
+
97
+ **Notes:**
98
+ - **APM features** include server-side echo cancellation, noise suppression, automatic gain control, background voice removal, and more.
99
+ - Typically, AEC/AINS/AGC, etc., are handled on the client; server-side activation is only necessary for specific requirements.
100
+ - If you need to enable APM, please contact Agora technical support.
101
+
102
+ **Usage Examples:**
103
+ - [RTC usage example](https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/examples)
104
+ - [RTM usage example](https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/rtm_examples)
67
105
  # 2025.11.07 release 2.3.3
68
106
  -- update: to support rtm
69
107
  -- adjust sdk's directory structure
70
108
  -- change requests to urllib
71
- # 2025.10.23 release 2.3.2: support rtc and rtm in one package
72
- -- update: to support rtm.can support both rtc and rtm in one package.
73
- -- adjust sdk's directory structure
74
- -- update rtc sdk
75
109
  # 2025.10.09 release 2.3.1
76
110
  -- update arm64 rtc sdk:Fixed a JNI referencing issue in the previous arm64 build. This issue only outputs logs to the console and does not affect functionality.
77
111
 
@@ -23,7 +23,7 @@
23
23
  # Required Operating Systems and Python Versions
24
24
  - Supported Linux versions:
25
25
  - Ubuntu 18.04 LTS and above
26
- - CentOS 7.0 and above
26
+ - CentOS 8.0 and above
27
27
 
28
28
  - Supported Mac versions:
29
29
  - MacOS 13 and above(only for coding and testing)
@@ -42,21 +42,55 @@ pip install agora_python_server_sdk
42
42
  - Download and unzip [test_data.zip](https://download.agora.io/demo/test/test_data_202408221437.zip) to the Agora-Python-Server-SDK directory.
43
43
 
44
44
  ## Executing Test Script
45
- or linux os, should set env to :/site_packages/agora/agora_sdk/, like:
45
+ for linux os, should set env to :/site_packages/agora/agora_sdk/, like:
46
46
  export LD_LIBRARY_PATH=/site_packages/agora/agora_sdk/
47
47
  ```
48
48
  python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx --userId=xxx --audioFile=./test_data/demo.pcm --sampleRate=16000 --numOfChannels=1
49
49
  ```
50
50
 
51
51
  # Change log
52
+ ## 2025.12.17 Release 2.4.1
53
+
54
+ - Updated RTC SDK to version 154.
55
+ - Added support for VAD (Voice Activity Detection) for external audio sources, including:
56
+ - **Background voice removal**
57
+ - **Noise suppression**
58
+ - **Echo cancellation**
59
+ - **Automatic gain control**
60
+ - **Other 3A algorithms**
61
+ All supported via the `external_Audio_Processor`.
62
+ - Modified LocalUser return values for clearer SDK error code distinction.
63
+ - Added `example_external_Audio_Processor.py` to demonstrate external audio data processing.
64
+
65
+ ---
66
+
67
+ ## 2025.11.18 Release 2.4.0
68
+
69
+ - Updated SDK to APM version: `4.4.32/1025`
70
+ - Added configuration support to enable/disable APM.
71
+ - Updated methods in `setup.py` and `__init__.py`, including version/URL and MD5 processing.
72
+ - Completed main code pipeline (**further testing recommended**).
73
+ - Added RTM support: one SDK now supports both RTC and RTM.
74
+
75
+ **To-Do Items:**
76
+ - [x] Add VAD algorithm update
77
+ - [x] Add vad_dump modifications
78
+ - [x] Add APM algorithm VAD switch support
79
+ - [x] Add VAD configuration parameter setting
80
+ - [x] Download and check for MD5 mismatch on every download
81
+
82
+ **Notes:**
83
+ - **APM features** include server-side echo cancellation, noise suppression, automatic gain control, background voice removal, and more.
84
+ - Typically, AEC/AINS/AGC, etc., are handled on the client; server-side activation is only necessary for specific requirements.
85
+ - If you need to enable APM, please contact Agora technical support.
86
+
87
+ **Usage Examples:**
88
+ - [RTC usage example](https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/examples)
89
+ - [RTM usage example](https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK/tree/main/agora_rtc/rtm_examples)
52
90
  # 2025.11.07 release 2.3.3
53
91
  -- update: to support rtm
54
92
  -- adjust sdk's directory structure
55
93
  -- change requests to urllib
56
- # 2025.10.23 release 2.3.2: support rtc and rtm in one package
57
- -- update: to support rtm.can support both rtc and rtm in one package.
58
- -- adjust sdk's directory structure
59
- -- update rtc sdk
60
94
  # 2025.10.09 release 2.3.1
61
95
  -- update arm64 rtc sdk:Fixed a JNI referencing issue in the previous arm64 build. This issue only outputs logs to the console and does not affect functionality.
62
96
 
@@ -95,7 +95,16 @@ def report_progress(blocknum, blocksize, totalsize):
95
95
  downloaded = blocknum * blocksize
96
96
  print(f"\rDownloading: ----{downloaded} bytes-----", end='', flush=True)
97
97
 
98
-
98
+ def _get_url_from_version_file(path: str):
99
+ if not os.path.exists(path):
100
+ return ""
101
+ try:
102
+ with open(path, 'r') as f:
103
+ lines = f.readline()
104
+ return lines
105
+ except Exception as e:
106
+ logger.error(f"Failed to read version file: {e}")
107
+ return ""
99
108
  def _check_download_and_extract_sdk():
100
109
  agora_service_path = os.path.dirname(os.path.abspath(__file__))
101
110
  # change from dir like: /home/xxx/agora_rtc/agora/rtc/agora_sdk to
@@ -122,11 +131,28 @@ def _check_download_and_extract_sdk():
122
131
  #fusion version: 20251023
123
132
 
124
133
  url = "https://download.agora.io/sdk/release/agora_rtc_sdk-x86_64-linux-gnu-v4.4.32-20250829_160340-860733-aed_20251107_1642.zip"
134
+ #20251110 Fusion version: with apm filter
135
+ mac_sdk="https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.30_25869_FULL_20251030_1836_953684-aed.zip"
136
+ 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"
137
+
138
+ linux_sdk = "https://download.agora.io/sdk/release/agora_rtc_sdk_x86_64-linux-gnu-Agora_Native_SDK_for_Linux_x64_zhourui_26895_SERVER_20251121_1628_987405_20251021_1427-3a.zip"
139
+ mac_sdk="https://download.agora.io/sdk/release/agora_sdk_mac_Agora_Native_SDK_for_Mac_zhourui_26101_FULL_20251121_2135_987705_20251021_1427-3a.zip"
140
+
141
+ linux_sdk="https://download.agora.io/sdk/release/agora_rtc_sdk_x86_64-linux-gnu-v4.4.32.154_26982_SERVER_20251210_1745_994155_20251021_1427-3a.zip"
142
+ mac_sdk="https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32.154_26308_FULL_20251210_1756_994156_20251021_1427-3a.zip"
143
+
125
144
 
145
+
126
146
 
127
- rtc_libfile_path = os.path.join(sdk_library_dir, "libagora_rtc_sdk.so")
147
+ linux_libfile_path = os.path.join(sdk_library_dir, "libagora_rtc_sdk.so")
148
+ mac_libfile_path = os.path.join(sdk_library_dir, "libAgoraRtcKit.dylib")
149
+ linux_md5 = "e89043f0db667c207d9308d3515a67ed"
150
+ mac_md5 = "f63e8af2047a53643a1ceb0a4b24b802"
151
+
128
152
  #rtc_md5 = "7031dd10d1681cd88fd89d68c5b54282"
129
- rtc_md5 = "7eb8042e43246f95f188549d8711d1bf"
153
+ url = linux_sdk
154
+ rtc_md5 = linux_md5
155
+ rtc_libfile_path = linux_libfile_path
130
156
  if sys.platform == 'darwin':
131
157
  #url = "https://download.agora.io/sdk/release/agora_rtc_sdk_mac_rel.v4.4.30_22472_FULL_20241024_1224_398653.zip"
132
158
  # version 2.2.0 for mac
@@ -134,13 +160,12 @@ def _check_download_and_extract_sdk():
134
160
  #url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_24915_FULL_20250715_1710_791284.zip"
135
161
  #url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_25418_FULL_20250829_1647_860754.zip"
136
162
  #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"
138
-
139
-
163
+ #url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.32_25418_FULL_20250829_1647_860754-aed_20251107_1639.zip"
164
+ url = mac_sdk
140
165
 
141
- rtc_libfile_path = os.path.join(sdk_library_dir, "libAgoraRtcKit.dylib")
166
+ rtc_libfile_path = mac_libfile_path
142
167
  #rtc_md5 = "ca3ca14f9e2b7d97eb2594d1f32dab9f"
143
- rtc_md5 = "df0ec3b5073d17dee76cc4d97c13699a"
168
+ rtc_md5 = mac_md5
144
169
  if arch == "aarch64" and sys.platform == 'linux':
145
170
  #url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.31-20250307_175457-603878.zip"
146
171
  #url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.32-20250425_150503-675674.zip"
@@ -148,6 +173,7 @@ def _check_download_and_extract_sdk():
148
173
  url = "https://download.agora.io/sdk/release/Agora-RTC-aarch64-linux-gnu-v4.4.32-20251009_145437-921455_20251023_1538.zip"
149
174
  rtc_md5 = "5c002f25d2b381e353082da4f835b4f2"
150
175
 
176
+ '''
151
177
  is_file_exist = os.path.exists(rtc_libfile_path)
152
178
  if is_file_exist:
153
179
  md5_value = get_file_md5(rtc_libfile_path)
@@ -155,8 +181,15 @@ def _check_download_and_extract_sdk():
155
181
  md5_value = ""
156
182
  if md5_value == rtc_md5:
157
183
  return
184
+ '''
185
+ is_file_exist = os.path.exists(rtc_libfile_path)
186
+ version_url = _get_url_from_version_file(os.path.join(sdk_root_dir, "version.txt"))
187
+ if version_url == url and is_file_exist:
188
+ return
189
+
190
+ #change from md5 check to url check
158
191
 
159
- logger.error(f"missing agora sdk, now download it, please wait for a while...: {rtc_libfile_path} {md5_value} {rtc_md5} {is_file_exist}")
192
+ logger.error(f"missing agora sdk, now download it, please wait for a while...: {rtc_libfile_path} {version_url} {url} {is_file_exist}")
160
193
  if os.path.exists(sdk_library_dir):
161
194
  os.system(f"rm -rf {sdk_library_dir}")
162
195
  os.makedirs(sdk_library_dir, exist_ok=True)
@@ -176,6 +209,9 @@ def _check_download_and_extract_sdk():
176
209
 
177
210
  if os.path.exists(zip_path):
178
211
  os.remove(zip_path)
212
+ #write version url to version.txt
213
+ with open(os.path.join(sdk_root_dir, "version.txt"), "w") as f:
214
+ f.write(url)
179
215
  logger.error("download done, continue...")
180
216
 
181
217
 
@@ -198,5 +234,6 @@ else:
198
234
  if not os.path.exists(rtc_libfile_path):
199
235
  logger.error(f"library {rtc_libfile_path} not found")
200
236
  sys.exit(1)
201
- # import these variables to the sub modules
202
- __all__ = ['sdk_library_dir', 'sdk_rtc_dir', 'sdk_rtm_dir', 'sdk_root_dir']
237
+
238
+ # Explicitly export these variables to ensure that submodules can import them
239
+ __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}")
@@ -1368,4 +1368,49 @@ class CapabilitiesItemMapInner(ctypes.Structure):
1368
1368
  return CapabilitiesItemMap(
1369
1369
  item=self.item,
1370
1370
  size=self.size
1371
- )
1371
+ )
1372
+
1373
+ class AudioSinkWantesInner(ctypes.Structure):
1374
+ _fields_ = [
1375
+ ("samples_per_sec", ctypes.c_int),
1376
+ ("channels", ctypes.c_uint32),
1377
+ ]
1378
+ pass
1379
+ class AudioLabelInner(ctypes.Structure):
1380
+ _fields_ = [
1381
+ ("far_filed_flag", ctypes.c_int),
1382
+ ("rms", ctypes.c_int),
1383
+ ("voice_prob", ctypes.c_int),
1384
+ ("music_prob", ctypes.c_int),
1385
+ ("pitch", ctypes.c_int),
1386
+ ]
1387
+ class AudioPcmFrameInner(ctypes.Structure):
1388
+ _fields_ = [
1389
+ ("capture_timestamp", ctypes.c_uint32),
1390
+ ("samples_per_channel", ctypes.c_uint32),
1391
+ ("sample_rate_hz", ctypes.c_int),
1392
+ ("num_channels", ctypes.c_uint32),
1393
+ ("bytes_per_sample", ctypes.c_uint32),
1394
+ ("data", ctypes.c_int16*3840),
1395
+ ("audio_label", AudioLabelInner),
1396
+ ]
1397
+ def get(self):
1398
+ return AudioFrame(
1399
+ type=0,
1400
+ samples_per_channel=self.samples_per_channel,
1401
+ bytes_per_sample=self.bytes_per_sample,
1402
+ channels=self.num_channels,
1403
+ samples_per_sec=self.sample_rate_hz,
1404
+ buffer=bytearray(ctypes.string_at(self.data, self.samples_per_channel * self.bytes_per_sample * self.num_channels)),
1405
+ render_time_ms=self.capture_timestamp,
1406
+ avsync_type=0,
1407
+ presentation_ms=0,
1408
+ audio_track_number=0,
1409
+ rtp_timestamp=0,
1410
+ far_field_flag=self.audio_label.far_filed_flag,
1411
+ rms=self.audio_label.rms,
1412
+ voice_prob=self.audio_label.voice_prob,
1413
+ music_prob=self.audio_label.music_prob,
1414
+ pitch=self.audio_label.pitch
1415
+ )
1416
+ pass
@@ -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,20 @@ 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
+ if config.enable_apm:
122
+ generator = "audio_processing_pcm_source"
123
+ cgenerator = generator.encode('utf-8')
124
+ result = agora_service_enable_extension(self.service_handle, cprovider, cgenerator, ctrak, 1)
125
+ if result != 0:
126
+ logger.error(f"Failed to enable audio processing pcm source filter. Error code: {result}")
127
+
105
128
  #versio 2.2.0 for callback when muted
106
129
  if config.should_callbck_when_muted > 0:
107
130
  agora_parameter.set_parameters("{\"rtc.audio.enable_user_silence_packet\": true}")
@@ -112,6 +135,17 @@ class AgoraService:
112
135
  '''
113
136
  agora_parameter.set_parameters("{\"che.video.min_enc_level\": 0}")
114
137
 
138
+ #keep & save apm config
139
+ self.enable_apm = config.enable_apm
140
+ if self.enable_apm:
141
+ if config.apm_config is None:
142
+ self.apm_config = APMConfig()
143
+ else:
144
+ self.apm_config = config.apm_config
145
+ else:
146
+ self.apm_config = None
147
+
148
+
115
149
  return result
116
150
 
117
151
  def release(self):
@@ -210,3 +244,27 @@ class AgoraService:
210
244
  else:
211
245
  logger.error(f"Failed to set log file. Error code: {result}")
212
246
  return result
247
+ #apm related:
248
+ #apm related api
249
+ def _get_audio_filter_position(is_local_track: bool = False) -> int:
250
+ if is_local_track:
251
+ return 3
252
+ return 2
253
+
254
+ def _enable_audio_filter_by_track(track: any, name: str, enable: bool, is_local_track: bool) -> int:
255
+ if track is None:
256
+ return -1000
257
+ c_name = ctypes.c_char_p(name.encode('utf-8'))
258
+ c_enable = ctypes.c_int(0)
259
+ if enable:
260
+ c_enable = ctypes.c_int(1)
261
+ position = _get_audio_filter_position(is_local_track)
262
+ return int(agora_audio_track_enable_audio_filter(track, c_name, c_enable, ctypes.c_int(position)))
263
+ def _set_filter_property_by_track(track: any, name: str, key: str, value: str, is_local_track: bool) -> int:
264
+ if track is None:
265
+ return -1000
266
+ c_name = ctypes.c_char_p(name.encode('utf-8'))
267
+ c_key = ctypes.c_char_p(key.encode('utf-8'))
268
+ c_value = ctypes.c_char_p(value.encode('utf-8'))
269
+ position = _get_audio_filter_position(is_local_track)
270
+ return int(agora_audio_track_set_filter_property(track, c_name, c_key, c_value, ctypes.c_int(position)))