agora-python-server-sdk 2.0.3__tar.gz → 2.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (42) hide show
  1. agora_python_server_sdk-2.0.4/PKG-INFO +53 -0
  2. agora_python_server_sdk-2.0.4/README.md +36 -0
  3. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/__init__.py +3 -3
  4. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/_audio_frame_observer.py +17 -31
  5. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/_local_user_observer.py +1 -51
  6. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/_rtc_connection_observer.py +5 -62
  7. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/_video_encoded_frame_observer.py +0 -6
  8. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/_video_frame_observer.py +6 -25
  9. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/agora_base.py +5 -0
  10. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/agora_service.py +19 -3
  11. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/audio_encoded_frame_sender.py +3 -20
  12. agora_python_server_sdk-2.0.4/agora/rtc/audio_frame_observer.py +32 -0
  13. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/audio_vad.py +1 -2
  14. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/globals.py +4 -4
  15. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/local_audio_track.py +11 -23
  16. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/local_user.py +11 -84
  17. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/local_user_observer.py +1 -1
  18. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/local_video_track.py +0 -6
  19. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/media_node_factory.py +5 -5
  20. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/remote_video_track.py +3 -12
  21. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/rtc_connection.py +11 -25
  22. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/rtc_connection_observer.py +0 -10
  23. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/video_encoded_frame_observer.py +0 -1
  24. agora_python_server_sdk-2.0.4/agora/rtc/video_encoded_image_sender.py +87 -0
  25. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/video_frame_observer.py +3 -0
  26. agora_python_server_sdk-2.0.4/agora/rtc/video_frame_sender.py +92 -0
  27. agora_python_server_sdk-2.0.4/agora_python_server_sdk.egg-info/PKG-INFO +53 -0
  28. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora_python_server_sdk.egg-info/SOURCES.txt +1 -0
  29. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/setup.py +3 -3
  30. agora_python_server_sdk-2.0.3/PKG-INFO +0 -76
  31. agora_python_server_sdk-2.0.3/README.md +0 -59
  32. agora_python_server_sdk-2.0.3/agora/rtc/audio_frame_observer.py +0 -50
  33. agora_python_server_sdk-2.0.3/agora/rtc/video_frame_sender.py +0 -200
  34. agora_python_server_sdk-2.0.3/agora_python_server_sdk.egg-info/PKG-INFO +0 -76
  35. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/MANIFEST.in +0 -0
  36. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/agora_parameter.py +0 -0
  37. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/audio_pcm_data_sender.py +0 -0
  38. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora/rtc/remote_audio_track.py +0 -0
  39. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora_python_server_sdk.egg-info/dependency_links.txt +0 -0
  40. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/agora_python_server_sdk.egg-info/top_level.txt +0 -0
  41. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/pyproject.toml +0 -0
  42. {agora_python_server_sdk-2.0.3 → agora_python_server_sdk-2.0.4}/setup.cfg +0 -0
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.1
2
+ Name: agora_python_server_sdk
3
+ Version: 2.0.4
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
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Note
19
+ - This is a Python SDK wrapper for the Agora RTC SDK.
20
+ - It supports Linux and Mac platforms.
21
+ - The examples are provided as very simple demonstrations and are not recommended for use in production environments.
22
+
23
+ # Very Important Notice !!!
24
+ - A process can only have one instance.
25
+ - An instance can have multiple connections.
26
+ - In all observers or callbacks, you must not call the SDK's own APIs, nor perform CPU-intensive tasks in the callbacks; data copying is allowed.
27
+
28
+ # Required Operating Systems and Python Versions
29
+ - Supported Linux versions:
30
+ - Ubuntu 18.04 LTS and above
31
+ - CentOS 7.0 and above
32
+
33
+ - Supported Mac versions:
34
+ - MacOS 13 and above
35
+
36
+ - Python version:
37
+ - Python 3.8 and above
38
+
39
+ # Using Agora-Python-Server-SDK
40
+ ```
41
+ pip install agora_python_server_sdk
42
+ ```
43
+
44
+ # Running Examples
45
+
46
+ ## Preparing Test Data
47
+ - Download and unzip [test_data.zip](https://download.agora.io/demo/test/test_data_202408221437.zip) to the Agora-Python-Server-SDK directory.
48
+
49
+ ## Executing Test Script
50
+ ```
51
+ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx --userId=xxx --audioFile=./test_data/demo.pcm --sampleRate=16000 --numOfChannels=1
52
+ ```
53
+
@@ -0,0 +1,36 @@
1
+ # Note
2
+ - This is a Python SDK wrapper for the Agora RTC SDK.
3
+ - It supports Linux and Mac platforms.
4
+ - The examples are provided as very simple demonstrations and are not recommended for use in production environments.
5
+
6
+ # Very Important Notice !!!
7
+ - A process can only have one instance.
8
+ - An instance can have multiple connections.
9
+ - In all observers or callbacks, you must not call the SDK's own APIs, nor perform CPU-intensive tasks in the callbacks; data copying is allowed.
10
+
11
+ # Required Operating Systems and Python Versions
12
+ - Supported Linux versions:
13
+ - Ubuntu 18.04 LTS and above
14
+ - CentOS 7.0 and above
15
+
16
+ - Supported Mac versions:
17
+ - MacOS 13 and above
18
+
19
+ - Python version:
20
+ - Python 3.8 and above
21
+
22
+ # Using Agora-Python-Server-SDK
23
+ ```
24
+ pip install agora_python_server_sdk
25
+ ```
26
+
27
+ # Running Examples
28
+
29
+ ## Preparing Test Data
30
+ - Download and unzip [test_data.zip](https://download.agora.io/demo/test/test_data_202408221437.zip) to the Agora-Python-Server-SDK directory.
31
+
32
+ ## Executing Test Script
33
+ ```
34
+ python agora_rtc/examples/example_audio_pcm_send.py --appId=xxx --channelId=xxx --userId=xxx --audioFile=./test_data/demo.pcm --sampleRate=16000 --numOfChannels=1
35
+ ```
36
+
@@ -16,16 +16,16 @@ def _check_download_and_extract_sdk():
16
16
  sdk_dir = os.path.join(agora_service_path, "agora_sdk")
17
17
  zip_path = os.path.join(agora_service_path, "agora_rtc_sdk.zip")
18
18
 
19
- url = "https://download.agora.io/sdk/release/agora_rtc_sdk_linux_v4.4_20240914_1538_336910.zip"
19
+ url = "https://download.agora.io/sdk/release/agora_rtc_sdk_linux_v4.4.30-20240928_160128-358664.zip"
20
20
  libagora_rtc_sdk_path = os.path.join(sdk_dir, "libagora_rtc_sdk.so")
21
21
  if sys.platform == 'darwin':
22
- url = "https://download.agora.io/sdk/release/agora_rtc_sdk_mac_v4.4_20240914_1538_336910.zip"
22
+ url = "https://download.agora.io/sdk/release/agora_sdk_mac_v4.4.30_22119_FULL_20240928_1647_358680.zip"
23
23
  libagora_rtc_sdk_path = os.path.join(sdk_dir, "libAgoraRtcKit.dylib")
24
24
 
25
25
  if os.path.exists(libagora_rtc_sdk_path):
26
26
  return
27
27
 
28
- logger.error("agora sdk was broken!!! now download it, please wait for a while...")
28
+ logger.error("missing agora sdk, now download it, please wait for a while...")
29
29
  if os.path.exists(sdk_dir):
30
30
  os.system(f"rm -rf {sdk_dir}")
31
31
  os.makedirs(agora_service_path, exist_ok=True)
@@ -16,7 +16,12 @@ class AudioFrameInner(ctypes.Structure):
16
16
  ("samples_per_sec", ctypes.c_int),
17
17
  ("buffer", ctypes.c_void_p),
18
18
  ("render_time_ms", ctypes.c_int64),
19
- ("avsync_type", ctypes.c_int)
19
+ ("avsync_type", ctypes.c_int),
20
+ ("far_field_flag", ctypes.c_int),
21
+ ("rms", ctypes.c_int),
22
+ ("voice_prob", ctypes.c_int),
23
+ ("music_prob", ctypes.c_int),
24
+ ("pitch", ctypes.c_int)
20
25
  ]
21
26
  def _to_audio_frame(self):
22
27
  audio_frame = AudioFrame()
@@ -29,6 +34,12 @@ class AudioFrameInner(ctypes.Structure):
29
34
  audio_frame.buffer = bytearray(cdata)
30
35
  audio_frame.render_time_ms = self.render_time_ms
31
36
  audio_frame.avsync_type = self.avsync_type
37
+ audio_frame.far_field_flag = self.far_field_flag
38
+ audio_frame.rms = self.rms
39
+ audio_frame.voice_prob = self.voice_prob
40
+ audio_frame.music_prob = self.music_prob
41
+ audio_frame.pitch = self.pitch
42
+
32
43
  return audio_frame
33
44
 
34
45
 
@@ -99,7 +110,7 @@ class AudioFrameObserverInner(ctypes.Structure):
99
110
  return ret
100
111
 
101
112
  def _on_playback_audio_frame_before_mixing(self, local_user_handle, channel_id, user_id, audio_frame_inner):
102
- logger.debug(f"AudioFrameObserverInner _on_playback_audio_frame_before_mixing: {local_user_handle}, {channel_id}, {user_id}, {audio_frame_inner}")
113
+ #logger.debug(f"AudioFrameObserverInner _on_playback_audio_frame_before_mixing: {local_user_handle}, {channel_id}, {user_id}, {audio_frame_inner}")
103
114
  if channel_id is None:
104
115
  channel_id_str = ""
105
116
  else:
@@ -112,46 +123,21 @@ class AudioFrameObserverInner(ctypes.Structure):
112
123
 
113
124
  def _on_get_audio_frame_position(self, local_user_handle):
114
125
  logger.debug(f"AudioFrameObserverInner _on_get_audio_frame_position: {local_user_handle}")
115
- return 0
116
126
  return self.observer.on_get_audio_frame_position(self.local_user)
117
127
 
118
- def _on_get_playback_audio_frame_param(self, local_user_handle):
128
+ def _on_get_playback_audio_frame_param(self, local_user_handle) -> AudioParams:
119
129
  logger.debug(f"AudioFrameObserverInner _on_get_playback_audio_frame_param: {local_user_handle}")
120
- params = AudioParams()
121
- params.sample_rate = 16000 # 示例值
122
- params.channels = 1 # 示例值
123
- params.mode = 0 # 示例值
124
- params.samples_per_call = 1024 # 示例值
125
- return params
126
130
  return self.observer.on_get_playback_audio_frame_param(self.local_user)
127
131
 
128
- def _on_get_record_audio_frame_param(self, local_user_handle):
132
+ def _on_get_record_audio_frame_param(self, local_user_handle) -> AudioParams:
129
133
  logger.debug(f"AudioFrameObserverInner _on_get_record_audio_frame_param: {local_user_handle}")
130
- params = AudioParams()
131
- params.sample_rate = 16000 # 示例值
132
- params.channels = 1 # 示例值
133
- params.mode = 0 # 示例值
134
- params.samples_per_call = 1024 # 示例值
135
- return params
136
134
  return self.observer.on_get_record_audio_frame_param(self.local_user)
137
135
 
138
- def _on_get_mixed_audio_frame_param(self, local_user_handle):
136
+ def _on_get_mixed_audio_frame_param(self, local_user_handle) -> AudioParams:
139
137
  logger.debug(f"AudioFrameObserverInner _on_get_mixed_audio_frame_param: {local_user_handle}")
140
- params = AudioParams()
141
- params.sample_rate = 16000 # 示例值
142
- params.channels = 1 # 示例值
143
- params.mode = 0 # 示例值
144
- params.samples_per_call = 1024 # 示例值
145
- return params
146
138
  return self.observer.on_get_mixed_audio_frame_param(self.local_user)
147
139
 
148
- def _on_get_ear_monitoring_audio_frame_param(self, local_user_handle):
140
+ def _on_get_ear_monitoring_audio_frame_param(self, local_user_handle) -> AudioParams:
149
141
  logger.debug(f"AudioFrameObserverInner _on_get_ear_monitoring_audio_frame_param: {local_user_handle}")
150
- params = AudioParams()
151
- params.sample_rate = 16000 # 示例值
152
- params.channels = 1 # 示例值
153
- params.mode = 0 # 示例值
154
- params.samples_per_call = 1024 # 示例值
155
- return params
156
142
  return self.observer.on_get_ear_monitoring_audio_frame_param(self.local_user)
157
143
 
@@ -6,14 +6,6 @@ from .remote_video_track import RemoteVideoTrack, RemoteVideoTrackStats
6
6
  import logging
7
7
  logger = logging.getLogger(__name__)
8
8
 
9
-
10
- uid_t = ctypes.c_uint
11
- track_id_t = ctypes.c_uint
12
-
13
- #========localuser observer=====
14
-
15
-
16
-
17
9
  class VideoTrackInfoInner(ctypes.Structure):
18
10
  _fields_ = [
19
11
  ("is_local", ctypes.c_int),
@@ -56,7 +48,6 @@ class RemoteVideoStreamInfo(ctypes.Structure):
56
48
  ("total_downscale_level_counts", ctypes.c_uint8)
57
49
  ]
58
50
 
59
- # 定义回调函数类型
60
51
  ON_AUDIO_TRACK_PUBLISH_SUCCESS_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, AGORA_HANDLE)
