diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e0da9393..7057955b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -160,12 +160,19 @@ jobs: - name: ubuntu-20.04_x86_64 runs-on: ubuntu-20.04 os: ubuntu + arch: x86_64 - name: ubuntu-22.04_x86_64 runs-on: ubuntu-22.04 os: ubuntu + arch: x86_64 - name: ubuntu-24.04_x86_64 runs-on: ubuntu-24.04 os: ubuntu + arch: x86_64 + - name: ubuntu-24.04_armv8 + runs-on: ubuntu-24.04 + os: ubuntu + arch: armv8 - name: android runs-on: ubuntu-22.04 os: android @@ -216,7 +223,7 @@ jobs: Pin-Priority: 990 EOF - name: Install deps for ${{ matrix.platform.name }} - if: matrix.platform.os == 'ubuntu' + if: matrix.platform.os == 'ubuntu' && matrix.platform.arch == 'x86_64' run: | source VERSION sudo apt-get update @@ -238,6 +245,12 @@ jobs: # Intel Media SDK のために libva-dev, libdrm-dev を入れる DEBIAN_FRONTEND=noninteractive sudo apt-get -y install libva-dev libdrm-dev + - name: Install deps for ${{ matrix.platform.name }} + if: matrix.platform.os == 'ubuntu' && matrix.platform.arch == 'armv8' + run: | + sudo apt-get -y install multistrap binutils-aarch64-linux-gnu + # multistrap に insecure なリポジトリからの取得を許可する設定を入れる + sudo sed -e 's/Apt::Get::AllowUnauthenticated=true/Apt::Get::AllowUnauthenticated=true";\n$config_str .= " -o Acquire::AllowInsecureRepositories=true/' -i /usr/sbin/multistrap - name: Install deps for Android if: matrix.platform.os == 'android' run: | @@ -319,6 +332,9 @@ jobs: - uses: ./.github/actions/download with: platform: ubuntu-24.04_x86_64 + - uses: ./.github/actions/download + with: + platform: ubuntu-24.04_armv8 - uses: ./.github/actions/download with: platform: android diff --git a/CHANGES.md b/CHANGES.md index ec48e616..f241b8fd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,8 +11,58 @@ ## develop +- [UPDATE] VPL を v2.13.0 に上げる + - @voluntas +- [UPDATE] CMake を 3.30.4 にあげる + - @voluntas +- [UPDATE] Boost を 1.86.0 にあげる + - @voluntas +- [UPDATE] libwebrtc を m129.6668.1.0 にあげる + - H.265 Patch の修正に伴い、C++ SDK の H.265 に関する設定を変更 + - examples と test に `rtc::CreateRandomString` のヘッダを追加 + - `SetRtpTimestamp` を `frame.timestamp` から `frame.rtp_timestamp` に変更 + - @tnoho @torikizi +- [UPDATE] Xcode のバージョンを 15.4 にあげる + - @tnoho +- [UPDATE] SDL を 2.30.8 に上げる + - @torikizi +- [UPDATE] BLEND2D_VERSION を上げる + - @torikizi +- [UPDATE] ASMJIT_VERSION を上げる + - @torikizi +- [ADD] シグナリングメッセージを取得できるよう OnSignalingMessage を SoraSignalingObserver に追加する + - @tnoho - [ADD] Intel VPL で AV1 エンコーダを動くようにする - @tnoho +- [ADD] ルート証明書を指定可能にする + - @melpon +- [ADD] Ubuntu 24.04 armv8 に対応する + - @melpon +- [ADD] VERSION と examples/VERSION のバージョンをチェックする仕組みを追加 + - @melpon +- [ADD] WebSocket の Close を取得できるよう SendOnWsClose を SoraSignalingObserver に追加する + - @tnoho +- [FIX] HTTP Proxy 利用時の Websocket 初期化で insecure_ メンバ変数が初期化されていなかったのを修正 + - @melpon +- [FIX] SoraSignalingConfig の client_cert と client_key に渡す必要がある値を、ファイルパスからファイルの内容に修正 + - Android の場合、jar に纏められたファイルからファイルパスが取得できないため + - @melpon +- [FIX] SoraSignalingConfig の client_cert と client_key の型を `std::string` から `std::optional` に修正 + - @melpon + +### misc + +- [UPDATE] SDL2 を 2.30.7 にあげる + - @voluntas +- [ADD] sumomo に証明書に関するオプションを追加する + - サーバー証明書の検証を行わないようにするオプション `--insecure` を追加 + - CA 証明書を指定するオプション `--ca-cert` を追加 + - 指定できるファイルは PEM 形式 + - クライアント認証に関するオプション `--client-cert`, `--client-key` を追加 + - 指定できるファイルは PEM 形式 + - @melpon +- [ADD] Ubuntu 24.04 armv8 向けの example を追加する + - @melpon ## 2024.7.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 91a5bbf4..a8f56ac1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,11 @@ elseif (SORA_TARGET STREQUAL "ubuntu-24.04_x86_64") set(SORA_TARGET_OS_VERSION "24.04") set(SORA_TARGET_ARCH "x86_64") set(SORA_TARGET_DEF "SORA_CPP_SDK_UBUNTU_2404") +elseif (SORA_TARGET STREQUAL "ubuntu-24.04_armv8") + set(SORA_TARGET_OS "ubuntu") + set(SORA_TARGET_OS_VERSION "24.04") + set(SORA_TARGET_ARCH "armv8") + set(SORA_TARGET_DEF "SORA_CPP_SDK_UBUNTU_2404") endif() list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) @@ -304,6 +309,9 @@ if (SORA_TARGET_OS STREQUAL "windows") # VS のバージョンと _MSC_VER のリストは以下を参照: # https://devblogs.microsoft.com/cppblog/msvc-toolset-minor-version-number-14-40-in-vs-2022-v17-10/ -allow-unsupported-compiler + # 更に STL が CUDA 12.4 以上のバージョンを要求するため、STL のバージョンも無視する + # ref: https://stackoverflow.com/questions/78515942/cuda-compatibility-with-visual-studio-2022-version-17-10 + -Xcompiler /D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -Xcompiler /utf-8 -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/third_party/NvCodec/include -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/third_party/NvCodec/NvCodec @@ -490,7 +498,7 @@ elseif (SORA_TARGET_OS STREQUAL "ubuntu") third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp PROPERTIES - COMPILE_OPTIONS "-xcuda;--cuda-gpu-arch=sm_35;-std=gnu++17" + COMPILE_OPTIONS "-xcuda;--cuda-gpu-arch=sm_35;-std=gnu++17;-Wno-tautological-constant-out-of-range-compare" ) # CUDA を要求したくないので libsora.a に含める diff --git a/README.md b/README.md index 5bb104b4..1855b60c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ Please read before u - 各プラットフォームで利用可能な HWA への対応 - [Intel VPL](https://github.com/intel/libvpl) - - VP9 / AV1 / H.264 / H.265 + - AV1 / H.264 / H.265 + - VP9 のデコードは利用可能ですが、エンコードは現在既知の問題があります。詳細は [known_issues.md](doc/known_issues.md) をお読みください。 - [NVIDIA Video Codec SDK](https://developer.nvidia.com/video-codec-sdk) - VP9 / H.264 / H.265 - [NVIDIA JetPack SDK](https://developer.nvidia.com/embedded/jetpack) (JetPack 6) diff --git a/VERSION b/VERSION index 022dd55a..78fb1d0c 100644 --- a/VERSION +++ b/VERSION @@ -1,13 +1,13 @@ -SORA_CPP_SDK_VERSION=2024.7.0 -WEBRTC_BUILD_VERSION=m128.6613.2.0 -BOOST_VERSION=1.85.0 -CMAKE_VERSION=3.29.6 +SORA_CPP_SDK_VERSION=2024.8.0-canary.13 +WEBRTC_BUILD_VERSION=m129.6668.1.0 +BOOST_VERSION=1.86.0 +CMAKE_VERSION=3.30.4 CUDA_VERSION=11.8.0-1 ANDROID_NDK_VERSION=r26b ANDROID_NATIVE_API_LEVEL=29 ANDROID_SDK_CMDLINE_TOOLS_VERSION=9862592 -VPL_VERSION=v2.10.1 +VPL_VERSION=v2.13.0 OPENH264_VERSION=v2.4.1 -BLEND2D_VERSION=06c52b5267c3c39dc3b09611d1bf066cbff35fd1 -ASMJIT_VERSION=917f19d940935998aa9dfa7479368834451622f7 +BLEND2D_VERSION=ca5403c1d02b2bc9d2de581e4cb13e5e80f33860 +ASMJIT_VERSION=2e93826348d6cd1325a8b1f7629e193c58332da9 CATCH2_VERSION=v3.5.3 diff --git a/buildbase.py b/buildbase.py index b91e070b..367299df 100644 --- a/buildbase.py +++ b/buildbase.py @@ -354,7 +354,7 @@ def clone_and_checkout(url, version, dir, fetch, fetch_force): cmd(["git", "checkout", "-f", version]) -def git_clone_shallow(url, hash, dir): +def git_clone_shallow(url, hash, dir, submodule=False): rm_rf(dir) mkdir_p(dir) with cd(dir): @@ -362,6 +362,19 @@ def git_clone_shallow(url, hash, dir): cmd(["git", "remote", "add", "origin", url]) cmd(["git", "fetch", "--depth=1", "origin", hash]) cmd(["git", "reset", "--hard", "FETCH_HEAD"]) + if submodule: + cmd( + [ + "git", + "submodule", + "update", + "--init", + "--recursive", + "--recommend-shallow", + "--depth", + "1", + ] + ) def apply_patch(patch, dir, depth): @@ -384,6 +397,30 @@ def apply_patch(patch, dir, depth): cmd(["patch", f"-p{depth}"], stdin=stdin) +def apply_patch_text(patch_text, dir, depth): + with cd(dir): + logging.info(f"echo '{patch_text[:100]}...' | patch -p{depth} -") + directory = cmdcap(["git", "rev-parse", "--show-prefix"]) + if platform.system() == "Windows": + cmd( + [ + "git", + "apply", + f"-p{depth}", + "--ignore-space-change", + "--ignore-whitespace", + "--whitespace=nowarn", + f"--directory={directory}", + "-", + ], + input=BOOST_PATCH_SUPPORT_14_4, + text=True, + encoding="utf-8", + ) + else: + cmd(["patch", f"-p{depth}"], input=patch_text, text=True, encoding="utf-8") + + def copyfile_if_different(src, dst): if os.path.exists(dst) and filecmp.cmp(src, dst, shallow=False): return @@ -649,6 +686,8 @@ def build_and_install_boost( architecture, android_ndk, native_api_level, + address_model="64", + runtime_link=None, ): version_underscore = version.replace(".", "_") archive = download( @@ -659,26 +698,12 @@ def build_and_install_boost( with cd(os.path.join(build_dir, "boost")): bootstrap = ".\\bootstrap.bat" if target_os == "windows" else "./bootstrap.sh" b2 = "b2" if target_os == "windows" else "./b2" - runtime_link = "static" if target_os == "windows" else "shared" + if runtime_link is None: + runtime_link = "static" if target_os == "windows" else "shared" # Windows かつ Boost 1.85.0 の場合はパッチを当てる if target_os == "windows" and version == "1.85.0": - directory = cmdcap(["git", "rev-parse", "--show-prefix"]) - cmd( - [ - "git", - "apply", - "-p1", - "--ignore-space-change", - "--ignore-whitespace", - "--whitespace=nowarn", - f"--directory={directory}", - "-", - ], - input=BOOST_PATCH_SUPPORT_14_4, - text=True, - encoding="utf-8", - ) + apply_patch_text(BOOST_PATCH_SUPPORT_14_4, os.path.join(build_dir, "boost"), 1) cmd([bootstrap]) @@ -718,7 +743,7 @@ def build_and_install_boost( f"toolset={toolset}", f"visibility={visibility}", f"target-os={target_os}", - "address-model=64", + f"address-model={address_model}", "link=static", f"runtime-link={runtime_link}", "threading=multi", @@ -789,7 +814,7 @@ def build_and_install_boost( f"toolset={toolset}", f"visibility={visibility}", f"target-os={target_os}", - "address-model=64", + f"address-model={address_model}", "link=static", f"runtime-link={runtime_link}", "threading=multi", @@ -817,7 +842,7 @@ def build_and_install_boost( f"toolset={toolset}", f"visibility={visibility}", f"target-os={target_os}", - "address-model=64", + f"address-model={address_model}", "link=static", f"runtime-link={runtime_link}", "threading=multi", @@ -839,23 +864,23 @@ def install_sora(version, source_dir, install_dir, platform: str): extract(archive, output_dir=install_dir, output_dirname="sora") -def install_sora_and_deps(platform: str, source_dir: str, install_dir: str): - version = read_version_file("VERSION") - +def install_sora_and_deps( + sora_version: str, boost_version: str, platform: str, source_dir: str, install_dir: str +): # Boost install_boost_args = { - "version": version["BOOST_VERSION"], + "version": boost_version, "version_file": os.path.join(install_dir, "boost.version"), "source_dir": source_dir, "install_dir": install_dir, - "sora_version": version["SORA_CPP_SDK_VERSION"], + "sora_version": sora_version, "platform": platform, } install_boost(**install_boost_args) # Sora C++ SDK install_sora_args = { - "version": version["SORA_CPP_SDK_VERSION"], + "version": sora_version, "version_file": os.path.join(install_dir, "sora.version"), "source_dir": source_dir, "install_dir": install_dir, @@ -903,10 +928,10 @@ def get_sora_info( @versioned -def install_rootfs(version, install_dir, conf): +def install_rootfs(version, install_dir, conf, arch="arm64"): rootfs_dir = os.path.join(install_dir, "rootfs") rm_rf(rootfs_dir) - cmd(["multistrap", "--no-auth", "-a", "arm64", "-d", rootfs_dir, "-f", conf]) + cmd(["multistrap", "--no-auth", "-a", arch, "-d", rootfs_dir, "-f", conf]) # 絶対パスのシンボリックリンクを相対パスに置き換えていく for dir, _, filenames in os.walk(rootfs_dir): for filename in filenames: @@ -950,12 +975,38 @@ def install_rootfs(version, install_dir, conf): @versioned -def install_android_ndk(version, install_dir, source_dir): - archive = download( - f"https://dl.google.com/android/repository/android-ndk-{version}-linux.zip", source_dir - ) +def install_android_ndk(version, install_dir, source_dir, platform="linux"): + if platform not in ("darwin", "linux"): + raise Exception(f"Not supported platform: {platform}") + + if platform == "darwin": + url = f"https://dl.google.com/android/repository/android-ndk-{version}-{platform}.dmg" + file = f"android-ndk-{version}-{platform}.dmg" + else: + url = f"https://dl.google.com/android/repository/android-ndk-{version}-{platform}.zip" + archive = download(url, source_dir) rm_rf(os.path.join(install_dir, "android-ndk")) - extract(archive, output_dir=install_dir, output_dirname="android-ndk") + if platform == "darwin": + cap = cmdcap(["hdiutil", "attach", os.path.join(source_dir, file)]) + # 以下のような結果が得られるはずなので、ここから /Volumes/Android NDK r26 のところだけ取り出す + # /dev/disk4 GUID_partition_scheme + # /dev/disk4s1 EFI + # /dev/disk4s2 Apple_HFS /Volumes/Android NDK r26 + volume = cap.split("\n")[-1].split("\t")[-1] + # AndroidNDK10792818.app みたいな感じの app があるはず + app = glob.glob("AndroidNDK*.app", root_dir=volume)[0] + # NDK ディレクトリをコピー + cmd( + [ + "cp", + "-r", + os.path.join(volume, app, "Contents", "NDK"), + os.path.join(install_dir, "android-ndk"), + ] + ) + cmdcap(["hdiutil", "detach", volume]) + else: + extract(archive, output_dir=install_dir, output_dirname="android-ndk") @versioned @@ -1432,11 +1483,160 @@ def install_protoc_gen_jsonif(version, source_dir, install_dir, platform: str): os.chmod(file.path, file.stat().st_mode | stat.S_IXUSR) +# iOS, Android などのクロスコンパイル環境で実行可能ファイルを生成しようとしてエラーになるのを防止するパッチ +# +# v1.64.1 をベースにパッチを当てている +# +# MEMO: gRPC の、submodule を含めて全ての diff を取得するコマンド +# git --no-pager diff --ignore-submodules && git submodule foreach --recursive 'git --no-pager diff --ignore-submodules --src-prefix a/$path/ --dst-prefix b/$path/' | grep -v '^Entering' +GRPC_PATCH_NO_EXECUTABLE = r""" +diff --git a/third_party/boringssl-with-bazel/CMakeLists.txt b/third_party/boringssl-with-bazel/CMakeLists.txt +index 6464e200f..c7bc417a1 100644 +--- a/third_party/boringssl-with-bazel/CMakeLists.txt ++++ b/third_party/boringssl-with-bazel/CMakeLists.txt +@@ -543,30 +543,6 @@ add_library( + + target_link_libraries(ssl crypto) + +-add_executable( +- bssl +- +- src/tool/args.cc +- src/tool/ciphers.cc +- src/tool/client.cc +- src/tool/const.cc +- src/tool/digest.cc +- src/tool/fd.cc +- src/tool/file.cc +- src/tool/generate_ech.cc +- src/tool/generate_ed25519.cc +- src/tool/genrsa.cc +- src/tool/pkcs12.cc +- src/tool/rand.cc +- src/tool/server.cc +- src/tool/sign.cc +- src/tool/speed.cc +- src/tool/tool.cc +- src/tool/transport_common.cc +-) +- +-target_link_libraries(bssl ssl crypto) +- + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + find_package(Threads REQUIRED) + target_link_libraries(crypto Threads::Threads) +diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt +index 7f1b69f..bcf5577 100644 +--- a/third_party/zlib/CMakeLists.txt ++++ b/third_party/zlib/CMakeLists.txt +@@ -147,10 +147,7 @@ if(MINGW) + set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) + endif(MINGW) + +-add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) + add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +-set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) +-set_target_properties(zlib PROPERTIES SOVERSION 1) + + if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version +@@ -160,22 +157,16 @@ if(NOT CYGWIN) + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc +- set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) + endif() + + if(UNIX) + # On unix-like platforms the library is almost always called libz +- set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) +- if(NOT APPLE) +- set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") +- endif() + elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version +- set_target_properties(zlib PROPERTIES SUFFIX "1.dll") + endif() + + if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) +- install(TARGETS zlib zlibstatic ++ install(TARGETS zlibstatic + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) +@@ -193,21 +184,3 @@ endif() + #============================================================================ + # Example binaries + #============================================================================ +- +-add_executable(example test/example.c) +-target_link_libraries(example zlib) +-add_test(example example) +- +-add_executable(minigzip test/minigzip.c) +-target_link_libraries(minigzip zlib) +- +-if(HAVE_OFF64_T) +- add_executable(example64 test/example.c) +- target_link_libraries(example64 zlib) +- set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +- add_test(example64 example64) +- +- add_executable(minigzip64 test/minigzip.c) +- target_link_libraries(minigzip64 zlib) +- set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +-endif() +""" + + +@versioned +def install_grpc(version, source_dir, build_dir, install_dir, debug: bool, cmake_args: List[str]): + grpc_source_dir = os.path.join(source_dir, "grpc") + grpc_build_dir = os.path.join(build_dir, "grpc") + grpc_install_dir = os.path.join(install_dir, "grpc") + rm_rf(grpc_source_dir) + rm_rf(grpc_build_dir) + rm_rf(grpc_install_dir) + git_clone_shallow("https://github.com/grpc/grpc.git", version, grpc_source_dir, submodule=True) + apply_patch_text(GRPC_PATCH_NO_EXECUTABLE, grpc_source_dir, 1) + mkdir_p(grpc_build_dir) + with cd(grpc_build_dir): + configuration = "Debug" if debug else "Release" + cmd( + [ + "cmake", + grpc_source_dir, + f"-DCMAKE_INSTALL_PREFIX={cmake_path(grpc_install_dir)}", + f"-DCMAKE_BUILD_TYPE={configuration}", + *cmake_args, + ] + ) + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + +@versioned +def install_ggrpc(version, install_dir): + ggrpc_install_dir = os.path.join(install_dir, "ggrpc") + rm_rf(ggrpc_install_dir) + git_clone_shallow("https://github.com/melpon/ggrpc.git", version, ggrpc_install_dir) + + +@versioned +def install_spdlog(version, install_dir): + spdlog_install_dir = os.path.join(install_dir, "spdlog") + rm_rf(spdlog_install_dir) + git_clone_shallow("https://github.com/gabime/spdlog.git", version, spdlog_install_dir) + + class PlatformTarget(object): - def __init__(self, os, osver, arch): + def __init__(self, os, osver, arch, extra=None): self.os = os self.osver = osver self.arch = arch + self.extra = extra @property def package_name(self): @@ -1453,7 +1653,13 @@ def package_name(self): if self.os == "raspberry-pi-os": return f"raspberry-pi-os_{self.arch}" if self.os == "jetson": - return "ubuntu-20.04_armv8_jetson" + if self.extra is None: + ubuntu_version = "ubuntu-20.04" + else: + ubuntu_version = self.extra + if self.osver is None: + return f"{ubuntu_version}_armv8_jetson" + return f"{ubuntu_version}_armv8_jetson_{self.osver}" raise Exception("error") @@ -1564,8 +1770,10 @@ def _check_platform_target(self, p: PlatformTarget): self._check(p.arch == "armv8") elif p.os in ("ios", "android"): self._check(p.arch is None) + elif p.os == "ubuntu": + self._check(p.arch in ("x86_64", "armv8")) else: - self._check(p.arch in ("x86_64", "arm64")) + self._check(p.arch in ("x86_64", "arm64", "hololens2")) def __init__(self, target_os, target_osver, target_arch): build = get_build_platform() @@ -1575,7 +1783,7 @@ def __init__(self, target_os, target_osver, target_arch): self._check_platform_target(target) if target.os == "windows": - self._check(target.arch == "x86_64") + self._check(target.arch in ("x86_64", "arm64", "hololens2")) self._check(build.os == "windows") self._check(build.arch == "x86_64") if target.os == "macos": @@ -1585,12 +1793,16 @@ def __init__(self, target_os, target_osver, target_arch): self._check(build.os == "macos") self._check(build.arch in ("x86_64", "arm64")) if target.os == "android": - self._check(build.os == "ubuntu") - self._check(build.arch == "x86_64") + self._check(build.os in ("ubuntu", "macos")) + if build.os == "ubuntu": + self._check(build.arch == "x86_64") + elif build.os == "macos": + self._check(build.arch in ("x86_64", "arm64")) if target.os == "ubuntu": self._check(build.os == "ubuntu") self._check(build.arch == "x86_64") - self._check(build.osver == target.osver) + if target.arch == "x86_64": + self._check(build.osver == target.osver) if target.os == "raspberry-pi-os": self._check(build.os == "ubuntu") self._check(build.arch == "x86_64") @@ -1617,7 +1829,10 @@ def get_webrtc_platform(platform: Platform) -> str: elif platform.target.os == "raspberry-pi-os": return f"raspberry-pi-os_{platform.target.arch}" elif platform.target.os == "jetson": - return "ubuntu-20.04_armv8" + if platform.target.extra is None: + return "ubuntu-20.04_armv8" + else: + return f"{platform.target.extra}_armv8" else: raise Exception(f"Unknown platform {platform.target.os}") diff --git a/doc/known_issues.md b/doc/known_issues.md index 154670c1..d73e5088 100644 --- a/doc/known_issues.md +++ b/doc/known_issues.md @@ -1,3 +1,14 @@ # 既知の問題 -現在は既知の問題は存在しません。 +## Intel VPL で VP9 をエンコードするとエラーが発生する + +現在 VPL を使用した時に VP9 の映像を送信できません。 +そのため Sora C++ SDK では VPL の VP9 HWA を使用したエンコードを無効化しています。 +VP9 を使用する場合はソフトウェアエンコードを使用するようになっています。 + +VPL の VP9 のデコードには問題はないため、受信は利用可能です。 + +## ブラウザと H.265 の送受信ができない + +Safari 18.0 以降のバージョンで送信した H.265 の映像が Sora C++ SDK 2024.7.0 で受信できません。 +H.265 の送受信を行う場合は、SDK どうしでの通信を行うか、他のコーデックを使用してください。 \ No newline at end of file diff --git a/doc/vpl.md b/doc/vpl.md index e59a31ae..1e3b4d87 100644 --- a/doc/vpl.md +++ b/doc/vpl.md @@ -40,17 +40,11 @@ Windows 11 では Intel の公式サイトからドライバーをインスト ### Ubuntu 22.04 -Ubuntu 22.04 で Intel VPL を利用するためには、ドライバーとライブラリをインストールする必要があります。 -公式ドキュメントの を参考に必要なドライバーとライブラリをインストールします。 +#### Intel の apt リポジトリを追加 -#### Intel VPL ランタイムをインストールする - -##### Intel の apt リポジトリを追加 - -パッケージのインストールには Intel の apt リポジトリを追加する必要があります。 +ランタイムのインストールには Intel の apt リポジトリを追加する必要があります。 ```bash - wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \ sudo gpg --dearmor --output /usr/share/keyrings/intel-graphics.gpg echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" | \ @@ -58,32 +52,55 @@ echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] htt sudo apt update ``` -##### パッケージのインストール +#### Intel 提供パッケージの最新化 + +Intel の apt リポジトリを追加することでインストール済みのパッケージも Intel から提供されている最新のものに更新できます。依存問題を起こさないため、ここで最新化を行なってください。 + +```bash +sudo apt upgrade +``` -公式ドキュメントでは libmfxgen1 をインストールする手順が記載されていますが、Intel VPL ランタイムを使用するには libmfx-gen1.2 が必要です。 +#### ドライバとライブラリのインストール -以下の実行例のように、 libmfx-gen1.2 をインストールしてください。 +以下のように、ドライバとライブラリをインストールしてください。 +intel-media-va-driver には無印と `non-free` 版がありますが、 `non-free` 版でしか動作しません。 ```bash -sudo apt install -y \ - intel-opencl-icd intel-level-zero-gpu level-zero \ - intel-media-va-driver-non-free libmfx1 libmfx-gen1.2 libvpl2 \ - libegl-mesa0 libegl1-mesa libegl1-mesa-dev libgbm1 libgl1-mesa-dev libgl1-mesa-dri \ - libglapi-mesa libgles2-mesa-dev libglx-mesa0 libigdgmm12 libxatracker2 mesa-va-drivers \ - mesa-vdpau-drivers mesa-vulkan-drivers va-driver-all vainfo hwinfo clinfo +sudo apt install -y intel-media-va-driver-non-free libmfxgen1 +``` + +### Ubuntu 24.04 + +デコードのみであれば標準のリポジトリからも libmfx-gen1.2 をインストール可能ですが、エンコードも行いたいため Intel の apt リポジトリより libmfxgen1 をインストールします。 + +#### Intel の apt リポジトリを追加 + +ランタイムのインストールには Intel の apt リポジトリを追加する必要があります。 + +```bash + +wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \ + sudo gpg --dearmor --output /usr/share/keyrings/intel-graphics.gpg +echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu noble client" | \ + sudo tee /etc/apt/sources.list.d/intel-gpu-noble.list +sudo apt update ``` -##### 再起動 +#### ライブラリのインストール -パッケージのインストールが完了したら、再起動してください。 +以下の実行例のように、 libmfxgen1 をインストールしてください。 -#### Intel Media SDK を利用する手順 +```bash +sudo apt install -y libmfxgen1 +``` + +### Intel Media SDK を利用する手順 Intel のチップセットの世代によって、 Intel Media SDK を利用する必要がある場合があります。 以下の手順で Intel Media SDK をインストールしてください。 -##### Intel の apt リポジトリを追加 +#### Intel の apt リポジトリを追加 ```bash wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \ @@ -93,7 +110,7 @@ echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] htt sudo apt update ``` -###### パッケージのインストール +##### パッケージのインストール ```bash sudo apt install -y \ @@ -104,11 +121,17 @@ sudo apt install -y \ mesa-vdpau-drivers mesa-vulkan-drivers va-driver-all vainfo hwinfo clinfo ``` -### Ubuntu 22.04 で環境構築ができたことを確認する手順 +## Ubuntu 22.04 で環境構築ができたことを確認する手順 `vainfo` コマンドを実行します。 エラーが発生しなければ、 Intel VPL の実行に必要なドライバーやライブラリのインストールに成功しています。 +`vainfo` がインストールされていない場合は、下記のコマンドで `vainfo` をインストールします。 + +```bash +sudo apt install -y vainfo +``` + 以下は `vainfo` を実行した出力の例です。 対応しているプロファイルやエントリーポイントは環境によって異なります。 diff --git a/examples/VERSION b/examples/VERSION index 520a1b4a..973b3d64 100644 --- a/examples/VERSION +++ b/examples/VERSION @@ -1,6 +1,6 @@ -SORA_CPP_SDK_VERSION=2024.7.0 -WEBRTC_BUILD_VERSION=m127.6533.1.1 -BOOST_VERSION=1.85.0 -CMAKE_VERSION=3.29.6 -SDL2_VERSION=2.30.5 +SORA_CPP_SDK_VERSION=2024.8.0-canary.13 +WEBRTC_BUILD_VERSION=m129.6668.1.0 +BOOST_VERSION=1.86.0 +CMAKE_VERSION=3.30.4 +SDL2_VERSION=2.30.8 CLI11_VERSION=v2.4.2 diff --git a/examples/messaging_recvonly_sample/README.md b/examples/messaging_recvonly_sample/README.md index 47c69464..b5b14026 100644 --- a/examples/messaging_recvonly_sample/README.md +++ b/examples/messaging_recvonly_sample/README.md @@ -82,6 +82,7 @@ _build/macos_arm64/release/messaging_recvonly_sample 必要なパッケージをインストールしてください。 ```shell +sudo apt install build-essential sudo apt install libx11-dev sudo apt install libdrm-dev sudo apt install libva-dev @@ -109,6 +110,7 @@ _build/ubuntu-20.04_x86_64/release/messaging_recvonly_sample/ 必要なパッケージをインストールしてください。 ```shell +sudo apt install build-essential sudo apt install libx11-dev sudo apt install libdrm-dev sudo apt install libva-dev @@ -129,6 +131,34 @@ _build/ubuntu-22.04_x86_64/release/messaging_recvonly_sample/ └── messaging_recvonly_sample ``` +#### Ubuntu 24.04 x86_64 向けのビルドをする + +##### 事前準備 + +必要なパッケージをインストールしてください。 + +```shell +sudo apt install build-essential +sudo apt install libx11-dev +sudo apt install libdrm-dev +sudo apt install libva-dev +sudo apt install pkg-config +sudo apt install python3 +``` + +##### ビルド + +```shell +python3 messaging_recvonly_sample/ubuntu-24.04_x86_64/run.py +``` + +成功した場合、以下のファイルが作成されます。`_build/ubuntu-24.04_x86_64/release/messaging_recvonly_sample` に `messaging_recvonly_sample` が作成されます。 + +``` +_build/ubuntu-24.04_x86_64/release/messaging_recvonly_sample/ +└── messaging_recvonly_sample +``` + ## 実行する ### コマンドラインから必要なオプションを指定して実行します diff --git a/examples/messaging_recvonly_sample/macos_arm64/run.py b/examples/messaging_recvonly_sample/macos_arm64/run.py index 334c086f..4f9a90ef 100644 --- a/examples/messaging_recvonly_sample/macos_arm64/run.py +++ b/examples/messaging_recvonly_sample/macos_arm64/run.py @@ -65,7 +65,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("macos_arm64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "macos_arm64", + source_dir, + install_dir, + ) else: build_sora( "macos_arm64", diff --git a/examples/messaging_recvonly_sample/ubuntu-20.04_x86_64/run.py b/examples/messaging_recvonly_sample/ubuntu-20.04_x86_64/run.py index 7d8d248a..fa4a65d9 100644 --- a/examples/messaging_recvonly_sample/ubuntu-20.04_x86_64/run.py +++ b/examples/messaging_recvonly_sample/ubuntu-20.04_x86_64/run.py @@ -93,7 +93,13 @@ def install_deps( install_llvm(**install_llvm_args) if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-20.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-20.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-20.04_x86_64", diff --git a/examples/messaging_recvonly_sample/ubuntu-22.04_x86_64/run.py b/examples/messaging_recvonly_sample/ubuntu-22.04_x86_64/run.py index 48c7134d..642ee82d 100644 --- a/examples/messaging_recvonly_sample/ubuntu-22.04_x86_64/run.py +++ b/examples/messaging_recvonly_sample/ubuntu-22.04_x86_64/run.py @@ -94,7 +94,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-22.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-22.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-22.04_x86_64", diff --git a/examples/messaging_recvonly_sample/ubuntu-24.04_armv8/CMakeLists.txt b/examples/messaging_recvonly_sample/ubuntu-24.04_armv8/CMakeLists.txt new file mode 100644 index 00000000..6e07768a --- /dev/null +++ b/examples/messaging_recvonly_sample/ubuntu-24.04_armv8/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.23) + +# Only interpret if() arguments as variables or keywords when unquoted. +cmake_policy(SET CMP0054 NEW) +# MSVC runtime library flags are selected by an abstraction. +cmake_policy(SET CMP0091 NEW) + +set(WEBRTC_INCLUDE_DIR "" CACHE PATH "WebRTC のインクルードディレクトリ") +set(WEBRTC_LIBRARY_DIR "" CACHE PATH "WebRTC のライブラリディレクトリ") +set(WEBRTC_LIBRARY_NAME "webrtc" CACHE STRING "WebRTC のライブラリ名") +set(BOOST_ROOT "" CACHE PATH "Boost のルートディレクトリ") +set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") +set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") + +project(sora-sumomo C CXX) + +list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR}) +list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) + +set(Boost_USE_STATIC_LIBS ON) + +find_package(Boost REQUIRED COMPONENTS json filesystem) +find_package(WebRTC REQUIRED) +find_package(Sora REQUIRED) +find_package(Threads REQUIRED) + +add_executable(messaging_recvonly_sample) +set_target_properties(messaging_recvonly_sample PROPERTIES CXX_STANDARD 20 C_STANDARD 20) +set_target_properties(messaging_recvonly_sample PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_sources(messaging_recvonly_sample PRIVATE ../src/messaging_recvonly_sample.cpp) + +target_compile_options(messaging_recvonly_sample + PRIVATE + "$<$:-nostdinc++>" + "$<$:-isystem${LIBCXX_INCLUDE_DIR}>" +) +target_include_directories(messaging_recvonly_sample PRIVATE ${CLI11_DIR}/include) +target_link_libraries(messaging_recvonly_sample PRIVATE Sora::sora) +target_compile_definitions(messaging_recvonly_sample PRIVATE CLI11_HAS_FILESYSTEM=0) diff --git a/examples/messaging_recvonly_sample/ubuntu-24.04_armv8/run.py b/examples/messaging_recvonly_sample/ubuntu-24.04_armv8/run.py new file mode 100644 index 00000000..a6f2f850 --- /dev/null +++ b/examples/messaging_recvonly_sample/ubuntu-24.04_armv8/run.py @@ -0,0 +1,220 @@ +import argparse +import hashlib +import multiprocessing +import os +import sys +from typing import List, Optional + +PROJECT_DIR = os.path.abspath(os.path.dirname(__file__)) +BASE_DIR = os.path.join(PROJECT_DIR, "..", "..") +BUILDBASE_DIR = os.path.join(BASE_DIR, "..") +sys.path.insert(0, BUILDBASE_DIR) + + +from buildbase import ( # noqa: E402 + add_path, + add_sora_arguments, + add_webrtc_build_arguments, + build_sora, + build_webrtc, + cd, + cmake_path, + cmd, + get_sora_info, + get_webrtc_info, + install_cli11, + install_cmake, + install_llvm, + install_rootfs, + install_sora_and_deps, + install_webrtc, + mkdir_p, + read_version_file, +) + + +def install_deps( + source_dir, + build_dir, + install_dir, + debug, + local_webrtc_build_dir: Optional[str], + local_webrtc_build_args: List[str], + local_sora_cpp_sdk_dir: Optional[str], + local_sora_cpp_sdk_args: List[str], +): + with cd(BASE_DIR): + version = read_version_file("VERSION") + + # multistrap を使った sysroot の構築 + conf = os.path.join(BASE_DIR, "multistrap", "ubuntu-24.04_armv8.conf") + # conf ファイルのハッシュ値をバージョンとする + version_md5 = hashlib.md5(open(conf, "rb").read()).hexdigest() + install_rootfs_args = { + "version": version_md5, + "version_file": os.path.join(install_dir, "rootfs.version"), + "install_dir": install_dir, + "conf": conf, + } + install_rootfs(**install_rootfs_args) + + # WebRTC + if local_webrtc_build_dir is None: + install_webrtc_args = { + "version": version["WEBRTC_BUILD_VERSION"], + "version_file": os.path.join(install_dir, "webrtc.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "ubuntu-24.04_armv8", + } + install_webrtc(**install_webrtc_args) + else: + build_webrtc_args = { + "platform": "ubuntu-24.04_armv8", + "local_webrtc_build_dir": local_webrtc_build_dir, + "local_webrtc_build_args": local_webrtc_build_args, + "debug": debug, + } + build_webrtc(**build_webrtc_args) + + webrtc_info = get_webrtc_info( + "ubuntu-24.04_armv8", local_webrtc_build_dir, install_dir, debug + ) + + if local_webrtc_build_dir is None: + webrtc_version = read_version_file(webrtc_info.version_file) + + # LLVM + tools_url = webrtc_version["WEBRTC_SRC_TOOLS_URL"] + tools_commit = webrtc_version["WEBRTC_SRC_TOOLS_COMMIT"] + libcxx_url = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_URL"] + libcxx_commit = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_COMMIT"] + buildtools_url = webrtc_version["WEBRTC_SRC_BUILDTOOLS_URL"] + buildtools_commit = webrtc_version["WEBRTC_SRC_BUILDTOOLS_COMMIT"] + install_llvm_args = { + "version": f"{tools_url}.{tools_commit}." + f"{libcxx_url}.{libcxx_commit}." + f"{buildtools_url}.{buildtools_commit}", + "version_file": os.path.join(install_dir, "llvm.version"), + "install_dir": install_dir, + "tools_url": tools_url, + "tools_commit": tools_commit, + "libcxx_url": libcxx_url, + "libcxx_commit": libcxx_commit, + "buildtools_url": buildtools_url, + "buildtools_commit": buildtools_commit, + } + install_llvm(**install_llvm_args) + + # Sora C++ SDK, Boost + if local_sora_cpp_sdk_dir is None: + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-24.04_armv8", + source_dir, + install_dir, + ) + else: + build_sora( + "ubuntu-24.04_armv8", + local_sora_cpp_sdk_dir, + local_sora_cpp_sdk_args, + debug, + local_webrtc_build_dir, + ) + + # CMake + install_cmake_args = { + "version": version["CMAKE_VERSION"], + "version_file": os.path.join(install_dir, "cmake.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "linux-x86_64", + "ext": "tar.gz", + } + install_cmake(**install_cmake_args) + add_path(os.path.join(install_dir, "cmake", "bin")) + + # CLI11 + install_cli11_args = { + "version": version["CLI11_VERSION"], + "version_file": os.path.join(install_dir, "cli11.version"), + "install_dir": install_dir, + } + install_cli11(**install_cli11_args) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--debug", action="store_true") + add_webrtc_build_arguments(parser) + add_sora_arguments(parser) + + args = parser.parse_args() + + configuration_dir = "debug" if args.debug else "release" + platform = "ubuntu-24.04_armv8" + source_dir = os.path.join(BASE_DIR, "_source", platform, configuration_dir) + build_dir = os.path.join(BASE_DIR, "_build", platform, configuration_dir) + install_dir = os.path.join(BASE_DIR, "_install", platform, configuration_dir) + mkdir_p(source_dir) + mkdir_p(build_dir) + mkdir_p(install_dir) + + install_deps( + source_dir, + build_dir, + install_dir, + args.debug, + args.local_webrtc_build_dir, + args.local_webrtc_build_args, + args.local_sora_cpp_sdk_dir, + args.local_sora_cpp_sdk_args, + ) + + configuration = "Debug" if args.debug else "Release" + + sample_build_dir = os.path.join(build_dir, "messaging_recvonly_sample") + mkdir_p(sample_build_dir) + with cd(sample_build_dir): + webrtc_info = get_webrtc_info( + "ubuntu-24.04_armv8", args.local_webrtc_build_dir, install_dir, args.debug + ) + sora_info = get_sora_info(platform, args.local_sora_cpp_sdk_dir, install_dir, args.debug) + + cmake_args = [] + cmake_args.append(f"-DCMAKE_BUILD_TYPE={configuration}") + cmake_args.append(f"-DBOOST_ROOT={cmake_path(sora_info.boost_install_dir)}") + cmake_args.append(f"-DWEBRTC_INCLUDE_DIR={cmake_path(webrtc_info.webrtc_include_dir)}") + cmake_args.append(f"-DWEBRTC_LIBRARY_DIR={cmake_path(webrtc_info.webrtc_library_dir)}") + cmake_args.append(f"-DSORA_DIR={cmake_path(sora_info.sora_install_dir)}") + cmake_args.append(f"-DCLI11_DIR={cmake_path(os.path.join(install_dir, 'cli11'))}") + + # クロスコンパイルの設定。 + # 本来は toolchain ファイルに書く内容 + sysroot = os.path.join(install_dir, "rootfs") + cmake_args += [ + f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}", + f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}", + f"-DLIBCXX_INCLUDE_DIR={os.path.join(webrtc_info.libcxx_dir, 'include')}", + "-DCMAKE_SYSTEM_NAME=Linux", + "-DCMAKE_SYSTEM_PROCESSOR=aarch64", + f"-DCMAKE_SYSROOT={sysroot}", + "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu", + "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu", + f"-DCMAKE_FIND_ROOT_PATH={sysroot}", + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH", + ] + + cmd(["cmake", os.path.join(PROJECT_DIR)] + cmake_args) + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + + +if __name__ == "__main__": + main() diff --git a/examples/messaging_recvonly_sample/ubuntu-24.04_x86_64/run.py b/examples/messaging_recvonly_sample/ubuntu-24.04_x86_64/run.py index a9b1f861..72710826 100644 --- a/examples/messaging_recvonly_sample/ubuntu-24.04_x86_64/run.py +++ b/examples/messaging_recvonly_sample/ubuntu-24.04_x86_64/run.py @@ -94,7 +94,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-24.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-24.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-24.04_x86_64", diff --git a/examples/messaging_recvonly_sample/windows_x86_64/run.py b/examples/messaging_recvonly_sample/windows_x86_64/run.py index 41608d36..5e0bf424 100644 --- a/examples/messaging_recvonly_sample/windows_x86_64/run.py +++ b/examples/messaging_recvonly_sample/windows_x86_64/run.py @@ -64,7 +64,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("windows_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "windows_x86_64", + source_dir, + install_dir, + ) else: build_sora( "windows_x86_64", diff --git a/examples/multistrap/ubuntu-24.04_armv8.conf b/examples/multistrap/ubuntu-24.04_armv8.conf new file mode 100644 index 00000000..a13684b6 --- /dev/null +++ b/examples/multistrap/ubuntu-24.04_armv8.conf @@ -0,0 +1,11 @@ +[General] +noauth=true +unpack=true +bootstrap=Ports +aptsources=Ports + +[Ports] +packages=libstdc++-13-dev libc6-dev libxext-dev libdbus-1-dev libudev-dev libgles-dev +source=http://ports.ubuntu.com +suite=noble +components=main universe diff --git a/examples/sdl_sample/README.md b/examples/sdl_sample/README.md index 5ff7ed8e..af752d5b 100644 --- a/examples/sdl_sample/README.md +++ b/examples/sdl_sample/README.md @@ -82,6 +82,7 @@ _build/macos_arm64/release/sdl_sample 必要なパッケージをインストールしてください。 ```shell +sudo apt install build-essential sudo apt install libxext-dev sudo apt install libx11-dev sudo apt install libdrm-dev @@ -110,6 +111,7 @@ _build/ubuntu-20.04_x86_64/release/sdl_sample/ 必要なパッケージをインストールしてください。 ```shell +sudo apt install build-essential sudo apt install libxext-dev sudo apt install libx11-dev sudo apt install libdrm-dev @@ -131,6 +133,35 @@ _build/ubuntu-22.04_x86_64/release/sdl_sample/ └── sdl_sample ``` +#### Ubuntu 24.04 x86_64 向けのビルドをする + +##### 事前準備 + +必要なパッケージをインストールしてください。 + +```shell +sudo apt install build-essential +sudo apt install libxext-dev +sudo apt install libx11-dev +sudo apt install libdrm-dev +sudo apt install libva-dev +sudo apt install pkg-config +sudo apt install python3 +``` + +##### ビルド + +```shell +python3 sdl_sample/ubuntu-24.04_x86_64/run.py +``` + +成功した場合、以下のファイルが作成されます。`_build/ubuntu-24.04_x86_64/release/sdl_sample` に `sdl_sample` が作成されます。 + +``` +_build/ubuntu-24.04_x86_64/release/sdl_sample/ +└── sdl_sample +``` + ## 実行する ### コマンドラインから必要なオプションを指定して実行します diff --git a/examples/sdl_sample/macos_arm64/run.py b/examples/sdl_sample/macos_arm64/run.py index 54ff806b..0befef52 100644 --- a/examples/sdl_sample/macos_arm64/run.py +++ b/examples/sdl_sample/macos_arm64/run.py @@ -68,7 +68,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("macos_arm64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "macos_arm64", + source_dir, + install_dir, + ) else: build_sora( "macos_arm64", diff --git a/examples/sdl_sample/ubuntu-20.04_x86_64/run.py b/examples/sdl_sample/ubuntu-20.04_x86_64/run.py index cea8092f..da9675e4 100644 --- a/examples/sdl_sample/ubuntu-20.04_x86_64/run.py +++ b/examples/sdl_sample/ubuntu-20.04_x86_64/run.py @@ -95,7 +95,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-20.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-20.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-20.04_x86_64", diff --git a/examples/sdl_sample/ubuntu-22.04_x86_64/run.py b/examples/sdl_sample/ubuntu-22.04_x86_64/run.py index 5217a82a..a06efded 100644 --- a/examples/sdl_sample/ubuntu-22.04_x86_64/run.py +++ b/examples/sdl_sample/ubuntu-22.04_x86_64/run.py @@ -95,7 +95,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-22.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-22.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-22.04_x86_64", diff --git a/examples/sdl_sample/ubuntu-24.04_armv8/CMakeLists.txt b/examples/sdl_sample/ubuntu-24.04_armv8/CMakeLists.txt new file mode 100644 index 00000000..7d9f2485 --- /dev/null +++ b/examples/sdl_sample/ubuntu-24.04_armv8/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.23) + +# Only interpret if() arguments as variables or keywords when unquoted. +cmake_policy(SET CMP0054 NEW) +# MSVC runtime library flags are selected by an abstraction. +cmake_policy(SET CMP0091 NEW) + +set(WEBRTC_INCLUDE_DIR "" CACHE PATH "WebRTC のインクルードディレクトリ") +set(WEBRTC_LIBRARY_DIR "" CACHE PATH "WebRTC のライブラリディレクトリ") +set(WEBRTC_LIBRARY_NAME "webrtc" CACHE STRING "WebRTC のライブラリ名") +set(BOOST_ROOT "" CACHE PATH "Boost のルートディレクトリ") +set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") +set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") +set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") + +project(sora-sdl-sample C CXX) + +list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) +list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) + +set(Boost_USE_STATIC_LIBS ON) + +find_package(Boost REQUIRED COMPONENTS json filesystem) +find_package(WebRTC REQUIRED) +find_package(Sora REQUIRED) +find_package(SDL2 REQUIRED) +find_package(Threads REQUIRED) + +add_executable(sdl_sample) +set_target_properties(sdl_sample PROPERTIES CXX_STANDARD 20 C_STANDARD 20) +set_target_properties(sdl_sample PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_sources(sdl_sample PRIVATE ../src/sdl_sample.cpp ../src/sdl_renderer.cpp) + +target_compile_options(sdl_sample + PRIVATE + "$<$:-nostdinc++>" + "$<$:-isystem${LIBCXX_INCLUDE_DIR}>" +) +target_include_directories(sdl_sample PRIVATE ${CLI11_DIR}/include) +target_link_libraries(sdl_sample PRIVATE Sora::sora SDL2::SDL2 SDL2::SDL2main) +target_compile_definitions(sdl_sample PRIVATE CLI11_HAS_FILESYSTEM=0) diff --git a/examples/sdl_sample/ubuntu-24.04_armv8/run.py b/examples/sdl_sample/ubuntu-24.04_armv8/run.py new file mode 100644 index 00000000..716cf58d --- /dev/null +++ b/examples/sdl_sample/ubuntu-24.04_armv8/run.py @@ -0,0 +1,249 @@ +import argparse +import hashlib +import multiprocessing +import os +import sys +from typing import List, Optional + +PROJECT_DIR = os.path.abspath(os.path.dirname(__file__)) +BASE_DIR = os.path.join(PROJECT_DIR, "..", "..") +BUILDBASE_DIR = os.path.join(BASE_DIR, "..") +sys.path.insert(0, BUILDBASE_DIR) + + +from buildbase import ( # noqa: E402 + add_path, + add_sora_arguments, + add_webrtc_build_arguments, + build_sora, + build_webrtc, + cd, + cmake_path, + cmd, + get_sora_info, + get_webrtc_info, + install_cli11, + install_cmake, + install_llvm, + install_rootfs, + install_sdl2, + install_sora_and_deps, + install_webrtc, + mkdir_p, + read_version_file, +) + + +def install_deps( + source_dir, + build_dir, + install_dir, + debug, + local_webrtc_build_dir: Optional[str], + local_webrtc_build_args: List[str], + local_sora_cpp_sdk_dir: Optional[str], + local_sora_cpp_sdk_args: List[str], +): + with cd(BASE_DIR): + version = read_version_file("VERSION") + + # multistrap を使った sysroot の構築 + conf = os.path.join(BASE_DIR, "multistrap", "ubuntu-24.04_armv8.conf") + # conf ファイルのハッシュ値をバージョンとする + version_md5 = hashlib.md5(open(conf, "rb").read()).hexdigest() + install_rootfs_args = { + "version": version_md5, + "version_file": os.path.join(install_dir, "rootfs.version"), + "install_dir": install_dir, + "conf": conf, + } + install_rootfs(**install_rootfs_args) + + # WebRTC + if local_webrtc_build_dir is None: + install_webrtc_args = { + "version": version["WEBRTC_BUILD_VERSION"], + "version_file": os.path.join(install_dir, "webrtc.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "ubuntu-24.04_armv8", + } + install_webrtc(**install_webrtc_args) + else: + build_webrtc_args = { + "platform": "ubuntu-24.04_armv8", + "local_webrtc_build_dir": local_webrtc_build_dir, + "local_webrtc_build_args": local_webrtc_build_args, + "debug": debug, + } + build_webrtc(**build_webrtc_args) + + webrtc_info = get_webrtc_info( + "ubuntu-24.04_armv8", local_webrtc_build_dir, install_dir, debug + ) + + if local_webrtc_build_dir is None: + webrtc_version = read_version_file(webrtc_info.version_file) + + # LLVM + tools_url = webrtc_version["WEBRTC_SRC_TOOLS_URL"] + tools_commit = webrtc_version["WEBRTC_SRC_TOOLS_COMMIT"] + libcxx_url = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_URL"] + libcxx_commit = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_COMMIT"] + buildtools_url = webrtc_version["WEBRTC_SRC_BUILDTOOLS_URL"] + buildtools_commit = webrtc_version["WEBRTC_SRC_BUILDTOOLS_COMMIT"] + install_llvm_args = { + "version": f"{tools_url}.{tools_commit}." + f"{libcxx_url}.{libcxx_commit}." + f"{buildtools_url}.{buildtools_commit}", + "version_file": os.path.join(install_dir, "llvm.version"), + "install_dir": install_dir, + "tools_url": tools_url, + "tools_commit": tools_commit, + "libcxx_url": libcxx_url, + "libcxx_commit": libcxx_commit, + "buildtools_url": buildtools_url, + "buildtools_commit": buildtools_commit, + } + install_llvm(**install_llvm_args) + + # Sora C++ SDK, Boost + if local_sora_cpp_sdk_dir is None: + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-24.04_armv8", + source_dir, + install_dir, + ) + else: + build_sora( + "ubuntu-24.04_armv8", + local_sora_cpp_sdk_dir, + local_sora_cpp_sdk_args, + debug, + local_webrtc_build_dir, + ) + + # CMake + install_cmake_args = { + "version": version["CMAKE_VERSION"], + "version_file": os.path.join(install_dir, "cmake.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "linux-x86_64", + "ext": "tar.gz", + } + install_cmake(**install_cmake_args) + add_path(os.path.join(install_dir, "cmake", "bin")) + + # SDL2 + sysroot = os.path.join(install_dir, "rootfs") + install_sdl2_args = { + "version": version["SDL2_VERSION"], + "version_file": os.path.join(install_dir, "sdl2.version"), + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "debug": debug, + "platform": "linux", + "cmake_args": [ + f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}", + f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}", + "-DCMAKE_SYSTEM_NAME=Linux", + "-DCMAKE_SYSTEM_PROCESSOR=aarch64", + f"-DCMAKE_SYSROOT={sysroot}", + "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu", + "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu", + f"-DCMAKE_FIND_ROOT_PATH={sysroot}", + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY", + "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY", + ], + } + install_sdl2(**install_sdl2_args) + + # CLI11 + install_cli11_args = { + "version": version["CLI11_VERSION"], + "version_file": os.path.join(install_dir, "cli11.version"), + "install_dir": install_dir, + } + install_cli11(**install_cli11_args) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--debug", action="store_true") + add_webrtc_build_arguments(parser) + add_sora_arguments(parser) + + args = parser.parse_args() + + configuration_dir = "debug" if args.debug else "release" + platform = "ubuntu-24.04_armv8" + source_dir = os.path.join(BASE_DIR, "_source", platform, configuration_dir) + build_dir = os.path.join(BASE_DIR, "_build", platform, configuration_dir) + install_dir = os.path.join(BASE_DIR, "_install", platform, configuration_dir) + mkdir_p(source_dir) + mkdir_p(build_dir) + mkdir_p(install_dir) + + install_deps( + source_dir, + build_dir, + install_dir, + args.debug, + args.local_webrtc_build_dir, + args.local_webrtc_build_args, + args.local_sora_cpp_sdk_dir, + args.local_sora_cpp_sdk_args, + ) + + configuration = "Debug" if args.debug else "Release" + + sample_build_dir = os.path.join(build_dir, "sdl_sample") + mkdir_p(sample_build_dir) + with cd(sample_build_dir): + webrtc_info = get_webrtc_info( + "ubuntu-24.04_armv8", args.local_webrtc_build_dir, install_dir, args.debug + ) + sora_info = get_sora_info(platform, args.local_sora_cpp_sdk_dir, install_dir, args.debug) + + cmake_args = [] + cmake_args.append(f"-DCMAKE_BUILD_TYPE={configuration}") + cmake_args.append(f"-DBOOST_ROOT={cmake_path(sora_info.boost_install_dir)}") + cmake_args.append(f"-DWEBRTC_INCLUDE_DIR={cmake_path(webrtc_info.webrtc_include_dir)}") + cmake_args.append(f"-DWEBRTC_LIBRARY_DIR={cmake_path(webrtc_info.webrtc_library_dir)}") + cmake_args.append(f"-DSORA_DIR={cmake_path(sora_info.sora_install_dir)}") + cmake_args.append(f"-DCLI11_DIR={cmake_path(os.path.join(install_dir, 'cli11'))}") + cmake_args.append(f"-DSDL2_DIR={cmake_path(os.path.join(install_dir, 'sdl2'))}") + + # クロスコンパイルの設定。 + # 本来は toolchain ファイルに書く内容 + sysroot = os.path.join(install_dir, "rootfs") + cmake_args += [ + f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}", + f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}", + f"-DLIBCXX_INCLUDE_DIR={os.path.join(webrtc_info.libcxx_dir, 'include')}", + "-DCMAKE_SYSTEM_NAME=Linux", + "-DCMAKE_SYSTEM_PROCESSOR=aarch64", + f"-DCMAKE_SYSROOT={sysroot}", + "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu", + "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu", + f"-DCMAKE_FIND_ROOT_PATH={sysroot}", + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH", + ] + + cmd(["cmake", os.path.join(PROJECT_DIR)] + cmake_args) + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + + +if __name__ == "__main__": + main() diff --git a/examples/sdl_sample/ubuntu-24.04_x86_64/run.py b/examples/sdl_sample/ubuntu-24.04_x86_64/run.py index 899e5e15..fcb8213b 100644 --- a/examples/sdl_sample/ubuntu-24.04_x86_64/run.py +++ b/examples/sdl_sample/ubuntu-24.04_x86_64/run.py @@ -95,7 +95,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-24.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-24.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-24.04_x86_64", diff --git a/examples/sdl_sample/windows_x86_64/run.py b/examples/sdl_sample/windows_x86_64/run.py index 4a7ea8b3..fbd12a42 100644 --- a/examples/sdl_sample/windows_x86_64/run.py +++ b/examples/sdl_sample/windows_x86_64/run.py @@ -65,7 +65,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("windows_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "windows_x86_64", + source_dir, + install_dir, + ) else: build_sora( "windows_x86_64", diff --git a/examples/sumomo/README.md b/examples/sumomo/README.md index db26bde0..77eb5037 100644 --- a/examples/sumomo/README.md +++ b/examples/sumomo/README.md @@ -82,6 +82,7 @@ _build/macos_arm64/release/sumomo 必要なパッケージをインストールしてください。 ```shell +sudo apt install build-essential sudo apt install libxext-dev sudo apt install libx11-dev sudo apt install libdrm-dev @@ -110,6 +111,7 @@ _build/ubuntu-20.04_x86_64/release/sumomo/ 必要なパッケージをインストールしてください。 ```shell +sudo apt install build-essential sudo apt install libxext-dev sudo apt install libx11-dev sudo apt install libdrm-dev @@ -131,6 +133,35 @@ _build/ubuntu-22.04_x86_64/release/sumomo/ └── sumomo ``` +#### Ubuntu 24.04 x86_64 向けのビルドをする + +##### 事前準備 + +必要なパッケージをインストールしてください。 + +```shell +sudo apt install build-essential +sudo apt install libxext-dev +sudo apt install libx11-dev +sudo apt install libdrm-dev +sudo apt install libva-dev +sudo apt install pkg-config +sudo apt install python3 +``` + +##### ビルド + +```shell +python3 sumomo/ubuntu-24.04_x86_64/run.py +``` + +成功した場合、以下のファイルが作成されます。`_build/ubuntu-24.04_x86_64/release/sumomo` に `sumomo` が作成されます。 + +``` +_build/ubuntu-24.04_x86_64/release/sumomo/ +└── sumomo +``` + ## 実行する ### コマンドラインから必要なオプションを指定して実行します @@ -171,7 +202,6 @@ Windows 以外の場合 - `--openh264` : openh264 ライブラリのパスをフルパスで指定します - デコードには対応していません - #### Sora に関するオプション 設定内容については [Sora のドキュメント](https://sora-doc.shiguredo.jp/SIGNALING) も参考にしてください。 @@ -231,6 +261,16 @@ Windows 以外の場合 - `--show-me` - 送信している自分の映像を表示します +#### 証明書に関するオプション + +- `--insecure` : サーバー証明書の検証を行わないようにするフラグ + - 未指定の場合は、サーバー証明書の検証を行います +- `--ca-cert` : CA 証明書ファイル +- `--client-cert` : クライアント証明書ファイル +- `--client-key` : クライアントプライベートキーファイル + +`--ca-cert`, `--client-cert`, `--client-key` には、PEM 形式のファイルを指定してください。 + #### その他のオプション - `--help` diff --git a/examples/sumomo/macos_arm64/CMakeLists.txt b/examples/sumomo/macos_arm64/CMakeLists.txt index 5dc8ca75..ea1fad35 100644 --- a/examples/sumomo/macos_arm64/CMakeLists.txt +++ b/examples/sumomo/macos_arm64/CMakeLists.txt @@ -13,7 +13,7 @@ set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") -project(sora-sdl-sample C CXX) +project(sora-sumomo C CXX) list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) diff --git a/examples/sumomo/macos_arm64/run.py b/examples/sumomo/macos_arm64/run.py index a21b161c..7b08f7e8 100644 --- a/examples/sumomo/macos_arm64/run.py +++ b/examples/sumomo/macos_arm64/run.py @@ -68,7 +68,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("macos_arm64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "macos_arm64", + source_dir, + install_dir, + ) else: build_sora( "macos_arm64", diff --git a/examples/sumomo/src/sumomo.cpp b/examples/sumomo/src/sumomo.cpp index 7db105fe..946fdb78 100644 --- a/examples/sumomo/src/sumomo.cpp +++ b/examples/sumomo/src/sumomo.cpp @@ -58,6 +58,11 @@ struct SumomoConfig { std::string srtp_key_log_file; + bool insecure = false; + std::string client_cert; + std::string client_key; + std::string ca_cert; + struct Size { int width; int height; @@ -164,6 +169,24 @@ class Sumomo : public std::enable_shared_from_this, context_->signaling_thread()->BlockingCall([this]() { return context_->connection_context()->default_socket_factory(); }); + config.insecure = config_.insecure; + auto load_file = [](const std::string& path) { + std::ifstream ifs(path, std::ios::binary); + if (!ifs) { + return std::string(); + } + return std::string((std::istreambuf_iterator(ifs)), + std::istreambuf_iterator()); + }; + if (!config_.client_cert.empty()) { + config.client_cert = load_file(config_.client_cert); + } + if (!config_.client_key.empty()) { + config.client_key = load_file(config_.client_key); + } + if (!config_.ca_cert.empty()) { + config.ca_cert = load_file(config_.ca_cert); + } conn_ = sora::SoraSignaling::Create(config); boost::asio::executor_work_guard @@ -417,6 +440,12 @@ int main(int argc, char* argv[]) { app.add_option("--srtp-key-log-file", config.srtp_key_log_file, "SRTP keying material output file"); + // 証明書に関するオプション + app.add_flag("--insecure", config.insecure, "Allow insecure connection"); + app.add_option("--client-cert", config.client_cert, "Client certificate file")->check(CLI::ExistingFile); + app.add_option("--client-key", config.client_key, "Client key file")->check(CLI::ExistingFile); + app.add_option("--ca-cert", config.ca_cert, "CA certificate file")->check(CLI::ExistingFile); + // SoraClientContextConfig に関するオプション boost::optional use_hardware_encoder; add_optional_bool(app, "--use-hardware-encoder", use_hardware_encoder, diff --git a/examples/sumomo/ubuntu-20.04_x86_64/CMakeLists.txt b/examples/sumomo/ubuntu-20.04_x86_64/CMakeLists.txt index c41f6cbc..10833ee7 100644 --- a/examples/sumomo/ubuntu-20.04_x86_64/CMakeLists.txt +++ b/examples/sumomo/ubuntu-20.04_x86_64/CMakeLists.txt @@ -13,7 +13,7 @@ set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") -project(sora-sdl-sample C CXX) +project(sora-sumomo C CXX) list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) diff --git a/examples/sumomo/ubuntu-20.04_x86_64/run.py b/examples/sumomo/ubuntu-20.04_x86_64/run.py index 5584d416..9c69b4d8 100644 --- a/examples/sumomo/ubuntu-20.04_x86_64/run.py +++ b/examples/sumomo/ubuntu-20.04_x86_64/run.py @@ -95,7 +95,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-20.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-20.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-20.04_x86_64", diff --git a/examples/sumomo/ubuntu-22.04_x86_64/CMakeLists.txt b/examples/sumomo/ubuntu-22.04_x86_64/CMakeLists.txt index c41f6cbc..10833ee7 100644 --- a/examples/sumomo/ubuntu-22.04_x86_64/CMakeLists.txt +++ b/examples/sumomo/ubuntu-22.04_x86_64/CMakeLists.txt @@ -13,7 +13,7 @@ set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") -project(sora-sdl-sample C CXX) +project(sora-sumomo C CXX) list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) diff --git a/examples/sumomo/ubuntu-22.04_x86_64/run.py b/examples/sumomo/ubuntu-22.04_x86_64/run.py index 814e313b..a9da2916 100644 --- a/examples/sumomo/ubuntu-22.04_x86_64/run.py +++ b/examples/sumomo/ubuntu-22.04_x86_64/run.py @@ -95,7 +95,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-22.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-22.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-22.04_x86_64", diff --git a/examples/sumomo/ubuntu-24.04_armv8/CMakeLists.txt b/examples/sumomo/ubuntu-24.04_armv8/CMakeLists.txt new file mode 100644 index 00000000..12a12823 --- /dev/null +++ b/examples/sumomo/ubuntu-24.04_armv8/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.23) + +# Only interpret if() arguments as variables or keywords when unquoted. +cmake_policy(SET CMP0054 NEW) +# MSVC runtime library flags are selected by an abstraction. +cmake_policy(SET CMP0091 NEW) + +set(WEBRTC_INCLUDE_DIR "" CACHE PATH "WebRTC のインクルードディレクトリ") +set(WEBRTC_LIBRARY_DIR "" CACHE PATH "WebRTC のライブラリディレクトリ") +set(WEBRTC_LIBRARY_NAME "webrtc" CACHE STRING "WebRTC のライブラリ名") +set(BOOST_ROOT "" CACHE PATH "Boost のルートディレクトリ") +set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") +set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") +set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") + +project(sora-sumomo C CXX) + +list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) +list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) + +set(Boost_USE_STATIC_LIBS ON) + +find_package(Boost REQUIRED COMPONENTS json filesystem) +find_package(WebRTC REQUIRED) +find_package(Sora REQUIRED) +find_package(SDL2 REQUIRED) +find_package(Threads REQUIRED) + +add_executable(sumomo) +set_target_properties(sumomo PROPERTIES CXX_STANDARD 20 C_STANDARD 20) +set_target_properties(sumomo PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_sources(sumomo PRIVATE ../src/sumomo.cpp ../src/sdl_renderer.cpp) + +target_compile_options(sumomo + PRIVATE + "$<$:-nostdinc++>" + "$<$:-isystem${LIBCXX_INCLUDE_DIR}>" +) +target_include_directories(sumomo PRIVATE ${CLI11_DIR}/include) +target_link_libraries(sumomo PRIVATE Sora::sora SDL2::SDL2 SDL2::SDL2main) +target_compile_definitions(sumomo PRIVATE CLI11_HAS_FILESYSTEM=0) diff --git a/examples/sumomo/ubuntu-24.04_armv8/run.py b/examples/sumomo/ubuntu-24.04_armv8/run.py new file mode 100644 index 00000000..8a861453 --- /dev/null +++ b/examples/sumomo/ubuntu-24.04_armv8/run.py @@ -0,0 +1,249 @@ +import argparse +import hashlib +import multiprocessing +import os +import sys +from typing import List, Optional + +PROJECT_DIR = os.path.abspath(os.path.dirname(__file__)) +BASE_DIR = os.path.join(PROJECT_DIR, "..", "..") +BUILDBASE_DIR = os.path.join(BASE_DIR, "..") +sys.path.insert(0, BUILDBASE_DIR) + + +from buildbase import ( # noqa: E402 + add_path, + add_sora_arguments, + add_webrtc_build_arguments, + build_sora, + build_webrtc, + cd, + cmake_path, + cmd, + get_sora_info, + get_webrtc_info, + install_cli11, + install_cmake, + install_llvm, + install_rootfs, + install_sdl2, + install_sora_and_deps, + install_webrtc, + mkdir_p, + read_version_file, +) + + +def install_deps( + source_dir, + build_dir, + install_dir, + debug, + local_webrtc_build_dir: Optional[str], + local_webrtc_build_args: List[str], + local_sora_cpp_sdk_dir: Optional[str], + local_sora_cpp_sdk_args: List[str], +): + with cd(BASE_DIR): + version = read_version_file("VERSION") + + # multistrap を使った sysroot の構築 + conf = os.path.join(BASE_DIR, "multistrap", "ubuntu-24.04_armv8.conf") + # conf ファイルのハッシュ値をバージョンとする + version_md5 = hashlib.md5(open(conf, "rb").read()).hexdigest() + install_rootfs_args = { + "version": version_md5, + "version_file": os.path.join(install_dir, "rootfs.version"), + "install_dir": install_dir, + "conf": conf, + } + install_rootfs(**install_rootfs_args) + + # WebRTC + if local_webrtc_build_dir is None: + install_webrtc_args = { + "version": version["WEBRTC_BUILD_VERSION"], + "version_file": os.path.join(install_dir, "webrtc.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "ubuntu-24.04_armv8", + } + install_webrtc(**install_webrtc_args) + else: + build_webrtc_args = { + "platform": "ubuntu-24.04_armv8", + "local_webrtc_build_dir": local_webrtc_build_dir, + "local_webrtc_build_args": local_webrtc_build_args, + "debug": debug, + } + build_webrtc(**build_webrtc_args) + + webrtc_info = get_webrtc_info( + "ubuntu-24.04_armv8", local_webrtc_build_dir, install_dir, debug + ) + + if local_webrtc_build_dir is None: + webrtc_version = read_version_file(webrtc_info.version_file) + + # LLVM + tools_url = webrtc_version["WEBRTC_SRC_TOOLS_URL"] + tools_commit = webrtc_version["WEBRTC_SRC_TOOLS_COMMIT"] + libcxx_url = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_URL"] + libcxx_commit = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_COMMIT"] + buildtools_url = webrtc_version["WEBRTC_SRC_BUILDTOOLS_URL"] + buildtools_commit = webrtc_version["WEBRTC_SRC_BUILDTOOLS_COMMIT"] + install_llvm_args = { + "version": f"{tools_url}.{tools_commit}." + f"{libcxx_url}.{libcxx_commit}." + f"{buildtools_url}.{buildtools_commit}", + "version_file": os.path.join(install_dir, "llvm.version"), + "install_dir": install_dir, + "tools_url": tools_url, + "tools_commit": tools_commit, + "libcxx_url": libcxx_url, + "libcxx_commit": libcxx_commit, + "buildtools_url": buildtools_url, + "buildtools_commit": buildtools_commit, + } + install_llvm(**install_llvm_args) + + # Sora C++ SDK, Boost + if local_sora_cpp_sdk_dir is None: + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-24.04_armv8", + source_dir, + install_dir, + ) + else: + build_sora( + "ubuntu-24.04_armv8", + local_sora_cpp_sdk_dir, + local_sora_cpp_sdk_args, + debug, + local_webrtc_build_dir, + ) + + # CMake + install_cmake_args = { + "version": version["CMAKE_VERSION"], + "version_file": os.path.join(install_dir, "cmake.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "linux-x86_64", + "ext": "tar.gz", + } + install_cmake(**install_cmake_args) + add_path(os.path.join(install_dir, "cmake", "bin")) + + # SDL2 + sysroot = os.path.join(install_dir, "rootfs") + install_sdl2_args = { + "version": version["SDL2_VERSION"], + "version_file": os.path.join(install_dir, "sdl2.version"), + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "debug": debug, + "platform": "linux", + "cmake_args": [ + f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}", + f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}", + "-DCMAKE_SYSTEM_NAME=Linux", + "-DCMAKE_SYSTEM_PROCESSOR=aarch64", + f"-DCMAKE_SYSROOT={sysroot}", + "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu", + "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu", + f"-DCMAKE_FIND_ROOT_PATH={sysroot}", + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY", + "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY", + ], + } + install_sdl2(**install_sdl2_args) + + # CLI11 + install_cli11_args = { + "version": version["CLI11_VERSION"], + "version_file": os.path.join(install_dir, "cli11.version"), + "install_dir": install_dir, + } + install_cli11(**install_cli11_args) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--debug", action="store_true") + add_webrtc_build_arguments(parser) + add_sora_arguments(parser) + + args = parser.parse_args() + + configuration_dir = "debug" if args.debug else "release" + platform = "ubuntu-24.04_armv8" + source_dir = os.path.join(BASE_DIR, "_source", platform, configuration_dir) + build_dir = os.path.join(BASE_DIR, "_build", platform, configuration_dir) + install_dir = os.path.join(BASE_DIR, "_install", platform, configuration_dir) + mkdir_p(source_dir) + mkdir_p(build_dir) + mkdir_p(install_dir) + + install_deps( + source_dir, + build_dir, + install_dir, + args.debug, + args.local_webrtc_build_dir, + args.local_webrtc_build_args, + args.local_sora_cpp_sdk_dir, + args.local_sora_cpp_sdk_args, + ) + + configuration = "Debug" if args.debug else "Release" + + sample_build_dir = os.path.join(build_dir, "sumomo") + mkdir_p(sample_build_dir) + with cd(sample_build_dir): + webrtc_info = get_webrtc_info( + "ubuntu-24.04_armv8", args.local_webrtc_build_dir, install_dir, args.debug + ) + sora_info = get_sora_info(platform, args.local_sora_cpp_sdk_dir, install_dir, args.debug) + + cmake_args = [] + cmake_args.append(f"-DCMAKE_BUILD_TYPE={configuration}") + cmake_args.append(f"-DBOOST_ROOT={cmake_path(sora_info.boost_install_dir)}") + cmake_args.append(f"-DWEBRTC_INCLUDE_DIR={cmake_path(webrtc_info.webrtc_include_dir)}") + cmake_args.append(f"-DWEBRTC_LIBRARY_DIR={cmake_path(webrtc_info.webrtc_library_dir)}") + cmake_args.append(f"-DSORA_DIR={cmake_path(sora_info.sora_install_dir)}") + cmake_args.append(f"-DCLI11_DIR={cmake_path(os.path.join(install_dir, 'cli11'))}") + cmake_args.append(f"-DSDL2_DIR={cmake_path(os.path.join(install_dir, 'sdl2'))}") + + # クロスコンパイルの設定。 + # 本来は toolchain ファイルに書く内容 + sysroot = os.path.join(install_dir, "rootfs") + cmake_args += [ + f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}", + f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}", + f"-DLIBCXX_INCLUDE_DIR={os.path.join(webrtc_info.libcxx_dir, 'include')}", + "-DCMAKE_SYSTEM_NAME=Linux", + "-DCMAKE_SYSTEM_PROCESSOR=aarch64", + f"-DCMAKE_SYSROOT={sysroot}", + "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu", + "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu", + f"-DCMAKE_FIND_ROOT_PATH={sysroot}", + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH", + ] + + cmd(["cmake", os.path.join(PROJECT_DIR)] + cmake_args) + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + + +if __name__ == "__main__": + main() diff --git a/examples/sumomo/ubuntu-24.04_x86_64/CMakeLists.txt b/examples/sumomo/ubuntu-24.04_x86_64/CMakeLists.txt index c41f6cbc..10833ee7 100644 --- a/examples/sumomo/ubuntu-24.04_x86_64/CMakeLists.txt +++ b/examples/sumomo/ubuntu-24.04_x86_64/CMakeLists.txt @@ -13,7 +13,7 @@ set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") -project(sora-sdl-sample C CXX) +project(sora-sumomo C CXX) list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) diff --git a/examples/sumomo/ubuntu-24.04_x86_64/run.py b/examples/sumomo/ubuntu-24.04_x86_64/run.py index 993abd72..da5c7a9c 100644 --- a/examples/sumomo/ubuntu-24.04_x86_64/run.py +++ b/examples/sumomo/ubuntu-24.04_x86_64/run.py @@ -95,7 +95,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("ubuntu-24.04_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "ubuntu-24.04_x86_64", + source_dir, + install_dir, + ) else: build_sora( "ubuntu-24.04_x86_64", diff --git a/examples/sumomo/windows_x86_64/CMakeLists.txt b/examples/sumomo/windows_x86_64/CMakeLists.txt index 0ea6b946..6cfb98fc 100644 --- a/examples/sumomo/windows_x86_64/CMakeLists.txt +++ b/examples/sumomo/windows_x86_64/CMakeLists.txt @@ -13,7 +13,7 @@ set(SORA_DIR "" CACHE PATH "Sora のルートディレクトリ") set(SDL2_DIR "" CACHE PATH "SDL2 のルートディレクトリ") set(CLI11_DIR "" CACHE PATH "CLI11 のルートディレクトリ") -project(sora-sdl-sample C CXX) +project(sora-sumomo C CXX) list(APPEND CMAKE_PREFIX_PATH ${SORA_DIR} ${SDL2_DIR}) list(APPEND CMAKE_MODULE_PATH ${SORA_DIR}/share/cmake) diff --git a/examples/sumomo/windows_x86_64/run.py b/examples/sumomo/windows_x86_64/run.py index 9ca037ea..005a634b 100644 --- a/examples/sumomo/windows_x86_64/run.py +++ b/examples/sumomo/windows_x86_64/run.py @@ -65,7 +65,13 @@ def install_deps( # Sora C++ SDK, Boost if local_sora_cpp_sdk_dir is None: - install_sora_and_deps("windows_x86_64", source_dir, install_dir) + install_sora_and_deps( + version["SORA_CPP_SDK_VERSION"], + version["BOOST_VERSION"], + "windows_x86_64", + source_dir, + install_dir, + ) else: build_sora( "windows_x86_64", diff --git a/include/sora/rtc_ssl_verifier.h b/include/sora/rtc_ssl_verifier.h index ef2910ba..79e5d37a 100644 --- a/include/sora/rtc_ssl_verifier.h +++ b/include/sora/rtc_ssl_verifier.h @@ -1,6 +1,9 @@ #ifndef RTC_SSL_VERIFIER #define RTC_SSL_VERIFIER +#include +#include + // WebRTC #include @@ -8,11 +11,12 @@ namespace sora { class RTCSSLVerifier : public rtc::SSLCertificateVerifier { public: - RTCSSLVerifier(bool insecure); + RTCSSLVerifier(bool insecure, std::optional ca_cert); bool Verify(const rtc::SSLCertificate& certificate) override; private: bool insecure_; + std::optional ca_cert_; }; } // namespace sora diff --git a/include/sora/sora_signaling.h b/include/sora/sora_signaling.h index 5634ef2e..d4a559fe 100644 --- a/include/sora/sora_signaling.h +++ b/include/sora/sora_signaling.h @@ -41,6 +41,16 @@ enum class SoraSignalingErrorCode { ICE_FAILED, }; +enum class SoraSignalingType { + WEBSOCKET, + DATACHANNEL, +}; + +enum class SoraSignalingDirection { + SENT, + RECEIVED, +}; + class SoraSignalingObserver { public: virtual void OnSetOffer(std::string offer) = 0; @@ -49,6 +59,10 @@ class SoraSignalingObserver { virtual void OnPush(std::string text) = 0; virtual void OnMessage(std::string label, std::string data) = 0; virtual void OnSwitched(std::string text) {} + virtual void OnSignalingMessage(SoraSignalingType type, + SoraSignalingDirection direction, + std::string message) {} + virtual void OnWsClose(uint16_t code, std::string message) {} virtual void OnTrack( rtc::scoped_refptr transceiver) = 0; @@ -121,8 +135,9 @@ struct SoraSignalingConfig { }; boost::optional forwarding_filter; - std::string client_cert; - std::string client_key; + std::optional client_cert; + std::optional client_key; + std::optional ca_cert; int websocket_close_timeout = 3; int websocket_connection_timeout = 30; @@ -208,7 +223,13 @@ class SoraSignaling : public std::enable_shared_from_this, std::vector encodings); void ResetEncodingParameters(); + void WsWriteSignaling(std::string text, Websocket::write_callback_t on_write); void SendOnDisconnect(SoraSignalingErrorCode ec, std::string message); + void SendOnSignalingMessage(SoraSignalingType type, + SoraSignalingDirection direction, + std::string message); + void SendOnWsClose(const boost::beast::websocket::close_reason& reason); + void SendSelfOnWsClose(boost::system::error_code ec); webrtc::DataBuffer ConvertToDataBuffer(const std::string& label, const std::string& input); diff --git a/include/sora/ssl_verifier.h b/include/sora/ssl_verifier.h index 6b2d18c4..220f8055 100644 --- a/include/sora/ssl_verifier.h +++ b/include/sora/ssl_verifier.h @@ -1,6 +1,7 @@ #ifndef SORA_SSL_VERIFIER_H_ #define SORA_SSL_VERIFIER_H_ +#include #include // openssl @@ -11,7 +12,9 @@ namespace sora { // 自前で SSL の証明書検証を行うためのクラス class SSLVerifier { public: - static bool VerifyX509(X509* x509, STACK_OF(X509) * chain); + static bool VerifyX509(X509* x509, + STACK_OF(X509) * chain, + const std::optional& ca_cert); private: // PEM 形式のルート証明書を追加する @@ -20,6 +23,6 @@ class SSLVerifier { static bool LoadBuiltinSSLRootCertificates(X509_STORE* store); }; -} +} // namespace sora #endif diff --git a/include/sora/websocket.h b/include/sora/websocket.h index 4208de62..759e5851 100644 --- a/include/sora/websocket.h +++ b/include/sora/websocket.h @@ -3,6 +3,7 @@ #include #include +#include // Boost #include @@ -51,14 +52,16 @@ class Websocket { Websocket(ssl_tag, boost::asio::io_context& ioc, bool insecure, - const std::string& client_cert, - const std::string& client_key); + const std::optional& client_cert, + const std::optional& client_key, + const std::optional& ca_cert); // HTTP Proxy + SSL Websocket(https_proxy_tag, boost::asio::io_context& ioc, bool insecure, - const std::string& client_cert, - const std::string& client_key, + const std::optional& client_cert, + const std::optional& client_key, + const std::optional& ca_cert, std::string proxy_url, std::string proxy_username, std::string proxy_password); @@ -89,7 +92,9 @@ class Websocket { private: bool IsSSL() const; - void InitWss(ssl_websocket_t* wss, bool insecure); + void InitWss(ssl_websocket_t* wss, + bool insecure, + const std::optional& ca_cert); void OnResolve(std::string host, std::string port, @@ -161,6 +166,8 @@ class Websocket { boost::beast::http::response_parser> proxy_resp_parser_; boost::beast::flat_buffer proxy_buffer_; + + std::optional ca_cert_; }; } // namespace sora diff --git a/multistrap/ubuntu-24.04_armv8.conf b/multistrap/ubuntu-24.04_armv8.conf new file mode 100644 index 00000000..4b18038e --- /dev/null +++ b/multistrap/ubuntu-24.04_armv8.conf @@ -0,0 +1,11 @@ +[General] +noauth=true +unpack=true +bootstrap=Ports +aptsources=Ports + +[Ports] +packages=libstdc++-13-dev libc6-dev libxext-dev libdbus-1-dev +source=http://ports.ubuntu.com +suite=noble +components=main universe diff --git a/run.py b/run.py index 587d6fd8..d446d2b5 100644 --- a/run.py +++ b/run.py @@ -1,4 +1,5 @@ import argparse +import hashlib import logging import multiprocessing import os @@ -31,6 +32,7 @@ install_cuda_windows, install_llvm, install_openh264, + install_rootfs, install_vpl, install_webrtc, mkdir_p, @@ -80,12 +82,20 @@ def get_common_cmake_args( args.append("-DCMAKE_C_COMPILER=clang-18") args.append("-DCMAKE_CXX_COMPILER=clang++-18") else: + sysroot = os.path.join(install_dir, "rootfs") args.append( f"-DCMAKE_C_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang'))}" ) args.append( f"-DCMAKE_CXX_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang++'))}" ) + args.append("-DCMAKE_SYSTEM_NAME=Linux") + args.append("-DCMAKE_SYSTEM_PROCESSOR=aarch64") + args.append(f"-DCMAKE_SYSROOT={sysroot}") + args.append("-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu") + args.append("-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu") + args.append(f"-DCMAKE_FIND_ROOT_PATH={sysroot}") + args.append("-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER") path = cmake_path(os.path.join(webrtc_info.libcxx_dir, "include")) args.append(f"-DCMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES={path}") cxxflags = ["-nostdinc++", "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE"] @@ -132,6 +142,19 @@ def install_deps( with cd(BASE_DIR): version = read_version_file("VERSION") + # multistrap を使った sysroot の構築 + if platform.target.os == "ubuntu" and platform.target.arch == "armv8": + conf = os.path.join(BASE_DIR, "multistrap", f"{platform.target.package_name}.conf") + # conf ファイルのハッシュ値をバージョンとする + version_md5 = hashlib.md5(open(conf, "rb").read()).hexdigest() + install_rootfs_args = { + "version": version_md5, + "version_file": os.path.join(install_dir, "rootfs.version"), + "install_dir": install_dir, + "conf": conf, + } + install_rootfs(**install_rootfs_args) + # Android NDK if platform.target.os == "android": install_android_ndk_args = { @@ -300,10 +323,28 @@ def install_deps( "-D_LIBCPP_DISABLE_AVAILABILITY", "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", "-nostdinc++", + "-std=gnu++17", f"-isystem{os.path.join(webrtc_info.libcxx_dir, 'include')}", "-fPIC", ] install_boost_args["toolset"] = "clang" + if platform.target.arch == "armv8": + sysroot = os.path.join(install_dir, "rootfs") + install_boost_args["cflags"] += [ + f"--sysroot={sysroot}", + "--target=aarch64-linux-gnu", + f"-I{os.path.join(sysroot, 'usr', 'include', 'aarch64-linux-gnu')}", + ] + install_boost_args["cxxflags"] += [ + f"--sysroot={sysroot}", + "--target=aarch64-linux-gnu", + f"-I{os.path.join(sysroot, 'usr', 'include', 'aarch64-linux-gnu')}", + ] + install_boost_args["linkflags"] += [ + f"-L{os.path.join(sysroot, 'usr', 'lib', 'aarch64-linux-gnu')}", + f"-B{os.path.join(sysroot, 'usr', 'lib', 'aarch64-linux-gnu')}", + ] + install_boost_args["architecture"] = "arm" build_and_install_boost(**install_boost_args) @@ -462,6 +503,29 @@ def install_deps( install_catch2(**install_catch2_args) +def check_version_file(): + version = read_version_file(os.path.join(BASE_DIR, "VERSION")) + example_version = read_version_file(os.path.join(BASE_DIR, "examples", "VERSION")) + has_error = False + if version["SORA_CPP_SDK_VERSION"] != example_version["SORA_CPP_SDK_VERSION"]: + logging.error( + f"SORA_CPP_SDK_VERSION mismatch: VERSION={version['SORA_CPP_SDK_VERSION']}, example/VERSION={example_version['SORA_CPP_SDK_VERSION']}" + ) + has_error = True + if version["WEBRTC_BUILD_VERSION"] != example_version["WEBRTC_BUILD_VERSION"]: + logging.error( + f"WEBRTC_BUILD_VERSION mismatch: VERSION={version['WEBRTC_BUILD_VERSION']}, example/VERSION={example_version['WEBRTC_BUILD_VERSION']}" + ) + has_error = True + if version["BOOST_VERSION"] != example_version["BOOST_VERSION"]: + logging.error( + f"BOOST_VERSION mismatch: VERSION={version['BOOST_VERSION']}, example/VERSION={example_version['BOOST_VERSION']}" + ) + has_error = True + if has_error: + raise Exception("VERSION mismatch") + + AVAILABLE_TARGETS = [ "windows_x86_64", "macos_x86_64", @@ -469,6 +533,7 @@ def install_deps( "ubuntu-20.04_x86_64", "ubuntu-22.04_x86_64", "ubuntu-24.04_x86_64", + "ubuntu-24.04_armv8", "ios", "android", ] @@ -476,6 +541,8 @@ def install_deps( def main(): + check_version_file() + parser = argparse.ArgumentParser() parser.add_argument("target", choices=AVAILABLE_TARGETS) parser.add_argument("--debug", action="store_true") @@ -498,6 +565,8 @@ def main(): platform = Platform("ubuntu", "22.04", "x86_64") elif args.target == "ubuntu-24.04_x86_64": platform = Platform("ubuntu", "24.04", "x86_64") + elif args.target == "ubuntu-24.04_armv8": + platform = Platform("ubuntu", "24.04", "armv8") elif args.target == "ios": platform = Platform("ios", None, None) elif args.target == "android": @@ -572,12 +641,20 @@ def main(): cmake_args.append("-DCMAKE_C_COMPILER=clang-18") cmake_args.append("-DCMAKE_CXX_COMPILER=clang++-18") else: + sysroot = os.path.join(install_dir, "rootfs") cmake_args.append( f"-DCMAKE_C_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang'))}" ) cmake_args.append( f"-DCMAKE_CXX_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang++'))}" ) + cmake_args.append("-DCMAKE_SYSTEM_NAME=Linux") + cmake_args.append("-DCMAKE_SYSTEM_PROCESSOR=aarch64") + cmake_args.append(f"-DCMAKE_SYSROOT={sysroot}") + cmake_args.append("-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu") + cmake_args.append("-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu") + cmake_args.append(f"-DCMAKE_FIND_ROOT_PATH={sysroot}") + cmake_args.append("-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER") cmake_args.append("-DUSE_LIBCXX=ON") cmake_args.append( f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}" @@ -684,7 +761,7 @@ def main(): os.path.join(sora_build_dir, "bundled", "sora.lib"), os.path.join(install_dir, "sora", "lib", "sora.lib"), ) - elif platform.target.os == "ubuntu": + elif platform.target.os == "ubuntu" and platform.target.arch == "x86_64": shutil.copyfile( os.path.join(sora_build_dir, "bundled", "libsora.a"), os.path.join(install_dir, "sora", "lib", "libsora.a"), @@ -776,12 +853,23 @@ def main(): cmake_args.append("-DCMAKE_C_COMPILER=clang-18") cmake_args.append("-DCMAKE_CXX_COMPILER=clang++-18") else: + sysroot = os.path.join(install_dir, "rootfs") cmake_args.append( f"-DCMAKE_C_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang'))}" ) cmake_args.append( f"-DCMAKE_CXX_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang++'))}" ) + cmake_args.append("-DCMAKE_SYSTEM_NAME=Linux") + cmake_args.append("-DCMAKE_SYSTEM_PROCESSOR=aarch64") + cmake_args.append(f"-DCMAKE_SYSROOT={sysroot}") + cmake_args.append("-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu") + cmake_args.append("-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu") + cmake_args.append(f"-DCMAKE_FIND_ROOT_PATH={sysroot}") + cmake_args.append("-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER") + cmake_args.append("-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH") + cmake_args.append("-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH") + cmake_args.append("-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH") cmake_args.append("-DUSE_LIBCXX=ON") cmake_args.append( f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}" diff --git a/src/default_video_formats.cpp b/src/default_video_formats.cpp index 7121ea6e..77ed0127 100644 --- a/src/default_video_formats.cpp +++ b/src/default_video_formats.cpp @@ -24,7 +24,7 @@ std::vector GetDefaultVideoFormats( } } else if (codec == webrtc::kVideoCodecAV1) { r.push_back(webrtc::SdpVideoFormat( - cricket::kAv1CodecName, webrtc::SdpVideoFormat::Parameters(), + cricket::kAv1CodecName, webrtc::CodecParameterMap(), webrtc::LibaomAv1EncoderSupportedScalabilityModes())); } else if (codec == webrtc::kVideoCodecH264) { for (auto profile : { diff --git a/src/hwenc_vpl/vpl_utils.h b/src/hwenc_vpl/vpl_utils.h index bdf8856d..d8d184bc 100644 --- a/src/hwenc_vpl/vpl_utils.h +++ b/src/hwenc_vpl/vpl_utils.h @@ -18,11 +18,11 @@ namespace sora { static mfxU32 ToMfxCodec(webrtc::VideoCodecType codec) { - return codec == webrtc::kVideoCodecVP8 ? MFX_CODEC_VP8 - : codec == webrtc::kVideoCodecVP9 ? MFX_CODEC_VP9 - : codec == webrtc::kVideoCodecH264 ? MFX_CODEC_AVC - : codec == webrtc::kVideoCodecH265 ? MFX_CODEC_HEVC - : MFX_CODEC_AV1; + return codec == webrtc::kVideoCodecVP8 ? (mfxU32)MFX_CODEC_VP8 + : codec == webrtc::kVideoCodecVP9 ? (mfxU32)MFX_CODEC_VP9 + : codec == webrtc::kVideoCodecH264 ? (mfxU32)MFX_CODEC_AVC + : codec == webrtc::kVideoCodecH265 ? (mfxU32)MFX_CODEC_HEVC + : (mfxU32)MFX_CODEC_AV1; } static std::string CodecToString(mfxU32 codec) { diff --git a/src/hwenc_vpl/vpl_video_encoder.cpp b/src/hwenc_vpl/vpl_video_encoder.cpp index 53d2519c..295f655d 100644 --- a/src/hwenc_vpl/vpl_video_encoder.cpp +++ b/src/hwenc_vpl/vpl_video_encoder.cpp @@ -125,13 +125,13 @@ std::unique_ptr VplVideoEncoderImpl::CreateEncoder( std::unique_ptr encoder( new MFXVideoENCODE(GetVplSession(session))); - mfxPlatform platform; - memset(&platform, 0, sizeof(platform)); - MFXVideoCORE_QueryPlatform(GetVplSession(session), &platform); - RTC_LOG(LS_VERBOSE) << "--------------- codec=" << CodecToString(codec) - << " CodeName=" << platform.CodeName - << " DeviceId=" << platform.DeviceId - << " MediaAdapterType=" << platform.MediaAdapterType; + // mfxPlatform platform; + // memset(&platform, 0, sizeof(platform)); + // MFXVideoCORE_QueryPlatform(GetVplSession(session), &platform); + // RTC_LOG(LS_VERBOSE) << "--------------- codec=" << CodecToString(codec) + // << " CodeName=" << platform.CodeName + // << " DeviceId=" << platform.DeviceId + // << " MediaAdapterType=" << platform.MediaAdapterType; mfxVideoParam param; ExtBuffer ext; diff --git a/src/rtc_ssl_verifier.cpp b/src/rtc_ssl_verifier.cpp index 40fceb80..9f27ef2a 100644 --- a/src/rtc_ssl_verifier.cpp +++ b/src/rtc_ssl_verifier.cpp @@ -7,7 +7,9 @@ namespace sora { -RTCSSLVerifier::RTCSSLVerifier(bool insecure) : insecure_(insecure) {} +RTCSSLVerifier::RTCSSLVerifier(bool insecure, + std::optional ca_cert) + : insecure_(insecure), ca_cert_(ca_cert) {} bool RTCSSLVerifier::Verify(const rtc::SSLCertificate& certificate) { // insecure の場合は証明書をチェックしない @@ -17,7 +19,7 @@ bool RTCSSLVerifier::Verify(const rtc::SSLCertificate& certificate) { SSL* ssl = static_cast(certificate).ssl(); X509* x509 = SSL_get_peer_certificate(ssl); STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl); - return SSLVerifier::VerifyX509(x509, chain); + return SSLVerifier::VerifyX509(x509, chain, ca_cert_); } -} \ No newline at end of file +} // namespace sora \ No newline at end of file diff --git a/src/sora_signaling.cpp b/src/sora_signaling.cpp index 41630e4d..f03bfcf9 100644 --- a/src/sora_signaling.cpp +++ b/src/sora_signaling.cpp @@ -138,6 +138,9 @@ void SoraSignaling::Redirect(std::string url) { return; } + // Disconnect と重複しないように Redirecting の場合のみ発火させる + self->SendSelfOnWsClose(ec); + // close 処理に成功してても失敗してても処理は続ける if (ec) { RTC_LOG(LS_WARNING) << "Redirect error: ec=" << ec.message(); @@ -171,13 +174,14 @@ void SoraSignaling::Redirect(std::string url) { ws.reset( new Websocket(Websocket::ssl_tag(), *self->config_.io_context, self->config_.insecure, self->config_.client_cert, - self->config_.client_key)); + self->config_.client_key, self->config_.ca_cert)); } else { ws.reset(new Websocket( Websocket::https_proxy_tag(), *self->config_.io_context, self->config_.insecure, self->config_.client_cert, - self->config_.client_key, self->config_.proxy_url, - self->config_.proxy_username, self->config_.proxy_password)); + self->config_.client_key, self->config_.ca_cert, + self->config_.proxy_url, self->config_.proxy_username, + self->config_.proxy_password)); } } else { ws.reset(new Websocket(*self->config_.io_context)); @@ -412,10 +416,10 @@ void SoraSignaling::DoSendConnect(bool redirect) { m["forwarding_filter"] = obj; } - RTC_LOG(LS_INFO) << "Send type=connect: " << boost::json::serialize(m); - ws_->WriteText( - boost::json::serialize(m), - [self = shared_from_this()](boost::system::error_code, size_t) {}); + std::string text = boost::json::serialize(m); + RTC_LOG(LS_INFO) << "Send type=connect: " << text; + WsWriteSignaling(std::move(text), [self = shared_from_this()]( + boost::system::error_code, size_t) {}); } void SoraSignaling::DoSendPong() { @@ -441,12 +445,15 @@ void SoraSignaling::DoSendPong( void SoraSignaling::DoSendUpdate(const std::string& sdp, std::string type) { boost::json::value m = {{"type", type}, {"sdp", sdp}}; + std::string text = boost::json::serialize(m); if (dc_ && using_datachannel_ && dc_->IsOpen("signaling")) { // DataChannel が使える場合は DataChannel に送る - SendDataChannel("signaling", boost::json::serialize(m)); + SendDataChannel("signaling", text); + SendOnSignalingMessage(SoraSignalingType::DATACHANNEL, + SoraSignalingDirection::SENT, std::move(text)); } else if (ws_) { - ws_->WriteText( - boost::json::serialize(m), + WsWriteSignaling( + std::move(text), [self = shared_from_this()](boost::system::error_code, size_t) {}); } } @@ -510,7 +517,7 @@ SoraSignaling::CreatePeerConnection(boost::json::value jconfig) { // // それを解消するために tls_cert_verifier を設定して自前で検証を行う。 dependencies.tls_cert_verifier = std::unique_ptr( - new RTCSSLVerifier(config_.insecure)); + new RTCSSLVerifier(config_.insecure, config_.ca_cert)); // Proxy を設定する if (!config_.proxy_url.empty() && config_.network_manager != nullptr && @@ -539,7 +546,8 @@ SoraSignaling::CreatePeerConnection(boost::json::value jconfig) { pi.username = config_.proxy_username; } if (!config_.proxy_password.empty()) { - pi.password = rtc::revive::CryptString(RawCryptString(config_.proxy_password)); + pi.password = + rtc::revive::CryptString(RawCryptString(config_.proxy_password)); } std::string proxy_agent = "Sora C++ SDK"; if (!config_.proxy_agent.empty()) { @@ -590,6 +598,7 @@ void SoraSignaling::DoInternalDisconnect( boost::system::error_code tec; self->closing_timeout_timer_.cancel(tec); auto ws_reason = self->ws_->reason(); + self->SendOnWsClose(ws_reason); std::string message = "Unintended disconnect WebSocket during Disconnect process: ec=" + ec.message() + " wscode=" + std::to_string(ws_reason.code) + @@ -599,11 +608,11 @@ void SoraSignaling::DoInternalDisconnect( } if (using_datachannel_ && ws_connected_) { - webrtc::DataBuffer disconnect = ConvertToDataBuffer( - "signaling", + std::string text = force_error_code == boost::none ? R"({"type":"disconnect","reason":"NO-ERROR"})" - : R"({"type":"disconnect","reason":")" + reason + "\"}"); + : R"({"type":"disconnect","reason":")" + reason + "\"}"; + webrtc::DataBuffer disconnect = ConvertToDataBuffer("signaling", text); dc_->Close( disconnect, [self = shared_from_this(), on_close, force_error_code, @@ -623,6 +632,7 @@ void SoraSignaling::DoInternalDisconnect( boost::system::error_code tec; self->closing_timeout_timer_.cancel(tec); auto ws_reason = self->ws_->reason(); + self->SendOnWsClose(ws_reason); std::string ws_reason_str = " wscode=" + std::to_string(ws_reason.code) + " wsreason=" + ws_reason.reason.c_str(); @@ -652,9 +662,12 @@ void SoraSignaling::DoInternalDisconnect( }; }, config_.disconnect_wait_timeout); + + SendOnSignalingMessage(SoraSignalingType::DATACHANNEL, + SoraSignalingDirection::SENT, std::move(text)); } else if (using_datachannel_ && !ws_connected_) { - webrtc::DataBuffer disconnect = ConvertToDataBuffer( - "signaling", R"({"type":"disconnect","reason":"NO-ERROR"})"); + std::string text = R"({"type":"disconnect","reason":"NO-ERROR"})"; + webrtc::DataBuffer disconnect = ConvertToDataBuffer("signaling", text); dc_->Close( disconnect, [on_close](boost::system::error_code ec) { @@ -667,10 +680,13 @@ void SoraSignaling::DoInternalDisconnect( "Succeeded to close DataChannel"); }, config_.disconnect_wait_timeout); + + SendOnSignalingMessage(SoraSignalingType::DATACHANNEL, + SoraSignalingDirection::SENT, std::move(text)); } else if (!using_datachannel_ && ws_connected_) { boost::json::value disconnect = {{"type", "disconnect"}, {"reason", "NO-ERROR"}}; - ws_->WriteText( + WsWriteSignaling( boost::json::serialize(disconnect), [self = shared_from_this(), on_close](boost::system::error_code ec, std::size_t) { @@ -695,9 +711,10 @@ void SoraSignaling::DoInternalDisconnect( self->on_ws_close_ = [self, on_close](boost::system::error_code ec) { boost::system::error_code tec; self->closing_timeout_timer_.cancel(tec); + auto reason = self->ws_->reason(); + self->SendOnWsClose(reason); bool ec_error = ec != boost::beast::websocket::error::closed; if (ec_error) { - auto reason = self->ws_->reason(); on_close(false, SoraSignalingErrorCode::CLOSE_FAILED, "Failed to close WebSocket: ec=" + ec.message() + " wscode=" + std::to_string(reason.code) + @@ -809,6 +826,7 @@ void SoraSignaling::OnRead(boost::system::error_code ec, ? SoraSignalingErrorCode::WEBSOCKET_ONCLOSE : SoraSignalingErrorCode::WEBSOCKET_ONERROR; auto reason = ws_->reason(); + SendOnWsClose(reason); std::string reason_str = " wscode=" + std::to_string(reason.code) + " wsreason=" + reason.reason.c_str(); SendOnDisconnect(error_code, "Failed to read WebSocket: ec=" + @@ -821,15 +839,16 @@ void SoraSignaling::OnRead(boost::system::error_code ec, } if (state_ == State::Connected && using_datachannel_ && ws_connected_) { // DataChanel で reason: "WEBSOCKET-ONCLOSE" または "WEBSOCKET-ONERROR" を送る事を試みてから終了する - webrtc::DataBuffer disconnect = ConvertToDataBuffer( - "signaling", + std::string text = ec == boost::beast::websocket::error::closed ? R"({"type":"disconnect","reason":"WEBSOCKET-ONCLOSE"})" - : R"({"type":"disconnect","reason":"WEBSOCKET-ONERROR"})"); + : R"({"type":"disconnect","reason":"WEBSOCKET-ONERROR"})"; + webrtc::DataBuffer disconnect = ConvertToDataBuffer("signaling", text); auto error_code = ec == boost::beast::websocket::error::closed ? SoraSignalingErrorCode::WEBSOCKET_ONCLOSE : SoraSignalingErrorCode::WEBSOCKET_ONERROR; auto reason = ws_->reason(); + SendOnWsClose(reason); std::string reason_str = " wscode=" + std::to_string(reason.code) + " wsreason=" + reason.reason.c_str(); state_ = State::Closing; @@ -851,6 +870,9 @@ void SoraSignaling::OnRead(boost::system::error_code ec, ec.message() + reason_str); }, config_.disconnect_wait_timeout); + + SendOnSignalingMessage(SoraSignalingType::DATACHANNEL, + SoraSignalingDirection::SENT, std::move(text)); return; } @@ -877,11 +899,18 @@ void SoraSignaling::OnRead(boost::system::error_code ec, } if (type == "redirect") { + SendOnSignalingMessage(SoraSignalingType::WEBSOCKET, + SoraSignalingDirection::RECEIVED, std::move(text)); + const std::string location = m.at("location").as_string().c_str(); Redirect(location); // Redirect の中で次の Read をしているのでここで return する return; } else if (type == "offer") { + // 後続で使っているので text はコピーする + SendOnSignalingMessage(SoraSignalingType::WEBSOCKET, + SoraSignalingDirection::RECEIVED, text); + const std::string sdp = m.at("sdp").as_string().c_str(); std::string video_mid; @@ -1022,7 +1051,7 @@ void SoraSignaling::OnRead(boost::system::error_code ec, } boost::json::value m = {{"type", "answer"}, {"sdp", sdp}}; - self->ws_->WriteText( + self->WsWriteSignaling( boost::json::serialize(m), [self](boost::system::error_code, size_t) {}); }); @@ -1036,6 +1065,10 @@ void SoraSignaling::OnRead(boost::system::error_code ec, if (pc_ == nullptr) { return; } + + SendOnSignalingMessage(SoraSignalingType::WEBSOCKET, + SoraSignalingDirection::RECEIVED, std::move(text)); + std::string answer_type = type == "update" ? "update" : "re-answer"; const std::string sdp = m.at("sdp").as_string().c_str(); if (!CheckSdp(sdp)) { @@ -1118,8 +1151,11 @@ void SoraSignaling::OnRead(boost::system::error_code ec, auto it = m.as_object().find("ignore_disconnect_websocket"); if (it != m.as_object().end() && it->value().as_bool() && ws_connected_) { RTC_LOG(LS_INFO) << "Close WebSocket for DataChannel"; - ws_->Close([self = shared_from_this()](boost::system::error_code) {}, - config_.websocket_close_timeout); + ws_->Close( + [self = shared_from_this()](boost::system::error_code ec) { + self->SendSelfOnWsClose(ec); + }, + config_.websocket_close_timeout); ws_connected_ = false; return; @@ -1172,12 +1208,12 @@ void SoraSignaling::DoConnect() { if (config_.proxy_url.empty()) { ws.reset(new Websocket(Websocket::ssl_tag(), *config_.io_context, config_.insecure, config_.client_cert, - config_.client_key)); + config_.client_key, config_.ca_cert)); } else { ws.reset(new Websocket( Websocket::https_proxy_tag(), *config_.io_context, config_.insecure, - config_.client_cert, config_.client_key, config_.proxy_url, - config_.proxy_username, config_.proxy_password)); + config_.client_cert, config_.client_key, config_.ca_cert, + config_.proxy_url, config_.proxy_username, config_.proxy_password)); } } else { ws.reset(new Websocket(*config_.io_context)); @@ -1303,6 +1339,14 @@ void SoraSignaling::ResetEncodingParameters() { sender->SetParameters(parameters); } +void SoraSignaling::WsWriteSignaling(std::string text, + Websocket::write_callback_t on_write) { + ws_->WriteText(text, on_write); + + SendOnSignalingMessage(SoraSignalingType::WEBSOCKET, + SoraSignalingDirection::SENT, std::move(text)); +} + void SoraSignaling::SendOnDisconnect(SoraSignalingErrorCode ec, std::string message) { if (ec != SoraSignalingErrorCode::CLOSE_SUCCEEDED) { @@ -1318,6 +1362,28 @@ void SoraSignaling::SendOnDisconnect(SoraSignalingErrorCode ec, }); } +void SoraSignaling::SendOnSignalingMessage(SoraSignalingType type, + SoraSignalingDirection direction, + std::string message) { + if (auto ob = config_.observer.lock(); ob) { + ob->OnSignalingMessage(type, direction, std::move(message)); + } +} + +void SoraSignaling::SendOnWsClose( + const boost::beast::websocket::close_reason& reason) { + if (auto ob = config_.observer.lock(); ob) { + ob->OnWsClose(reason.code, reason.reason.c_str()); + } +} + +void SoraSignaling::SendSelfOnWsClose(boost::system::error_code ec) { + auto close_reason = boost::beast::websocket::close_reason( + ec ? 4999 : boost::beast::websocket::close_code::normal); + close_reason.reason = "SELF-CLOSED"; + SendOnWsClose(close_reason); +} + webrtc::DataBuffer SoraSignaling::ConvertToDataBuffer( const std::string& label, const std::string& input) { @@ -1437,8 +1503,8 @@ void SoraSignaling::OnIceCandidate( return; } - self->ws_->WriteText(boost::json::serialize(m), - [self](boost::system::error_code, size_t) {}); + self->WsWriteSignaling(boost::json::serialize(m), + [self](boost::system::error_code, size_t) {}); }); } @@ -1533,7 +1599,7 @@ void SoraSignaling::OnMessage( return; } - boost::json::error_code ec; + boost::system::error_code ec; auto json = boost::json::parse(data, ec); if (ec) { RTC_LOG(LS_ERROR) << "JSON Parse Error ec=" << ec.message(); @@ -1541,6 +1607,9 @@ void SoraSignaling::OnMessage( } if (label == "signaling") { + SendOnSignalingMessage(SoraSignalingType::DATACHANNEL, + SoraSignalingDirection::RECEIVED, std::move(data)); + const std::string type = json.at("type").as_string().c_str(); if (type == "re-offer") { const std::string sdp = json.at("sdp").as_string().c_str(); diff --git a/src/ssl_verifier.cpp b/src/ssl_verifier.cpp index 458d2f69..96e0046e 100644 --- a/src/ssl_verifier.cpp +++ b/src/ssl_verifier.cpp @@ -97,20 +97,23 @@ bool SSLVerifier::AddCert(const std::string& pem, X509_STORE* store) { RTC_LOG(LS_ERROR) << "BIO_new_mem_buf failed"; return false; } - X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); - if (cert == nullptr) { - BIO_free(bio); - RTC_LOG(LS_ERROR) << "PEM_read_bio_X509 failed"; - return false; - } - int r = X509_STORE_add_cert(store, cert); - if (r == 0) { + while (true) { + X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); + if (cert == nullptr) { + ERR_get_error(); + break; + } + + int r = X509_STORE_add_cert(store, cert); + if (r == 0) { + X509_free(cert); + BIO_free(bio); + RTC_LOG(LS_ERROR) << "X509_STORE_add_cert failed"; + return false; + } X509_free(cert); - BIO_free(bio); - RTC_LOG(LS_ERROR) << "X509_STORE_add_cert failed"; - return false; } - X509_free(cert); + BIO_free(bio); return true; } @@ -138,7 +141,9 @@ bool SSLVerifier::LoadBuiltinSSLRootCertificates(X509_STORE* store) { return count_of_added_certs > 0; } -bool SSLVerifier::VerifyX509(X509* x509, STACK_OF(X509) * chain) { +bool SSLVerifier::VerifyX509(X509* x509, + STACK_OF(X509) * chain, + const std::optional& ca_cert) { { char data[256]; RTC_LOG(LS_INFO) << "cert:"; @@ -186,20 +191,28 @@ bool SSLVerifier::VerifyX509(X509* x509, STACK_OF(X509) * chain) { return false; } - // Let's Encrypt の証明書を追加 - if (!AddCert(isrg_root, store)) { - return false; - } - if (!AddCert(lets_encrypt_r3, store)) { - return false; - } - - // WebRTC が用意しているルート証明書の設定 - LoadBuiltinSSLRootCertificates(store); - // デフォルト証明書のパスの設定 - X509_STORE_set_default_paths(store); - RTC_LOG(LS_INFO) << "default cert file: " << X509_get_default_cert_file(); + if (!ca_cert) { + // Let's Encrypt の証明書を追加 + if (!AddCert(isrg_root, store)) { + return false; + } + if (!AddCert(lets_encrypt_r3, store)) { + return false; + } + // WebRTC が用意しているルート証明書の設定 + LoadBuiltinSSLRootCertificates(store); + // デフォルト証明書のパスの設定 + X509_STORE_set_default_paths(store); + RTC_LOG(LS_INFO) << "default cert file: " << X509_get_default_cert_file(); + } else { + // ルート証明書が指定されている場合、その証明書以外は読み込まない + if (!AddCert(*ca_cert, store)) { + RTC_LOG(LS_ERROR) << "Failed to add ca_cert: ca_cert_length=" + << ca_cert->size(); + return false; + } + } ctx = X509_STORE_CTX_new(); if (ctx == nullptr) { RTC_LOG(LS_ERROR) << "X509_STORE_CTX_new failed"; diff --git a/src/websocket.cpp b/src/websocket.cpp index 5b60a404..5c944301 100644 --- a/src/websocket.cpp +++ b/src/websocket.cpp @@ -19,8 +19,8 @@ namespace sora { static std::shared_ptr CreateSSLContext( - const std::string& client_cert, - const std::string& client_key) { + const std::optional& client_cert, + const std::optional& client_key) { // TLS 1.2 と 1.3 のみ対応 SSL_CTX* handle = ::SSL_CTX_new(::TLS_method()); SSL_CTX_set_min_proto_version(handle, TLS1_2_VERSION); @@ -31,15 +31,27 @@ static std::shared_ptr CreateSSLContext( boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::single_dh_use); - if (!client_cert.empty()) { - ctx->use_certificate_file(client_cert, - boost::asio::ssl::context_base::file_format::pem); - RTC_LOG(LS_INFO) << "client_cert=" << client_cert; + if (client_cert) { + boost::system::error_code ec; + ctx->use_certificate(boost::asio::buffer(*client_cert), + boost::asio::ssl::context_base::file_format::pem, ec); + if (ec) { + RTC_LOG(LS_WARNING) << "client_cert is set, but use_certificate failed: " + << ec.message(); + } else { + RTC_LOG(LS_INFO) << "client_cert is set"; + } } - if (!client_key.empty()) { - ctx->use_private_key_file(client_key, - boost::asio::ssl::context_base::file_format::pem); - RTC_LOG(LS_INFO) << "client_key=" << client_key; + if (client_key) { + boost::system::error_code ec; + ctx->use_private_key(boost::asio::buffer(*client_key), + boost::asio::ssl::context_base::file_format::pem, ec); + if (ec) { + RTC_LOG(LS_WARNING) << "client_key is set, but use_private_key failed: " + << ec.message(); + } else { + RTC_LOG(LS_INFO) << "client_key is set"; + } } return ctx; } @@ -55,16 +67,18 @@ Websocket::Websocket(boost::asio::io_context& ioc) Websocket::Websocket(Websocket::ssl_tag, boost::asio::io_context& ioc, bool insecure, - const std::string& client_cert, - const std::string& client_key) + const std::optional& client_cert, + const std::optional& client_key, + const std::optional& ca_cert) : resolver_(new boost::asio::ip::tcp::resolver(ioc)), strand_(ioc.get_executor()), close_timeout_timer_(ioc), insecure_(insecure), - user_agent_(Version::GetDefaultUserAgent()) { + user_agent_(Version::GetDefaultUserAgent()), + ca_cert_(ca_cert) { ssl_ctx_ = CreateSSLContext(client_cert, client_key); wss_.reset(new ssl_websocket_t(ioc, *ssl_ctx_)); - InitWss(wss_.get(), insecure); + InitWss(wss_.get(), insecure, ca_cert); } Websocket::Websocket(boost::asio::ip::tcp::socket socket) : ws_(new websocket_t(std::move(socket))), @@ -76,14 +90,17 @@ Websocket::Websocket(boost::asio::ip::tcp::socket socket) Websocket::Websocket(https_proxy_tag, boost::asio::io_context& ioc, bool insecure, - const std::string& client_cert, - const std::string& client_key, + const std::optional& client_cert, + const std::optional& client_key, + const std::optional& ca_cert, std::string proxy_url, std::string proxy_username, std::string proxy_password) : resolver_(new boost::asio::ip::tcp::resolver(ioc)), strand_(ioc.get_executor()), close_timeout_timer_(ioc), + insecure_(insecure), + ca_cert_(ca_cert), https_proxy_(true), proxy_socket_(new boost::asio::ip::tcp::socket(ioc)), proxy_url_(std::move(proxy_url)), @@ -105,12 +122,15 @@ bool Websocket::IsSSL() const { return https_proxy_ || wss_ != nullptr; } -void Websocket::InitWss(ssl_websocket_t* wss, bool insecure) { +void Websocket::InitWss(ssl_websocket_t* wss, + bool insecure, + const std::optional& ca_cert) { wss->write_buffer_bytes(8192); wss->next_layer().set_verify_mode(boost::asio::ssl::verify_peer); wss->next_layer().set_verify_callback( - [insecure](bool preverified, boost::asio::ssl::verify_context& ctx) { + [insecure, ca_cert](bool preverified, + boost::asio::ssl::verify_context& ctx) { if (preverified) { return true; } @@ -120,7 +140,7 @@ void Websocket::InitWss(ssl_websocket_t* wss, bool insecure) { } X509* cert = X509_STORE_CTX_get0_cert(ctx.native_handle()); STACK_OF(X509)* chain = X509_STORE_CTX_get0_chain(ctx.native_handle()); - return SSLVerifier::VerifyX509(cert, chain); + return SSLVerifier::VerifyX509(cert, chain, ca_cert); }); } @@ -411,7 +431,7 @@ void Websocket::OnReadProxy(boost::system::error_code ec, // wss を作って、あとは普通の SSL ハンドシェイクを行う wss_.reset(new ssl_websocket_t(std::move(*proxy_socket_), *ssl_ctx_)); - InitWss(wss_.get(), insecure_); + InitWss(wss_.get(), insecure_, ca_cert_); // SNI の設定を行う if (!SSL_set_tlsext_host_name(wss_->next_layer().native_handle(), @@ -563,4 +583,4 @@ const boost::beast::websocket::close_reason& Websocket::reason() const { return IsSSL() ? wss_->reason() : ws_->reason(); } -} // namespace sora \ No newline at end of file +} // namespace sora diff --git a/test/android/app/build.gradle b/test/android/app/build.gradle index cc159cf7..1f763091 100644 --- a/test/android/app/build.gradle +++ b/test/android/app/build.gradle @@ -65,7 +65,7 @@ android { externalNativeBuild { cmake { path file('src/main/cpp/CMakeLists.txt') - version '3.29.6' + version '3.30.3' } } buildFeatures {