diff --git a/.github/actions/download/action.yml b/.github/actions/download/action.yml index 4cee2a5..f367648 100644 --- a/.github/actions/download/action.yml +++ b/.github/actions/download/action.yml @@ -10,7 +10,7 @@ inputs: runs: using: composite steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ${{ inputs.platform }}.env path: ${{ inputs.platform }}.env @@ -22,7 +22,7 @@ runs: echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT echo "$PACKAGE_NAME/$PACKAGE_NAME" >> package_paths.env id: env - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ${{ steps.env.outputs.package_name }} path: ${{ steps.env.outputs.package_name }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ae6654..4d3363d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: name: Build zakuro for ${{ matrix.name }} runs-on: ${{ matrix.name == 'ubuntu-22.04_x86_64' && 'ubuntu-22.04' || 'ubuntu-20.04' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Update repo if: matrix.name == 'ubuntu-22.04_x86_64' run: | @@ -46,12 +46,12 @@ jobs: echo "name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT id: package_name - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.package_name.outputs.name }} path: _package/${{ matrix.name }}/release/${{ steps.package_name.outputs.name }} - name: Upload Environment - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.name }}.env path: _package/${{ matrix.name }}/release/zakuro.env @@ -62,7 +62,7 @@ jobs: - build-linux runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/download with: platform: ubuntu-20.04_x86_64 diff --git a/.gitignore b/.gitignore index 5e57cf6..6792c56 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,6 @@ zakuro core -.vscode *.tar.gz webrtc_logs_0 .DS_Store diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..f3f6436 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,37 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "/usr/include", + "${workspaceFolder}/_build/ubuntu-20.04_x86_64/release/zakuro", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/sora/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/webrtc/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/webrtc/include/third_party/abseil-cpp", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/webrtc/include/third_party/boringssl/src/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/webrtc/include/third_party/libyuv/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/llvm/libcxx/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/boost/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/cli11/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/blend2d/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/openh264/include", + "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/yaml/include" + ], + "defines": [ + "WEBRTC_POSIX", + "WEBRTC_LINUX", + "_LIBCPP_ABI_NAMESPACE=Cr", + "_LIBCPP_ABI_VERSION=2", + "_LIBCPP_DISABLE_AVAILABILITY", + "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + "OPENSSL_IS_BORINGSSL" + ], + "compilerPath": "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/llvm/clang/bin/clang++", + "compilerArgs": ["-nostdinc++"], + "cStandard": "gnu17", + "cppStandard": "gnu++17", + "intelliSenseMode": "linux-clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..8dca371 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["charliermarsh.ruff", "ms-python.mypy-type-checker"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1115a58 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,40 @@ +{ + "python.analysis.autoImportCompletions": true, + "python.analysis.typeCheckingMode": "basic", + "[python]": { + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.autoIndent": "full", + "editor.codeActionsOnSave": { + "source.fixAll.ruff": "always", + "source.organizeImports.ruff": "explicit" + } + }, + "[cpp]": { + "editor.formatOnSave": true + }, + "files.associations": { + "*.cs": "csharp", + "CMakeLists.txt": "cmake", + "*.txt": "plaintext", + "csignal": "cpp", + "cstdlib": "cpp", + "memory": "cpp", + "algorithm": "cpp", + "*.ipp": "cpp", + "fstream": "cpp", + "iosfwd": "cpp", + "type_traits": "cpp", + "memory_resource": "cpp", + "ostream": "cpp", + "__node_handle": "cpp", + "__config": "cpp", + "random": "cpp", + "stdexcept": "cpp", + "chrono": "cpp", + "string": "cpp", + "__mutex_base": "cpp", + "vector": "cpp" + } +} \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 73db70b..9eefe7a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,49 @@ ## develop +## 2024.1.0 (2024-04-24) + +- [CHANGE] Lyra を削除 + - `--sora-audio-codec-lyra-bitrate` オプションを削除 + - `--sora-audio-codec-lyra-usedtx` オプションを削除 + - `--sora-check-lyra-version` オプションを削除 + - `--sora-audio-codec-type` から LYRA を削除 + - インストールするファイルに model_coeffs を含めないようにする + - VERSION ファイルから LYRA_VERSION を削除 + - @melpon +- [ADD] run.py に `--webrtc-build-dir` と `--webrtc-build-args` オプションを追加 + - @melpon +- [ADD] run.py に `--sora-dir` と `--sora-args` オプションを追加 + - @melpon +- [UPDATE] Sora C++ SDK を 2024.6.1 に上げる + - それに伴って以下のライブラリのバージョンも上げる + - WebRTC を m122.6261.1.0 に上げる + - Ubuntu のビルドを通すために、 __assertion_handler というファイルをコピーする処理を追加した + - Boost を 1.84.0 に上げる + - @torikizi @voluntas @melpon +- [UPDATE] asmjit と blend2d を最新版に上げる + - @voluntas @melpon +- [UPDATE] `CMake` を `3.28.1` に上げる + - @voluntas @torikizi @melpon +- [UPDATE] OpenH264 を 2.4.1 に上げる + - @melpon +- [UPDATE] CLI11 を 2.4.1 に上げる + - @melpon +- [UPDATE] run.py に定義されていた関数を buildbase.py に移動する + - @melpon +- [UPDATE] Github Actions の actions/checkout , actions/upload-artifact , actions/download-artifact をアップデート + - Node.js 16 の Deprecated に伴うアップデート + - actions/checkout@v3 から actions/checkout@v4 にアップデート + - actions/upload-artifact@v3 から actions/upload-artifact@v4 にアップデート + - actions/download-artifact@v3 から actions/download-artifact@v4 にアップデート + - @miosakuma @torikizi +- [FIX] VideoCodec は Protected のため CreateVideoCodec に修正 + - m117.5938.2.0 へのアップデートに伴う修正 + - @torikizi +- [FIX] resetMatrix() から resetTransform() に修正 + - blend2d を最新版に上げた際に発生した問題の修正 + - @torikizi + ## 2023.1.0 (2023-08-23) - [CHANGE] `--fake-network-send-codel-active-queue-management` と `--fake-network-receive-codel-active-queue-management` オプションを削除 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d94241..0b1d8a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,6 @@ set(Boost_USE_STATIC_LIBS ON) set(WEBRTC_LIBRARY_NAME webrtc) find_package(Boost REQUIRED COMPONENTS json filesystem) -find_package(Lyra REQUIRED) find_package(WebRTC REQUIRED) find_package(Sora REQUIRED) find_package(Threads REQUIRED) @@ -43,7 +42,7 @@ target_sources(zakuro PRIVATE src/dynamic_h264_video_encoder.cpp src/embedded_binary.cpp - src/fake_network_call_factory.cpp + src/enable_media_with_fake_call.cpp src/fake_video_capturer.cpp src/main.cpp src/nop_video_decoder.cpp @@ -65,7 +64,7 @@ target_link_libraries(zakuro Boost::filesystem CLI11::CLI11 Blend2D::Blend2D - yaml-cpp + yaml-cpp::yaml-cpp ) target_compile_definitions(zakuro diff --git a/README.md b/README.md index eac26dc..6fbb0d5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # WebRTC Load Testing Tool Zakuro -[![libwebrtc](https://img.shields.io/badge/libwebrtc-m115.5790-blue.svg)](https://chromium.googlesource.com/external/webrtc/+/branch-heads/5790) +[![libwebrtc](https://img.shields.io/badge/libwebrtc-m122.6261-blue.svg)](https://chromium.googlesource.com/external/webrtc/+/branch-heads/6261) [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/shiguredo/zakuro.svg)](https://github.com/shiguredo/zakuro) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) diff --git a/VERSION b/VERSION index 0dfd83d..d5bc5ab 100644 --- a/VERSION +++ b/VERSION @@ -1,11 +1,10 @@ -ZAKURO_VERSION=2023.1.0 -SORA_CPP_SDK_VERSION=2023.9.0 -WEBRTC_BUILD_VERSION=m115.5790.7.0 -BOOST_VERSION=1.82.0 -LYRA_VERSION=1.3.0 -CLI11_VERSION=v2.3.2 -CMAKE_VERSION=3.26.4 -BLEND2D_VERSION=a84dfdbd1d03f9b203e18b9158387af32b6ce41e -ASMJIT_VERSION=5c469e3f7c307da939d38d72e09f08db7ca076ef -OPENH264_VERSION=v2.3.1 -YAML_CPP_VERSION=yaml-cpp-0.7.0 +ZAKURO_VERSION=2024.1.0 +SORA_CPP_SDK_VERSION=2024.6.1 +WEBRTC_BUILD_VERSION=m122.6261.1.0 +BOOST_VERSION=1.84.0 +CLI11_VERSION=v2.4.1 +CMAKE_VERSION=3.28.1 +BLEND2D_VERSION=5a263ce51f3f880ee6c60f6345d18c3eccbe200f +ASMJIT_VERSION=3ca5c186bf8922e5fe3018432e93651fd2fa4053 +OPENH264_VERSION=v2.4.1 +YAML_CPP_VERSION=0.8.0 diff --git a/buildbase.py b/buildbase.py new file mode 100644 index 0000000..2bf0e9c --- /dev/null +++ b/buildbase.py @@ -0,0 +1,1528 @@ +# buildbase.py はビルドスクリプトのテンプレートとなるファイル +# +# 自身のリポジトリにコピーして利用する。 +# +# 元のファイルは以下のリポジトリにある: +# https://github.com/melpon/buildbase +# +# 更新する場合は以下のコマンドを利用する: +# curl -LO https://raw.githubusercontent.com/melpon/buildbase/master/buildbase.py +# +# ライセンス: Apache License 2.0 +# +# Copyright 2024 melpon (Wandbox) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import filecmp +import glob +import logging +import multiprocessing +import os +import platform +import shlex +import shutil +import stat +import subprocess +import tarfile +import urllib.parse +import zipfile +from typing import Dict, List, NamedTuple, Optional + +if platform.system() == "Windows": + import winreg + + +class ChangeDirectory(object): + def __init__(self, cwd): + self._cwd = cwd + + def __enter__(self): + self._old_cwd = os.getcwd() + logging.debug(f"pushd {self._old_cwd} --> {self._cwd}") + os.chdir(self._cwd) + + def __exit__(self, exctype, excvalue, trace): + logging.debug(f"popd {self._old_cwd} <-- {self._cwd}") + os.chdir(self._old_cwd) + return False + + +def cd(cwd): + return ChangeDirectory(cwd) + + +def cmd(args, **kwargs): + logging.debug(f"+{args} {kwargs}") + if "check" not in kwargs: + kwargs["check"] = True + if "resolve" in kwargs: + resolve = kwargs["resolve"] + del kwargs["resolve"] + else: + resolve = True + if resolve: + args = [shutil.which(args[0]), *args[1:]] + return subprocess.run(args, **kwargs) + + +# 標準出力をキャプチャするコマンド実行。シェルの `cmd ...` や $(cmd ...) と同じ +def cmdcap(args, **kwargs): + # 3.7 でしか使えない + # kwargs['capture_output'] = True + kwargs["stdout"] = subprocess.PIPE + kwargs["stderr"] = subprocess.PIPE + kwargs["encoding"] = "utf-8" + return cmd(args, **kwargs).stdout.strip() + + +# https://stackoverflow.com/a/2656405 +def onerror(func, path, exc_info): + """ + Error handler for ``shutil.rmtree``. + If the error is due to an access error (read only file) + it attempts to add write permission and then retries. + If the error is for another reason it re-raises the error. + + Usage : ``shutil.rmtree(path, onerror=onerror)`` + """ + import stat + + # Is the error an access error? + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise + + +def rm_rf(path: str): + if not os.path.exists(path): + logging.debug(f"rm -rf {path} => path not found") + return + if os.path.isfile(path) or os.path.islink(path): + os.remove(path) + logging.debug(f"rm -rf {path} => file removed") + if os.path.isdir(path): + shutil.rmtree(path, onerror=onerror) + logging.debug(f"rm -rf {path} => directory removed") + + +def mkdir_p(path: str): + if os.path.exists(path): + logging.debug(f"mkdir -p {path} => already exists") + return + os.makedirs(path, exist_ok=True) + logging.debug(f"mkdir -p {path} => directory created") + + +if platform.system() == "Windows": + PATH_SEPARATOR = ";" +else: + PATH_SEPARATOR = ":" + + +def add_path(path: str, is_after=False): + logging.debug(f"add_path: {path}") + if "PATH" not in os.environ: + os.environ["PATH"] = path + return + + if is_after: + os.environ["PATH"] = os.environ["PATH"] + PATH_SEPARATOR + path + else: + os.environ["PATH"] = path + PATH_SEPARATOR + os.environ["PATH"] + + +def download(url: str, output_dir: Optional[str] = None, filename: Optional[str] = None) -> str: + if filename is None: + output_path = urllib.parse.urlparse(url).path.split("/")[-1] + else: + output_path = filename + + if output_dir is not None: + output_path = os.path.join(output_dir, output_path) + + if os.path.exists(output_path): + return output_path + + try: + if shutil.which("curl") is not None: + cmd(["curl", "-fLo", output_path, url]) + else: + cmd(["wget", "-cO", output_path, url]) + except Exception: + # ゴミを残さないようにする + if os.path.exists(output_path): + os.remove(output_path) + raise + + return output_path + + +def read_version_file(path: str) -> Dict[str, str]: + versions = {} + + lines = open(path).readlines() + for line in lines: + line = line.strip() + + # コメント行 + if line[:1] == "#": + continue + + # 空行 + if len(line) == 0: + continue + + [a, b] = map(lambda x: x.strip(), line.split("=", 2)) + versions[a] = b.strip('"') + + return versions + + +# dir 以下にある全てのファイルパスを、dir2 からの相対パスで返す +def enum_all_files(dir, dir2): + for root, _, files in os.walk(dir): + for file in files: + yield os.path.relpath(os.path.join(root, file), dir2) + + +def versioned(func): + def wrapper(version, version_file, *args, **kwargs): + if "ignore_version" in kwargs: + if kwargs.get("ignore_version"): + rm_rf(version_file) + del kwargs["ignore_version"] + + if os.path.exists(version_file): + ver = open(version_file).read() + if ver.strip() == version.strip(): + return + + r = func(version=version, *args, **kwargs) + + with open(version_file, "w") as f: + f.write(version) + + return r + + return wrapper + + +# アーカイブが単一のディレクトリに全て格納されているかどうかを調べる。 +# +# 単一のディレクトリに格納されている場合はそのディレクトリ名を返す。 +# そうでない場合は None を返す。 +def _is_single_dir(infos, get_name, is_dir) -> Optional[str]: + # tarfile: ['path', 'path/to', 'path/to/file.txt'] + # zipfile: ['path/', 'path/to/', 'path/to/file.txt'] + # どちらも / 区切りだが、ディレクトリの場合、後ろに / が付くかどうかが違う + dirname = None + for info in infos: + name = get_name(info) + n = name.rstrip("/").find("/") + if n == -1: + # ルートディレクトリにファイルが存在している + if not is_dir(info): + return None + dir = name.rstrip("/") + else: + dir = name[0:n] + # ルートディレクトリに2個以上のディレクトリが存在している + if dirname is not None and dirname != dir: + return None + dirname = dir + + return dirname + + +def is_single_dir_tar(tar: tarfile.TarFile) -> Optional[str]: + return _is_single_dir(tar.getmembers(), lambda t: t.name, lambda t: t.isdir()) + + +def is_single_dir_zip(zip: zipfile.ZipFile) -> Optional[str]: + return _is_single_dir(zip.infolist(), lambda z: z.filename, lambda z: z.is_dir()) + + +# 解凍した上でファイル属性を付与する +def _extractzip(z: zipfile.ZipFile, path: str): + z.extractall(path) + if platform.system() == "Windows": + return + for info in z.infolist(): + if info.is_dir(): + continue + filepath = os.path.join(path, info.filename) + mod = info.external_attr >> 16 + if (mod & 0o120000) == 0o120000: + # シンボリックリンク + with open(filepath, "r") as f: + src = f.read() + os.remove(filepath) + with cd(os.path.dirname(filepath)): + if os.path.exists(src): + os.symlink(src, filepath) + if os.path.exists(filepath): + # 普通のファイル + os.chmod(filepath, mod & 0o777) + + +# zip または tar.gz ファイルを展開する。 +# +# 展開先のディレクトリは {output_dir}/{output_dirname} となり、 +# 展開先のディレクトリが既に存在していた場合は削除される。 +# +# もしアーカイブの内容が単一のディレクトリであった場合、 +# そのディレクトリは無いものとして展開される。 +# +# つまりアーカイブ libsora-1.23.tar.gz の内容が +# ['libsora-1.23', 'libsora-1.23/file1', 'libsora-1.23/file2'] +# であった場合、extract('libsora-1.23.tar.gz', 'out', 'libsora') のようにすると +# - out/libsora/file1 +# - out/libsora/file2 +# が出力される。 +# +# また、アーカイブ libsora-1.23.tar.gz の内容が +# ['libsora-1.23', 'libsora-1.23/file1', 'libsora-1.23/file2', 'LICENSE'] +# であった場合、extract('libsora-1.23.tar.gz', 'out', 'libsora') のようにすると +# - out/libsora/libsora-1.23/file1 +# - out/libsora/libsora-1.23/file2 +# - out/libsora/LICENSE +# が出力される。 +def extract(file: str, output_dir: str, output_dirname: str, filetype: Optional[str] = None): + path = os.path.join(output_dir, output_dirname) + logging.info(f"Extract {file} to {path}") + if filetype == "gzip" or file.endswith(".tar.gz"): + rm_rf(path) + with tarfile.open(file) as t: + dir = is_single_dir_tar(t) + if dir is None: + os.makedirs(path, exist_ok=True) + t.extractall(path) + else: + logging.info(f"Directory {dir} is stripped") + path2 = os.path.join(output_dir, dir) + rm_rf(path2) + t.extractall(output_dir) + if path != path2: + logging.debug(f"mv {path2} {path}") + os.replace(path2, path) + elif filetype == "zip" or file.endswith(".zip"): + rm_rf(path) + with zipfile.ZipFile(file) as z: + dir = is_single_dir_zip(z) + if dir is None: + os.makedirs(path, exist_ok=True) + # z.extractall(path) + _extractzip(z, path) + else: + logging.info(f"Directory {dir} is stripped") + path2 = os.path.join(output_dir, dir) + rm_rf(path2) + # z.extractall(output_dir) + _extractzip(z, output_dir) + if path != path2: + logging.debug(f"mv {path2} {path}") + os.replace(path2, path) + else: + raise Exception("file should end with .tar.gz or .zip") + + +def clone_and_checkout(url, version, dir, fetch, fetch_force): + if fetch_force: + rm_rf(dir) + + if not os.path.exists(os.path.join(dir, ".git")): + cmd(["git", "clone", url, dir]) + fetch = True + + if fetch: + with cd(dir): + cmd(["git", "fetch"]) + cmd(["git", "reset", "--hard"]) + cmd(["git", "clean", "-df"]) + cmd(["git", "checkout", "-f", version]) + + +def git_clone_shallow(url, hash, dir): + rm_rf(dir) + mkdir_p(dir) + with cd(dir): + cmd(["git", "init"]) + cmd(["git", "remote", "add", "origin", url]) + cmd(["git", "fetch", "--depth=1", "origin", hash]) + cmd(["git", "reset", "--hard", "FETCH_HEAD"]) + + +def apply_patch(patch, dir, depth): + with cd(dir): + logging.info(f"patch -p{depth} < {patch}") + if platform.system() == "Windows": + cmd( + [ + "git", + "apply", + f"-p{depth}", + "--ignore-space-change", + "--ignore-whitespace", + "--whitespace=nowarn", + patch, + ] + ) + else: + with open(patch) as stdin: + cmd(["patch", f"-p{depth}"], stdin=stdin) + + +def copyfile_if_different(src, dst): + if os.path.exists(dst) and filecmp.cmp(src, dst, shallow=False): + return + shutil.copyfile(src, dst) + + +# NOTE(enm10k): shutil.copytree に Python 3.8 で追加された dirs_exist_ok=True を指定して使いたかったが、 +# GitHub Actions の Windows のランナー (widnwos-2019) にインストールされている Python のバージョンが古くて利用できなかった +# actions/setup-python で Python 3.8 を設定してビルドしたところ、 Lyra のビルドがエラーになったためこの関数を自作した +# Windows のランナーを更新した場合は、この関数は不要になる可能性が高い +def copytree(src_dir, dst_dir): + for file_path in glob.glob(src_dir + "/**", recursive=True): + dest_path = os.path.join(dst_dir, os.path.relpath(file_path, src_dir)) + + if os.path.isdir(file_path): + os.makedirs(dest_path, exist_ok=True) + else: + shutil.copy2(file_path, dest_path) + + +def git_get_url_and_revision(dir): + with cd(dir): + rev = cmdcap(["git", "rev-parse", "HEAD"]) + url = cmdcap(["git", "remote", "get-url", "origin"]) + return url, rev + + +def replace_vcproj_static_runtime(project_file: str): + # なぜか MSVC_STATIC_RUNTIME が効かずに DLL ランタイムを使ってしまうので + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + s = open(project_file, "r", encoding="utf-8").read() + s = s.replace("MultiThreadedDLL", "MultiThreaded") + s = s.replace("MultiThreadedDebugDLL", "MultiThreadedDebug") + open(project_file, "w", encoding="utf-8").write(s) + + +@versioned +def install_webrtc(version, source_dir, install_dir, platform: str): + win = platform.startswith("windows_") + filename = f'webrtc.{platform}.{"zip" if win else "tar.gz"}' + rm_rf(os.path.join(source_dir, filename)) + archive = download( + f"https://github.com/shiguredo-webrtc-build/webrtc-build/releases/download/{version}/{filename}", + output_dir=source_dir, + ) + rm_rf(os.path.join(install_dir, "webrtc")) + extract(archive, output_dir=install_dir, output_dirname="webrtc") + + +def build_webrtc(platform, webrtc_build_dir, webrtc_build_args, debug): + with cd(webrtc_build_dir): + args = ["--webrtc-nobuild-ios-framework", "--webrtc-nobuild-android-aar"] + if debug: + args += ["--debug"] + + args += webrtc_build_args + + cmd(["python3", "run.py", "build", platform, *args]) + + # インクルードディレクトリを増やしたくないので、 + # __config_site を libc++ のディレクトリにコピーしておく + webrtc_source_dir = os.path.join(webrtc_build_dir, "_source", platform, "webrtc") + src_config = os.path.join( + webrtc_source_dir, "src", "buildtools", "third_party", "libc++", "__config_site" + ) + dst_config = os.path.join( + webrtc_source_dir, "src", "third_party", "libc++", "src", "include", "__config_site" + ) + copyfile_if_different(src_config, dst_config) + + # __assertion_handler をコピーする + src_assertion = os.path.join( + webrtc_source_dir, + "src", + "buildtools", + "third_party", + "libc++", + "__assertion_handler", + ) + dst_assertion = os.path.join( + webrtc_source_dir, + "src", + "third_party", + "libc++", + "src", + "include", + "__assertion_handler", + ) + copyfile_if_different(src_assertion, dst_assertion) + + +class WebrtcInfo(NamedTuple): + version_file: str + deps_file: str + webrtc_include_dir: str + webrtc_source_dir: Optional[str] + webrtc_library_dir: str + clang_dir: str + libcxx_dir: str + + +def get_webrtc_info( + platform: str, webrtc_build_dir: Optional[str], install_dir: str, debug: bool +) -> WebrtcInfo: + webrtc_install_dir = os.path.join(install_dir, "webrtc") + + if webrtc_build_dir is None: + return WebrtcInfo( + version_file=os.path.join(webrtc_install_dir, "VERSIONS"), + deps_file=os.path.join(webrtc_install_dir, "DEPS"), + webrtc_include_dir=os.path.join(webrtc_install_dir, "include"), + webrtc_source_dir=None, + webrtc_library_dir=os.path.join(webrtc_install_dir, "lib"), + clang_dir=os.path.join(install_dir, "llvm", "clang"), + libcxx_dir=os.path.join(install_dir, "llvm", "libcxx"), + ) + else: + webrtc_build_source_dir = os.path.join(webrtc_build_dir, "_source", platform, "webrtc") + configuration = "debug" if debug else "release" + webrtc_build_build_dir = os.path.join( + webrtc_build_dir, "_build", platform, configuration, "webrtc" + ) + + return WebrtcInfo( + version_file=os.path.join(webrtc_build_dir, "VERSION"), + deps_file=os.path.join(webrtc_build_dir, "DEPS"), + webrtc_include_dir=os.path.join(webrtc_build_source_dir, "src"), + webrtc_source_dir=os.path.join(webrtc_build_source_dir, "src"), + webrtc_library_dir=webrtc_build_build_dir, + clang_dir=os.path.join( + webrtc_build_source_dir, "src", "third_party", "llvm-build", "Release+Asserts" + ), + libcxx_dir=os.path.join(webrtc_build_source_dir, "src", "third_party", "libc++", "src"), + ) + + +@versioned +def install_boost(version, source_dir, install_dir, sora_version, platform: str): + win = platform.startswith("windows_") + filename = ( + f'boost-{version}_sora-cpp-sdk-{sora_version}_{platform}.{"zip" if win else "tar.gz"}' + ) + rm_rf(os.path.join(source_dir, filename)) + archive = download( + f"https://github.com/shiguredo/sora-cpp-sdk/releases/download/{sora_version}/{filename}", + output_dir=source_dir, + ) + rm_rf(os.path.join(install_dir, "boost")) + extract(archive, output_dir=install_dir, output_dirname="boost") + + +@versioned +def build_and_install_boost( + version: str, + source_dir, + build_dir, + install_dir, + debug: bool, + cxx: str, + cflags: List[str], + cxxflags: List[str], + linkflags: List[str], + toolset, + visibility, + target_os, + architecture, + android_ndk, + native_api_level, +): + version_underscore = version.replace(".", "_") + archive = download( + f"https://boostorg.jfrog.io/artifactory/main/release/{version}/source/boost_{version_underscore}.tar.gz", + source_dir, + ) + extract(archive, output_dir=build_dir, output_dirname="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" + + cmd([bootstrap]) + + if target_os == "iphone": + IOS_BUILD_TARGETS = [("arm64", "iphoneos")] + for arch, sdk in IOS_BUILD_TARGETS: + clangpp = cmdcap(["xcodebuild", "-find", "clang++"]) + sysroot = cmdcap(["xcrun", "--sdk", sdk, "--show-sdk-path"]) + boost_arch = "x86" if arch == "x86_64" else "arm" + with open("project-config.jam", "w") as f: + f.write( + f"using clang \ + : iphone \ + : {clangpp} -arch {arch} -isysroot {sysroot} \ + -fembed-bitcode \ + -mios-version-min=10.0 \ + -fvisibility=hidden \ + : {sysroot} \ + ; \ + " + ) + cmd( + [ + b2, + "install", + "-d+0", + f'--build-dir={os.path.join(build_dir, "boost", f"build-{arch}-{sdk}")}', + f'--prefix={os.path.join(build_dir, "boost", f"install-{arch}-{sdk}")}', + "--with-json", + "--with-filesystem", + "--layout=system", + "--ignore-site-config", + f'variant={"debug" if debug else "release"}', + f'cflags={" ".join(cflags)}', + f'cxxflags={" ".join(cxxflags)}', + f'linkflags={" ".join(linkflags)}', + f"toolset={toolset}", + f"visibility={visibility}", + f"target-os={target_os}", + "address-model=64", + "link=static", + f"runtime-link={runtime_link}", + "threading=multi", + f"architecture={boost_arch}", + ] + ) + arch, sdk = IOS_BUILD_TARGETS[0] + installed_path = os.path.join(build_dir, "boost", f"install-{arch}-{sdk}") + rm_rf(os.path.join(install_dir, "boost")) + cmd(["cp", "-r", installed_path, os.path.join(install_dir, "boost")]) + + for lib in enum_all_files( + os.path.join(installed_path, "lib"), os.path.join(installed_path, "lib") + ): + if not lib.endswith(".a"): + continue + files = [ + os.path.join(build_dir, "boost", f"install-{arch}-{sdk}", "lib", lib) + for arch, sdk in IOS_BUILD_TARGETS + ] + if len(files) == 1: + shutil.copyfile(files[0], os.path.join(install_dir, "boost", "lib", lib)) + else: + cmd( + [ + "lipo", + "-create", + "-output", + os.path.join(install_dir, "boost", "lib", lib), + ] + + files + ) + elif target_os == "android": + # Android の場合、android-ndk を使ってビルドする + with open("project-config.jam", "w") as f: + bin = os.path.join( + android_ndk, "toolchains", "llvm", "prebuilt", "linux-x86_64", "bin" + ) + sysroot = os.path.join( + android_ndk, "toolchains", "llvm", "prebuilt", "linux-x86_64", "sysroot" + ) + f.write( + f"using clang \ + : android \ + : {os.path.join(bin, 'clang++')} \ + --target=aarch64-none-linux-android{native_api_level} \ + --sysroot={sysroot} \ + : {os.path.join(bin, 'llvm-ar')} \ + {os.path.join(bin, 'llvm-ranlib')} \ + ; \ + " + ) + cmd( + [ + b2, + "install", + "-d+0", + f'--prefix={os.path.join(install_dir, "boost")}', + "--with-json", + "--with-filesystem", + "--layout=system", + "--ignore-site-config", + f'variant={"debug" if debug else "release"}', + f"compileflags=--sysroot={sysroot}", + f'cflags={" ".join(cflags)}', + f'cxxflags={" ".join(cxxflags)}', + f'linkflags={" ".join(linkflags)}', + f"toolset={toolset}", + f"visibility={visibility}", + f"target-os={target_os}", + "address-model=64", + "link=static", + f"runtime-link={runtime_link}", + "threading=multi", + "architecture=arm", + ] + ) + else: + if len(cxx) != 0: + with open("project-config.jam", "w") as f: + f.write(f"using {toolset} : : {cxx} : ;") + cmd( + [ + b2, + "install", + "-d+0", + f'--prefix={os.path.join(install_dir, "boost")}', + "--with-json", + "--with-filesystem", + "--layout=system", + "--ignore-site-config", + f'variant={"debug" if debug else "release"}', + f'cflags={" ".join(cflags)}', + f'cxxflags={" ".join(cxxflags)}', + f'linkflags={" ".join(linkflags)}', + f"toolset={toolset}", + f"visibility={visibility}", + f"target-os={target_os}", + "address-model=64", + "link=static", + f"runtime-link={runtime_link}", + "threading=multi", + f"architecture={architecture}", + ] + ) + + +@versioned +def install_sora(version, source_dir, install_dir, platform: str): + win = platform.startswith("windows_") + filename = f'sora-cpp-sdk-{version}_{platform}.{"zip" if win else "tar.gz"}' + rm_rf(os.path.join(source_dir, filename)) + archive = download( + f"https://github.com/shiguredo/sora-cpp-sdk/releases/download/{version}/{filename}", + output_dir=source_dir, + ) + rm_rf(os.path.join(install_dir, "sora")) + 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") + + # Boost + install_boost_args = { + "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"], + "platform": platform, + } + install_boost(**install_boost_args) + + # Sora C++ SDK + install_sora_args = { + "version": version["SORA_CPP_SDK_VERSION"], + "version_file": os.path.join(install_dir, "sora.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": platform, + } + install_sora(**install_sora_args) + + +def build_sora( + platform: str, sora_dir: str, sora_args: List[str], debug: bool, webrtc_build_dir: Optional[str] +): + if debug and "--debug" not in sora_args: + sora_args = ["--debug", *sora_args] + if webrtc_build_dir is not None: + sora_args = ["--webrtc-build-dir", webrtc_build_dir, *sora_args] + + with cd(sora_dir): + cmd(["python3", "run.py", platform, *sora_args]) + + +class SoraInfo(NamedTuple): + sora_install_dir: str + boost_install_dir: str + + +def get_sora_info( + platform: str, sora_dir: Optional[str], install_dir: str, debug: bool +) -> SoraInfo: + if sora_dir is not None: + configuration = "debug" if debug else "release" + install_dir = os.path.join(sora_dir, "_install", platform, configuration) + + return SoraInfo( + sora_install_dir=os.path.join(install_dir, "sora"), + boost_install_dir=os.path.join(install_dir, "boost"), + ) + + +@versioned +def install_rootfs(version, install_dir, conf): + rootfs_dir = os.path.join(install_dir, "rootfs") + rm_rf(rootfs_dir) + cmd(["multistrap", "--no-auth", "-a", "arm64", "-d", rootfs_dir, "-f", conf]) + # 絶対パスのシンボリックリンクを相対パスに置き換えていく + for dir, _, filenames in os.walk(rootfs_dir): + for filename in filenames: + linkpath = os.path.join(dir, filename) + # symlink かどうか + if not os.path.islink(linkpath): + continue + target = os.readlink(linkpath) + # 絶対パスかどうか + if not os.path.isabs(target): + continue + # rootfs_dir を先頭に付けることで、 + # rootfs の外から見て正しい絶対パスにする + targetpath = rootfs_dir + target + # 参照先の絶対パスが存在するかどうか + if not os.path.exists(targetpath): + continue + # 相対パスに置き換える + relpath = os.path.relpath(targetpath, dir) + logging.debug(f"{linkpath[len(rootfs_dir):]} targets {target} to {relpath}") + os.remove(linkpath) + os.symlink(relpath, linkpath) + + # なぜかシンボリックリンクが登録されていないので作っておく + link = os.path.join(rootfs_dir, "usr", "lib", "aarch64-linux-gnu", "tegra", "libnvbuf_fdmap.so") + file = os.path.join( + rootfs_dir, "usr", "lib", "aarch64-linux-gnu", "tegra", "libnvbuf_fdmap.so.1.0.0" + ) + if os.path.exists(file) and not os.path.exists(link): + os.symlink(os.path.basename(file), link) + + +@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 + ) + rm_rf(os.path.join(install_dir, "android-ndk")) + extract(archive, output_dir=install_dir, output_dirname="android-ndk") + + +@versioned +def install_android_sdk_cmdline_tools(version, install_dir, source_dir): + archive = download( + f"https://dl.google.com/android/repository/commandlinetools-linux-{version}_latest.zip", + source_dir, + ) + tools_dir = os.path.join(install_dir, "android-sdk-cmdline-tools") + rm_rf(tools_dir) + extract(archive, output_dir=tools_dir, output_dirname="cmdline-tools") + sdkmanager = os.path.join(tools_dir, "cmdline-tools", "bin", "sdkmanager") + # ライセンスを許諾する + cmd(["/bin/bash", "-c", f"yes | {sdkmanager} --sdk_root={tools_dir} --licenses"]) + + +@versioned +def install_llvm( + version, + install_dir, + tools_url, + tools_commit, + libcxx_url, + libcxx_commit, + buildtools_url, + buildtools_commit, +): + llvm_dir = os.path.join(install_dir, "llvm") + rm_rf(llvm_dir) + mkdir_p(llvm_dir) + with cd(llvm_dir): + # tools の update.py を叩いて特定バージョンの clang バイナリを拾う + git_clone_shallow(tools_url, tools_commit, "tools") + with cd("tools"): + cmd( + [ + "python3", + os.path.join("clang", "scripts", "update.py"), + "--output-dir", + os.path.join(llvm_dir, "clang"), + ] + ) + + # 特定バージョンの libcxx を利用する + git_clone_shallow(libcxx_url, libcxx_commit, "libcxx") + + # __config_site のために特定バージョンの buildtools を取得する + git_clone_shallow(buildtools_url, buildtools_commit, "buildtools") + with cd("buildtools"): + cmd(["git", "reset", "--hard", buildtools_commit]) + shutil.copyfile( + os.path.join(llvm_dir, "buildtools", "third_party", "libc++", "__config_site"), + os.path.join(llvm_dir, "libcxx", "include", "__config_site"), + ) + + # __assertion_handler をコピーする + # 背景: https://source.chromium.org/chromium/_/chromium/external/github.com/llvm/llvm-project/libcxx.git/+/1e5bda0d1ce8e346955aa4a85eaab258785f11f7 + shutil.copyfile( + # NOTE(enm10k): 最初は default_assertion_handler.in をコピーしていたが、 buildtools 以下に + # default_assertion_handler.in から生成されたと思われる __assertion_handler が存在するため、それをコピーする + # os.path.join(llvm_dir, "libcxx", "vendor", "llvm", "default_assertion_handler.in"), + os.path.join(llvm_dir, "buildtools", "third_party", "libc++", "__assertion_handler"), + os.path.join(llvm_dir, "libcxx", "include", "__assertion_handler"), + ) + + +def cmake_path(path: str) -> str: + return path.replace("\\", "/") + + +@versioned +def install_cmake(version, source_dir, install_dir, platform: str, ext): + url = f"https://github.com/Kitware/CMake/releases/download/v{version}/cmake-{version}-{platform}.{ext}" + path = download(url, source_dir) + extract(path, install_dir, "cmake") + # Android で自前の CMake を利用する場合、ninja へのパスが見つけられない問題があるので、同じディレクトリに symlink を貼る + # https://issuetracker.google.com/issues/206099937 + if platform.startswith("linux"): + with cd(os.path.join(install_dir, "cmake", "bin")): + cmd(["ln", "-s", "/usr/bin/ninja", "ninja"]) + + +@versioned +def install_sdl2( + version, source_dir, build_dir, install_dir, debug: bool, platform: str, cmake_args: List[str] +): + url = f"http://www.libsdl.org/release/SDL2-{version}.zip" + path = download(url, source_dir) + sdl2_source_dir = os.path.join(source_dir, "sdl2") + sdl2_build_dir = os.path.join(build_dir, "sdl2") + sdl2_install_dir = os.path.join(install_dir, "sdl2") + rm_rf(sdl2_source_dir) + rm_rf(sdl2_build_dir) + rm_rf(sdl2_install_dir) + extract(path, source_dir, "sdl2") + + mkdir_p(sdl2_build_dir) + with cd(sdl2_build_dir): + configuration = "Debug" if debug else "Release" + cmake_args = cmake_args[:] + cmake_args += [ + sdl2_source_dir, + f"-DCMAKE_BUILD_TYPE={configuration}", + f"-DCMAKE_INSTALL_PREFIX={cmake_path(sdl2_install_dir)}", + "-DBUILD_SHARED_LIBS=OFF", + ] + if platform == "windows": + cmake_args += [ + "-G", + "Visual Studio 16 2019", + "-DSDL_FORCE_STATIC_VCRT=ON", + "-DHAVE_LIBC=ON", + ] + elif platform == "macos": + # システムでインストール済みかによって ON/OFF が切り替わってしまうため、 + # どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する + cmake_args += [ + "-DSDL_ATOMIC=OFF", + "-DSDL_AUDIO=OFF", + "-DSDL_VIDEO=ON", + "-DSDL_RENDER=ON", + "-DSDL_EVENTS=ON", + "-DSDL_JOYSTICK=ON", + "-DSDL_HAPTIC=ON", + "-DSDL_POWER=ON", + "-DSDL_THREADS=ON", + "-DSDL_TIMERS=OFF", + "-DSDL_FILE=OFF", + "-DSDL_LOADSO=ON", + "-DSDL_CPUINFO=OFF", + "-DSDL_FILESYSTEM=OFF", + "-DSDL_SENSOR=ON", + "-DSDL_OPENGL=ON", + "-DSDL_OPENGLES=ON", + "-DSDL_RPI=OFF", + "-DSDL_WAYLAND=OFF", + "-DSDL_X11=OFF", + "-DSDL_VULKAN=OFF", + "-DSDL_VIVANTE=OFF", + "-DSDL_COCOA=ON", + "-DSDL_METAL=ON", + "-DSDL_KMSDRM=OFF", + ] + elif platform == "linux": + # システムでインストール済みかによって ON/OFF が切り替わってしまうため、 + # どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する + cmake_args += [ + "-DSDL_ATOMIC=OFF", + "-DSDL_AUDIO=OFF", + "-DSDL_VIDEO=ON", + "-DSDL_RENDER=ON", + "-DSDL_EVENTS=ON", + "-DSDL_JOYSTICK=ON", + "-DSDL_HAPTIC=ON", + "-DSDL_POWER=ON", + "-DSDL_THREADS=ON", + "-DSDL_TIMERS=OFF", + "-DSDL_FILE=OFF", + "-DSDL_LOADSO=ON", + "-DSDL_CPUINFO=OFF", + "-DSDL_FILESYSTEM=OFF", + "-DSDL_SENSOR=ON", + "-DSDL_OPENGL=ON", + "-DSDL_OPENGLES=ON", + "-DSDL_RPI=OFF", + "-DSDL_WAYLAND=OFF", + "-DSDL_X11=ON", + "-DSDL_X11_SHARED=OFF", + "-DSDL_X11_XCURSOR=OFF", + "-DSDL_X11_XDBE=OFF", + "-DSDL_X11_XFIXES=OFF", + "-DSDL_X11_XINERAMA=OFF", + "-DSDL_X11_XINPUT=OFF", + "-DSDL_X11_XRANDR=OFF", + "-DSDL_X11_XSCRNSAVER=OFF", + "-DSDL_X11_XSHAPE=OFF", + "-DSDL_X11_XVM=OFF", + "-DSDL_VULKAN=OFF", + "-DSDL_VIVANTE=OFF", + "-DSDL_COCOA=OFF", + "-DSDL_METAL=OFF", + "-DSDL_KMSDRM=OFF", + ] + cmd(["cmake"] + cmake_args) + + cmd( + ["cmake", "--build", ".", "--config", configuration, f"-j{multiprocessing.cpu_count()}"] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + +@versioned +def install_cli11(version, install_dir): + cli11_install_dir = os.path.join(install_dir, "cli11") + rm_rf(cli11_install_dir) + cmd( + [ + "git", + "clone", + "--branch", + version, + "--depth", + "1", + "https://github.com/CLIUtils/CLI11.git", + cli11_install_dir, + ] + ) + + +@versioned +def install_cuda_windows(version, source_dir, build_dir, install_dir): + rm_rf(os.path.join(build_dir, "cuda")) + rm_rf(os.path.join(install_dir, "cuda")) + if version == "10.2.89-1": + url = "http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_441.22_win10.exe" # noqa: E501 + elif version == "11.8.0-1": + url = "https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_522.06_windows.exe" # noqa: E501 + else: + raise Exception(f"Unknown CUDA version {version}") + file = download(url, source_dir) + + mkdir_p(os.path.join(build_dir, "cuda")) + mkdir_p(os.path.join(install_dir, "cuda")) + with cd(os.path.join(build_dir, "cuda")): + cmd(["7z", "x", file]) + copytree( + os.path.join(build_dir, "cuda", "cuda_nvcc", "nvcc"), os.path.join(install_dir, "cuda") + ) + copytree( + os.path.join(build_dir, "cuda", "cuda_cudart", "cudart"), os.path.join(install_dir, "cuda") + ) + + +@versioned +def install_vpl(version, configuration, source_dir, build_dir, install_dir, cmake_args): + vpl_source_dir = os.path.join(source_dir, "vpl") + vpl_build_dir = os.path.join(build_dir, "vpl") + vpl_install_dir = os.path.join(install_dir, "vpl") + rm_rf(vpl_source_dir) + rm_rf(vpl_build_dir) + rm_rf(vpl_install_dir) + git_clone_shallow("https://github.com/intel/libvpl.git", version, vpl_source_dir) + + mkdir_p(vpl_build_dir) + with cd(vpl_build_dir): + cmd( + [ + "cmake", + f"-DCMAKE_INSTALL_PREFIX={cmake_path(vpl_install_dir)}", + f"-DCMAKE_BUILD_TYPE={configuration}", + "-DBUILD_SHARED_LIBS=OFF", + "-DBUILD_TOOLS=OFF", + "-DBUILD_EXAMPLES=OFF", + "-DBUILD_PREVIEW=OFF", + "-DINSTALL_EXAMPLE_CODE=OFF", + "-DBUILD_TOOLS_ONEVPL_EXPERIMENTAL=OFF", + "-DUSE_MSVC_STATIC_RUNTIME=ON", + vpl_source_dir, + *cmake_args, + ] + ) + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + vpl_path = os.path.join("libvpl", "VPL.vcxproj") + if os.path.exists(vpl_path): + replace_vcproj_static_runtime(vpl_path) + + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + +@versioned +def install_blend2d( + version, + configuration, + source_dir, + build_dir, + install_dir, + blend2d_version, + asmjit_version, + ios, + cmake_args, +): + rm_rf(os.path.join(source_dir, "blend2d")) + rm_rf(os.path.join(build_dir, "blend2d")) + rm_rf(os.path.join(install_dir, "blend2d")) + + git_clone_shallow( + "https://github.com/blend2d/blend2d", blend2d_version, os.path.join(source_dir, "blend2d") + ) + mkdir_p(os.path.join(source_dir, "blend2d", "3rdparty")) + git_clone_shallow( + "https://github.com/asmjit/asmjit", + asmjit_version, + os.path.join(source_dir, "blend2d", "3rdparty", "asmjit"), + ) + + mkdir_p(os.path.join(build_dir, "blend2d")) + with cd(os.path.join(build_dir, "blend2d")): + cmd( + [ + "cmake", + os.path.join(source_dir, "blend2d"), + f"-DCMAKE_BUILD_TYPE={configuration}", + f"-DCMAKE_INSTALL_PREFIX={cmake_path(os.path.join(install_dir, 'blend2d'))}", + "-DBLEND2D_STATIC=ON", + *cmake_args, + ] + ) + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + project_path = os.path.join(build_dir, "blend2d", "blend2d.vcxproj") + if os.path.exists(project_path): + replace_vcproj_static_runtime(project_path) + + if ios: + cmd( + [ + "cmake", + "--build", + ".", + f"-j{multiprocessing.cpu_count()}", + "--config", + configuration, + "--target", + "blend2d", + "--", + "-arch", + "arm64", + "-sdk", + "iphoneos", + ] + ) + cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration]) + else: + cmd( + [ + "cmake", + "--build", + ".", + f"-j{multiprocessing.cpu_count()}", + "--config", + configuration, + ] + ) + cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration]) + + +@versioned +def install_openh264(version, source_dir, install_dir, is_windows): + rm_rf(os.path.join(source_dir, "openh264")) + rm_rf(os.path.join(install_dir, "openh264")) + git_clone_shallow( + "https://github.com/cisco/openh264.git", version, os.path.join(source_dir, "openh264") + ) + with cd(os.path.join(source_dir, "openh264")): + if is_windows: + # Windows は make が無いので手動でコピーする + # install-headers: + # mkdir -p $(DESTDIR)$(PREFIX)/include/wels + # install -m 644 $(SRC_PATH)/codec/api/wels/codec*.h $(DESTDIR)$(PREFIX)/include/wels + mkdir_p(os.path.join(install_dir, "openh264", "include", "wels")) + with cd(os.path.join("codec", "api", "wels")): + for file in glob.glob("codec*.h"): + shutil.copyfile( + file, os.path.join(install_dir, "openh264", "include", "wels", file) + ) + else: + cmd(["make", f'PREFIX={os.path.join(install_dir, "openh264")}', "install-headers"]) + + +@versioned +def install_yaml(version, source_dir, build_dir, install_dir, cmake_args): + rm_rf(os.path.join(source_dir, "yaml")) + rm_rf(os.path.join(install_dir, "yaml")) + rm_rf(os.path.join(build_dir, "yaml")) + git_clone_shallow( + "https://github.com/jbeder/yaml-cpp.git", version, os.path.join(source_dir, "yaml") + ) + + mkdir_p(os.path.join(build_dir, "yaml")) + with cd(os.path.join(build_dir, "yaml")): + cmd( + [ + "cmake", + os.path.join(source_dir, "yaml"), + "-DCMAKE_BUILD_TYPE=Release", + f"-DCMAKE_INSTALL_PREFIX={install_dir}/yaml", + "-DYAML_CPP_BUILD_TESTS=OFF", + "-DYAML_CPP_BUILD_TOOLS=OFF", + *cmake_args, + ] + ) + cmd(["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}"]) + cmd(["cmake", "--build", ".", "--target", "install"]) + + +@versioned +def install_catch2(version, source_dir, build_dir, install_dir, configuration, cmake_args): + rm_rf(os.path.join(source_dir, "catch2")) + rm_rf(os.path.join(install_dir, "catch2")) + rm_rf(os.path.join(build_dir, "catch2")) + git_clone_shallow( + "https://github.com/catchorg/Catch2.git", version, os.path.join(source_dir, "catch2") + ) + + mkdir_p(os.path.join(build_dir, "catch2")) + with cd(os.path.join(build_dir, "catch2")): + cmd( + [ + "cmake", + os.path.join(source_dir, "catch2"), + f"-DCMAKE_BUILD_TYPE={configuration}", + f"-DCMAKE_INSTALL_PREFIX={install_dir}/catch2", + "-DCATCH_BUILD_TESTING=OFF", + *cmake_args, + ] + ) + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + project_path = os.path.join("src", "Catch2.vcxproj") + if os.path.exists(project_path): + replace_vcproj_static_runtime(project_path) + project_path = os.path.join("src", "Catch2WithMain.vcxproj") + if os.path.exists(project_path): + replace_vcproj_static_runtime(project_path) + cmd( + ["cmake", "--build", ".", "--config", configuration, f"-j{multiprocessing.cpu_count()}"] + ) + cmd(["cmake", "--build", ".", "--config", configuration, "--target", "install"]) + + +@versioned +def install_protobuf(version, source_dir, install_dir, platform: str): + # platform: + # - linux-aarch_64 + # - linux-ppcle_64 + # - linux-s390_64 + # - linux-x86_32 + # - linux-x86_64 + # - osx-aarch_64 + # - osx-universal_binary + # - osx-x86_64 + # - win32 + # - win64 + url = f"https://github.com/protocolbuffers/protobuf/releases/download/v{version}/protoc-{version}-{platform}.zip" + path = download(url, source_dir) + rm_rf(os.path.join(install_dir, "protobuf")) + extract(path, install_dir, "protobuf") + # なぜか実行属性が消えてるので入れてやる + for file in os.scandir(os.path.join(install_dir, "protobuf", "bin")): + if file.is_file(): + os.chmod(file.path, file.stat().st_mode | stat.S_IXUSR) + + +@versioned +def install_protoc_gen_jsonif(version, source_dir, install_dir, platform: str): + # platform: + # - darwin-amd64 + # - darwin-arm64 + # - linux-amd64 + # - windows-amd64 + url = f"https://github.com/melpon/protoc-gen-jsonif/releases/download/{version}/protoc-gen-jsonif.tar.gz" + rm_rf(os.path.join(source_dir, "protoc-gen-jsonif.tar.gz")) + path = download(url, source_dir) + jsonif_install_dir = os.path.join(install_dir, "protoc-gen-jsonif") + rm_rf(jsonif_install_dir) + extract(path, install_dir, "protoc-gen-jsonif") + # 自分の環境のバイナリを /bin に配置する + shutil.copytree( + os.path.join(jsonif_install_dir, *platform.split("-")), + os.path.join(jsonif_install_dir, "bin"), + ) + # なぜか実行属性が消えてるので入れてやる + for file in os.scandir(os.path.join(jsonif_install_dir, "bin")): + if file.is_file(): + os.chmod(file.path, file.stat().st_mode | stat.S_IXUSR) + + +class PlatformTarget(object): + def __init__(self, os, osver, arch): + self.os = os + self.osver = osver + self.arch = arch + + @property + def package_name(self): + if self.os == "windows": + return f"windows_{self.arch}" + if self.os == "macos": + return f"macos_{self.arch}" + if self.os == "ubuntu": + return f"ubuntu-{self.osver}_{self.arch}" + if self.os == "ios": + return "ios" + if self.os == "android": + return "android" + if self.os == "raspberry-pi-os": + return f"raspberry-pi-os_{self.arch}" + if self.os == "jetson": + return "ubuntu-20.04_armv8_jetson" + raise Exception("error") + + +def get_windows_osver(): + osver = platform.release() + # Windows 以外の環境だと reportAttributeAccessIssue を報告されてしまうので ignore する + with winreg.OpenKeyEx( # type: ignore[reportAttributeAccessIssue] + winreg.HKEY_LOCAL_MACHINE, # type: ignore[reportAttributeAccessIssue] + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + ) as key: + return osver + "." + winreg.QueryValueEx(key, "ReleaseId")[0] # type: ignore[reportAttributeAccessIssue] + + +def get_macos_osver(): + platform.mac_ver()[0] + + +def get_build_platform() -> PlatformTarget: + os = platform.system() + if os == "Windows": + os = "windows" + osver = get_windows_osver() + elif os == "Darwin": + os = "macos" + osver = get_macos_osver() + elif os == "Linux": + release = read_version_file("/etc/os-release") + os = release["NAME"] + if os == "Ubuntu": + os = "ubuntu" + osver = release["VERSION_ID"] + else: + raise Exception(f"OS {os} not supported") + pass + else: + raise Exception(f"OS {os} not supported") + + arch = platform.machine() + if arch in ("AMD64", "x86_64"): + arch = "x86_64" + elif arch in ("aarch64", "arm64"): + arch = "arm64" + else: + raise Exception(f"Arch {arch} not supported") + + return PlatformTarget(os, osver, arch) + + +def get_clang_version(clang): + version_str = cmdcap([clang, "--version"]) + + # version_str は以下のような文字列になっているので、ここからバージョンを取る + # + # clang version 16.0.0 (...) + # Target: x86_64-unknown-linux-gnu + # Thread model: posix + # InstalledDir: /path/to/clang/bin + # + # Android 版だと以下のような文字列になっている + # + # Android (8490178, based on r450784d) clang version 14.0.6 (...) + # Target: aarch64-unknown-linux-android29 + # Thread model: posix + # InstalledDir: /path/to/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin + + # clang version の次の文字列を取る + xs = version_str.split("\n")[0].split(" ") + for i in range(2, len(xs)): + if xs[i - 2] == "clang" and xs[i - 1] == "version": + return xs[i] + + raise Exception("Failed to get clang version") + + +def fix_clang_version(clang_dir, clang_version): + # /lib/clang//include または + # /lib64/clang//include が存在するか調べて、 + # 存在しない場合は clang_version を調節して、存在するバージョンに変換する + # + # /lib/clang/16.0.0/include になっている場合と + # /lib/clang/16/include になっている場合があるため + paths = [os.path.join(clang_dir, "lib", "clang"), os.path.join(clang_dir, "lib64", "clang")] + exists = any(map(lambda x: os.path.exists(os.path.join(x, clang_version, "include")), paths)) + if exists: + return clang_version + + fixed_clang_version = clang_version.split(".")[0] + exists = any( + map(lambda x: os.path.exists(os.path.join(x, fixed_clang_version, "include")), paths) + ) + if exists: + return fixed_clang_version + + raise Exception( + f"Failed to fix clang version: clang_dir={clang_dir} clang_version={clang_version}" + ) + + +class Platform(object): + def _check(self, flag): + if not flag: + raise Exception("Not supported") + + def _check_platform_target(self, p: PlatformTarget): + if p.os == "raspberry-pi-os": + self._check(p.arch in ("armv6", "armv7", "armv8")) + elif p.os == "jetson": + self._check(p.arch == "armv8") + elif p.os in ("ios", "android"): + self._check(p.arch is None) + else: + self._check(p.arch in ("x86_64", "arm64")) + + def __init__(self, target_os, target_osver, target_arch): + build = get_build_platform() + target = PlatformTarget(target_os, target_osver, target_arch) + + self._check_platform_target(build) + self._check_platform_target(target) + + if target.os == "windows": + self._check(target.arch == "x86_64") + self._check(build.os == "windows") + self._check(build.arch == "x86_64") + if target.os == "macos": + self._check(build.os == "macos") + self._check(build.arch in ("x86_64", "arm64")) + if target.os == "ios": + 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") + if target.os == "ubuntu": + self._check(build.os == "ubuntu") + self._check(build.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") + if target.os == "jetson": + self._check(build.os == "ubuntu") + self._check(build.arch == "x86_64") + + self.build = build + self.target = target + + +def get_webrtc_platform(platform: Platform) -> str: + # WebRTC + if platform.target.os == "windows": + return f"windows_{platform.target.arch}" + elif platform.target.os == "macos": + return f"macos_{platform.target.arch}" + elif platform.target.os == "ios": + return "ios" + elif platform.target.os == "android": + return "android" + elif platform.target.os == "ubuntu": + return f"ubuntu-{platform.target.osver}_{platform.target.arch}" + 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" + else: + raise Exception(f"Unknown platform {platform.target.os}") + + +# 内部で os.path.abspath() を利用しており、 os.path.abspath() はカレントディレクトリに依存するため、 +# この関数を利用する場合は ArgumentParser.parse_args() 実行前にカレントディレクトリを変更してはならない +# +# また、 --sora-args の指定には `--sora-args='--test'` のように `=` を使う必要がある +# `--sora-args '--test'` のようにスペースを使うと、ハイフンから始まるオプションが正しく解釈されない +def add_sora_arguments(parser): + parser.add_argument( + "--sora-dir", + type=os.path.abspath, + default=None, + help="Refer to local Sora C++ SDK. " + "When this option is specified, Sora C++ SDK will also be built.", + ) + parser.add_argument( + "--sora-args", + type=shlex.split, + default=[], + help="Options for building local Sora C++ SDK when `--sora-dir` is specified.", + ) + + +# add_sora_arguments と同様の注意点があるので注意すること +def add_webrtc_build_arguments(parser): + parser.add_argument( + "--webrtc-build-dir", + type=os.path.abspath, + default=None, + help="Refer to local webrtc-build. " + "When this option is specified, webrtc-build will also be built.", + ) + parser.add_argument( + "--webrtc-build-args", + type=shlex.split, + default=[], + help="Options for building local webrtc-build when `--webrtc-build-dir` is specified.", + ) diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..71de868 --- /dev/null +++ b/ruff.toml @@ -0,0 +1 @@ +line-length = 100 diff --git a/run.py b/run.py index a8746c3..33c9d1b 100644 --- a/run.py +++ b/run.py @@ -1,815 +1,337 @@ -import subprocess +import argparse import logging +import multiprocessing import os -import urllib.parse -import zipfile -import tarfile +import shlex import shutil -import platform -import multiprocessing -import argparse -from typing import Callable, NamedTuple, Optional, List, Union, Dict - +import tarfile +from typing import List, Optional + +from buildbase import ( + WebrtcInfo, + add_path, + build_sora, + build_webrtc, + cd, + cmake_path, + cmd, + cmdcap, + download, + enum_all_files, + get_sora_info, + get_webrtc_info, + install_blend2d, + install_boost, + install_cli11, + install_cmake, + install_llvm, + install_openh264, + install_sora_and_deps, + install_webrtc, + install_yaml, + mkdir_p, + read_version_file, + rm_rf, +) logging.basicConfig(level=logging.DEBUG) -class ChangeDirectory(object): - def __init__(self, cwd): - self._cwd = cwd - - def __enter__(self): - self._old_cwd = os.getcwd() - logging.debug(f'pushd {self._old_cwd} --> {self._cwd}') - os.chdir(self._cwd) - - def __exit__(self, exctype, excvalue, trace): - logging.debug(f'popd {self._old_cwd} <-- {self._cwd}') - os.chdir(self._old_cwd) - return False - - -def cd(cwd): - return ChangeDirectory(cwd) - - -def cmd(args, **kwargs): - logging.debug(f'+{args} {kwargs}') - if 'check' not in kwargs: - kwargs['check'] = True - if 'resolve' in kwargs: - resolve = kwargs['resolve'] - del kwargs['resolve'] - else: - resolve = True - if resolve: - args = [shutil.which(args[0]), *args[1:]] - return subprocess.run(args, **kwargs) - - -# 標準出力をキャプチャするコマンド実行。シェルの `cmd ...` や $(cmd ...) と同じ -def cmdcap(args, **kwargs): - # 3.7 でしか使えない - # kwargs['capture_output'] = True - kwargs['stdout'] = subprocess.PIPE - kwargs['stderr'] = subprocess.PIPE - kwargs['encoding'] = 'utf-8' - return cmd(args, **kwargs).stdout.strip() - - -def rm_rf(path: str): - if not os.path.exists(path): - logging.debug(f'rm -rf {path} => path not found') - return - if os.path.isfile(path) or os.path.islink(path): - os.remove(path) - logging.debug(f'rm -rf {path} => file removed') - if os.path.isdir(path): - shutil.rmtree(path) - logging.debug(f'rm -rf {path} => directory removed') - - -def mkdir_p(path: str): - if os.path.exists(path): - logging.debug(f'mkdir -p {path} => already exists') - return - os.makedirs(path, exist_ok=True) - logging.debug(f'mkdir -p {path} => directory created') - - -if platform.system() == 'Windows': - PATH_SEPARATOR = ';' -else: - PATH_SEPARATOR = ':' - - -def add_path(path: str, is_after=False): - logging.debug(f'add_path: {path}') - if 'PATH' not in os.environ: - os.environ['PATH'] = path - return - - if is_after: - os.environ['PATH'] = os.environ['PATH'] + PATH_SEPARATOR + path - else: - os.environ['PATH'] = path + PATH_SEPARATOR + os.environ['PATH'] - - -def download(url: str, output_dir: Optional[str] = None, filename: Optional[str] = None) -> str: - if filename is None: - output_path = urllib.parse.urlparse(url).path.split('/')[-1] - else: - output_path = filename - - if output_dir is not None: - output_path = os.path.join(output_dir, output_path) - - if os.path.exists(output_path): - return output_path - - try: - if shutil.which('curl') is not None: - cmd(["curl", "-fLo", output_path, url]) - else: - cmd(["wget", "-cO", output_path, url]) - except Exception: - # ゴミを残さないようにする - if os.path.exists(output_path): - os.remove(output_path) - raise - - return output_path - - -def read_version_file(path: str) -> Dict[str, str]: - versions = {} - - lines = open(path).readlines() - for line in lines: - line = line.strip() - - # コメント行 - if line[:1] == '#': - continue - - # 空行 - if len(line) == 0: - continue - - [a, b] = map(lambda x: x.strip(), line.split('=', 2)) - versions[a] = b.strip('"') - - return versions - - -# dir 以下にある全てのファイルパスを、dir2 からの相対パスで返す -def enum_all_files(dir, dir2): - for root, _, files in os.walk(dir): - for file in files: - yield os.path.relpath(os.path.join(root, file), dir2) - - -def versioned(func): - def wrapper(version, version_file, *args, **kwargs): - if 'ignore_version' in kwargs: - if kwargs.get('ignore_version'): - rm_rf(version_file) - del kwargs['ignore_version'] - - if os.path.exists(version_file): - ver = open(version_file).read() - if ver.strip() == version.strip(): - return - - r = func(version=version, *args, **kwargs) - - with open(version_file, 'w') as f: - f.write(version) - - return r - - return wrapper - - -# アーカイブが単一のディレクトリに全て格納されているかどうかを調べる。 -# -# 単一のディレクトリに格納されている場合はそのディレクトリ名を返す。 -# そうでない場合は None を返す。 -def _is_single_dir(infos: List[Union[zipfile.ZipInfo, tarfile.TarInfo]], - get_name: Callable[[Union[zipfile.ZipInfo, tarfile.TarInfo]], str], - is_dir: Callable[[Union[zipfile.ZipInfo, tarfile.TarInfo]], bool]) -> Optional[str]: - # tarfile: ['path', 'path/to', 'path/to/file.txt'] - # zipfile: ['path/', 'path/to/', 'path/to/file.txt'] - # どちらも / 区切りだが、ディレクトリの場合、後ろに / が付くかどうかが違う - dirname = None - for info in infos: - name = get_name(info) - n = name.rstrip('/').find('/') - if n == -1: - # ルートディレクトリにファイルが存在している - if not is_dir(info): - return None - dir = name.rstrip('/') - else: - dir = name[0:n] - # ルートディレクトリに2個以上のディレクトリが存在している - if dirname is not None and dirname != dir: - return None - dirname = dir - - return dirname - - -def is_single_dir_tar(tar: tarfile.TarFile) -> Optional[str]: - return _is_single_dir(tar.getmembers(), lambda t: t.name, lambda t: t.isdir()) - - -def is_single_dir_zip(zip: zipfile.ZipFile) -> Optional[str]: - return _is_single_dir(zip.infolist(), lambda z: z.filename, lambda z: z.is_dir()) - - -# 解凍した上でファイル属性を付与する -def _extractzip(z: zipfile.ZipFile, path: str): - z.extractall(path) - if platform.system() == 'Windows': - return - for info in z.infolist(): - if info.is_dir(): - continue - filepath = os.path.join(path, info.filename) - mod = info.external_attr >> 16 - if (mod & 0o120000) == 0o120000: - # シンボリックリンク - with open(filepath, 'r') as f: - src = f.read() - os.remove(filepath) - with cd(os.path.dirname(filepath)): - if os.path.exists(src): - os.symlink(src, filepath) - if os.path.exists(filepath): - # 普通のファイル - os.chmod(filepath, mod & 0o777) - - -# zip または tar.gz ファイルを展開する。 -# -# 展開先のディレクトリは {output_dir}/{output_dirname} となり、 -# 展開先のディレクトリが既に存在していた場合は削除される。 -# -# もしアーカイブの内容が単一のディレクトリであった場合、 -# そのディレクトリは無いものとして展開される。 -# -# つまりアーカイブ libsora-1.23.tar.gz の内容が -# ['libsora-1.23', 'libsora-1.23/file1', 'libsora-1.23/file2'] -# であった場合、extract('libsora-1.23.tar.gz', 'out', 'libsora') のようにすると -# - out/libsora/file1 -# - out/libsora/file2 -# が出力される。 -# -# また、アーカイブ libsora-1.23.tar.gz の内容が -# ['libsora-1.23', 'libsora-1.23/file1', 'libsora-1.23/file2', 'LICENSE'] -# であった場合、extract('libsora-1.23.tar.gz', 'out', 'libsora') のようにすると -# - out/libsora/libsora-1.23/file1 -# - out/libsora/libsora-1.23/file2 -# - out/libsora/LICENSE -# が出力される。 -def extract(file: str, output_dir: str, output_dirname: str, filetype: Optional[str] = None): - path = os.path.join(output_dir, output_dirname) - logging.info(f"Extract {file} to {path}") - if filetype == 'gzip' or file.endswith('.tar.gz'): - rm_rf(path) - with tarfile.open(file) as t: - dir = is_single_dir_tar(t) - if dir is None: - os.makedirs(path, exist_ok=True) - t.extractall(path) - else: - logging.info(f"Directory {dir} is stripped") - path2 = os.path.join(output_dir, dir) - rm_rf(path2) - t.extractall(output_dir) - if path != path2: - logging.debug(f"mv {path2} {path}") - os.replace(path2, path) - elif filetype == 'zip' or file.endswith('.zip'): - rm_rf(path) - with zipfile.ZipFile(file) as z: - dir = is_single_dir_zip(z) - if dir is None: - os.makedirs(path, exist_ok=True) - # z.extractall(path) - _extractzip(z, path) - else: - logging.info(f"Directory {dir} is stripped") - path2 = os.path.join(output_dir, dir) - rm_rf(path2) - # z.extractall(output_dir) - _extractzip(z, output_dir) - if path != path2: - logging.debug(f"mv {path2} {path}") - os.replace(path2, path) - else: - raise Exception('file should end with .tar.gz or .zip') - - -def clone_and_checkout(url, version, dir, fetch, fetch_force): - if fetch_force: - rm_rf(dir) - - if not os.path.exists(os.path.join(dir, '.git')): - cmd(['git', 'clone', url, dir]) - fetch = True - - if fetch: - with cd(dir): - cmd(['git', 'fetch']) - cmd(['git', 'reset', '--hard']) - cmd(['git', 'clean', '-df']) - cmd(['git', 'checkout', '-f', version]) - - -def git_clone_shallow(url, hash, dir): - rm_rf(dir) - mkdir_p(dir) - with cd(dir): - cmd(['git', 'init']) - cmd(['git', 'remote', 'add', 'origin', url]) - cmd(['git', 'fetch', '--depth=1', 'origin', hash]) - cmd(['git', 'reset', '--hard', 'FETCH_HEAD']) - - -@versioned -def install_rootfs(version, install_dir, conf): - rootfs_dir = os.path.join(install_dir, 'rootfs') - rm_rf(rootfs_dir) - cmd(['multistrap', '--no-auth', '-a', 'arm64', '-d', rootfs_dir, '-f', conf]) - # 絶対パスのシンボリックリンクを相対パスに置き換えていく - for dir, _, filenames in os.walk(rootfs_dir): - for filename in filenames: - linkpath = os.path.join(dir, filename) - # symlink かどうか - if not os.path.islink(linkpath): - continue - target = os.readlink(linkpath) - # 絶対パスかどうか - if not os.path.isabs(target): - continue - # rootfs_dir を先頭に付けることで、 - # rootfs の外から見て正しい絶対パスにする - targetpath = rootfs_dir + target - # 参照先の絶対パスが存在するかどうか - if not os.path.exists(targetpath): - continue - # 相対パスに置き換える - relpath = os.path.relpath(targetpath, dir) - logging.debug( - f'{linkpath[len(rootfs_dir):]} targets {target} to {relpath}') - os.remove(linkpath) - os.symlink(relpath, linkpath) - - # なぜかシンボリックリンクが登録されていないので作っておく - link = os.path.join(rootfs_dir, 'usr', 'lib', - 'aarch64-linux-gnu', 'tegra', 'libnvbuf_fdmap.so') - file = os.path.join(rootfs_dir, 'usr', 'lib', - 'aarch64-linux-gnu', 'tegra', 'libnvbuf_fdmap.so.1.0.0') - if os.path.exists(file) and not os.path.exists(link): - os.symlink(os.path.basename(file), link) - - -@versioned -def install_webrtc(version, source_dir, install_dir, platform: str): - win = platform.startswith("windows_") - filename = f'webrtc.{platform}.{"zip" if win else "tar.gz"}' - rm_rf(os.path.join(source_dir, filename)) - archive = download( - f'https://github.com/shiguredo-webrtc-build/webrtc-build/releases/download/{version}/{filename}', - output_dir=source_dir) - rm_rf(os.path.join(install_dir, 'webrtc')) - extract(archive, output_dir=install_dir, output_dirname='webrtc') - - -class WebrtcInfo(NamedTuple): - version_file: str - webrtc_include_dir: str - webrtc_library_dir: str - clang_dir: str - libcxx_dir: str - - -def get_webrtc_info(webrtcbuild: bool, source_dir: str, build_dir: str, install_dir: str) -> WebrtcInfo: - webrtc_source_dir = os.path.join(source_dir, 'webrtc') - webrtc_build_dir = os.path.join(build_dir, 'webrtc') - webrtc_install_dir = os.path.join(install_dir, 'webrtc') - - if webrtcbuild: - return WebrtcInfo( - version_file=os.path.join(source_dir, 'webrtc-build', 'VERSION'), - webrtc_include_dir=os.path.join(webrtc_source_dir, 'src'), - webrtc_library_dir=os.path.join(webrtc_build_dir, 'obj') - if platform.system() == 'Windows' else webrtc_build_dir, clang_dir=os.path.join( - webrtc_source_dir, 'src', 'third_party', 'llvm-build', 'Release+Asserts'), - libcxx_dir=os.path.join(webrtc_source_dir, 'src', 'buildtools', 'third_party', 'libc++', 'trunk'),) - else: - return WebrtcInfo( - version_file=os.path.join(webrtc_install_dir, 'VERSIONS'), - webrtc_include_dir=os.path.join(webrtc_install_dir, 'include'), - webrtc_library_dir=os.path.join(install_dir, 'webrtc', 'lib'), - clang_dir=os.path.join(install_dir, 'llvm', 'clang'), - libcxx_dir=os.path.join(install_dir, 'llvm', 'libcxx'), - ) - - -@versioned -def install_llvm(version, install_dir, - tools_url, tools_commit, - libcxx_url, libcxx_commit, - buildtools_url, buildtools_commit): - llvm_dir = os.path.join(install_dir, 'llvm') - rm_rf(llvm_dir) - mkdir_p(llvm_dir) - with cd(llvm_dir): - # tools の update.py を叩いて特定バージョンの clang バイナリを拾う - git_clone_shallow(tools_url, tools_commit, 'tools') - with cd('tools'): - cmd(['python3', - os.path.join('clang', 'scripts', 'update.py'), - '--output-dir', os.path.join(llvm_dir, 'clang')]) - - # 特定バージョンの libcxx を利用する - git_clone_shallow(libcxx_url, libcxx_commit, 'libcxx') - - # __config_site のために特定バージョンの buildtools を取得する - git_clone_shallow(buildtools_url, buildtools_commit, 'buildtools') - shutil.copyfile(os.path.join(llvm_dir, 'buildtools', 'third_party', 'libc++', '__config_site'), - os.path.join(llvm_dir, 'libcxx', 'include', '__config_site')) - - -@versioned -def install_boost(version, source_dir, install_dir, sora_version, platform: str): - win = platform.startswith("windows_") - filename = f'boost-{version}_sora-cpp-sdk-{sora_version}_{platform}.{"zip" if win else "tar.gz"}' - rm_rf(os.path.join(source_dir, filename)) - archive = download( - f'https://github.com/shiguredo/sora-cpp-sdk/releases/download/{sora_version}/{filename}', - output_dir=source_dir) - rm_rf(os.path.join(install_dir, 'boost')) - extract(archive, output_dir=install_dir, output_dirname='boost') - - -@versioned -def install_lyra(version, source_dir, install_dir, sora_version, platform: str): - win = platform.startswith("windows_") - filename = f'lyra-{version}_sora-cpp-sdk-{sora_version}_{platform}.{"zip" if win else "tar.gz"}' - rm_rf(os.path.join(source_dir, filename)) - archive = download( - f'https://github.com/shiguredo/sora-cpp-sdk/releases/download/{sora_version}/{filename}', - output_dir=source_dir) - rm_rf(os.path.join(install_dir, 'lyra')) - extract(archive, output_dir=install_dir, output_dirname='lyra') - - -def cmake_path(path: str) -> str: - return path.replace('\\', '/') - - -@versioned -def install_cmake(version, source_dir, install_dir, platform: str, ext): - url = f'https://github.com/Kitware/CMake/releases/download/v{version}/cmake-{version}-{platform}.{ext}' - path = download(url, source_dir) - extract(path, install_dir, 'cmake') - # Android で自前の CMake を利用する場合、ninja へのパスが見つけられない問題があるので、同じディレクトリに symlink を貼る - # https://issuetracker.google.com/issues/206099937 - if platform.startswith('linux'): - with cd(os.path.join(install_dir, 'cmake', 'bin')): - cmd(['ln', '-s', '/usr/bin/ninja', 'ninja']) - - -@versioned -def install_sora(version, source_dir, install_dir, platform: str): - win = platform.startswith("windows_") - filename = f'sora-cpp-sdk-{version}_{platform}.{"zip" if win else "tar.gz"}' - rm_rf(os.path.join(source_dir, filename)) - archive = download( - f'https://github.com/shiguredo/sora-cpp-sdk/releases/download/{version}/{filename}', - output_dir=source_dir) - rm_rf(os.path.join(install_dir, 'sora')) - extract(archive, output_dir=install_dir, output_dirname='sora') - - -@versioned -def install_cli11(version, install_dir): - cli11_install_dir = os.path.join(install_dir, 'cli11') - rm_rf(cli11_install_dir) - git_clone_shallow('https://github.com/CLIUtils/CLI11.git', - version, cli11_install_dir) - - -@versioned -def install_blend2d(version, source_dir, build_dir, install_dir, blend2d_version, asmjit_version, cmake_args): - rm_rf(os.path.join(source_dir, 'blend2d')) - rm_rf(os.path.join(build_dir, 'blend2d')) - rm_rf(os.path.join(install_dir, 'blend2d')) - - git_clone_shallow('https://github.com/blend2d/blend2d', - blend2d_version, os.path.join(source_dir, 'blend2d')) - mkdir_p(os.path.join(source_dir, 'blend2d', '3rdparty')) - git_clone_shallow('https://github.com/asmjit/asmjit', asmjit_version, - os.path.join(source_dir, 'blend2d', '3rdparty', 'asmjit')) - - mkdir_p(os.path.join(build_dir, 'blend2d')) - with cd(os.path.join(build_dir, 'blend2d')): - cmd(['cmake', os.path.join(source_dir, 'blend2d'), - '-DCMAKE_BUILD_TYPE=Release', - f'-DCMAKE_INSTALL_PREFIX={install_dir}/blend2d', - '-DBLEND2D_STATIC=ON', - *cmake_args]) - cmd(['cmake', '--build', '.', f'-j{multiprocessing.cpu_count()}']) - cmd(['cmake', '--build', '.', '--target', 'install']) - - -@versioned -def install_openh264(version, source_dir, install_dir): - rm_rf(os.path.join(source_dir, 'openh264')) - rm_rf(os.path.join(install_dir, 'openh264')) - git_clone_shallow('https://github.com/cisco/openh264.git', - version, os.path.join(source_dir, 'openh264')) - with cd(os.path.join(source_dir, 'openh264')): - cmd([ - 'make', f'PREFIX={os.path.join(install_dir, "openh264")}', 'install-headers']) - - -@versioned -def install_yaml(version, source_dir, build_dir, install_dir, cmake_args): - rm_rf(os.path.join(source_dir, 'yaml')) - rm_rf(os.path.join(install_dir, 'yaml')) - rm_rf(os.path.join(build_dir, 'yaml')) - git_clone_shallow('https://github.com/jbeder/yaml-cpp.git', - version, os.path.join(source_dir, 'yaml')) - - mkdir_p(os.path.join(build_dir, 'yaml')) - with cd(os.path.join(build_dir, 'yaml')): - cmd(['cmake', os.path.join(source_dir, 'yaml'), - '-DCMAKE_BUILD_TYPE=Release', - f'-DCMAKE_INSTALL_PREFIX={install_dir}/yaml', - '-DYAML_CPP_BUILD_TESTS=OFF', - '-DYAML_CPP_BUILD_TOOLS=OFF', - *cmake_args]) - cmd(['cmake', '--build', '.', f'-j{multiprocessing.cpu_count()}']) - cmd(['cmake', '--build', '.', '--target', 'install']) - - -def get_common_cmake_args(install_dir, platform): +def get_common_cmake_args(install_dir, platform, webrtc_info: WebrtcInfo): # クロスコンパイルの設定。 # 本来は toolchain ファイルに書く内容 - if platform in ('ubuntu-20.04_x86_64', 'ubuntu-22.04_x86_64'): + if platform in ("ubuntu-20.04_x86_64", "ubuntu-22.04_x86_64"): return [ - f'-DCMAKE_C_COMPILER={install_dir}/llvm/clang/bin/clang', - f'-DCMAKE_CXX_COMPILER={install_dir}/llvm/clang/bin/clang++', - '-DCMAKE_CXX_FLAGS=' + ' '.join([ - '-D_LIBCPP_ABI_NAMESPACE=Cr', - '-D_LIBCPP_ABI_VERSION=2', - '-D_LIBCPP_DISABLE_AVAILABILITY', - '-nostdinc++', - f'-isystem{install_dir}/llvm/libcxx/include', - ]) + f"-DCMAKE_C_COMPILER={webrtc_info.clang_dir}/bin/clang", + f"-DCMAKE_CXX_COMPILER={webrtc_info.clang_dir}/bin/clang++", + "-DCMAKE_CXX_FLAGS=" + + " ".join( + [ + "-D_LIBCPP_ABI_NAMESPACE=Cr", + "-D_LIBCPP_ABI_VERSION=2", + "-D_LIBCPP_DISABLE_AVAILABILITY", + "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + "-nostdinc++", + f"-isystem{webrtc_info.libcxx_dir}/include", + ] + ), ] - elif platform == 'macos_arm64': - sysroot = cmdcap(['xcrun', '--sdk', 'macosx', '--show-sdk-path']) + elif platform == "macos_arm64": + sysroot = cmdcap(["xcrun", "--sdk", "macosx", "--show-sdk-path"]) return [ - '-DCMAKE_SYSTEM_PROCESSOR=arm64', - '-DCMAKE_OSX_ARCHITECTURES=arm64', + "-DCMAKE_SYSTEM_PROCESSOR=arm64", + "-DCMAKE_OSX_ARCHITECTURES=arm64", "-DCMAKE_C_COMPILER=clang", - '-DCMAKE_C_COMPILER_TARGET=aarch64-apple-darwin', + "-DCMAKE_C_COMPILER_TARGET=aarch64-apple-darwin", "-DCMAKE_CXX_COMPILER=clang++", - '-DCMAKE_CXX_COMPILER_TARGET=aarch64-apple-darwin', - f'-DCMAKE_SYSROOT={sysroot}', + "-DCMAKE_CXX_COMPILER_TARGET=aarch64-apple-darwin", + f"-DCMAKE_SYSROOT={sysroot}", ] else: - raise Exception(f'Unsupported platform: {platform}') + raise Exception(f"Unsupported platform: {platform}") BASE_DIR = os.path.abspath(os.path.dirname(__file__)) -def install_deps(source_dir, build_dir, install_dir, debug, platform): +def install_deps( + platform: str, + source_dir: str, + build_dir: str, + install_dir: str, + debug: bool, + webrtc_build_dir: Optional[str], + webrtc_build_args: List[str], + sora_dir: Optional[str], + sora_args: List[str], +): with cd(BASE_DIR): - version = read_version_file('VERSION') + version = read_version_file("VERSION") # WebRTC - 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': platform, - } - install_webrtc(**install_webrtc_args) + if 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": platform, + } + + install_webrtc(**install_webrtc_args) + else: + build_webrtc_args = { + "platform": platform, + "webrtc_build_dir": webrtc_build_dir, + "webrtc_build_args": webrtc_build_args, + "debug": debug, + } + + build_webrtc(**build_webrtc_args) - if platform in ('ubuntu-20.04_x86_64', 'ubuntu-22.04_x86_64'): - webrtc_info = get_webrtc_info( - False, source_dir, build_dir, install_dir) + webrtc_info = get_webrtc_info(platform, webrtc_build_dir, install_dir, debug) + + if platform in ("ubuntu-20.04_x86_64", "ubuntu-22.04_x86_64") and 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_BUILDTOOLS_THIRD_PARTY_LIBCXX_TRUNK_URL'] - libcxx_commit = webrtc_version['WEBRTC_SRC_BUILDTOOLS_THIRD_PARTY_LIBCXX_TRUNK_COMMIT'] - buildtools_url = webrtc_version['WEBRTC_SRC_BUILDTOOLS_URL'] - buildtools_commit = webrtc_version['WEBRTC_SRC_BUILDTOOLS_COMMIT'] + 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, + "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) # Boost install_boost_args = { - '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'], - 'platform': platform, + "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"], + "platform": platform, } install_boost(**install_boost_args) - # Lyra - install_lyra_args = { - 'version': version['LYRA_VERSION'], - 'version_file': os.path.join(install_dir, 'lyra.version'), - 'source_dir': source_dir, - 'install_dir': install_dir, - 'sora_version': version['SORA_CPP_SDK_VERSION'], - 'platform': platform, - } - install_lyra(**install_lyra_args) - # 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': '', - 'ext': 'tar.gz' + "version": version["CMAKE_VERSION"], + "version_file": os.path.join(install_dir, "cmake.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "", + "ext": "tar.gz", } - if platform in ('ubuntu-20.04_x86_64', 'ubuntu-22.04_x86_64'): - install_cmake_args['platform'] = 'linux-x86_64' - elif platform == 'macos_arm64': - install_cmake_args['platform'] = 'macos-universal' + if platform in ("ubuntu-20.04_x86_64", "ubuntu-22.04_x86_64"): + install_cmake_args["platform"] = "linux-x86_64" + elif platform == "macos_arm64": + install_cmake_args["platform"] = "macos-universal" install_cmake(**install_cmake_args) - if platform == 'macos_arm64': - add_path(os.path.join(install_dir, 'cmake', - 'CMake.app', 'Contents', 'bin')) + if platform == "macos_arm64": + add_path(os.path.join(install_dir, "cmake", "CMake.app", "Contents", "bin")) else: - add_path(os.path.join(install_dir, 'cmake', 'bin')) + add_path(os.path.join(install_dir, "cmake", "bin")) # Sora C++ SDK - install_sora_args = { - 'version': version['SORA_CPP_SDK_VERSION'], - 'version_file': os.path.join(install_dir, 'sora.version'), - 'source_dir': source_dir, - 'install_dir': install_dir, - 'platform': platform, - } - install_sora(**install_sora_args) + if sora_dir is None: + install_sora_and_deps(platform, source_dir, install_dir) + else: + build_sora(platform, sora_dir, sora_args, debug, webrtc_build_dir) # CLI11 install_cli11_args = { - 'version': version['CLI11_VERSION'], - 'version_file': os.path.join(install_dir, 'cli11.version'), - 'install_dir': install_dir, + "version": version["CLI11_VERSION"], + "version_file": os.path.join(install_dir, "cli11.version"), + "install_dir": install_dir, } install_cli11(**install_cli11_args) - cmake_args = get_common_cmake_args(install_dir, platform) + cmake_args = get_common_cmake_args(install_dir, platform, webrtc_info) # Blend2D install_blend2d_args = { - 'version': version['BLEND2D_VERSION'] + '-' + version['ASMJIT_VERSION'], - 'version_file': os.path.join(install_dir, 'blend2d.version'), - 'source_dir': source_dir, - 'build_dir': build_dir, - 'install_dir': install_dir, - 'blend2d_version': version['BLEND2D_VERSION'], - 'asmjit_version': version['ASMJIT_VERSION'], - 'cmake_args': cmake_args, + "version": version["BLEND2D_VERSION"] + "-" + version["ASMJIT_VERSION"], + "version_file": os.path.join(install_dir, "blend2d.version"), + "configuration": "Debug" if debug else "Release", + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "blend2d_version": version["BLEND2D_VERSION"], + "asmjit_version": version["ASMJIT_VERSION"], + "ios": False, + "cmake_args": cmake_args, } install_blend2d(**install_blend2d_args) # OpenH264 install_openh264_args = { - 'version': version['OPENH264_VERSION'], - 'version_file': os.path.join(install_dir, 'openh264.version'), - 'source_dir': source_dir, - 'install_dir': install_dir, + "version": version["OPENH264_VERSION"], + "version_file": os.path.join(install_dir, "openh264.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "is_windows": False, } install_openh264(**install_openh264_args) # yaml-cpp install_yaml_args = { - 'version': version['YAML_CPP_VERSION'], - 'version_file': os.path.join(install_dir, 'yaml.version'), - 'source_dir': source_dir, - 'build_dir': build_dir, - 'install_dir': install_dir, - 'cmake_args': cmake_args, + "version": version["YAML_CPP_VERSION"], + "version_file": os.path.join(install_dir, "yaml.version"), + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "cmake_args": cmake_args, } install_yaml(**install_yaml_args) def main(): parser = argparse.ArgumentParser() - parser.add_argument("target", choices=[ - 'macos_arm64', 'ubuntu-20.04_x86_64', 'ubuntu-22.04_x86_64']) - parser.add_argument("--debug", action='store_true') - parser.add_argument("--package", action='store_true') + parser.add_argument( + "target", choices=["macos_arm64", "ubuntu-20.04_x86_64", "ubuntu-22.04_x86_64"] + ) + parser.add_argument("--debug", action="store_true") + parser.add_argument("--relwithdebinfo", action="store_true") + parser.add_argument("--webrtc-build-dir", type=os.path.abspath) + parser.add_argument("--webrtc-build-args", default="", type=shlex.split) + parser.add_argument("--sora-dir", type=os.path.abspath) + parser.add_argument("--sora-args", default="", type=shlex.split) + parser.add_argument("--package", action="store_true") args = parser.parse_args() - configuration_dir = 'debug' if args.debug else 'release' - source_dir = os.path.join( - BASE_DIR, '_source', args.target, configuration_dir) - build_dir = os.path.join( - BASE_DIR, '_build', args.target, configuration_dir) - install_dir = os.path.join( - BASE_DIR, '_install', args.target, configuration_dir) - package_dir = os.path.join( - BASE_DIR, '_package', args.target, configuration_dir) + platform = args.target + configuration_dir = "debug" if args.debug else "release" + 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) + package_dir = os.path.join(BASE_DIR, "_package", 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.target) - - configuration = 'Debug' if args.debug else 'Release' - - mkdir_p(os.path.join(build_dir, 'zakuro')) - with cd(os.path.join(build_dir, 'zakuro')): - webrtc_info = get_webrtc_info( - False, source_dir, build_dir, install_dir) + install_deps( + platform, + source_dir, + build_dir, + install_dir, + args.debug, + args.webrtc_build_dir, + args.webrtc_build_args, + args.sora_dir, + args.sora_args, + ) + + configuration = "Release" + if args.debug: + configuration = "Debug" + if args.relwithdebinfo: + configuration = "RelWithDebInfo" + + mkdir_p(os.path.join(build_dir, "zakuro")) + with cd(os.path.join(build_dir, "zakuro")): + webrtc_info = get_webrtc_info(platform, args.webrtc_build_dir, install_dir, args.debug) webrtc_version = read_version_file(webrtc_info.version_file) + sora_info = get_sora_info(platform, args.sora_dir, install_dir, args.debug) with cd(BASE_DIR): - version = read_version_file('VERSION') - zakuro_version = version['ZAKURO_VERSION'] - zakuro_commit = cmdcap(['git', 'rev-parse', 'HEAD']) + version = read_version_file("VERSION") + zakuro_version = version["ZAKURO_VERSION"] + zakuro_commit = cmdcap(["git", "rev-parse", "HEAD"]) cmake_args = [] - cmake_args.append(f'-DCMAKE_BUILD_TYPE={configuration}') - cmake_args.append(f'-DZAKURO_PLATFORM={args.target}') - cmake_args.append(f'-DZAKURO_VERSION={zakuro_version}') - cmake_args.append(f'-DZAKURO_COMMIT={zakuro_commit}') + cmake_args.append(f"-DCMAKE_BUILD_TYPE={configuration}") + cmake_args.append(f"-DZAKURO_PLATFORM={args.target}") + cmake_args.append(f"-DZAKURO_VERSION={zakuro_version}") + cmake_args.append(f"-DZAKURO_COMMIT={zakuro_commit}") cmake_args.append(f"-DWEBRTC_BUILD_VERSION={webrtc_version['WEBRTC_BUILD_VERSION']}") cmake_args.append(f"-DWEBRTC_READABLE_VERSION={webrtc_version['WEBRTC_READABLE_VERSION']}") cmake_args.append(f"-DWEBRTC_COMMIT={webrtc_version['WEBRTC_COMMIT']}") - cmake_args.append(f"-DSORA_DIR={cmake_path(os.path.join(install_dir, 'sora'))}") - cmake_args.append(f"-DBOOST_ROOT={cmake_path(os.path.join(install_dir, 'boost'))}") - cmake_args.append(f"-DLYRA_DIR={cmake_path(os.path.join(install_dir, 'lyra'))}") + cmake_args.append(f"-DSORA_DIR={cmake_path(sora_info.sora_install_dir)}") + 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"-DCLI11_ROOT_DIR={cmake_path(os.path.join(install_dir, 'cli11'))}") cmake_args.append(f"-DBLEND2D_ROOT_DIR={cmake_path(os.path.join(install_dir, 'blend2d'))}") - cmake_args.append(f"-DOPENH264_ROOT_DIR={cmake_path(os.path.join(install_dir, 'openh264'))}") + cmake_args.append( + f"-DOPENH264_ROOT_DIR={cmake_path(os.path.join(install_dir, 'openh264'))}" + ) cmake_args.append(f"-DYAML_ROOT_DIR={cmake_path(os.path.join(install_dir, 'yaml'))}") - cmake_args += get_common_cmake_args(install_dir, args.target) + cmake_args += get_common_cmake_args(install_dir, args.target, webrtc_info) - cmd(['cmake', BASE_DIR, *cmake_args]) - cmd(['cmake', '--build', '.', - f'-j{multiprocessing.cpu_count()}', '--config', configuration]) - # Lyra の model_coeffs をコピー - shutil.copytree(os.path.join(install_dir, 'lyra/share', 'model_coeffs'), - os.path.join(build_dir, 'zakuro', 'model_coeffs'), dirs_exist_ok=True) + cmd(["cmake", BASE_DIR, *cmake_args]) + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) if args.package: mkdir_p(package_dir) - zakuro_package_dir = os.path.join( - package_dir, f'zakuro-{zakuro_version}') + zakuro_package_dir = os.path.join(package_dir, f"zakuro-{zakuro_version}") rm_rf(zakuro_package_dir) - rm_rf(os.path.join(package_dir, 'zakuro.env')) + rm_rf(os.path.join(package_dir, "zakuro.env")) with cd(BASE_DIR): - version = read_version_file('VERSION') - zakuro_version = version['ZAKURO_VERSION'] + version = read_version_file("VERSION") + zakuro_version = version["ZAKURO_VERSION"] mkdir_p(zakuro_package_dir) with cd(zakuro_package_dir): - shutil.copyfile(os.path.join( - build_dir, 'zakuro', 'zakuro'), 'zakuro') - shutil.copytree(os.path.join( - install_dir, 'lyra/share', 'model_coeffs'), 'model_coeffs') - shutil.copyfile(os.path.join(BASE_DIR, 'LICENSE'), 'LICENSE') - with open('NOTICE', 'w') as f: - f.write(open(os.path.join(BASE_DIR, 'NOTICE')).read()) - f.write(open(os.path.join(install_dir, 'webrtc', 'NOTICE')).read()) - download('http://www.openh264.org/BINARY_LICENSE.txt') - f.write('# OpenH264 Binary License\n') - f.write('```\n') - f.write(open('BINARY_LICENSE.txt').read()) - f.write('```\n') - rm_rf('BINARY_LICENSE.txt') + shutil.copyfile(os.path.join(build_dir, "zakuro", "zakuro"), "zakuro") + shutil.copyfile(os.path.join(BASE_DIR, "LICENSE"), "LICENSE") + with open("NOTICE", "w") as f: + f.write(open(os.path.join(BASE_DIR, "NOTICE")).read()) + f.write(open(os.path.join(install_dir, "webrtc", "NOTICE")).read()) + download("http://www.openh264.org/BINARY_LICENSE.txt") + f.write("# OpenH264 Binary License\n") + f.write("```\n") + f.write(open("BINARY_LICENSE.txt").read()) + f.write("```\n") + rm_rf("BINARY_LICENSE.txt") with cd(package_dir): - archive_name = f'zakuro-{zakuro_version}_{args.target}.tar.gz' + archive_name = f"zakuro-{zakuro_version}_{args.target}.tar.gz" archive_path = os.path.join(package_dir, archive_name) - with tarfile.open(archive_path, 'w:gz') as f: - for file in enum_all_files(f'zakuro-{zakuro_version}', '.'): + with tarfile.open(archive_path, "w:gz") as f: + for file in enum_all_files(f"zakuro-{zakuro_version}", "."): f.add(name=file, arcname=file) - with open(os.path.join(package_dir, 'zakuro.env'), 'w') as f: + with open(os.path.join(package_dir, "zakuro.env"), "w") as f: f.write("CONTENT_TYPE=application/gzip\n") - f.write(f'PACKAGE_NAME={archive_name}\n') + f.write(f"PACKAGE_NAME={archive_name}\n") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/dynamic_h264_video_encoder.cpp b/src/dynamic_h264_video_encoder.cpp index 441e32c..c65fc91 100644 --- a/src/dynamic_h264_video_encoder.cpp +++ b/src/dynamic_h264_video_encoder.cpp @@ -512,7 +512,7 @@ int32_t DynamicH264VideoEncoder::Encode( encoded_images_[i]._encodedWidth = configurations_[i].width; encoded_images_[i]._encodedHeight = configurations_[i].height; - encoded_images_[i].SetTimestamp(input_frame.timestamp()); + encoded_images_[i].SetRtpTimestamp(input_frame.timestamp()); encoded_images_[i]._frameType = ConvertToVideoFrameType(info.eFrameType); encoded_images_[i].SetSpatialIndex(configurations_[i].simulcast_idx); diff --git a/src/enable_media_with_fake_call.cpp b/src/enable_media_with_fake_call.cpp new file mode 100644 index 0000000..3b7fb65 --- /dev/null +++ b/src/enable_media_with_fake_call.cpp @@ -0,0 +1,68 @@ +#include "enable_media_with_fake_call.h" + +#include +#include +#include +#include + +// WebRTC +#include +#include +#include + +class MediaFactoryImpl : public webrtc::MediaFactory { + public: + MediaFactoryImpl( + std::unique_ptr p, + const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, + const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config) + : p_(std::move(p)), + send_config_(send_config), + receive_config_(receive_config) {} + MediaFactoryImpl(const MediaFactoryImpl&) = delete; + MediaFactoryImpl& operator=(const MediaFactoryImpl&) = delete; + ~MediaFactoryImpl() override = default; + + std::unique_ptr CreateCall( + const webrtc::CallConfig& config) override { + webrtc::DegradedCall::TimeScopedNetworkConfig default_config; + + bool send_config_changed = + memcmp(&send_config_, &default_config, sizeof(default_config)) != 0; + bool receive_config_changed = + memcmp(&receive_config_, &default_config, sizeof(default_config)) != 0; + + std::unique_ptr call = webrtc::Call::Create(config); + + if (send_config_changed || receive_config_changed) { + std::vector send_config = { + send_config_}; + std::vector + receive_config = {receive_config_}; + return std::make_unique( + std::move(call), send_config, receive_config); + } + + return call; + } + + std::unique_ptr CreateMediaEngine( + const webrtc::Environment& env, + webrtc::PeerConnectionFactoryDependencies& deps) override { + return p_->CreateMediaEngine(env, deps); + } + + private: + std::unique_ptr p_; + webrtc::DegradedCall::TimeScopedNetworkConfig send_config_; + webrtc::DegradedCall::TimeScopedNetworkConfig receive_config_; +}; + +void EnableMediaWithFakeCall( + webrtc::PeerConnectionFactoryDependencies& deps, + const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, + const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config) { + webrtc::EnableMedia(deps); + deps.media_factory = std::make_unique( + std::move(deps.media_factory), send_config, receive_config); +} \ No newline at end of file diff --git a/src/enable_media_with_fake_call.h b/src/enable_media_with_fake_call.h new file mode 100644 index 0000000..4b342ac --- /dev/null +++ b/src/enable_media_with_fake_call.h @@ -0,0 +1,12 @@ +#ifndef ENABLE_MEDIA_WITH_FAKE_CALL_H_ +#define ENABLE_MEDIA_WITH_FAKE_CALL_H_ + +#include +#include + +void EnableMediaWithFakeCall( + webrtc::PeerConnectionFactoryDependencies& deps, + const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, + const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config); + +#endif \ No newline at end of file diff --git a/src/fake_network_call_factory.cpp b/src/fake_network_call_factory.cpp deleted file mode 100644 index cd93049..0000000 --- a/src/fake_network_call_factory.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "fake_network_call_factory.h" - -#include -#include -#include -#include - -// WebRTC -#include -#include -#include -#include - -FakeNetworkCallFactory::FakeNetworkCallFactory( - const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, - const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config) - : send_config_(send_config), receive_config_(receive_config) {} - -webrtc::Call* FakeNetworkCallFactory::CreateCall( - const webrtc::Call::Config& config) { - webrtc::DegradedCall::TimeScopedNetworkConfig default_config; - - webrtc::RtpTransportConfig transport_config = config.ExtractTransportConfig(); - - bool send_config_changed = - memcmp(&send_config_, &default_config, sizeof(default_config)) != 0; - bool receive_config_changed = - memcmp(&receive_config_, &default_config, sizeof(default_config)) != 0; - - webrtc::Call* call = webrtc::Call::Create( - config, webrtc::Clock::GetRealTimeClock(), - config.rtp_transport_controller_send_factory->Create( - transport_config, webrtc::Clock::GetRealTimeClock())); - - if (send_config_changed || receive_config_changed) { - std::vector send_config = { - send_config_}; - std::vector receive_config = - {receive_config_}; - return new webrtc::DegradedCall(std::unique_ptr(call), - send_config, receive_config); - } - - return call; -} -std::unique_ptr CreateFakeNetworkCallFactory( - const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, - const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config) { - return std::unique_ptr( - new FakeNetworkCallFactory(send_config, receive_config)); -} \ No newline at end of file diff --git a/src/fake_network_call_factory.h b/src/fake_network_call_factory.h deleted file mode 100644 index 8ae6370..0000000 --- a/src/fake_network_call_factory.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FAKE_NETWORK_CALL_FACTORY_H_ -#define FAKE_NETWORK_CALL_FACTORY_H_ - -#include -#include -#include -#include -#include -#include -#include - -class FakeNetworkCallFactory : public webrtc::CallFactoryInterface { - public: - FakeNetworkCallFactory( - const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, - const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config); - - private: - ~FakeNetworkCallFactory() override {} - webrtc::Call* CreateCall(const webrtc::CallConfig& config) override; - - webrtc::DegradedCall::TimeScopedNetworkConfig send_config_; - webrtc::DegradedCall::TimeScopedNetworkConfig receive_config_; -}; - -std::unique_ptr CreateFakeNetworkCallFactory( - const webrtc::DegradedCall::TimeScopedNetworkConfig& send_config, - const webrtc::DegradedCall::TimeScopedNetworkConfig& receive_config); - -#endif \ No newline at end of file diff --git a/src/game/game_kuzushi.h b/src/game/game_kuzushi.h index a467b9b..183366e 100644 --- a/src/game/game_kuzushi.h +++ b/src/game/game_kuzushi.h @@ -423,7 +423,7 @@ class GameKuzushi { } if (view_help_) { - ctx.resetMatrix(); + ctx.resetTransform(); ctx.setStrokeStyle(BLRgba32(255, 255, 255)); ctx.setFillStyle(BLRgba32(255, 255, 255)); std::string text = diff --git a/src/nop_video_decoder.cpp b/src/nop_video_decoder.cpp index 99e5f2b..782cca3 100644 --- a/src/nop_video_decoder.cpp +++ b/src/nop_video_decoder.cpp @@ -25,7 +25,7 @@ int32_t NopVideoDecoder::Decode(const webrtc::EncodedImage& input_image, webrtc::VideoFrame decoded_image = webrtc::VideoFrame::Builder() .set_video_frame_buffer(i420_buffer) - .set_timestamp_rtp(input_image.Timestamp()) + .set_timestamp_rtp(input_image.RtpTimestamp()) .build(); callback_->Decoded(decoded_image, absl::nullopt, absl::nullopt); diff --git a/src/util.cpp b/src/util.cpp index 38065bc..453a29d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -94,15 +94,18 @@ void Util::ParseArgs(const std::vector& cargs, app.add_option("--vcs-hatch-rate", config.vcs_hatch_rate, "Spawned virtual clients per seconds (default: 1.0)") ->check(CLI::Range(0.1, 100.0)); - app.add_option( - "--duration", config.duration, - "(Experimental) Duration of virtual client running in seconds (if not zero) (default: 0.0)"); + app.add_option("--duration", config.duration, + "(Experimental) Duration of virtual client running in seconds " + "(if not zero) (default: 0.0)"); app.add_option("--repeat-interval", config.repeat_interval, - "(Experimental) (If duration is set) Interval to reconnect after disconnection (default: 0.0)"); - app.add_option("--max-retry", config.max_retry, - "(Experimental) Max retries when a connection fails (default: 0)"); + "(Experimental) (If duration is set) Interval to reconnect " + "after disconnection (default: 0.0)"); + app.add_option( + "--max-retry", config.max_retry, + "(Experimental) Max retries when a connection fails (default: 0)"); app.add_option("--retry-interval", config.retry_interval, - "(Experimental) (If max-retry is set) Interval to reconnect after connection fails (default: 60)"); + "(Experimental) (If max-retry is set) Interval to reconnect " + "after connection fails (default: 60)"); app.add_flag("--no-video-device", config.no_video_device, "Do not use video device (default: false)"); @@ -116,7 +119,8 @@ void Util::ParseArgs(const std::vector& cargs, app.add_option("--fake-audio-capture", config.fake_audio_capture, "Fake Audio from File") ->check(CLI::ExistingFile); - app.add_flag("--sandstorm", config.sandstorm, "Fake Sandstorm Video (default: false)"); + app.add_flag("--sandstorm", config.sandstorm, + "Fake Sandstorm Video (default: false)"); #if defined(__APPLE__) app.add_option("--video-device", config.video_device, "Use the video device specified by an index or a name " @@ -131,15 +135,18 @@ void Util::ParseArgs(const std::vector& cargs, "Video resolution (one of QVGA, VGA, HD, FHD, 4K, or " "[WIDTH]x[HEIGHT]) (default: VGA)") ->check(is_valid_resolution); - app.add_option("--framerate", config.framerate, "Video framerate (default: 30)") + app.add_option("--framerate", config.framerate, + "Video framerate (default: 30)") ->check(CLI::Range(1, 60)); app.add_flag("--fixed-resolution", config.fixed_resolution, "Maintain video resolution in degradation (default: false)"); - app.add_option("--priority", config.priority, - "(Experimental) Preference in video degradation (default: BALANCE)") + app.add_option( + "--priority", config.priority, + "(Experimental) Preference in video degradation (default: BALANCE)") ->check(CLI::IsMember({"BALANCE", "FRAMERATE", "RESOLUTION"})); - app.add_flag("--insecure", config.insecure, - "Allow insecure server connections when using SSL (default: false)"); + app.add_flag( + "--insecure", config.insecure, + "Allow insecure server connections when using SSL (default: false)"); app.add_option("--openh264", config.openh264, "OpenH264 dynamic library path. \"OpenH264 Video Codec " "provided by Cisco Systems, Inc.\"") @@ -166,7 +173,8 @@ void Util::ParseArgs(const std::vector& cargs, "Signaling URLs") ->take_all(); app.add_flag("--sora-disable-signaling-url-randomization", - config.sora_disable_signaling_url_randomization, "Disable random connections to signaling URLs (default: false)"); + config.sora_disable_signaling_url_randomization, + "Disable random connections to signaling URLs (default: false)"); app.add_option("--sora-channel-id", config.sora_channel_id, "Channel ID"); app.add_option("--sora-client-id", config.sora_client_id, "Client ID"); app.add_option("--sora-bundle-id", config.sora_bundle_id, "Bundle ID"); @@ -184,18 +192,7 @@ void Util::ParseArgs(const std::vector& cargs, ->check(CLI::IsMember({"", "VP8", "VP9", "AV1", "H264"})); app.add_option("--sora-audio-codec-type", config.sora_audio_codec_type, "Audio codec for send (default: none)") - ->check(CLI::IsMember({"", "OPUS", "LYRA"})); - app.add_option("--sora-audio-codec-lyra-bitrate", - config.sora_audio_codec_lyra_bit_rate, - "Lyra audio codec bitrate (default: none)") - ->check(CLI::Range(0, 9200)); - app.add_option("--sora-audio-codec-lyra-usedtx", - config.sora_audio_codec_lyra_usedtx, - "Lyra usedtx (default: none)") - ->type_name("TEXT") - ->transform(CLI::CheckedTransformer(optional_bool_map, CLI::ignore_case)); - app.add_option("--sora-check-lyra-version", config.sora_check_lyra_version, - "Lyra version check (default: false)"); + ->check(CLI::IsMember({"", "OPUS"})); app.add_option("--sora-video-bit-rate", config.sora_video_bit_rate, "Video bit rate (default: none)") ->check(CLI::Range(0, 30000)); @@ -219,7 +216,8 @@ void Util::ParseArgs(const std::vector& cargs, app.add_option("--sora-spotlight-focus-rid", config.sora_spotlight_focus_rid, "Spotlight focus rid (default: none)"); app.add_option("--sora-spotlight-unfocus-rid", - config.sora_spotlight_unfocus_rid, "Spotlight unfocus rid (default: none)"); + config.sora_spotlight_unfocus_rid, + "Spotlight unfocus rid (default: none)"); app.add_option("--sora-data-channel-signaling", config.sora_data_channel_signaling, "Use DataChannel for Sora signaling (default: none)") @@ -256,10 +254,12 @@ void Util::ParseArgs(const std::vector& cargs, ->check(is_json); std::string sora_signaling_notify_metadata; app.add_option("--sora-signaling-notify-metadata", - sora_signaling_notify_metadata, "Signaling metadata (default: none)") + sora_signaling_notify_metadata, + "Signaling metadata (default: none)") ->check(is_json); std::string sora_data_channels; - app.add_option("--sora-data-channels", sora_data_channels, "DataChannels (default: none)") + app.add_option("--sora-data-channels", sora_data_channels, + "DataChannels (default: none)") ->check(is_json); // Fake network 系 @@ -356,8 +356,9 @@ void Util::ParseArgs(const std::vector& cargs, config.sora_video_codec_type != "VP9" && config.sora_video_codec_type != "AV1" && config.sora_video_codec_type != "H264") { - std::cerr << "Simulcast works only --sora-video-codec=VP8, VP9, AV1 or H264." - << std::endl; + std::cerr + << "Simulcast works only --sora-video-codec=VP8, VP9, AV1 or H264." + << std::endl; std::exit(1); } diff --git a/src/virtual_client.cpp b/src/virtual_client.cpp index e8e7eef..344adef 100644 --- a/src/virtual_client.cpp +++ b/src/virtual_client.cpp @@ -57,7 +57,7 @@ void VirtualClient::Connect() { if (!config_.no_video_device) { std::string video_track_id = rtc::CreateRandomString(16); video_track_ = config_.context->peer_connection_factory()->CreateVideoTrack( - video_track_id, config_.capturer.get()); + config_.capturer, video_track_id); if (config_.fixed_resolution) { video_track_->set_content_hint( diff --git a/src/zakuro.cpp b/src/zakuro.cpp index 6fa0294..cd76a7b 100644 --- a/src/zakuro.cpp +++ b/src/zakuro.cpp @@ -13,8 +13,8 @@ #include #include "dynamic_h264_video_encoder.h" +#include "enable_media_with_fake_call.h" #include "fake_audio_key_trigger.h" -#include "fake_network_call_factory.h" #include "fake_video_capturer.h" #include "game/game_kuzushi.h" #include "nop_video_decoder.h" @@ -316,11 +316,10 @@ int Zakuro::Run() { context_config.use_hardware_encoder = false; context_config.use_audio_device = false; - context_config.configure_media_dependencies = - [vc = vc_config]( - const webrtc::PeerConnectionFactoryDependencies& dependencies, - cricket::MediaEngineDependencies& media_dependencies) { - media_dependencies.adm = dependencies.worker_thread->BlockingCall([&] { + context_config.configure_dependencies = + [vc = + vc_config](webrtc::PeerConnectionFactoryDependencies& dependencies) { + auto adm = dependencies.worker_thread->BlockingCall([&] { ZakuroAudioDeviceModuleConfig admconfig; admconfig.task_queue_factory = dependencies.task_queue_factory.get(); if (vc.audio_type == VirtualClientConfig::AudioType::Device) { @@ -356,6 +355,8 @@ int Zakuro::Run() { } return ZakuroAudioDeviceModule::Create(std::move(admconfig)); }); + dependencies.worker_thread->BlockingCall( + [&] { dependencies.adm = adm; }); auto sw_config = sora::GetSoftwareOnlyVideoEncoderFactoryConfig(); sw_config.use_simulcast_adapter = true; @@ -364,22 +365,18 @@ int Zakuro::Run() { [openh264 = vc.openh264]( auto format) -> std::unique_ptr { return webrtc::DynamicH264VideoEncoder::Create( - cricket::VideoCodec(format), openh264); + cricket::CreateVideoCodec(format), openh264); })); - media_dependencies.video_encoder_factory = + dependencies.video_encoder_factory = absl::make_unique( std::move(sw_config)); - media_dependencies.video_decoder_factory.reset( - new NopVideoDecoderFactory()); - }; + dependencies.video_decoder_factory.reset(new NopVideoDecoderFactory()); - context_config.configure_dependencies = - [vc = - vc_config](webrtc::PeerConnectionFactoryDependencies& dependencies) { - dependencies.call_factory = CreateFakeNetworkCallFactory( - vc.fake_network_send, vc.fake_network_receive); dependencies.sctp_factory.reset( new SctpTransportFactory(dependencies.network_thread)); + + EnableMediaWithFakeCall(dependencies, vc.fake_network_send, + vc.fake_network_receive); }; vc_config.context = sora::SoraClientContext::Create(context_config); @@ -398,9 +395,6 @@ int Zakuro::Run() { sora_config.audio = config_.sora_audio; sora_config.video_codec_type = config_.sora_video_codec_type; sora_config.audio_codec_type = config_.sora_audio_codec_type; - sora_config.audio_codec_lyra_bitrate = config_.sora_audio_codec_lyra_bit_rate; - sora_config.audio_codec_lyra_usedtx = config_.sora_audio_codec_lyra_usedtx; - sora_config.check_lyra_version = config_.sora_check_lyra_version; sora_config.video_bit_rate = config_.sora_video_bit_rate; sora_config.audio_bit_rate = config_.sora_audio_bit_rate; sora_config.metadata = config_.sora_metadata;