61
52
  ON_AUDIO_TRACK_PUBLISH_START_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, AGORA_HANDLE)
62
53
  ON_AUDIO_TRACK_UNPUBLISHED_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, AGORA_HANDLE)
@@ -95,31 +86,6 @@ ON_REMOTE_SUBSCRIBE_FALLBACK_TO_AUDIO_ONLY_CALLBACK = ctypes.CFUNCTYPE(None, AGO
95
86
  ON_STREAM_MESSAGE_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, user_id_t, ctypes.c_int, ctypes.c_char_p, ctypes.c_size_t)
96
87
  ON_USER_STATE_CHANGED_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, user_id_t, ctypes.c_uint32)
97
88
 
98
-
99
- """
100
- on_user_info_updated(user_id_t: string ; msg: int, val: int)
101
- msg:
102
- enum USER_MEDIA_INFO {
103
- /**
104
- * 0: The user has muted the audio.
105
- */
106
- USER_MEDIA_INFO_MUTE_AUDIO = 0,
107
- /**
108
- * 1: The user has muted the video.
109
- */
110
- USER_MEDIA_INFO_MUTE_VIDEO = 1,
111
- /**
112
- * 4: The user has enabled the video, which includes video capturing and encoding.
113
- */
114
- USER_MEDIA_INFO_ENABLE_VIDEO = 4,
115
- /**
116
- * 8: The user has enabled the local video capturing.
117
- */
118
- USER_MEDIA_INFO_ENABLE_LOCAL_VIDEO = 8,
119
- };
120
- val: 1: The user has muted the audio.0: unmuted the audio
121
- 参考:https://doc.shengwang.cn/api-ref/rtc-server-sdk/cpp/classagora_1_1rtc_1_1_i_local_user_observer#onUserInfoUpdated()
122
- """
123
89
  class RTCLocalUserObserverInner(ctypes.Structure):
