sora-sdk 2025.4.0.dev0__tar.gz → 2025.4.0.dev2__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.
- {sora_sdk-2025.4.0.dev0/src/sora_sdk.egg-info → sora_sdk-2025.4.0.dev2}/PKG-INFO +1 -1
- sora_sdk-2025.4.0.dev2/VERSION +1 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/buildbase.py +292 -3
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/pyproject.toml +1 -1
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk/sora_sdk_ext.cpython-311-darwin.so +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2/src/sora_sdk.egg-info}/PKG-INFO +1 -1
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk.egg-info/SOURCES.txt +1 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_amd_amf.py +72 -4
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_intel_vpl.py +137 -133
- sora_sdk-2025.4.0.dev2/tests/test_key_frame_request.py +75 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_nvidia_video_codec_sdk.py +65 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_sendonly_recvonly.py +10 -0
- sora_sdk-2025.4.0.dev0/VERSION +0 -1
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/LICENSE +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/MANIFEST.in +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/README.md +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/pypath.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/run.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/setup.cfg +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/setup.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk/__init__.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk/py.typed +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk/sora_sdk_ext.pyi +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk.egg-info/dependency_links.txt +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk.egg-info/top_level.txt +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_apple_video_toolbox.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_authz.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_authz_simulcast.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_ca_cert.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_capability.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_degradation_preference.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_encoded_transform.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_messaging.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_messaging_header.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_openh264.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_openh264_simulcast.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_opus.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_re_offer_re_answer_sdp.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_signaling.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_signaling_message.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_signaling_notify.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_simulcast.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_sora_disconnect.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_type_disconnect.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_type_switched.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_vad.py +0 -0
- {sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/tests/test_version.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2025.4.0.dev2
|
|
@@ -302,7 +302,12 @@ def _extractzip(z: zipfile.ZipFile, path: str):
|
|
|
302
302
|
def extract(file: str, output_dir: str, output_dirname: str, filetype: Optional[str] = None):
|
|
303
303
|
path = os.path.join(output_dir, output_dirname)
|
|
304
304
|
logging.info(f"Extract {file} to {path}")
|
|
305
|
-
if
|
|
305
|
+
if (
|
|
306
|
+
filetype == "gzip"
|
|
307
|
+
or file.endswith(".tar.gz")
|
|
308
|
+
or filetype == "lzma"
|
|
309
|
+
or file.endswith(".tar.xz")
|
|
310
|
+
):
|
|
306
311
|
rm_rf(path)
|
|
307
312
|
with tarfile.open(file) as t:
|
|
308
313
|
dir = is_single_dir_tar(t)
|
|
@@ -378,6 +383,7 @@ def git_clone_shallow(url, hash, dir, submodule=False):
|
|
|
378
383
|
|
|
379
384
|
|
|
380
385
|
def apply_patch(patch, dir, depth):
|
|
386
|
+
patch = os.path.abspath(patch)
|
|
381
387
|
with cd(dir):
|
|
382
388
|
logging.info(f"patch -p{depth} < {patch}")
|
|
383
389
|
if platform.system() == "Windows":
|
|
@@ -800,6 +806,7 @@ def build_and_install_boost(
|
|
|
800
806
|
)
|
|
801
807
|
elif target_os == "android":
|
|
802
808
|
# Android の場合、android-ndk を使ってビルドする
|
|
809
|
+
# ただし cxx が指定されてた場合はそちらを優先する
|
|
803
810
|
with open("project-config.jam", "w", encoding="utf-8") as f:
|
|
804
811
|
bin = os.path.join(
|
|
805
812
|
android_ndk, "toolchains", "llvm", "prebuilt", android_build_platform, "bin"
|
|
@@ -814,7 +821,7 @@ def build_and_install_boost(
|
|
|
814
821
|
f.write(
|
|
815
822
|
f"using clang \
|
|
816
823
|
: android \
|
|
817
|
-
: {escape(os.path.join(bin, 'clang++'))} \
|
|
824
|
+
: {escape(cxx if len(cxx) != 0 else os.path.join(bin, 'clang++'))} \
|
|
818
825
|
--target=aarch64-none-linux-android{native_api_level} \
|
|
819
826
|
--sysroot={escape(sysroot)} \
|
|
820
827
|
: <archiver>{escape(os.path.join(bin, 'llvm-ar'))} \
|
|
@@ -932,7 +939,7 @@ def build_sora(
|
|
|
932
939
|
]
|
|
933
940
|
|
|
934
941
|
with cd(local_sora_cpp_sdk_dir):
|
|
935
|
-
cmd(["python3", "run.py", platform, *local_sora_cpp_sdk_args])
|
|
942
|
+
cmd(["python3", "run.py", "build", platform, *local_sora_cpp_sdk_args])
|
|
936
943
|
|
|
937
944
|
|
|
938
945
|
class SoraInfo(NamedTuple):
|
|
@@ -1226,6 +1233,93 @@ def install_sdl2(
|
|
|
1226
1233
|
cmd(["cmake", "--install", ".", "--config", configuration])
|
|
1227
1234
|
|
|
1228
1235
|
|
|
1236
|
+
@versioned
|
|
1237
|
+
def install_sdl3(
|
|
1238
|
+
version, source_dir, build_dir, install_dir, debug: bool, platform: str, cmake_args: List[str]
|
|
1239
|
+
):
|
|
1240
|
+
url = f"https://github.com/libsdl-org/SDL/releases/download/release-{version}/SDL3-{version}.tar.gz"
|
|
1241
|
+
path = download(url, source_dir)
|
|
1242
|
+
sdl3_source_dir = os.path.join(source_dir, "sdl3")
|
|
1243
|
+
sdl3_build_dir = os.path.join(build_dir, "sdl3")
|
|
1244
|
+
sdl3_install_dir = os.path.join(install_dir, "sdl3")
|
|
1245
|
+
rm_rf(sdl3_source_dir)
|
|
1246
|
+
rm_rf(sdl3_build_dir)
|
|
1247
|
+
rm_rf(sdl3_install_dir)
|
|
1248
|
+
extract(path, source_dir, "sdl3")
|
|
1249
|
+
|
|
1250
|
+
mkdir_p(sdl3_build_dir)
|
|
1251
|
+
with cd(sdl3_build_dir):
|
|
1252
|
+
configuration = "Debug" if debug else "Release"
|
|
1253
|
+
cmake_args = cmake_args[:]
|
|
1254
|
+
cmake_args += [
|
|
1255
|
+
sdl3_source_dir,
|
|
1256
|
+
f"-DCMAKE_BUILD_TYPE={configuration}",
|
|
1257
|
+
f"-DCMAKE_INSTALL_PREFIX={cmake_path(sdl3_install_dir)}",
|
|
1258
|
+
"-DBUILD_SHARED_LIBS=OFF",
|
|
1259
|
+
"-DSDL_STATIC=ON",
|
|
1260
|
+
"-DSDL_SHARED=OFF",
|
|
1261
|
+
]
|
|
1262
|
+
if platform == "windows":
|
|
1263
|
+
cmake_args += [
|
|
1264
|
+
f"-DCMAKE_MSVC_RUNTIME_LIBRARY={'MultiThreaded' if not debug else 'MultiThreadedDebug'}",
|
|
1265
|
+
"-DSDL_AUDIO=OFF",
|
|
1266
|
+
"-DSDL_JOYSTICK=OFF",
|
|
1267
|
+
"-DSDL_HAPTIC=OFF",
|
|
1268
|
+
# GitHub Actions 上で gameinput.h が存在しないのに
|
|
1269
|
+
# なぜか check_c_source_compiles() が成功してしまうので
|
|
1270
|
+
# HAVE_GAMEINPUT_H=0 で強制的に無効化する
|
|
1271
|
+
"-DHAVE_GAMEINPUT_H=0",
|
|
1272
|
+
]
|
|
1273
|
+
elif platform == "macos":
|
|
1274
|
+
# どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する
|
|
1275
|
+
cmake_args += [
|
|
1276
|
+
"-DSDL_AUDIO=OFF",
|
|
1277
|
+
"-DSDL_VIDEO=ON",
|
|
1278
|
+
"-DSDL_RENDER=ON",
|
|
1279
|
+
"-DSDL_HAPTIC=ON",
|
|
1280
|
+
"-DSDL_POWER=ON",
|
|
1281
|
+
"-DSDL_JOYSTICK=ON",
|
|
1282
|
+
"-DSDL_SENSOR=ON",
|
|
1283
|
+
"-DSDL_OPENGL=ON",
|
|
1284
|
+
"-DSDL_OPENGLES=ON",
|
|
1285
|
+
"-DSDL_METAL=ON",
|
|
1286
|
+
"-DSDL_VULKAN=OFF",
|
|
1287
|
+
]
|
|
1288
|
+
elif platform == "linux":
|
|
1289
|
+
# どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する
|
|
1290
|
+
cmake_args += [
|
|
1291
|
+
"-DSDL_AUDIO=OFF",
|
|
1292
|
+
"-DSDL_VIDEO=ON",
|
|
1293
|
+
"-DSDL_RENDER=ON",
|
|
1294
|
+
"-DSDL_HAPTIC=ON",
|
|
1295
|
+
"-DSDL_POWER=ON",
|
|
1296
|
+
"-DSDL_JOYSTICK=ON",
|
|
1297
|
+
"-DSDL_SENSOR=ON",
|
|
1298
|
+
"-DSDL_OPENGL=ON",
|
|
1299
|
+
"-DSDL_OPENGLES=ON",
|
|
1300
|
+
"-DSDL_X11=ON",
|
|
1301
|
+
"-DSDL_X11_SHARED=OFF",
|
|
1302
|
+
"-DSDL_X11_XCURSOR=OFF",
|
|
1303
|
+
"-DSDL_X11_XDBE=OFF",
|
|
1304
|
+
"-DSDL_X11_XFIXES=OFF",
|
|
1305
|
+
"-DSDL_X11_XINPUT=OFF",
|
|
1306
|
+
"-DSDL_X11_XRANDR=OFF",
|
|
1307
|
+
"-DSDL_X11_XSCRNSAVER=OFF",
|
|
1308
|
+
"-DSDL_X11_XSHAPE=OFF",
|
|
1309
|
+
"-DSDL_X11_XSYNC=OFF",
|
|
1310
|
+
"-DSDL_WAYLAND=OFF",
|
|
1311
|
+
"-DSDL_VULKAN=OFF",
|
|
1312
|
+
"-DSDL_KMSDRM=OFF",
|
|
1313
|
+
"-DSDL_RPI=OFF",
|
|
1314
|
+
]
|
|
1315
|
+
cmd(["cmake"] + cmake_args)
|
|
1316
|
+
|
|
1317
|
+
cmd(
|
|
1318
|
+
["cmake", "--build", ".", "--config", configuration, f"-j{multiprocessing.cpu_count()}"]
|
|
1319
|
+
)
|
|
1320
|
+
cmd(["cmake", "--install", ".", "--config", configuration])
|
|
1321
|
+
|
|
1322
|
+
|
|
1229
1323
|
@versioned
|
|
1230
1324
|
def install_cli11(version, install_dir):
|
|
1231
1325
|
cli11_install_dir = os.path.join(install_dir, "cli11")
|
|
@@ -1307,6 +1401,33 @@ def install_vpl(version, configuration, source_dir, build_dir, install_dir, cmak
|
|
|
1307
1401
|
cmd(["cmake", "--install", ".", "--config", configuration])
|
|
1308
1402
|
|
|
1309
1403
|
|
|
1404
|
+
@versioned
|
|
1405
|
+
def install_blend2d_official(
|
|
1406
|
+
version,
|
|
1407
|
+
configuration,
|
|
1408
|
+
source_dir,
|
|
1409
|
+
build_dir,
|
|
1410
|
+
install_dir,
|
|
1411
|
+
ios,
|
|
1412
|
+
cmake_args,
|
|
1413
|
+
):
|
|
1414
|
+
rm_rf(os.path.join(source_dir, "blend2d"))
|
|
1415
|
+
rm_rf(os.path.join(build_dir, "blend2d"))
|
|
1416
|
+
rm_rf(os.path.join(install_dir, "blend2d"))
|
|
1417
|
+
|
|
1418
|
+
url = f"https://blend2d.com/download/blend2d-{version}.tar.gz"
|
|
1419
|
+
path = download(url, source_dir)
|
|
1420
|
+
extract(path, source_dir, "blend2d")
|
|
1421
|
+
_build_blend2d(
|
|
1422
|
+
configuration=configuration,
|
|
1423
|
+
source_dir=source_dir,
|
|
1424
|
+
build_dir=build_dir,
|
|
1425
|
+
install_dir=install_dir,
|
|
1426
|
+
ios=ios,
|
|
1427
|
+
cmake_args=cmake_args,
|
|
1428
|
+
)
|
|
1429
|
+
|
|
1430
|
+
|
|
1310
1431
|
@versioned
|
|
1311
1432
|
def install_blend2d(
|
|
1312
1433
|
version,
|
|
@@ -1332,7 +1453,17 @@ def install_blend2d(
|
|
|
1332
1453
|
asmjit_version,
|
|
1333
1454
|
os.path.join(source_dir, "blend2d", "3rdparty", "asmjit"),
|
|
1334
1455
|
)
|
|
1456
|
+
_build_blend2d(
|
|
1457
|
+
configuration=configuration,
|
|
1458
|
+
source_dir=source_dir,
|
|
1459
|
+
build_dir=build_dir,
|
|
1460
|
+
install_dir=install_dir,
|
|
1461
|
+
ios=ios,
|
|
1462
|
+
cmake_args=cmake_args,
|
|
1463
|
+
)
|
|
1464
|
+
|
|
1335
1465
|
|
|
1466
|
+
def _build_blend2d(configuration, source_dir, build_dir, install_dir, ios, cmake_args):
|
|
1336
1467
|
mkdir_p(os.path.join(build_dir, "blend2d"))
|
|
1337
1468
|
with cd(os.path.join(build_dir, "blend2d")):
|
|
1338
1469
|
cmd(
|
|
@@ -1747,6 +1878,7 @@ def install_opus(
|
|
|
1747
1878
|
"cmake",
|
|
1748
1879
|
f"-DCMAKE_INSTALL_PREFIX={cmake_path(opus_install_dir)}",
|
|
1749
1880
|
f"-DCMAKE_BUILD_TYPE={configuration}",
|
|
1881
|
+
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
|
|
1750
1882
|
"-DOPUS_BUILD_SHARED_LIBRARY=OFF",
|
|
1751
1883
|
"-DOPUS_BUILD_TESTING=OFF",
|
|
1752
1884
|
"-DOPUS_BUILD_PROGRAMS=OFF",
|
|
@@ -1803,6 +1935,163 @@ def install_amf(version, install_dir):
|
|
|
1803
1935
|
)
|
|
1804
1936
|
|
|
1805
1937
|
|
|
1938
|
+
@versioned
|
|
1939
|
+
def install_mbedtls(version, source_dir, build_dir, install_dir, debug, cmake_args):
|
|
1940
|
+
rm_rf(os.path.join(source_dir, "mbedtls"))
|
|
1941
|
+
rm_rf(os.path.join(build_dir, "mbedtls"))
|
|
1942
|
+
rm_rf(os.path.join(install_dir, "mbedtls"))
|
|
1943
|
+
git_clone_shallow(
|
|
1944
|
+
"https://github.com/Mbed-TLS/mbedtls.git",
|
|
1945
|
+
version,
|
|
1946
|
+
os.path.join(source_dir, "mbedtls"),
|
|
1947
|
+
)
|
|
1948
|
+
with cd(os.path.join(source_dir, "mbedtls")):
|
|
1949
|
+
configuration = "Debug" if debug else "Release"
|
|
1950
|
+
cmd(["python3", "scripts/config.py", "set", "MBEDTLS_SSL_DTLS_SRTP"])
|
|
1951
|
+
cmd(
|
|
1952
|
+
[
|
|
1953
|
+
"cmake",
|
|
1954
|
+
f"-DCMAKE_INSTALL_PREFIX={cmake_path(os.path.join(install_dir, 'mbedtls'))}",
|
|
1955
|
+
f"-DCMAKE_BUILD_TYPE={configuration}",
|
|
1956
|
+
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
|
|
1957
|
+
"-B",
|
|
1958
|
+
os.path.join(build_dir, "mbedtls"),
|
|
1959
|
+
]
|
|
1960
|
+
+ cmake_args
|
|
1961
|
+
)
|
|
1962
|
+
cmd(
|
|
1963
|
+
[
|
|
1964
|
+
"cmake",
|
|
1965
|
+
"--build",
|
|
1966
|
+
os.path.join(build_dir, "mbedtls"),
|
|
1967
|
+
f"-j{multiprocessing.cpu_count()}",
|
|
1968
|
+
"--config",
|
|
1969
|
+
"Release",
|
|
1970
|
+
]
|
|
1971
|
+
)
|
|
1972
|
+
cmd(["cmake", "--install", os.path.join(build_dir, "mbedtls")])
|
|
1973
|
+
|
|
1974
|
+
|
|
1975
|
+
@versioned
|
|
1976
|
+
def install_libjpeg_turbo(version, source_dir, build_dir, install_dir, configuration, cmake_args):
|
|
1977
|
+
libjpeg_source_dir = os.path.join(source_dir, "libjpeg-turbo")
|
|
1978
|
+
libjpeg_build_dir = os.path.join(build_dir, "libjpeg-turbo")
|
|
1979
|
+
libjpeg_install_dir = os.path.join(install_dir, "libjpeg-turbo")
|
|
1980
|
+
rm_rf(libjpeg_source_dir)
|
|
1981
|
+
rm_rf(libjpeg_build_dir)
|
|
1982
|
+
rm_rf(libjpeg_install_dir)
|
|
1983
|
+
git_clone_shallow(
|
|
1984
|
+
"https://github.com/libjpeg-turbo/libjpeg-turbo.git",
|
|
1985
|
+
version,
|
|
1986
|
+
libjpeg_source_dir,
|
|
1987
|
+
)
|
|
1988
|
+
mkdir_p(libjpeg_build_dir)
|
|
1989
|
+
with cd(libjpeg_build_dir):
|
|
1990
|
+
cmd(
|
|
1991
|
+
[
|
|
1992
|
+
"cmake",
|
|
1993
|
+
libjpeg_source_dir,
|
|
1994
|
+
f"-DCMAKE_INSTALL_PREFIX={libjpeg_install_dir}",
|
|
1995
|
+
f"-DCMAKE_BUILD_TYPE={configuration}",
|
|
1996
|
+
"-DENABLE_SHARED=FALSE",
|
|
1997
|
+
"-DENABLE_STATIC=TRUE",
|
|
1998
|
+
"-DCMAKE_BUILD_TYPE=Release",
|
|
1999
|
+
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
|
|
2000
|
+
]
|
|
2001
|
+
+ cmake_args
|
|
2002
|
+
)
|
|
2003
|
+
cmd(
|
|
2004
|
+
[
|
|
2005
|
+
"cmake",
|
|
2006
|
+
"--build",
|
|
2007
|
+
libjpeg_build_dir,
|
|
2008
|
+
f"-j{multiprocessing.cpu_count()}",
|
|
2009
|
+
"--config",
|
|
2010
|
+
"Release",
|
|
2011
|
+
]
|
|
2012
|
+
)
|
|
2013
|
+
cmd(["cmake", "--install", libjpeg_build_dir])
|
|
2014
|
+
|
|
2015
|
+
|
|
2016
|
+
@versioned
|
|
2017
|
+
def install_libyuv(
|
|
2018
|
+
version, source_dir, build_dir, install_dir, libjpeg_turbo_dir, configuration, cmake_args
|
|
2019
|
+
):
|
|
2020
|
+
libyuv_source_dir = os.path.join(source_dir, "libyuv")
|
|
2021
|
+
libyuv_build_dir = os.path.join(build_dir, "libyuv")
|
|
2022
|
+
libyuv_install_dir = os.path.join(install_dir, "libyuv")
|
|
2023
|
+
rm_rf(libyuv_source_dir)
|
|
2024
|
+
rm_rf(libyuv_build_dir)
|
|
2025
|
+
rm_rf(libyuv_install_dir)
|
|
2026
|
+
git_clone_shallow(
|
|
2027
|
+
"https://chromium.googlesource.com/libyuv/libyuv",
|
|
2028
|
+
version,
|
|
2029
|
+
libyuv_source_dir,
|
|
2030
|
+
)
|
|
2031
|
+
mkdir_p(libyuv_build_dir)
|
|
2032
|
+
with cd(libyuv_build_dir):
|
|
2033
|
+
cmd(
|
|
2034
|
+
[
|
|
2035
|
+
"cmake",
|
|
2036
|
+
libyuv_source_dir,
|
|
2037
|
+
f"-DCMAKE_INSTALL_PREFIX={cmake_path(libyuv_install_dir)}",
|
|
2038
|
+
f"-DCMAKE_BUILD_TYPE={configuration}",
|
|
2039
|
+
f"-DCMAKE_PREFIX_PATH={cmake_path(libjpeg_turbo_dir)}",
|
|
2040
|
+
*cmake_args,
|
|
2041
|
+
]
|
|
2042
|
+
)
|
|
2043
|
+
cmd(
|
|
2044
|
+
[
|
|
2045
|
+
"cmake",
|
|
2046
|
+
"--build",
|
|
2047
|
+
libyuv_build_dir,
|
|
2048
|
+
f"-j{multiprocessing.cpu_count()}",
|
|
2049
|
+
"--config",
|
|
2050
|
+
"Release",
|
|
2051
|
+
]
|
|
2052
|
+
)
|
|
2053
|
+
cmd(["cmake", "--install", libyuv_build_dir])
|
|
2054
|
+
|
|
2055
|
+
|
|
2056
|
+
@versioned
|
|
2057
|
+
def install_aom(version, source_dir, build_dir, install_dir, configuration, cmake_args):
|
|
2058
|
+
aom_source_dir = os.path.join(source_dir, "aom")
|
|
2059
|
+
aom_build_dir = os.path.join(build_dir, "aom")
|
|
2060
|
+
aom_install_dir = os.path.join(install_dir, "aom")
|
|
2061
|
+
rm_rf(aom_source_dir)
|
|
2062
|
+
rm_rf(aom_build_dir)
|
|
2063
|
+
rm_rf(aom_install_dir)
|
|
2064
|
+
git_clone_shallow(
|
|
2065
|
+
"https://aomedia.googlesource.com/aom",
|
|
2066
|
+
version,
|
|
2067
|
+
aom_source_dir,
|
|
2068
|
+
)
|
|
2069
|
+
with cd(aom_source_dir):
|
|
2070
|
+
cmd(
|
|
2071
|
+
[
|
|
2072
|
+
"cmake",
|
|
2073
|
+
"-B",
|
|
2074
|
+
aom_build_dir,
|
|
2075
|
+
f"-DCMAKE_INSTALL_PREFIX={cmake_path(aom_install_dir)}",
|
|
2076
|
+
f"-DCMAKE_BUILD_TYPE={configuration}",
|
|
2077
|
+
"-DENABLE_DOCS=OFF",
|
|
2078
|
+
"-DENABLE_TESTS=OFF",
|
|
2079
|
+
*cmake_args,
|
|
2080
|
+
]
|
|
2081
|
+
)
|
|
2082
|
+
cmd(
|
|
2083
|
+
[
|
|
2084
|
+
"cmake",
|
|
2085
|
+
"--build",
|
|
2086
|
+
aom_build_dir,
|
|
2087
|
+
f"-j{multiprocessing.cpu_count()}",
|
|
2088
|
+
"--config",
|
|
2089
|
+
"Release",
|
|
2090
|
+
]
|
|
2091
|
+
)
|
|
2092
|
+
cmd(["cmake", "--install", aom_build_dir])
|
|
2093
|
+
|
|
2094
|
+
|
|
1806
2095
|
class PlatformTarget(object):
|
|
1807
2096
|
def __init__(self, os, osver, arch, extra=None):
|
|
1808
2097
|
self.os = os
|
{sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk/sora_sdk_ext.cpython-311-darwin.so
RENAMED
|
Binary file
|
|
@@ -24,6 +24,7 @@ tests/test_capability.py
|
|
|
24
24
|
tests/test_degradation_preference.py
|
|
25
25
|
tests/test_encoded_transform.py
|
|
26
26
|
tests/test_intel_vpl.py
|
|
27
|
+
tests/test_key_frame_request.py
|
|
27
28
|
tests/test_messaging.py
|
|
28
29
|
tests/test_messaging_header.py
|
|
29
30
|
tests/test_nvidia_video_codec_sdk.py
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import time
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
|
+
from api import request_key_frame_api
|
|
5
6
|
from client import (
|
|
6
7
|
SoraClient,
|
|
7
8
|
SoraRole,
|
|
@@ -60,8 +61,70 @@ def test_amd_amf_available(settings):
|
|
|
60
61
|
@pytest.mark.parametrize(
|
|
61
62
|
"video_codec_type",
|
|
62
63
|
[
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
"AV1",
|
|
65
|
+
"H264",
|
|
66
|
+
"H265",
|
|
67
|
+
],
|
|
68
|
+
)
|
|
69
|
+
def test_amd_amf_key_frame_request(settings, video_codec_type):
|
|
70
|
+
sendonly = SoraClient(
|
|
71
|
+
settings,
|
|
72
|
+
SoraRole.SENDONLY,
|
|
73
|
+
audio=False,
|
|
74
|
+
video=True,
|
|
75
|
+
video_codec_type=video_codec_type,
|
|
76
|
+
video_codec_preference=SoraVideoCodecPreference(
|
|
77
|
+
codecs=[
|
|
78
|
+
SoraVideoCodecPreference.Codec(
|
|
79
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
80
|
+
encoder=SoraVideoCodecImplementation.AMD_AMF,
|
|
81
|
+
),
|
|
82
|
+
]
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
sendonly.connect(fake_video=True)
|
|
86
|
+
|
|
87
|
+
time.sleep(3)
|
|
88
|
+
|
|
89
|
+
assert sendonly.connection_id is not None
|
|
90
|
+
|
|
91
|
+
# キーフレーム要求 API を 3 秒間隔で 3 回呼び出す
|
|
92
|
+
api_count = 3
|
|
93
|
+
for _ in range(api_count):
|
|
94
|
+
response = request_key_frame_api(
|
|
95
|
+
settings.api_url, sendonly.channel_id, sendonly.connection_id
|
|
96
|
+
)
|
|
97
|
+
assert response.status_code == 200
|
|
98
|
+
time.sleep(3)
|
|
99
|
+
|
|
100
|
+
# 統計を取得する
|
|
101
|
+
sendonly_stats = sendonly.get_stats()
|
|
102
|
+
|
|
103
|
+
sendonly.disconnect()
|
|
104
|
+
|
|
105
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
106
|
+
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
107
|
+
|
|
108
|
+
print("video_codec_type:", video_codec_type)
|
|
109
|
+
print("keyFramesEncoded:", outbound_rtp_stats["keyFramesEncoded"])
|
|
110
|
+
print("pliCount:", outbound_rtp_stats["pliCount"])
|
|
111
|
+
print(
|
|
112
|
+
"keyFramesEncoded >= pliCount * 0.7:",
|
|
113
|
+
outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > api_count
|
|
117
|
+
assert outbound_rtp_stats["pliCount"] >= api_count
|
|
118
|
+
|
|
119
|
+
# PLI カウントの 50% 以上がキーフレームとしてエンコードされることを確認
|
|
120
|
+
assert outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@pytest.mark.skipif(os.environ.get("AMD_AMF") is None, reason="AMD AMF でのみ実行する")
|
|
124
|
+
@pytest.mark.parametrize(
|
|
125
|
+
"video_codec_type",
|
|
126
|
+
[
|
|
127
|
+
"AV1",
|
|
65
128
|
"H264",
|
|
66
129
|
"H265",
|
|
67
130
|
],
|
|
@@ -89,6 +152,8 @@ def test_amd_amf_sendonly_recvonly(settings, video_codec_type):
|
|
|
89
152
|
)
|
|
90
153
|
sendonly.connect(fake_video=True)
|
|
91
154
|
|
|
155
|
+
time.sleep(5)
|
|
156
|
+
|
|
92
157
|
recvonly = SoraClient(
|
|
93
158
|
settings,
|
|
94
159
|
SoraRole.RECVONLY,
|
|
@@ -123,7 +188,6 @@ def test_amd_amf_sendonly_recvonly(settings, video_codec_type):
|
|
|
123
188
|
|
|
124
189
|
# codec が無かったら StopIteration 例外が上がる
|
|
125
190
|
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
126
|
-
# H.264/H.265 が採用されているかどうか確認する
|
|
127
191
|
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
128
192
|
|
|
129
193
|
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
@@ -131,10 +195,13 @@ def test_amd_amf_sendonly_recvonly(settings, video_codec_type):
|
|
|
131
195
|
assert outbound_rtp_stats["encoderImplementation"] == "AMF"
|
|
132
196
|
assert outbound_rtp_stats["bytesSent"] > 0
|
|
133
197
|
assert outbound_rtp_stats["packetsSent"] > 0
|
|
198
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > 0
|
|
199
|
+
assert outbound_rtp_stats["pliCount"] > 0
|
|
200
|
+
# PLI カウントの 50% 以上がキーフレームとしてエンコードされることを確認
|
|
201
|
+
assert outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.5
|
|
134
202
|
|
|
135
203
|
# codec が無かったら StopIteration 例外が上がる
|
|
136
204
|
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
|
|
137
|
-
# H.264/H.265 が採用されているかどうか確認する
|
|
138
205
|
assert recvonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
139
206
|
|
|
140
207
|
# inbound-rtp が無かったら StopIteration 例外が上がる
|
|
@@ -142,6 +209,7 @@ def test_amd_amf_sendonly_recvonly(settings, video_codec_type):
|
|
|
142
209
|
assert inbound_rtp_stats["decoderImplementation"] == "AMF"
|
|
143
210
|
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
144
211
|
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
212
|
+
assert inbound_rtp_stats["keyFramesDecoded"] > 0
|
|
145
213
|
|
|
146
214
|
|
|
147
215
|
@pytest.mark.skipif(os.environ.get("AMD_AMF") is None, reason="AMD AMF でのみ実行する")
|
|
@@ -3,6 +3,7 @@ import platform
|
|
|
3
3
|
import time
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
|
+
from api import get_stats_connection_api, request_key_frame_api
|
|
6
7
|
from client import (
|
|
7
8
|
SoraClient,
|
|
8
9
|
SoraRole,
|
|
@@ -43,8 +44,8 @@ def test_intel_vpl_available():
|
|
|
43
44
|
case SoraVideoCodecType.VP9:
|
|
44
45
|
assert c.decoder is True
|
|
45
46
|
# VPL 的に VP9 は利用できるが、
|
|
46
|
-
# Sora Python SDK では VPL VP9 Encoder
|
|
47
|
-
assert c.encoder is
|
|
47
|
+
# Sora Python SDK では VPL VP9 Encoder が正常に動作しない
|
|
48
|
+
assert c.encoder is True
|
|
48
49
|
case SoraVideoCodecType.AV1:
|
|
49
50
|
# チップによって対応指定ないものがあるので判断しない
|
|
50
51
|
# assert c.decoder is True
|
|
@@ -60,6 +61,69 @@ def test_intel_vpl_available():
|
|
|
60
61
|
pytest.fail(f"未実装の codec_type: {c.type}")
|
|
61
62
|
|
|
62
63
|
|
|
64
|
+
@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
|
|
65
|
+
@pytest.mark.parametrize(
|
|
66
|
+
"video_codec_type",
|
|
67
|
+
[
|
|
68
|
+
"VP9",
|
|
69
|
+
"AV1",
|
|
70
|
+
"H264",
|
|
71
|
+
"H265",
|
|
72
|
+
],
|
|
73
|
+
)
|
|
74
|
+
def test_intel_vpl_key_frame_request(settings, video_codec_type):
|
|
75
|
+
sendonly = SoraClient(
|
|
76
|
+
settings,
|
|
77
|
+
SoraRole.SENDONLY,
|
|
78
|
+
audio=False,
|
|
79
|
+
video=True,
|
|
80
|
+
video_codec_type=video_codec_type,
|
|
81
|
+
video_codec_preference=SoraVideoCodecPreference(
|
|
82
|
+
codecs=[
|
|
83
|
+
SoraVideoCodecPreference.Codec(
|
|
84
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
85
|
+
encoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
86
|
+
),
|
|
87
|
+
]
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
sendonly.connect(fake_video=True)
|
|
91
|
+
|
|
92
|
+
time.sleep(3)
|
|
93
|
+
|
|
94
|
+
assert sendonly.connection_id is not None
|
|
95
|
+
|
|
96
|
+
# キーフレーム要求 API を 3 秒間隔で 3 回呼び出す
|
|
97
|
+
api_count = 3
|
|
98
|
+
for _ in range(api_count):
|
|
99
|
+
response = request_key_frame_api(
|
|
100
|
+
settings.api_url, sendonly.channel_id, sendonly.connection_id
|
|
101
|
+
)
|
|
102
|
+
assert response.status_code == 200
|
|
103
|
+
time.sleep(3)
|
|
104
|
+
|
|
105
|
+
# 統計を取得する
|
|
106
|
+
sendonly_stats = sendonly.get_stats()
|
|
107
|
+
|
|
108
|
+
sendonly.disconnect()
|
|
109
|
+
|
|
110
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
111
|
+
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
112
|
+
|
|
113
|
+
# 3 回以上
|
|
114
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > api_count
|
|
115
|
+
assert outbound_rtp_stats["pliCount"] >= api_count
|
|
116
|
+
print("keyFramesEncoded:", outbound_rtp_stats["keyFramesEncoded"])
|
|
117
|
+
print("pliCount:", outbound_rtp_stats["pliCount"])
|
|
118
|
+
|
|
119
|
+
# PLI カウントの 50% 以上がキーフレームとしてエンコードされることを確認
|
|
120
|
+
assert outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7
|
|
121
|
+
print(
|
|
122
|
+
"keyFramesEncoded >= pliCount * 0.7:",
|
|
123
|
+
outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
63
127
|
@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
|
|
64
128
|
@pytest.mark.parametrize(
|
|
65
129
|
(
|
|
@@ -73,14 +137,17 @@ def test_intel_vpl_available():
|
|
|
73
137
|
# FIXME: AV1 では、解像度が一定数より低くなる場合、エラーになるのでコメントアウトしている
|
|
74
138
|
[
|
|
75
139
|
# 1080p
|
|
140
|
+
("VP9", "libvpl", 1920, 1080, 3),
|
|
76
141
|
("AV1", "libvpl", 1920, 1080, 3),
|
|
77
142
|
("H264", "libvpl", 1920, 1080, 3),
|
|
78
143
|
("H265", "libvpl", 1920, 1080, 3),
|
|
79
144
|
# 720p
|
|
145
|
+
("VP9", "libvpl", 1280, 720, 3),
|
|
80
146
|
("AV1", "libvpl", 1280, 720, 3),
|
|
81
147
|
("H264", "libvpl", 1280, 720, 3),
|
|
82
148
|
("H265", "libvpl", 1280, 720, 3),
|
|
83
149
|
# 540p
|
|
150
|
+
("VP9", "libvpl", 960, 540, 3),
|
|
84
151
|
("AV1", "libvpl", 960, 540, 3),
|
|
85
152
|
("H264", "libvpl", 960, 540, 3),
|
|
86
153
|
("H265", "libvpl", 960, 540, 3),
|
|
@@ -139,7 +206,7 @@ def test_intel_vpl_simulcast(
|
|
|
139
206
|
)
|
|
140
207
|
sendonly.connect(fake_video=True)
|
|
141
208
|
|
|
142
|
-
time.sleep(
|
|
209
|
+
time.sleep(3)
|
|
143
210
|
|
|
144
211
|
sendonly_stats = sendonly.get_stats()
|
|
145
212
|
|
|
@@ -218,6 +285,7 @@ def test_intel_vpl_simulcast(
|
|
|
218
285
|
@pytest.mark.parametrize(
|
|
219
286
|
"video_codec_type",
|
|
220
287
|
[
|
|
288
|
+
"VP9",
|
|
221
289
|
"AV1",
|
|
222
290
|
"H264",
|
|
223
291
|
"H265",
|
|
@@ -246,6 +314,8 @@ def test_intel_vpl_sendonly_recvonly(settings, video_codec_type):
|
|
|
246
314
|
)
|
|
247
315
|
sendonly.connect(fake_video=True)
|
|
248
316
|
|
|
317
|
+
time.sleep(3)
|
|
318
|
+
|
|
249
319
|
recvonly = SoraClient(
|
|
250
320
|
settings,
|
|
251
321
|
SoraRole.RECVONLY,
|
|
@@ -260,7 +330,7 @@ def test_intel_vpl_sendonly_recvonly(settings, video_codec_type):
|
|
|
260
330
|
)
|
|
261
331
|
recvonly.connect()
|
|
262
332
|
|
|
263
|
-
time.sleep(
|
|
333
|
+
time.sleep(3)
|
|
264
334
|
|
|
265
335
|
sendonly_stats = sendonly.get_stats()
|
|
266
336
|
recvonly_stats = recvonly.get_stats()
|
|
@@ -346,7 +416,7 @@ def test_intel_vpl_av1_mini_resolution(
|
|
|
346
416
|
)
|
|
347
417
|
sendonly.connect(fake_video=True)
|
|
348
418
|
|
|
349
|
-
time.sleep(
|
|
419
|
+
time.sleep(3)
|
|
350
420
|
|
|
351
421
|
assert sendonly.connect_message is not None
|
|
352
422
|
assert sendonly.connect_message["channel_id"] == settings.channel_id
|
|
@@ -384,21 +454,39 @@ def test_intel_vpl_av1_mini_resolution(
|
|
|
384
454
|
assert outbound_rtp_stats["packetsSent"] > 0
|
|
385
455
|
|
|
386
456
|
|
|
457
|
+
## VPL Decode
|
|
458
|
+
|
|
459
|
+
|
|
387
460
|
@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
|
|
388
|
-
|
|
461
|
+
@pytest.mark.parametrize(
|
|
462
|
+
(
|
|
463
|
+
"video_codec_type",
|
|
464
|
+
"encoder_implementation",
|
|
465
|
+
"decoder_implementation",
|
|
466
|
+
),
|
|
467
|
+
[
|
|
468
|
+
("VP9", "libvpx", "libvpl"),
|
|
469
|
+
("AV1", "libaom", "libvpl"),
|
|
470
|
+
],
|
|
471
|
+
)
|
|
472
|
+
def test_intel_vpl_decode(
|
|
473
|
+
settings, video_codec_type, encoder_implementation, decoder_implementation
|
|
474
|
+
):
|
|
389
475
|
"""
|
|
390
|
-
N100 などは AV1 のデコーディングに対応している
|
|
476
|
+
* N100 などは AV1 のデコーディングに対応している
|
|
477
|
+
* VPL VP9 はデコーダーは利用できるので、そのテスト
|
|
391
478
|
"""
|
|
392
479
|
sendonly = SoraClient(
|
|
393
480
|
settings,
|
|
394
481
|
SoraRole.SENDONLY,
|
|
395
482
|
audio=False,
|
|
396
483
|
video=True,
|
|
397
|
-
video_codec_type=
|
|
484
|
+
video_codec_type=video_codec_type,
|
|
398
485
|
video_codec_preference=SoraVideoCodecPreference(
|
|
399
486
|
codecs=[
|
|
400
487
|
SoraVideoCodecPreference.Codec(
|
|
401
|
-
type=
|
|
488
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
489
|
+
# エンコーダーはソフトウェアを利用する
|
|
402
490
|
encoder=SoraVideoCodecImplementation.INTERNAL,
|
|
403
491
|
),
|
|
404
492
|
]
|
|
@@ -406,13 +494,15 @@ def test_intel_vpl_decoding_av1(settings):
|
|
|
406
494
|
)
|
|
407
495
|
sendonly.connect(fake_video=True)
|
|
408
496
|
|
|
497
|
+
time.sleep(3)
|
|
498
|
+
|
|
409
499
|
recvonly = SoraClient(
|
|
410
500
|
settings,
|
|
411
501
|
SoraRole.RECVONLY,
|
|
412
502
|
video_codec_preference=SoraVideoCodecPreference(
|
|
413
503
|
codecs=[
|
|
414
504
|
SoraVideoCodecPreference.Codec(
|
|
415
|
-
type=
|
|
505
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
416
506
|
decoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
417
507
|
),
|
|
418
508
|
]
|
|
@@ -420,7 +510,7 @@ def test_intel_vpl_decoding_av1(settings):
|
|
|
420
510
|
)
|
|
421
511
|
recvonly.connect()
|
|
422
512
|
|
|
423
|
-
time.sleep(
|
|
513
|
+
time.sleep(3)
|
|
424
514
|
|
|
425
515
|
sendonly_stats = sendonly.get_stats()
|
|
426
516
|
recvonly_stats = recvonly.get_stats()
|
|
@@ -431,61 +521,52 @@ def test_intel_vpl_decoding_av1(settings):
|
|
|
431
521
|
# offer の sdp に video_codec_type が含まれているかどうかを確認している
|
|
432
522
|
assert sendonly.offer_message is not None
|
|
433
523
|
assert "sdp" in sendonly.offer_message
|
|
434
|
-
assert
|
|
524
|
+
assert video_codec_type in sendonly.offer_message["sdp"]
|
|
435
525
|
|
|
436
526
|
# answer の sdp に video_codec_type が含まれているかどうかを確認している
|
|
437
527
|
assert sendonly.answer_message is not None
|
|
438
528
|
assert "sdp" in sendonly.answer_message
|
|
439
|
-
assert
|
|
529
|
+
assert video_codec_type in sendonly.answer_message["sdp"]
|
|
440
530
|
|
|
441
531
|
# codec が無かったら StopIteration 例外が上がる
|
|
442
532
|
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
443
|
-
|
|
533
|
+
# VP9 が採用されているかどうか確認する
|
|
534
|
+
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
444
535
|
|
|
445
536
|
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
446
537
|
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
447
|
-
assert outbound_rtp_stats["encoderImplementation"] ==
|
|
538
|
+
assert outbound_rtp_stats["encoderImplementation"] == encoder_implementation
|
|
448
539
|
assert outbound_rtp_stats["bytesSent"] > 0
|
|
449
540
|
assert outbound_rtp_stats["packetsSent"] > 0
|
|
541
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > 0
|
|
542
|
+
assert outbound_rtp_stats["pliCount"] > 0
|
|
450
543
|
|
|
451
544
|
# codec が無かったら StopIteration 例外が上がる
|
|
452
545
|
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
|
|
453
|
-
|
|
546
|
+
# VP9 が採用されているかどうか確認する
|
|
547
|
+
assert recvonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
454
548
|
|
|
455
549
|
# inbound-rtp が無かったら StopIteration 例外が上がる
|
|
456
550
|
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
|
|
457
|
-
assert inbound_rtp_stats["decoderImplementation"] ==
|
|
551
|
+
assert inbound_rtp_stats["decoderImplementation"] == decoder_implementation
|
|
458
552
|
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
459
553
|
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
## VP9
|
|
554
|
+
assert inbound_rtp_stats["keyFramesDecoded"] > 0
|
|
463
555
|
|
|
464
556
|
|
|
465
557
|
@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
|
|
466
|
-
|
|
467
|
-
strict=True, reason="VP9 は C++ SDK の Intel VPL で対応できていないのでテストが失敗する"
|
|
468
|
-
)
|
|
469
|
-
@pytest.mark.parametrize(
|
|
470
|
-
(
|
|
471
|
-
"video_codec_type",
|
|
472
|
-
"expected_implementation",
|
|
473
|
-
),
|
|
474
|
-
[
|
|
475
|
-
("VP9", "libvpl"),
|
|
476
|
-
],
|
|
477
|
-
)
|
|
478
|
-
def test_intel_vpl_vp9_failed(settings, video_codec_type, expected_implementation):
|
|
558
|
+
def test_intel_vpl_av1_rtp_hdr_ext(settings):
|
|
479
559
|
sendonly = SoraClient(
|
|
480
560
|
settings,
|
|
481
561
|
SoraRole.SENDONLY,
|
|
482
562
|
audio=False,
|
|
483
563
|
video=True,
|
|
484
|
-
video_codec_type=
|
|
564
|
+
video_codec_type="AV1",
|
|
485
565
|
video_codec_preference=SoraVideoCodecPreference(
|
|
486
566
|
codecs=[
|
|
487
567
|
SoraVideoCodecPreference.Codec(
|
|
488
|
-
type=
|
|
568
|
+
type=codec_type_string_to_codec_type("AV1"),
|
|
569
|
+
# エンコーダーはソフトウェアを利用する
|
|
489
570
|
encoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
490
571
|
),
|
|
491
572
|
]
|
|
@@ -493,113 +574,36 @@ def test_intel_vpl_vp9_failed(settings, video_codec_type, expected_implementatio
|
|
|
493
574
|
)
|
|
494
575
|
sendonly.connect(fake_video=True)
|
|
495
576
|
|
|
496
|
-
time.sleep(
|
|
497
|
-
|
|
498
|
-
assert sendonly.connect_message is not None
|
|
499
|
-
assert sendonly.connect_message["channel_id"] == settings.channel_id
|
|
500
|
-
assert "video" in sendonly.connect_message
|
|
501
|
-
assert sendonly.connect_message["video"]["codec_type"] == video_codec_type
|
|
577
|
+
time.sleep(3)
|
|
502
578
|
|
|
503
|
-
|
|
579
|
+
assert sendonly.connection_id is not None
|
|
504
580
|
assert sendonly.offer_message is not None
|
|
505
581
|
assert "sdp" in sendonly.offer_message
|
|
506
|
-
assert
|
|
582
|
+
assert "AV1" in sendonly.offer_message["sdp"]
|
|
583
|
+
assert (
|
|
584
|
+
"https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension"
|
|
585
|
+
in sendonly.offer_message["sdp"]
|
|
586
|
+
)
|
|
507
587
|
|
|
508
|
-
# answer の sdp に video_codec_type が含まれているかどうかを確認している
|
|
509
588
|
assert sendonly.answer_message is not None
|
|
510
589
|
assert "sdp" in sendonly.answer_message
|
|
511
|
-
assert
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
sendonly.disconnect()
|
|
516
|
-
|
|
517
|
-
# codec が無かったら StopIteration 例外が上がる
|
|
518
|
-
codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
519
|
-
# VP9 が採用されているかどうか確認する
|
|
520
|
-
assert codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
521
|
-
|
|
522
|
-
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
523
|
-
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
524
|
-
# ここで libvpx になって失敗する
|
|
525
|
-
assert outbound_rtp_stats["encoderImplementation"] == expected_implementation
|
|
526
|
-
assert outbound_rtp_stats["bytesSent"] > 0
|
|
527
|
-
assert outbound_rtp_stats["packetsSent"] > 0
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
|
|
531
|
-
def test_intel_vpl_decoding_vp9(settings):
|
|
532
|
-
"""
|
|
533
|
-
VPL VP9 はデコーダーは利用できるので、そのテスト
|
|
534
|
-
"""
|
|
535
|
-
sendonly = SoraClient(
|
|
536
|
-
settings,
|
|
537
|
-
SoraRole.SENDONLY,
|
|
538
|
-
audio=False,
|
|
539
|
-
video=True,
|
|
540
|
-
video_codec_type="VP9",
|
|
541
|
-
video_codec_preference=SoraVideoCodecPreference(
|
|
542
|
-
codecs=[
|
|
543
|
-
SoraVideoCodecPreference.Codec(
|
|
544
|
-
type=SoraVideoCodecType.VP9,
|
|
545
|
-
# VPL で VP9 Encoder は正常に動作しないので無効化しているので INTERNAL を指定
|
|
546
|
-
encoder=SoraVideoCodecImplementation.INTERNAL,
|
|
547
|
-
),
|
|
548
|
-
]
|
|
549
|
-
),
|
|
590
|
+
assert "AV1" in sendonly.answer_message["sdp"]
|
|
591
|
+
assert (
|
|
592
|
+
"https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension"
|
|
593
|
+
in sendonly.answer_message["sdp"]
|
|
550
594
|
)
|
|
551
|
-
sendonly.connect(fake_video=True)
|
|
552
595
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
video_codec_preference=SoraVideoCodecPreference(
|
|
557
|
-
codecs=[
|
|
558
|
-
SoraVideoCodecPreference.Codec(
|
|
559
|
-
type=SoraVideoCodecType.VP9,
|
|
560
|
-
decoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
561
|
-
),
|
|
562
|
-
]
|
|
563
|
-
),
|
|
596
|
+
# コネクションの統計情報を取得
|
|
597
|
+
response = get_stats_connection_api(
|
|
598
|
+
settings.api_url, sendonly.channel_id, sendonly.connection_id
|
|
564
599
|
)
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
sendonly_stats = sendonly.get_stats()
|
|
570
|
-
recvonly_stats = recvonly.get_stats()
|
|
600
|
+
# FIX: ここで失敗すると disconnect が実行されずメモリーリークになる
|
|
601
|
+
assert response.status_code == 200
|
|
602
|
+
stats = response.json()
|
|
571
603
|
|
|
572
604
|
sendonly.disconnect()
|
|
573
|
-
recvonly.disconnect()
|
|
574
605
|
|
|
575
|
-
#
|
|
576
|
-
assert
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
# answer の sdp に video_codec_type が含まれているかどうかを確認している
|
|
581
|
-
assert sendonly.answer_message is not None
|
|
582
|
-
assert "sdp" in sendonly.answer_message
|
|
583
|
-
assert "VP9" in sendonly.answer_message["sdp"]
|
|
584
|
-
|
|
585
|
-
# codec が無かったら StopIteration 例外が上がる
|
|
586
|
-
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
587
|
-
# VP9 が採用されているかどうか確認する
|
|
588
|
-
assert sendonly_codec_stats["mimeType"] == "video/VP9"
|
|
589
|
-
|
|
590
|
-
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
591
|
-
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
592
|
-
assert outbound_rtp_stats["encoderImplementation"] == "libvpx"
|
|
593
|
-
assert outbound_rtp_stats["bytesSent"] > 0
|
|
594
|
-
assert outbound_rtp_stats["packetsSent"] > 0
|
|
595
|
-
|
|
596
|
-
# codec が無かったら StopIteration 例外が上がる
|
|
597
|
-
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
|
|
598
|
-
# VP9 が採用されているかどうか確認する
|
|
599
|
-
assert recvonly_codec_stats["mimeType"] == "video/VP9"
|
|
600
|
-
|
|
601
|
-
# inbound-rtp が無かったら StopIteration 例外が上がる
|
|
602
|
-
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
|
|
603
|
-
assert inbound_rtp_stats["decoderImplementation"] == "libvpl"
|
|
604
|
-
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
605
|
-
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
606
|
+
# AV1 の RTP ヘッダー拡張が送られてきていることを確認
|
|
607
|
+
assert stats["rtp_hdrext"]["total_received_rtp_hdrext_av1_rtp_sepc"] > 0, (
|
|
608
|
+
"Dependency Descriptor RTP Header Extension が Python SDK から送られてきていません"
|
|
609
|
+
)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from api import request_key_frame_api
|
|
5
|
+
from client import (
|
|
6
|
+
SoraClient,
|
|
7
|
+
SoraRole,
|
|
8
|
+
codec_type_string_to_codec_type,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from sora_sdk import (
|
|
12
|
+
SoraVideoCodecImplementation,
|
|
13
|
+
SoraVideoCodecPreference,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.parametrize(
|
|
18
|
+
"video_codec_type",
|
|
19
|
+
[
|
|
20
|
+
"VP9",
|
|
21
|
+
"VP8",
|
|
22
|
+
"AV1",
|
|
23
|
+
],
|
|
24
|
+
)
|
|
25
|
+
def test_key_frame_request(settings, video_codec_type):
|
|
26
|
+
sendonly = SoraClient(
|
|
27
|
+
settings,
|
|
28
|
+
SoraRole.SENDONLY,
|
|
29
|
+
audio=False,
|
|
30
|
+
video=True,
|
|
31
|
+
video_codec_type=video_codec_type,
|
|
32
|
+
video_codec_preference=SoraVideoCodecPreference(
|
|
33
|
+
codecs=[
|
|
34
|
+
SoraVideoCodecPreference.Codec(
|
|
35
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
36
|
+
encoder=SoraVideoCodecImplementation.INTERNAL,
|
|
37
|
+
),
|
|
38
|
+
]
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
sendonly.connect(fake_video=True)
|
|
42
|
+
|
|
43
|
+
time.sleep(3)
|
|
44
|
+
|
|
45
|
+
assert sendonly.connection_id is not None
|
|
46
|
+
|
|
47
|
+
# キーフレーム要求 API を 3 秒間隔で 3 回呼び出す
|
|
48
|
+
api_count = 3
|
|
49
|
+
for _ in range(api_count):
|
|
50
|
+
response = request_key_frame_api(
|
|
51
|
+
settings.api_url, sendonly.channel_id, sendonly.connection_id
|
|
52
|
+
)
|
|
53
|
+
assert response.status_code == 200
|
|
54
|
+
time.sleep(3)
|
|
55
|
+
|
|
56
|
+
# 統計を取得する
|
|
57
|
+
sendonly_stats = sendonly.get_stats()
|
|
58
|
+
|
|
59
|
+
sendonly.disconnect()
|
|
60
|
+
|
|
61
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
62
|
+
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
63
|
+
|
|
64
|
+
# 3 回以上
|
|
65
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > api_count
|
|
66
|
+
assert outbound_rtp_stats["pliCount"] >= api_count
|
|
67
|
+
print("keyFramesEncoded:", outbound_rtp_stats["keyFramesEncoded"])
|
|
68
|
+
print("pliCount:", outbound_rtp_stats["pliCount"])
|
|
69
|
+
|
|
70
|
+
# PLI カウントの 50% 以上がキーフレームとしてエンコードされることを確認
|
|
71
|
+
assert outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7
|
|
72
|
+
print(
|
|
73
|
+
"keyFramesEncoded >= pliCount * 0.7:",
|
|
74
|
+
outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7,
|
|
75
|
+
)
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import time
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
|
+
from api import request_key_frame_api
|
|
5
6
|
from client import (
|
|
6
7
|
SoraClient,
|
|
7
8
|
SoraRole,
|
|
@@ -56,6 +57,70 @@ def test_nvidia_video_codec_sdk_available():
|
|
|
56
57
|
pytest.fail(f"未実装の codec_type: {c.type}")
|
|
57
58
|
|
|
58
59
|
|
|
60
|
+
@pytest.mark.skipif(
|
|
61
|
+
os.environ.get("NVIDIA_VIDEO_CODEC_SDK") is None, reason="NVIDIA Video Codec SDK でのみ実行する"
|
|
62
|
+
)
|
|
63
|
+
@pytest.mark.parametrize(
|
|
64
|
+
"video_codec_type",
|
|
65
|
+
[
|
|
66
|
+
"AV1",
|
|
67
|
+
"H264",
|
|
68
|
+
"H265",
|
|
69
|
+
],
|
|
70
|
+
)
|
|
71
|
+
def test_intel_vpl_key_frame_request(settings, video_codec_type):
|
|
72
|
+
sendonly = SoraClient(
|
|
73
|
+
settings,
|
|
74
|
+
SoraRole.SENDONLY,
|
|
75
|
+
audio=False,
|
|
76
|
+
video=True,
|
|
77
|
+
video_codec_type=video_codec_type,
|
|
78
|
+
video_codec_preference=SoraVideoCodecPreference(
|
|
79
|
+
codecs=[
|
|
80
|
+
SoraVideoCodecPreference.Codec(
|
|
81
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
82
|
+
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
83
|
+
),
|
|
84
|
+
]
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
sendonly.connect(fake_video=True)
|
|
88
|
+
|
|
89
|
+
time.sleep(3)
|
|
90
|
+
|
|
91
|
+
assert sendonly.connection_id is not None
|
|
92
|
+
|
|
93
|
+
# キーフレーム要求 API を 3 秒間隔で 3 回呼び出す
|
|
94
|
+
api_count = 3
|
|
95
|
+
for _ in range(api_count):
|
|
96
|
+
response = request_key_frame_api(
|
|
97
|
+
settings.api_url, sendonly.channel_id, sendonly.connection_id
|
|
98
|
+
)
|
|
99
|
+
assert response.status_code == 200
|
|
100
|
+
time.sleep(3)
|
|
101
|
+
|
|
102
|
+
# 統計を取得する
|
|
103
|
+
sendonly_stats = sendonly.get_stats()
|
|
104
|
+
|
|
105
|
+
sendonly.disconnect()
|
|
106
|
+
|
|
107
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
108
|
+
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
109
|
+
|
|
110
|
+
# 3 回以上
|
|
111
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > api_count
|
|
112
|
+
assert outbound_rtp_stats["pliCount"] >= api_count
|
|
113
|
+
print("keyFramesEncoded:", outbound_rtp_stats["keyFramesEncoded"])
|
|
114
|
+
print("pliCount:", outbound_rtp_stats["pliCount"])
|
|
115
|
+
|
|
116
|
+
# PLI カウントの 50% 以上がキーフレームとしてエンコードされることを確認
|
|
117
|
+
assert outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7
|
|
118
|
+
print(
|
|
119
|
+
"keyFramesEncoded >= pliCount * 0.7:",
|
|
120
|
+
outbound_rtp_stats["keyFramesEncoded"] >= outbound_rtp_stats["pliCount"] * 0.7,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
59
124
|
@pytest.mark.skipif(
|
|
60
125
|
os.environ.get("NVIDIA_VIDEO_CODEC_SDK") is None, reason="NVIDIA Video Codec SDK でのみ実行する"
|
|
61
126
|
)
|
|
@@ -68,6 +68,8 @@ def test_sendonly_recvonly_video(
|
|
|
68
68
|
)
|
|
69
69
|
sendonly.connect(fake_video=True)
|
|
70
70
|
|
|
71
|
+
time.sleep(5)
|
|
72
|
+
|
|
71
73
|
recvonly = SoraClient(
|
|
72
74
|
settings,
|
|
73
75
|
SoraRole.RECVONLY,
|
|
@@ -91,6 +93,11 @@ def test_sendonly_recvonly_video(
|
|
|
91
93
|
assert outbound_rtp_stats["encoderImplementation"] == encoder_implementation
|
|
92
94
|
assert outbound_rtp_stats["bytesSent"] > 0
|
|
93
95
|
assert outbound_rtp_stats["packetsSent"] > 0
|
|
96
|
+
assert outbound_rtp_stats["keyFramesEncoded"] > 0
|
|
97
|
+
assert outbound_rtp_stats["pliCount"] > 0
|
|
98
|
+
|
|
99
|
+
print("keyFramesEncoded:", outbound_rtp_stats["keyFramesEncoded"])
|
|
100
|
+
print("pliCount:", outbound_rtp_stats["pliCount"])
|
|
94
101
|
|
|
95
102
|
# codec が無かったら StopIteration 例外が上がる
|
|
96
103
|
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
|
|
@@ -101,3 +108,6 @@ def test_sendonly_recvonly_video(
|
|
|
101
108
|
assert inbound_rtp_stats["decoderImplementation"] == decoder_implementation
|
|
102
109
|
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
103
110
|
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
111
|
+
assert inbound_rtp_stats["keyFramesDecoded"] > 0
|
|
112
|
+
|
|
113
|
+
print("keyFrameDecoded:", inbound_rtp_stats["keyFramesDecoded"])
|
sora_sdk-2025.4.0.dev0/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2025.4.0.dev0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sora_sdk-2025.4.0.dev0 → sora_sdk-2025.4.0.dev2}/src/sora_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|