sora-sdk 2025.4.0.dev6__tar.gz → 2025.5.0.dev1__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 sora-sdk might be problematic. Click here for more details.

Files changed (47) hide show
  1. {sora_sdk-2025.4.0.dev6/src/sora_sdk.egg-info → sora_sdk-2025.5.0.dev1}/PKG-INFO +32 -6
  2. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/README.md +31 -5
  3. sora_sdk-2025.5.0.dev1/VERSION +1 -0
  4. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/buildbase.py +188 -66
  5. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/pyproject.toml +6 -12
  6. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/run.py +46 -8
  7. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/setup.py +7 -1
  8. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk/sora_sdk_ext.cpython-311-darwin.so +0 -0
  9. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk/sora_sdk_ext.pyi +5 -1
  10. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1/src/sora_sdk.egg-info}/PKG-INFO +32 -6
  11. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk.egg-info/SOURCES.txt +1 -1
  12. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_intel_vpl.py +3 -3
  13. sora_sdk-2025.4.0.dev6/tests/test_nvidia_video_codec_sdk.py → sora_sdk-2025.5.0.dev1/tests/test_nvidia_video_codec.py +1 -1
  14. sora_sdk-2025.4.0.dev6/VERSION +0 -1
  15. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/LICENSE +0 -0
  16. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/MANIFEST.in +0 -0
  17. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/pypath.py +0 -0
  18. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/setup.cfg +0 -0
  19. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk/__init__.py +0 -0
  20. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk/py.typed +0 -0
  21. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk.egg-info/dependency_links.txt +0 -0
  22. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/src/sora_sdk.egg-info/top_level.txt +0 -0
  23. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_amd_amf.py +0 -0
  24. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_apple_video_toolbox.py +0 -0
  25. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_authz.py +0 -0
  26. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_authz_simulcast.py +0 -0
  27. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_ca_cert.py +0 -0
  28. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_capability.py +0 -0
  29. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_degradation_preference.py +0 -0
  30. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_encoded_transform.py +0 -0
  31. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_key_frame_request.py +0 -0
  32. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_messaging.py +0 -0
  33. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_messaging_header.py +0 -0
  34. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_openh264.py +0 -0
  35. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_openh264_simulcast.py +0 -0
  36. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_opus.py +0 -0
  37. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_re_offer_re_answer_sdp.py +0 -0
  38. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_sendonly_recvonly.py +0 -0
  39. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_signaling.py +0 -0
  40. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_signaling_message.py +0 -0
  41. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_signaling_notify.py +0 -0
  42. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_simulcast.py +0 -0
  43. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_sora_disconnect.py +0 -0
  44. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_type_disconnect.py +0 -0
  45. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_type_switched.py +0 -0
  46. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_vad.py +0 -0
  47. {sora_sdk-2025.4.0.dev6 → sora_sdk-2025.5.0.dev1}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sora_sdk
3
- Version: 2025.4.0.dev6
3
+ Version: 2025.5.0.dev1
4
4
  Summary: WebRTC SFU Sora Python SDK
5
5
  Home-page: https://github.com/shiguredo/sora-python-sdk
6
6
  Author-email: "Shiguredo Inc." <contact+pypi@shiguredo.jp>
@@ -47,13 +47,13 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
47
47
 