124
90
  _fields_ = [
125
91
  ("on_audio_track_publish_success", ON_AUDIO_TRACK_PUBLISH_SUCCESS_CALLBACK),
@@ -241,7 +207,6 @@ class RTCLocalUserObserverInner(ctypes.Structure):
241
207
  def _on_audio_track_publication_failure(self, local_user_handle, local_audio_track_handle, error_code):
242
208
  logger.debug(f"LocalUserCB _on_audio_track_publication_failure: {local_user_handle}, {local_audio_track_handle}, {error_code}")
243
209
  audio_track = self.local_user.get_audio_map(local_audio_track_handle)
244
- #note :move from map for failed publish
245
210
  self.local_user.del_audio_map(local_audio_track_handle)
246
211
  self.local_user_observer.on_audio_track_publication_failure(self.local_user, audio_track, error_code)
247
212
 
@@ -251,22 +216,9 @@ class RTCLocalUserObserverInner(ctypes.Structure):
251
216
  self.local_user_observer.on_local_audio_track_state_changed(self.local_user, audio_track, state, error)
252
217
 
253
218
  def _on_local_audio_track_statistics(self, local_user_handle, stats):
254
- #logger.debug("LocalUserCB _on_local_audio_track_statistics:", local_user_handle, stats)
255
- #stats: pointer to LocalAudioStats
256
219
  local_audio_stats = stats.contents
257
220
  self.local_user_observer.on_local_audio_track_statistics(self.local_user, local_audio_stats)
258
- #这个有点trick
259
- """
260
- # 在LocalUser中是通过LocalUser.sub_audio(uid) 创建的,所以这里直接用uid来获取对应的RemoteAudioTrack
261
- # 也就是说从app层的视角,对audio的区分是uid,但这边的回调并没有userid,所以对app层是不太友好的
262
- # 也就是需要在LocalUser层中建立一个map表,用来记录userid和handle
263
- # 然后在回调中,通过handle,找到uid,然后call 给app层的是uid
264
- # 这样的话,在LocalUser层,就可以直接通过uid来获取对应的RemoteAudioTrack
265
- """
266
- #
267
- # _on_user_audio_track_subscribed:in LocalUser to do sub(userid), and in this call back it pass out with
268
- # user_id & remote_audio_track_handle, so we should construct RemoteAudioTrack with (user_id & remote_audio_track_handle
269
- # and save it in local_user, then in app layer, we can get RemoteAudioTrack with userid)
221
+
270
222
  def _on_user_audio_track_subscribed(self, local_user_handle, user_id, remote_audio_track_handle):
271
223
  logger.debug(f"LocalUserCB _on_user_audio_track_subscribed: {local_user_handle}, {user_id}, {remote_audio_track_handle}")
272
224
  user_id_str = user_id.decode('utf-8') if user_id else ""
@@ -282,7 +234,6 @@ class RTCLocalUserObserverInner(ctypes.Structure):
282
234
  remote_audio_track = self.local_user.get_remote_audio_map(remote_audio_track_handle)
283
235
  self.local_user_observer.on_remote_audio_track_statistics(self.local_user, remote_audio_track, audio_stats)
284
236
 
285
-
286
237
  def _on_user_audio_track_state_changed(self, local_user_handle, user_id, remote_audio_track_handle, state, reason, elapsed):
287
238
  logger.debug(f"LocalUserCB _on_user_audio_track_state_changed: {local_user_handle}, {user_id}, {remote_audio_track_handle}, {state}, {reason}, {elapsed}")
288
239
  user_id_str = user_id.decode('utf-8') if user_id else ""
@@ -333,7 +284,6 @@ class RTCLocalUserObserverInner(ctypes.Structure):
333
284
  local_video_track = self.local_user.get_video_map(local_video_track_handle)
334
285
  video_stats = stats.contents
335
286
  self.local_user_observer.on_local_video_track_statistics(self.local_user, local_video_track, video_stats)
336
- # # #ctypes.CFUNCTYPE(None, AGORA_HANDLE, user_id_t, ctypes.POINTER(VideoTrackInfo), AGORA_HANDLE)
337
287
  def _on_user_video_track_subscribed(self, local_user_handle, user_id, video_track_info, remote_video_track_handle):
338
288
  logger.debug(f"LocalUserCB _on_user_video_track_subscribed: {local_user_handle}, {user_id}, {remote_video_track_handle}, {video_track_info}")
339
289
  user_id_str = user_id.decode('utf-8') if user_id else ""
@@ -3,7 +3,6 @@ import ctypes
3
3
  from .agora_base import *
4
4
  from .local_user import *
5
5
  from .globals import *
6
- # from .rtc_connection import *
7
6
  from .rtc_connection_observer import *
8
7
  import logging
9
8
  logger = logging.getLogger(__name__)
@@ -19,20 +18,12 @@ class RTCConnInfoInner(ctypes.Structure):
19
18
  def _convert_to_rtc_conn_info(self):
20
19
  from .rtc_connection import RTCConnInfo
21
20
  con_info = RTCConnInfo()
22
-
23
- # 直接访问字段
24
21
  con_info.id = self.id
25
22
  con_info.channel_id = self.channel_id.decode('utf-8') if self.channel_id else ''
26
23
  con_info.state = self.state
27
24
  con_info.local_user_id = self.local_user_id.decode('utf-8') if self.local_user_id else ''
28
25
  con_info.internal_uid = self.internal_uid
29
-
30
26
  return con_info
31
-
32
-
33
-
34
- uid_t = ctypes.c_uint
35
- track_id_t = ctypes.c_uint
36
27
 
37
28
  ON_CONNECTED_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, ctypes.POINTER(RTCConnInfoInner), ctypes.c_int)
