agora-python-server-sdk 2.4.1__tar.gz → 2.4.3__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.4.1 → agora_python_server_sdk-2.4.3}/PKG-INFO +35 -2
  2. agora_python_server_sdk-2.4.1/agora_python_server_sdk.egg-info/PKG-INFO → agora_python_server_sdk-2.4.3/README.md +28 -16
  3. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_ctypes_handle/_local_user_observer.py +1 -1
  4. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_ctypes_handle/_rtc_connection_observer.py +1 -1
  5. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/agora_base.py +13 -0
  6. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/agora_service.py +5 -5
  7. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/local_user.py +16 -1
  8. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/rtc_connection.py +94 -5
  9. agora_python_server_sdk-2.4.1/README.md → agora_python_server_sdk-2.4.3/agora_python_server_sdk.egg-info/PKG-INFO +49 -1
  10. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/setup.py +1 -1
  11. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/MANIFEST.in +0 -0
  12. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/__init__.py +0 -0
  13. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/__init__.py +0 -0
  14. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_ctypes_handle/_audio_frame_observer.py +0 -0
  15. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_ctypes_handle/_ctypes_data.py +0 -0
  16. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_ctypes_handle/_video_encoded_frame_observer.py +0 -0
  17. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_ctypes_handle/_video_frame_observer.py +0 -0
  18. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/_utils/globals.py +0 -0
  19. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/agora_parameter.py +0 -0
  20. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/audio_encoded_frame_sender.py +0 -0
  21. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/audio_frame_observer.py +0 -0
  22. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/audio_pcm_data_sender.py +0 -0
  23. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/audio_sessionctrl.py +0 -0
  24. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/audio_vad_manager.py +0 -0
  25. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/external_audio_processor.py +0 -0
  26. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/local_audio_track.py +0 -0
  27. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/local_user_observer.py +0 -0
  28. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/local_video_track.py +0 -0
  29. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/media_node_factory.py +0 -0
  30. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/remote_audio_track.py +0 -0
  31. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/remote_video_track.py +0 -0
  32. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/rtc_connection_observer.py +0 -0
  33. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/utils/audio_consumer.py +0 -0
  34. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/utils/vad_dump.py +0 -0
  35. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/video_encoded_frame_observer.py +0 -0
  36. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/video_encoded_image_sender.py +0 -0
  37. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/video_frame_observer.py +0 -0
  38. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/video_frame_sender.py +0 -0
  39. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtc/voice_detection.py +0 -0
  40. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtm/__init__.py +0 -0
  41. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtm/_ctypes_handle/_ctypes_data.py +0 -0
  42. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtm/rtm_base.py +0 -0
  43. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtm/rtm_client.py +0 -0
  44. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora/rtm/rtm_event_handler.py +0 -0
  45. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora_python_server_sdk.egg-info/SOURCES.txt +0 -0
  46. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora_python_server_sdk.egg-info/dependency_links.txt +0 -0
  47. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/agora_python_server_sdk.egg-info/top_level.txt +0 -0
  48. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/pyproject.toml +0 -0
  49. {agora_python_server_sdk-2.4.1 → agora_python_server_sdk-2.4.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: agora_python_server_sdk
3
- Version: 2.4.1
3
+ Version: 2.4.3
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,6 +12,12 @@ 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
15
21
 
16
22
  # Note
17
23
  - This is a Python SDK wrapper for the Agora RTC SDK.
@@ -64,6 +70,33 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
64
70
  ```
65
71
 
66
72
  # Change log
73
+
74
+ ## 2026.01.15 Release Version 2.4.3
75
+
76
+ - **Bugfix**: Fixed a bug to reset `pcm_consumer_` when calling `interrupt_audio`.
77
+
78
+ ## 2025.12.29 Release Version 2.4.2
79
+
80
+ - Added **incremental send mode** support.
81
+ - New `connection::send_intra_request` API, allowing you to initiate an intra request to remote users and trigger them to send a key frame.
82
+
83
+ #### Example usage of incremental send mode
84
+
85
+ ```python
86
+ # Configure incremental send parameters
87
+ publish_config.send_external_audio_parameters = SendExternalAudioParameters(
88
+ enabled=True,
89
+ send_ms=2000,
90
+ send_speed=2,
91
+ deliver_mute_data_for_fake_adm=False
92
+ )
93
+
94
+ # Create an RTC connection
95
+ connection = agora_service.create_rtc_connection(con_config, publish_config)
96
+ ```
97
+
98
+
99
+
67
100
  ## 2025.12.17 Release 2.4.1
68
101
 
69
102
  - Updated RTC SDK to version 154.
@@ -1,18 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: agora_python_server_sdk
3
- Version: 2.4.1
4
- Summary: A Python SDK for Agora Server
5
- Home-page: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK
6
- Classifier: Intended Audience :: Developers
7
- Classifier: License :: OSI Approved :: MIT License
8
- Classifier: Topic :: Multimedia :: Sound/Audio
9
- Classifier: Topic :: Multimedia :: Video
10
- Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3 :: Only
13
- Requires-Python: >=3.10
14
- Description-Content-Type: text/markdown
15
-
16
1
  # Note
17
2
  - This is a Python SDK wrapper for the Agora RTC SDK.
18
3
  - It supports Linux and Mac platforms.
@@ -64,6 +49,33 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
64
49
  ```
65
50
 
66
51
  # Change log
52
+
53
+ ## 2026.01.15 Release Version 2.4.3
54
+
55
+ - **Bugfix**: Fixed a bug to reset `pcm_consumer_` when calling `interrupt_audio`.
56
+
57
+ ## 2025.12.29 Release Version 2.4.2
58
+
59
+ - Added **incremental send mode** support.
60
+ - New `connection::send_intra_request` API, allowing you to initiate an intra request to remote users and trigger them to send a key frame.
61
+
62
+ #### Example usage of incremental send mode
63
+
64
+ ```python
65
+ # Configure incremental send parameters
66
+ publish_config.send_external_audio_parameters = SendExternalAudioParameters(
67
+ enabled=True,
68
+ send_ms=2000,
69
+ send_speed=2,
70
+ deliver_mute_data_for_fake_adm=False
71
+ )
72
+
73
+ # Create an RTC connection
74
+ connection = agora_service.create_rtc_connection(con_config, publish_config)
75
+ ```
76
+
77
+
78
+
67
79
  ## 2025.12.17 Release 2.4.1
68
80
 
69
81
  - Updated RTC SDK to version 154.
@@ -570,4 +582,4 @@ VAD: Good afternoon, what are some fun places to visit in Beijing?
570
582
 
571
583
 
572
584
 
573
- If latency is a concern, you can lower this value, or consult with the development team to determine how to manage latency while ensuring semantic continuity in speech recognition. This will help avoid the AI being interrupted too sensitively.
585
+ If latency is a concern, you can lower this value, or consult with the development team to determine how to manage latency while ensuring semantic continuity in speech recognition. This will help avoid the AI being interrupted too sensitively.
@@ -171,7 +171,7 @@ class RTCLocalUserObserverInner(ctypes.Structure):
171
171
  def _on_audio_track_publication_failure(self, local_user_handle, local_audio_track_handle, error_code):
172
172
  logger.debug(f"LocalUserCB _on_audio_track_publication_failure: {local_user_handle}, {local_audio_track_handle}, {error_code}")
173
173
  audio_track = self.local_user.get_audio_map(local_audio_track_handle)
174
- self.local_user.del_audio_map(local_audio_track_handle)
174
+ self.local_user._del_audio_map(local_audio_track_handle)
175
175
  self.local_user_observer.on_audio_track_publication_failure(self.local_user, audio_track, error_code)
176
176
 
177
177
  def _on_local_audio_track_state_changed(self, local_user_handle, local_audio_track_handle, state, error):
@@ -288,7 +288,7 @@ class CapabilitiesObserverInner(ctypes.Structure):
288
288
  self.on_capabilities_changed = ON_CAPABILITIES_CHANGED_CALLBACK(self._on_capabilities_changed)
289
289
 
290
290
  def _on_capabilities_changed(self, agora_capabilities_observer, ptr_caps_inner, size):
291
- print(f"ConnCB _on_capabilities_changed: {agora_capabilities_observer}, {ptr_caps_inner}, {size}")
291
+ logger.debug(f"ConnCB _on_capabilities_changed: {agora_capabilities_observer}, {ptr_caps_inner}, {size}")
292
292
 
293
293
  # 正确解析C指针数组
294
294
  # 方法1: 使用ctypes.cast将指针转换为数组
@@ -427,6 +427,18 @@ class SenderOptions:
427
427
  cc_mode: TCcMode = TCcMode.CC_ENABLED
428
428
  codec_type: VideoCodecType = VideoCodecType.VIDEO_CODEC_H264
429
429
 
430
+ '''
431
+ note: DeliverMuteDataForFakeAdm can only set to rtc engine level, can not
432
+ set to connection level
433
+ so if once a connection has set to true, wihich will affect all the connections,
434
+ '''
435
+ @dataclass(kw_only=True)
436
+ class SendExternalAudioParameters:
437
+ enabled: bool = False
438
+ send_ms: int = 0
439
+ send_speed: int = 0
440
+ deliver_mute_data_for_fake_adm: bool = False
441
+
430
442
 
431
443
  @dataclass(kw_only=True)
432
444
  class RtcConnectionPublishConfig:
@@ -437,6 +449,7 @@ class RtcConnectionPublishConfig:
437
449
  audio_publish_type: AudioPublishType = AudioPublishType.AUDIO_PUBLISH_TYPE_PCM
438
450
  video_publish_type: VideoPublishType = VideoPublishType.VIDEO_PUBLISH_TYPE_NONE
439
451
  video_encoded_image_sender_options: 'SenderOptions' = field(default_factory=SenderOptions)
452
+ send_external_audio_parameters: 'SendExternalAudioParameters | None' = None
440
453
 
441
454
  @dataclass(kw_only=True)
442
455
  class VideoSubscriptionOptions:
@@ -186,11 +186,11 @@ class AgoraService:
186
186
  return RTCConnection(self, con_config, publish_config)
187
187
 
188
188
  # createCustomAudioTrackPcm: creatae a custom audio track from pcm data sender
189
- def _create_custom_audio_track_pcm(self, audio_pcm_data_sender: AudioPcmDataSender, scenario: AudioScenarioType) -> LocalAudioTrack:
189
+ def _create_custom_audio_track_pcm(self, audio_pcm_data_sender: AudioPcmDataSender, scenario: AudioScenarioType, is_extra_audio: bool) -> LocalAudioTrack:
190
190
  if not self.inited:
191
191
  logger.error("AgoraService is not initialized. Please call initialize() first.")
192
192
  return None
193
- if scenario == AudioScenarioType.AUDIO_SCENARIO_AI_SERVER:
193
+ if scenario == AudioScenarioType.AUDIO_SCENARIO_AI_SERVER and is_extra_audio == False:
194
194
  custom_audio_track = agora_service_create_direct_custom_audio_track_pcm(self.service_handle, audio_pcm_data_sender.sender_handle)
195
195
  else:
196
196
  custom_audio_track = agora_service_create_custom_audio_track_pcm(self.service_handle, audio_pcm_data_sender.sender_handle)
@@ -198,10 +198,10 @@ class AgoraService:
198
198
  return None
199
199
  local_track = LocalAudioTrack(custom_audio_track)
200
200
  #default for ai senario to set min delay to 10ms
201
- if scenario != AudioScenarioType.AUDIO_SCENARIO_AI_SERVER:
202
- local_track.set_send_delay_ms(10)
203
- local_track.set_max_buffer_audio_frame_number(100000)
201
+
202
+ local_track.set_max_buffer_audio_frame_number(100000)
204
203
  #and set enable to true
204
+ local_track.set_send_delay_ms(10)
205
205
  local_track.set_enabled(True)
206
206
  return local_track
207
207
  # mix_mode: MIX_ENABLED = 0, MIX_DISABLED = 1
@@ -230,7 +230,9 @@ agora_local_user_send_aduio_meta_data = agora_lib.agora_local_user_send_audio_me
230
230
  agora_local_user_send_aduio_meta_data.restype = AGORA_API_C_INT
231
231
  agora_local_user_send_aduio_meta_data.argtypes = [AGORA_HANDLE, ctypes.c_char_p, ctypes.c_size_t]
232
232
 
233
-
233
+ agora_local_user_send_intra_request = agora_lib.agora_local_user_send_intra_request
234
+ agora_local_user_send_intra_request.restype = AGORA_API_C_INT
235
+ agora_local_user_send_intra_request.argtypes = [AGORA_HANDLE, ctypes.c_char_p]
234
236
 
235
237
 
236
238
  class LocalUser:
@@ -628,3 +630,16 @@ class LocalUser:
628
630
  ret = self.connection._set_apm_filter_properties(remote_audio_track_handle, user_id_str)
629
631
  print(f"**********LocalUser _set_apm_filter_properties: {ret}")
630
632
  return ret
633
+ pass
634
+ def _send_intra_request(self, remote_uid: str) -> int:
635
+ #validity check
636
+ if remote_uid is None:
637
+ return -1000
638
+ if self.user_handle is None:
639
+ return -1001
640
+ uid_str = remote_uid.encode('utf-8')
641
+ ret = agora_local_user_send_intra_request(self.user_handle, ctypes.c_char_p(uid_str))
642
+ if ret < 0:
643
+ logger.error("Failed to send intra request")
644
+ return ret
645
+ pass
@@ -83,6 +83,13 @@ agora_local_user_unregister_capabilities_observer = agora_lib.agora_local_user_u
83
83
  agora_local_user_unregister_capabilities_observer.restype = AGORA_API_C_INT
84
84
  agora_local_user_unregister_capabilities_observer.argtypes = [AGORA_HANDLE, AGORA_HANDLE]
85
85
 
86
+ agora_local_audio_track_set_total_extra_send_ms = agora_lib.agora_local_audio_track_set_total_extra_send_ms
87
+ agora_local_audio_track_set_total_extra_send_ms.restype = AGORA_API_C_INT
88
+ agora_local_audio_track_set_total_extra_send_ms.argtypes = [AGORA_HANDLE, ctypes.c_uint64]
89
+
90
+ #global variable
91
+ _is_deliver_mute_data_has_set: bool = False
92
+
86
93
  class RTCConnection:
87
94
  def __init__(self, service: AgoraService, conn_config: RTCConnConfig, publish_config: RtcConnectionPublishConfig) -> None:
88
95
  self.conn_handle = None
@@ -90,6 +97,7 @@ class RTCConnection:
90
97
  self.local_user = None
91
98
  self.rtc_engine = service
92
99
  self._con_observer = None
100
+ self._agora_parameter = None
93
101
  #1 create conn_handle
94
102
  self.conn_handle = agora_rtc_conn_create(self.rtc_engine.service_handle, ctypes.byref(RTCConnConfigInner.create(conn_config)))
95
103
  if self.conn_handle is None:
@@ -98,6 +106,7 @@ class RTCConnection:
98
106
  self.local_user_handle = agora_rtc_conn_get_local_user(self.conn_handle)
99
107
  if self.local_user_handle:
100
108
  self.local_user = LocalUser(self.local_user_handle, self)
109
+ self._agora_parameter = self._init_agora_parameter()
101
110
  #keep publish_config
102
111
  self.publish_config = publish_config
103
112
  #and prepare track and sender for publish
@@ -107,6 +116,9 @@ class RTCConnection:
107
116
  self._audio_encoded_sender = None
108
117
  self._video_sender = None
109
118
  self._video_encoded_sender = None
119
+ # for external audio parameters
120
+ self._send_external_audio_parameters = publish_config.send_external_audio_parameters
121
+
110
122
  self._pcm_consume_stats = PcmConsumeStats()
111
123
  self._prepare_publish_track_and_sender()
112
124
  #3 set profile and scenario
@@ -123,12 +135,15 @@ class RTCConnection:
123
135
  self._capabilities_observer_obj = None
124
136
  if self.publish_config.audio_scenario == AudioScenarioType.AUDIO_SCENARIO_AI_SERVER:
125
137
  self._register_capabilities_observer()
138
+ # for external audio parameters
139
+ self._set_send_external_send_frame_speed(self._send_external_audio_parameters)
126
140
 
127
141
  def _prepare_publish_track_and_sender(self)->int:
128
142
  if self.publish_config.is_publish_audio:
129
143
  if self.publish_config.audio_publish_type == AudioPublishType.AUDIO_PUBLISH_TYPE_PCM:
130
144
  self._audio_sender = self.rtc_engine.media_node_factory.create_audio_pcm_data_sender()
131
- self._audio_track = self.rtc_engine._create_custom_audio_track_pcm(self._audio_sender, self.publish_config.audio_scenario)
145
+ is_extra_audio = self._is_support_send_external_audio()
146
+ self._audio_track = self.rtc_engine._create_custom_audio_track_pcm(self._audio_sender, self.publish_config.audio_scenario, is_extra_audio)
132
147
  elif self.publish_config.audio_publish_type == AudioPublishType.AUDIO_PUBLISH_TYPE_ENCODED_PCM:
133
148
  self._audio_encoded_sender = self.rtc_engine.media_node_factory.create_audio_encoded_frame_sender()
134
149
  self._audio_track = self.rtc_engine.create_custom_audio_track_encoded(self._audio_encoded_sender, 1)#mix_mode: MIX_ENABLED = 0, MIX_DISABLED = 1
@@ -203,11 +218,13 @@ class RTCConnection:
203
218
  return ret
204
219
 
205
220
  #
206
- def get_agora_parameter(self):
221
+ def _init_agora_parameter(self):
207
222
  agora_parameter = agora_rtc_conn_get_agora_parameter(self.conn_handle)
208
223
  if not agora_parameter:
209
224
  return None
210
225
  return AgoraParameter(agora_parameter)
226
+ def get_agora_parameter(self):
227
+ return self._agora_parameter
211
228
 
212
229
  #
213
230
 
@@ -337,6 +354,8 @@ class RTCConnection:
337
354
  ret = -1000
338
355
  if self.local_user and self._audio_track:
339
356
  ret = self.local_user._unpublish_audio(self._audio_track)
357
+ #reset pcm consumer state now
358
+ self._pcm_consume_stats.reset()
340
359
  return ret
341
360
  def publish_video(self)->int:
342
361
  ret = -1000
@@ -357,6 +376,9 @@ class RTCConnection:
357
376
  self.publish_audio()
358
377
  elif self._audio_track:
359
378
  self._audio_track.clear_sender_buffer()
379
+
380
+ # reset pcm consumer to new state now
381
+ self._pcm_consume_stats.reset()
360
382
  return ret
361
383
  def send_audio_meta_data(self, data)->int:
362
384
  ret = -1000
@@ -397,6 +419,11 @@ class RTCConnection:
397
419
  frame.samples_per_channel = readLen // (channels * 2)
398
420
  frame.present_time_ms = start_pts
399
421
 
422
+ #check if a new round or not. if new round should call _set_total_extra_send_ms()
423
+ is_new_round = self._pcm_consume_stats.is_new_round()
424
+ if is_new_round:
425
+ self._set_total_extra_send_ms()
426
+
400
427
  ret = self._audio_sender.send_audio_pcm_data(frame)
401
428
  self._pcm_consume_stats.add_pcm_data(readLen, sample_rate, channels)
402
429
  return ret
@@ -431,8 +458,9 @@ class RTCConnection:
431
458
 
432
459
  updated_track = None
433
460
  delayed_del_track = None
461
+ is_extra_audio = False
434
462
  if self._audio_sender:
435
- updated_track = self.rtc_engine._create_custom_audio_track_pcm(self._audio_sender, scenario)
463
+ updated_track = self.rtc_engine._create_custom_audio_track_pcm(self._audio_sender, scenario, is_extra_audio)
436
464
  elif self._audio_encoded_sender:
437
465
  updated_track = self.rtc_engine.create_custom_audio_track_encoded(self._audio_encoded_sender, scenario)
438
466
 
@@ -440,6 +468,8 @@ class RTCConnection:
440
468
  delayed_del_track = self._audio_track
441
469
  self._audio_track = updated_track
442
470
  self._audio_track.set_enabled(True)
471
+ self._audio_track.set_send_delay_ms(10)
472
+ self._audio_track.set_max_buffer_audio_frame_number(100000)
443
473
 
444
474
  if delayed_del_track:
445
475
  delayed_del_track.release()
@@ -467,10 +497,10 @@ class RTCConnection:
467
497
  item_index = 0
468
498
  for cap in capabilities:
469
499
  item_index = 0
470
- print(f"Capability[{index}] - Type: {cap.capability_type}")
500
+ logger.debug(f"Capability[{index}] - Type: {cap.capability_type}")
471
501
  index += 1
472
502
  for item in cap.item_map.item:
473
- print(f"Item[{item_index}] - ID: {item.id}, Name: {item.name}")
503
+ logger.debug(f"Item[{item_index}] - ID: {item.id}, Name: {item.name}")
474
504
  item_index += 1
475
505
  if cap.capability_type == 19 and item.name and item.name.upper() == "SUPPORT":
476
506
  fallback_scenario = False
@@ -541,5 +571,64 @@ class RTCConnection:
541
571
  print(f"**********APM: to enable apm_dump, error: {ret}")
542
572
  return ret
543
573
 
574
+ def _set_send_external_send_frame_speed(self, send_external_audio_parameters: SendExternalAudioParameters)->int:
575
+ ret = -1000
576
+ if send_external_audio_parameters == None or send_external_audio_parameters.enabled == False or send_external_audio_parameters.send_ms <= 0 or send_external_audio_parameters.send_speed <= 1:
577
+ return -1001
578
+ speed = send_external_audio_parameters.send_speed
579
+ if speed < 1:
580
+ speed = 1
581
+ if speed > 5:
582
+ speed = 5
583
+ #set send speed for fake adm to connection level
584
+ params = '{"che.audio.extra_send_frames_per_interval_for_fake_adm": %d}' % speed
585
+
586
+ if (self._agora_parameter is None):
587
+ return -1002
588
+ ret = self._agora_parameter.set_parameters(params)
589
+
590
+
591
+ # set deliver mute data for fake adm to service level and only once
592
+ self._set_deliver_mute_data_for_fake_adm(send_external_audio_parameters.deliver_mute_data_for_fake_adm)
593
+
594
+ return ret
595
+ pass
596
+
597
+ def _set_deliver_mute_data_for_fake_adm(self, deliver_mute_data_for_fake_adm: bool)->int:
598
+ ret = -1000
599
+ global _is_deliver_mute_data_has_set
600
+ if deliver_mute_data_for_fake_adm == False and _is_deliver_mute_data_has_set == False:
601
+ params = '{"che.audio.deliver_mute_data_for_fake_adm": false}'
602
+ rtc_parameter = self.rtc_engine.get_agora_parameter()
603
+ if rtc_parameter is not None:
604
+ ret = rtc_parameter.set_parameters(params)
605
+ _is_deliver_mute_data_has_set = True
606
+ return ret
607
+ def _is_support_send_external_audio(self)->bool:
608
+ ret = False
609
+ if ((self._send_external_audio_parameters is not None)
610
+ and (self._send_external_audio_parameters.enabled == True)
611
+ and (self._send_external_audio_parameters.send_ms > 0)
612
+ and (self._send_external_audio_parameters.send_speed > 1)):
613
+ ret = True
614
+ return ret
615
+ pass
616
+ #only valid after call this api
617
+ #and default call before each round
618
+ def _set_total_extra_send_ms(self)->int:
619
+ is_support = self._is_support_send_external_audio()
620
+ if is_support == False:
621
+ return 0
622
+ send_ms = self._send_external_audio_parameters.send_ms
623
+ ret = agora_local_audio_track_set_total_extra_send_ms(self._audio_track.track_handle, ctypes.c_uint64(send_ms))
544
624
 
625
+ return ret
626
+ pass
627
+ def send_intra_request(self, remote_uid: str) -> int:
628
+ ret = -1000
629
+ if self.local_user is None:
630
+ return -1001
631
+ ret = self.local_user._send_intra_request(remote_uid)
632
+ return ret
633
+ pass
545
634
 
@@ -1,3 +1,24 @@
1
+ Metadata-Version: 2.2
2
+ Name: agora_python_server_sdk
3
+ Version: 2.4.3
4
+ Summary: A Python SDK for Agora Server
5
+ Home-page: https://github.com/AgoraIO-Extensions/Agora-Python-Server-SDK
6
+ Classifier: Intended Audience :: Developers
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Topic :: Multimedia :: Sound/Audio
9
+ Classifier: Topic :: Multimedia :: Video
10
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Requires-Python: >=3.10
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
+
1
22
  # Note
2
23
  - This is a Python SDK wrapper for the Agora RTC SDK.
3
24
  - It supports Linux and Mac platforms.
@@ -49,6 +70,33 @@ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx
49
70
  ```
50
71
 
51
72
  # Change log
73
+
74
+ ## 2026.01.15 Release Version 2.4.3
75
+
76
+ - **Bugfix**: Fixed a bug to reset `pcm_consumer_` when calling `interrupt_audio`.
77
+
78
+ ## 2025.12.29 Release Version 2.4.2
79
+
80
+ - Added **incremental send mode** support.
81
+ - New `connection::send_intra_request` API, allowing you to initiate an intra request to remote users and trigger them to send a key frame.
82
+
83
+ #### Example usage of incremental send mode
84
+
85
+ ```python
86
+ # Configure incremental send parameters
87
+ publish_config.send_external_audio_parameters = SendExternalAudioParameters(
88
+ enabled=True,
89
+ send_ms=2000,
90
+ send_speed=2,
91
+ deliver_mute_data_for_fake_adm=False
92
+ )
93
+
94
+ # Create an RTC connection
95
+ connection = agora_service.create_rtc_connection(con_config, publish_config)
96
+ ```
97
+
98
+
99
+
52
100
  ## 2025.12.17 Release 2.4.1
53
101
 
54
102
  - Updated RTC SDK to version 154.
@@ -555,4 +603,4 @@ VAD: Good afternoon, what are some fun places to visit in Beijing?
555
603
 
556
604
 
557
605
 
558
- If latency is a concern, you can lower this value, or consult with the development team to determine how to manage latency while ensuring semantic continuity in speech recognition. This will help avoid the AI being interrupted too sensitively.
606
+ If latency is a concern, you can lower this value, or consult with the development team to determine how to manage latency while ensuring semantic continuity in speech recognition. This will help avoid the AI being interrupted too sensitively.
@@ -126,7 +126,7 @@ class CustomInstallCommand(install):
126
126
 
127
127
  setup(
128
128
  name='agora_python_server_sdk',
129
- version='2.4.1',
129
+ version='2.4.3',
130
130
  description='A Python SDK for Agora Server',
131
131
  long_description=open('README.md').read(),
132
132
  long_description_content_type='text/markdown',