48
48
  - [Sora C++ SDK](https://github.com/shiguredo/sora-cpp-sdk) ベース
49
49
  - WebRTC 部分の機能は [libwebrtc](https://webrtc.googlesource.com/src/) を採用
50
- - Windows / macOS / Linux (Ubuntu) プラットフォームに対応
50
+ - Windows / macOS / Linux (Ubuntu / Raspberry Pi OS) プラットフォームに対応
51
51
  - [WebRTC 統計情報](https://www.w3.org/TR/webrtc-stats/) の取得が可能
52
52
  - [WebRTC Encoded Transform](https://www.w3.org/TR/webrtc-encoded-transform/) に対応
53
53
  - 回線が不安定になった際、解像度とフレームレートどちらを維持するかの設定をする [DegradationPreference](https://w3c.github.io/mst-content-hint/#degradation-preference-when-encoding) に対応
54
54
  - MAINTAIN_FRAMERATE / MAINTAIN_RESOLUTION / BALANCED が指定できる
55
55
  - 発話区間の検出が可能な VAD (Voice Activity Detection) に対応
56
- - Intel / Apple / NVIDIA のハードウェアデコーダー/エンコーダーに対応
56
+ - Intel / Apple / NVIDIA / Raspberry Pi のハードウェアデコーダー/エンコーダーに対応
57
57
  - Apple Video Toolbox (H.264 / H.265)
58
58
  - macOS arm64 で利用できる
59
59
  - Intel VPL (AV1 / H.264 / H.265)
@@ -62,10 +62,13 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
62
62
  - Ubuntu x86_64 / Windows x86_64 で利用できる
63
63
  - AV1 エンコードは Windows x86_64 でのみ利用できる
64
64
  - VP9 はデコードのみ利用できる
65
- - NVIDIA Video Codec SDK (VP8 / VP9 / AV1 / H.264 / H.265)
65
+ - NVIDIA Video Codec (VP8 / VP9 / AV1 / H.264 / H.265)
66
66
  - Ubuntu x86_64 / Windows x86_64 で利用できる
67
67
  - VP8 と VP9 はデコードのみ利用できる
68
68
  - NVIDIA Jetson JetPack SDK (AV1 / H.264 / H.265)
69
+ - Raspberry Pi (H.264)
70
+ - Raspberry Pi 4 / Raspberry Pi 3 / Raspberry Pi 2 Model B v1.2 / Raspberry Pi Zero 2 W で利用できる
71
+ - V4L2-M2M API を利用している
69
72
  - [各プラットフォームで利用可能な HWA への対応](https://github.com/shiguredo/sora-cpp-sdk?tab=readme-ov-file#%E7%89%B9%E5%BE%B4)
70
73
  - [OpenH264](https://github.com/cisco/openh264) を利用した H.264 のソフトウェアエンコーダー/デコーダーに対応
71
74
  - Ubuntu x86_64 / Ubuntu arm64 / Windows x86_64 / macOS arm64 で利用できる
@@ -73,7 +76,9 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
73
76
  - 映像デバイス処理に [opencv-python](https://pypi.org/project/opencv-python/) などが利用できる
74
77
  - 音声認識などの入力に受信した音声を利用できる
75
78
  - 物体検出などの入力に受信した映像を利用できる
76
- - `uv add sora_sdk` や `pip install sora_sdk` でインストール可能
79
+ - `uv add sora_sdk` や `pip install sora_sdk` でインストールできる
80
+ - Raspberry Pi 向けのパッケージも `uv add sora_sdk_rpi` でインストールできる
81
+ - Raspberry Pi 向けに libcamera 用の `create_libcamera_source` を提供
77
82
  - [NVIDIA Jetson JetPack SDK](https://developer.nvidia.com/embedded/jetpack) に対応
78
83
 
79
84
  ## 利用イメージ
@@ -99,6 +104,12 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
99
104
  uv add sora_sdk
100
105
  ```
101
106
 
107
+ ### Raspberry Pi OS 向けパッケージ
108
+
109
+ ```bash
110
+ uv add sora_sdk_rpi
111
+ ```
112
+
102
113
  ### NVIDIA Jetson 向けパッケージ
103
114
 
104
115
  PyPI 経由ではインストールできません。
@@ -125,8 +136,23 @@ PyPI 経由ではインストールできません。
125
136
  - macOS Ventura 14 arm64
126
137
  - Windows 11 x86_64
127
138
  - Windows Server 2025 x86_64
139
+ - Raspberry Pi OS armv8
140
+
141
+ ### Raspberry Pi OS 向け
142
+
143
+ - Raspberry Pi OS bookworm (64bit)
144
+ - Raspberry Pi 5
145
+ - Raspberry Pi 4
146
+ - Raspberry Pi 3
147
+ - Raspberry Pi 2 Model B v1.2
148
+ - Raspberry Pi Zero 2 W
149
+
150
+ > [!CAUTION]
151
+ >
152
+ > - Raspberry Pi 5 は H.264 ハードウェアエンコーダーが搭載されていません
153
+ > - Raspberry Pi 5 の H.265 ハードウェアデコーダーに対応していません
128
154
 
129
- ### Jetson 向け
155
+ ### NVIDIA Jetson 向け
130
156
 
131
157
  - Ubuntu 22.04 LTS arm64 (NVIDIA Jetson JetPack SDK 6)
132
158
  - PyPI からではなくパッケージファイルを利用してください
@@ -27,13 +27,13 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
27
27
 
28
28
  - [Sora C++ SDK](https://github.com/shiguredo/sora-cpp-sdk) ベース
29
29
  - WebRTC 部分の機能は [libwebrtc](https://webrtc.googlesource.com/src/) を採用
30
- - Windows / macOS / Linux (Ubuntu) プラットフォームに対応
30
+ - Windows / macOS / Linux (Ubuntu / Raspberry Pi OS) プラットフォームに対応
31
31
  - [WebRTC 統計情報](https://www.w3.org/TR/webrtc-stats/) の取得が可能
32
32
  - [WebRTC Encoded Transform](https://www.w3.org/TR/webrtc-encoded-transform/) に対応
33
33
  - 回線が不安定になった際、解像度とフレームレートどちらを維持するかの設定をする [DegradationPreference](https://w3c.github.io/mst-content-hint/#degradation-preference-when-encoding) に対応
34
34
  - MAINTAIN_FRAMERATE / MAINTAIN_RESOLUTION / BALANCED が指定できる
35
35
  - 発話区間の検出が可能な VAD (Voice Activity Detection) に対応
36
- - Intel / Apple / NVIDIA のハードウェアデコーダー/エンコーダーに対応
36
+ - Intel / Apple / NVIDIA / Raspberry Pi のハードウェアデコーダー/エンコーダーに対応
37
37
  - Apple Video Toolbox (H.264 / H.265)
38
38
  - macOS arm64 で利用できる
39
39
  - Intel VPL (AV1 / H.264 / H.265)
@@ -42,10 +42,13 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
42
42
  - Ubuntu x86_64 / Windows x86_64 で利用できる
43
43
  - AV1 エンコードは Windows x86_64 でのみ利用できる
44
44
  - VP9 はデコードのみ利用できる
45
- - NVIDIA Video Codec SDK (VP8 / VP9 / AV1 / H.264 / H.265)
45
+ - NVIDIA Video Codec (VP8 / VP9 / AV1 / H.264 / H.265)
46
46
  - Ubuntu x86_64 / Windows x86_64 で利用できる
47
47
  - VP8 と VP9 はデコードのみ利用できる
48
48
  - NVIDIA Jetson JetPack SDK (AV1 / H.264 / H.265)
49
+ - Raspberry Pi (H.264)
50
+ - Raspberry Pi 4 / Raspberry Pi 3 / Raspberry Pi 2 Model B v1.2 / Raspberry Pi Zero 2 W で利用できる
51
+ - V4L2-M2M API を利用している
49
52
  - [各プラットフォームで利用可能な HWA への対応](https://github.com/shiguredo/sora-cpp-sdk?tab=readme-ov-file#%E7%89%B9%E5%BE%B4)
50
53
  - [OpenH264](https://github.com/cisco/openh264) を利用した H.264 のソフトウェアエンコーダー/デコーダーに対応
51
54
  - Ubuntu x86_64 / Ubuntu arm64 / Windows x86_64 / macOS arm64 で利用できる
@@ -53,7 +56,9 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
53
56
  - 映像デバイス処理に [opencv-python](https://pypi.org/project/opencv-python/) などが利用できる
54
57
  - 音声認識などの入力に受信した音声を利用できる
55
58
  - 物体検出などの入力に受信した映像を利用できる
56
- - `uv add sora_sdk` や `pip install sora_sdk` でインストール可能
59
+ - `uv add sora_sdk` や `pip install sora_sdk` でインストールできる
60
+ - Raspberry Pi 向けのパッケージも `uv add sora_sdk_rpi` でインストールできる
61
+ - Raspberry Pi 向けに libcamera 用の `create_libcamera_source` を提供
57
62
  - [NVIDIA Jetson JetPack SDK](https://developer.nvidia.com/embedded/jetpack) に対応
58
63
 
59
64
  ## 利用イメージ
@@ -79,6 +84,12 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
79
84
  uv add sora_sdk
80
85
  ```
81
86
 
87
+ ### Raspberry Pi OS 向けパッケージ
88
+
89
+ ```bash
90
+ uv add sora_sdk_rpi
91
+ ```
92
+
82
93
  ### NVIDIA Jetson 向けパッケージ
83
94
 
84
95
  PyPI 経由ではインストールできません。
@@ -105,8 +116,23 @@ PyPI 経由ではインストールできません。
105
116
  - macOS Ventura 14 arm64
106
117
  - Windows 11 x86_64
107
118
  - Windows Server 2025 x86_64
119
+ - Raspberry Pi OS armv8
120
+
121
+ ### Raspberry Pi OS 向け
122
+
123
+ - Raspberry Pi OS bookworm (64bit)
124
+ - Raspberry Pi 5
125
+ - Raspberry Pi 4
126
+ - Raspberry Pi 3
127
+ - Raspberry Pi 2 Model B v1.2
128
+ - Raspberry Pi Zero 2 W
129
+
130
+ > [!CAUTION]
131
+ >
132
+ > - Raspberry Pi 5 は H.264 ハードウェアエンコーダーが搭載されていません
133
+ > - Raspberry Pi 5 の H.265 ハードウェアデコーダーに対応していません
108
134
 
109
- ### Jetson 向け
135
+ ### NVIDIA Jetson 向け
110
136
 
111
137
  - Ubuntu 22.04 LTS arm64 (NVIDIA Jetson JetPack SDK 6)
112
138
  - PyPI からではなくパッケージファイルを利用してください
@@ -0,0 +1 @@
1
+ 2025.5.0.dev1
@@ -25,6 +25,7 @@
25
25
  # limitations under the License.
26
26
  import filecmp
27
27
  import glob
28
+ import hashlib
28
29
  import logging
29
30
  import multiprocessing
30
31
  import os
@@ -143,7 +144,12 @@ def add_path(path: str, is_after=False):
143
144
  os.environ["PATH"] = path + PATH_SEPARATOR + os.environ["PATH"]
144
145
 
145
146
 
146
- def download(url: str, output_dir: Optional[str] = None, filename: Optional[str] = None) -> str:
147
+ def download(
148
+ url: str,
149
+ output_dir: Optional[str] = None,
150
+ filename: Optional[str] = None,
151
+ expected_sha256: Optional[str] = None,
152
+ ) -> str:
147
153
  if filename is None:
148
154
  output_path = urllib.parse.urlparse(url).path.split("/")[-1]
149
155
  else:
@@ -153,22 +159,67 @@ def download(url: str, output_dir: Optional[str] = None, filename: Optional[str]
153
159
  output_path = os.path.join(output_dir, output_path)
154
160
 
155
161
  if os.path.exists(output_path):
156
- return output_path
162
+ # ファイルが既に存在する場合でもハッシュチェックを行う
163
+ if expected_sha256 is not None:
164
+ try:
165
+ verify_sha256(output_path, expected_sha256)
166
+ except ValueError:
167
+ # ハッシュ不一致の場合はファイルを削除して再ダウンロードを試みる
168
+ logging.warning(f"Existing file has invalid hash, removing: {output_path}")
169
+ os.remove(output_path)
170
+ # 再ダウンロードを試みる
171
+ return download(url, output_dir, filename, expected_sha256)
172
+ else:
173
+ return output_path
157
174
 
158
175
  try:
176
+ logging.info(f"Downloading {url} to {output_path}")
159
177
  if shutil.which("curl") is not None:
160
178
  cmd(["curl", "-fLo", output_path, url])
161
179
  else:
162
180
  cmd(["wget", "-cO", output_path, url])
181
+
182
+ # ダウンロード後にハッシュチェック
183
+ if expected_sha256 is not None:
184
+ try:
185
+ verify_sha256(output_path, expected_sha256)
186
+ except ValueError as e:
187
+ logging.error(f"Hash verification failed. {e}")
188
+ raise
189
+
163
190
  except Exception:
164
191
  # ゴミを残さないようにする
165
192
  if os.path.exists(output_path):
193
+ logging.error(f"Removing incomplete/invalid file: {output_path}")
166
194
  os.remove(output_path)
167
195
  raise
168
196
 
169
197
  return output_path
170
198
 
171
199
 
200
+ def verify_sha256(file_path: str, expected_sha256: str):
201
+ """ファイルの SHA256 ハッシュを検証する"""
202
+ logging.info(f"Verifying SHA256 hash for {file_path}")
203
+ sha256_hash = hashlib.sha256()
204
+ with open(file_path, "rb") as f:
205
+ # メモリ効率のため、チャンクごとに読み込む
206
+ for byte_block in iter(lambda: f.read(4096), b""):
207
+ sha256_hash.update(byte_block)
208
+
209
+ actual_sha256 = sha256_hash.hexdigest()
210
+ if actual_sha256 != expected_sha256.lower():
211
+ error_msg = (
212
+ f"SHA256 hash mismatch for {file_path}:\n"
213
+ f" Expected: {expected_sha256.lower()}\n"
214
+ f" Actual: {actual_sha256}"
215
+ )
216
+ logging.error(error_msg)
217
+ logging.error("Aborting due to hash verification failure")
218
+ raise ValueError(error_msg)
219
+ else:
220
+ logging.info(f"SHA256 hash verified successfully for {file_path}")
221
+
222
+
172
223
  def read_version_file(path: str) -> Dict[str, str]:
173
224
  versions = {}
174
225
 
@@ -575,7 +626,14 @@ def get_webrtc_info(
575
626
 
576
627
 
577
628
  @versioned
578
- def install_boost(version, source_dir, install_dir, sora_version, platform: str):
629
+ def install_boost(
630
+ version,
631
+ source_dir,
632
+ install_dir,
633
+ sora_version,
634
+ platform: str,
635
+ expected_sha256: Optional[str] = None,
636
+ ):
579
637
  win = platform.startswith("windows_")
580
638
  filename = (
581
639
  f"boost-{version}_sora-cpp-sdk-{sora_version}_{platform}.{'zip' if win else 'tar.gz'}"
@@ -584,6 +642,7 @@ def install_boost(version, source_dir, install_dir, sora_version, platform: str)
584
642
  archive = download(
585
643
  f"https://github.com/shiguredo/sora-cpp-sdk/releases/download/{sora_version}/{filename}",
586
644
  output_dir=source_dir,
645
+ expected_sha256=expected_sha256,
587
646
  )
588
647
  rm_rf(os.path.join(install_dir, "boost"))
589
648
  extract(archive, output_dir=install_dir, output_dirname="boost")
@@ -704,14 +763,17 @@ def build_and_install_boost(
704
763
  address_model="64",
705
764
  runtime_link=None,
706
765
  android_build_platform="linux-x86_64",
766
+ expected_sha256: Optional[str] = None,
707
767
  ):
708
768
  version_underscore = version.replace(".", "_")
769
+
709
770
  archive = download(
710
771
  # 公式サイトに負荷をかけないための時雨堂によるミラー
711
772
  f"https://oss-mirrors.shiguredo.jp/boost_{version_underscore}.tar.gz",
712
773
  # Boost 公式のミラー
713
774
  # f"https://archives.boost.io/release/{version}/source/boost_{version_underscore}.tar.gz",
714
775
  source_dir,
776
+ expected_sha256=expected_sha256,
715
777
  )
716
778
  extract(archive, output_dir=build_dir, output_dirname="boost")
717
779
  with cd(os.path.join(build_dir, "boost")):
@@ -738,7 +800,9 @@ def build_and_install_boost(
738
800
  if target_os == "iphone":
739
801
  IOS_BUILD_TARGETS = [("arm64", "iphoneos")]
740
802
  for arch, sdk in IOS_BUILD_TARGETS:
741
- clangpp = cmdcap(["xcodebuild", "-find", "clang++"])
803
+ # xcode clang++ を利用する
804
+ # ただし cxx が指定されてた場合はそちらを優先する
805
+ clangpp = cmdcap(["xcodebuild", "-find", "clang++"]) if len(cxx) == 0 else cxx
742
806
  sysroot = cmdcap(["xcrun", "--sdk", sdk, "--show-sdk-path"])
743
807
  boost_arch = "x86" if arch == "x86_64" else "arm"
744
808
  with open("project-config.jam", "w", encoding="utf-8") as f:
@@ -1057,6 +1121,21 @@ def install_android_sdk_cmdline_tools(version, install_dir, source_dir):
1057
1121
  cmd(["/bin/bash", "-c", f"yes | {sdkmanager} --sdk_root={tools_dir} --licenses"])
1058
1122
 
1059
1123
 
1124
+ @versioned
1125
+ def install_android_sdk_platform_tools(version, install_dir, source_dir, platform):
1126
+ if version not in ("latest",):
1127
+ raise Exception(f"Supports only 'latest' version, but got: {version}")
1128
+ if platform not in ("windows", "darwin", "linux"):
1129
+ raise Exception(f"Not supported platform: {platform}")
1130
+ archive = download(
1131
+ f"https://dl.google.com/android/repository/platform-tools-{version}-{platform}.zip",
1132
+ source_dir,
1133
+ )
1134
+ tools_dir = os.path.join(install_dir, "android-sdk-platform-tools")
1135
+ rm_rf(tools_dir)
1136
+ extract(archive, output_dir=tools_dir, output_dirname="platform-tools")
1137
+
1138
+
1060
1139
  @versioned
1061
1140
  def install_llvm(
1062
1141
  version,
@@ -1408,22 +1487,24 @@ def install_blend2d_official(
1408
1487
  source_dir,
1409
1488
  build_dir,
1410
1489
  install_dir,
1411
- ios,
1412
1490
  cmake_args,
1491
+ expected_sha256: Optional[str] = None,
1413
1492
  ):
1414
1493
  rm_rf(os.path.join(source_dir, "blend2d"))
1415
1494
  rm_rf(os.path.join(build_dir, "blend2d"))
1416
1495
  rm_rf(os.path.join(install_dir, "blend2d"))
1417
1496
 
1418
- url = f"https://blend2d.com/download/blend2d-{version}.tar.gz"
1419
- path = download(url, source_dir)
1497
+ # 公式サイトに負荷をかけないための時雨堂によるミラー
1498
+ url = f"https://oss-mirrors.shiguredo.jp/blend2d-{version}.tar.gz"
1499
+ # Blend2d 公式
1500
+ # url = f"https://blend2d.com/download/blend2d-{version}.tar.gz"
1501
+ path = download(url, source_dir, expected_sha256=expected_sha256)
1420
1502
  extract(path, source_dir, "blend2d")
1421
1503
  _build_blend2d(
1422
1504
  configuration=configuration,
1423
1505
  source_dir=source_dir,
1424
1506
  build_dir=build_dir,
1425
1507
  install_dir=install_dir,
1426
- ios=ios,
1427
1508
  cmake_args=cmake_args,
1428
1509
  )
1429
1510
 
@@ -1437,7 +1518,6 @@ def install_blend2d(
1437
1518
  install_dir,
1438
1519
  blend2d_version,
1439
1520
  asmjit_version,
1440
- ios,
1441
1521
  cmake_args,
1442
1522
  ):
1443
1523
  rm_rf(os.path.join(source_dir, "blend2d"))
@@ -1458,12 +1538,11 @@ def install_blend2d(
1458
1538
  source_dir=source_dir,
1459
1539
  build_dir=build_dir,
1460
1540
  install_dir=install_dir,
1461
- ios=ios,
1462
1541
  cmake_args=cmake_args,
1463
1542
  )
1464
1543
 
1465
1544
 
1466
- def _build_blend2d(configuration, source_dir, build_dir, install_dir, ios, cmake_args):
1545
+ def _build_blend2d(configuration, source_dir, build_dir, install_dir, cmake_args):
1467
1546
  mkdir_p(os.path.join(build_dir, "blend2d"))
1468
1547
  with cd(os.path.join(build_dir, "blend2d")):
1469
1548
  cmd(
@@ -1481,37 +1560,17 @@ def _build_blend2d(configuration, source_dir, build_dir, install_dir, ios, cmake
1481
1560
  if os.path.exists(project_path):
1482
1561
  replace_vcproj_static_runtime(project_path)
1483
1562
 
1484
- if ios:
1485
- cmd(
1486
- [
1487
- "cmake",
1488
- "--build",
1489
- ".",
1490
- f"-j{multiprocessing.cpu_count()}",
1491
- "--config",
1492
- configuration,
1493
- "--target",
1494
- "blend2d",
1495
- "--",
1496
- "-arch",
1497
- "arm64",
1498
- "-sdk",
1499
- "iphoneos",
1500
- ]
1501
- )
1502
- cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration])
1503
- else:
1504
- cmd(
1505
- [
1506
- "cmake",
1507
- "--build",
1508
- ".",
1509
- f"-j{multiprocessing.cpu_count()}",
1510
- "--config",
1511
- configuration,
1512
- ]
1513
- )
1514
- cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration])
1563
+ cmd(
1564
+ [
1565
+ "cmake",
1566
+ "--build",
1567
+ ".",
1568
+ f"-j{multiprocessing.cpu_count()}",
1569
+ "--config",
1570
+ configuration,
1571
+ ]
1572
+ )
1573
+ cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration])
1515
1574
 
1516
1575
 
1517
1576
  @versioned
@@ -2223,21 +2282,33 @@ def fix_clang_version(clang_dir, clang_version):
2223
2282
 
2224
2283
 
2225
2284
  class Platform(object):
2226
- def _check(self, flag):
2285
+ def _check(self, flag, error_message):
2227
2286
  if not flag:
2228
- raise Exception("Not supported")
2287
+ raise Exception(error_message)
2229
2288
 
2230
2289
  def _check_platform_target(self, p: PlatformTarget):
2231
2290
  if p.os == "raspberry-pi-os":
2232
- self._check(p.arch in ("armv6", "armv7", "armv8"))
2291
+ self._check(
2292
+ p.arch in ("armv6", "armv7", "armv8"),
2293
+ f"Architecture {p.arch} is not supported for {p.os}. Supported: armv6, armv7, armv8",
2294
+ )
2233
2295
  elif p.os == "jetson":
2234
- self._check(p.arch == "armv8")
2296
+ self._check(
2297
+ p.arch == "armv8",
2298
+ f"Architecture {p.arch} is not supported for {p.os}. Only armv8 is supported",
2299
+ )
2235
2300
  elif p.os in ("ios", "android"):
2236
- self._check(p.arch is None)
2301
+ self._check(p.arch is None, f"Architecture should be None for {p.os}, but got {p.arch}")
2237
2302
  elif p.os == "ubuntu":
2238
- self._check(p.arch in ("x86_64", "armv8"))
2303
+ self._check(
2304
+ p.arch in ("x86_64", "armv8"),
2305
+ f"Architecture {p.arch} is not supported for {p.os}. Supported: x86_64, armv8",
2306
+ )
2239
2307
  else:
2240
- self._check(p.arch in ("x86_64", "arm64", "hololens2"))
2308
+ self._check(
2309
+ p.arch in ("x86_64", "arm64", "hololens2"),
2310
+ f"Architecture {p.arch} is not supported for {p.os}. Supported: x86_64, arm64, hololens2",
2311
+ )
2241
2312
 
2242
2313
  def __init__(self, target_os, target_osver, target_arch, target_extra=None):
2243
2314
  build = get_build_platform()
@@ -2247,32 +2318,83 @@ class Platform(object):
2247
2318
  self._check_platform_target(target)
2248
2319
 
2249
2320
  if target.os == "windows":
2250
- self._check(target.arch in ("x86_64", "arm64", "hololens2"))
2251
- self._check(build.os == "windows")
2252
- self._check(build.arch == "x86_64")
2321
+ self._check(
2322
+ target.arch in ("x86_64", "arm64", "hololens2"),
2323
+ f"Target architecture {target.arch} is not supported for Windows",
2324
+ )
2325
+ self._check(
2326
+ build.os == "windows",
2327
+ f"Windows target requires Windows build platform, but got {build.os}",
2328
+ )
2329
+ self._check(
2330
+ build.arch == "x86_64",
2331
+ f"Windows build requires x86_64 architecture, but got {build.arch}",
2332
+ )
2253
2333
  if target.os == "macos":
2254
- self._check(build.os == "macos")
2255
- self._check(build.arch in ("x86_64", "arm64"))
2334
+ self._check(
2335
+ build.os == "macos",
2336
+ f"macOS target requires macOS build platform, but got {build.os}",
2337
+ )
2338
+ self._check(
2339
+ build.arch in ("x86_64", "arm64"),
2340
+ f"macOS build requires x86_64 or arm64, but got {build.arch}",
2341
+ )
2256
2342
  if target.os == "ios":
2257
- self._check(build.os == "macos")
2258
- self._check(build.arch in ("x86_64", "arm64"))
2343
+ self._check(
2344
+ build.os == "macos", f"iOS target requires macOS build platform, but got {build.os}"
2345
+ )
2346
+ self._check(
2347
+ build.arch in ("x86_64", "arm64"),
2348
+ f"iOS build requires x86_64 or arm64, but got {build.arch}",
2349
+ )
2259
2350
  if target.os == "android":
2260
- self._check(build.os in ("ubuntu", "macos"))
2351
+ self._check(
2352
+ build.os in ("ubuntu", "macos"),
2353
+ f"Android target requires Ubuntu or macOS build platform, but got {build.os}",
2354
+ )
2261
2355
  if build.os == "ubuntu":
2262
- self._check(build.arch == "x86_64")
2356
+ self._check(
2357
+ build.arch == "x86_64",
2358
+ f"Android build on Ubuntu requires x86_64, but got {build.arch}",
2359
+ )
2263
2360
  elif build.os == "macos":
2264
- self._check(build.arch in ("x86_64", "arm64"))
2361
+ self._check(
2362
+ build.arch in ("x86_64", "arm64"),
2363
+ f"Android build on macOS requires x86_64 or arm64, but got {build.arch}",
2364
+ )
2265
2365
  if target.os == "ubuntu":
2266
- self._check(build.os == "ubuntu")
2267
- self._check(build.arch in ("x86_64", "armv8"))
2366
+ self._check(
2367
+ build.os == "ubuntu",
2368
+ f"Ubuntu target requires Ubuntu build platform, but got {build.os}",
2369
+ )
2370
+ self._check(
2371
+ build.arch in ("x86_64", "armv8"),
2372
+ f"Ubuntu build requires x86_64 or armv8, but got {build.arch}",
2373
+ )
2268
2374
  if build.arch == target.arch:
2269
- self._check(build.osver == target.osver)
2375
+ self._check(
2376
+ build.osver == target.osver,
2377
+ f"When building for the same architecture ({build.arch}), OS versions must match. "
2378
+ f"Build OS: Ubuntu {build.osver}, Target OS: Ubuntu {target.osver}. "
2379
+ f"This typically happens when GitHub Actions runner OS version doesn't match the target.",
2380
+ )
2270
2381
  if target.os == "raspberry-pi-os":
2271
- self._check(build.os == "ubuntu")
2272
- self._check(build.arch == "x86_64")
2382
+ self._check(
2383
+ build.os == "ubuntu",
2384
+ f"Raspberry Pi OS target requires Ubuntu build platform, but got {build.os}",
2385
+ )
2386
+ self._check(
2387
+ build.arch == "x86_64",
2388
+ f"Raspberry Pi OS build requires x86_64, but got {build.arch}",
2389
+ )
2273
2390
  if target.os == "jetson":
2274
- self._check(build.os == "ubuntu")
2275
- self._check(build.arch == "x86_64")
2391
+ self._check(
2392
+ build.os == "ubuntu",
2393
+ f"Jetson target requires Ubuntu build platform, but got {build.os}",
2394
+ )
2395
+ self._check(
2396
+ build.arch == "x86_64", f"Jetson build requires x86_64, but got {build.arch}"
2397
+ )
2276
2398
 
2277
2399
  self.build = build
2278
2400
  self.target = target
@@ -23,20 +23,14 @@ Discord = "https://discord.gg/shiguredo"
23
23
  requires = ["setuptools==80.9", "wheel==0.45.1"]
24
24
  build-backend = "setuptools.build_meta"
25
25
 
26
+ [dependency-groups]
27
+ dev = ["nanobind==2.9.2", "setuptools==80.9.0", "ruff", "ty"]
28
+ test = ["pytest", "pytest-repeat", "pytest-xdist", "numpy", "httpx", "pyjwt"]
29
+ lint = ["ruff", "ty"]
30
+
26
31
  [tool.uv]
27
32
  python-preference = "only-managed"
28
- dev-dependencies = [
29
- "nanobind==2.9.2",
30
- "setuptools==80.9.0",
31
- "pytest",
32
- "pytest-repeat",
33
- "pytest-xdist",
34
- "numpy",
35
- "httpx",
36
- "pyjwt",
37
- "ruff",
38
- "ty",
39
- ]
33
+ default-groups = ["dev", "test", "lint"]
40
34
 
41
35
  [tool.ruff]
42
36
  target-version = "py311"
@@ -51,10 +51,11 @@ def install_deps(
51
51
  version = read_version_file("DEPS")
52
52
 
53
53
  # multistrap を使った sysroot の構築
54
- if (
55
- platform.target.os == "jetson"
56
- or platform.target.os == "ubuntu"
57
- and platform.target.arch == "armv8"
54
+ if platform.target.package_name in (
55
+ "ubuntu-22.04_armv8_jetson",
56
+ "raspberry-pi-os_armv8",
57
+ "ubuntu-22.04_armv8",
58
+ "ubuntu-24.04_armv8",
58
59
  ):
59
60
  conf = os.path.join("multistrap", f"{platform.target.package_name}.conf")
60
61
  # conf ファイルのハッシュ値をバージョンとする
@@ -90,7 +91,9 @@ def install_deps(
90
91
  webrtc_info = get_webrtc_info(webrtc_platform, local_webrtc_build_dir, install_dir, debug)
91
92
  webrtc_version = read_version_file(webrtc_info.version_file)
92
93
 
93
- if platform.build.os == "ubuntu" and local_webrtc_build_dir is None:
94
+ if (
95
+ platform.build.os == "macos" or platform.build.os == "ubuntu"
96
+ ) and local_webrtc_build_dir is None:
94
97
  # LLVM
95
98
  tools_url = webrtc_version["WEBRTC_SRC_TOOLS_URL"]
96
99
  tools_commit = webrtc_version["WEBRTC_SRC_TOOLS_COMMIT"]
@@ -178,6 +181,7 @@ AVAILABLE_TARGETS = [
178
181
  "ubuntu-22.04_armv8",
179
182
  "ubuntu-24.04_armv8",
180
183
  "ubuntu-22.04_armv8_jetson",
184
+ "raspberry-pi-os_armv8",
181
185
  ]
182
186
 
183
187
 
@@ -208,6 +212,8 @@ def _get_platform(target: str) -> Platform:
208
212
  platform = Platform("ubuntu", "24.04", "armv8")
209
213
  elif target == "ubuntu-22.04_armv8_jetson":
210
214
  platform = Platform("jetson", None, "armv8", "ubuntu-22.04")
215
+ elif target == "raspberry-pi-os_armv8":
216
+ platform = Platform("raspberry-pi-os", None, "armv8")
211
217
  else:
212
218
  raise Exception(f"Unknown target {target}")
213
219
  return platform
@@ -258,7 +264,11 @@ def _build(
258
264
  cmake_args = []
259
265
  cmake_args.append(f"-DCMAKE_BUILD_TYPE={configuration}")
260
266
  cmake_args.append(f"-DTARGET_OS={platform.target.os}")
261
- cmake_args.append(f"-DSORA_PYTHON_SDK_VERSION={importlib.metadata.version('sora-sdk')}")
267
+ # Raspberry Pi OS の場合は sora-sdk-rpi パッケージからバージョンを取得する
268
+ if platform.target.os == "raspberry-pi-os":
269
+ cmake_args.append(f"-DSORA_PYTHON_SDK_VERSION={importlib.metadata.version('sora-sdk-rpi')}")
270
+ else:
271
+ cmake_args.append(f"-DSORA_PYTHON_SDK_VERSION={importlib.metadata.version('sora-sdk')}")
262
272
  cmake_args.append(f"-DBOOST_ROOT={cmake_path(sora_info.boost_install_dir)}")
263
273
  cmake_args.append(f"-DWEBRTC_INCLUDE_DIR={cmake_path(webrtc_info.webrtc_include_dir)}")
264
274
  cmake_args.append(f"-DWEBRTC_LIBRARY_DIR={cmake_path(webrtc_info.webrtc_library_dir)}")
@@ -310,11 +320,13 @@ def _build(
310
320
  cmake_args += [
311
321
  "-DCMAKE_SYSTEM_PROCESSOR=arm64",
312
322
  "-DCMAKE_OSX_ARCHITECTURES=arm64",
313
- "-DCMAKE_C_COMPILER=clang",
323
+ f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}",
314
324
  "-DCMAKE_C_COMPILER_TARGET=aarch64-apple-darwin",
315
- "-DCMAKE_CXX_COMPILER=clang++",
325
+ f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}",
316
326
  "-DCMAKE_CXX_COMPILER_TARGET=aarch64-apple-darwin",
317
327
  f"-DCMAKE_SYSROOT={sysroot}",
328
+ f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}",
329
+ f"-DLIBCXXABI_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxxabi_dir, 'include'))}",
318
330
  ]
319
331
  elif platform.target.os == "jetson":
320
332
  sysroot = os.path.join(install_dir, "rootfs")
@@ -332,9 +344,30 @@ def _build(
332
344
  "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
333
345
  f"-DCMAKE_SYSROOT={sysroot}",
334
346
  f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}",
347
+ f"-DLIBCXXABI_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxxabi_dir, 'include'))}",
335
348
  f"-DPython_ROOT_DIR={cmake_path(os.path.join(sysroot, 'usr', 'include', 'python3.10'))}",
336
349
  "-DNB_SUFFIX=.cpython-310-aarch64-linux-gnu.so",
337
350
  ]
351
+ elif platform.target.os == "raspberry-pi-os":
352
+ sysroot = os.path.join(install_dir, "rootfs")
353
+ cmake_args += [
354
+ "-DCMAKE_SYSTEM_NAME=Linux",
355
+ "-DCMAKE_SYSTEM_PROCESSOR=aarch64",
356
+ f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}",
357
+ "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu",
358
+ f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}",
359
+ "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu",
360
+ f"-DCMAKE_FIND_ROOT_PATH={sysroot}",
361
+ "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER",
362
+ "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH",
363
+ "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH",
364
+ "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
365
+ f"-DCMAKE_SYSROOT={sysroot}",
366
+ f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}",
367
+ f"-DLIBCXXABI_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxxabi_dir, 'include'))}",
368
+ f"-DPython_ROOT_DIR={cmake_path(os.path.join(sysroot, 'usr', 'include', 'python3.11'))}",
369
+ "-DNB_SUFFIX=.cpython-311-aarch64-linux-gnu.so",
370
+ ]
338
371
 
339
372
  # Windows 以外の、クロスコンパイルでない環境では pyi ファイルを生成する
340
373
  if (
@@ -382,6 +415,11 @@ def _build(
382
415
  os.path.join(sora_build_target_dir, file), os.path.join(sora_src_dir, file)
383
416
  )
384
417
 
418
+ if platform.target.os == "raspberry-pi-os":
419
+ # libcamerac.so を sora_sdk_ext.*.so と同じディレクトリにコピーする
420
+ libcamerac_so = os.path.join(sora_info.sora_install_dir, "lib", "libcamerac.so")
421
+ shutil.copyfile(libcamerac_so, os.path.join(sora_src_dir, "libcamerac.so"))
422
+
385
423
 
386
424
  def _format(
387
425
  clang_format_path: Optional[str] = None,
@@ -21,6 +21,7 @@ def run_setup(build_platform, target_platform):
21
21
  version += "+debug"
22
22
 
23
23
  plat = None
24
+ additional_files = []
24
25
  if target_platform.os == "jetson":
25
26
  plat = "manylinux_2_17_aarch64.manylinux2014_aarch64"
26
27
  elif target_platform.os == "ubuntu" and target_platform.arch == "armv8":
@@ -33,6 +34,9 @@ def run_setup(build_platform, target_platform):
33
34
  plat = "manylinux_2_31_x86_64"
34
35
  if target_platform.osver == "24.04":
35
36
  plat = "manylinux_2_35_x86_64"
37
+ elif target_platform.os == "raspberry-pi-os":
38
+ plat = "manylinux_2_35_aarch64"
39
+ additional_files += ["libcamerac.so"]
36
40
 
37
41
  class bdist_wheel(_bdist_wheel):
38
42
  def finalize_options(self):
@@ -50,7 +54,7 @@ def run_setup(build_platform, target_platform):
50
54
  packages=["sora_sdk"],
51
55
  package_dir={"": "src"},
52
56
  package_data={
53
- "sora_sdk": ["sora_sdk_ext.*"],
57
+ "sora_sdk": ["sora_sdk_ext.*", *additional_files],
54
58
  },
55
59
  include_package_data=True,
56
60
  cmdclass={
@@ -71,6 +75,8 @@ def main():
71
75
  target_platform = PlatformTarget("ubuntu", "24.04", "armv8")
72
76
  elif target == "ubuntu-22.04_armv8_jetson":
73
77
  target_platform = PlatformTarget("jetson", None, "armv8", "ubuntu-22.04")
78
+ elif target == "raspberry-pi-os_armv8":
79
+ target_platform = PlatformTarget("raspberry-pi-os", None, "armv8")
74
80
  else:
75
81
  raise Exception(f"Unknown target {target}")
76
82
 
@@ -370,6 +370,8 @@ class SoraVideoCodecImplementation(enum.IntEnum):
370
370
 
371
371
  AMD_AMF = 4
372
372
 
373
+ RASPI_V4L2M2M = 5
374
+
373
375
  class SoraVideoCodecType(enum.IntEnum):
374
376
  VP8 = 1
375
377
 
@@ -490,10 +492,12 @@ class SoraVideoCodecPreference:
490
492
  def create_video_codec_preference_from_implementation(arg0: SoraVideoCodecCapability, arg1: SoraVideoCodecImplementation, /) -> SoraVideoCodecPreference: ...
491
493
 
492
494
  class Sora:
493
- def __init__(self, openh264: str | None = None, video_codec_preference: SoraVideoCodecPreference | None = None) -> None: ...
495
+ def __init__(self, openh264: str | None = None, video_codec_preference: SoraVideoCodecPreference | None = None, force_i420_conversion: bool | None = None) -> None: ...
494
496
 
495
497
  def create_connection(self, signaling_urls: list[str], role: str, channel_id: str, client_id: Optional[str] = None, bundle_id: Optional[str] = None, metadata: Optional[dict] = None, signaling_notify_metadata: Optional[dict] = None, audio_source: Optional[SoraTrackInterface] = None, video_source: Optional[SoraTrackInterface] = None, audio_frame_transformer: Optional[SoraAudioFrameTransformer] = None, video_frame_transformer: Optional[SoraVideoFrameTransformer] = None, audio: Optional[bool] = None, video: Optional[bool] = None, audio_codec_type: Optional[str] = None, video_codec_type: Optional[str] = None, video_bit_rate: Optional[int] = None, audio_bit_rate: Optional[int] = None, video_vp9_params: Optional[dict] = None, video_av1_params: Optional[dict] = None, video_h264_params: Optional[dict] = None, audio_opus_params: Optional[dict] = None, simulcast: Optional[bool] = None, spotlight: Optional[bool] = None, spotlight_number: Optional[int] = None, simulcast_rid: Optional[str] = None, spotlight_focus_rid: Optional[str] = None, spotlight_unfocus_rid: Optional[str] = None, forwarding_filter: Optional[dict] = None, forwarding_filters: Optional[list[dict]] = None, data_channels: Optional[list[dict]] = None, data_channel_signaling: Optional[bool] = None, ignore_disconnect_websocket: Optional[bool] = None, data_channel_signaling_timeout: Optional[int] = None, disconnect_wait_timeout: Optional[int] = None, websocket_close_timeout: Optional[int] = None, websocket_connection_timeout: Optional[int] = None, audio_streaming_language_code: Optional[str] = None, insecure: Optional[bool] = None, client_cert: Optional[bytes] = None, client_key: Optional[bytes] = None, ca_cert: Optional[bytes] = None, proxy_url: Optional[str] = None, proxy_username: Optional[str] = None, proxy_password: Optional[str] = None, proxy_agent: Optional[str] = None, degradation_preference: Optional[SoraDegradationPreference] = None, user_agent: Optional[str] = None) -> SoraConnection: ...
496
498
 
497
499
  def create_audio_source(self, channels: int, sample_rate: int) -> SoraAudioSource: ...
498
500
 
499
501
  def create_video_source(self) -> SoraVideoSource: ...
502
+
503
+ def create_libcamera_source(self, width: int, height: int, fps: int, native_frame_output: bool, controls: Optional[list[tuple[str, str]]] = None) -> SoraTrackInterface: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sora_sdk
3
- Version: 2025.4.0.dev6
3
+ Version: 2025.5.0.dev1
4
4
  Summary: WebRTC SFU Sora Python SDK
5
5
  Home-page: https://github.com/shiguredo/sora-python-sdk
6
6
  Author-email: "Shiguredo Inc." <contact+pypi@shiguredo.jp>
@@ -47,13 +47,13 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
47
47
 
48
48
  - [Sora C++ SDK](https://github.com/shiguredo/sora-cpp-sdk) ベース
49
49
  - WebRTC 部分の機能は [libwebrtc](https://webrtc.googlesource.com/src/) を採用
50
- - Windows / macOS / Linux (Ubuntu) プラットフォームに対応
50
+ - Windows / macOS / Linux (Ubuntu / Raspberry Pi OS) プラットフォームに対応
51
51
  - [WebRTC 統計情報](https://www.w3.org/TR/webrtc-stats/) の取得が可能
52
52
  - [WebRTC Encoded Transform](https://www.w3.org/TR/webrtc-encoded-transform/) に対応
53
53
  - 回線が不安定になった際、解像度とフレームレートどちらを維持するかの設定をする [DegradationPreference](https://w3c.github.io/mst-content-hint/#degradation-preference-when-encoding) に対応
54
54
  - MAINTAIN_FRAMERATE / MAINTAIN_RESOLUTION / BALANCED が指定できる
55
55
  - 発話区間の検出が可能な VAD (Voice Activity Detection) に対応
56
- - Intel / Apple / NVIDIA のハードウェアデコーダー/エンコーダーに対応
56
+ - Intel / Apple / NVIDIA / Raspberry Pi のハードウェアデコーダー/エンコーダーに対応
57
57
  - Apple Video Toolbox (H.264 / H.265)
58
58
  - macOS arm64 で利用できる
59
59
  - Intel VPL (AV1 / H.264 / H.265)
@@ -62,10 +62,13 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
62
62
  - Ubuntu x86_64 / Windows x86_64 で利用できる
63
63
  - AV1 エンコードは Windows x86_64 でのみ利用できる
64
64
  - VP9 はデコードのみ利用できる
65
- - NVIDIA Video Codec SDK (VP8 / VP9 / AV1 / H.264 / H.265)
65
+ - NVIDIA Video Codec (VP8 / VP9 / AV1 / H.264 / H.265)
66
66
  - Ubuntu x86_64 / Windows x86_64 で利用できる
67
67
  - VP8 と VP9 はデコードのみ利用できる
68
68
  - NVIDIA Jetson JetPack SDK (AV1 / H.264 / H.265)
69
+ - Raspberry Pi (H.264)
70
+ - Raspberry Pi 4 / Raspberry Pi 3 / Raspberry Pi 2 Model B v1.2 / Raspberry Pi Zero 2 W で利用できる
71
+ - V4L2-M2M API を利用している
69
72
  - [各プラットフォームで利用可能な HWA への対応](https://github.com/shiguredo/sora-cpp-sdk?tab=readme-ov-file#%E7%89%B9%E5%BE%B4)
70
73
  - [OpenH264](https://github.com/cisco/openh264) を利用した H.264 のソフトウェアエンコーダー/デコーダーに対応
71
74
  - Ubuntu x86_64 / Ubuntu arm64 / Windows x86_64 / macOS arm64 で利用できる
@@ -73,7 +76,9 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
73
76
  - 映像デバイス処理に [opencv-python](https://pypi.org/project/opencv-python/) などが利用できる
74
77
  - 音声認識などの入力に受信した音声を利用できる
75
78
  - 物体検出などの入力に受信した映像を利用できる
76
- - `uv add sora_sdk` や `pip install sora_sdk` でインストール可能
79
+ - `uv add sora_sdk` や `pip install sora_sdk` でインストールできる
80
+ - Raspberry Pi 向けのパッケージも `uv add sora_sdk_rpi` でインストールできる
81
+ - Raspberry Pi 向けに libcamera 用の `create_libcamera_source` を提供
77
82
  - [NVIDIA Jetson JetPack SDK](https://developer.nvidia.com/embedded/jetpack) に対応
78
83
 
79
84
  ## 利用イメージ
@@ -99,6 +104,12 @@ Please read <https://github.com/shiguredo/oss/blob/master/README.en.md> before u
99
104
  uv add sora_sdk
100
105
  ```
101
106
 
107
+ ### Raspberry Pi OS 向けパッケージ
108
+
109
+ ```bash
110
+ uv add sora_sdk_rpi
111
+ ```
112
+
102
113
  ### NVIDIA Jetson 向けパッケージ
103
114
 
104
115
  PyPI 経由ではインストールできません。
@@ -125,8 +136,23 @@ PyPI 経由ではインストールできません。
125
136
  - macOS Ventura 14 arm64
126
137
  - Windows 11 x86_64
127
138
  - Windows Server 2025 x86_64
139
+ - Raspberry Pi OS armv8
140
+
141
+ ### Raspberry Pi OS 向け
142
+
143
+ - Raspberry Pi OS bookworm (64bit)
144
+ - Raspberry Pi 5
145
+ - Raspberry Pi 4
146
+ - Raspberry Pi 3
147
+ - Raspberry Pi 2 Model B v1.2
148
+ - Raspberry Pi Zero 2 W
149
+
150
+ > [!CAUTION]
151
+ >
152
+ > - Raspberry Pi 5 は H.264 ハードウェアエンコーダーが搭載されていません
153
+ > - Raspberry Pi 5 の H.265 ハードウェアデコーダーに対応していません
128
154
 
129
- ### Jetson 向け
155
+ ### NVIDIA Jetson 向け
130
156
 
131
157
  - Ubuntu 22.04 LTS arm64 (NVIDIA Jetson JetPack SDK 6)
132
158
  - PyPI からではなくパッケージファイルを利用してください
@@ -27,7 +27,7 @@ tests/test_intel_vpl.py
27
27
  tests/test_key_frame_request.py
28
28
  tests/test_messaging.py
29
29
  tests/test_messaging_header.py
30
- tests/test_nvidia_video_codec_sdk.py
30
+ tests/test_nvidia_video_codec.py
31
31
  tests/test_openh264.py
32
32
  tests/test_openh264_simulcast.py
33
33
  tests/test_opus.py
@@ -602,6 +602,6 @@ def test_intel_vpl_av1_rtp_hdr_ext(settings):
602
602
  sendonly.disconnect()
603
603
 
604
604
  # AV1 の RTP ヘッダー拡張が送られてきていることを確認
605
- assert (
606
- stats["rtp_hdrext"]["total_received_rtp_hdrext_av1_rtp_sepc"] > 0
607
- ), "Dependency Descriptor RTP Header Extension が Python SDK から送られてきていません"
605
+ assert stats["rtp_hdrext"]["total_received_rtp_hdrext_av1_rtp_sepc"] > 0, (
606
+ "Dependency Descriptor RTP Header Extension が Python SDK から送られてきていません"
607
+ )
@@ -18,7 +18,7 @@ from sora_sdk import (
18
18
  )
19
19
 
20
20
  pytestmark = pytest.mark.skipif(
21
- os.environ.get("NVIDIA_VIDEO_CODEC_SDK") is None, reason="NVIDIA Video Codec SDK でのみ実行する"
21
+ os.environ.get("NVIDIA_VIDEO_CODEC") is None, reason="NVIDIA Video Codec でのみ実行する"
22
22
  )
23
23
 
24
24
 
@@ -1 +0,0 @@
1
- 2025.4.0.dev6