38
29
  ON_DISCONNECTED_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, ctypes.POINTER(RTCConnInfoInner), ctypes.c_int)
@@ -144,32 +135,6 @@ class RTCConnectionObserverInner(ctypes.Structure):
144
135
  self.on_encryption_error = ON_ENCRYPTION_ERROR_CALLBACK(self._on_encryption_error)
145
136
  self.on_upload_log_result = ON_UPLOAD_LOG_RESULT_CALLBACK(self._on_upload_log_result)
146
137
 
147
-
148
- #agora_rtc_conn: handle of RTCConnection; conn_info_inner:pointer to RTCConnInfoInner
149
- #reason: int type
150
- #
151
- """
152
- parameter type desp:
153
- agora_rtc_conn: handle of RTCConnection;
154
- conn_info_inner:pointer to RTCConnInfoInner
155
- reason: int type
156
- quality:int type
157
-
158
- # note: sumary for ctypes.POINTER
159
- #note: conn_info_inner is a pointer to RTCConnInfoInner, so we should do like following to ensure
160
- # conn_info is a RTCConnInfo
161
- # we make sure: conn_info_inner is a pointer to RTCConnInfoInner from ctypes, so
162
- # no need to do type check like isinstance(xx),just use dereferencing method to get the contents
163
- if isinstance(conn_info_inner, ctypes.POINTER(RTCConnInfoInner)):
164
- conn_info = conn_info_inner.contents._convert_to_rtc_conn_info()
165
- else:
166
- conn_info = conn_info_inner._convert_to_rtc_conn_info()
167
-
168
- just use:
169
- conn_info = conn_info_inner.contents.()
170
-
171
- to
172
- """
173
138
  def _on_connected(self, agora_rtc_conn, conn_info_inner, reason):
174
139
  logger.debug(f"ConnCB _on_connected: {agora_rtc_conn}, {conn_info_inner}, {reason}")
175
140
  conn_info = conn_info_inner.contents._convert_to_rtc_conn_info()
@@ -204,16 +169,11 @@ class RTCConnectionObserverInner(ctypes.Structure):
204
169
  logger.debug(f"ConnCB _on_lastmile_quality: {agora_rtc_conn}, {quality}")
205
170
  self.conn_observer.on_lastmile_quality(self.conn, quality)
206
171
 
207
- #last_mile_prob_result_ptr: ctypes.POINTER(LastmileProbeResult)) type
208
172
  def _on_lastmile_probe_result(self, agora_rtc_conn, last_mile_prob_result_ptr):
209
173
  logger.debug(f"ConnCB _on_lastmile_probe_result: {agora_rtc_conn}, {last_mile_prob_result_ptr}")
210
- # result is a pointer to LastmileProbeResult
211
- # we should dereference the pointer to get the LastmileProbeResult, thus we can access its fields
212
- last_mile_result = last_mile_prob_result_ptr.contents
213
-
174
+ last_mile_result = last_mile_prob_result_ptr.contents
214
175
  self.conn_observer.on_lastmile_probe_result(self.conn, last_mile_result)
215
176
 
216
- #token: ctypes.char_p
217
177
  def _on_token_privilege_will_expire(self, agora_rtc_conn, token):
218
178
  logger.debug(f"ConnCB _on_token_privilege_will_expire: {agora_rtc_conn}, {token}")
219
179
  token_str = token.decode('utf-8') #decode will generate a new object
@@ -231,7 +191,7 @@ class RTCConnectionObserverInner(ctypes.Structure):
231
191
  logger.debug(f"ConnCB _on_connection_failure: {agora_rtc_conn}, {conn_info_inner}, {reason}")
232
192
  conn_info = conn_info_inner.contents._convert_to_rtc_conn_info()
233
193
  self.conn_observer.on_connection_failure(self.conn, conn_info, reason)
234
- #userid: ctyps.char_p
194
+
235
195
  def _on_user_joined(self, agora_rtc_conn, user_id):
236
196
  logger.debug(f"ConnCB _on_user_joined: {agora_rtc_conn}, {user_id}")
237
197
  userid_str = user_id.decode('utf-8')
@@ -241,21 +201,12 @@ class RTCConnectionObserverInner(ctypes.Structure):
241
201
  logger.debug(f"ConnCB _on_user_left: {agora_rtc_conn}, {user_id}, {reason}")
242
202
  userid_str = user_id.decode('utf-8')
243
203
  self.conn_observer.on_user_left(self.conn, userid_str, reason)
244
- #stats: ctypes.POINTER(RTCStats)
204
+
245
205
  def _on_transport_stats(self, agora_rtc_conn, stats):
246
206
  logger.debug(f"ConnCB _on_transport_stats: {agora_rtc_conn}, {stats}")
247
- #stats is a pointer to RTCStats
248
- #should dereference the pointer to get the RTCStats, thus we can access its fields
249
- rtc_stats = stats.contents
250
- """
251
- if isinstance(stats, ctypes.POINTER(RTCStats)):
252
- rtc_stats = stats.contents
253
- else:
254
- rtc_stats = stats
255
- """
256
-
207
+ rtc_stats = stats.contents
257
208
  self.conn_observer.on_transport_stats(self.conn, rtc_stats)
258
- #old_role/new_role: ctypes.int
209
+
259
210
  def _on_change_role_success(self, agora_rtc_conn, old_role, new_role):
260
211
  logger.debug(f"ConnCB _on_change_role_success: {agora_rtc_conn}, {old_role}, {new_role}")
261
212
  self.conn_observer.on_change_role_success(self.conn, old_role, new_role)
@@ -266,32 +217,25 @@ class RTCConnectionObserverInner(ctypes.Structure):
266
217
 
267
218
  def _on_user_network_quality(self, agora_rtc_conn, user_id, tx_quality, rx_quality):
268
219
  logger.debug(f"ConnCB _on_user_network_quality: {agora_rtc_conn}, {user_id}, {tx_quality}, {rx_quality}")
269
- #user_id: ctypes.char_p
270
- #tx_quality: ctypes.int
271
- #rx_quality: ctypes.int
272
220
  userid_str = user_id.decode('utf-8') if user_id else ""
273
221
  self.conn_observer.on_user_network_quality(self.conn, userid_str, tx_quality, rx_quality)
274
222
 
275
223
  def _on_network_type_changed(self, agora_rtc_conn, network_type):
276
224
  logger.debug(f"ConnCB _on_network_type_changed: {agora_rtc_conn}, {network_type}")
277
- #network_type: ctypes.int
278
225
  self.conn_observer.on_network_type_changed(self.conn, network_type)
279
226
 
280
227
  def _on_api_call_executed(self, agora_rtc_conn, error, api_type, api_params):
281
228
  logger.debug(f"ConnCB _on_api_call_executed: {agora_rtc_conn}, {error}, {api_type}, {api_params}")
282
- #error: ctypes.int; api_type: ctypes.char_p; api_params: ctypes.char_p
283
229
  _api_type_str = api_type.decode('utf-8') if api_type else ""
284
230
  _api_param_str = api_params.decode('utf-8') if api_params else ""
285
231
  self.conn_observer.on_api_call_executed(self.conn, error, _api_type_str, _api_param_str)
286
232
 
287
233
  def _on_content_inspect_result(self, agora_rtc_conn, result):
288
234
  logger.debug(f"ConnCB _on_content_inspect_result: {agora_rtc_conn}, {result}")
289
- #result: ctypes.int
290
235
  self.conn_observer.on_content_inspect_result(self.conn, result)
291
236
 
292
237
  def _on_snapshot_taken(self, agora_rtc_conn, channel, uid, filepath, width, height, errCode):
293
238
  logger.debug(f"ConnCB _on_snapshot_taken: {agora_rtc_conn}, {channel}, {uid}, {filepath}, {width}, {height}, {errCode}")
294
- #channel: ctypes.c_char_p; uid: ctypes.c_uint32; filepath: ctypes.c_char_p; width: ctypes.c_int32; height: ctypes.c_int32; errCode: ctypes.c_int32
295
239
  _channel_str = channel.decode('utf-8') if channel else ""
296
240
  _file_path_str = filepath.decode('utf-8') if filepath else ""
297
241
  self.conn_observer.on_snapshot_taken(self.conn, _channel_str, uid, _file_path_str, width, height, errCode)
@@ -330,7 +274,6 @@ class RTCConnectionObserverInner(ctypes.Structure):
330
274
  logger.debug(f"ConnCB _on_encryption_error: {agora_rtc_conn}, {error_type}")
331
275
  self.conn_observer.on_encryption_error(self.conn, error_type)
332
276
 
333
- #request_id: ctypes.c_char_p; success/reason: ctypes.int
334
277
  def _on_upload_log_result(self, agora_rtc_conn, request_id, success, reason):
335
278
  logger.debug(f"ConnCB _on_upload_log_result: {agora_rtc_conn}, {request_id}, {success}, {reason}")
336
279
  _request_id_str = request_id.decode("utf-8") if request_id else ""
@@ -6,12 +6,6 @@ from .video_encoded_frame_observer import IVideoEncodedFrameObserver, EncodedVid
6
6
  import logging
7
7
  logger = logging.getLogger(__name__)
8
8
 
9
- # typedef struct _video_encoded_frame_observer {
10
- # int (*on_encoded_video_frame)(AGORA_HANDLE agora_video_encoded_frame_observer, uid_t uid, const uint8_t* image_buffer, size_t length,
11
- # const encoded_video_frame_info* video_encoded_frame_info);
12
- # } video_encoded_frame_observer;
13
-
14
-
15
9
  class EncodedVideoFrameInfoInner(ctypes.Structure):
16
10
  _fields_ = [
17
11
  ("codec_type", ctypes.c_int),
@@ -52,6 +52,11 @@ class VideoFrameInner(ctypes.Structure):
52
52
 
53
53
  ON_FRAME_CALLBACK = ctypes.CFUNCTYPE(None, AGORA_HANDLE, ctypes.c_char_p, user_id_t, ctypes.POINTER(VideoFrameInner))
54
54
 
55
+ agora_video_frame_observer_get_rotation_applied = agora_lib.agora_video_frame_observer_get_rotation_applied
56
+ agora_video_frame_observer_get_rotation_applied.restype = ctypes.c_int
57
+ agora_video_frame_observer_get_rotation_applied.argtypes = [AGORA_HANDLE]
58
+
59
+
55
60
  class VideoFrameObserverInner(ctypes.Structure):
56
61
  _fields_ = [
57
62
  ("on_frame", ON_FRAME_CALLBACK)
@@ -65,29 +70,5 @@ class VideoFrameObserverInner(ctypes.Structure):
65
70
 
66
71
  def _on_frame(self, agora_handle, channel_id, user_id, video_frame:VideoFrameInner):
67
72
  vf = video_frame.contents
68
- # logger.debug("VideoFrameObserver _on_frame:", agora_handle, channel_id, user_id, vf.metadata_buffer, vf.metadata_size)
69
73
  self.video_frame_observer.on_frame(agora_handle, channel_id.decode() if channel_id else None, user_id.decode(), vf.to_video_frame())
70
-
71
-
72
-
73
-
74
-
75
-
76
- # ON_ENCODED_VIDEO_IMAGE_RECEIVED_CALLBACK = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint32, ctypes.POINTER(encoded_video_frame_info))
77
-
78
- # class VideoEncodedImageReceiverInner(ctypes.Structure):
79
- # _fields_ = [
80
- # ("on_encoded_video_image_received", ON_ENCODED_VIDEO_IMAGE_RECEIVED_CALLBACK)
81
- # ]
82
-
83
- # def __init__(self, video_encoded_image_receiver:'IVideoEncodedImageReceiver'):
84
- # self.video_encoded_image_receiver = video_encoded_image_receiver
85
- # self.on_encoded_video_image_received = ON_ENCODED_VIDEO_IMAGE_RECEIVED_CALLBACK(self._on_encoded_video_image_received)
86
-
87
-
88
- # def _on_encoded_video_image_received(self, agora_handle, image_buffer, length, info):
89
- # logger.debug("VideoFrameObserver _on_frame:", agora_handle, image_buffer, length, info)
90
- # # self.on_encoded_video_image_received(agora_handle, image_buffer, length, info)
91
- # self.video_encoded_image_receiver.on_encoded_video_image_received(agora_handle, image_buffer, length, info)
92
-
93
-
74
+
@@ -294,6 +294,11 @@ class AudioFrame:
294
294
  self.buffer = None
295
295
  self.render_time_ms = 0
296
296
  self.avsync_type = 0
297
+ self.far_field_flag = 0
298
+ self.rms = 0
299
+ self.voice_prob = 0
300
+ self.music_prob = 0
301
+ self.pitch = 0
297
302
 
298
303
  class AudioParams(ctypes.Structure):
299
304
  _fields_ = [
@@ -123,6 +123,11 @@ agora_service_create_custom_video_track_frame = agora_lib.agora_service_create_c
123
123
  agora_service_create_custom_video_track_frame.restype = AGORA_HANDLE
124
124
  agora_service_create_custom_video_track_frame.argtypes = [AGORA_HANDLE, AGORA_HANDLE]
125
125
 
126
+ agora_service_enable_extension = agora_lib.agora_service_enable_extension
127
+ agora_service_enable_extension.restype = AGORA_API_C_INT
128
+ agora_service_enable_extension.argtypes = [AGORA_HANDLE, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint]
129
+
130
+
126
131
  class SenderOptions(ctypes.Structure):
127
132
  _fields_ = [
128
133
  ("cc_mode", ctypes.c_int),
@@ -142,6 +147,8 @@ agora_service_create_custom_video_track_encoded.argtypes = [AGORA_HANDLE, AGORA_
142
147
  class AgoraService:
143
148
  def __init__(self) -> None:
144
149
  self.service_handle = agora_service_create()
150
+
151
+ # set tag???
145
152
  self.inited = False
146
153
 
147
154
  def initialize(self, config: AgoraServiceConfig):
@@ -153,6 +160,15 @@ class AgoraService:
153
160
  self.inited = True
154
161
  logger.debug(f'Initialization result: {result}')
155
162
 
163
+ # to enable plugin
164
+ provider = "agora.builtin"
165
+ generator = "agora_audio_label_generator"
166
+ cprovider = provider.encode('utf-8')
167
+ cgenerator = generator.encode('utf-8')
168
+ ctrak = ctypes.c_char_p(None)
169
+ #agora_service_enable_extension(self.service_handle, "agora.builtin", "agora_audio_label_generator", None, 1)
170
+ agora_service_enable_extension(self.service_handle, cprovider, cgenerator, ctrak, 1)
171
+
156
172
  if config.log_path:
157
173
  log_size = 512 * 1024
158
174
  if config.log_size > 0:
@@ -172,7 +188,7 @@ class AgoraService:
172
188
  self.inited = False
173
189
  self.service_handle = None
174
190
 
175
- #createMediaNodeFactory 创建一个媒体节点工厂对象。
191
+ #createMediaNodeFactory: to create a medianode factory object
176
192
  def create_media_node_factory(self):
177
193
  if not self.inited:
178
194
  logger.error("AgoraService is not initialized. Please call initialize() first.")
@@ -193,8 +209,8 @@ class AgoraService:
193
209
  return RTCConnection(rtc_conn_handle)
194
210
 
195
211
 
196
- #createCustomAudioTrackPcm 创建一个自定义音频Track。
197
- def create_custom_audio_track_pcm(self, audio_pcm_data_sender:AudioPcmDataSender):
212
+ #createCustomAudioTrackPcm: creatae a custom audio track from pcm data sender
213
+ def create_custom_audio_track_pcm(self, audio_pcm_data_sender:AudioPcmDataSender) -> LocalAudioTrack | None:
198
214
  if not self.inited:
199
215
  logger.error("AgoraService is not initialized. Please call initialize() first.")
200
216
  return None
@@ -6,9 +6,6 @@ logger = logging.getLogger(__name__)
6
6
  class EncodedAudioFrame:
7
7
  def __init__(
8
8
  self,
9
- # data: bytearray = None,
10
- # buffer_ptr: int = 0,
11
- # buffer_size: int = 0,
12
9
  capture_timems: int = 0,
13
10
  codec: AudioCodecType = AudioCodecType.AUDIO_CODEC_AACLC,
14
11
  number_of_channels: int = 1,
@@ -17,18 +14,13 @@ class EncodedAudioFrame:
17
14
  send_even_if_empty: int = 1,
18
15
  speech: int = 1
19
16
  )->None:
20
- # self.data = data
21
- # self.buffer_ptr = buffer_ptr
22
- # self.buffer_size = buffer_size
23
- self.capture_timems = capture_timems #int64, 音频帧的 Unix 时间戳(毫秒)
24
- #int, 音频帧的编码格式; ref: https://doc.shengwang.cn/api-ref/rtc-server-sdk/cpp/namespaceagora_1_1rtc#ac211c1a503d38d504c92b5f006240053
17
+ self.capture_timems = capture_timems
25
18
  self.codec = codec
26
19
  self.number_of_channels = number_of_channels
27
20
  self.sample_rate = sample_rate
28
- #int, 对于 aac 编码格式,默认为 1024;对于 Opus 编码格式,默认为 960
29
21
  self.samples_per_channel = samples_per_channel
30
- self.send_even_if_empty = send_even_if_empty #bool value, 是否发送空音频帧,default TRUE
31
- self.speech = speech #bool, 是否是语音,default TRUE
22
+ self.send_even_if_empty = send_even_if_empty
23
+ self.speech = speech
32
24
 
33
25
  def to_owned_encoded_audio_frame(self):
34
26
  info = OwnedEncodedAudioFrameInfo()
@@ -75,19 +67,10 @@ class AudioEncodedFrameSender:
75
67
  # c_date = (ctypes.c_char * len(frame.data)).from_buffer(frame.data)
76
68
  # ownedinfo = frame.to_owned_encoded_audio_frame()
77
69
  # ret = agora_audio_encoded_frame_sender_send(self.sender_handle, c_date, ctypes.c_uint32(len(frame.data)), ctypes.byref(ownedinfo))
78
- # if ret < 0:
79
- # logger.error(f"Failed to send encoded audio frame with error code: {ret}")
80
70
  # return ret
81
71
 
82
72
  def send_encoded_audio_frame(self, buffer_ptr:int, buffer_size:int, frame:EncodedAudioFrame):
83
73
  buffer_ptr = ctypes.cast(buffer_ptr, ctypes.POINTER(ctypes.c_void_p))
84
74
  ownedinfo = frame.to_owned_encoded_audio_frame()
85
75
  ret = agora_audio_encoded_frame_sender_send(self.sender_handle, buffer_ptr, ctypes.c_uint32(buffer_size), ctypes.byref(ownedinfo))
86
- if ret < 0:
87
- logger.error(f"Failed to send encoded audio frame with error code: {ret}")
88
76
  return ret
89
-
90
-
91
- def release(self):
92
- # agora_local_audio_track_destroy(self.sender_handle)
93
- pass
@@ -0,0 +1,32 @@
1
+ from .agora_base import AudioFrame, AudioParams
2
+
3
+ class IAudioFrameObserver:
4
+ def on_record_audio_frame(self, agora_local_user, channelId, frame):
5
+ return 1
6
+
7
+ def on_playback_audio_frame(self, agora_local_user, channelId, frame):
8
+ return 1
9
+
10
+ def on_mixed_audio_frame(self, agora_local_user, channelId, frame):
11
+ return 1
12
+
13
+ def on_ear_monitoring_audio_frame(self, agora_local_user, frame):
14
+ return 1
15
+
16
+ def on_playback_audio_frame_before_mixing(self, agora_local_user, channelId, uid, frame:AudioFrame):
17
+ return 1
18
+
19
+ def on_get_audio_frame_position(self, agora_local_user):
20
+ return 1
21
+
22
+ def on_get_playback_audio_frame_param(self, agora_local_user) -> AudioParams:
23
+ pass
24
+
25
+ def on_get_record_audio_frame_param(self, agora_local_user) -> AudioParams:
26
+ pass
27
+
28
+ def on_get_mixed_audio_frame_param(self, agora_local_user) -> AudioParams:
29
+ pass
30
+
31
+ def on_get_ear_monitoring_audio_frame_param(self, agora_local_user) -> AudioParams:
32
+ pass