From cf4179ede09974f921a1b533ff26b54972b943ba Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 5 May 2026 12:05:00 -0600 Subject: [PATCH 1/6] Try clang-format in CI --- .clang-format | 2 + .github/workflows/builds.yml | 49 ++++ scripts/clang-format.sh | 427 +++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 .clang-format create mode 100755 scripts/clang-format.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..f6b8fdf2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: LLVM diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 784687d2..dfcfe6be 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -17,6 +17,8 @@ on: - docker/Dockerfile.base - docker/Dockerfile.sdk - .github/workflows/** + - .clang-format + - scripts/clang-format.sh pull_request: branches: ["main"] paths: @@ -33,6 +35,8 @@ on: - docker/Dockerfile.base - docker/Dockerfile.sdk - .github/workflows/** + - .clang-format + - scripts/clang-format.sh workflow_dispatch: permissions: @@ -547,6 +551,51 @@ jobs: cmake --build build --parallel ' + clang-format: + name: clang-format + runs-on: ubuntu-latest + continue-on-error: false + permissions: + contents: read + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + # No submodules: scripts/clang-format.sh only walks our own src/ + # tree (the client-sdk-rust submodule has its own .clang-format). + fetch-depth: 1 + + - name: Install clang-format 19 + run: | + set -eux + # Pin clang-format 19 to match the clang-tidy job and keep CI + # output deterministic across runs. Ubuntu 24.04's default + # clang-format ships with LLVM 18; pull 19 from the upstream + # LLVM apt repository so a developer running clang-format-19 + # locally gets the same result CI does. + sudo install -m 0755 -d /etc/apt/keyrings + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ + | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null + sudo chmod a+r /etc/apt/keyrings/llvm.asc + codename=$(lsb_release -cs) + echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-19 main" \ + | sudo tee /etc/apt/sources.list.d/llvm-19.list >/dev/null + sudo apt-get update + sudo apt-get install -y clang-format-19 + sudo ln -sf /usr/bin/clang-format-19 /usr/local/bin/clang-format + clang-format --version + + - name: Run clang-format + env: + FORMAT_BLOB_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + # This script is intended to be run locally and in CI. It will + # auto-detect the GHA environment and emit PR file annotations + # plus a markdown step summary when GITHUB_ACTIONS=true. Default + # mode is check-only (--dry-run --Werror), which exits non-zero + # on any divergence from the repo-root .clang-format. + run: ./scripts/clang-format.sh + clang-tidy: name: clang-tidy runs-on: ubuntu-latest diff --git a/scripts/clang-format.sh b/scripts/clang-format.sh new file mode 100755 index 00000000..2643e352 --- /dev/null +++ b/scripts/clang-format.sh @@ -0,0 +1,427 @@ +#!/usr/bin/env bash +# +# Copyright 2026 LiveKit +# +# 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. + +# +# clang-format.sh -- Run clang-format locally and in CI using the same file +# set and config. Picks up style from the repo-root .clang-format +# automatically. +# +# Usage (from anywhere; the script self-anchors to the repo root): +# ./scripts/clang-format.sh # check the full src/ tree +# ./scripts/clang-format.sh --fix # apply formatting in place +# ./scripts/clang-format.sh src/room.cpp src/foo.h # check just these files +# ./scripts/clang-format.sh --fix src/room.cpp # fix just this file +# ./scripts/clang-format.sh --github-actions # force CI annotation mode +# +# Default mode is "check" (clang-format --dry-run --Werror): no files are +# modified and the script exits non-zero if any file diverges from +# .clang-format. Pass --fix / -i to apply formatting in place instead. +# +# Every run prints a concise stdout summary at the end with the number of +# files checked / fixed (and the list of offending paths when checking). +# +# In GitHub Actions (auto-detected via $GITHUB_ACTIONS=true, or forced with +# --github-actions), this script additionally: +# - Emits ::error workflow commands so violations appear as PR file +# annotations (red). +# - Writes a markdown summary to $GITHUB_STEP_SUMMARY listing every file +# that needs formatting, linkified to github.com when possible. +# +# Exit code: +# - 0 when every file is already formatted (check mode) or when --fix +# completed successfully. +# - 1 when at least one file needs formatting (check mode only). +# - The clang-format / xargs exit code on any other failure (missing tool, +# unreadable file, etc.). + +set -euo pipefail + +# Anchor every relative path (clang-format.log, git ls-files, etc.) to the +# repo root regardless of how/where this script is invoked. Without this, +# calling the script from a subdirectory or via an absolute path would break +# git ls-files scoping and the log path below. +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +cd "${script_dir}/.." + +# Usage banner. Printed by --help and referenced by the EXIT trap below so +# users who hit a pre-flight error or a bad argument get pointed at this. +usage() { + cat <<'EOF' +Usage: ./scripts/clang-format.sh [OPTIONS] [FILE...] + +Run clang-format locally or in CI using the repo-root .clang-format. Defaults +to check-only (dry-run); pass --fix to rewrite files in place. + +Options: + -h, --help, -? + Show this help and exit. + --fix, -i + Apply formatting in place. Without this, the script runs in check + mode (--dry-run --Werror) and exits non-zero on any divergence. + --github-actions, --gh + Force GitHub Actions annotation + step-summary mode. + Auto-detected when GITHUB_ACTIONS=true. + +Positional arguments: + FILE... + Explicit list of files to format / check. When omitted, the script + walks the tracked src/ tree (excluding src/tests/) and operates on + every C/C++ source and header it finds. Pass paths to make the + script work as a precommit hook on a curated set of files, e.g.: + git diff --cached --name-only --diff-filter=ACMR \ + | grep -E '\.(c|cc|cpp|cxx|h|hpp|hxx)$' \ + | xargs ./scripts/clang-format.sh --fix + +Examples: + ./scripts/clang-format.sh # check full src/ tree + ./scripts/clang-format.sh --fix # fix the same tree + ./scripts/clang-format.sh src/room.cpp src/foo.h # check just these files + ./scripts/clang-format.sh --fix src/room.cpp # fix just this file + ./scripts/clang-format.sh --github-actions # force CI annotations + +Pre-requisites: + clang-format must be installed and on PATH: + brew install clang-format # macOS + apt install clang-format-19 # Linux (or any version >= 11) +EOF +} + +# Print a one-line "see --help" hint on any non-zero exit during pre-flight +# (argument parsing, missing tool, etc.). Suppressed once we hand off to +# clang-format itself, so legitimate formatting violations don't trigger +# the hint. +__fmt_hint_active=1 +__fmt_print_hint() { + local rc=$? + if (( rc != 0 )) && (( __fmt_hint_active )); then + echo >&2 + echo "Run './scripts/clang-format.sh --help' for usage." >&2 + fi +} +trap __fmt_print_hint EXIT + +CI_MODE=0 +# Automatically detect CI mode if in GitHub Actions environment. +if [[ "${GITHUB_ACTIONS:-}" == "true" ]]; then + CI_MODE=1 +fi + +# Default to check (dry-run) mode; --fix flips to in-place rewriting. +FIX_MODE=0 + +explicit_files=() +while (($#)); do + case "$1" in + -h|--help|-\?) + usage + __fmt_hint_active=0 + exit 0 + ;; + --fix|-i) + FIX_MODE=1 + shift + ;; + --github-actions|--gh) + CI_MODE=1 + shift + ;; + --) + # Explicit positional separator: everything after `--` is a file path. + shift + explicit_files+=("$@") + break + ;; + --*|-*) + # Long / short options we don't recognize are user typos far more often + # than legitimate clang-format flags. Reject and surface usage. + echo "ERROR: unknown option: $1" >&2 + usage >&2 + exit 2 + ;; + *) + explicit_files+=("$1") + shift + ;; + esac +done + +if ! command -v clang-format >/dev/null 2>&1; then + echo "ERROR: clang-format not found in PATH." >&2 + echo "Install: brew install clang-format (macOS)" >&2 + echo " apt install clang-format-19 (Linux)" >&2 + exit 1 +fi + +# Surface the version in CI logs so future regressions tied to a specific +# clang-format release are easy to bisect. +clang-format --version + +# Build the list of files to operate on. When the user passes explicit paths +# we honor them verbatim (no globbing, no src/tests/ filtering) so a precommit +# hook can supply its own staged-file list. Otherwise we walk the tracked +# src/ tree, excluding src/tests/. Using `git ls-files` automatically skips +# the client-sdk-rust/ submodule, build-*/, _deps/, local-install/, etc., +# without having to maintain a lookahead exclusion regex. +files=() +if (( ${#explicit_files[@]} > 0 )); then + files=("${explicit_files[@]}") +else + while IFS= read -r -d '' path; do + [[ "${path}" == src/tests/* ]] && continue + files+=("${path}") + done < <(git ls-files -z \ + 'src/*.c' 'src/*.cc' 'src/*.cpp' 'src/*.cxx' \ + 'src/*.h' 'src/*.hpp' 'src/*.hxx') +fi + +file_count=${#files[@]} +if (( file_count == 0 )); then + echo "clang-format: no files to process." + __fmt_hint_active=0 + exit 0 +fi + +# xargs parallelism: one worker per logical CPU. `nproc` is the Linux +# coreutils tool; macOS doesn't ship it, so fall back to `sysctl hw.ncpu`, +# and finally to a conservative 4 if neither is available. +if command -v nproc >/dev/null 2>&1; then + jobs=$(nproc) +else + jobs=$(sysctl -n hw.ncpu 2>/dev/null || echo 4) +fi + +# Capture clang-format's combined stdout+stderr to a stable, repo-local path +# so it can be re-parsed after the run (for annotations and the step summary) +# and re-read by the user afterwards. `*.log` is gitignored so this file +# never gets committed. +log="clang-format.log" +: > "${log}" + +# Past pre-flight: any non-zero exit from here on is a clang-format result +# (violations, internal error, etc.), not a user-facing argument/usage error, +# so suppress the "see --help" hint installed via the EXIT trap above. +__fmt_hint_active=0 + +# -------- Begin GitHub Actions annotations -------- + +# Emit GitHub Actions workflow commands for each clang-format diagnostic line +# in the given log. Source / caret lines are skipped; only the +# `path:line:col: error: ... [-Wclang-format-violations]` lines become +# annotations. Severity is always ::error because --Werror promotes every +# violation to an error and we treat any divergence as a hard CI failure. +emit_annotations() { + local log_file="$1" + local workspace="${GITHUB_WORKSPACE:-${PWD}}" + local line path lineno col message rel_path + + while IFS= read -r line; do + [[ "${line}" =~ ^(.+):([0-9]+):([0-9]+):[[:space:]]+(error|warning):[[:space:]]+(.+)[[:space:]]\[-Wclang-format-violations\][[:space:]]*$ ]] || continue + path="${BASH_REMATCH[1]}" + lineno="${BASH_REMATCH[2]}" + col="${BASH_REMATCH[3]}" + message="${BASH_REMATCH[5]}" + + rel_path="${path#${workspace}/}" + + message="${message//$'%'/%25}" + message="${message//$'\r'/%0D}" + message="${message//$'\n'/%0A}" + + printf '::error file=%s,line=%s,col=%s,title=clang-format::%s\n' \ + "${rel_path}" "${lineno}" "${col}" "${message}" + done < "${log_file}" +} + +# Append a markdown summary (count + per-file list) to $GITHUB_STEP_SUMMARY so +# the GitHub job page surfaces every offending file without scanning the raw +# log. Each file is linkified to github.com when we can resolve a blob URL. +write_step_summary() { + local log_file="$1" + local summary_file="${GITHUB_STEP_SUMMARY:-}" + [[ -n "${summary_file}" ]] || return 0 + + local workspace="${GITHUB_WORKSPACE:-${PWD}}" + local files_tsv + files_tsv="$(mktemp -t fmt-files.XXXXXX)" + + # Extract first violation line per file as path\tline. Multiple violations + # in one file collapse to a single row -- clicking through to the file is + # enough; the developer fixes them with `clang-format -i` regardless. + local sline spath slineno + declare -A seen=() + while IFS= read -r sline; do + [[ "${sline}" =~ ^(.+):([0-9]+):([0-9]+):[[:space:]]+(error|warning):[[:space:]]+(.+)[[:space:]]\[-Wclang-format-violations\][[:space:]]*$ ]] || continue + spath="${BASH_REMATCH[1]#${workspace}/}" + slineno="${BASH_REMATCH[2]}" + if [[ -z "${seen[${spath}]:-}" ]]; then + seen[${spath}]=1 + printf '%s\t%s\n' "${spath}" "${slineno}" >> "${files_tsv}" + fi + done < "${log_file}" + + local violation_files + violation_files=$(wc -l < "${files_tsv}" | tr -d ' ') + + # Resolve a blob URL prefix so files in the table become clickable links. + # Prefer FORMAT_BLOB_SHA (set by the workflow to the PR head SHA) over + # GITHUB_SHA -- on pull_request events GITHUB_SHA points at the ephemeral + # refs/pull/N/merge commit, whose blob URLs stop resolving once the PR + # closes. On push / workflow_dispatch / schedule runs FORMAT_BLOB_SHA is + # unset and we fall through to GITHUB_SHA, which is the pushed / selected + # commit respectively. + local repo_url="" + if [[ -n "${GITHUB_SERVER_URL:-}" && -n "${GITHUB_REPOSITORY:-}" ]]; then + local blob_sha="${FORMAT_BLOB_SHA:-${GITHUB_SHA:-}}" + if [[ -n "${blob_sha}" ]]; then + repo_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/blob/${blob_sha}" + fi + fi + + { + echo "## clang-format results" + echo + if (( violation_files == 0 )); then + echo ":white_check_mark: All files are properly formatted." + else + echo ":x: ${violation_files} file(s) need formatting." + echo + echo "
Files needing formatting" + echo + echo '| File |' + echo '|------|' + while IFS=$'\t' read -r path lineno; do + local file_cell + if [[ -n "${repo_url}" && "${path}" != /* ]]; then + file_cell="[\`${path}\`](${repo_url}/${path}#L${lineno})" + else + file_cell="\`${path}\`" + fi + printf '| %s |\n' "${file_cell}" + done < "${files_tsv}" + echo + echo "
" + echo + echo "Run \`./scripts/clang-format.sh --fix\` locally to apply formatting." + fi + } >> "${summary_file}" + + rm -f "${files_tsv}" +} + +# Print a one-line summary plus the offending file list to stdout. Always +# runs (regardless of CI_MODE) so local invocations get the same headline +# view the GitHub step summary provides. Sets a global consumed by the +# exit-code logic below: __FMT_VIOLATION_FILES. +print_stdout_summary() { + local log_file="$1" + local total="$2" + local files_tsv + files_tsv="$(mktemp -t fmt-stdout.XXXXXX)" + + local line spath + declare -A seen=() + while IFS= read -r line; do + [[ "${line}" =~ ^(.+):([0-9]+):([0-9]+):[[:space:]]+(error|warning):[[:space:]]+(.+)[[:space:]]\[-Wclang-format-violations\][[:space:]]*$ ]] || continue + spath="${BASH_REMATCH[1]}" + if [[ -z "${seen[${spath}]:-}" ]]; then + seen[${spath}]=1 + echo "${spath}" >> "${files_tsv}" + fi + done < "${log_file}" + + local violation_files + violation_files=$(wc -l < "${files_tsv}" | tr -d ' ') + + echo "------------------------------------------------------------" + if (( violation_files == 0 )); then + printf 'clang-format summary: clean (%d file(s) checked)\n' "${total}" + else + printf 'clang-format summary: %d of %d file(s) need formatting\n' \ + "${violation_files}" "${total}" + echo " files:" + while IFS= read -r f; do + printf ' %s\n' "${f}" + done < "${files_tsv}" + echo + echo " Run './scripts/clang-format.sh --fix' to apply formatting." + fi + echo "------------------------------------------------------------" + + rm -f "${files_tsv}" + __FMT_VIOLATION_FILES="${violation_files}" +} + +# --------- End GitHub Actions annotations --------- + +# Run clang-format. In fix mode, batch files across worker invocations for +# throughput; in check mode, hand each worker exactly one file so per-file +# diagnostics don't interleave across processes (clang-format writes one +# small diagnostic per violation, which on POSIX is atomic for writes +# <= PIPE_BUF, but only when each writer holds the fd alone for the whole +# message -- using -n 1 keeps each process's output contiguous in the log). +set +e +if (( FIX_MODE == 1 )); then + printf '%s\0' "${files[@]}" \ + | xargs -0 -n 32 -P "${jobs}" clang-format -i \ + >"${log}" 2>&1 + rc=$? +else + printf '%s\0' "${files[@]}" \ + | xargs -0 -n 1 -P "${jobs}" clang-format --dry-run --Werror \ + >"${log}" 2>&1 + rc=$? +fi +set -e + +# Mirror the captured log to stdout so users see violations inline (the file +# is also kept on disk for re-parsing / re-reading after the run). +cat "${log}" + +if [[ "${CI_MODE}" == "1" ]]; then + emit_annotations "${log}" + write_step_summary "${log}" +fi + +echo "Results written to: $(pwd)/${log}" + +# Always emit the concise headline summary to stdout. Sets +# __FMT_VIOLATION_FILES which the exit-code logic below consumes. +__FMT_VIOLATION_FILES=0 +if (( FIX_MODE == 1 )); then + echo "------------------------------------------------------------" + printf 'clang-format summary: applied formatting to %d file(s)\n' "${file_count}" + echo "------------------------------------------------------------" +else + print_stdout_summary "${log}" "${file_count}" +fi + +# Exit-code policy: +# - In --fix mode, propagate clang-format's own exit code (non-zero means +# a real failure such as a missing file, not "needed reformatting"). +# - In check mode, treat xargs's "child exited 1-125" status (123) as a +# formatting violation -> exit 1. Any other non-zero status is a real +# failure (missing file, IO error, etc.) and we propagate it as-is. +if (( FIX_MODE == 1 )); then + exit "${rc}" +fi + +if (( rc == 0 )); then + exit 0 +elif (( rc == 123 )) || (( __FMT_VIOLATION_FILES > 0 )); then + exit 1 +else + exit "${rc}" +fi From e352d8fd1af5c105e042b24a36b43b6fb0c67228 Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 5 May 2026 12:53:13 -0600 Subject: [PATCH 2/6] Fixed all format issues (allegedly) --- src/audio_frame.cpp | 3 ++- src/audio_source.cpp | 5 +++-- src/data_stream.cpp | 11 +++++------ src/ffi_client.cpp | 14 ++++++++------ src/ffi_client.h | 4 ++-- src/room_proto_converter.cpp | 6 ++++-- src/trace/event_tracer.cpp | 4 ++-- src/video_frame.cpp | 8 ++++++-- src/video_utils.cpp | 3 ++- 9 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/audio_frame.cpp b/src/audio_frame.cpp index dc27136d..fd070960 100644 --- a/src/audio_frame.cpp +++ b/src/audio_frame.cpp @@ -70,7 +70,8 @@ AudioFrame::fromOwnedInfo(const proto::OwnedAudioFrameBuffer &owned) { static_cast(samples_per_channel); const std::int16_t *ptr = - reinterpret_cast(info.data_ptr()); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr) + reinterpret_cast(info.data_ptr()); if (ptr == nullptr && count > 0) { throw std::runtime_error( diff --git a/src/audio_source.cpp b/src/audio_source.cpp index 63fcd07d..c5c6ee0c 100644 --- a/src/audio_source.cpp +++ b/src/audio_source.cpp @@ -102,8 +102,9 @@ void AudioSource::captureFrame(const AudioFrame &frame, int timeout_ms) { // Queue tracking, same logic as before const double now = now_seconds(); const double elapsed = (last_capture_ == 0.0) ? 0.0 : (now - last_capture_); - const double frame_duration = static_cast(frame.samples_per_channel()) / - static_cast(sample_rate_); + const double frame_duration = + static_cast(frame.samples_per_channel()) / + static_cast(sample_rate_); q_size_ += frame_duration - elapsed; if (q_size_ < 0.0) { q_size_ = 0.0; // clamp diff --git a/src/data_stream.cpp b/src/data_stream.cpp index 9f846a27..ef46a8fe 100644 --- a/src/data_stream.cpp +++ b/src/data_stream.cpp @@ -192,14 +192,12 @@ bool ByteStreamReader::readNext(std::vector &out) { BaseStreamWriter::BaseStreamWriter( LocalParticipant &local_participant, std::string topic, - std::map attributes, - std::string stream_id, std::optional total_size, - std::string mime_type, + std::map attributes, std::string stream_id, + std::optional total_size, std::string mime_type, std::vector destination_identities, std::string sender_identity) : local_participant_(local_participant), - stream_id_(stream_id.empty() ? generateRandomId() - : std::move(stream_id)), + stream_id_(stream_id.empty() ? generateRandomId() : std::move(stream_id)), mime_type_(std::move(mime_type)), topic_(std::move(topic)), timestamp_ms_(std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) @@ -348,7 +346,8 @@ void ByteStreamWriter::write(const std::vector &data) { const std::size_t n = std::min(kStreamChunkSize, data.size() - offset); auto it = data.begin() + static_cast(offset); - const std::vector chunk(it, it + static_cast(n)); + const std::vector chunk(it, + it + static_cast(n)); sendChunk(chunk); offset += n; } diff --git a/src/ffi_client.cpp b/src/ffi_client.cpp index 1f08d824..c6480cd2 100644 --- a/src/ffi_client.cpp +++ b/src/ffi_client.cpp @@ -24,11 +24,11 @@ #include "livekit/data_track_error.h" #include "livekit/e2ee.h" #include "livekit/ffi_handle.h" -#include "lk_log.h" #include "livekit/room.h" #include "livekit/rpc_error.h" #include "livekit/track.h" #include "livekit_ffi.h" +#include "lk_log.h" #include "room.pb.h" #include "room_proto_converter.h" @@ -247,7 +247,9 @@ void FfiClient::PushEvent(const proto::FfiEvent &event) const { void LivekitFfiCallback(const uint8_t *buf, size_t len) { proto::FfiEvent event; - event.ParseFromArray(buf, static_cast(len)); // TODO: this fixes for now, what if len exceeds int? + event.ParseFromArray( + buf, static_cast( + len)); // TODO: this fixes for now, what if len exceeds int? FfiClient::instance().PushEvent(event); } @@ -641,9 +643,8 @@ FfiClient::publishDataTrackAsync(std::uint64_t local_participant_handle, const auto &cb = event.publish_data_track(); if (cb.has_error()) { pr.set_value( - Result::failure( - PublishDataTrackError::fromProto(cb.error()))); + Result:: + failure(PublishDataTrackError::fromProto(cb.error()))); return; } if (!cb.has_track()) { @@ -655,7 +656,8 @@ FfiClient::publishDataTrackAsync(std::uint64_t local_participant_handle, return; } pr.set_value( - Result::success(cb.track())); + Result::success( + cb.track())); }); proto::FfiRequest req; diff --git a/src/ffi_client.h b/src/ffi_client.h index 182dc143..22a5c1c3 100644 --- a/src/ffi_client.h +++ b/src/ffi_client.h @@ -190,8 +190,8 @@ class FfiClient { promise.set_exception(std::make_exception_ptr( std::runtime_error("Async operation cancelled"))); } catch (const std::future_error &e) { - // Unlikely to throw here as the promise should be satisfied before cancel() - // Logging a debug message to avoid clang empty catch warning + // Unlikely to throw here as the promise should be satisfied before + // cancel() Logging a debug message to avoid clang empty catch warning LK_LOG_DEBUG("FfiClient::cancel: promise already satisfied: {}", e.what()); } diff --git a/src/room_proto_converter.cpp b/src/room_proto_converter.cpp index 4de4c822..ed5ef96b 100644 --- a/src/room_proto_converter.cpp +++ b/src/room_proto_converter.cpp @@ -109,7 +109,8 @@ UserPacketData fromProto(const proto::UserPacket &in) { UserPacketData out; // TODO, double check following code is safe const auto &buf = in.data().data(); - const auto *ptr = reinterpret_cast(buf.data_ptr()); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr) + const auto *ptr = reinterpret_cast(buf.data_ptr()); auto len = static_cast(buf.data_len()); out.data.assign(ptr, ptr + len); if (in.has_topic()) { @@ -426,7 +427,8 @@ UserDataPacketEvent userDataPacketFromProto(const proto::DataPacketReceived &in, const auto &owned = in.user().data(); const auto &info = owned.data(); if (info.data_ptr() != 0 && info.data_len() > 0) { - const auto *ptr = reinterpret_cast(info.data_ptr()); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr) + const auto *ptr = reinterpret_cast(info.data_ptr()); auto len = static_cast(info.data_len()); ev.data.assign(ptr, ptr + len); } else { diff --git a/src/trace/event_tracer.cpp b/src/trace/event_tracer.cpp index ec57de33..9fbc959d 100644 --- a/src/trace/event_tracer.cpp +++ b/src/trace/event_tracer.cpp @@ -357,8 +357,8 @@ void EventTracer::AddTraceEvent(char phase, // Handle string arguments if (arg_types && (arg_types[i] == 6 || arg_types[i] == 7)) { - const char *str_val = - reinterpret_cast(arg_values[i]); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr) + const char *str_val = reinterpret_cast(arg_values[i]); if (str_val) { event.arg_string_values[i] = str_val; } diff --git a/src/video_frame.cpp b/src/video_frame.cpp index 25505397..761ad622 100644 --- a/src/video_frame.cpp +++ b/src/video_frame.cpp @@ -336,14 +336,18 @@ VideoFrame VideoFrame::fromOwnedInfo(const proto::OwnedVideoBuffer &owned) { std::size_t offset = 0; for (const auto &comp : info.components()) { const auto sz = static_cast(comp.size()); - const auto *src_ptr = reinterpret_cast(comp.data_ptr()); // NOLINT(performance-no-int-to-ptr) + const auto *src_ptr = + // NOLINTNEXTLINE(performance-no-int-to-ptr) + reinterpret_cast(comp.data_ptr()); std::memcpy(buffer.data() + offset, src_ptr, sz); offset += sz; } } else { // Packed format: treat top-level data_ptr as a single contiguous buffer. - const auto *src_ptr = reinterpret_cast(info.data_ptr()); // NOLINT(performance-no-int-to-ptr) + const auto *src_ptr = + // NOLINTNEXTLINE(performance-no-int-to-ptr) + reinterpret_cast(info.data_ptr()); std::size_t total_size = 0; if (info.has_stride()) { diff --git a/src/video_utils.cpp b/src/video_utils.cpp index 4f510ade..1f7b3636 100644 --- a/src/video_utils.cpp +++ b/src/video_utils.cpp @@ -184,7 +184,8 @@ VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer &owned) { if (src_ptr == 0) { throw std::runtime_error("fromOwnedProto: info.data_ptr is null"); } - const auto *src = reinterpret_cast(src_ptr); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr) + const auto *src = reinterpret_cast(src_ptr); std::memcpy(dst, src, dst_size); From 1df6375962781a2c31fcf370ffabf51b8046502e Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 5 May 2026 14:04:36 -0600 Subject: [PATCH 3/6] Headers now scanned --- include/livekit/data_stream.h | 3 +- include/livekit/remote_track_publication.h | 2 +- include/livekit/result.h | 8 +- include/livekit/track.h | 3 +- scripts/clang-format.sh | 128 +++++++++++++++------ 5 files changed, 102 insertions(+), 42 deletions(-) diff --git a/include/livekit/data_stream.h b/include/livekit/data_stream.h index 2d5b3f0d..19bdfc4c 100644 --- a/include/livekit/data_stream.h +++ b/include/livekit/data_stream.h @@ -176,8 +176,7 @@ class BaseStreamWriter { const std::map &attributes = {}); protected: - BaseStreamWriter(LocalParticipant &local_participant, - std::string topic = "", + BaseStreamWriter(LocalParticipant &local_participant, std::string topic = "", std::map attributes = {}, std::string stream_id = "", std::optional total_size = std::nullopt, diff --git a/include/livekit/remote_track_publication.h b/include/livekit/remote_track_publication.h index 212eabd3..97360db3 100644 --- a/include/livekit/remote_track_publication.h +++ b/include/livekit/remote_track_publication.h @@ -29,7 +29,7 @@ class RemoteTrackPublication : public TrackPublication { /// Note, this RemoteTrackPublication is constructed internally only; /// safe to accept proto::OwnedTrackPublication. explicit RemoteTrackPublication(const proto::OwnedTrackPublication &owned); - + bool subscribed() const noexcept { return subscribed_; } void setSubscribed(bool subscribed); diff --git a/include/livekit/result.h b/include/livekit/result.h index dce0e874..acb3b957 100644 --- a/include/livekit/result.h +++ b/include/livekit/result.h @@ -64,10 +64,10 @@ template class [[nodiscard]] Result { /// Allows `if (result)` style success checks. explicit operator bool() const noexcept { return ok(); } - // TODO (AEG): clang-tidy flagged these accessors because the signatures are marked - // noexcept, but std::get can throw a std::bad_variant_access exception on - // std::variant specifically. Investigate if this is actually a concern or if the types - // are safe within this class (unit test ideal). + // TODO (AEG): clang-tidy flagged these accessors because the signatures are + // marked noexcept, but std::get can throw a std::bad_variant_access exception + // on std::variant specifically. Investigate if this is actually a concern or + // if the types are safe within this class (unit test ideal). /// Access the success value. Requires `ok() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) diff --git a/include/livekit/track.h b/include/livekit/track.h index 6d1e98c4..9e188a2d 100644 --- a/include/livekit/track.h +++ b/include/livekit/track.h @@ -85,7 +85,8 @@ class Track { std::optional simulcasted() const noexcept { return simulcasted_; } std::optional width() const noexcept { return width_; } std::optional height() const noexcept { return height_; } - // std::string can actually throw, suppressing for now to maintain API compatibility + // std::string can actually throw, suppressing for now to maintain API + // compatibility // NOLINTNEXTLINE(bugprone-exception-escape) std::optional mime_type() const noexcept { return mime_type_; } diff --git a/scripts/clang-format.sh b/scripts/clang-format.sh index 2643e352..b4e379dc 100755 --- a/scripts/clang-format.sh +++ b/scripts/clang-format.sh @@ -78,19 +78,21 @@ Options: Positional arguments: FILE... Explicit list of files to format / check. When omitted, the script - walks the tracked src/ tree (excluding src/tests/) and operates on - every C/C++ source and header it finds. Pass paths to make the - script work as a precommit hook on a curated set of files, e.g.: + walks the tracked first-party C/C++ trees (src/ excluding + src/tests/, include/, and benchmarks/) and operates on every + source / header it finds. Pass paths to make the script work as + a precommit hook on a curated set of files, e.g.: git diff --cached --name-only --diff-filter=ACMR \ | grep -E '\.(c|cc|cpp|cxx|h|hpp|hxx)$' \ | xargs ./scripts/clang-format.sh --fix Examples: - ./scripts/clang-format.sh # check full src/ tree - ./scripts/clang-format.sh --fix # fix the same tree - ./scripts/clang-format.sh src/room.cpp src/foo.h # check just these files - ./scripts/clang-format.sh --fix src/room.cpp # fix just this file - ./scripts/clang-format.sh --github-actions # force CI annotations + ./scripts/clang-format.sh # check src/, include/, benchmarks/ + ./scripts/clang-format.sh --fix # fix the same trees + ./scripts/clang-format.sh src/room.cpp include/livekit/room.h + # check just these files + ./scripts/clang-format.sh --fix src/room.cpp # fix just this file + ./scripts/clang-format.sh --github-actions # force CI annotations Pre-requisites: clang-format must be installed and on PATH: @@ -172,9 +174,16 @@ clang-format --version # Build the list of files to operate on. When the user passes explicit paths # we honor them verbatim (no globbing, no src/tests/ filtering) so a precommit # hook can supply its own staged-file list. Otherwise we walk the tracked -# src/ tree, excluding src/tests/. Using `git ls-files` automatically skips -# the client-sdk-rust/ submodule, build-*/, _deps/, local-install/, etc., -# without having to maintain a lookahead exclusion regex. +# first-party C/C++ trees: +# - src/ (implementation + internal headers, excluding src/tests/) +# - include/ (public API headers shipped in the installed SDK) +# - benchmarks/ (in-tree micro-benchmarks) +# Using `git ls-files` automatically skips the client-sdk-rust/ submodule, +# build-*/, _deps/, local-install/, vcpkg_installed/, etc., without having +# to maintain a lookahead exclusion regex. The deprecated bridge/ tree and +# the empty examples/ tree are intentionally left out -- bridge/ has its +# own conventions (it's frozen pending removal), and examples/ has no +# tracked C/C++ files today. files=() if (( ${#explicit_files[@]} > 0 )); then files=("${explicit_files[@]}") @@ -184,7 +193,10 @@ else files+=("${path}") done < <(git ls-files -z \ 'src/*.c' 'src/*.cc' 'src/*.cpp' 'src/*.cxx' \ - 'src/*.h' 'src/*.hpp' 'src/*.hxx') + 'src/*.h' 'src/*.hpp' 'src/*.hxx' \ + 'include/*.h' 'include/*.hpp' 'include/*.hxx' \ + 'benchmarks/*.c' 'benchmarks/*.cc' 'benchmarks/*.cpp' 'benchmarks/*.cxx' \ + 'benchmarks/*.h' 'benchmarks/*.hpp' 'benchmarks/*.hxx') fi file_count=${#files[@]} @@ -194,15 +206,6 @@ if (( file_count == 0 )); then exit 0 fi -# xargs parallelism: one worker per logical CPU. `nproc` is the Linux -# coreutils tool; macOS doesn't ship it, so fall back to `sysctl hw.ncpu`, -# and finally to a conservative 4 if neither is available. -if command -v nproc >/dev/null 2>&1; then - jobs=$(nproc) -else - jobs=$(sysctl -n hw.ncpu 2>/dev/null || echo 4) -fi - # Capture clang-format's combined stdout+stderr to a stable, repo-local path # so it can be re-parsed after the run (for annotations and the step summary) # and re-read by the user afterwards. `*.log` is gitignored so this file @@ -366,31 +369,78 @@ print_stdout_summary() { # --------- End GitHub Actions annotations --------- -# Run clang-format. In fix mode, batch files across worker invocations for -# throughput; in check mode, hand each worker exactly one file so per-file -# diagnostics don't interleave across processes (clang-format writes one -# small diagnostic per violation, which on POSIX is atomic for writes -# <= PIPE_BUF, but only when each writer holds the fd alone for the whole -# message -- using -n 1 keeps each process's output contiguous in the log). +# Run clang-format. We run serially (no -P parallelism) so per-file +# diagnostics never interleave -- clang-format itself is fast enough +# (~1-2 ms per file) that a few hundred files still complete in well +# under a second, and CI workflow startup dwarfs the runtime regardless. +# `xargs` (without -P) still chunks the file list so we don't blow past +# ARG_MAX when the tree grows: each invocation gets as many files as fit +# in one command line, and successive invocations append to the log in +# discovery order. +# +# In fix mode we snapshot file content hashes before and after invoking +# clang-format so the summary can report only the files that *actually +# changed* (vs. the entire scanned set). `git hash-object --stdin-paths` +# hashes every input path in a single git invocation, sidestepping the +# portability headache of sha1sum (Linux) vs shasum (macOS) vs cksum +# (POSIX, but only 32-bit) and getting us per-file SHA-1s in one shot. +__hash_files() { + if (( ${#files[@]} == 0 )); then + return + fi + printf '%s\n' "${files[@]}" | git hash-object --stdin-paths +} + +pre_hashes=() +if (( FIX_MODE == 1 )); then + while IFS= read -r __h; do + pre_hashes+=("${__h}") + done < <(__hash_files) +fi + set +e if (( FIX_MODE == 1 )); then printf '%s\0' "${files[@]}" \ - | xargs -0 -n 32 -P "${jobs}" clang-format -i \ + | xargs -0 clang-format -i \ >"${log}" 2>&1 rc=$? else printf '%s\0' "${files[@]}" \ - | xargs -0 -n 1 -P "${jobs}" clang-format --dry-run --Werror \ + | xargs -0 clang-format --dry-run --Werror \ >"${log}" 2>&1 rc=$? fi set -e -# Mirror the captured log to stdout so users see violations inline (the file -# is also kept on disk for re-parsing / re-reading after the run). -cat "${log}" +# Identify which files actually changed on disk during the fix pass by +# rehashing and comparing against the pre-run snapshot. Files where the +# hash matches were no-ops (already conformant) and are excluded from +# the summary count. Order is preserved (git hash-object emits hashes in +# input order) so the i-th post-hash corresponds to the i-th file. +changed_files=() +if (( FIX_MODE == 1 )); then + post_hashes=() + while IFS= read -r __h; do + post_hashes+=("${__h}") + done < <(__hash_files) + for i in "${!files[@]}"; do + if [[ "${pre_hashes[$i]:-}" != "${post_hashes[$i]:-}" ]]; then + changed_files+=("${files[$i]}") + fi + done +fi -if [[ "${CI_MODE}" == "1" ]]; then +# Mirror the captured log to stdout so users see violations inline. In fix +# mode there's nothing useful in the log (clang-format -i writes silently), +# so skip the cat to keep the output focused on the summary below. +if (( FIX_MODE == 0 )); then + cat "${log}" +fi + +# CI annotations / step summary only make sense for the check-mode log, +# which contains the violation diagnostics. Fix mode has already resolved +# them, so emitting annotations would be misleading. +if [[ "${CI_MODE}" == "1" ]] && (( FIX_MODE == 0 )); then emit_annotations "${log}" write_step_summary "${log}" fi @@ -402,7 +452,17 @@ echo "Results written to: $(pwd)/${log}" __FMT_VIOLATION_FILES=0 if (( FIX_MODE == 1 )); then echo "------------------------------------------------------------" - printf 'clang-format summary: applied formatting to %d file(s)\n' "${file_count}" + if (( ${#changed_files[@]} == 0 )); then + printf 'clang-format summary: clean (0 of %d file(s) needed formatting)\n' \ + "${file_count}" + else + printf 'clang-format summary: formatted %d of %d file(s)\n' \ + "${#changed_files[@]}" "${file_count}" + echo " files:" + for __cf in "${changed_files[@]}"; do + printf ' %s\n' "${__cf}" + done + fi echo "------------------------------------------------------------" else print_stdout_summary "${log}" "${file_count}" From 23808cdbbfaf240823daf3743be7703783559d36 Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 5 May 2026 15:27:06 -0600 Subject: [PATCH 4/6] Doc changes --- AGENTS.md | 4 +++- README.md | 28 ++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 03aeb199..f697ec47 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -166,8 +166,10 @@ All source files must have the LiveKit Apache 2.0 copyright header. Use the curr ### Readability and Performance Code should be easy to read and understand. If a sacrifice is made for performance or readability, it should be documented. +Adhere to clang-format checks configured in `.clang-format`. Run `./scripts/clang-format.sh` if needed to confirm code styling. + ### Static Analysis -Adhere to clang-tidy checks configured in `.clang-tidy`. +Adhere to clang-tidy checks configured in `.clang-tidy`. Run `./scripts/clang-tidy.sh` if needed to confirm code quality. ## Dependencies diff --git a/README.md b/README.md index 773767d6..ff659ea8 100644 --- a/README.md +++ b/README.md @@ -500,7 +500,7 @@ This SDK leverages various tools and checks to ensure the highest quality of the ### Clang Tools - `clang-tidy`: static analysis checks to catch common C++ pitfalls. See [.clang-tidy](./.clang-tidy) for the list of current checks (enforced in CI on PR) -- `clang-format`: (coming soon) code formatting and style consistency +- `clang-format`: code formatting and style consistency. See [.clang-format](./.clang-format) for the list of style configurations (enforced in CI on PR) > **Note**: clang-tidy is not currently supported on Windows for this project because the Visual Studio CMake generator does not produce the compile_commands.json database that clang-tidy requires. @@ -521,7 +521,13 @@ This installs `clang-format`, `clang-tidy`, and `run-clang-tidy`. Homebrew may a sudo apt-get install clang-format clang-tidy clang-tools ``` -To run: +**Pre-commit hook** + +```bash +printf '#!/bin/sh\nFILES=$(git diff --cached --name-only --diff-filter=ACMR -- "*.c" "*.cc" "*.cpp" "*.cxx" "*.h" "*.hpp" "*.hxx")\n[ -z "$FILES" ] && exit 0\necho "$FILES" | xargs ./scripts/clang-format.sh --fix\necho "$FILES" | xargs git add\n' > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit +``` + +To run `clang-tidy`: 1. Generate `compile_commands.json` and the protobuf headers via a release build: @@ -545,6 +551,24 @@ The wrapper forwards extra arguments to `run-clang-tidy`, examples below: Output is captured to `clang-tidy.log` at the repo root. This is done as a convenience feature, as often times the terminal buffer is not large enough for all the output. +To run `clang-format`: + +```bash +./scripts/clang-format.sh +``` + +With no arguments, runs `clang-format` against every relevant file in the repository against defined `.clang-format` rules. + +Pass flags or paths as needed, examples below: + +```bash +./scripts/clang-format.sh --fix # Rewrite files in place +./scripts/clang-format.sh src/room.cpp include/livekit/room.h # Check just these files +./scripts/clang-format.sh --fix src/room.cpp # Fix just this file +``` + +Output is captured to `clang-format.log` at the repo root. + ### Memory Checks Run valgrind on various examples or tests to check for memory leaks and other issues. From ac614f28726c7e0027b2d13acee9d80ad7229935 Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 5 May 2026 17:00:26 -0600 Subject: [PATCH 5/6] Try google style --- .clang-format | 10 +- benchmarks/data_track_throughput/common.h | 134 +- benchmarks/data_track_throughput/consumer.cpp | 209 +- benchmarks/data_track_throughput/producer.cpp | 194 +- include/livekit/audio_frame.h | 12 +- include/livekit/audio_processing_module.h | 18 +- include/livekit/audio_source.h | 14 +- include/livekit/audio_stream.h | 28 +- include/livekit/data_stream.h | 90 +- include/livekit/data_track_error.h | 9 +- include/livekit/data_track_frame.h | 14 +- include/livekit/data_track_stream.h | 20 +- include/livekit/e2ee.h | 53 +- include/livekit/ffi_handle.h | 8 +- include/livekit/livekit.h | 3 +- include/livekit/local_audio_track.h | 19 +- include/livekit/local_data_track.h | 27 +- include/livekit/local_participant.h | 97 +- include/livekit/local_track_publication.h | 2 +- include/livekit/local_video_track.h | 20 +- include/livekit/logging.h | 4 +- include/livekit/participant.h | 53 +- include/livekit/remote_audio_track.h | 5 +- include/livekit/remote_data_track.h | 22 +- include/livekit/remote_participant.h | 28 +- include/livekit/remote_track_publication.h | 2 +- include/livekit/remote_video_track.h | 5 +- include/livekit/result.h | 51 +- include/livekit/room.h | 88 +- include/livekit/room_delegate.h | 102 +- include/livekit/room_event_types.h | 41 +- include/livekit/rpc_error.h | 10 +- include/livekit/stats.h | 68 +- .../livekit/subscription_thread_dispatcher.h | 133 +- include/livekit/tracing.h | 3 +- include/livekit/track.h | 24 +- include/livekit/track_publication.h | 31 +- include/livekit/video_frame.h | 31 +- include/livekit/video_source.h | 13 +- include/livekit/video_stream.h | 28 +- scripts/clang-format.sh | 14 +- scripts/clang-tidy.sh | 17 +- src/audio_frame.cpp | 62 +- src/audio_processing_module.cpp | 55 +- src/audio_source.cpp | 18 +- src/audio_stream.cpp | 53 +- src/data_stream.cpp | 175 +- src/data_track_error.cpp | 112 +- src/data_track_frame.cpp | 11 +- src/data_track_stream.cpp | 25 +- src/e2ee.cpp | 81 +- src/ffi_client.cpp | 622 +++-- src/ffi_client.h | 145 +- src/ffi_handle.cpp | 5 +- src/livekit.cpp | 7 +- src/lk_log.h | 21 +- src/local_audio_track.cpp | 28 +- src/local_data_track.cpp | 41 +- src/local_participant.cpp | 221 +- src/local_track_publication.cpp | 16 +- src/local_video_track.cpp | 28 +- src/logging.cpp | 85 +- src/remote_audio_track.cpp | 9 +- src/remote_data_track.cpp | 36 +- src/remote_participant.cpp | 20 +- src/remote_track_publication.cpp | 21 +- src/remote_video_track.cpp | 9 +- src/room.cpp | 2003 ++++++++--------- src/room_event_converter.cpp | 252 +-- src/room_proto_converter.cpp | 230 +- src/room_proto_converter.h | 75 +- src/rpc_error.cpp | 62 +- src/stats.cpp | 485 ++-- src/subscription_thread_dispatcher.cpp | 377 ++-- src/trace/event_tracer.cpp | 166 +- src/trace/event_tracer.h | 27 +- src/trace/event_tracer_internal.h | 3 +- src/trace/trace_event.h | 604 ++--- src/trace/tracing.cpp | 4 +- src/track.cpp | 24 +- src/track_proto_converter.cpp | 127 +- src/track_proto_converter.h | 8 +- src/track_publication.cpp | 23 +- src/video_frame.cpp | 426 ++-- src/video_source.cpp | 15 +- src/video_stream.cpp | 53 +- src/video_utils.cpp | 150 +- src/video_utils.h | 13 +- 88 files changed, 3931 insertions(+), 4856 deletions(-) diff --git a/.clang-format b/.clang-format index f6b8fdf2..7707fc51 100644 --- a/.clang-format +++ b/.clang-format @@ -1,2 +1,10 @@ --- -BasedOnStyle: LLVM +BasedOnStyle: Google +Language: Cpp +Standard: c++17 + +# LiveKit modifications to Google style below + +ColumnLimit: 120 # more width on modern screens +SpacesBeforeTrailingComments: 1 # one space for trailing namespace comments, e.g. `} // namespace foo` (Google uses 2) +AccessModifierOffset: -2 # left-align public/protected/private with the class keyword (Google indents by 1) diff --git a/benchmarks/data_track_throughput/common.h b/benchmarks/data_track_throughput/common.h index e0f43e2d..0c775b5b 100644 --- a/benchmarks/data_track_throughput/common.h +++ b/benchmarks/data_track_throughput/common.h @@ -35,9 +35,9 @@ namespace data_track_throughput { using json = nlohmann::json; -constexpr const char *kDefaultTrackName = "data-track-throughput"; -constexpr const char *kPrepareRpcMethod = "throughput.prepare"; -constexpr const char *kFinishRpcMethod = "throughput.finish"; +constexpr const char* kDefaultTrackName = "data-track-throughput"; +constexpr const char* kPrepareRpcMethod = "throughput.prepare"; +constexpr const char* kFinishRpcMethod = "throughput.finish"; constexpr std::size_t kMinimumPayloadBytes = 1024; constexpr std::size_t kMaximumPayloadBytes = 256ull * 1024ull * 1024ull; constexpr double kMinimumRateHz = 1.0; @@ -47,38 +47,31 @@ constexpr std::uint32_t kFrameMagic = 0x31545444u; // "DTT1" constexpr std::uint32_t kFrameVersion = 1; constexpr std::size_t kFrameHeaderBytes = 56; -inline std::string getenvOrEmpty(const char *name) { - const char *value = std::getenv(name); +inline std::string getenvOrEmpty(const char* name) { + const char* value = std::getenv(name); return value == nullptr ? std::string{} : std::string(value); } inline std::uint64_t nowSystemUs() { using namespace std::chrono; - return static_cast( - duration_cast(system_clock::now().time_since_epoch()) - .count()); + return static_cast(duration_cast(system_clock::now().time_since_epoch()).count()); } inline std::string toLower(std::string value) { - std::transform( - value.begin(), value.end(), value.begin(), - [](unsigned char c) { return static_cast(std::tolower(c)); }); + std::transform(value.begin(), value.end(), value.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); return value; } inline std::string trim(std::string value) { auto is_space = [](unsigned char c) { return std::isspace(c) != 0; }; - value.erase(value.begin(), - std::find_if(value.begin(), value.end(), - [&](unsigned char c) { return !is_space(c); })); - value.erase(std::find_if(value.rbegin(), value.rend(), - [&](unsigned char c) { return !is_space(c); }) - .base(), + value.erase(value.begin(), std::find_if(value.begin(), value.end(), [&](unsigned char c) { return !is_space(c); })); + value.erase(std::find_if(value.rbegin(), value.rend(), [&](unsigned char c) { return !is_space(c); }).base(), value.end()); return value; } -inline std::size_t parseByteSize(const std::string &text) { +inline std::size_t parseByteSize(const std::string& text) { const std::string lowered = toLower(trim(text)); if (lowered.empty()) { throw std::runtime_error("Empty byte size"); @@ -86,8 +79,7 @@ inline std::size_t parseByteSize(const std::string &text) { std::size_t split = 0; while (split < lowered.size() && - (std::isdigit(static_cast(lowered[split])) != 0 || - lowered[split] == '.')) { + (std::isdigit(static_cast(lowered[split])) != 0 || lowered[split] == '.')) { ++split; } @@ -111,7 +103,7 @@ inline std::size_t parseByteSize(const std::string &text) { } inline std::string humanBytes(std::size_t bytes) { - static constexpr const char *kUnits[] = {"B", "KiB", "MiB", "GiB"}; + static constexpr const char* kUnits[] = {"B", "KiB", "MiB", "GiB"}; double value = static_cast(bytes); std::size_t unit_index = 0; while (value >= 1024.0 && unit_index + 1 < std::size(kUnits)) { @@ -120,12 +112,11 @@ inline std::string humanBytes(std::size_t bytes) { } std::ostringstream oss; - oss << std::fixed << std::setprecision(unit_index == 0 ? 0 : 2) << value - << kUnits[unit_index]; + oss << std::fixed << std::setprecision(unit_index == 0 ? 0 : 2) << value << kUnits[unit_index]; return oss.str(); } -inline std::string csvEscape(const std::string &value) { +inline std::string csvEscape(const std::string& value) { if (value.find_first_of(",\"\n") == std::string::npos) { return value; } @@ -142,8 +133,7 @@ inline std::string csvEscape(const std::string &value) { return escaped; } -inline void ensureCsvHeader(const std::filesystem::path &path, - const std::string &header) { +inline void ensureCsvHeader(const std::filesystem::path& path, const std::string& header) { if (std::filesystem::exists(path)) { return; } @@ -186,24 +176,19 @@ struct FrameHeader { std::uint64_t send_time_us = 0; }; -inline void writeLe32(std::vector &buffer, std::size_t offset, - std::uint32_t value) { +inline void writeLe32(std::vector& buffer, std::size_t offset, std::uint32_t value) { for (int idx = 0; idx < 4; ++idx) { - buffer[offset + idx] = - static_cast((value >> (idx * 8)) & 0xFF); + buffer[offset + idx] = static_cast((value >> (idx * 8)) & 0xFF); } } -inline void writeLe64(std::vector &buffer, std::size_t offset, - std::uint64_t value) { +inline void writeLe64(std::vector& buffer, std::size_t offset, std::uint64_t value) { for (int idx = 0; idx < 8; ++idx) { - buffer[offset + idx] = - static_cast((value >> (idx * 8)) & 0xFF); + buffer[offset + idx] = static_cast((value >> (idx * 8)) & 0xFF); } } -inline std::uint32_t readLe32(const std::vector &buffer, - std::size_t offset) { +inline std::uint32_t readLe32(const std::vector& buffer, std::size_t offset) { std::uint32_t value = 0; for (int idx = 0; idx < 4; ++idx) { value |= static_cast(buffer[offset + idx]) << (idx * 8); @@ -211,8 +196,7 @@ inline std::uint32_t readLe32(const std::vector &buffer, return value; } -inline std::uint64_t readLe64(const std::vector &buffer, - std::size_t offset) { +inline std::uint64_t readLe64(const std::vector& buffer, std::size_t offset) { std::uint64_t value = 0; for (int idx = 0; idx < 8; ++idx) { value |= static_cast(buffer[offset + idx]) << (idx * 8); @@ -220,15 +204,13 @@ inline std::uint64_t readLe64(const std::vector &buffer, return value; } -inline std::vector makePayload(const ScenarioRequest &request, - std::uint64_t sequence, +inline std::vector makePayload(const ScenarioRequest& request, std::uint64_t sequence, std::uint64_t send_time_us) { if (request.packet_size_bytes < kFrameHeaderBytes) { throw std::runtime_error("Payload too small for frame header"); } - std::vector payload(request.packet_size_bytes, - static_cast(sequence & 0xFF)); + std::vector payload(request.packet_size_bytes, static_cast(sequence & 0xFF)); writeLe32(payload, 0, kFrameMagic); writeLe32(payload, 4, kFrameVersion); writeLe64(payload, 8, request.run_id); @@ -240,13 +222,11 @@ inline std::vector makePayload(const ScenarioRequest &request, return payload; } -inline std::optional -parseHeader(const std::vector &payload) { +inline std::optional parseHeader(const std::vector& payload) { if (payload.size() < kFrameHeaderBytes) { return std::nullopt; } - if (readLe32(payload, 0) != kFrameMagic || - readLe32(payload, 4) != kFrameVersion) { + if (readLe32(payload, 0) != kFrameMagic || readLe32(payload, 4) != kFrameVersion) { return std::nullopt; } @@ -260,8 +240,7 @@ parseHeader(const std::vector &payload) { return header; } -inline std::string defaultScenarioName(std::size_t packet_size_bytes, - double rate_hz) { +inline std::string defaultScenarioName(std::size_t packet_size_bytes, double rate_hz) { std::ostringstream oss; oss << humanBytes(packet_size_bytes); oss << "_" << std::fixed << std::setprecision(0) << rate_hz << "Hz"; @@ -275,11 +254,9 @@ inline std::vector defaultPayloadSizesBytes() { 128ull * 1024ull, 256ull * 1024ull, 512ull * 1024ull}; } -inline std::vector defaultRatesHz() { - return {1.0, 5.0, 10.0, 25.0, 50.0, 100.0, 200.0, 500.0, 1000.0}; -} +inline std::vector defaultRatesHz() { return {1.0, 5.0, 10.0, 25.0, 50.0, 100.0, 200.0, 500.0, 1000.0}; } -inline json toJson(const ScenarioRequest &request) { +inline json toJson(const ScenarioRequest& request) { return json{ {"run_id", request.run_id}, {"scenario_name", request.scenario_name}, @@ -291,7 +268,7 @@ inline json toJson(const ScenarioRequest &request) { }; } -inline ScenarioRequest scenarioRequestFromJson(const json &value) { +inline ScenarioRequest scenarioRequestFromJson(const json& value) { ScenarioRequest request; request.run_id = value.at("run_id").get(); request.scenario_name = value.at("scenario_name").get(); @@ -303,7 +280,7 @@ inline ScenarioRequest scenarioRequestFromJson(const json &value) { return request; } -inline json toJson(const ProducerStats &stats) { +inline json toJson(const ProducerStats& stats) { return json{ {"run_id", stats.run_id}, {"scenario_name", stats.scenario_name}, @@ -317,53 +294,43 @@ inline json toJson(const ProducerStats &stats) { }; } -inline ProducerStats producerStatsFromJson(const json &value) { +inline ProducerStats producerStatsFromJson(const json& value) { ProducerStats stats; stats.run_id = value.at("run_id").get(); stats.scenario_name = value.at("scenario_name").get(); stats.attempted_count = value.at("attempted_count").get(); - stats.enqueue_success_count = - value.at("enqueue_success_count").get(); - stats.enqueue_failure_count = - value.at("enqueue_failure_count").get(); + stats.enqueue_success_count = value.at("enqueue_success_count").get(); + stats.enqueue_failure_count = value.at("enqueue_failure_count").get(); stats.attempted_bytes = value.at("attempted_bytes").get(); stats.enqueued_bytes = value.at("enqueued_bytes").get(); - stats.first_send_time_us = - value.at("first_send_time_us").get(); + stats.first_send_time_us = value.at("first_send_time_us").get(); stats.last_send_time_us = value.at("last_send_time_us").get(); return stats; } -inline bool exceedsDataRateBudget(const ScenarioRequest &request) { - return static_cast(request.packet_size_bytes) * - request.desired_rate_hz > - kMaximumDataRateBytesPerSec; +inline bool exceedsDataRateBudget(const ScenarioRequest& request) { + return static_cast(request.packet_size_bytes) * request.desired_rate_hz > kMaximumDataRateBytesPerSec; } -inline void validateScenario(const ScenarioRequest &request) { +inline void validateScenario(const ScenarioRequest& request) { if (request.message_count == 0) { throw std::runtime_error("message_count must be greater than zero"); } - if (request.desired_rate_hz < kMinimumRateHz || - request.desired_rate_hz > kMaximumRateHz) { + if (request.desired_rate_hz < kMinimumRateHz || request.desired_rate_hz > kMaximumRateHz) { throw std::runtime_error("desired_rate_hz must be between 1 and 50000"); } - if (request.packet_size_bytes < kMinimumPayloadBytes || - request.packet_size_bytes > kMaximumPayloadBytes) { - throw std::runtime_error( - "packet_size_bytes must be between 1 KiB and 256 MiB"); + if (request.packet_size_bytes < kMinimumPayloadBytes || request.packet_size_bytes > kMaximumPayloadBytes) { + throw std::runtime_error("packet_size_bytes must be between 1 KiB and 256 MiB"); } if (exceedsDataRateBudget(request)) { throw std::runtime_error("scenario exceeds data-rate budget of 10 Gbps"); } } -inline std::vector -makeScenarioPlan(const std::string &producer_identity, - const std::string &track_name, - std::size_t messages_per_scenario, - const std::vector &payload_sizes, - const std::vector &rates) { +inline std::vector makeScenarioPlan(const std::string& producer_identity, + const std::string& track_name, std::size_t messages_per_scenario, + const std::vector& payload_sizes, + const std::vector& rates) { std::vector scenarios; std::uint64_t run_id = 1; @@ -387,12 +354,11 @@ makeScenarioPlan(const std::string &producer_identity, return scenarios; } -inline std::vector -makeDefaultScenarioPlan(const std::string &producer_identity, - const std::string &track_name, - std::size_t messages_per_scenario) { - return makeScenarioPlan(producer_identity, track_name, messages_per_scenario, - defaultPayloadSizesBytes(), defaultRatesHz()); +inline std::vector makeDefaultScenarioPlan(const std::string& producer_identity, + const std::string& track_name, + std::size_t messages_per_scenario) { + return makeScenarioPlan(producer_identity, track_name, messages_per_scenario, defaultPayloadSizesBytes(), + defaultRatesHz()); } } // namespace data_track_throughput diff --git a/benchmarks/data_track_throughput/consumer.cpp b/benchmarks/data_track_throughput/consumer.cpp index 01fced70..a4a7683f 100644 --- a/benchmarks/data_track_throughput/consumer.cpp +++ b/benchmarks/data_track_throughput/consumer.cpp @@ -12,10 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "common.h" - -#include "livekit/livekit.h" - #include #include #include @@ -34,6 +30,9 @@ #include #include +#include "common.h" +#include "livekit/livekit.h" + using namespace livekit; using namespace data_track_throughput; using namespace std::chrono_literals; @@ -72,7 +71,7 @@ struct RunState { void handleSignal(int) { g_running.store(false); } -void printUsage(const char *prog) { +void printUsage(const char* prog) { std::cout << "Usage:\n" << " " << prog << " \n" << " " << prog << " --url --token \n\n" @@ -80,8 +79,7 @@ void printUsage(const char *prog) { << " --output CSV output directory. Default: " "data_track_throughput_results\n" << " --output-dir Alias for --output\n" - << " --track-name Data track name. Default: " - << kDefaultTrackName << "\n" + << " --track-name Data track name. Default: " << kDefaultTrackName << "\n" << " --quiet-period-ms No-new-message window before " "finalizing. Default: 2000\n" << " --max-finish-wait-ms Hard cap for run finalization. " @@ -90,8 +88,8 @@ void printUsage(const char *prog) { << " LIVEKIT_URL, LIVEKIT_TOKEN" << std::endl; } -bool parseArgs(int argc, char *argv[], ConsumerOptions &options) { - auto readFlagValue = [&](const std::string &flag, int &index) -> std::string { +bool parseArgs(int argc, char* argv[], ConsumerOptions& options) { + auto readFlagValue = [&](const std::string& flag, int& index) -> std::string { const std::string arg = argv[index]; const std::string prefix = flag + "="; if (arg == flag && index + 1 < argc) { @@ -102,10 +100,9 @@ bool parseArgs(int argc, char *argv[], ConsumerOptions &options) { } return {}; }; - auto matchingOutputFlag = [](const std::string &arg) -> const char * { - static constexpr const char *kOutputFlags[] = {"--output-dir", "--output", - "--ouput"}; - for (const char *flag : kOutputFlags) { + auto matchingOutputFlag = [](const std::string& arg) -> const char* { + static constexpr const char* kOutputFlags[] = {"--output-dir", "--output", "--ouput"}; + for (const char* flag : kOutputFlags) { if (arg.rfind(flag, 0) == 0) { return flag; } @@ -123,17 +120,14 @@ bool parseArgs(int argc, char *argv[], ConsumerOptions &options) { options.url = readFlagValue("--url", index); } else if (arg.rfind("--token", 0) == 0) { options.token = readFlagValue("--token", index); - } else if (const char *output_flag = matchingOutputFlag(arg); - output_flag != nullptr) { + } else if (const char* output_flag = matchingOutputFlag(arg); output_flag != nullptr) { options.output_dir = readFlagValue(output_flag, index); } else if (arg.rfind("--track-name", 0) == 0) { options.track_name = readFlagValue("--track-name", index); } else if (arg.rfind("--quiet-period-ms", 0) == 0) { - options.quiet_period = std::chrono::milliseconds( - std::stoll(readFlagValue("--quiet-period-ms", index))); + options.quiet_period = std::chrono::milliseconds(std::stoll(readFlagValue("--quiet-period-ms", index))); } else if (arg.rfind("--max-finish-wait-ms", 0) == 0) { - options.max_finish_wait = std::chrono::milliseconds( - std::stoll(readFlagValue("--max-finish-wait-ms", index))); + options.max_finish_wait = std::chrono::milliseconds(std::stoll(readFlagValue("--max-finish-wait-ms", index))); } } @@ -168,41 +162,38 @@ bool parseArgs(int argc, char *argv[], ConsumerOptions &options) { class ThroughputConsumer { public: - explicit ThroughputConsumer(const ConsumerOptions &options) + explicit ThroughputConsumer(const ConsumerOptions& options) : options_(options), summary_csv_path_(options.output_dir / "throughput_summary.csv"), message_csv_path_(options.output_dir / "throughput_messages.csv") { std::filesystem::create_directories(options_.output_dir); - ensureCsvHeader( - summary_csv_path_, - "run_id,scenario_name,desired_rate_hz,packet_size_bytes," - "messages_requested,messages_attempted,messages_enqueued," - "messages_enqueue_failed,messages_received,messages_missed," - "duplicate_messages,attempted_bytes,enqueued_bytes,received_bytes," - "first_send_time_us,last_send_time_us," - "first_arrival_time_us,last_arrival_time_us"); + ensureCsvHeader(summary_csv_path_, + "run_id,scenario_name,desired_rate_hz,packet_size_bytes," + "messages_requested,messages_attempted,messages_enqueued," + "messages_enqueue_failed,messages_received,messages_missed," + "duplicate_messages,attempted_bytes,enqueued_bytes,received_bytes," + "first_send_time_us,last_send_time_us," + "first_arrival_time_us,last_arrival_time_us"); ensureCsvHeader(message_csv_path_, "run_id,sequence,payload_bytes,send_time_us," "arrival_time_us,is_duplicate"); } ~ThroughputConsumer() { - if (room_ != nullptr && - callback_id_ != std::numeric_limits::max()) { + if (room_ != nullptr && callback_id_ != std::numeric_limits::max()) { room_->removeOnDataFrameCallback(callback_id_); } } - void setRoom(Room &room) { room_ = &room; } + void setRoom(Room& room) { room_ = &room; } - void ensureDataCallbackRegistered(const ScenarioRequest &request) { + void ensureDataCallbackRegistered(const ScenarioRequest& request) { if (room_ == nullptr) { throw std::runtime_error("Room not attached to throughput consumer"); } if (callback_id_ != std::numeric_limits::max() && - callback_producer_identity_ == request.producer_identity && - callback_track_name_ == request.track_name) { + callback_producer_identity_ == request.producer_identity && callback_track_name_ == request.track_name) { return; } @@ -213,8 +204,7 @@ class ThroughputConsumer { callback_id_ = room_->addOnDataFrameCallback( request.producer_identity, request.track_name, - [this](const std::vector &payload, - std::optional user_timestamp) { + [this](const std::vector& payload, std::optional user_timestamp) { this->onDataFrame(payload, user_timestamp); }); if (callback_id_ == std::numeric_limits::max()) { @@ -224,14 +214,12 @@ class ThroughputConsumer { callback_producer_identity_ = request.producer_identity; callback_track_name_ = request.track_name; - std::cout << "Listening for throughput data track '" << request.track_name - << "' from " << request.producer_identity << std::endl; + std::cout << "Listening for throughput data track '" << request.track_name << "' from " << request.producer_identity + << std::endl; } - std::optional - handlePrepareRpc(const RpcInvocationData &invocation) { - const ScenarioRequest request = - scenarioRequestFromJson(json::parse(invocation.payload)); + std::optional handlePrepareRpc(const RpcInvocationData& invocation) { + const ScenarioRequest request = scenarioRequestFromJson(json::parse(invocation.payload)); validateScenario(request); ensureDataCallbackRegistered(request); @@ -240,19 +228,13 @@ class ThroughputConsumer { state.request = request; runs_[request.run_id] = std::move(state); - std::cout << "Prepared " << request.scenario_name - << " rate=" << request.desired_rate_hz << "Hz" - << " packet_size=" << request.packet_size_bytes - << " messages=" << request.message_count << std::endl; + std::cout << "Prepared " << request.scenario_name << " rate=" << request.desired_rate_hz << "Hz" + << " packet_size=" << request.packet_size_bytes << " messages=" << request.message_count << std::endl; - return json{{"ready", true}, - {"scenario_name", request.scenario_name}, - {"track_name", options_.track_name}} - .dump(); + return json{{"ready", true}, {"scenario_name", request.scenario_name}, {"track_name", options_.track_name}}.dump(); } - std::optional - handleFinishRpc(const RpcInvocationData &invocation) { + std::optional handleFinishRpc(const RpcInvocationData& invocation) { const auto payload = json::parse(invocation.payload); const ProducerStats stats = producerStatsFromJson(payload.at("stats")); @@ -260,10 +242,7 @@ class ThroughputConsumer { std::lock_guard lock(mutex_); auto it = runs_.find(stats.run_id); if (it == runs_.end()) { - return json{{"ready", false}, - {"message", "Unknown run_id in finish RPC"}, - {"run_id", stats.run_id}} - .dump(); + return json{{"ready", false}, {"message", "Unknown run_id in finish RPC"}, {"run_id", stats.run_id}}.dump(); } it->second.producer_stats = stats; @@ -275,8 +254,7 @@ class ThroughputConsumer { } private: - void onDataFrame(const std::vector &payload, - std::optional user_timestamp) { + void onDataFrame(const std::vector& payload, std::optional user_timestamp) { const std::uint64_t arrival_time_us = nowSystemUs(); const auto header = parseHeader(payload); if (!header) { @@ -287,12 +265,11 @@ class ThroughputConsumer { std::lock_guard lock(mutex_); auto run_it = runs_.find(header->run_id); if (run_it == runs_.end()) { - std::cerr << "Ignored frame for unknown run_id=" << header->run_id - << std::endl; + std::cerr << "Ignored frame for unknown run_id=" << header->run_id << std::endl; return; } - RunState &run = run_it->second; + RunState& run = run_it->second; const bool duplicate = !run.seen_sequences.insert(header->sequence).second; if (duplicate) { @@ -300,24 +277,18 @@ class ThroughputConsumer { } if (payload.size() != run.request.packet_size_bytes) { - std::cerr << "WARN: payload size mismatch run_id=" << header->run_id - << " seq=" << header->sequence - << " expected=" << run.request.packet_size_bytes - << " got=" << payload.size() << std::endl; + std::cerr << "WARN: payload size mismatch run_id=" << header->run_id << " seq=" << header->sequence + << " expected=" << run.request.packet_size_bytes << " got=" << payload.size() << std::endl; } - if (header->payload_size_bytes != payload.size() || - header->message_count != run.request.message_count || + if (header->payload_size_bytes != payload.size() || header->message_count != run.request.message_count || header->packet_size_bytes != run.request.packet_size_bytes) { - std::cerr << "WARN: header field mismatch run_id=" << header->run_id - << " seq=" << header->sequence << std::endl; + std::cerr << "WARN: header field mismatch run_id=" << header->run_id << " seq=" << header->sequence << std::endl; } if (user_timestamp.has_value() && *user_timestamp != header->send_time_us) { - std::cerr << "WARN: timestamp mismatch run_id=" << header->run_id - << " seq=" << header->sequence << std::endl; + std::cerr << "WARN: timestamp mismatch run_id=" << header->run_id << " seq=" << header->sequence << std::endl; } if (header->sequence >= run.request.message_count) { - std::cerr << "WARN: unexpected sequence run_id=" << header->run_id - << " seq=" << header->sequence + std::cerr << "WARN: unexpected sequence run_id=" << header->run_id << " seq=" << header->sequence << " max=" << run.request.message_count << std::endl; } @@ -345,27 +316,21 @@ class ThroughputConsumer { throw std::runtime_error("Run missing during finalization"); } - const auto deadline = - std::chrono::steady_clock::now() + options_.max_finish_wait; + const auto deadline = std::chrono::steady_clock::now() + options_.max_finish_wait; while (g_running.load()) { auto now = std::chrono::steady_clock::now(); - if (it->second.seen_sequences.size() >= - it->second.request.message_count) { + if (it->second.seen_sequences.size() >= it->second.request.message_count) { break; } if (now >= deadline) { break; } if (it->second.producer_finished) { - const std::uint64_t reference_time_us = - it->second.last_arrival_us != 0 - ? it->second.last_arrival_us - : it->second.producer_stats.last_send_time_us; + const std::uint64_t reference_time_us = it->second.last_arrival_us != 0 + ? it->second.last_arrival_us + : it->second.producer_stats.last_send_time_us; if (reference_time_us != 0 && - nowSystemUs() > - reference_time_us + static_cast( - options_.quiet_period.count()) * - 1000ull) { + nowSystemUs() > reference_time_us + static_cast(options_.quiet_period.count()) * 1000ull) { break; } } @@ -385,16 +350,15 @@ class ThroughputConsumer { appendMessageRows(completed); appendSummaryRow(summary); - std::cout << "Wrote scenario " << completed.request.scenario_name << " to " - << summary_csv_path_.string() << " and " + std::cout << "Wrote scenario " << completed.request.scenario_name << " to " << summary_csv_path_.string() << " and " << message_csv_path_.string() << std::endl; return summary.dump(); } - json buildSummaryJson(const RunState &run) const { + json buildSummaryJson(const RunState& run) const { std::size_t unique_count = 0; std::uint64_t received_bytes = 0; - for (const auto &obs : run.observations) { + for (const auto& obs : run.observations) { if (!obs.duplicate) { ++unique_count; received_bytes += obs.payload_bytes; @@ -402,9 +366,7 @@ class ThroughputConsumer { } const std::size_t messages_missed = - run.request.message_count > unique_count - ? run.request.message_count - unique_count - : 0; + run.request.message_count > unique_count ? run.request.message_count - unique_count : 0; json summary; summary["run_id"] = run.request.run_id; @@ -414,8 +376,7 @@ class ThroughputConsumer { summary["messages_requested"] = run.request.message_count; summary["messages_attempted"] = run.producer_stats.attempted_count; summary["messages_enqueued"] = run.producer_stats.enqueue_success_count; - summary["messages_enqueue_failed"] = - run.producer_stats.enqueue_failure_count; + summary["messages_enqueue_failed"] = run.producer_stats.enqueue_failure_count; summary["messages_received"] = unique_count; summary["messages_missed"] = messages_missed; summary["duplicate_messages"] = run.duplicate_count; @@ -429,37 +390,34 @@ class ThroughputConsumer { return summary; } - void appendSummaryRow(const json &summary) const { + void appendSummaryRow(const json& summary) const { std::ofstream out; out.open(summary_csv_path_, std::ios::app); if (!out) { throw std::runtime_error("Failed to open summary CSV for append"); } - out << summary.at("run_id").get() << ',' - << csvEscape(summary.at("scenario_name").get()) << ',' - << summary.at("desired_rate_hz").get() << ',' + out << summary.at("run_id").get() << ',' << csvEscape(summary.at("scenario_name").get()) + << ',' << summary.at("desired_rate_hz").get() << ',' << summary.at("packet_size_bytes").get() << ',' << summary.at("messages_requested").get() << ',' << summary.at("messages_attempted").get() << ',' << summary.at("messages_enqueued").get() << ',' << summary.at("messages_enqueue_failed").get() << ',' - << summary.at("messages_received").get() << ',' - << summary.at("messages_missed").get() << ',' - << summary.at("duplicate_messages").get() << ',' + << summary.at("messages_received").get() << ',' << summary.at("messages_missed").get() + << ',' << summary.at("duplicate_messages").get() << ',' << summary.at("attempted_bytes").get() << ',' - << summary.at("enqueued_bytes").get() << ',' - << summary.at("received_bytes").get() << ',' - << summary.at("first_send_time_us").get() << ',' + << summary.at("enqueued_bytes").get() << ',' << summary.at("received_bytes").get() + << ',' << summary.at("first_send_time_us").get() << ',' << summary.at("last_send_time_us").get() << ',' << summary.at("first_arrival_time_us").get() << ',' << summary.at("last_arrival_time_us").get() << '\n'; } - void appendMessageRows(const RunState &run) const { + void appendMessageRows(const RunState& run) const { std::vector observations = run.observations; std::sort(observations.begin(), observations.end(), - [](const MessageObservation &lhs, const MessageObservation &rhs) { + [](const MessageObservation& lhs, const MessageObservation& rhs) { return lhs.arrival_time_us < rhs.arrival_time_us; }); @@ -469,11 +427,9 @@ class ThroughputConsumer { throw std::runtime_error("Failed to open message CSV for append"); } - for (const auto &message : observations) { - out << run.request.run_id << ',' << message.sequence << ',' - << message.payload_bytes << ',' << message.send_time_us << ',' - << message.arrival_time_us << ',' << (message.duplicate ? 1 : 0) - << '\n'; + for (const auto& message : observations) { + out << run.request.run_id << ',' << message.sequence << ',' << message.payload_bytes << ',' + << message.send_time_us << ',' << message.arrival_time_us << ',' << (message.duplicate ? 1 : 0) << '\n'; } } @@ -482,9 +438,8 @@ class ThroughputConsumer { std::filesystem::path message_csv_path_; mutable std::mutex mutex_; std::condition_variable cv_; - Room *room_ = nullptr; - DataFrameCallbackId callback_id_ = - std::numeric_limits::max(); + Room* room_ = nullptr; + DataFrameCallbackId callback_id_ = std::numeric_limits::max(); std::string callback_producer_identity_; std::string callback_track_name_; std::unordered_map runs_; @@ -492,14 +447,14 @@ class ThroughputConsumer { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ConsumerOptions options; try { if (!parseArgs(argc, argv, options)) { printUsage(argv[0]); return 1; } - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "Argument error: " << e.what() << std::endl; printUsage(argv[0]); return 1; @@ -526,28 +481,24 @@ int main(int argc, char *argv[]) { throw std::runtime_error("Failed to connect to LiveKit room"); } - auto *local_participant = room.localParticipant(); + auto* local_participant = room.localParticipant(); if (local_participant == nullptr) { throw std::runtime_error("Local participant unavailable after connect"); } - local_participant->registerRpcMethod( - kPrepareRpcMethod, [&consumer](const RpcInvocationData &invocation) { - return consumer.handlePrepareRpc(invocation); - }); - local_participant->registerRpcMethod( - kFinishRpcMethod, [&consumer](const RpcInvocationData &invocation) { - return consumer.handleFinishRpc(invocation); - }); + local_participant->registerRpcMethod(kPrepareRpcMethod, [&consumer](const RpcInvocationData& invocation) { + return consumer.handlePrepareRpc(invocation); + }); + local_participant->registerRpcMethod(kFinishRpcMethod, [&consumer](const RpcInvocationData& invocation) { + return consumer.handleFinishRpc(invocation); + }); - std::cout << "Ready. CSV output directory: " - << std::filesystem::absolute(options.output_dir).string() - << std::endl; + std::cout << "Ready. CSV output directory: " << std::filesystem::absolute(options.output_dir).string() << std::endl; while (g_running.load()) { std::this_thread::sleep_for(250ms); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << e.what() << std::endl; livekit::shutdown(); return 1; diff --git a/benchmarks/data_track_throughput/producer.cpp b/benchmarks/data_track_throughput/producer.cpp index cd966079..e326fbad 100644 --- a/benchmarks/data_track_throughput/producer.cpp +++ b/benchmarks/data_track_throughput/producer.cpp @@ -12,10 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "common.h" - -#include "livekit/livekit.h" - #include #include #include @@ -27,6 +23,9 @@ #include #include +#include "common.h" +#include "livekit/livekit.h" + using namespace livekit; using namespace data_track_throughput; @@ -49,37 +48,33 @@ struct ProducerOptions { void handleSignal(int) { g_running.store(false); } -void printUsage(const char *prog) { - std::cout - << "Usage:\n" - << " " << prog << " [--consumer ]\n" - << " " << prog - << " --url --token [--consumer ]\n\n" - << "Optional flags:\n" - << " --track-name Data track name. Default: " - << kDefaultTrackName << "\n" - << " --messages-per-scenario Default sweep message count. " - "Default: 30\n" - << " --sizes_kb Comma-separated sweep sizes in " - "KiB. Default: 1,4,16,64,128,256,512\n" - << " --freq_hz Comma-separated sweep rates in " - "Hz. Default: 1,5,10,25,50,100,200,500,1000\n" - << " --rate-hz Run a single scenario instead of " - "the full sweep\n" - << " --packet-size Single-scenario packet size, e.g. " - "1mb\n" - << " --num-msgs Single-scenario message count\n\n" - << "Env fallbacks:\n" - << " LIVEKIT_URL, LIVEKIT_TOKEN" << std::endl; +void printUsage(const char* prog) { + std::cout << "Usage:\n" + << " " << prog << " [--consumer ]\n" + << " " << prog << " --url --token [--consumer ]\n\n" + << "Optional flags:\n" + << " --track-name Data track name. Default: " << kDefaultTrackName << "\n" + << " --messages-per-scenario Default sweep message count. " + "Default: 30\n" + << " --sizes_kb Comma-separated sweep sizes in " + "KiB. Default: 1,4,16,64,128,256,512\n" + << " --freq_hz Comma-separated sweep rates in " + "Hz. Default: 1,5,10,25,50,100,200,500,1000\n" + << " --rate-hz Run a single scenario instead of " + "the full sweep\n" + << " --packet-size Single-scenario packet size, e.g. " + "1mb\n" + << " --num-msgs Single-scenario message count\n\n" + << "Env fallbacks:\n" + << " LIVEKIT_URL, LIVEKIT_TOKEN" << std::endl; } -std::vector splitCommaSeparated(const std::string &text) { +std::vector splitCommaSeparated(const std::string& text) { std::vector values; std::size_t start = 0; while (start < text.size()) { const std::size_t end = text.find(',', start); - const std::size_t count = - end == std::string::npos ? std::string::npos : end - start; + const std::size_t count = end == std::string::npos ? std::string::npos : end - start; values.push_back(trim(text.substr(start, count))); if (end == std::string::npos) { break; @@ -89,9 +84,9 @@ std::vector splitCommaSeparated(const std::string &text) { return values; } -std::vector parseRateListHz(const std::string &text) { +std::vector parseRateListHz(const std::string& text) { std::vector rates; - for (const auto &value : splitCommaSeparated(text)) { + for (const auto& value : splitCommaSeparated(text)) { if (value.empty()) { throw std::runtime_error("--freq_hz contains an empty value"); } @@ -103,9 +98,9 @@ std::vector parseRateListHz(const std::string &text) { return rates; } -std::vector parseSizeListKb(const std::string &text) { +std::vector parseSizeListKb(const std::string& text) { std::vector sizes; - for (const auto &value : splitCommaSeparated(text)) { + for (const auto& value : splitCommaSeparated(text)) { if (value.empty()) { throw std::runtime_error("--sizes_kb contains an empty value"); } @@ -117,8 +112,8 @@ std::vector parseSizeListKb(const std::string &text) { return sizes; } -bool parseArgs(int argc, char *argv[], ProducerOptions &options) { - auto readFlagValue = [&](const std::string &flag, int &index) -> std::string { +bool parseArgs(int argc, char* argv[], ProducerOptions& options) { + auto readFlagValue = [&](const std::string& flag, int& index) -> std::string { const std::string arg = argv[index]; const std::string prefix = flag + "="; if (arg == flag && index + 1 < argc) { @@ -145,21 +140,18 @@ bool parseArgs(int argc, char *argv[], ProducerOptions &options) { } else if (arg.rfind("--track-name", 0) == 0) { options.track_name = readFlagValue("--track-name", index); } else if (arg.rfind("--messages-per-scenario", 0) == 0) { - options.messages_per_scenario = static_cast( - std::stoull(readFlagValue("--messages-per-scenario", index))); + options.messages_per_scenario = + static_cast(std::stoull(readFlagValue("--messages-per-scenario", index))); } else if (arg.rfind("--sizes_kb", 0) == 0) { - options.payload_sizes_bytes = - parseSizeListKb(readFlagValue("--sizes_kb", index)); + options.payload_sizes_bytes = parseSizeListKb(readFlagValue("--sizes_kb", index)); } else if (arg.rfind("--freq_hz", 0) == 0) { options.rates_hz = parseRateListHz(readFlagValue("--freq_hz", index)); } else if (arg.rfind("--rate-hz", 0) == 0) { options.single_rate_hz = std::stod(readFlagValue("--rate-hz", index)); } else if (arg.rfind("--packet-size", 0) == 0) { - options.single_packet_size_bytes = - parseByteSize(readFlagValue("--packet-size", index)); + options.single_packet_size_bytes = parseByteSize(readFlagValue("--packet-size", index)); } else if (arg.rfind("--num-msgs", 0) == 0) { - options.single_message_count = static_cast( - std::stoull(readFlagValue("--num-msgs", index))); + options.single_message_count = static_cast(std::stoull(readFlagValue("--num-msgs", index))); } } @@ -189,25 +181,22 @@ bool parseArgs(int argc, char *argv[], ProducerOptions &options) { options.token = getenvOrEmpty("LIVEKIT_TOKEN"); } - const bool single_mode_requested = - options.single_rate_hz.has_value() || - options.single_packet_size_bytes.has_value() || - options.single_message_count.has_value(); - const bool single_mode_complete = - options.single_rate_hz.has_value() && - options.single_packet_size_bytes.has_value() && - options.single_message_count.has_value(); + const bool single_mode_requested = options.single_rate_hz.has_value() || + options.single_packet_size_bytes.has_value() || + options.single_message_count.has_value(); + const bool single_mode_complete = options.single_rate_hz.has_value() && + options.single_packet_size_bytes.has_value() && + options.single_message_count.has_value(); if (single_mode_requested && !single_mode_complete) { - throw std::runtime_error("Single-scenario mode requires --rate-hz, " - "--packet-size, and --num-msgs"); + throw std::runtime_error( + "Single-scenario mode requires --rate-hz, " + "--packet-size, and --num-msgs"); } return !(options.url.empty() || options.token.empty()); } -std::string waitForConsumerIdentity(Room &room, - const std::string &requested_identity, - std::chrono::seconds timeout) { +std::string waitForConsumerIdentity(Room& room, const std::string& requested_identity, std::chrono::seconds timeout) { const auto deadline = std::chrono::steady_clock::now() + timeout; while (g_running.load() && std::chrono::steady_clock::now() < deadline) { if (!requested_identity.empty()) { @@ -224,20 +213,16 @@ std::string waitForConsumerIdentity(Room &room, std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - throw std::runtime_error( - requested_identity.empty() - ? "Timed out waiting for exactly one remote consumer participant" - : "Timed out waiting for consumer identity: " + requested_identity); + throw std::runtime_error(requested_identity.empty() + ? "Timed out waiting for exactly one remote consumer participant" + : "Timed out waiting for consumer identity: " + requested_identity); } -std::vector -buildScenarioPlan(const ProducerOptions &options, - const std::string &producer_identity) { +std::vector buildScenarioPlan(const ProducerOptions& options, const std::string& producer_identity) { if (options.single_rate_hz.has_value()) { ScenarioRequest request; request.run_id = 1; - request.scenario_name = defaultScenarioName( - *options.single_packet_size_bytes, *options.single_rate_hz); + request.scenario_name = defaultScenarioName(*options.single_packet_size_bytes, *options.single_rate_hz); request.producer_identity = producer_identity; request.track_name = options.track_name; request.desired_rate_hz = *options.single_rate_hz; @@ -247,27 +232,23 @@ buildScenarioPlan(const ProducerOptions &options, return {request}; } - auto scenarios = makeScenarioPlan( - producer_identity, options.track_name, options.messages_per_scenario, - options.payload_sizes_bytes, options.rates_hz); - for (const auto &scenario : scenarios) { + auto scenarios = makeScenarioPlan(producer_identity, options.track_name, options.messages_per_scenario, + options.payload_sizes_bytes, options.rates_hz); + for (const auto& scenario : scenarios) { validateScenario(scenario); } return scenarios; } -ProducerStats runScenario(LocalDataTrack &track, - const ScenarioRequest &request) { +ProducerStats runScenario(LocalDataTrack& track, const ScenarioRequest& request) { ProducerStats stats; stats.run_id = request.run_id; stats.scenario_name = request.scenario_name; - const auto frame_interval = - std::chrono::duration(1.0 / request.desired_rate_hz); + const auto frame_interval = std::chrono::duration(1.0 / request.desired_rate_hz); auto next_send = std::chrono::steady_clock::now(); - for (std::size_t index = 0; index < request.message_count && g_running.load(); - ++index) { + for (std::size_t index = 0; index < request.message_count && g_running.load(); ++index) { const std::uint64_t send_time_us = nowSystemUs(); if (stats.first_send_time_us == 0) { @@ -277,47 +258,41 @@ ProducerStats runScenario(LocalDataTrack &track, ++stats.attempted_count; stats.attempted_bytes += request.packet_size_bytes; - auto payload = - makePayload(request, static_cast(index), send_time_us); + auto payload = makePayload(request, static_cast(index), send_time_us); auto push_result = track.tryPush(std::move(payload), send_time_us); if (push_result) { ++stats.enqueue_success_count; stats.enqueued_bytes += request.packet_size_bytes; } else { ++stats.enqueue_failure_count; - std::cerr << "tryPush failed for scenario " << request.scenario_name - << " seq=" << index << " reason=" << push_result.error().message - << std::endl; + std::cerr << "tryPush failed for scenario " << request.scenario_name << " seq=" << index + << " reason=" << push_result.error().message << std::endl; } - next_send += - std::chrono::duration_cast( - frame_interval); + next_send += std::chrono::duration_cast(frame_interval); std::this_thread::sleep_until(next_send); } return stats; } -void printScenarioSummary(const json &summary) { +void printScenarioSummary(const json& summary) { std::cout << "Summary " << summary.value("scenario_name", "") - << ": received=" << summary.value("messages_received", 0) << "/" - << summary.value("messages_requested", 0) + << ": received=" << summary.value("messages_received", 0) << "/" << summary.value("messages_requested", 0) << " missed=" << summary.value("messages_missed", 0) - << " received_bytes=" << summary.value("received_bytes", 0) - << std::endl; + << " received_bytes=" << summary.value("received_bytes", 0) << std::endl; } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ProducerOptions options; try { if (!parseArgs(argc, argv, options)) { printUsage(argv[0]); return 1; } - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "Argument error: " << e.what() << std::endl; printUsage(argv[0]); return 1; @@ -341,58 +316,53 @@ int main(int argc, char *argv[]) { throw std::runtime_error("Failed to connect to LiveKit room"); } - auto *local_participant = room.localParticipant(); + auto* local_participant = room.localParticipant(); if (local_participant == nullptr) { throw std::runtime_error("Local participant unavailable after connect"); } - const auto publish_result = - local_participant->publishDataTrack(options.track_name); + const auto publish_result = local_participant->publishDataTrack(options.track_name); if (!publish_result) { - throw std::runtime_error("Failed to publish data track: " + - publish_result.error().message); + throw std::runtime_error("Failed to publish data track: " + publish_result.error().message); } auto track = publish_result.value(); - const std::string consumer_identity = waitForConsumerIdentity( - room, options.consumer_identity, std::chrono::seconds(30)); - const auto scenarios = - buildScenarioPlan(options, local_participant->identity()); + const std::string consumer_identity = + waitForConsumerIdentity(room, options.consumer_identity, std::chrono::seconds(30)); + const auto scenarios = buildScenarioPlan(options, local_participant->identity()); std::cout << "Target consumer: " << consumer_identity << std::endl; std::cout << "Running " << scenarios.size() << " scenario(s)" << std::endl; - for (const auto &scenario : scenarios) { + for (const auto& scenario : scenarios) { if (!g_running.load()) { break; } - std::cout << "Preparing " << scenario.scenario_name - << " rate=" << scenario.desired_rate_hz << "Hz" - << " packet_size=" << humanBytes(scenario.packet_size_bytes) - << " messages=" << scenario.message_count << std::endl; + std::cout << "Preparing " << scenario.scenario_name << " rate=" << scenario.desired_rate_hz << "Hz" + << " packet_size=" << humanBytes(scenario.packet_size_bytes) << " messages=" << scenario.message_count + << std::endl; const auto prepare_payload = toJson(scenario).dump(); - const std::string prepare_response = local_participant->performRpc( - consumer_identity, kPrepareRpcMethod, prepare_payload, 30.0); + const std::string prepare_response = + local_participant->performRpc(consumer_identity, kPrepareRpcMethod, prepare_payload, 30.0); const json prepare_json = json::parse(prepare_response); if (!prepare_json.value("ready", false)) { - throw std::runtime_error( - "Consumer rejected scenario " + scenario.scenario_name + ": " + - prepare_json.value("message", "unknown error")); + throw std::runtime_error("Consumer rejected scenario " + scenario.scenario_name + ": " + + prepare_json.value("message", "unknown error")); } const ProducerStats stats = runScenario(*track, scenario); json finish_payload; finish_payload["stats"] = toJson(stats); - const std::string finish_response = local_participant->performRpc( - consumer_identity, kFinishRpcMethod, finish_payload.dump(), 60.0); + const std::string finish_response = + local_participant->performRpc(consumer_identity, kFinishRpcMethod, finish_payload.dump(), 60.0); const json summary = json::parse(finish_response); printScenarioSummary(summary); } track->unpublishDataTrack(); - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << e.what() << std::endl; livekit::shutdown(); return 1; diff --git a/include/livekit/audio_frame.h b/include/livekit/audio_frame.h index 2db2b9be..139804df 100644 --- a/include/livekit/audio_frame.h +++ b/include/livekit/audio_frame.h @@ -47,26 +47,24 @@ class AudioFrame { * Throws std::invalid_argument if the data size is inconsistent with * num_channels * samples_per_channel. */ - AudioFrame(std::vector data, int sample_rate, int num_channels, - int samples_per_channel); + AudioFrame(std::vector data, int sample_rate, int num_channels, int samples_per_channel); AudioFrame(); // Default constructor virtual ~AudioFrame() = default; /** * Create a new zero-initialized AudioFrame instance. */ - static AudioFrame create(int sample_rate, int num_channels, - int samples_per_channel); + static AudioFrame create(int sample_rate, int num_channels, int samples_per_channel); /** * Construct an AudioFrame by copying data out of an OwnedAudioFrameBuffer. */ - static AudioFrame fromOwnedInfo(const proto::OwnedAudioFrameBuffer &owned); + static AudioFrame fromOwnedInfo(const proto::OwnedAudioFrameBuffer& owned); // ---- Accessors ---- - const std::vector &data() const noexcept { return data_; } - std::vector &data() noexcept { return data_; } + const std::vector& data() const noexcept { return data_; } + std::vector& data() noexcept { return data_; } /// Number of samples in the buffer (per all channels). std::size_t total_samples() const noexcept { return data_.size(); } diff --git a/include/livekit/audio_processing_module.h b/include/livekit/audio_processing_module.h index 29eab332..5f5f204c 100644 --- a/include/livekit/audio_processing_module.h +++ b/include/livekit/audio_processing_module.h @@ -81,17 +81,17 @@ class AudioProcessingModule { * @param options Configuration for which processing features to enable. * @throws std::runtime_error if the APM could not be created. */ - explicit AudioProcessingModule(const Options &options); + explicit AudioProcessingModule(const Options& options); virtual ~AudioProcessingModule() = default; // Non-copyable - AudioProcessingModule(const AudioProcessingModule &) = delete; - AudioProcessingModule &operator=(const AudioProcessingModule &) = delete; + AudioProcessingModule(const AudioProcessingModule&) = delete; + AudioProcessingModule& operator=(const AudioProcessingModule&) = delete; // Movable - AudioProcessingModule(AudioProcessingModule &&) noexcept = default; - AudioProcessingModule &operator=(AudioProcessingModule &&) noexcept = default; + AudioProcessingModule(AudioProcessingModule&&) noexcept = default; + AudioProcessingModule& operator=(AudioProcessingModule&&) noexcept = default; /** * @brief Process the forward (near-end/microphone) audio stream. @@ -109,7 +109,7 @@ class AudioProcessingModule { * * @note The frame must contain exactly 10ms of audio. */ - void processStream(AudioFrame &frame); + void processStream(AudioFrame& frame); /** * @brief Process the reverse (far-end/speaker) audio stream. @@ -127,7 +127,7 @@ class AudioProcessingModule { * * @note The frame must contain exactly 10ms of audio. */ - void processReverseStream(AudioFrame &frame); + void processReverseStream(AudioFrame& frame); /** * @brief Set the estimated delay between the reverse and forward streams. @@ -159,9 +159,7 @@ class AudioProcessingModule { bool valid() const noexcept { return handle_.valid(); } /// Get the underlying FFI handle ID (used internally). - std::uint64_t ffi_handle_id() const noexcept { - return static_cast(handle_.get()); - } + std::uint64_t ffi_handle_id() const noexcept { return static_cast(handle_.get()); } FfiHandle handle_; }; diff --git a/include/livekit/audio_source.h b/include/livekit/audio_source.h index 4fbc58cc..e5d1d5e0 100644 --- a/include/livekit/audio_source.h +++ b/include/livekit/audio_source.h @@ -71,10 +71,10 @@ class AudioSource { AudioSource(int sample_rate, int num_channels, int queue_size_ms = 0); virtual ~AudioSource() = default; - AudioSource(const AudioSource &) = delete; - AudioSource &operator=(const AudioSource &) = delete; - AudioSource(AudioSource &&) noexcept = default; - AudioSource &operator=(AudioSource &&) noexcept = default; + AudioSource(const AudioSource&) = delete; + AudioSource& operator=(const AudioSource&) = delete; + AudioSource(AudioSource&&) noexcept = default; + AudioSource& operator=(AudioSource&&) noexcept = default; /// The sample rate of the audio source in Hz. int sample_rate() const noexcept { return sample_rate_; } @@ -83,9 +83,7 @@ class AudioSource { int num_channels() const noexcept { return num_channels_; } /// Underlying FFI handle ID used in FFI requests. - std::uint64_t ffi_handle_id() const noexcept { - return static_cast(handle_.get()); - } + std::uint64_t ffi_handle_id() const noexcept { return static_cast(handle_.get()); } /// Current duration of queued audio (in seconds). double queuedDuration() const noexcept; @@ -139,7 +137,7 @@ class AudioSource { * - the FFI reports an error * - a timeout occurs in bounded-wait mode */ - void captureFrame(const AudioFrame &frame, int timeout_ms = 20); + void captureFrame(const AudioFrame& frame, int timeout_ms = 20); private: // Internal helper to reset the local queue tracking (like _release_waiter). diff --git a/include/livekit/audio_stream.h b/include/livekit/audio_stream.h index d6dce270..c7dba834 100644 --- a/include/livekit/audio_stream.h +++ b/include/livekit/audio_stream.h @@ -87,21 +87,19 @@ class AudioStream { }; /// Factory: create an AudioStream bound to a specific Track - static std::shared_ptr - fromTrack(const std::shared_ptr &track, const Options &options); + static std::shared_ptr fromTrack(const std::shared_ptr& track, const Options& options); /// Factory: create an AudioStream from a Participant + TrackSource - static std::shared_ptr fromParticipant(Participant &participant, - TrackSource track_source, - const Options &options); + static std::shared_ptr fromParticipant(Participant& participant, TrackSource track_source, + const Options& options); virtual ~AudioStream(); /// No copy, assignment constructors. - AudioStream(const AudioStream &) = delete; - AudioStream &operator=(const AudioStream &) = delete; - AudioStream(AudioStream &&) noexcept; - AudioStream &operator=(AudioStream &&) noexcept; + AudioStream(const AudioStream&) = delete; + AudioStream& operator=(const AudioStream&) = delete; + AudioStream(AudioStream&&) noexcept; + AudioStream& operator=(AudioStream&&) noexcept; /// Blocking read: waits until there is an AudioFrameEvent available in the /// internal queue, or the stream reaches EOS / is closed. @@ -109,7 +107,7 @@ class AudioStream { /// \param out_event On success, filled with the next audio frame. /// \return true if a frame was delivered; false if the stream ended /// (end-of-stream or close()) and no more data is available. - bool read(AudioFrameEvent &out_event); + bool read(AudioFrameEvent& out_event); /// Signal that we are no longer interested in audio frames. /// @@ -121,16 +119,14 @@ class AudioStream { private: AudioStream() = default; - void initFromTrack(const std::shared_ptr &track, - const Options &options); - void initFromParticipant(Participant &participant, TrackSource track_source, - const Options &options); + void initFromTrack(const std::shared_ptr& track, const Options& options); + void initFromParticipant(Participant& participant, TrackSource track_source, const Options& options); // FFI event handler (registered with FfiClient) - void onFfiEvent(const proto::FfiEvent &event); + void onFfiEvent(const proto::FfiEvent& event); // Queue helpers - void pushFrame(AudioFrameEvent &&ev); + void pushFrame(AudioFrameEvent&& ev); void pushEos(); mutable std::mutex mutex_; diff --git a/include/livekit/data_stream.h b/include/livekit/data_stream.h index 19bdfc4c..ddd65c67 100644 --- a/include/livekit/data_stream.h +++ b/include/livekit/data_stream.h @@ -80,29 +80,29 @@ class TextStreamReader { /// Construct a reader from initial stream metadata. explicit TextStreamReader(TextStreamInfo info); - TextStreamReader(const TextStreamReader &) = delete; - TextStreamReader &operator=(const TextStreamReader &) = delete; + TextStreamReader(const TextStreamReader&) = delete; + TextStreamReader& operator=(const TextStreamReader&) = delete; /// Blocking read of next text chunk. /// Returns false when the stream has ended. - bool readNext(std::string &out); + bool readNext(std::string& out); /// Convenience: read entire stream into a single string. /// Blocks until the stream is closed. std::string readAll(); /// Metadata associated with this stream. - const TextStreamInfo &info() const noexcept { return info_; } + const TextStreamInfo& info() const noexcept { return info_; } private: friend class Room; /// Called by the Room when a new chunk arrives. - void onChunkUpdate(const std::string &text); + void onChunkUpdate(const std::string& text); /// Called by the Room when the stream is closed. /// Additional trailer attributes are merged into info().attributes. - void onStreamClose(const std::map &trailer_attrs); + void onStreamClose(const std::map& trailer_attrs); TextStreamInfo info_; @@ -120,25 +120,25 @@ class ByteStreamReader { /// Construct a reader from initial stream metadata. explicit ByteStreamReader(ByteStreamInfo info); - ByteStreamReader(const ByteStreamReader &) = delete; - ByteStreamReader &operator=(const ByteStreamReader &) = delete; + ByteStreamReader(const ByteStreamReader&) = delete; + ByteStreamReader& operator=(const ByteStreamReader&) = delete; /// Blocking read of next byte chunk. /// Returns false when the stream has ended. - bool readNext(std::vector &out); + bool readNext(std::vector& out); /// Metadata associated with this stream. - const ByteStreamInfo &info() const noexcept { return info_; } + const ByteStreamInfo& info() const noexcept { return info_; } private: friend class Room; /// Called by the Room when a new chunk arrives. - void onChunkUpdate(const std::vector &bytes); + void onChunkUpdate(const std::vector& bytes); /// Called by the Room when the stream is closed. /// Additional trailer attributes are merged into info().attributes. - void onStreamClose(const std::map &trailer_attrs); + void onStreamClose(const std::map& trailer_attrs); ByteStreamInfo info_; @@ -156,13 +156,13 @@ class BaseStreamWriter { virtual ~BaseStreamWriter() = default; /// Stream id assigned to this writer. - const std::string &streamId() const noexcept { return stream_id_; } + const std::string& streamId() const noexcept { return stream_id_; } /// Topic of this stream. - const std::string &topic() const noexcept { return topic_; } + const std::string& topic() const noexcept { return topic_; } /// MIME type for this stream. - const std::string &mimeType() const noexcept { return mime_type_; } + const std::string& mimeType() const noexcept { return mime_type_; } /// Timestamp (ms) when the stream was created. std::int64_t timestampMs() const noexcept { return timestamp_ms_; } @@ -172,21 +172,17 @@ class BaseStreamWriter { /// Close the stream with optional reason and attributes. /// Throws on FFI error or if already closed. - void close(const std::string &reason = "", - const std::map &attributes = {}); + void close(const std::string& reason = "", const std::map& attributes = {}); protected: - BaseStreamWriter(LocalParticipant &local_participant, std::string topic = "", - std::map attributes = {}, - std::string stream_id = "", - std::optional total_size = std::nullopt, - std::string mime_type = "", - std::vector destination_identities = {}, - std::string sender_identity = ""); + BaseStreamWriter(LocalParticipant& local_participant, std::string topic = "", + std::map attributes = {}, std::string stream_id = "", + std::optional total_size = std::nullopt, std::string mime_type = "", + std::vector destination_identities = {}, std::string sender_identity = ""); enum class StreamKind { kUnknown, kText, kByte }; - LocalParticipant &local_participant_; + LocalParticipant& local_participant_; // Public-ish metadata (mirrors BaseStreamInfo, but kept simple here) std::string stream_id_; @@ -211,33 +207,29 @@ class BaseStreamWriter { /// Send a raw chunk of bytes. /// Throws on error or if stream is closed. - void sendChunk(const std::vector &content); + void sendChunk(const std::vector& content); /// Send the trailer with given reason and attributes. /// Throws on error. - void sendTrailer(const std::string &reason, - const std::map &attributes); + void sendTrailer(const std::string& reason, const std::map& attributes); }; /// Writer for outgoing text streams. class TextStreamWriter : public BaseStreamWriter { public: - TextStreamWriter(LocalParticipant &local_participant, - const std::string &topic = "", - const std::map &attributes = {}, - const std::string &stream_id = "", - std::optional total_size = std::nullopt, - const std::string &reply_to_id = "", - const std::vector &destination_identities = {}, - const std::string &sender_identity = ""); + TextStreamWriter(LocalParticipant& local_participant, const std::string& topic = "", + const std::map& attributes = {}, const std::string& stream_id = "", + std::optional total_size = std::nullopt, const std::string& reply_to_id = "", + const std::vector& destination_identities = {}, + const std::string& sender_identity = ""); /// Write a UTF-8 string to the stream. /// Data will be split into chunks of at most kStreamChunkSize bytes. /// Throws on error or if the stream is closed. - void write(const std::string &text); + void write(const std::string& text); /// Metadata associated with this stream. - const TextStreamInfo &info() const noexcept { return info_; } + const TextStreamInfo& info() const noexcept { return info_; } private: TextStreamInfo info_; @@ -247,22 +239,20 @@ class TextStreamWriter : public BaseStreamWriter { /// Writer for outgoing byte streams. class ByteStreamWriter : public BaseStreamWriter { public: - ByteStreamWriter(LocalParticipant &local_participant, const std::string &name, - const std::string &topic = "", - const std::map &attributes = {}, - const std::string &stream_id = "", + ByteStreamWriter(LocalParticipant& local_participant, const std::string& name, const std::string& topic = "", + const std::map& attributes = {}, const std::string& stream_id = "", std::optional total_size = std::nullopt, - const std::string &mime_type = "application/octet-stream", - const std::vector &destination_identities = {}, - const std::string &sender_identity = ""); + const std::string& mime_type = "application/octet-stream", + const std::vector& destination_identities = {}, + const std::string& sender_identity = ""); /// Write binary data to the stream. /// Data will be chunked into kStreamChunkSize-sized chunks. /// Throws on error or if the stream is closed. - void write(const std::vector &data); + void write(const std::vector& data); /// Metadata associated with this stream. - const ByteStreamInfo &info() const noexcept { return info_; } + const ByteStreamInfo& info() const noexcept { return info_; } private: ByteStreamInfo info_; @@ -276,8 +266,7 @@ class ByteStreamWriter : public BaseStreamWriter { * user spawns a background thread to consume the stream). */ using TextStreamHandler = - std::function, - const std::string &participant_identity)>; + std::function, const std::string& participant_identity)>; /* Callback invoked when a new incoming byte stream is opened. * @@ -286,7 +275,6 @@ using TextStreamHandler = * or background processing). */ using ByteStreamHandler = - std::function, - const std::string &participant_identity)>; + std::function, const std::string& participant_identity)>; } // namespace livekit diff --git a/include/livekit/data_track_error.h b/include/livekit/data_track_error.h index 5ec8f97f..e8519a64 100644 --- a/include/livekit/data_track_error.h +++ b/include/livekit/data_track_error.h @@ -45,8 +45,7 @@ struct PublishDataTrackError { PublishDataTrackErrorCode code{PublishDataTrackErrorCode::UNKNOWN}; std::string message; - static PublishDataTrackError - fromProto(const proto::PublishDataTrackError &error); + static PublishDataTrackError fromProto(const proto::PublishDataTrackError& error); }; enum class LocalDataTrackTryPushErrorCode : std::uint32_t { @@ -61,8 +60,7 @@ struct LocalDataTrackTryPushError { LocalDataTrackTryPushErrorCode code{LocalDataTrackTryPushErrorCode::UNKNOWN}; std::string message; - static LocalDataTrackTryPushError - fromProto(const proto::LocalDataTrackTryPushError &error); + static LocalDataTrackTryPushError fromProto(const proto::LocalDataTrackTryPushError& error); }; enum class SubscribeDataTrackErrorCode : std::uint32_t { @@ -79,8 +77,7 @@ struct SubscribeDataTrackError { SubscribeDataTrackErrorCode code{SubscribeDataTrackErrorCode::UNKNOWN}; std::string message; - static SubscribeDataTrackError - fromProto(const proto::SubscribeDataTrackError &error); + static SubscribeDataTrackError fromProto(const proto::SubscribeDataTrackError& error); }; } // namespace livekit diff --git a/include/livekit/data_track_frame.h b/include/livekit/data_track_frame.h index d4f08e6e..fa37c490 100644 --- a/include/livekit/data_track_frame.h +++ b/include/livekit/data_track_frame.h @@ -45,14 +45,12 @@ struct DataTrackFrame { */ std::optional user_timestamp; DataTrackFrame() = default; - DataTrackFrame(const DataTrackFrame &) = default; - DataTrackFrame(DataTrackFrame &&) noexcept = default; - DataTrackFrame &operator=(const DataTrackFrame &) = default; - DataTrackFrame &operator=(DataTrackFrame &&) noexcept = default; + DataTrackFrame(const DataTrackFrame&) = default; + DataTrackFrame(DataTrackFrame&&) noexcept = default; + DataTrackFrame& operator=(const DataTrackFrame&) = default; + DataTrackFrame& operator=(DataTrackFrame&&) noexcept = default; - explicit DataTrackFrame( - std::vector &&p, - std::optional ts = std::nullopt) noexcept + explicit DataTrackFrame(std::vector&& p, std::optional ts = std::nullopt) noexcept : payload(std::move(p)), user_timestamp(ts) {} /** @@ -62,7 +60,7 @@ struct DataTrackFrame { * @param owned The proto::DataTrackFrame to create a DataTrackFrame from. * @return The created DataTrackFrame. */ - static DataTrackFrame fromOwnedInfo(const proto::DataTrackFrame &owned); + static DataTrackFrame fromOwnedInfo(const proto::DataTrackFrame& owned); }; } // namespace livekit diff --git a/include/livekit/data_track_stream.h b/include/livekit/data_track_stream.h index cb81054e..5a3345f0 100644 --- a/include/livekit/data_track_stream.h +++ b/include/livekit/data_track_stream.h @@ -16,9 +16,6 @@ #pragma once -#include "livekit/data_track_frame.h" -#include "livekit/ffi_handle.h" - #include #include #include @@ -26,6 +23,9 @@ #include #include +#include "livekit/data_track_frame.h" +#include "livekit/ffi_handle.h" + namespace livekit { namespace proto { @@ -61,14 +61,14 @@ class DataTrackStream { virtual ~DataTrackStream(); - DataTrackStream(const DataTrackStream &) = delete; - DataTrackStream &operator=(const DataTrackStream &) = delete; + DataTrackStream(const DataTrackStream&) = delete; + DataTrackStream& operator=(const DataTrackStream&) = delete; // The FFI listener captures `this`, so moving the object would leave the // registered callback pointing at the old address. - DataTrackStream(DataTrackStream &&) noexcept = delete; + DataTrackStream(DataTrackStream&&) noexcept = delete; // Instances are created and returned as std::shared_ptr, so value-move // support is not required by the current API. - DataTrackStream &operator=(DataTrackStream &&) noexcept = delete; + DataTrackStream& operator=(DataTrackStream&&) noexcept = delete; /** * Blocking read: waits until a DataTrackFrame is available, or the @@ -77,7 +77,7 @@ class DataTrackStream { * @param out On success, filled with the next data frame. * @return true if a frame was delivered; false if the stream ended. */ - bool read(DataTrackFrame &out); + bool read(DataTrackFrame& out); /** * End the stream early. @@ -95,10 +95,10 @@ class DataTrackStream { void init(FfiHandle subscription_handle); /// FFI event handler, called by FfiClient. - void onFfiEvent(const proto::FfiEvent &event); + void onFfiEvent(const proto::FfiEvent& event); /// Push a received DataTrackFrame to the internal storage. - void pushFrame(DataTrackFrame &&frame); + void pushFrame(DataTrackFrame&& frame); /// Push an end-of-stream signal (EOS). void pushEos(); diff --git a/include/livekit/e2ee.h b/include/livekit/e2ee.h index e6473ae8..1260aaf2 100644 --- a/include/livekit/e2ee.h +++ b/include/livekit/e2ee.h @@ -33,7 +33,7 @@ enum class EncryptionType { }; /* Defaults (match other SDKs / Python defaults). */ -inline constexpr const char *kDefaultRatchetSalt = "LKFrameEncryptionKey"; +inline constexpr const char* kDefaultRatchetSalt = "LKFrameEncryptionKey"; inline constexpr int kDefaultRatchetWindowSize = 16; inline constexpr int kDefaultFailureTolerance = -1; @@ -61,8 +61,7 @@ struct KeyProviderOptions { /// /// If empty, the underlying implementation default is used. std::vector ratchet_salt = std::vector( - kDefaultRatchetSalt, kDefaultRatchetSalt + std::char_traits::length( - kDefaultRatchetSalt)); + kDefaultRatchetSalt, kDefaultRatchetSalt + std::char_traits::length(kDefaultRatchetSalt)); /// Controls how many previous keys are retained during ratcheting. int ratchet_window_size = kDefaultRatchetWindowSize; @@ -118,16 +117,16 @@ class E2EEManager { public: ~KeyProvider() = default; - KeyProvider(const KeyProvider &) = delete; - KeyProvider &operator=(const KeyProvider &) = delete; - KeyProvider(KeyProvider &&) noexcept = default; - KeyProvider &operator=(KeyProvider &&) noexcept = default; + KeyProvider(const KeyProvider&) = delete; + KeyProvider& operator=(const KeyProvider&) = delete; + KeyProvider(KeyProvider&&) noexcept = default; + KeyProvider& operator=(KeyProvider&&) noexcept = default; /// Returns the options used to initialize this KeyProvider. - const KeyProviderOptions &options() const; + const KeyProviderOptions& options() const; /// Sets the shared key for the given key slot. - void setSharedKey(const std::vector &key, int key_index = 0); + void setSharedKey(const std::vector& key, int key_index = 0); /// Exports the shared key for a given key slot. std::vector exportSharedKey(int key_index = 0) const; @@ -136,16 +135,13 @@ class E2EEManager { std::vector ratchetSharedKey(int key_index = 0); /// Sets a key for a specific participant identity. - void setKey(const std::string &participant_identity, - const std::vector &key, int key_index = 0); + void setKey(const std::string& participant_identity, const std::vector& key, int key_index = 0); /// Exports a participant-specific key. - std::vector exportKey(const std::string &participant_identity, - int key_index = 0) const; + std::vector exportKey(const std::string& participant_identity, int key_index = 0) const; /// Ratchets a participant-specific key and returns the new key. - std::vector - ratchetKey(const std::string &participant_identity, int key_index = 0); + std::vector ratchetKey(const std::string& participant_identity, int key_index = 0); private: friend class E2EEManager; @@ -156,15 +152,14 @@ class E2EEManager { class FrameCryptor { public: - FrameCryptor(std::uint64_t room_handle, std::string participant_identity, - int key_index, bool enabled); + FrameCryptor(std::uint64_t room_handle, std::string participant_identity, int key_index, bool enabled); ~FrameCryptor() = default; - FrameCryptor(const FrameCryptor &) = delete; - FrameCryptor &operator=(const FrameCryptor &) = delete; - FrameCryptor(FrameCryptor &&) noexcept = default; - FrameCryptor &operator=(FrameCryptor &&) noexcept = default; + FrameCryptor(const FrameCryptor&) = delete; + FrameCryptor& operator=(const FrameCryptor&) = delete; + FrameCryptor(FrameCryptor&&) noexcept = default; + FrameCryptor& operator=(FrameCryptor&&) noexcept = default; - const std::string &participantIdentity() const; + const std::string& participantIdentity() const; int keyIndex() const; bool enabled() const; @@ -182,10 +177,10 @@ class E2EEManager { }; ~E2EEManager() = default; - E2EEManager(const E2EEManager &) = delete; - E2EEManager &operator=(const E2EEManager &) = delete; - E2EEManager(E2EEManager &&) noexcept = delete; - E2EEManager &operator=(E2EEManager &&) noexcept = delete; + E2EEManager(const E2EEManager&) = delete; + E2EEManager& operator=(const E2EEManager&) = delete; + E2EEManager(E2EEManager&&) noexcept = delete; + E2EEManager& operator=(E2EEManager&&) noexcept = delete; /// Returns whether E2EE is currently enabled for this room at runtime. bool enabled() const; @@ -199,15 +194,15 @@ class E2EEManager { /// Returns the key provider if E2EE was configured for the room; otherwise /// nullptr. - KeyProvider *keyProvider(); - const KeyProvider *keyProvider() const; + KeyProvider* keyProvider(); + const KeyProvider* keyProvider() const; /// Retrieves the current list of frame cryptors from the underlying runtime. std::vector frameCryptors() const; protected: /// Internal constructor used by Room when E2EEOptions are provided. - explicit E2EEManager(std::uint64_t room_handle, const E2EEOptions &options); + explicit E2EEManager(std::uint64_t room_handle, const E2EEOptions& options); friend class Room; private: diff --git a/include/livekit/ffi_handle.h b/include/livekit/ffi_handle.h index 55ef6b64..7cd10466 100644 --- a/include/livekit/ffi_handle.h +++ b/include/livekit/ffi_handle.h @@ -32,12 +32,12 @@ class FfiHandle { ~FfiHandle(); // Non-copyable - FfiHandle(const FfiHandle &) = delete; - FfiHandle &operator=(const FfiHandle &) = delete; + FfiHandle(const FfiHandle&) = delete; + FfiHandle& operator=(const FfiHandle&) = delete; // Movable - FfiHandle(FfiHandle &&other) noexcept; - FfiHandle &operator=(FfiHandle &&other) noexcept; + FfiHandle(FfiHandle&& other) noexcept; + FfiHandle& operator=(FfiHandle&& other) noexcept; // Replace the current handle with a new one, dropping the old if needed void reset(uintptr_t new_handle = 0) noexcept; diff --git a/include/livekit/livekit.h b/include/livekit/livekit.h index b662b2a8..fb668611 100644 --- a/include/livekit/livekit.h +++ b/include/livekit/livekit.h @@ -59,8 +59,7 @@ enum class LogSink { /// @param log_sink The log sink to use for SDK messages (default: Console). /// @returns true if initialization happened on this call, false if it was /// already initialized. -bool initialize(const LogLevel &level = LogLevel::Info, - const LogSink &log_sink = LogSink::kConsole); +bool initialize(const LogLevel& level = LogLevel::Info, const LogSink& log_sink = LogSink::kConsole); /// Shut down the LiveKit SDK. /// diff --git a/include/livekit/local_audio_track.h b/include/livekit/local_audio_track.h index d8ad51e4..72359efa 100644 --- a/include/livekit/local_audio_track.h +++ b/include/livekit/local_audio_track.h @@ -16,11 +16,12 @@ #pragma once +#include +#include + #include "audio_frame.h" #include "local_track_publication.h" #include "track.h" -#include -#include namespace livekit { @@ -61,9 +62,8 @@ class LocalAudioTrack : public Track { /// directly for frame capture. /// /// @return A shared pointer to the newly constructed `LocalAudioTrack`. - static std::shared_ptr - createLocalAudioTrack(const std::string &name, - const std::shared_ptr &source); + static std::shared_ptr createLocalAudioTrack(const std::string& name, + const std::shared_ptr& source); /// Mutes the audio track. /// @@ -80,21 +80,18 @@ class LocalAudioTrack : public Track { /// Returns the publication that owns this track, or nullptr if the track is /// not published. - std::shared_ptr publication() const noexcept { - return local_publication_; - } + std::shared_ptr publication() const noexcept { return local_publication_; } /// Sets the publication that owns this track. /// Note: std::move on a const& silently falls back to a copy, so we assign /// directly. Changing the virtual signature to take by value would enable /// a true move but is an API-breaking change left for a future revision. - void setPublication(const std::shared_ptr - &publication) noexcept override { + void setPublication(const std::shared_ptr& publication) noexcept override { local_publication_ = publication; } private: - explicit LocalAudioTrack(FfiHandle handle, const proto::OwnedTrack &track); + explicit LocalAudioTrack(FfiHandle handle, const proto::OwnedTrack& track); /// The publication that owns this track. This is a nullptr until the track /// is published, and then points to the publication that owns this track. diff --git a/include/livekit/local_data_track.h b/include/livekit/local_data_track.h index 6d128de9..1e4365d7 100644 --- a/include/livekit/local_data_track.h +++ b/include/livekit/local_data_track.h @@ -16,18 +16,18 @@ #pragma once -#include "livekit/data_track_error.h" -#include "livekit/data_track_frame.h" -#include "livekit/data_track_info.h" -#include "livekit/ffi_handle.h" -#include "livekit/result.h" - #include #include #include #include #include +#include "livekit/data_track_error.h" +#include "livekit/data_track_frame.h" +#include "livekit/data_track_info.h" +#include "livekit/ffi_handle.h" +#include "livekit/result.h" + namespace livekit { namespace proto { @@ -59,11 +59,11 @@ class LocalDataTrack { public: ~LocalDataTrack() = default; - LocalDataTrack(const LocalDataTrack &) = delete; - LocalDataTrack &operator=(const LocalDataTrack &) = delete; + LocalDataTrack(const LocalDataTrack&) = delete; + LocalDataTrack& operator=(const LocalDataTrack&) = delete; /// Metadata about this data track. - const DataTrackInfo &info() const noexcept { return info_; } + const DataTrackInfo& info() const noexcept { return info_; } /** * Try to push a frame to all subscribers of this track. @@ -71,7 +71,7 @@ class LocalDataTrack { * @return success on delivery acceptance, or a typed error describing why * the frame could not be queued. */ - Result tryPush(const DataTrackFrame &frame); + Result tryPush(const DataTrackFrame& frame); /** * Try to push a frame to all subscribers of this track. @@ -79,9 +79,8 @@ class LocalDataTrack { * @return success on delivery acceptance, or a typed error describing why * the frame could not be queued. */ - Result - tryPush(std::vector &&payload, - std::optional user_timestamp = std::nullopt); + Result tryPush(std::vector&& payload, + std::optional user_timestamp = std::nullopt); /// Whether the track is still published in the room. bool isPublished() const; @@ -96,7 +95,7 @@ class LocalDataTrack { private: friend class LocalParticipant; - explicit LocalDataTrack(const proto::OwnedLocalDataTrack &owned); + explicit LocalDataTrack(const proto::OwnedLocalDataTrack& owned); uintptr_t ffi_handle_id() const noexcept { return handle_.get(); } diff --git a/include/livekit/local_participant.h b/include/livekit/local_participant.h index a7b855d2..52253d7e 100644 --- a/include/livekit/local_participant.h +++ b/include/livekit/local_participant.h @@ -16,14 +16,6 @@ #pragma once -#include "livekit/ffi_handle.h" -#include "livekit/local_audio_track.h" -#include "livekit/local_data_track.h" -#include "livekit/local_video_track.h" -#include "livekit/participant.h" -#include "livekit/room_event_types.h" -#include "livekit/rpc_error.h" - #include #include #include @@ -34,6 +26,14 @@ #include #include +#include "livekit/ffi_handle.h" +#include "livekit/local_audio_track.h" +#include "livekit/local_data_track.h" +#include "livekit/local_video_track.h" +#include "livekit/participant.h" +#include "livekit/room_event_types.h" +#include "livekit/rpc_error.h" + namespace livekit { struct ParticipantTrackPermission; @@ -56,8 +56,7 @@ struct RpcInvocationData { */ class LocalParticipant : public Participant { public: - using PublicationMap = - std::unordered_map>; + using PublicationMap = std::unordered_map>; using TrackMap = std::unordered_map>; /** @@ -70,13 +69,11 @@ class LocalParticipant : public Participant { * Returning std::nullopt means "no payload" and results in an empty * response body being sent back to the caller. */ - using RpcHandler = - std::function(const RpcInvocationData &)>; + using RpcHandler = std::function(const RpcInvocationData&)>; - LocalParticipant(FfiHandle handle, std::string sid, std::string name, - std::string identity, std::string metadata, - std::unordered_map attributes, - ParticipantKind kind, DisconnectReason reason); + LocalParticipant(FfiHandle handle, std::string sid, std::string name, std::string identity, std::string metadata, + std::unordered_map attributes, ParticipantKind kind, + DisconnectReason reason); /** * Track publications for this participant, keyed by publication SID. @@ -96,10 +93,8 @@ class LocalParticipant : public Participant { * * Throws std::runtime_error if FFI reports an error (if you wire that up). */ - void publishData(const std::vector &payload, - bool reliable = true, - const std::vector &destination_identities = {}, - const std::string &topic = {}); + void publishData(const std::vector& payload, bool reliable = true, + const std::vector& destination_identities = {}, const std::string& topic = {}); /** * Publish a SIP DTMF (phone keypad) tone into the room. @@ -110,16 +105,15 @@ class LocalParticipant : public Participant { * @param code DTMF code (0-15). * @param digit Human-readable digit string (e.g. "5", "#"). */ - void publishDtmf(int code, const std::string &digit); + void publishDtmf(int code, const std::string& digit); // ------------------------------------------------------------------------- // Metadata APIs (set metadata / name / attributes) // ------------------------------------------------------------------------- - void setMetadata(const std::string &metadata); - void setName(const std::string &name); - void - setAttributes(const std::unordered_map &attributes); + void setMetadata(const std::string& metadata); + void setName(const std::string& name); + void setAttributes(const std::unordered_map& attributes); /** * Set track subscription permissions for this participant. @@ -127,18 +121,15 @@ class LocalParticipant : public Participant { * @param allow_all_participants If true, all participants may subscribe. * @param participant_permissions Optional participant-specific permissions. */ - void - setTrackSubscriptionPermissions(bool allow_all_participants, - const std::vector - &participant_permissions = {}); + void setTrackSubscriptionPermissions(bool allow_all_participants, + const std::vector& participant_permissions = {}); /** * Publish a local track to the room. * * Throws std::runtime_error on error (e.g. publish failure). */ - void publishTrack(const std::shared_ptr &track, - const TrackPublishOptions &options); + void publishTrack(const std::shared_ptr& track, const TrackPublishOptions& options); /** * Create a \ref LocalVideoTrack backed by the given \ref VideoSource, @@ -147,10 +138,9 @@ class LocalParticipant : public Participant { * The caller retains ownership of \p source and should use it directly * for frame capture on the video thread. */ - std::shared_ptr - publishVideoTrack(const std::string &name, - const std::shared_ptr &source, - TrackSource track_source); + std::shared_ptr publishVideoTrack(const std::string& name, + const std::shared_ptr& source, + TrackSource track_source); /** * Create a \ref LocalAudioTrack backed by the given \ref AudioSource, @@ -159,17 +149,16 @@ class LocalParticipant : public Participant { * The caller retains ownership of \p source and should use it directly * for frame capture on the audio thread. */ - std::shared_ptr - publishAudioTrack(const std::string &name, - const std::shared_ptr &source, - TrackSource track_source); + std::shared_ptr publishAudioTrack(const std::string& name, + const std::shared_ptr& source, + TrackSource track_source); /** * Unpublish a track from the room by SID. * * If the publication exists in the local map, it is removed. */ - void unpublishTrack(const std::string &track_sid); + void unpublishTrack(const std::string& track_sid); /** * Publish a data track to the room. @@ -184,8 +173,7 @@ class LocalParticipant : public Participant { * @return The published track on success, or a typed error describing why * publication failed. */ - Result, PublishDataTrackError> - publishDataTrack(const std::string &name); + Result, PublishDataTrackError> publishDataTrack(const std::string& name); /** * Unpublish a data track from the room. @@ -195,7 +183,7 @@ class LocalParticipant : public Participant { * * @param track The data track to unpublish. Null is ignored. */ - void unpublishDataTrack(const std::shared_ptr &track); + void unpublishDataTrack(const std::shared_ptr& track); /** * Initiate an RPC call to a remote participant. @@ -214,10 +202,8 @@ class LocalParticipant : public Participant { * @throws std::runtime_error If the underlying FFI handle is invalid or * the FFI call fails unexpectedly. */ - std::string - performRpc(const std::string &destination_identity, const std::string &method, - const std::string &payload, - const std::optional &response_timeout = std::nullopt); + std::string performRpc(const std::string& destination_identity, const std::string& method, const std::string& payload, + const std::optional& response_timeout = std::nullopt); /** * Register a handler for an incoming RPC method. @@ -235,7 +221,7 @@ class LocalParticipant : public Participant { * replaced by the new handler. */ - void registerRpcMethod(const std::string &method_name, RpcHandler handler); + void registerRpcMethod(const std::string& method_name, RpcHandler handler); /** * Unregister a previously registered RPC method handler. @@ -248,7 +234,7 @@ class LocalParticipant : public Participant { * If no handler is registered for this name, the call * is a no-op. */ - void unregisterRpcMethod(const std::string &method_name); + void unregisterRpcMethod(const std::string& method_name); protected: /** @@ -261,15 +247,11 @@ class LocalParticipant : public Participant { // Called by Room when an rpc_method_invocation event is received from the // SFU. This is internal plumbing and not intended to be called directly by // SDK users. - void handleRpcMethodInvocation(std::uint64_t invocation_id, - const std::string &method, - const std::string &request_id, - const std::string &caller_identity, - const std::string &payload, + void handleRpcMethodInvocation(std::uint64_t invocation_id, const std::string& method, const std::string& request_id, + const std::string& caller_identity, const std::string& payload, double response_timeout); // Called by Room events like kTrackMuted. - std::shared_ptr - findTrackPublication(const std::string &sid) const override; + std::shared_ptr findTrackPublication(const std::string& sid) const override; friend class Room; private: @@ -289,8 +271,7 @@ class LocalParticipant : public Participant { int active_invocations = 0; bool shutting_down = false; }; - std::shared_ptr rpc_state_ = - std::make_shared(); + std::shared_ptr rpc_state_ = std::make_shared(); }; } // namespace livekit diff --git a/include/livekit/local_track_publication.h b/include/livekit/local_track_publication.h index f2ccd346..51d1820a 100644 --- a/include/livekit/local_track_publication.h +++ b/include/livekit/local_track_publication.h @@ -28,7 +28,7 @@ class LocalTrackPublication : public TrackPublication { public: /// Note, this LocalTrackPublication is constructed internally only; /// safe to accept proto::OwnedTrackPublication. - explicit LocalTrackPublication(const proto::OwnedTrackPublication &owned); + explicit LocalTrackPublication(const proto::OwnedTrackPublication& owned); }; } // namespace livekit diff --git a/include/livekit/local_video_track.h b/include/livekit/local_video_track.h index 93e27837..7fc316b8 100644 --- a/include/livekit/local_video_track.h +++ b/include/livekit/local_video_track.h @@ -16,12 +16,12 @@ #pragma once -#include "local_track_publication.h" -#include "track.h" - #include #include +#include "local_track_publication.h" +#include "track.h" + namespace livekit { namespace proto { @@ -62,9 +62,8 @@ class LocalVideoTrack : public Track { /// directly for frame capture. /// /// @return A shared pointer to the newly constructed `LocalVideoTrack`. - static std::shared_ptr - createLocalVideoTrack(const std::string &name, - const std::shared_ptr &source); + static std::shared_ptr createLocalVideoTrack(const std::string& name, + const std::shared_ptr& source); /// Mutes the video track. /// @@ -81,21 +80,18 @@ class LocalVideoTrack : public Track { /// Returns the publication that owns this track, or nullptr if the track is /// not published. - std::shared_ptr publication() const noexcept { - return local_publication_; - } + std::shared_ptr publication() const noexcept { return local_publication_; } /// Sets the publication that owns this track. /// Note: std::move on a const& silently falls back to a copy, so we assign /// directly. Changing the virtual signature to take by value would enable /// a true move but is a API-breaking change hence left for a future revision. - void setPublication(const std::shared_ptr - &publication) noexcept override { + void setPublication(const std::shared_ptr& publication) noexcept override { local_publication_ = publication; } private: - explicit LocalVideoTrack(FfiHandle handle, const proto::OwnedTrack &track); + explicit LocalVideoTrack(FfiHandle handle, const proto::OwnedTrack& track); /// The publication that owns this track. This is a nullptr until the track /// is published, and then points to the publication that owns this track. diff --git a/include/livekit/logging.h b/include/livekit/logging.h index 9d2cc564..4ba93401 100644 --- a/include/livekit/logging.h +++ b/include/livekit/logging.h @@ -50,9 +50,7 @@ LogLevel getLogLevel(); /// The callback is invoked sequentially (never concurrently) from the /// thread that generated the log message. Implementations must not block /// for extended periods. -using LogCallback = - std::function; +using LogCallback = std::function; /// Install a custom log callback, replacing the default stderr sink. /// diff --git a/include/livekit/participant.h b/include/livekit/participant.h index 5987963e..98c67617 100644 --- a/include/livekit/participant.h +++ b/include/livekit/participant.h @@ -30,25 +30,24 @@ enum class ParticipantKind { Standard = 0, Ingress, Egress, Sip, Agent }; class Participant { public: - Participant(FfiHandle handle, std::string sid, std::string name, - std::string identity, std::string metadata, - std::unordered_map attributes, - ParticipantKind kind, DisconnectReason reason) - : handle_(std::move(handle)), sid_(std::move(sid)), - name_(std::move(name)), identity_(std::move(identity)), - metadata_(std::move(metadata)), attributes_(std::move(attributes)), - kind_(kind), reason_(reason) {} + Participant(FfiHandle handle, std::string sid, std::string name, std::string identity, std::string metadata, + std::unordered_map attributes, ParticipantKind kind, DisconnectReason reason) + : handle_(std::move(handle)), + sid_(std::move(sid)), + name_(std::move(name)), + identity_(std::move(identity)), + metadata_(std::move(metadata)), + attributes_(std::move(attributes)), + kind_(kind), + reason_(reason) {} virtual ~Participant() = default; // Plain getters (caller ensures threading) - const std::string &sid() const noexcept { return sid_; } - const std::string &name() const noexcept { return name_; } - const std::string &identity() const noexcept { return identity_; } - const std::string &metadata() const noexcept { return metadata_; } - const std::unordered_map & - attributes() const noexcept { - return attributes_; - } + const std::string& sid() const noexcept { return sid_; } + const std::string& name() const noexcept { return name_; } + const std::string& identity() const noexcept { return identity_; } + const std::string& metadata() const noexcept { return metadata_; } + const std::unordered_map& attributes() const noexcept { return attributes_; } ParticipantKind kind() const noexcept { return kind_; } DisconnectReason disconnectReason() const noexcept { return reason_; } @@ -56,25 +55,15 @@ class Participant { // Setters (caller ensures threading) void set_name(std::string name) noexcept { name_ = std::move(name); } - void set_metadata(std::string metadata) noexcept { - metadata_ = std::move(metadata); - } - void - set_attributes(std::unordered_map attrs) noexcept { - attributes_ = std::move(attrs); - } - void set_attribute(const std::string &key, const std::string &value) { - attributes_[key] = value; - } - void remove_attribute(const std::string &key) { attributes_.erase(key); } + void set_metadata(std::string metadata) noexcept { metadata_ = std::move(metadata); } + void set_attributes(std::unordered_map attrs) noexcept { attributes_ = std::move(attrs); } + void set_attribute(const std::string& key, const std::string& value) { attributes_[key] = value; } + void remove_attribute(const std::string& key) { attributes_.erase(key); } void set_kind(ParticipantKind kind) noexcept { kind_ = kind; } - void set_disconnect_reason(DisconnectReason reason) noexcept { - reason_ = reason; - } + void set_disconnect_reason(DisconnectReason reason) noexcept { reason_ = reason; } protected: - virtual std::shared_ptr - findTrackPublication(const std::string &sid) const = 0; + virtual std::shared_ptr findTrackPublication(const std::string& sid) const = 0; friend class Room; private: diff --git a/include/livekit/remote_audio_track.h b/include/livekit/remote_audio_track.h index 572e62c1..cfe8761c 100644 --- a/include/livekit/remote_audio_track.h +++ b/include/livekit/remote_audio_track.h @@ -16,10 +16,11 @@ #pragma once -#include "track.h" #include #include +#include "track.h" + namespace livekit { namespace proto { @@ -45,7 +46,7 @@ class RemoteAudioTrack : public Track { /// Constructs a `RemoteAudioTrack` from an internal protocol-level /// `OwnedTrack` description provided by the signaling/FFI layer. /// This constructor is intended for internal SDK use only. - explicit RemoteAudioTrack(const proto::OwnedTrack &track); + explicit RemoteAudioTrack(const proto::OwnedTrack& track); /// Returns a concise, human-readable string summarizing the track, /// including its SID and name. Useful for debugging and logging. diff --git a/include/livekit/remote_data_track.h b/include/livekit/remote_data_track.h index 762140b7..a0b40515 100644 --- a/include/livekit/remote_data_track.h +++ b/include/livekit/remote_data_track.h @@ -16,15 +16,15 @@ #pragma once +#include +#include + #include "livekit/data_track_error.h" #include "livekit/data_track_info.h" #include "livekit/data_track_stream.h" #include "livekit/ffi_handle.h" #include "livekit/result.h" -#include -#include - namespace livekit { namespace proto { @@ -54,16 +54,14 @@ class RemoteDataTrack { public: ~RemoteDataTrack() = default; - RemoteDataTrack(const RemoteDataTrack &) = delete; - RemoteDataTrack &operator=(const RemoteDataTrack &) = delete; + RemoteDataTrack(const RemoteDataTrack&) = delete; + RemoteDataTrack& operator=(const RemoteDataTrack&) = delete; /// Metadata about this data track. - const DataTrackInfo &info() const noexcept { return info_; } + const DataTrackInfo& info() const noexcept { return info_; } /// Identity of the remote participant who published this track. - const std::string &publisherIdentity() const noexcept { - return publisher_identity_; - } + const std::string& publisherIdentity() const noexcept { return publisher_identity_; } /// Whether the track is still published by the remote participant. bool isPublished() const; @@ -79,13 +77,13 @@ class RemoteDataTrack { * Returns a DataTrackStream that delivers frames via blocking * read(). Destroy the stream to unsubscribe. */ - Result, SubscribeDataTrackError> - subscribe(const DataTrackStream::Options &options = {}); + Result, SubscribeDataTrackError> subscribe( + const DataTrackStream::Options& options = {}); private: friend class Room; - explicit RemoteDataTrack(const proto::OwnedRemoteDataTrack &owned); + explicit RemoteDataTrack(const proto::OwnedRemoteDataTrack& owned); uintptr_t ffi_handle_id() const noexcept { return handle_.get(); } /** RAII wrapper for the Rust-owned FFI resource. */ diff --git a/include/livekit/remote_participant.h b/include/livekit/remote_participant.h index 367061fe..938086a0 100644 --- a/include/livekit/remote_participant.h +++ b/include/livekit/remote_participant.h @@ -16,43 +16,36 @@ #pragma once -#include "participant.h" - #include #include #include +#include "participant.h" + namespace livekit { class RemoteTrackPublication; class RemoteParticipant : public Participant { public: - using PublicationMap = - std::unordered_map>; + using PublicationMap = std::unordered_map>; - RemoteParticipant(FfiHandle handle, std::string sid, std::string name, - std::string identity, std::string metadata, - std::unordered_map attributes, - ParticipantKind kind, DisconnectReason reason); + RemoteParticipant(FfiHandle handle, std::string sid, std::string name, std::string identity, std::string metadata, + std::unordered_map attributes, ParticipantKind kind, + DisconnectReason reason); // A dictionary of track publications associated with the participant. - const PublicationMap &trackPublications() const noexcept { - return track_publications_; - } + const PublicationMap& trackPublications() const noexcept { return track_publications_; } // Optional: non-const access if you want to mutate in-place. - PublicationMap &mutableTrackPublications() noexcept { - return track_publications_; - } + PublicationMap& mutableTrackPublications() noexcept { return track_publications_; } std::string to_string() const; protected: // Called by Room events like kTrackMuted. This is internal plumbing and not // intended to be called directly by SDK users. - std::shared_ptr - findTrackPublication(const std::string &sid) const override; + std::shared_ptr findTrackPublication(const std::string& sid) const override; friend class Room; private: @@ -60,7 +53,6 @@ class RemoteParticipant : public Participant { }; // Convenience for logging / streaming -std::ostream &operator<<(std::ostream &os, - const RemoteParticipant &participant); +std::ostream& operator<<(std::ostream& os, const RemoteParticipant& participant); } // namespace livekit diff --git a/include/livekit/remote_track_publication.h b/include/livekit/remote_track_publication.h index 97360db3..5ad4c0fe 100644 --- a/include/livekit/remote_track_publication.h +++ b/include/livekit/remote_track_publication.h @@ -28,7 +28,7 @@ class RemoteTrackPublication : public TrackPublication { public: /// Note, this RemoteTrackPublication is constructed internally only; /// safe to accept proto::OwnedTrackPublication. - explicit RemoteTrackPublication(const proto::OwnedTrackPublication &owned); + explicit RemoteTrackPublication(const proto::OwnedTrackPublication& owned); bool subscribed() const noexcept { return subscribed_; } diff --git a/include/livekit/remote_video_track.h b/include/livekit/remote_video_track.h index e7a2dada..891d8fbd 100644 --- a/include/livekit/remote_video_track.h +++ b/include/livekit/remote_video_track.h @@ -16,10 +16,11 @@ #pragma once -#include "track.h" #include #include +#include "track.h" + namespace livekit { namespace proto { @@ -45,7 +46,7 @@ class RemoteVideoTrack : public Track { /// Constructs a `RemoteVideoTrack` from an internal protocol-level /// `OwnedTrack` description provided by the signaling/FFI layer. /// This constructor is intended for internal SDK use only. - explicit RemoteVideoTrack(const proto::OwnedTrack &track); + explicit RemoteVideoTrack(const proto::OwnedTrack& track); /// Returns a concise, human-readable string summarizing the track, /// including its SID and name. Useful for debugging and logging. diff --git a/include/livekit/result.h b/include/livekit/result.h index acb3b957..635d8930 100644 --- a/include/livekit/result.h +++ b/include/livekit/result.h @@ -39,22 +39,19 @@ namespace livekit { * result, or `error()` on a success result, is a programmer error and will * trip the debug assertion. */ -template class [[nodiscard]] Result { +template +class [[nodiscard]] Result { public: /// Construct a successful result containing a value. - template ::value>> - static Result success(U &&value) { - return Result( - std::variant(std::in_place_index<0>, std::forward(value))); + template ::value>> + static Result success(U&& value) { + return Result(std::variant(std::in_place_index<0>, std::forward(value))); } /// Construct a failed result containing an error. - template ::value>> - static Result failure(F &&error) { - return Result( - std::variant(std::in_place_index<1>, std::forward(error))); + template ::value>> + static Result failure(F&& error) { + return Result(std::variant(std::in_place_index<1>, std::forward(error))); } /// True when the result contains a success value. @@ -71,56 +68,56 @@ template class [[nodiscard]] Result { /// Access the success value. Requires `ok() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - T &value() & noexcept { + T& value() & noexcept { assert(ok()); return std::get<0>(storage_); } /// Access the success value. Requires `ok() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - const T &value() const & noexcept { + const T& value() const& noexcept { assert(ok()); return std::get<0>(storage_); } /// Move the success value out. Requires `ok() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - T &&value() && noexcept { + T&& value() && noexcept { assert(ok()); return std::get<0>(std::move(storage_)); } /// Move the success value out. Requires `ok() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - const T &&value() const && noexcept { + const T&& value() const&& noexcept { assert(ok()); return std::get<0>(std::move(storage_)); } /// Access the error value. Requires `has_error() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - E &error() & noexcept { + E& error() & noexcept { assert(has_error()); return std::get<1>(storage_); } /// Access the error value. Requires `has_error() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - const E &error() const & noexcept { + const E& error() const& noexcept { assert(has_error()); return std::get<1>(storage_); } /// Move the error value out. Requires `has_error() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - E &&error() && noexcept { + E&& error() && noexcept { assert(has_error()); return std::get<1>(std::move(storage_)); } /// Move the error value out. Requires `has_error() == true`. // NOLINTNEXTLINE(bugprone-exception-escape) - const E &&error() const && noexcept { + const E&& error() const&& noexcept { assert(has_error()); return std::get<1>(std::move(storage_)); } @@ -137,15 +134,15 @@ template class [[nodiscard]] Result { * This keeps the same calling style as `Result` without forcing callers * to invent a dummy success payload. */ -template class [[nodiscard]] Result { +template +class [[nodiscard]] Result { public: /// Construct a successful result with no payload. static Result success() { return Result(std::nullopt); } /// Construct a failed result containing an error. - template ::value>> - static Result failure(F &&error) { + template ::value>> + static Result failure(F&& error) { return Result(std::optional(std::forward(error))); } @@ -160,25 +157,25 @@ template class [[nodiscard]] Result { void value() const noexcept { assert(ok()); } /// Access the error value. Requires `has_error() == true`. - E &error() & noexcept { + E& error() & noexcept { assert(has_error()); return *error_; } /// Access the error value. Requires `has_error() == true`. - const E &error() const & noexcept { + const E& error() const& noexcept { assert(has_error()); return *error_; } /// Move the error value out. Requires `has_error() == true`. - E &&error() && noexcept { + E&& error() && noexcept { assert(has_error()); return std::move(*error_); } /// Move the error value out. Requires `has_error() == true`. - const E &&error() const && noexcept { + const E&& error() const&& noexcept { assert(has_error()); return std::move(*error_); } diff --git a/include/livekit/room.h b/include/livekit/room.h index e65d7d1f..932e01cd 100644 --- a/include/livekit/room.h +++ b/include/livekit/room.h @@ -17,16 +17,16 @@ #ifndef LIVEKIT_ROOM_H #define LIVEKIT_ROOM_H +#include +#include +#include + #include "livekit/data_stream.h" #include "livekit/e2ee.h" #include "livekit/ffi_handle.h" #include "livekit/room_event_types.h" #include "livekit/subscription_thread_dispatcher.h" -#include -#include -#include - namespace livekit { class RoomDelegate; @@ -109,7 +109,7 @@ class Room { * Room room; * room.setDelegate(&del); */ - void setDelegate(RoomDelegate *delegate); + void setDelegate(RoomDelegate* delegate); /* Connect to a LiveKit room using the given URL and token, applying the * supplied connection options. @@ -131,8 +131,7 @@ class Room { * Without auto_subscribe enabled, remote tracks will NOT be subscribed * automatically, and no remote audio/video will ever arrive. */ - bool Connect(const std::string &url, const std::string &token, - const RoomOptions &options); + bool Connect(const std::string& url, const std::string& token, const RoomOptions& options); // Accessors @@ -155,7 +154,7 @@ class Room { * Return value: * Non-null pointer after successful Connect(). */ - LocalParticipant *localParticipant() const; + LocalParticipant* localParticipant() const; /* Look up a remote participant by identity. * @@ -168,7 +167,7 @@ class Room { * - track publications * - callbacks for track subscribed/unsubscribed, muted/unmuted */ - RemoteParticipant *remoteParticipant(const std::string &identity) const; + RemoteParticipant* remoteParticipant(const std::string& identity) const; /// Returns a snapshot of all current remote participants. std::vector> remoteParticipants() const; @@ -191,14 +190,13 @@ class Room { * Throws: * std::runtime_error if a handler is already registered for the topic. */ - void registerTextStreamHandler(const std::string &topic, - TextStreamHandler handler); + void registerTextStreamHandler(const std::string& topic, TextStreamHandler handler); /* Unregister the text stream handler for the given topic. * * If no handler exists for the topic, this function is a no-op. */ - void unregisterTextStreamHandler(const std::string &topic); + void unregisterTextStreamHandler(const std::string& topic); /* Register a handler for incoming byte streams on a specific topic. * @@ -217,14 +215,13 @@ class Room { * Throws: * std::runtime_error if a handler is already registered for the topic. */ - void registerByteStreamHandler(const std::string &topic, - ByteStreamHandler handler); + void registerByteStreamHandler(const std::string& topic, ByteStreamHandler handler); /* Unregister the byte stream handler for the given topic. * * If no handler exists for the topic, this function is a no-op. */ - void unregisterByteStreamHandler(const std::string &topic); + void unregisterByteStreamHandler(const std::string& topic); /** * Returns the room's E2EE manager, or nullptr if E2EE was not enabled at @@ -234,7 +231,7 @@ class Room { * - The manager is created after a successful Connect(). * - If E2EE was not configured in RoomOptions, this will return nullptr. */ - E2EEManager *e2eeManager() const; + E2EEManager* e2eeManager() const; // --------------------------------------------------------------- // Frame callbacks @@ -243,72 +240,58 @@ class Room { /** * @brief Sets the audio frame callback via SubscriptionThreadDispatcher. */ - void setOnAudioFrameCallback(const std::string &participant_identity, - TrackSource source, AudioFrameCallback callback, - const AudioStream::Options &opts = {}); + void setOnAudioFrameCallback(const std::string& participant_identity, TrackSource source, AudioFrameCallback callback, + const AudioStream::Options& opts = {}); /** * @brief Sets the audio frame callback via SubscriptionThreadDispatcher. */ - void setOnAudioFrameCallback(const std::string &participant_identity, - const std::string &track_name, - AudioFrameCallback callback, - const AudioStream::Options &opts = {}); + void setOnAudioFrameCallback(const std::string& participant_identity, const std::string& track_name, + AudioFrameCallback callback, const AudioStream::Options& opts = {}); /** * @brief Sets the video frame callback via SubscriptionThreadDispatcher. */ - void setOnVideoFrameCallback(const std::string &participant_identity, - TrackSource source, VideoFrameCallback callback, - const VideoStream::Options &opts = {}); + void setOnVideoFrameCallback(const std::string& participant_identity, TrackSource source, VideoFrameCallback callback, + const VideoStream::Options& opts = {}); /** * @brief Sets the video frame callback via SubscriptionThreadDispatcher. */ - void setOnVideoFrameCallback(const std::string &participant_identity, - const std::string &track_name, - VideoFrameCallback callback, - const VideoStream::Options &opts = {}); + void setOnVideoFrameCallback(const std::string& participant_identity, const std::string& track_name, + VideoFrameCallback callback, const VideoStream::Options& opts = {}); /** * @brief Sets the video frame event callback via * SubscriptionThreadDispatcher. */ - void setOnVideoFrameEventCallback(const std::string &participant_identity, - const std::string &track_name, - VideoFrameEventCallback callback, - const VideoStream::Options &opts = {}); + void setOnVideoFrameEventCallback(const std::string& participant_identity, const std::string& track_name, + VideoFrameEventCallback callback, const VideoStream::Options& opts = {}); /** * @brief Clears the audio frame callback via SubscriptionThreadDispatcher. */ - void clearOnAudioFrameCallback(const std::string &participant_identity, - TrackSource source); + void clearOnAudioFrameCallback(const std::string& participant_identity, TrackSource source); /** * @brief Clears the audio frame callback via SubscriptionThreadDispatcher. */ - void clearOnAudioFrameCallback(const std::string &participant_identity, - const std::string &track_name); + void clearOnAudioFrameCallback(const std::string& participant_identity, const std::string& track_name); /** * @brief Clears the video frame callback via SubscriptionThreadDispatcher. */ - void clearOnVideoFrameCallback(const std::string &participant_identity, - TrackSource source); + void clearOnVideoFrameCallback(const std::string& participant_identity, TrackSource source); /** * @brief Clears the video frame callback via SubscriptionThreadDispatcher. */ - void clearOnVideoFrameCallback(const std::string &participant_identity, - const std::string &track_name); + void clearOnVideoFrameCallback(const std::string& participant_identity, const std::string& track_name); /** * @brief Adds a data frame callback via SubscriptionThreadDispatcher. */ - DataFrameCallbackId - addOnDataFrameCallback(const std::string &participant_identity, - const std::string &track_name, - DataFrameCallback callback); + DataFrameCallbackId addOnDataFrameCallback(const std::string& participant_identity, const std::string& track_name, + DataFrameCallback callback); /** * @brief Removes the data frame callback via SubscriptionThreadDispatcher. @@ -320,19 +303,16 @@ class Room { mutable std::mutex lock_; ConnectionState connection_state_ = ConnectionState::Disconnected; - RoomDelegate *delegate_ = nullptr; // Not owned + RoomDelegate* delegate_ = nullptr; // Not owned RoomInfoData room_info_; std::shared_ptr room_handle_; std::unique_ptr local_participant_; - std::unordered_map> - remote_participants_; + std::unordered_map> remote_participants_; // Data stream std::unordered_map text_stream_handlers_; std::unordered_map byte_stream_handlers_; - std::unordered_map> - text_stream_readers_; - std::unordered_map> - byte_stream_readers_; + std::unordered_map> text_stream_readers_; + std::unordered_map> byte_stream_readers_; // E2EE std::unique_ptr e2ee_manager_; std::shared_ptr subscription_thread_dispatcher_; @@ -340,7 +320,7 @@ class Room { // FfiClient listener ID (0 means no listener registered) int listener_id_{0}; - void OnEvent(const proto::FfiEvent &event); + void OnEvent(const proto::FfiEvent& event); }; } // namespace livekit diff --git a/include/livekit/room_delegate.h b/include/livekit/room_delegate.h index 2621c92c..addc90c4 100644 --- a/include/livekit/room_delegate.h +++ b/include/livekit/room_delegate.h @@ -42,15 +42,12 @@ class RoomDelegate { /** * Called when a new remote participant joins the room. */ - virtual void onParticipantConnected(Room &, - const ParticipantConnectedEvent &) {} + virtual void onParticipantConnected(Room&, const ParticipantConnectedEvent&) {} /** * Called when a remote participant leaves the room. */ - virtual void onParticipantDisconnected(Room &, - const ParticipantDisconnectedEvent &) { - } + virtual void onParticipantDisconnected(Room&, const ParticipantDisconnectedEvent&) {} // ------------------------------------------------------------------ // Local track publication events @@ -59,20 +56,17 @@ class RoomDelegate { /** * Called when a local track is successfully published. */ - virtual void onLocalTrackPublished(Room &, const LocalTrackPublishedEvent &) { - } + virtual void onLocalTrackPublished(Room&, const LocalTrackPublishedEvent&) {} /** * Called when a local track is unpublished. */ - virtual void onLocalTrackUnpublished(Room &, - const LocalTrackUnpublishedEvent &) {} + virtual void onLocalTrackUnpublished(Room&, const LocalTrackUnpublishedEvent&) {} /** * Called when a local track gains its first subscriber. */ - virtual void onLocalTrackSubscribed(Room &, - const LocalTrackSubscribedEvent &) {} + virtual void onLocalTrackSubscribed(Room&, const LocalTrackSubscribedEvent&) {} // ------------------------------------------------------------------ // Remote track publication/subscription @@ -81,39 +75,37 @@ class RoomDelegate { /** * Called when a remote participant publishes a track. */ - virtual void onTrackPublished(Room &, const TrackPublishedEvent &) {} + virtual void onTrackPublished(Room&, const TrackPublishedEvent&) {} /** * Called when a remote participant unpublishes a track. */ - virtual void onTrackUnpublished(Room &, const TrackUnpublishedEvent &) {} + virtual void onTrackUnpublished(Room&, const TrackUnpublishedEvent&) {} /** * Called when a remote track is successfully subscribed. */ - virtual void onTrackSubscribed(Room &, const TrackSubscribedEvent &) {} + virtual void onTrackSubscribed(Room&, const TrackSubscribedEvent&) {} /** * Called when a remote track is unsubscribed. */ - virtual void onTrackUnsubscribed(Room &, const TrackUnsubscribedEvent &) {} + virtual void onTrackUnsubscribed(Room&, const TrackUnsubscribedEvent&) {} /** * Called when subscribing to a remote track fails. */ - virtual void onTrackSubscriptionFailed(Room &, - const TrackSubscriptionFailedEvent &) { - } + virtual void onTrackSubscriptionFailed(Room&, const TrackSubscriptionFailedEvent&) {} /** * Called when a track is muted. */ - virtual void onTrackMuted(Room &, const TrackMutedEvent &) {} + virtual void onTrackMuted(Room&, const TrackMutedEvent&) {} /** * Called when a track is unmuted. */ - virtual void onTrackUnmuted(Room &, const TrackUnmutedEvent &) {} + virtual void onTrackUnmuted(Room&, const TrackUnmutedEvent&) {} // ------------------------------------------------------------------ // Active speakers @@ -122,8 +114,7 @@ class RoomDelegate { /** * Called when the list of active speakers changes. */ - virtual void onActiveSpeakersChanged(Room &, - const ActiveSpeakersChangedEvent &) {} + virtual void onActiveSpeakersChanged(Room&, const ActiveSpeakersChangedEvent&) {} // ------------------------------------------------------------------ // Room info / metadata @@ -132,23 +123,22 @@ class RoomDelegate { /** * Called when the room's metadata changes. */ - virtual void onRoomMetadataChanged(Room &, const RoomMetadataChangedEvent &) { - } + virtual void onRoomMetadataChanged(Room&, const RoomMetadataChangedEvent&) {} /** * Called when the room SID changes (e.g., after migration). */ - virtual void onRoomSidChanged(Room &, const RoomSidChangedEvent &) {} + virtual void onRoomSidChanged(Room&, const RoomSidChangedEvent&) {} /** * Called when any room info is updated. */ - virtual void onRoomUpdated(Room &, const RoomUpdatedEvent &) {} + virtual void onRoomUpdated(Room&, const RoomUpdatedEvent&) {} /** * Called when the participant is moved to another room. */ - virtual void onRoomMoved(Room &, const RoomMovedEvent &) {} + virtual void onRoomMoved(Room&, const RoomMovedEvent&) {} // ------------------------------------------------------------------ // Participant info changes @@ -157,28 +147,22 @@ class RoomDelegate { /** * Called when a participant's metadata is updated. */ - virtual void - onParticipantMetadataChanged(Room &, - const ParticipantMetadataChangedEvent &) {} + virtual void onParticipantMetadataChanged(Room&, const ParticipantMetadataChangedEvent&) {} /** * Called when a participant's name is changed. */ - virtual void onParticipantNameChanged(Room &, - const ParticipantNameChangedEvent &) {} + virtual void onParticipantNameChanged(Room&, const ParticipantNameChangedEvent&) {} /** * Called when a participant's attributes are updated. */ - virtual void - onParticipantAttributesChanged(Room &, - const ParticipantAttributesChangedEvent &) {} + virtual void onParticipantAttributesChanged(Room&, const ParticipantAttributesChangedEvent&) {} /** * Called when a participant's encryption status changes. */ - virtual void onParticipantEncryptionStatusChanged( - Room &, const ParticipantEncryptionStatusChangedEvent &) {} + virtual void onParticipantEncryptionStatusChanged(Room&, const ParticipantEncryptionStatusChangedEvent&) {} // ------------------------------------------------------------------ // Connection quality / state @@ -187,29 +171,27 @@ class RoomDelegate { /** * Called when a participant's connection quality changes. */ - virtual void - onConnectionQualityChanged(Room &, const ConnectionQualityChangedEvent &) {} + virtual void onConnectionQualityChanged(Room&, const ConnectionQualityChangedEvent&) {} /** * Called when the room's connection state changes. */ - virtual void onConnectionStateChanged(Room &, - const ConnectionStateChangedEvent &) {} + virtual void onConnectionStateChanged(Room&, const ConnectionStateChangedEvent&) {} /** * Called when the room is disconnected. */ - virtual void onDisconnected(Room &, const DisconnectedEvent &) {} + virtual void onDisconnected(Room&, const DisconnectedEvent&) {} /** * Called before the SDK attempts to reconnect. */ - virtual void onReconnecting(Room &, const ReconnectingEvent &) {} + virtual void onReconnecting(Room&, const ReconnectingEvent&) {} /** * Called after the SDK successfully reconnects. */ - virtual void onReconnected(Room &, const ReconnectedEvent &) {} + virtual void onReconnected(Room&, const ReconnectedEvent&) {} // ------------------------------------------------------------------ // E2EE @@ -218,7 +200,7 @@ class RoomDelegate { /** * Called when a participant's end-to-end encryption state changes. */ - virtual void onE2eeStateChanged(Room &, const E2eeStateChangedEvent &) {} + virtual void onE2eeStateChanged(Room&, const E2eeStateChangedEvent&) {} // ------------------------------------------------------------------ // EOS @@ -228,7 +210,7 @@ class RoomDelegate { * Called when the room reaches end-of-stream and will not emit further * events. */ - virtual void onRoomEos(Room &, const RoomEosEvent &) {} + virtual void onRoomEos(Room&, const RoomEosEvent&) {} // ------------------------------------------------------------------ // Data / transcription / chat @@ -237,12 +219,12 @@ class RoomDelegate { /** * Called when a user data packet (non-SIP) is received. */ - virtual void onUserPacketReceived(Room &, const UserDataPacketEvent &) {} + virtual void onUserPacketReceived(Room&, const UserDataPacketEvent&) {} /** * Called when a SIP DTMF packet is received. */ - virtual void onSipDtmfReceived(Room &, const SipDtmfReceivedEvent &) {} + virtual void onSipDtmfReceived(Room&, const SipDtmfReceivedEvent&) {} // ------------------------------------------------------------------ // Data streams @@ -251,27 +233,23 @@ class RoomDelegate { /** * Called when a data stream header is received. */ - virtual void - onDataStreamHeaderReceived(Room &, const DataStreamHeaderReceivedEvent &) {} + virtual void onDataStreamHeaderReceived(Room&, const DataStreamHeaderReceivedEvent&) {} /** * Called when a data stream chunk is received. */ - virtual void onDataStreamChunkReceived(Room &, - const DataStreamChunkReceivedEvent &) { - } + virtual void onDataStreamChunkReceived(Room&, const DataStreamChunkReceivedEvent&) {} /** * Called when a data stream trailer is received. */ - virtual void - onDataStreamTrailerReceived(Room &, const DataStreamTrailerReceivedEvent &) {} + virtual void onDataStreamTrailerReceived(Room&, const DataStreamTrailerReceivedEvent&) {} /** * Called when a data channel's buffered amount falls below its low threshold. */ virtual void onDataChannelBufferedAmountLowThresholdChanged( - Room &, const DataChannelBufferedAmountLowThresholdChangedEvent &) {} + Room&, const DataChannelBufferedAmountLowThresholdChangedEvent&) {} // ------------------------------------------------------------------ // High-level byte/text streams @@ -280,12 +258,12 @@ class RoomDelegate { /** * Called when a high-level byte stream reader is opened. */ - virtual void onByteStreamOpened(Room &, const ByteStreamOpenedEvent &) {} + virtual void onByteStreamOpened(Room&, const ByteStreamOpenedEvent&) {} /** * Called when a high-level text stream reader is opened. */ - virtual void onTextStreamOpened(Room &, const TextStreamOpenedEvent &) {} + virtual void onTextStreamOpened(Room&, const TextStreamOpenedEvent&) {} // ------------------------------------------------------------------ // Data tracks @@ -297,13 +275,12 @@ class RoomDelegate { * Data tracks are independent of the audio/video track hierarchy and * require an explicit subscribe() call to start receiving frames. */ - virtual void onDataTrackPublished(Room &, const DataTrackPublishedEvent &) {} + virtual void onDataTrackPublished(Room&, const DataTrackPublishedEvent&) {} /** * Called when a remote participant unpublishes a data track. */ - virtual void onDataTrackUnpublished(Room &, - const DataTrackUnpublishedEvent &) {} + virtual void onDataTrackUnpublished(Room&, const DataTrackUnpublishedEvent&) {} // ------------------------------------------------------------------ // Participants snapshot @@ -312,8 +289,7 @@ class RoomDelegate { /** * Called when a snapshot of participants has been updated. */ - virtual void onParticipantsUpdated(Room &, const ParticipantsUpdatedEvent &) { - } + virtual void onParticipantsUpdated(Room&, const ParticipantsUpdatedEvent&) {} }; } // namespace livekit diff --git a/include/livekit/room_event_types.h b/include/livekit/room_event_types.h index 809f9efc..d30d925b 100644 --- a/include/livekit/room_event_types.h +++ b/include/livekit/room_event_types.h @@ -189,8 +189,7 @@ struct AttributeEntry { AttributeEntry() = default; - AttributeEntry(std::string k, std::string v) - : key(std::move(k)), value(std::move(v)) {} + AttributeEntry(std::string k, std::string v) : key(std::move(k)), value(std::move(v)) {} }; /** @@ -362,7 +361,7 @@ struct TrackPublishOptions { */ struct ParticipantConnectedEvent { /** The newly connected remote participant (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; }; /** @@ -370,7 +369,7 @@ struct ParticipantConnectedEvent { */ struct ParticipantDisconnectedEvent { /** The participant that disconnected (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; /** Reason for the disconnect, if known. */ DisconnectReason reason = DisconnectReason::Unknown; @@ -411,7 +410,7 @@ struct TrackPublishedEvent { std::shared_ptr publication; /** Remote participant who owns this track (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; }; /** @@ -422,7 +421,7 @@ struct TrackUnpublishedEvent { std::shared_ptr publication; /** Remote participant who owned this track (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; }; /** @@ -436,7 +435,7 @@ struct TrackSubscribedEvent { std::shared_ptr publication; /** Remote participant who owns the track (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; }; /** @@ -450,7 +449,7 @@ struct TrackUnsubscribedEvent { std::shared_ptr publication; /** Remote participant who owns the track (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; }; /** @@ -458,7 +457,7 @@ struct TrackUnsubscribedEvent { */ struct TrackSubscriptionFailedEvent { /** Remote participant for which the subscription failed (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; /** SID of the track that failed to subscribe. */ std::string track_sid; @@ -472,7 +471,7 @@ struct TrackSubscriptionFailedEvent { */ struct TrackMutedEvent { /** Local or remote participant who owns the track (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** Publication that was muted. */ std::shared_ptr publication; @@ -483,7 +482,7 @@ struct TrackMutedEvent { */ struct TrackUnmutedEvent { /** Local or remote participant who owns the track (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** Publication that was unmuted. */ std::shared_ptr publication; @@ -494,7 +493,7 @@ struct TrackUnmutedEvent { */ struct ActiveSpeakersChangedEvent { /** Participants currently considered active speakers (owned by Room). */ - std::vector speakers; + std::vector speakers; }; /** @@ -521,7 +520,7 @@ struct RoomSidChangedEvent { */ struct ParticipantMetadataChangedEvent { /** Participant whose metadata changed (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** Old metadata value. */ std::string old_metadata; @@ -535,7 +534,7 @@ struct ParticipantMetadataChangedEvent { */ struct ParticipantNameChangedEvent { /** Participant whose name changed (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** Previous name. */ std::string old_name; @@ -549,7 +548,7 @@ struct ParticipantNameChangedEvent { */ struct ParticipantAttributesChangedEvent { /** Participant whose attributes changed (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** Set of attributes that changed (key/value pairs). */ std::vector changed_attributes; @@ -560,7 +559,7 @@ struct ParticipantAttributesChangedEvent { */ struct ParticipantEncryptionStatusChangedEvent { /** Participant whose encryption status changed (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** True if the participant is now fully encrypted. */ bool is_encrypted = false; @@ -571,7 +570,7 @@ struct ParticipantEncryptionStatusChangedEvent { */ struct ConnectionQualityChangedEvent { /** Participant whose connection quality changed (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** New connection quality. */ ConnectionQuality quality = ConnectionQuality::Good; @@ -589,7 +588,7 @@ struct UserDataPacketEvent { /** Remote participant that sent this packet, or nullptr if server (owned by * Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; /** Optional topic associated with this data (may be empty). */ std::string topic; @@ -606,7 +605,7 @@ struct SipDtmfReceivedEvent { std::string digit; /** Remote participant that sent the DTMF (owned by Room). */ - RemoteParticipant *participant = nullptr; + RemoteParticipant* participant = nullptr; }; /** @@ -727,7 +726,7 @@ struct RoomMovedEvent { */ struct ParticipantsUpdatedEvent { /** Participants updated in this event (owned by Room). */ - std::vector participants; + std::vector participants; }; /** @@ -735,7 +734,7 @@ struct ParticipantsUpdatedEvent { */ struct E2eeStateChangedEvent { /** Local or remote participant whose state changed (owned by Room). */ - Participant *participant = nullptr; + Participant* participant = nullptr; /** New encryption state. */ EncryptionState state = EncryptionState::New; diff --git a/include/livekit/rpc_error.h b/include/livekit/rpc_error.h index 2efb988c..3756907e 100644 --- a/include/livekit/rpc_error.h +++ b/include/livekit/rpc_error.h @@ -87,13 +87,13 @@ class RpcError : public std::runtime_error { /** * Human-readable error message. */ - const std::string &message() const noexcept; + const std::string& message() const noexcept; /** * Optional extra data associated with the error (JSON recommended). * May be an empty string if no data was provided. */ - const std::string &data() const noexcept; + const std::string& data() const noexcept; /** * Create a built-in RpcError using a predefined ErrorCode and default @@ -102,18 +102,18 @@ class RpcError : public std::runtime_error { * @param code Built-in error code. * @param data Optional extra data payload (JSON recommended). */ - static RpcError builtIn(ErrorCode code, const std::string &data = {}); + static RpcError builtIn(ErrorCode code, const std::string& data = {}); protected: // ----- Protected: only used by LocalParticipant (internal SDK code) ----- proto::RpcError toProto() const; - static RpcError fromProto(const proto::RpcError &err); + static RpcError fromProto(const proto::RpcError& err); friend class LocalParticipant; friend class FfiClient; private: - static const char *defaultMessageFor(ErrorCode code); + static const char* defaultMessageFor(ErrorCode code); std::uint32_t code_; std::string message_; diff --git a/include/livekit/stats.h b/include/livekit/stats.h index de56bc05..70a526f8 100644 --- a/include/livekit/stats.h +++ b/include/livekit/stats.h @@ -300,14 +300,14 @@ struct VideoSourceStats { * useful for monitoring audio quality and detecting issues like underruns. */ struct AudioPlayoutStats { - std::string kind; ///< The type of media ("audio"). - double synthesized_samples_duration; ///< Duration of synthesized samples in - ///< seconds. + std::string kind; ///< The type of media ("audio"). + double synthesized_samples_duration; ///< Duration of synthesized samples in + ///< seconds. std::uint32_t synthesized_samples_events; ///< Number of synthesis events ///< (e.g., concealment). - double total_samples_duration; ///< Total duration of all samples in seconds. - double total_playout_delay; ///< Cumulative playout delay in seconds. - std::uint64_t total_samples_count; ///< Total number of samples played out. + double total_samples_duration; ///< Total duration of all samples in seconds. + double total_playout_delay; ///< Cumulative playout delay in seconds. + std::uint64_t total_samples_count; ///< Total number of samples played out. }; struct PeerConnectionStats { @@ -490,11 +490,9 @@ struct RtcStreamStats { // Deprecated Track omitted on purpose. using RtcStatsVariant = - std::variant; struct RtcStats { @@ -505,34 +503,32 @@ struct RtcStats { // fromProto declarations // ---------------------- -RtcStatsData fromProto(const proto::RtcStatsData &); - -CodecStats fromProto(const proto::CodecStats &); -RtpStreamStats fromProto(const proto::RtpStreamStats &); -ReceivedRtpStreamStats fromProto(const proto::ReceivedRtpStreamStats &); -InboundRtpStreamStats fromProto(const proto::InboundRtpStreamStats &); -SentRtpStreamStats fromProto(const proto::SentRtpStreamStats &); -OutboundRtpStreamStats fromProto(const proto::OutboundRtpStreamStats &); -RemoteInboundRtpStreamStats -fromProto(const proto::RemoteInboundRtpStreamStats &); -RemoteOutboundRtpStreamStats -fromProto(const proto::RemoteOutboundRtpStreamStats &); -MediaSourceStats fromProto(const proto::MediaSourceStats &); -AudioSourceStats fromProto(const proto::AudioSourceStats &); -VideoSourceStats fromProto(const proto::VideoSourceStats &); -AudioPlayoutStats fromProto(const proto::AudioPlayoutStats &); -PeerConnectionStats fromProto(const proto::PeerConnectionStats &); -DataChannelStats fromProto(const proto::DataChannelStats &); -TransportStats fromProto(const proto::TransportStats &); -CandidatePairStats fromProto(const proto::CandidatePairStats &); -IceCandidateStats fromProto(const proto::IceCandidateStats &); -CertificateStats fromProto(const proto::CertificateStats &); -StreamStats fromProto(const proto::StreamStats &); +RtcStatsData fromProto(const proto::RtcStatsData&); + +CodecStats fromProto(const proto::CodecStats&); +RtpStreamStats fromProto(const proto::RtpStreamStats&); +ReceivedRtpStreamStats fromProto(const proto::ReceivedRtpStreamStats&); +InboundRtpStreamStats fromProto(const proto::InboundRtpStreamStats&); +SentRtpStreamStats fromProto(const proto::SentRtpStreamStats&); +OutboundRtpStreamStats fromProto(const proto::OutboundRtpStreamStats&); +RemoteInboundRtpStreamStats fromProto(const proto::RemoteInboundRtpStreamStats&); +RemoteOutboundRtpStreamStats fromProto(const proto::RemoteOutboundRtpStreamStats&); +MediaSourceStats fromProto(const proto::MediaSourceStats&); +AudioSourceStats fromProto(const proto::AudioSourceStats&); +VideoSourceStats fromProto(const proto::VideoSourceStats&); +AudioPlayoutStats fromProto(const proto::AudioPlayoutStats&); +PeerConnectionStats fromProto(const proto::PeerConnectionStats&); +DataChannelStats fromProto(const proto::DataChannelStats&); +TransportStats fromProto(const proto::TransportStats&); +CandidatePairStats fromProto(const proto::CandidatePairStats&); +IceCandidateStats fromProto(const proto::IceCandidateStats&); +CertificateStats fromProto(const proto::CertificateStats&); +StreamStats fromProto(const proto::StreamStats&); // High-level: -RtcStats fromProto(const proto::RtcStats &); +RtcStats fromProto(const proto::RtcStats&); // helper if you have repeated RtcStats in proto: -std::vector fromProto(const std::vector &); +std::vector fromProto(const std::vector&); } // namespace livekit diff --git a/include/livekit/subscription_thread_dispatcher.h b/include/livekit/subscription_thread_dispatcher.h index 8e5fa65c..dfe53d32 100644 --- a/include/livekit/subscription_thread_dispatcher.h +++ b/include/livekit/subscription_thread_dispatcher.h @@ -17,9 +17,6 @@ #ifndef LIVEKIT_SUBSCRIPTION_THREAD_DISPATCHER_H #define LIVEKIT_SUBSCRIPTION_THREAD_DISPATCHER_H -#include "livekit/audio_stream.h" -#include "livekit/video_stream.h" - #include #include #include @@ -30,6 +27,9 @@ #include #include +#include "livekit/audio_stream.h" +#include "livekit/video_stream.h" + namespace livekit { class AudioFrame; @@ -40,24 +40,22 @@ class VideoFrame; /// Callback type for incoming audio frames. /// Invoked on a dedicated reader thread per (participant, source) pair. -using AudioFrameCallback = std::function; +using AudioFrameCallback = std::function; /// Callback type for incoming video frames. /// Invoked on a dedicated reader thread per (participant, source) pair. -using VideoFrameCallback = - std::function; +using VideoFrameCallback = std::function; /// Callback type for incoming video frame events. /// Invoked on a dedicated reader thread per (participant, track_name) pair. -using VideoFrameEventCallback = std::function; +using VideoFrameEventCallback = std::function; /// Callback type for incoming data track frames. /// Invoked on a dedicated reader thread per subscription. /// @param payload Raw binary data received. /// @param user_timestamp Optional application-defined timestamp from sender. using DataFrameCallback = - std::function &payload, - std::optional user_timestamp)>; + std::function& payload, std::optional user_timestamp)>; /// Opaque identifier returned by addOnDataFrameCallback, used to remove an /// individual subscription via removeOnDataFrameCallback. @@ -106,9 +104,8 @@ class SubscriptionThreadDispatcher { * @param opts Options used when creating the backing * \ref AudioStream. */ - void setOnAudioFrameCallback(const std::string &participant_identity, - TrackSource source, AudioFrameCallback callback, - const AudioStream::Options &opts = {}); + void setOnAudioFrameCallback(const std::string& participant_identity, TrackSource source, AudioFrameCallback callback, + const AudioStream::Options& opts = {}); /** * Register or replace an audio frame callback for a remote subscription. @@ -123,10 +120,8 @@ class SubscriptionThreadDispatcher { * @param opts Options used when creating the backing * \ref AudioStream. */ - void setOnAudioFrameCallback(const std::string &participant_identity, - const std::string &track_name, - AudioFrameCallback callback, - const AudioStream::Options &opts = {}); + void setOnAudioFrameCallback(const std::string& participant_identity, const std::string& track_name, + AudioFrameCallback callback, const AudioStream::Options& opts = {}); /** * Register or replace a video frame callback for a remote subscription. @@ -141,9 +136,8 @@ class SubscriptionThreadDispatcher { * @param opts Options used when creating the backing * \ref VideoStream. */ - void setOnVideoFrameCallback(const std::string &participant_identity, - TrackSource source, VideoFrameCallback callback, - const VideoStream::Options &opts = {}); + void setOnVideoFrameCallback(const std::string& participant_identity, TrackSource source, VideoFrameCallback callback, + const VideoStream::Options& opts = {}); /** * Register or replace a video frame callback for a remote subscription. @@ -158,10 +152,8 @@ class SubscriptionThreadDispatcher { * @param opts Options used when creating the backing * \ref VideoStream. */ - void setOnVideoFrameCallback(const std::string &participant_identity, - const std::string &track_name, - VideoFrameCallback callback, - const VideoStream::Options &opts = {}); + void setOnVideoFrameCallback(const std::string& participant_identity, const std::string& track_name, + VideoFrameCallback callback, const VideoStream::Options& opts = {}); /** * Register or replace a rich video frame event callback for a remote @@ -178,10 +170,8 @@ class SubscriptionThreadDispatcher { * @param opts Options used when creating the backing * \ref VideoStream. */ - void setOnVideoFrameEventCallback(const std::string &participant_identity, - const std::string &track_name, - VideoFrameEventCallback callback, - const VideoStream::Options &opts = {}); + void setOnVideoFrameEventCallback(const std::string& participant_identity, const std::string& track_name, + VideoFrameEventCallback callback, const VideoStream::Options& opts = {}); /** * Remove an audio callback registration and stop any active reader. @@ -192,8 +182,7 @@ class SubscriptionThreadDispatcher { * @param participant_identity Identity of the remote participant. * @param source Track source to clear. */ - void clearOnAudioFrameCallback(const std::string &participant_identity, - TrackSource source); + void clearOnAudioFrameCallback(const std::string& participant_identity, TrackSource source); /** * Remove an audio callback registration and stop any active reader. @@ -204,8 +193,7 @@ class SubscriptionThreadDispatcher { * @param participant_identity Identity of the remote participant. * @param track_name Track name to clear. */ - void clearOnAudioFrameCallback(const std::string &participant_identity, - const std::string &track_name); + void clearOnAudioFrameCallback(const std::string& participant_identity, const std::string& track_name); /** * Remove a video callback registration and stop any active reader. @@ -216,8 +204,7 @@ class SubscriptionThreadDispatcher { * @param participant_identity Identity of the remote participant. * @param source Track source to clear. */ - void clearOnVideoFrameCallback(const std::string &participant_identity, - TrackSource source); + void clearOnVideoFrameCallback(const std::string& participant_identity, TrackSource source); /** * Remove a video callback registration and stop any active reader. @@ -228,8 +215,7 @@ class SubscriptionThreadDispatcher { * @param participant_identity Identity of the remote participant. * @param track_name Track name to clear. */ - void clearOnVideoFrameCallback(const std::string &participant_identity, - const std::string &track_name); + void clearOnVideoFrameCallback(const std::string& participant_identity, const std::string& track_name); /** * Start or restart reader dispatch for a newly subscribed remote track. @@ -245,9 +231,8 @@ class SubscriptionThreadDispatcher { * @param source Track source associated with the subscription. * @param track Subscribed remote track to read from. */ - void handleTrackSubscribed(const std::string &participant_identity, - TrackSource source, const std::string &track_name, - const std::shared_ptr &track); + void handleTrackSubscribed(const std::string& participant_identity, TrackSource source, const std::string& track_name, + const std::shared_ptr& track); /** * Stop reader dispatch for an unsubscribed remote track. @@ -261,9 +246,8 @@ class SubscriptionThreadDispatcher { * @param source Track source associated with the subscription. * @param track_name Track name associated with the subscription. */ - void handleTrackUnsubscribed(const std::string &participant_identity, - TrackSource source, - const std::string &track_name); + void handleTrackUnsubscribed(const std::string& participant_identity, TrackSource source, + const std::string& track_name); // --------------------------------------------------------------- // Data track callbacks @@ -286,10 +270,8 @@ class SubscriptionThreadDispatcher { * @return An opaque ID that can later be passed to * removeOnDataFrameCallback() to tear down this subscription. */ - DataFrameCallbackId - addOnDataFrameCallback(const std::string &participant_identity, - const std::string &track_name, - DataFrameCallback callback); + DataFrameCallbackId addOnDataFrameCallback(const std::string& participant_identity, const std::string& track_name, + DataFrameCallback callback); /** * Remove a data frame callback previously registered via @@ -310,7 +292,7 @@ class SubscriptionThreadDispatcher { * * @param track The newly published remote data track. */ - void handleDataTrackPublished(const std::shared_ptr &track); + void handleDataTrackPublished(const std::shared_ptr& track); /** * Notify the dispatcher that a remote data track has been unpublished. @@ -320,7 +302,7 @@ class SubscriptionThreadDispatcher { * * @param sid The SID of the unpublished data track. */ - void handleDataTrackUnpublished(const std::string &sid); + void handleDataTrackUnpublished(const std::string& sid); /** * Stop all readers and clear all callback registrations. @@ -341,15 +323,14 @@ class SubscriptionThreadDispatcher { TrackSource source; std::string track_name; - bool operator==(const CallbackKey &o) const { - return participant_identity == o.participant_identity && - source == o.source && track_name == o.track_name; + bool operator==(const CallbackKey& o) const { + return participant_identity == o.participant_identity && source == o.source && track_name == o.track_name; } }; /// Hash function for \ref CallbackKey so it can be used in unordered maps. struct CallbackKeyHash { - std::size_t operator()(const CallbackKey &k) const { + std::size_t operator()(const CallbackKey& k) const { auto h1 = std::hash{}(k.participant_identity); auto h2 = std::hash{}(static_cast(k.source)); auto h3 = std::hash{}(k.track_name); @@ -369,15 +350,14 @@ class SubscriptionThreadDispatcher { std::string participant_identity; std::string track_name; - bool operator==(const DataCallbackKey &o) const { - return participant_identity == o.participant_identity && - track_name == o.track_name; + bool operator==(const DataCallbackKey& o) const { + return participant_identity == o.participant_identity && track_name == o.track_name; } }; /// Hash function for \ref DataCallbackKey. struct DataCallbackKeyHash { - std::size_t operator()(const DataCallbackKey &k) const { + std::size_t operator()(const DataCallbackKey& k) const { auto h1 = std::hash{}(k.participant_identity); auto h2 = std::hash{}(k.track_name); return h1 ^ (h2 << 1); @@ -415,30 +395,26 @@ class SubscriptionThreadDispatcher { /// /// Must be called with \ref lock_ held. The returned thread, if joinable, /// must be joined after releasing the lock. - std::thread extractReaderThreadLocked(const CallbackKey &key); + std::thread extractReaderThreadLocked(const CallbackKey& key); /// Select the appropriate reader startup path for \p track. /// /// Must be called with \ref lock_ held. - std::thread startReaderLocked(const CallbackKey &key, - const std::shared_ptr &track); + std::thread startReaderLocked(const CallbackKey& key, const std::shared_ptr& track); /// Start an audio reader thread for \p key using \p track. /// /// Must be called with \ref lock_ held. Any previous reader for the same key /// is extracted and returned to the caller for joining outside the lock. - std::thread startAudioReaderLocked(const CallbackKey &key, - const std::shared_ptr &track, - const AudioFrameCallback &cb, - const AudioStream::Options &opts); + std::thread startAudioReaderLocked(const CallbackKey& key, const std::shared_ptr& track, + const AudioFrameCallback& cb, const AudioStream::Options& opts); /// Start a video reader thread for \p key using \p track. /// /// Must be called with \ref lock_ held. Any previous reader for the same key /// is extracted and returned to the caller for joining outside the lock. - std::thread startVideoReaderLocked(const CallbackKey &key, - const std::shared_ptr &track, - const RegisteredVideoCallback &callback); + std::thread startVideoReaderLocked(const CallbackKey& key, const std::shared_ptr& track, + const RegisteredVideoCallback& callback); /// Extract and close the data reader for a given callback ID, returning its /// thread. Must be called with \ref lock_ held. @@ -446,45 +422,36 @@ class SubscriptionThreadDispatcher { /// Extract and close the data reader for a given (participant, track_name) /// key, returning its thread. Must be called with \ref lock_ held. - std::thread extractDataReaderThreadLocked(const DataCallbackKey &key); + std::thread extractDataReaderThreadLocked(const DataCallbackKey& key); /// Start a data reader thread for the given callback ID, key, and track. /// Must be called with \ref lock_ held. - std::thread - startDataReaderLocked(DataFrameCallbackId id, const DataCallbackKey &key, - const std::shared_ptr &track, - const DataFrameCallback &cb); + std::thread startDataReaderLocked(DataFrameCallbackId id, const DataCallbackKey& key, + const std::shared_ptr& track, const DataFrameCallback& cb); /// Protects callback registration maps and active reader state. mutable std::mutex lock_; /// Registered audio frame callbacks keyed by \ref CallbackKey. - std::unordered_map - audio_callbacks_; + std::unordered_map audio_callbacks_; /// Registered video frame callbacks keyed by \ref CallbackKey. - std::unordered_map - video_callbacks_; + std::unordered_map video_callbacks_; /// Active stream/thread state keyed by \ref CallbackKey. - std::unordered_map - active_readers_; + std::unordered_map active_readers_; /// Next auto-increment ID for data frame callbacks. DataFrameCallbackId next_data_callback_id_{0}; /// Registered data frame callbacks keyed by opaque callback ID. - std::unordered_map - data_callbacks_; + std::unordered_map data_callbacks_; /// Active data reader threads keyed by callback ID. - std::unordered_map> - active_data_readers_; + std::unordered_map> active_data_readers_; /// Currently published remote data tracks, keyed by (participant, name). - std::unordered_map, - DataCallbackKeyHash> - remote_data_tracks_; + std::unordered_map, DataCallbackKeyHash> remote_data_tracks_; /// Hard limit on concurrently active per-subscription reader threads. static constexpr int kMaxActiveReaders = 20; diff --git a/include/livekit/tracing.h b/include/livekit/tracing.h index 0434a4d9..1477bac6 100644 --- a/include/livekit/tracing.h +++ b/include/livekit/tracing.h @@ -35,8 +35,7 @@ namespace livekit { * categories. * @return true if tracing was started, false if already running or file error */ -bool startTracing(const std::string &trace_file_path, - const std::vector &categories = {}); +bool startTracing(const std::string& trace_file_path, const std::vector& categories = {}); /** * Stop tracing and flush remaining events to file. diff --git a/include/livekit/track.h b/include/livekit/track.h index 9e188a2d..fd89656b 100644 --- a/include/livekit/track.h +++ b/include/livekit/track.h @@ -15,8 +15,6 @@ */ #pragma once -#include "livekit/ffi_handle.h" -#include "livekit/stats.h" #include #include #include @@ -25,6 +23,9 @@ #include #include +#include "livekit/ffi_handle.h" +#include "livekit/stats.h" + namespace livekit { class LocalTrackPublication; @@ -73,8 +74,8 @@ class Track { virtual ~Track() = default; // Read-only properties - const std::string &sid() const noexcept { return sid_; } - const std::string &name() const noexcept { return name_; } + const std::string& sid() const noexcept { return sid_; } + const std::string& name() const noexcept { return name_; } TrackKind kind() const noexcept { return kind_; } StreamState stream_state() const noexcept { return state_; } bool muted() const noexcept { return muted_; } @@ -99,10 +100,7 @@ class Track { /// After publishing a local track, associates the \ref LocalTrackPublication /// with this track. Default implementation is a no-op (e.g. remote tracks). - virtual void setPublication( - const std::shared_ptr &publication) noexcept { - (void)publication; - } + virtual void setPublication(const std::shared_ptr& publication) noexcept { (void)publication; } // Internal updates (called by Room) void setStreamState(StreamState s) noexcept { state_ = s; } @@ -110,13 +108,11 @@ class Track { void setName(std::string n) noexcept { name_ = std::move(n); } protected: - Track(FfiHandle handle, std::string sid, std::string name, TrackKind kind, - StreamState state, bool muted, bool remote); + Track(FfiHandle handle, std::string sid, std::string name, TrackKind kind, StreamState state, bool muted, + bool remote); - void setPublicationFields(std::optional source, - std::optional simulcasted, - std::optional width, - std::optional height, + void setPublicationFields(std::optional source, std::optional simulcasted, + std::optional width, std::optional height, std::optional mime_type); private: diff --git a/include/livekit/track_publication.h b/include/livekit/track_publication.h index 5d0ff47f..abed3a27 100644 --- a/include/livekit/track_publication.h +++ b/include/livekit/track_publication.h @@ -41,44 +41,37 @@ class TrackPublication { public: virtual ~TrackPublication() = default; - TrackPublication(const TrackPublication &) = delete; - TrackPublication &operator=(const TrackPublication &) = delete; - TrackPublication(TrackPublication &&) noexcept = default; - TrackPublication &operator=(TrackPublication &&) noexcept = default; + TrackPublication(const TrackPublication&) = delete; + TrackPublication& operator=(const TrackPublication&) = delete; + TrackPublication(TrackPublication&&) noexcept = default; + TrackPublication& operator=(TrackPublication&&) noexcept = default; // Basic metadata - const std::string &sid() const noexcept { return sid_; } - const std::string &name() const noexcept { return name_; } + const std::string& sid() const noexcept { return sid_; } + const std::string& name() const noexcept { return name_; } TrackKind kind() const noexcept { return kind_; } TrackSource source() const noexcept { return source_; } bool simulcasted() const noexcept { return simulcasted_; } std::uint32_t width() const noexcept { return width_; } std::uint32_t height() const noexcept { return height_; } - const std::string &mimeType() const noexcept { return mime_type_; } + const std::string& mimeType() const noexcept { return mime_type_; } bool muted() const noexcept { return muted_; } void setMuted(bool muted) noexcept { muted_ = muted; } EncryptionType encryptionType() const noexcept { return encryption_type_; } - const std::vector &audioFeatures() const noexcept { - return audio_features_; - } + const std::vector& audioFeatures() const noexcept { return audio_features_; } /// Underlying FFI handle value. uintptr_t ffiHandleId() const noexcept { return handle_.get(); } /// Associated Track (if attached). std::shared_ptr track() const noexcept { return track_; } - void setTrack(const std::shared_ptr &track) noexcept { - track_ = track; - } + void setTrack(const std::shared_ptr& track) noexcept { track_ = track; } protected: - TrackPublication(FfiHandle handle, std::string sid, std::string name, - TrackKind kind, TrackSource source, bool simulcasted, - std::uint32_t width, std::uint32_t height, - std::string mime_type, bool muted, - EncryptionType encryption_type, - std::vector audio_features); + TrackPublication(FfiHandle handle, std::string sid, std::string name, TrackKind kind, TrackSource source, + bool simulcasted, std::uint32_t width, std::uint32_t height, std::string mime_type, bool muted, + EncryptionType encryption_type, std::vector audio_features); FfiHandle handle_; std::shared_ptr track_; diff --git a/include/livekit/video_frame.h b/include/livekit/video_frame.h index d9632f30..ecdae9a3 100644 --- a/include/livekit/video_frame.h +++ b/include/livekit/video_frame.h @@ -24,19 +24,7 @@ namespace livekit { // Mirror of WebRTC video buffer type -enum class VideoBufferType { - RGBA = 0, - ABGR, - ARGB, - BGRA, - RGB24, - I420, - I420A, - I422, - I444, - I010, - NV12 -}; +enum class VideoBufferType { RGBA = 0, ABGR, ARGB, BGRA, RGB24, I420, I420A, I422, I444, I010, NV12 }; struct VideoPlaneInfo { std::uintptr_t data_ptr; // pointer to plane data (for FFI) @@ -59,14 +47,13 @@ class OwnedVideoBuffer; class VideoFrame { public: VideoFrame(); - VideoFrame(int width, int height, VideoBufferType type, - std::vector data); + VideoFrame(int width, int height, VideoBufferType type, std::vector data); virtual ~VideoFrame() = default; - VideoFrame(const VideoFrame &) = delete; - VideoFrame &operator=(const VideoFrame &) = delete; - VideoFrame(VideoFrame &&) noexcept = default; - VideoFrame &operator=(VideoFrame &&) noexcept = default; + VideoFrame(const VideoFrame&) = delete; + VideoFrame& operator=(const VideoFrame&) = delete; + VideoFrame(VideoFrame&&) noexcept = default; + VideoFrame& operator=(VideoFrame&&) noexcept = default; /** * Allocate a new frame with the correct buffer size for the given format. @@ -79,8 +66,8 @@ class VideoFrame { int height() const noexcept { return height_; } VideoBufferType type() const noexcept { return type_; } - std::uint8_t *data() noexcept { return data_.data(); } - const std::uint8_t *data() const noexcept { return data_.data(); } + std::uint8_t* data() noexcept { return data_.data(); } + const std::uint8_t* data() const noexcept { return data_.data(); } std::size_t dataSize() const noexcept { return data_.size(); } /** @@ -122,7 +109,7 @@ class VideoFrame { friend class VideoStream; // Only internal classes (e.g., VideoStream) // should construct frames directly from FFI buffers. - static VideoFrame fromOwnedInfo(const proto::OwnedVideoBuffer &owned); + static VideoFrame fromOwnedInfo(const proto::OwnedVideoBuffer& owned); private: int width_; diff --git a/include/livekit/video_source.h b/include/livekit/video_source.h index c015a437..e0d8544f 100644 --- a/include/livekit/video_source.h +++ b/include/livekit/video_source.h @@ -76,10 +76,10 @@ class VideoSource { VideoSource(int width, int height); virtual ~VideoSource() = default; - VideoSource(const VideoSource &) = delete; - VideoSource &operator=(const VideoSource &) = delete; - VideoSource(VideoSource &&) noexcept = default; - VideoSource &operator=(VideoSource &&) noexcept = default; + VideoSource(const VideoSource&) = delete; + VideoSource& operator=(const VideoSource&) = delete; + VideoSource(VideoSource&&) noexcept = default; + VideoSource& operator=(VideoSource&&) noexcept = default; /// Source resolution as declared at construction. int width() const noexcept { return width_; } @@ -94,13 +94,12 @@ class VideoSource { * @param frame Video frame to send. * @param options Timestamp, rotation, and optional metadata for this frame. */ - void captureFrame(const VideoFrame &frame, - const VideoCaptureOptions &options); + void captureFrame(const VideoFrame& frame, const VideoCaptureOptions& options); /** * Backward-compatible convenience overload for timestamp + rotation only. */ - void captureFrame(const VideoFrame &frame, std::int64_t timestamp_us = 0, + void captureFrame(const VideoFrame& frame, std::int64_t timestamp_us = 0, VideoRotation rotation = VideoRotation::VIDEO_ROTATION_0); private: diff --git a/include/livekit/video_stream.h b/include/livekit/video_stream.h index 850b5038..2ac9aca6 100644 --- a/include/livekit/video_stream.h +++ b/include/livekit/video_stream.h @@ -79,20 +79,18 @@ class VideoStream { }; // Factory: create a VideoStream bound to a specific Track - static std::shared_ptr - fromTrack(const std::shared_ptr &track, const Options &options); + static std::shared_ptr fromTrack(const std::shared_ptr& track, const Options& options); // Factory: create a VideoStream from a Participant + TrackSource - static std::shared_ptr fromParticipant(Participant &participant, - TrackSource track_source, - const Options &options); + static std::shared_ptr fromParticipant(Participant& participant, TrackSource track_source, + const Options& options); virtual ~VideoStream(); - VideoStream(const VideoStream &) = delete; - VideoStream &operator=(const VideoStream &) = delete; - VideoStream(VideoStream &&) noexcept; - VideoStream &operator=(VideoStream &&) noexcept; + VideoStream(const VideoStream&) = delete; + VideoStream& operator=(const VideoStream&) = delete; + VideoStream(VideoStream&&) noexcept; + VideoStream& operator=(VideoStream&&) noexcept; /// Blocking read: waits until a VideoFrameEvent is available in the internal /// queue, or the stream reaches EOS / is closed. @@ -100,7 +98,7 @@ class VideoStream { /// \param out On success, filled with the next video frame event. /// \return true if a frame was delivered; false if the stream ended /// (end-of-stream or close()) and no more data is available. - bool read(VideoFrameEvent &out); + bool read(VideoFrameEvent& out); /// Signal that we are no longer interested in video frames. /// @@ -113,16 +111,14 @@ class VideoStream { VideoStream() = default; // Internal init helpers, used by the factories - void initFromTrack(const std::shared_ptr &track, - const Options &options); - void initFromParticipant(Participant &participant, TrackSource source, - const Options &options); + void initFromTrack(const std::shared_ptr& track, const Options& options); + void initFromParticipant(Participant& participant, TrackSource source, const Options& options); // FFI event handler (registered with FfiClient) - void onFfiEvent(const proto::FfiEvent &event); + void onFfiEvent(const proto::FfiEvent& event); // Queue helpers - void pushFrame(VideoFrameEvent &&ev); + void pushFrame(VideoFrameEvent&& ev); void pushEos(); mutable std::mutex mutex_; diff --git a/scripts/clang-format.sh b/scripts/clang-format.sh index b4e379dc..bf17d6e0 100755 --- a/scripts/clang-format.sh +++ b/scripts/clang-format.sh @@ -445,10 +445,10 @@ if [[ "${CI_MODE}" == "1" ]] && (( FIX_MODE == 0 )); then write_step_summary "${log}" fi -echo "Results written to: $(pwd)/${log}" - # Always emit the concise headline summary to stdout. Sets # __FMT_VIOLATION_FILES which the exit-code logic below consumes. +# print_stdout_summary reads the log, so this must happen before the +# conditional log cleanup below. __FMT_VIOLATION_FILES=0 if (( FIX_MODE == 1 )); then echo "------------------------------------------------------------" @@ -468,6 +468,16 @@ else print_stdout_summary "${log}" "${file_count}" fi +# Only advertise the log when it actually has content -- a clean check run +# and a no-op fix run both leave it empty, and the summary banner above +# already conveys "nothing to see". Drop the empty file so a stale log +# from a previous dirty run doesn't linger and confuse the next reader. +if [[ -s "${log}" ]]; then + echo "Results written to: $(pwd)/${log}" +else + rm -f "${log}" +fi + # Exit-code policy: # - In --fix mode, propagate clang-format's own exit code (non-zero means # a real failure such as a missing file, not "needed reformatting"). diff --git a/scripts/clang-tidy.sh b/scripts/clang-tidy.sh index edcca5b9..fdbc43b2 100755 --- a/scripts/clang-tidy.sh +++ b/scripts/clang-tidy.sh @@ -504,14 +504,25 @@ if [[ "${CI_MODE}" == "1" ]]; then write_step_summary "${log}" fi -echo "Results written to: $(cd "$(dirname "${log}")" && pwd)/$(basename "${log}")" - # Always emit the concise headline summary to stdout. Sets __TIDY_WARNINGS / -# __TIDY_ERRORS globals which the strict-mode escalation below consumes. +# __TIDY_ERRORS globals which the strict-mode escalation and the log +# advertisement below consume. __TIDY_WARNINGS=0 __TIDY_ERRORS=0 print_stdout_summary "${log}" +# Only advertise the log when the run actually produced findings. A clean +# run still leaves per-file progress lines (`[N/M][T.Ts] /path/...`) in the +# file, but that's transient noise -- delete it so a stale log from a +# previous dirty run doesn't linger and confuse the next reader. CI +# annotations and the step summary above have already been emitted from +# the in-flight log, so cleanup here is purely about post-run state. +if (( __TIDY_WARNINGS > 0 || __TIDY_ERRORS > 0 )); then + echo "Results written to: $(cd "$(dirname "${log}")" && pwd)/$(basename "${log}")" +else + rm -f "${log}" +fi + # Strict mode: any warning escalates to a non-zero exit. Errors already make # run-clang-tidy itself exit non-zero (rc != 0), so this only changes the # warnings-only case. Used by CI to gate merges on a clean clang-tidy result. diff --git a/src/audio_frame.cpp b/src/audio_frame.cpp index fd070960..a9e4544c 100644 --- a/src/audio_frame.cpp +++ b/src/audio_frame.cpp @@ -28,19 +28,17 @@ namespace livekit { -AudioFrame::AudioFrame() - : sample_rate_(0), num_channels_(0), samples_per_channel_(0) {} +AudioFrame::AudioFrame() : sample_rate_(0), num_channels_(0), samples_per_channel_(0) {} -AudioFrame::AudioFrame(std::vector data, int sample_rate, - int num_channels, int samples_per_channel) - : data_(std::move(data)), sample_rate_(sample_rate), - num_channels_(num_channels), samples_per_channel_(samples_per_channel) { - const std::size_t expected = static_cast(num_channels_) * - static_cast(samples_per_channel_); +AudioFrame::AudioFrame(std::vector data, int sample_rate, int num_channels, int samples_per_channel) + : data_(std::move(data)), + sample_rate_(sample_rate), + num_channels_(num_channels), + samples_per_channel_(samples_per_channel) { + const std::size_t expected = static_cast(num_channels_) * static_cast(samples_per_channel_); if (data_.size() < expected) { - throw std::invalid_argument( - "AudioFrame: data size must be >= num_channels * samples_per_channel"); + throw std::invalid_argument("AudioFrame: data size must be >= num_channels * samples_per_channel"); } if (data_.size() % expected != 0) { throw std::invalid_argument( @@ -49,33 +47,27 @@ AudioFrame::AudioFrame(std::vector data, int sample_rate, } } -AudioFrame AudioFrame::create(int sample_rate, int num_channels, - int samples_per_channel) { - const std::size_t count = static_cast(num_channels) * - static_cast(samples_per_channel); +AudioFrame AudioFrame::create(int sample_rate, int num_channels, int samples_per_channel) { + const std::size_t count = static_cast(num_channels) * static_cast(samples_per_channel); std::vector data(count, 0); - return AudioFrame(std::move(data), sample_rate, num_channels, - samples_per_channel); + return AudioFrame(std::move(data), sample_rate, num_channels, samples_per_channel); } -AudioFrame -AudioFrame::fromOwnedInfo(const proto::OwnedAudioFrameBuffer &owned) { - const auto &info = owned.info(); +AudioFrame AudioFrame::fromOwnedInfo(const proto::OwnedAudioFrameBuffer& owned) { + const auto& info = owned.info(); const int num_channels = static_cast(info.num_channels()); const int samples_per_channel = static_cast(info.samples_per_channel()); const int sample_rate = static_cast(info.sample_rate()); - const std::size_t count = static_cast(num_channels) * - static_cast(samples_per_channel); + const std::size_t count = static_cast(num_channels) * static_cast(samples_per_channel); - const std::int16_t *ptr = + const std::int16_t* ptr = // NOLINTNEXTLINE(performance-no-int-to-ptr) - reinterpret_cast(info.data_ptr()); + reinterpret_cast(info.data_ptr()); if (ptr == nullptr && count > 0) { - throw std::runtime_error( - "AudioFrame::fromOwnedInfo: null data_ptr with nonzero size"); + throw std::runtime_error("AudioFrame::fromOwnedInfo: null data_ptr with nonzero size"); } std::vector data; @@ -89,20 +81,17 @@ AudioFrame::fromOwnedInfo(const proto::OwnedAudioFrameBuffer &owned) { // drop the OwnedAudioFrameBuffer. } - return AudioFrame(std::move(data), sample_rate, num_channels, - samples_per_channel); + return AudioFrame(std::move(data), sample_rate, num_channels, samples_per_channel); } proto::AudioFrameBufferInfo AudioFrame::toProto() const { proto::AudioFrameBufferInfo info; - const std::uint64_t ptr = - data_.empty() ? 0 : reinterpret_cast(data_.data()); + const std::uint64_t ptr = data_.empty() ? 0 : reinterpret_cast(data_.data()); info.set_data_ptr(ptr); info.set_num_channels(static_cast(num_channels_)); info.set_sample_rate(static_cast(sample_rate_)); - info.set_samples_per_channel( - static_cast(samples_per_channel_)); + info.set_samples_per_channel(static_cast(samples_per_channel_)); return info; } @@ -110,17 +99,14 @@ double AudioFrame::duration() const noexcept { if (sample_rate_ <= 0) { return 0.0; } - return static_cast(samples_per_channel_) / - static_cast(sample_rate_); + return static_cast(samples_per_channel_) / static_cast(sample_rate_); } std::string AudioFrame::to_string() const { std::ostringstream oss; - oss << "rtc.AudioFrame(sample_rate=" << sample_rate_ - << ", num_channels=" << num_channels_ - << ", samples_per_channel=" << samples_per_channel_ - << ", duration=" << std::fixed << std::setprecision(3) << duration() - << ")"; + oss << "rtc.AudioFrame(sample_rate=" << sample_rate_ << ", num_channels=" << num_channels_ + << ", samples_per_channel=" << samples_per_channel_ << ", duration=" << std::fixed << std::setprecision(3) + << duration() << ")"; return oss.str(); } diff --git a/src/audio_processing_module.cpp b/src/audio_processing_module.cpp index ff802891..601043bc 100644 --- a/src/audio_processing_module.cpp +++ b/src/audio_processing_module.cpp @@ -24,12 +24,11 @@ namespace livekit { -AudioProcessingModule::AudioProcessingModule() - : AudioProcessingModule(Options{}) {} +AudioProcessingModule::AudioProcessingModule() : AudioProcessingModule(Options{}) {} -AudioProcessingModule::AudioProcessingModule(const Options &options) { +AudioProcessingModule::AudioProcessingModule(const Options& options) { proto::FfiRequest req; - auto *msg = req.mutable_new_apm(); + auto* msg = req.mutable_new_apm(); msg->set_echo_canceller_enabled(options.echo_cancellation); msg->set_noise_suppression_enabled(options.noise_suppression); msg->set_high_pass_filter_enabled(options.high_pass_filter); @@ -38,20 +37,18 @@ AudioProcessingModule::AudioProcessingModule(const Options &options) { const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); if (!resp.has_new_apm()) { - throw std::runtime_error( - "AudioProcessingModule: failed to create APM - no response"); + throw std::runtime_error("AudioProcessingModule: failed to create APM - no response"); } - const auto &apm_info = resp.new_apm().apm(); + const auto& apm_info = resp.new_apm().apm(); handle_ = FfiHandle(static_cast(apm_info.handle().id())); if (!handle_.valid()) { - throw std::runtime_error( - "AudioProcessingModule: failed to create APM - invalid handle"); + throw std::runtime_error("AudioProcessingModule: failed to create APM - invalid handle"); } } -void AudioProcessingModule::processStream(AudioFrame &frame) { +void AudioProcessingModule::processStream(AudioFrame& frame) { if (!handle_.valid()) { throw std::runtime_error("AudioProcessingModule: invalid handle"); } @@ -61,29 +58,26 @@ void AudioProcessingModule::processStream(AudioFrame &frame) { } proto::FfiRequest req; - auto *msg = req.mutable_apm_process_stream(); + auto* msg = req.mutable_apm_process_stream(); msg->set_apm_handle(static_cast(handle_.get())); msg->set_data_ptr(reinterpret_cast(frame.data().data())); - msg->set_size( - static_cast(frame.data().size() * sizeof(std::int16_t))); + msg->set_size(static_cast(frame.data().size() * sizeof(std::int16_t))); msg->set_sample_rate(static_cast(frame.sample_rate())); msg->set_num_channels(static_cast(frame.num_channels())); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); if (!resp.has_apm_process_stream()) { - throw std::runtime_error( - "AudioProcessingModule::processStream: unexpected response"); + throw std::runtime_error("AudioProcessingModule::processStream: unexpected response"); } - const auto &result = resp.apm_process_stream(); + const auto& result = resp.apm_process_stream(); if (result.has_error()) { - throw std::runtime_error("AudioProcessingModule::processStream: " + - result.error()); + throw std::runtime_error("AudioProcessingModule::processStream: " + result.error()); } } -void AudioProcessingModule::processReverseStream(AudioFrame &frame) { +void AudioProcessingModule::processReverseStream(AudioFrame& frame) { if (!handle_.valid()) { throw std::runtime_error("AudioProcessingModule: invalid handle"); } @@ -93,25 +87,22 @@ void AudioProcessingModule::processReverseStream(AudioFrame &frame) { } proto::FfiRequest req; - auto *msg = req.mutable_apm_process_reverse_stream(); + auto* msg = req.mutable_apm_process_reverse_stream(); msg->set_apm_handle(static_cast(handle_.get())); msg->set_data_ptr(reinterpret_cast(frame.data().data())); - msg->set_size( - static_cast(frame.data().size() * sizeof(std::int16_t))); + msg->set_size(static_cast(frame.data().size() * sizeof(std::int16_t))); msg->set_sample_rate(static_cast(frame.sample_rate())); msg->set_num_channels(static_cast(frame.num_channels())); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); if (!resp.has_apm_process_reverse_stream()) { - throw std::runtime_error( - "AudioProcessingModule::processReverseStream: unexpected response"); + throw std::runtime_error("AudioProcessingModule::processReverseStream: unexpected response"); } - const auto &result = resp.apm_process_reverse_stream(); + const auto& result = resp.apm_process_reverse_stream(); if (result.has_error()) { - throw std::runtime_error("AudioProcessingModule::processReverseStream: " + - result.error()); + throw std::runtime_error("AudioProcessingModule::processReverseStream: " + result.error()); } } @@ -121,21 +112,19 @@ void AudioProcessingModule::setStreamDelayMs(int delay_ms) { } proto::FfiRequest req; - auto *msg = req.mutable_apm_set_stream_delay(); + auto* msg = req.mutable_apm_set_stream_delay(); msg->set_apm_handle(static_cast(handle_.get())); msg->set_delay_ms(delay_ms); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); if (!resp.has_apm_set_stream_delay()) { - throw std::runtime_error( - "AudioProcessingModule::setStreamDelayMs: unexpected response"); + throw std::runtime_error("AudioProcessingModule::setStreamDelayMs: unexpected response"); } - const auto &result = resp.apm_set_stream_delay(); + const auto& result = resp.apm_set_stream_delay(); if (result.has_error()) { - throw std::runtime_error("AudioProcessingModule::setStreamDelayMs: " + - result.error()); + throw std::runtime_error("AudioProcessingModule::setStreamDelayMs: " + result.error()); } } diff --git a/src/audio_source.cpp b/src/audio_source.cpp index c5c6ee0c..2a05655e 100644 --- a/src/audio_source.cpp +++ b/src/audio_source.cpp @@ -41,10 +41,9 @@ static double now_seconds() { // ============================================================================ AudioSource::AudioSource(int sample_rate, int num_channels, int queue_size_ms) - : sample_rate_(sample_rate), num_channels_(num_channels), - queue_size_ms_(queue_size_ms) { + : sample_rate_(sample_rate), num_channels_(num_channels), queue_size_ms_(queue_size_ms) { proto::FfiRequest req; - auto *msg = req.mutable_new_audio_source(); + auto* msg = req.mutable_new_audio_source(); msg->set_type(proto::AudioSourceType::AUDIO_SOURCE_NATIVE); msg->set_sample_rate(static_cast(sample_rate_)); msg->set_num_channels(static_cast(num_channels_)); @@ -52,7 +51,7 @@ AudioSource::AudioSource(int sample_rate, int num_channels, int queue_size_ms) const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); - const auto &source_info = resp.new_audio_source().source(); + const auto& source_info = resp.new_audio_source().source(); // Wrap FFI handle in RAII FfiHandle handle_ = FfiHandle(static_cast(source_info.handle().id())); } @@ -80,7 +79,7 @@ void AudioSource::clearQueue() { } proto::FfiRequest req; - auto *msg = req.mutable_clear_audio_buffer(); + auto* msg = req.mutable_clear_audio_buffer(); msg->set_source_handle(static_cast(handle_.get())); (void)FfiClient::instance().sendRequest(req); @@ -89,7 +88,7 @@ void AudioSource::clearQueue() { resetQueueTracking(); } -void AudioSource::captureFrame(const AudioFrame &frame, int timeout_ms) { +void AudioSource::captureFrame(const AudioFrame& frame, int timeout_ms) { using namespace std::chrono_literals; if (!handle_) { return; @@ -102,9 +101,7 @@ void AudioSource::captureFrame(const AudioFrame &frame, int timeout_ms) { // Queue tracking, same logic as before const double now = now_seconds(); const double elapsed = (last_capture_ == 0.0) ? 0.0 : (now - last_capture_); - const double frame_duration = - static_cast(frame.samples_per_channel()) / - static_cast(sample_rate_); + const double frame_duration = static_cast(frame.samples_per_channel()) / static_cast(sample_rate_); q_size_ += frame_duration - elapsed; if (q_size_ < 0.0) { q_size_ = 0.0; // clamp @@ -121,8 +118,7 @@ void AudioSource::captureFrame(const AudioFrame &frame, int timeout_ms) { } // This will throw std::runtime_error if the callback reported an error auto status = fut.wait_for(std::chrono::milliseconds(timeout_ms)); - if (status == std::future_status::ready || - status == std::future_status::deferred) { + if (status == std::future_status::ready || status == std::future_status::deferred) { fut.get(); } else { // std::future_status::timeout LK_LOG_WARN("captureAudioFrameAsync timed out after {} ms", timeout_ms); diff --git a/src/audio_stream.cpp b/src/audio_stream.cpp index 07b1e693..ae27761d 100644 --- a/src/audio_stream.cpp +++ b/src/audio_stream.cpp @@ -32,17 +32,14 @@ using proto::FfiRequest; // Factory helpers // ------------------------ -std::shared_ptr -AudioStream::fromTrack(const std::shared_ptr &track, - const Options &options) { +std::shared_ptr AudioStream::fromTrack(const std::shared_ptr& track, const Options& options) { auto stream = std::shared_ptr(new AudioStream()); stream->initFromTrack(track, options); return stream; } -std::shared_ptr -AudioStream::fromParticipant(Participant &participant, TrackSource track_source, - const Options &options) { +std::shared_ptr AudioStream::fromParticipant(Participant& participant, TrackSource track_source, + const Options& options) { auto stream = std::shared_ptr(new AudioStream()); stream->initFromParticipant(participant, track_source, options); return stream; @@ -54,7 +51,7 @@ AudioStream::fromParticipant(Participant &participant, TrackSource track_source, AudioStream::~AudioStream() { close(); } -AudioStream::AudioStream(AudioStream &&other) noexcept { +AudioStream::AudioStream(AudioStream&& other) noexcept { const std::scoped_lock lock(other.mutex_); queue_ = std::move(other.queue_); capacity_ = other.capacity_; @@ -68,7 +65,7 @@ AudioStream::AudioStream(AudioStream &&other) noexcept { other.closed_ = true; } -AudioStream &AudioStream::operator=(AudioStream &&other) noexcept { +AudioStream& AudioStream::operator=(AudioStream&& other) noexcept { if (this == &other) { return *this; } @@ -94,7 +91,7 @@ AudioStream &AudioStream::operator=(AudioStream &&other) noexcept { return *this; } -bool AudioStream::read(AudioFrameEvent &out_event) { +bool AudioStream::read(AudioFrameEvent& out_event) { std::unique_lock lock(mutex_); cv_.wait(lock, [this] { return !queue_.empty() || eof_ || closed_; }); @@ -134,20 +131,17 @@ void AudioStream::close() { // Internal functions -void AudioStream::initFromTrack(const std::shared_ptr &track, - const Options &options) { +void AudioStream::initFromTrack(const std::shared_ptr& track, const Options& options) { capacity_ = options.capacity; options_ = options; // 1) Subscribe to FFI events - listener_id_ = FfiClient::instance().AddListener( - [this](const FfiEvent &e) { this->onFfiEvent(e); }); + listener_id_ = FfiClient::instance().AddListener([this](const FfiEvent& e) { this->onFfiEvent(e); }); // 2) Send FfiRequest to create a new audio stream bound to this track FfiRequest req; - auto *new_audio_stream = req.mutable_new_audio_stream(); - new_audio_stream->set_track_handle( - static_cast(track->ffi_handle_id())); + auto* new_audio_stream = req.mutable_new_audio_stream(); + new_audio_stream->set_track_handle(static_cast(track->ffi_handle_id())); // TODO, sample_rate and num_channels are not useful in AudioStream, remove it // from FFI. // new_audio_stream->set_sample_rate(options_.sample_rate); @@ -155,32 +149,27 @@ void AudioStream::initFromTrack(const std::shared_ptr &track, new_audio_stream->set_type(proto::AudioStreamType::AUDIO_STREAM_NATIVE); if (!options_.noise_cancellation_module.empty()) { - new_audio_stream->set_audio_filter_module_id( - options_.noise_cancellation_module); + new_audio_stream->set_audio_filter_module_id(options_.noise_cancellation_module); // Always set options JSON even if empty - backend will treat empty string // as "no options" - new_audio_stream->set_audio_filter_options( - options_.noise_cancellation_options_json); + new_audio_stream->set_audio_filter_options(options_.noise_cancellation_options_json); } auto resp = FfiClient::instance().sendRequest(req); - const auto &stream = resp.new_audio_stream().stream(); + const auto& stream = resp.new_audio_stream().stream(); stream_handle_ = FfiHandle(static_cast(stream.handle().id())); } -void AudioStream::initFromParticipant(Participant &participant, - TrackSource track_source, - const Options &options) { +void AudioStream::initFromParticipant(Participant& participant, TrackSource track_source, const Options& options) { capacity_ = options.capacity; options_ = options; // 1) Subscribe to FFI events - listener_id_ = FfiClient::instance().AddListener( - [this](const FfiEvent &e) { this->onFfiEvent(e); }); + listener_id_ = FfiClient::instance().AddListener([this](const FfiEvent& e) { this->onFfiEvent(e); }); // 2) Send FfiRequest to create audio stream from participant + track source FfiRequest req; - auto *as = req.mutable_audio_stream_from_participant(); + auto* as = req.mutable_audio_stream_from_participant(); as->set_participant_handle(participant.ffiHandleId()); // TODO, sample_rate and num_channels are not useful in AudioStream, remove it // from FFI. @@ -197,21 +186,21 @@ void AudioStream::initFromParticipant(Participant &participant, } auto resp = FfiClient::instance().sendRequest(req); - const auto &stream = resp.audio_stream_from_participant().stream(); + const auto& stream = resp.audio_stream_from_participant().stream(); stream_handle_ = FfiHandle(static_cast(stream.handle().id())); } -void AudioStream::onFfiEvent(const FfiEvent &event) { +void AudioStream::onFfiEvent(const FfiEvent& event) { if (event.message_case() != FfiEvent::kAudioStreamEvent) { return; } - const auto &ase = event.audio_stream_event(); + const auto& ase = event.audio_stream_event(); // Check if this event is for our stream handle. if (ase.stream_handle() != static_cast(stream_handle_.get())) { return; } if (ase.has_frame_received()) { - const auto &fr = ase.frame_received(); + const auto& fr = ase.frame_received(); AudioFrameEvent ev{AudioFrame::fromOwnedInfo(fr.frame())}; pushFrame(std::move(ev)); } else if (ase.has_eos()) { @@ -219,7 +208,7 @@ void AudioStream::onFfiEvent(const FfiEvent &event) { } } -void AudioStream::pushFrame(AudioFrameEvent &&ev) { +void AudioStream::pushFrame(AudioFrameEvent&& ev) { { const std::scoped_lock lock(mutex_); diff --git a/src/data_stream.cpp b/src/data_stream.cpp index ef46a8fe..d75a6c37 100644 --- a/src/data_stream.cpp +++ b/src/data_stream.cpp @@ -36,7 +36,7 @@ std::string generateRandomId(std::size_t bytes = 16) { std::string out; out.reserve(bytes * 2); - const char *hex = "0123456789abcdef"; + const char* hex = "0123456789abcdef"; for (std::size_t i = 0; i < bytes; ++i) { const int v = dist(rng); out.push_back(hex[(v >> 4) & 0xF]); @@ -46,11 +46,11 @@ std::string generateRandomId(std::size_t bytes = 16) { } // Split UTF-8 string into chunks of at most max_bytes, not breaking codepoints. -std::vector splitUtf8(const std::string &s, - std::size_t max_bytes) { +std::vector splitUtf8(const std::string& s, std::size_t max_bytes) { std::vector result; - if (s.empty()) + if (s.empty()) { return result; + } std::size_t i = 0; const std::size_t n = s.size(); @@ -60,13 +60,11 @@ std::vector splitUtf8(const std::string &s, // If end points into a UTF-8 continuation byte, walk back to a lead byte. // NOTE: end is an index into the string; ensure end < n before indexing. - while (end > i && end < n && - (static_cast(s[end]) & 0xC0) == 0x80) { + while (end > i && end < n && (static_cast(s[end]) & 0xC0) == 0x80) { --end; } // If end==n, we may still have landed on a continuation byte due to min(). - while (end > i && end == n && - (static_cast(s[end - 1]) & 0xC0) == 0x80) { + while (end > i && end == n && (static_cast(s[end - 1]) & 0xC0) == 0x80) { // Walk back until we hit a lead byte boundary. // This isn't perfect but is consistent with your earlier intent. --end; @@ -85,11 +83,9 @@ std::vector splitUtf8(const std::string &s, return result; } -void fillBaseInfo(BaseStreamInfo &dst, const std::string &stream_id, - const std::string &mime_type, const std::string &topic, - std::int64_t timestamp_ms, - const std::optional &total_size, - const std::map &attrs) { +void fillBaseInfo(BaseStreamInfo& dst, const std::string& stream_id, const std::string& mime_type, + const std::string& topic, std::int64_t timestamp_ms, const std::optional& total_size, + const std::map& attrs) { dst.stream_id = stream_id; dst.mime_type = mime_type; dst.topic = topic; @@ -104,24 +100,23 @@ void fillBaseInfo(BaseStreamInfo &dst, const std::string &stream_id, // Reader implementation // ===================================================================== -TextStreamReader::TextStreamReader(TextStreamInfo info) - : info_(std::move(info)) {} +TextStreamReader::TextStreamReader(TextStreamInfo info) : info_(std::move(info)) {} -void TextStreamReader::onChunkUpdate(const std::string &text) { +void TextStreamReader::onChunkUpdate(const std::string& text) { { const std::scoped_lock lock(mutex_); - if (closed_) + if (closed_) { return; + } queue_.push_back(text); } cv_.notify_one(); } -void TextStreamReader::onStreamClose( - const std::map &trailer_attrs) { +void TextStreamReader::onStreamClose(const std::map& trailer_attrs) { { const std::scoped_lock lock(mutex_); - for (const auto &kv : trailer_attrs) { + for (const auto& kv : trailer_attrs) { info_.attributes[kv.first] = kv.second; } closed_ = true; @@ -129,7 +124,7 @@ void TextStreamReader::onStreamClose( cv_.notify_all(); } -bool TextStreamReader::readNext(std::string &out) { +bool TextStreamReader::readNext(std::string& out) { std::unique_lock lock(mutex_); cv_.wait(lock, [this] { return !queue_.empty() || closed_; }); @@ -144,29 +139,29 @@ bool TextStreamReader::readNext(std::string &out) { std::string TextStreamReader::readAll() { std::string result; std::string chunk; - while (readNext(chunk)) + while (readNext(chunk)) { result += chunk; + } return result; } -ByteStreamReader::ByteStreamReader(ByteStreamInfo info) - : info_(std::move(info)) {} +ByteStreamReader::ByteStreamReader(ByteStreamInfo info) : info_(std::move(info)) {} -void ByteStreamReader::onChunkUpdate(const std::vector &bytes) { +void ByteStreamReader::onChunkUpdate(const std::vector& bytes) { { const std::scoped_lock lock(mutex_); - if (closed_) + if (closed_) { return; + } queue_.push_back(bytes); } cv_.notify_one(); } -void ByteStreamReader::onStreamClose( - const std::map &trailer_attrs) { +void ByteStreamReader::onStreamClose(const std::map& trailer_attrs) { { const std::scoped_lock lock(mutex_); - for (const auto &kv : trailer_attrs) { + for (const auto& kv : trailer_attrs) { info_.attributes[kv.first] = kv.second; } closed_ = true; @@ -174,7 +169,7 @@ void ByteStreamReader::onStreamClose( cv_.notify_all(); } -bool ByteStreamReader::readNext(std::vector &out) { +bool ByteStreamReader::readNext(std::vector& out) { std::unique_lock lock(mutex_); cv_.wait(lock, [this] { return !queue_.empty() || closed_; }); @@ -190,19 +185,19 @@ bool ByteStreamReader::readNext(std::vector &out) { // Writer implementation (uses your future-based FfiClient) // ===================================================================== -BaseStreamWriter::BaseStreamWriter( - LocalParticipant &local_participant, std::string topic, - std::map attributes, std::string stream_id, - std::optional total_size, std::string mime_type, - std::vector destination_identities, - std::string sender_identity) +BaseStreamWriter::BaseStreamWriter(LocalParticipant& local_participant, std::string topic, + std::map attributes, std::string stream_id, + std::optional total_size, std::string mime_type, + std::vector destination_identities, std::string sender_identity) : local_participant_(local_participant), stream_id_(stream_id.empty() ? generateRandomId() : std::move(stream_id)), - mime_type_(std::move(mime_type)), topic_(std::move(topic)), - timestamp_ms_(std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count()), - total_size_(total_size), attributes_(std::move(attributes)), + mime_type_(std::move(mime_type)), + topic_(std::move(topic)), + timestamp_ms_( + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count()), + total_size_(total_size), + attributes_(std::move(attributes)), destination_identities_(std::move(destination_identities)), sender_identity_(std::move(sender_identity)) { if (sender_identity_.empty()) { @@ -211,8 +206,9 @@ BaseStreamWriter::BaseStreamWriter( } void BaseStreamWriter::ensureHeaderSent() { - if (header_sent_) + if (header_sent_) { return; + } proto::DataStream::Header header; header.set_stream_id(stream_id_); header.set_timestamp(timestamp_ms_); @@ -222,13 +218,12 @@ void BaseStreamWriter::ensureHeaderSent() { if (total_size_.has_value()) { header.set_total_length(static_cast(*total_size_)); } - for (const auto &kv : attributes_) { + for (const auto& kv : attributes_) { (*header.mutable_attributes())[kv.first] = kv.second; } if (kind_ == StreamKind::kText) { - auto *th = header.mutable_text_header(); - th->set_operation_type( - proto::DataStream::OperationType::DataStream_OperationType_CREATE); + auto* th = header.mutable_text_header(); + th->set_operation_type(proto::DataStream::OperationType::DataStream_OperationType_CREATE); if (!reply_to_id_.empty()) { th->set_reply_to_stream_id(reply_to_id_); } @@ -237,15 +232,15 @@ void BaseStreamWriter::ensureHeaderSent() { } FfiClient::instance() - .sendStreamHeaderAsync(local_participant_.ffiHandleId(), header, - destination_identities_, sender_identity_) + .sendStreamHeaderAsync(local_participant_.ffiHandleId(), header, destination_identities_, sender_identity_) .get(); header_sent_ = true; } -void BaseStreamWriter::sendChunk(const std::vector &content) { - if (closed_) +void BaseStreamWriter::sendChunk(const std::vector& content) { + if (closed_) { throw std::runtime_error("Cannot send chunk after stream is closed"); + } ensureHeaderSent(); @@ -255,99 +250,83 @@ void BaseStreamWriter::sendChunk(const std::vector &content) { chunk.set_content(content.data(), content.size()); FfiClient::instance() - .sendStreamChunkAsync(local_participant_.ffiHandleId(), chunk, - destination_identities_, sender_identity_) + .sendStreamChunkAsync(local_participant_.ffiHandleId(), chunk, destination_identities_, sender_identity_) .get(); } -void BaseStreamWriter::sendTrailer( - const std::string &reason, - const std::map &attributes) { +void BaseStreamWriter::sendTrailer(const std::string& reason, const std::map& attributes) { ensureHeaderSent(); proto::DataStream::Trailer trailer; trailer.set_stream_id(stream_id_); trailer.set_reason(reason); - for (const auto &kv : attributes) { + for (const auto& kv : attributes) { (*trailer.mutable_attributes())[kv.first] = kv.second; } - FfiClient::instance() - .sendStreamTrailerAsync(local_participant_.ffiHandleId(), trailer, - sender_identity_) - .get(); + FfiClient::instance().sendStreamTrailerAsync(local_participant_.ffiHandleId(), trailer, sender_identity_).get(); } -void BaseStreamWriter::close( - const std::string &reason, - const std::map &attributes) { - if (closed_) +void BaseStreamWriter::close(const std::string& reason, const std::map& attributes) { + if (closed_) { throw std::runtime_error("Stream already closed"); + } closed_ = true; sendTrailer(reason, attributes); } -TextStreamWriter::TextStreamWriter( - LocalParticipant &local_participant, const std::string &topic, - const std::map &attributes, - const std::string &stream_id, std::optional total_size, - const std::string &reply_to_id, - const std::vector &destination_identities, - const std::string &sender_identity) - : BaseStreamWriter( - local_participant, topic, attributes, stream_id, total_size, - /*mime_type=*/"text/plain", destination_identities, sender_identity) { +TextStreamWriter::TextStreamWriter(LocalParticipant& local_participant, const std::string& topic, + const std::map& attributes, const std::string& stream_id, + std::optional total_size, const std::string& reply_to_id, + const std::vector& destination_identities, + const std::string& sender_identity) + : BaseStreamWriter(local_participant, topic, attributes, stream_id, total_size, + /*mime_type=*/"text/plain", destination_identities, sender_identity) { kind_ = StreamKind::kText; reply_to_id_ = reply_to_id; // ✅ Canonical user-facing metadata comes from BaseStreamWriter fields. - fillBaseInfo(info_, stream_id_, mime_type_, topic_, timestamp_ms_, - total_size_, attributes_); + fillBaseInfo(info_, stream_id_, mime_type_, topic_, timestamp_ms_, total_size_, attributes_); } -void TextStreamWriter::write(const std::string &text) { +void TextStreamWriter::write(const std::string& text) { const std::scoped_lock lock(write_mutex_); - if (closed_) + if (closed_) { throw std::runtime_error("Cannot write to closed TextStreamWriter"); + } - for (const auto &chunk_str : splitUtf8(text, kStreamChunkSize)) { - const auto *p = reinterpret_cast(chunk_str.data()); + for (const auto& chunk_str : splitUtf8(text, kStreamChunkSize)) { + const auto* p = reinterpret_cast(chunk_str.data()); const std::vector bytes(p, p + chunk_str.size()); LK_LOG_DEBUG("sending chunk"); sendChunk(bytes); } } -ByteStreamWriter::ByteStreamWriter( - LocalParticipant &local_participant, const std::string &name, - const std::string &topic, - const std::map &attributes, - const std::string &stream_id, std::optional total_size, - const std::string &mime_type, - const std::vector &destination_identities, - const std::string &sender_identity) - : BaseStreamWriter(local_participant, topic, attributes, stream_id, - total_size, mime_type, destination_identities, +ByteStreamWriter::ByteStreamWriter(LocalParticipant& local_participant, const std::string& name, + const std::string& topic, const std::map& attributes, + const std::string& stream_id, std::optional total_size, + const std::string& mime_type, const std::vector& destination_identities, + const std::string& sender_identity) + : BaseStreamWriter(local_participant, topic, attributes, stream_id, total_size, mime_type, destination_identities, sender_identity) { kind_ = StreamKind::kByte; byte_name_ = name; - fillBaseInfo(info_, stream_id_, mime_type_, topic_, timestamp_ms_, - total_size_, attributes_); + fillBaseInfo(info_, stream_id_, mime_type_, topic_, timestamp_ms_, total_size_, attributes_); info_.name = name; } -void ByteStreamWriter::write(const std::vector &data) { +void ByteStreamWriter::write(const std::vector& data) { const std::scoped_lock lock(write_mutex_); - if (closed_) + if (closed_) { throw std::runtime_error("Cannot write to closed ByteStreamWriter"); + } std::size_t offset = 0; while (offset < data.size()) { - const std::size_t n = - std::min(kStreamChunkSize, data.size() - offset); + const std::size_t n = std::min(kStreamChunkSize, data.size() - offset); auto it = data.begin() + static_cast(offset); - const std::vector chunk(it, - it + static_cast(n)); + const std::vector chunk(it, it + static_cast(n)); sendChunk(chunk); offset += n; } diff --git a/src/data_track_error.cpp b/src/data_track_error.cpp index 9926493c..3b107797 100644 --- a/src/data_track_error.cpp +++ b/src/data_track_error.cpp @@ -24,83 +24,77 @@ namespace { PublishDataTrackErrorCode fromProtoCode(proto::PublishDataTrackErrorCode code) { switch (code) { - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: - return PublishDataTrackErrorCode::INVALID_HANDLE; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_DUPLICATE_NAME: - return PublishDataTrackErrorCode::DUPLICATE_NAME; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_TIMEOUT: - return PublishDataTrackErrorCode::TIMEOUT; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_DISCONNECTED: - return PublishDataTrackErrorCode::DISCONNECTED; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_NOT_ALLOWED: - return PublishDataTrackErrorCode::NOT_ALLOWED; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_NAME: - return PublishDataTrackErrorCode::INVALID_NAME; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_LIMIT_REACHED: - return PublishDataTrackErrorCode::LIMIT_REACHED; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: - return PublishDataTrackErrorCode::PROTOCOL_ERROR; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_INTERNAL: - return PublishDataTrackErrorCode::INTERNAL; - case proto::PUBLISH_DATA_TRACK_ERROR_CODE_UNKNOWN: - default: - return PublishDataTrackErrorCode::UNKNOWN; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: + return PublishDataTrackErrorCode::INVALID_HANDLE; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_DUPLICATE_NAME: + return PublishDataTrackErrorCode::DUPLICATE_NAME; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_TIMEOUT: + return PublishDataTrackErrorCode::TIMEOUT; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_DISCONNECTED: + return PublishDataTrackErrorCode::DISCONNECTED; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_NOT_ALLOWED: + return PublishDataTrackErrorCode::NOT_ALLOWED; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_NAME: + return PublishDataTrackErrorCode::INVALID_NAME; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_LIMIT_REACHED: + return PublishDataTrackErrorCode::LIMIT_REACHED; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: + return PublishDataTrackErrorCode::PROTOCOL_ERROR; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_INTERNAL: + return PublishDataTrackErrorCode::INTERNAL; + case proto::PUBLISH_DATA_TRACK_ERROR_CODE_UNKNOWN: + default: + return PublishDataTrackErrorCode::UNKNOWN; } } -LocalDataTrackTryPushErrorCode -fromProtoCode(proto::LocalDataTrackTryPushErrorCode code) { +LocalDataTrackTryPushErrorCode fromProtoCode(proto::LocalDataTrackTryPushErrorCode code) { switch (code) { - case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INVALID_HANDLE: - return LocalDataTrackTryPushErrorCode::INVALID_HANDLE; - case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_TRACK_UNPUBLISHED: - return LocalDataTrackTryPushErrorCode::TRACK_UNPUBLISHED; - case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_QUEUE_FULL: - return LocalDataTrackTryPushErrorCode::QUEUE_FULL; - case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INTERNAL: - return LocalDataTrackTryPushErrorCode::INTERNAL; - case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_UNKNOWN: - default: - return LocalDataTrackTryPushErrorCode::UNKNOWN; + case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INVALID_HANDLE: + return LocalDataTrackTryPushErrorCode::INVALID_HANDLE; + case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_TRACK_UNPUBLISHED: + return LocalDataTrackTryPushErrorCode::TRACK_UNPUBLISHED; + case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_QUEUE_FULL: + return LocalDataTrackTryPushErrorCode::QUEUE_FULL; + case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INTERNAL: + return LocalDataTrackTryPushErrorCode::INTERNAL; + case proto::LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_UNKNOWN: + default: + return LocalDataTrackTryPushErrorCode::UNKNOWN; } } -SubscribeDataTrackErrorCode -fromProtoCode(proto::SubscribeDataTrackErrorCode code) { +SubscribeDataTrackErrorCode fromProtoCode(proto::SubscribeDataTrackErrorCode code) { switch (code) { - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: - return SubscribeDataTrackErrorCode::INVALID_HANDLE; - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNPUBLISHED: - return SubscribeDataTrackErrorCode::UNPUBLISHED; - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_TIMEOUT: - return SubscribeDataTrackErrorCode::TIMEOUT; - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_DISCONNECTED: - return SubscribeDataTrackErrorCode::DISCONNECTED; - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: - return SubscribeDataTrackErrorCode::PROTOCOL_ERROR; - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_INTERNAL: - return SubscribeDataTrackErrorCode::INTERNAL; - case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNKNOWN: - default: - return SubscribeDataTrackErrorCode::UNKNOWN; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: + return SubscribeDataTrackErrorCode::INVALID_HANDLE; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNPUBLISHED: + return SubscribeDataTrackErrorCode::UNPUBLISHED; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_TIMEOUT: + return SubscribeDataTrackErrorCode::TIMEOUT; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_DISCONNECTED: + return SubscribeDataTrackErrorCode::DISCONNECTED; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: + return SubscribeDataTrackErrorCode::PROTOCOL_ERROR; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_INTERNAL: + return SubscribeDataTrackErrorCode::INTERNAL; + case proto::SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNKNOWN: + default: + return SubscribeDataTrackErrorCode::UNKNOWN; } } } // namespace -PublishDataTrackError -PublishDataTrackError::fromProto(const proto::PublishDataTrackError &error) { +PublishDataTrackError PublishDataTrackError::fromProto(const proto::PublishDataTrackError& error) { return PublishDataTrackError{fromProtoCode(error.code()), error.message()}; } -LocalDataTrackTryPushError LocalDataTrackTryPushError::fromProto( - const proto::LocalDataTrackTryPushError &error) { - return LocalDataTrackTryPushError{fromProtoCode(error.code()), - error.message()}; +LocalDataTrackTryPushError LocalDataTrackTryPushError::fromProto(const proto::LocalDataTrackTryPushError& error) { + return LocalDataTrackTryPushError{fromProtoCode(error.code()), error.message()}; } -SubscribeDataTrackError SubscribeDataTrackError::fromProto( - const proto::SubscribeDataTrackError &error) { +SubscribeDataTrackError SubscribeDataTrackError::fromProto(const proto::SubscribeDataTrackError& error) { return SubscribeDataTrackError{fromProtoCode(error.code()), error.message()}; } diff --git a/src/data_track_frame.cpp b/src/data_track_frame.cpp index 99dc1268..9728272f 100644 --- a/src/data_track_frame.cpp +++ b/src/data_track_frame.cpp @@ -20,14 +20,11 @@ namespace livekit { -DataTrackFrame -DataTrackFrame::fromOwnedInfo(const proto::DataTrackFrame &owned) { +DataTrackFrame DataTrackFrame::fromOwnedInfo(const proto::DataTrackFrame& owned) { DataTrackFrame frame; - const auto &payload_str = owned.payload(); - frame.payload.assign( - reinterpret_cast(payload_str.data()), - reinterpret_cast(payload_str.data()) + - payload_str.size()); + const auto& payload_str = owned.payload(); + frame.payload.assign(reinterpret_cast(payload_str.data()), + reinterpret_cast(payload_str.data()) + payload_str.size()); if (owned.has_user_timestamp()) { frame.user_timestamp = owned.user_timestamp(); } diff --git a/src/data_track_stream.cpp b/src/data_track_stream.cpp index 30a355c8..277120de 100644 --- a/src/data_track_stream.cpp +++ b/src/data_track_stream.cpp @@ -16,13 +16,13 @@ #include "livekit/data_track_stream.h" +#include + #include "data_track.pb.h" #include "ffi.pb.h" #include "ffi_client.h" #include "lk_log.h" -#include - namespace livekit { using proto::FfiEvent; @@ -32,25 +32,23 @@ DataTrackStream::~DataTrackStream() { close(); } void DataTrackStream::init(FfiHandle subscription_handle) { subscription_handle_ = std::move(subscription_handle); - listener_id_ = FfiClient::instance().AddListener( - [this](const FfiEvent &e) { this->onFfiEvent(e); }); + listener_id_ = FfiClient::instance().AddListener([this](const FfiEvent& e) { this->onFfiEvent(e); }); } -bool DataTrackStream::read(DataTrackFrame &out) { +bool DataTrackStream::read(DataTrackFrame& out) { { const std::scoped_lock lock(mutex_); if (closed_ || eof_) { return false; } - const auto subscription_handle = - static_cast(subscription_handle_.get()); + const auto subscription_handle = static_cast(subscription_handle_.get()); // Signal the Rust side that we're ready to receive the next frame. // The Rust SubscriptionTask uses a demand-driven protocol: it won't pull // from the underlying stream until notified via this request. proto::FfiRequest req; - auto *msg = req.mutable_data_track_stream_read(); + auto* msg = req.mutable_data_track_stream_read(); msg->set_stream_handle(subscription_handle); FfiClient::instance().sendRequest(req); } @@ -87,22 +85,21 @@ void DataTrackStream::close() { cv_.notify_all(); } -void DataTrackStream::onFfiEvent(const FfiEvent &event) { +void DataTrackStream::onFfiEvent(const FfiEvent& event) { if (event.message_case() != FfiEvent::kDataTrackStreamEvent) { return; } - const auto &dts = event.data_track_stream_event(); + const auto& dts = event.data_track_stream_event(); { const std::scoped_lock lock(mutex_); - if (closed_ || dts.stream_handle() != - static_cast(subscription_handle_.get())) { + if (closed_ || dts.stream_handle() != static_cast(subscription_handle_.get())) { return; } } if (dts.has_frame_received()) { - const auto &fr = dts.frame_received().frame(); + const auto& fr = dts.frame_received().frame(); DataTrackFrame frame = DataTrackFrame::fromOwnedInfo(fr); pushFrame(std::move(frame)); } else if (dts.has_eos()) { @@ -110,7 +107,7 @@ void DataTrackStream::onFfiEvent(const FfiEvent &event) { } } -void DataTrackStream::pushFrame(DataTrackFrame &&frame) { +void DataTrackStream::pushFrame(DataTrackFrame&& frame) { const std::scoped_lock lock(mutex_); if (closed_ || eof_) { diff --git a/src/e2ee.cpp b/src/e2ee.cpp index ae46bf79..c1f8db2b 100644 --- a/src/e2ee.cpp +++ b/src/e2ee.cpp @@ -28,13 +28,11 @@ namespace livekit { namespace { -std::string bytesToString(const std::vector &v) { - return std::string(reinterpret_cast(v.data()), v.size()); +std::string bytesToString(const std::vector& v) { + return std::string(reinterpret_cast(v.data()), v.size()); } -std::vector stringToBytes(const std::string &s) { - return std::vector(s.begin(), s.end()); -} +std::vector stringToBytes(const std::string& s) { return std::vector(s.begin(), s.end()); } } // namespace @@ -42,26 +40,20 @@ std::vector stringToBytes(const std::string &s) { // KeyProvider // ============================================================================ -E2EEManager::KeyProvider::KeyProvider(std::uint64_t room_handle, - KeyProviderOptions options) +E2EEManager::KeyProvider::KeyProvider(std::uint64_t room_handle, KeyProviderOptions options) : room_handle_(room_handle), options_(std::move(options)) {} -const KeyProviderOptions &E2EEManager::KeyProvider::options() const { - return options_; -} +const KeyProviderOptions& E2EEManager::KeyProvider::options() const { return options_; } -void E2EEManager::KeyProvider::setSharedKey( - const std::vector &key, int key_index) { +void E2EEManager::KeyProvider::setSharedKey(const std::vector& key, int key_index) { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); req.mutable_e2ee()->mutable_set_shared_key()->set_key_index(key_index); - req.mutable_e2ee()->mutable_set_shared_key()->set_shared_key( - bytesToString(key)); + req.mutable_e2ee()->mutable_set_shared_key()->set_shared_key(bytesToString(key)); FfiClient::instance().sendRequest(req); } -std::vector -E2EEManager::KeyProvider::exportSharedKey(int key_index) const { +std::vector E2EEManager::KeyProvider::exportSharedKey(int key_index) const { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); req.mutable_e2ee()->mutable_get_shared_key()->set_key_index(key_index); @@ -69,8 +61,7 @@ E2EEManager::KeyProvider::exportSharedKey(int key_index) const { return stringToBytes(resp.e2ee().get_shared_key().key()); } -std::vector -E2EEManager::KeyProvider::ratchetSharedKey(int key_index) { +std::vector E2EEManager::KeyProvider::ratchetSharedKey(int key_index) { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); req.mutable_e2ee()->mutable_ratchet_shared_key()->set_key_index(key_index); @@ -78,37 +69,30 @@ E2EEManager::KeyProvider::ratchetSharedKey(int key_index) { return stringToBytes(resp.e2ee().ratchet_shared_key().new_key()); } -void E2EEManager::KeyProvider::setKey(const std::string &participant_identity, - const std::vector &key, +void E2EEManager::KeyProvider::setKey(const std::string& participant_identity, const std::vector& key, int key_index) { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); - req.mutable_e2ee()->mutable_set_key()->set_participant_identity( - participant_identity); + req.mutable_e2ee()->mutable_set_key()->set_participant_identity(participant_identity); req.mutable_e2ee()->mutable_set_key()->set_key_index(key_index); req.mutable_e2ee()->mutable_set_key()->set_key(bytesToString(key)); FfiClient::instance().sendRequest(req); } -std::vector -E2EEManager::KeyProvider::exportKey(const std::string &participant_identity, - int key_index) const { +std::vector E2EEManager::KeyProvider::exportKey(const std::string& participant_identity, + int key_index) const { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); - req.mutable_e2ee()->mutable_get_key()->set_participant_identity( - participant_identity); + req.mutable_e2ee()->mutable_get_key()->set_participant_identity(participant_identity); req.mutable_e2ee()->mutable_get_key()->set_key_index(key_index); auto resp = FfiClient::instance().sendRequest(req); return stringToBytes(resp.e2ee().get_key().key()); } -std::vector -E2EEManager::KeyProvider::ratchetKey(const std::string &participant_identity, - int key_index) { +std::vector E2EEManager::KeyProvider::ratchetKey(const std::string& participant_identity, int key_index) { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); - req.mutable_e2ee()->mutable_ratchet_key()->set_participant_identity( - participant_identity); + req.mutable_e2ee()->mutable_ratchet_key()->set_participant_identity(participant_identity); req.mutable_e2ee()->mutable_ratchet_key()->set_key_index(key_index); auto resp = FfiClient::instance().sendRequest(req); return stringToBytes(resp.e2ee().ratchet_key().new_key()); @@ -118,24 +102,21 @@ E2EEManager::KeyProvider::ratchetKey(const std::string &participant_identity, // FrameCryptor // ============================================================================ -E2EEManager::FrameCryptor::FrameCryptor(std::uint64_t room_handle, - std::string participant_identity, - int key_index, bool enabled) - : room_handle_(room_handle), enabled_(enabled), +E2EEManager::FrameCryptor::FrameCryptor(std::uint64_t room_handle, std::string participant_identity, int key_index, + bool enabled) + : room_handle_(room_handle), + enabled_(enabled), participant_identity_(std::move(participant_identity)), key_index_(key_index) {} -const std::string &E2EEManager::FrameCryptor::participantIdentity() const { - return participant_identity_; -} +const std::string& E2EEManager::FrameCryptor::participantIdentity() const { return participant_identity_; } int E2EEManager::FrameCryptor::keyIndex() const { return key_index_; } bool E2EEManager::FrameCryptor::enabled() const { return enabled_; } void E2EEManager::FrameCryptor::setEnabled(bool enabled) { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); - req.mutable_e2ee()->mutable_cryptor_set_enabled()->set_participant_identity( - participant_identity_); + req.mutable_e2ee()->mutable_cryptor_set_enabled()->set_participant_identity(participant_identity_); req.mutable_e2ee()->mutable_cryptor_set_enabled()->set_enabled(enabled); FfiClient::instance().sendRequest(req); } @@ -143,8 +124,7 @@ void E2EEManager::FrameCryptor::setEnabled(bool enabled) { void E2EEManager::FrameCryptor::setKeyIndex(int key_index) { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); - req.mutable_e2ee()->mutable_cryptor_set_key_index()->set_participant_identity( - participant_identity_); + req.mutable_e2ee()->mutable_cryptor_set_key_index()->set_participant_identity(participant_identity_); req.mutable_e2ee()->mutable_cryptor_set_key_index()->set_key_index(key_index); FfiClient::instance().sendRequest(req); } @@ -153,7 +133,7 @@ void E2EEManager::FrameCryptor::setKeyIndex(int key_index) { // E2EEManager // ============================================================================ -E2EEManager::E2EEManager(std::uint64_t room_handle, const E2EEOptions &options) +E2EEManager::E2EEManager(std::uint64_t room_handle, const E2EEOptions& options) : room_handle_(room_handle), enabled_(true), // or false, depending on your desired default behavior options_(options), @@ -169,21 +149,18 @@ void E2EEManager::setEnabled(bool enabled) { enabled_ = enabled; } -E2EEManager::KeyProvider *E2EEManager::keyProvider() { return &key_provider_; } -const E2EEManager::KeyProvider *E2EEManager::keyProvider() const { - return &key_provider_; -} +E2EEManager::KeyProvider* E2EEManager::keyProvider() { return &key_provider_; } +const E2EEManager::KeyProvider* E2EEManager::keyProvider() const { return &key_provider_; } std::vector E2EEManager::frameCryptors() const { proto::FfiRequest req; req.mutable_e2ee()->set_room_handle(room_handle_); auto resp = FfiClient::instance().sendRequest(req); std::vector out; - const auto &list = resp.e2ee().manager_get_frame_cryptors().frame_cryptors(); + const auto& list = resp.e2ee().manager_get_frame_cryptors().frame_cryptors(); out.reserve(static_cast(list.size())); - for (const auto &fc : list) { - out.emplace_back(room_handle_, fc.participant_identity(), fc.key_index(), - fc.enabled()); + for (const auto& fc : list) { + out.emplace_back(room_handle_, fc.participant_identity(), fc.key_index(), fc.enabled()); } return out; } diff --git a/src/ffi_client.cpp b/src/ffi_client.cpp index c6480cd2..9d7bf76e 100644 --- a/src/ffi_client.cpp +++ b/src/ffi_client.cpp @@ -14,12 +14,13 @@ * limitations under the License. */ +#include "ffi_client.h" + #include #include "data_track.pb.h" #include "e2ee.pb.h" #include "ffi.pb.h" -#include "ffi_client.h" #include "livekit/build.h" #include "livekit/data_track_error.h" #include "livekit/e2ee.h" @@ -36,104 +37,104 @@ namespace livekit { namespace { -std::string bytesToString(const std::vector &b) { - return std::string(reinterpret_cast(b.data()), b.size()); +std::string bytesToString(const std::vector& b) { + return std::string(reinterpret_cast(b.data()), b.size()); } -inline void logAndThrow(const std::string &error_msg) { +inline void logAndThrow(const std::string& error_msg) { LK_LOG_ERROR("LiveKit SDK Error: {}", error_msg); throw std::runtime_error(error_msg); } -std::optional ExtractAsyncId(const proto::FfiEvent &event) { +std::optional ExtractAsyncId(const proto::FfiEvent& event) { using E = proto::FfiEvent; switch (event.message_case()) { - case E::kConnect: - return event.connect().async_id(); - case E::kDisconnect: - return event.disconnect().async_id(); - case E::kDispose: - return event.dispose().async_id(); - case E::kPublishTrack: - return event.publish_track().async_id(); - case E::kUnpublishTrack: - return event.unpublish_track().async_id(); - case E::kPublishData: - return event.publish_data().async_id(); - case E::kPublishTranscription: - return event.publish_transcription().async_id(); - case E::kCaptureAudioFrame: - return event.capture_audio_frame().async_id(); - case E::kSetLocalMetadata: - return event.set_local_metadata().async_id(); - case E::kSetLocalName: - return event.set_local_name().async_id(); - case E::kSetLocalAttributes: - return event.set_local_attributes().async_id(); - case E::kGetStats: - return event.get_stats().async_id(); - case E::kGetSessionStats: - return event.get_session_stats().async_id(); - case E::kPublishSipDtmf: - return event.publish_sip_dtmf().async_id(); - case E::kChatMessage: - return event.chat_message().async_id(); - case E::kPerformRpc: - return event.perform_rpc().async_id(); - - // low-level data stream callbacks - case E::kSendStreamHeader: - return event.send_stream_header().async_id(); - case E::kSendStreamChunk: - return event.send_stream_chunk().async_id(); - case E::kSendStreamTrailer: - return event.send_stream_trailer().async_id(); - - // high-level - case E::kByteStreamReaderReadAll: - return event.byte_stream_reader_read_all().async_id(); - case E::kByteStreamReaderWriteToFile: - return event.byte_stream_reader_write_to_file().async_id(); - case E::kByteStreamOpen: - return event.byte_stream_open().async_id(); - case E::kByteStreamWriterWrite: - return event.byte_stream_writer_write().async_id(); - case E::kByteStreamWriterClose: - return event.byte_stream_writer_close().async_id(); - case E::kSendFile: - return event.send_file().async_id(); - - case E::kTextStreamReaderReadAll: - return event.text_stream_reader_read_all().async_id(); - case E::kTextStreamOpen: - return event.text_stream_open().async_id(); - case E::kTextStreamWriterWrite: - return event.text_stream_writer_write().async_id(); - case E::kTextStreamWriterClose: - return event.text_stream_writer_close().async_id(); - case E::kSendText: - return event.send_text().async_id(); - case E::kSendBytes: - return event.send_bytes().async_id(); - - // data track async completions - case E::kPublishDataTrack: - return event.publish_data_track().async_id(); - - // NOT async completion: - case E::kRoomEvent: - case E::kTrackEvent: - case E::kVideoStreamEvent: - case E::kAudioStreamEvent: - case E::kByteStreamReaderEvent: - case E::kTextStreamReaderEvent: - case E::kDataTrackStreamEvent: - case E::kRpcMethodInvocation: - case E::kLogs: - case E::kPanic: - case E::MESSAGE_NOT_SET: - default: - return std::nullopt; + case E::kConnect: + return event.connect().async_id(); + case E::kDisconnect: + return event.disconnect().async_id(); + case E::kDispose: + return event.dispose().async_id(); + case E::kPublishTrack: + return event.publish_track().async_id(); + case E::kUnpublishTrack: + return event.unpublish_track().async_id(); + case E::kPublishData: + return event.publish_data().async_id(); + case E::kPublishTranscription: + return event.publish_transcription().async_id(); + case E::kCaptureAudioFrame: + return event.capture_audio_frame().async_id(); + case E::kSetLocalMetadata: + return event.set_local_metadata().async_id(); + case E::kSetLocalName: + return event.set_local_name().async_id(); + case E::kSetLocalAttributes: + return event.set_local_attributes().async_id(); + case E::kGetStats: + return event.get_stats().async_id(); + case E::kGetSessionStats: + return event.get_session_stats().async_id(); + case E::kPublishSipDtmf: + return event.publish_sip_dtmf().async_id(); + case E::kChatMessage: + return event.chat_message().async_id(); + case E::kPerformRpc: + return event.perform_rpc().async_id(); + + // low-level data stream callbacks + case E::kSendStreamHeader: + return event.send_stream_header().async_id(); + case E::kSendStreamChunk: + return event.send_stream_chunk().async_id(); + case E::kSendStreamTrailer: + return event.send_stream_trailer().async_id(); + + // high-level + case E::kByteStreamReaderReadAll: + return event.byte_stream_reader_read_all().async_id(); + case E::kByteStreamReaderWriteToFile: + return event.byte_stream_reader_write_to_file().async_id(); + case E::kByteStreamOpen: + return event.byte_stream_open().async_id(); + case E::kByteStreamWriterWrite: + return event.byte_stream_writer_write().async_id(); + case E::kByteStreamWriterClose: + return event.byte_stream_writer_close().async_id(); + case E::kSendFile: + return event.send_file().async_id(); + + case E::kTextStreamReaderReadAll: + return event.text_stream_reader_read_all().async_id(); + case E::kTextStreamOpen: + return event.text_stream_open().async_id(); + case E::kTextStreamWriterWrite: + return event.text_stream_writer_write().async_id(); + case E::kTextStreamWriterClose: + return event.text_stream_writer_close().async_id(); + case E::kSendText: + return event.send_text().async_id(); + case E::kSendBytes: + return event.send_bytes().async_id(); + + // data track async completions + case E::kPublishDataTrack: + return event.publish_data_track().async_id(); + + // NOT async completion: + case E::kRoomEvent: + case E::kTrackEvent: + case E::kVideoStreamEvent: + case E::kAudioStreamEvent: + case E::kByteStreamReaderEvent: + case E::kTextStreamReaderEvent: + case E::kDataTrackStreamEvent: + case E::kRpcMethodInvocation: + case E::kLogs: + case E::kPanic: + case E::MESSAGE_NOT_SET: + default: + return std::nullopt; } } @@ -161,17 +162,13 @@ bool FfiClient::initialize(bool capture_logs) { return false; } initialized_.store(true, std::memory_order_release); - livekit_ffi_initialize(&LivekitFfiCallback, capture_logs, - LIVEKIT_BUILD_FLAVOR, LIVEKIT_BUILD_VERSION_FULL); + livekit_ffi_initialize(&LivekitFfiCallback, capture_logs, LIVEKIT_BUILD_FLAVOR, LIVEKIT_BUILD_VERSION_FULL); return true; } -bool FfiClient::isInitialized() const noexcept { - return initialized_.load(std::memory_order_acquire); -} +bool FfiClient::isInitialized() const noexcept { return initialized_.load(std::memory_order_acquire); } -FfiClient::ListenerId -FfiClient::AddListener(const FfiClient::Listener &listener) { +FfiClient::ListenerId FfiClient::AddListener(const FfiClient::Listener& listener) { const std::scoped_lock guard(lock_); const FfiClient::ListenerId id = next_listener_id++; listeners_[id] = listener; @@ -183,20 +180,17 @@ void FfiClient::RemoveListener(ListenerId id) { listeners_.erase(id); } -proto::FfiResponse -FfiClient::sendRequest(const proto::FfiRequest &request) const { +proto::FfiResponse FfiClient::sendRequest(const proto::FfiRequest& request) const { std::string bytes; if (!request.SerializeToString(&bytes) || bytes.empty()) { throw std::runtime_error("failed to serialize FfiRequest"); } - const uint8_t *resp_ptr = nullptr; + const uint8_t* resp_ptr = nullptr; size_t resp_len = 0; const FfiHandleId handle = - livekit_ffi_request(reinterpret_cast(bytes.data()), - bytes.size(), &resp_ptr, &resp_len); + livekit_ffi_request(reinterpret_cast(bytes.data()), bytes.size(), &resp_ptr, &resp_len); if (handle == INVALID_HANDLE) { - throw std::runtime_error( - "failed to send request, received an invalid handle"); + throw std::runtime_error("failed to send request, received an invalid handle"); } // Ensure we drop the handle exactly once on all paths @@ -212,7 +206,7 @@ FfiClient::sendRequest(const proto::FfiRequest &request) const { return response; } -void FfiClient::PushEvent(const proto::FfiEvent &event) const { +void FfiClient::PushEvent(const proto::FfiEvent& event) const { std::unique_ptr to_complete; std::vector listeners_copy; { @@ -221,8 +215,7 @@ void FfiClient::PushEvent(const proto::FfiEvent &event) const { // Complete pending future if this event is a callback with async_id if (auto async_id = ExtractAsyncId(event)) { auto it = pending_by_id_.find(*async_id); - if (it != pending_by_id_.end() && it->second && - it->second->matches(event)) { + if (it != pending_by_id_.end() && it->second && it->second->matches(event)) { to_complete = std::move(it->second); pending_by_id_.erase(it); } @@ -230,7 +223,7 @@ void FfiClient::PushEvent(const proto::FfiEvent &event) const { // Snapshot listeners listeners_copy.reserve(listeners_.size()); - for (const auto &kv : listeners_) { + for (const auto& kv : listeners_) { listeners_copy.push_back(kv.second); } } @@ -240,23 +233,20 @@ void FfiClient::PushEvent(const proto::FfiEvent &event) const { } // Notify listeners outside lock - for (auto &listener : listeners_copy) { + for (auto& listener : listeners_copy) { listener(event); } } -void LivekitFfiCallback(const uint8_t *buf, size_t len) { +void LivekitFfiCallback(const uint8_t* buf, size_t len) { proto::FfiEvent event; - event.ParseFromArray( - buf, static_cast( - len)); // TODO: this fixes for now, what if len exceeds int? + event.ParseFromArray(buf, + static_cast(len)); // TODO: this fixes for now, what if len exceeds int? FfiClient::instance().PushEvent(event); } -FfiClient::AsyncId FfiClient::generateAsyncId() { - return next_async_id_.fetch_add(1, std::memory_order_relaxed); -} +FfiClient::AsyncId FfiClient::generateAsyncId() { return next_async_id_.fetch_add(1, std::memory_order_relaxed); } bool FfiClient::cancelPendingByAsyncId(AsyncId async_id) { std::unique_ptr to_cancel; @@ -276,9 +266,8 @@ bool FfiClient::cancelPendingByAsyncId(AsyncId async_id) { } template -std::future FfiClient::registerAsync( - AsyncId async_id, std::function match, - std::function &)> handler) { +std::future FfiClient::registerAsync(AsyncId async_id, std::function match, + std::function&)> handler) { auto pending = std::make_unique>(); pending->async_id = async_id; auto fut = pending->promise.get_future(); @@ -292,10 +281,8 @@ std::future FfiClient::registerAsync( } // Room APIs Implementation -std::future -FfiClient::connectAsync(const std::string &url, const std::string &token, - const RoomOptions &options) { - +std::future FfiClient::connectAsync(const std::string& url, const std::string& token, + const RoomOptions& options) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); @@ -303,16 +290,14 @@ FfiClient::connectAsync(const std::string &url, const std::string &token, auto fut = registerAsync( async_id, // match lambda: is this the connect event with our async_id? - [async_id](const proto::FfiEvent &event) { + [async_id](const proto::FfiEvent& event) { return event.has_connect() && event.connect().async_id() == async_id; }, // handler lambda: fill the promise with RoomInfo or an exception - [](const proto::FfiEvent &event, - std::promise &pr) { - const auto &connectCb = event.connect(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& connectCb = event.connect(); if (!connectCb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(connectCb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(connectCb.error()))); return; } @@ -321,29 +306,28 @@ FfiClient::connectAsync(const std::string &url, const std::string &token, // Build and send the request proto::FfiRequest req; - auto *connect = req.mutable_connect(); + auto* connect = req.mutable_connect(); connect->set_url(url); connect->set_token(token); connect->set_request_async_id(async_id); - auto *opts = connect->mutable_options(); + auto* opts = connect->mutable_options(); opts->set_auto_subscribe(options.auto_subscribe); opts->set_dynacast(options.dynacast); opts->set_single_peer_connection(options.single_peer_connection); - LK_LOG_DEBUG("[FfiClient] connectAsync: auto_subscribe={}, dynacast={}, " - "single_peer_connection={}", - options.auto_subscribe, options.dynacast, - options.single_peer_connection); + LK_LOG_DEBUG( + "[FfiClient] connectAsync: auto_subscribe={}, dynacast={}, " + "single_peer_connection={}", + options.auto_subscribe, options.dynacast, options.single_peer_connection); // --- E2EE / encryption (optional) --- if (options.encryption.has_value()) { - const E2EEOptions &e2ee = *options.encryption; - const auto &kpo = e2ee.key_provider_options; + const E2EEOptions& e2ee = *options.encryption; + const auto& kpo = e2ee.key_provider_options; - auto *enc = opts->mutable_encryption(); - enc->set_encryption_type( - static_cast(e2ee.encryption_type)); - auto *kp = enc->mutable_key_provider_options(); + auto* enc = opts->mutable_encryption(); + enc->set_encryption_type(static_cast(e2ee.encryption_type)); + auto* kp = enc->mutable_key_provider_options(); // shared_key is optional. If not set, leave the field unset/cleared. if (kpo.shared_key && !kpo.shared_key->empty()) { kp->set_shared_key(bytesToString(*kpo.shared_key)); @@ -354,10 +338,8 @@ FfiClient::connectAsync(const std::string &url, const std::string &token, // uses default. if (!kpo.ratchet_salt.empty() && kpo.ratchet_salt != - std::vector( - kDefaultRatchetSalt, - kDefaultRatchetSalt + - std::char_traits::length(kDefaultRatchetSalt))) { + std::vector(kDefaultRatchetSalt, + kDefaultRatchetSalt + std::char_traits::length(kDefaultRatchetSalt))) { kp->set_ratchet_salt(bytesToString(kpo.ratchet_salt)); } else { kp->clear_ratchet_salt(); @@ -378,17 +360,14 @@ FfiClient::connectAsync(const std::string &url, const std::string &token, // --- RTC configuration (optional) --- if (options.rtc_config.has_value()) { - const RtcConfig &rc = *options.rtc_config; - auto *rtc = opts->mutable_rtc_config(); + const RtcConfig& rc = *options.rtc_config; + auto* rtc = opts->mutable_rtc_config(); - rtc->set_ice_transport_type( - static_cast(rc.ice_transport_type)); - rtc->set_continual_gathering_policy( - static_cast( - rc.continual_gathering_policy)); + rtc->set_ice_transport_type(static_cast(rc.ice_transport_type)); + rtc->set_continual_gathering_policy(static_cast(rc.continual_gathering_policy)); - for (const IceServer &ice : rc.ice_servers) { - auto *s = rtc->add_ice_servers(); + for (const IceServer& ice : rc.ice_servers) { + auto* s = rtc->add_ice_servers(); // proto: repeated string urls = 1 if (!ice.url.empty()) { @@ -418,8 +397,7 @@ FfiClient::connectAsync(const std::string &url, const std::string &token, } // Track APIs Implementation -std::future> -FfiClient::getTrackStatsAsync(uintptr_t track_handle) { +std::future> FfiClient::getTrackStatsAsync(uintptr_t track_handle) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); @@ -427,24 +405,21 @@ FfiClient::getTrackStatsAsync(uintptr_t track_handle) { auto fut = registerAsync>( async_id, // match - [async_id](const proto::FfiEvent &event) { - return event.has_get_stats() && - event.get_stats().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_get_stats() && event.get_stats().async_id() == async_id; }, // handler - [](const proto::FfiEvent &event, - std::promise> &pr) { - const auto &gs = event.get_stats(); + [](const proto::FfiEvent& event, std::promise>& pr) { + const auto& gs = event.get_stats(); if (!gs.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(gs.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(gs.error()))); return; } std::vector stats_vec; stats_vec.reserve(gs.stats_size()); - for (const auto &ps : gs.stats()) { + for (const auto& ps : gs.stats()) { stats_vec.push_back(fromProto(ps)); } pr.set_value(std::move(stats_vec)); @@ -452,7 +427,7 @@ FfiClient::getTrackStatsAsync(uintptr_t track_handle) { // Build and send the request proto::FfiRequest req; - auto *get_stats_req = req.mutable_get_stats(); + auto* get_stats_req = req.mutable_get_stats(); get_stats_req->set_track_handle(track_handle); get_stats_req->set_request_async_id(async_id); @@ -470,10 +445,9 @@ FfiClient::getTrackStatsAsync(uintptr_t track_handle) { } // Participant APIs Implementation -std::future -FfiClient::publishTrackAsync(std::uint64_t local_participant_handle, - std::uint64_t track_handle, - const TrackPublishOptions &options) { +std::future FfiClient::publishTrackAsync(std::uint64_t local_participant_handle, + std::uint64_t track_handle, + const TrackPublishOptions& options) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); @@ -481,35 +455,31 @@ FfiClient::publishTrackAsync(std::uint64_t local_participant_handle, auto fut = registerAsync( async_id, // Match: is this our PublishTrackCallback? - [async_id](const proto::FfiEvent &event) { - return event.has_publish_track() && - event.publish_track().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_publish_track() && event.publish_track().async_id() == async_id; }, // Handler: resolve with publication or throw error - [](const proto::FfiEvent &event, - std::promise &pr) { - const auto &cb = event.publish_track(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.publish_track(); // Oneof message { string error = 2; OwnedTrackPublication publication = // 3; } if (cb.has_error() && !cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } if (!cb.has_publication()) { - pr.set_exception(std::make_exception_ptr( - std::runtime_error("PublishTrackCallback missing publication"))); + pr.set_exception(std::make_exception_ptr(std::runtime_error("PublishTrackCallback missing publication"))); return; } - const proto::OwnedTrackPublication &pub = cb.publication(); + const proto::OwnedTrackPublication& pub = cb.publication(); pr.set_value(pub); }); // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_publish_track(); + auto* msg = req.mutable_publish_track(); msg->set_local_participant_handle(local_participant_handle); msg->set_track_handle(track_handle); msg->set_request_async_id(async_id); @@ -529,25 +499,21 @@ FfiClient::publishTrackAsync(std::uint64_t local_participant_handle, return fut; } -std::future -FfiClient::unpublishTrackAsync(std::uint64_t local_participant_handle, - const std::string &track_sid, - bool stop_on_unpublish) { +std::future FfiClient::unpublishTrackAsync(std::uint64_t local_participant_handle, const std::string& track_sid, + bool stop_on_unpublish) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &event) { - return event.has_unpublish_track() && - event.unpublish_track().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_unpublish_track() && event.unpublish_track().async_id() == async_id; }, - [](const proto::FfiEvent &event, std::promise &pr) { - const auto &cb = event.unpublish_track(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.unpublish_track(); if (cb.has_error() && !cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -555,7 +521,7 @@ FfiClient::unpublishTrackAsync(std::uint64_t local_participant_handle, // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_unpublish_track(); + auto* msg = req.mutable_unpublish_track(); msg->set_local_participant_handle(local_participant_handle); msg->set_track_sid(track_sid); msg->set_stop_on_unpublish(stop_on_unpublish); @@ -574,26 +540,23 @@ FfiClient::unpublishTrackAsync(std::uint64_t local_participant_handle, return fut; } -std::future FfiClient::publishDataAsync( - std::uint64_t local_participant_handle, const std::uint8_t *data_ptr, - std::uint64_t data_len, bool reliable, - const std::vector &destination_identities, - const std::string &topic) { +std::future FfiClient::publishDataAsync(std::uint64_t local_participant_handle, const std::uint8_t* data_ptr, + std::uint64_t data_len, bool reliable, + const std::vector& destination_identities, + const std::string& topic) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &event) { - return event.has_publish_data() && - event.publish_data().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_publish_data() && event.publish_data().async_id() == async_id; }, - [](const proto::FfiEvent &event, std::promise &pr) { - const auto &cb = event.publish_data(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.publish_data(); if (cb.has_error() && !cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -601,14 +564,14 @@ std::future FfiClient::publishDataAsync( // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_publish_data(); + auto* msg = req.mutable_publish_data(); msg->set_local_participant_handle(local_participant_handle); msg->set_data_ptr(reinterpret_cast(data_ptr)); msg->set_data_len(data_len); msg->set_reliable(reliable); msg->set_topic(topic); msg->set_request_async_id(async_id); - for (const auto &id : destination_identities) { + for (const auto& id : destination_identities) { msg->add_destination_identities(id); } @@ -625,43 +588,32 @@ std::future FfiClient::publishDataAsync( return fut; } -std::future> -FfiClient::publishDataTrackAsync(std::uint64_t local_participant_handle, - const std::string &track_name) { +std::future> FfiClient::publishDataTrackAsync( + std::uint64_t local_participant_handle, const std::string& track_name) { const AsyncId async_id = generateAsyncId(); - auto fut = registerAsync< - Result>( + auto fut = registerAsync>( async_id, - [async_id](const proto::FfiEvent &event) { - return event.has_publish_data_track() && - event.publish_data_track().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_publish_data_track() && event.publish_data_track().async_id() == async_id; }, - [](const proto::FfiEvent &event, - std::promise> - &pr) { - const auto &cb = event.publish_data_track(); + [](const proto::FfiEvent& event, std::promise>& pr) { + const auto& cb = event.publish_data_track(); if (cb.has_error()) { - pr.set_value( - Result:: - failure(PublishDataTrackError::fromProto(cb.error()))); + pr.set_value(Result::failure( + PublishDataTrackError::fromProto(cb.error()))); return; } if (!cb.has_track()) { - pr.set_value( - Result::failure(PublishDataTrackError{ - PublishDataTrackErrorCode::PROTOCOL_ERROR, - "PublishDataTrackCallback missing track"})); + pr.set_value(Result::failure(PublishDataTrackError{ + PublishDataTrackErrorCode::PROTOCOL_ERROR, "PublishDataTrackCallback missing track"})); return; } - pr.set_value( - Result::success( - cb.track())); + pr.set_value(Result::success(cb.track())); }); proto::FfiRequest req; - auto *msg = req.mutable_publish_data_track(); + auto* msg = req.mutable_publish_data_track(); msg->set_local_participant_handle(local_participant_handle); msg->mutable_options()->set_name(track_name); msg->set_request_async_id(async_id); @@ -670,34 +622,28 @@ FfiClient::publishDataTrackAsync(std::uint64_t local_participant_handle, const proto::FfiResponse resp = sendRequest(req); if (!resp.has_publish_data_track()) { cancelPendingByAsyncId(async_id); - std::promise> - pr; - pr.set_value( - Result::failure( - PublishDataTrackError{PublishDataTrackErrorCode::PROTOCOL_ERROR, - "FfiResponse missing publish_data_track"})); + std::promise> pr; + pr.set_value(Result::failure( + PublishDataTrackError{PublishDataTrackErrorCode::PROTOCOL_ERROR, "FfiResponse missing publish_data_track"})); return pr.get_future(); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { cancelPendingByAsyncId(async_id); std::promise> pr; - pr.set_value( - Result::failure( - PublishDataTrackError{PublishDataTrackErrorCode::INTERNAL, - e.what()})); + pr.set_value(Result::failure( + PublishDataTrackError{PublishDataTrackErrorCode::INTERNAL, e.what()})); return pr.get_future(); } return fut; } -Result -FfiClient::subscribeDataTrack(std::uint64_t track_handle, - std::optional buffer_size) { +Result FfiClient::subscribeDataTrack( + std::uint64_t track_handle, std::optional buffer_size) { proto::FfiRequest req; - auto *msg = req.mutable_subscribe_data_track(); + auto* msg = req.mutable_subscribe_data_track(); msg->set_track_handle(track_handle); - auto *opts = msg->mutable_options(); + auto* opts = msg->mutable_options(); if (buffer_size.has_value()) { opts->set_buffer_size(buffer_size.value()); } @@ -705,46 +651,37 @@ FfiClient::subscribeDataTrack(std::uint64_t track_handle, try { const proto::FfiResponse resp = sendRequest(req); if (!resp.has_subscribe_data_track()) { - return Result::failure(SubscribeDataTrackError{ - SubscribeDataTrackErrorCode::PROTOCOL_ERROR, - "FfiResponse missing subscribe_data_track"}); + return Result::failure(SubscribeDataTrackError{ + SubscribeDataTrackErrorCode::PROTOCOL_ERROR, "FfiResponse missing subscribe_data_track"}); } if (!resp.subscribe_data_track().has_stream()) { - return Result::failure(SubscribeDataTrackError{ - SubscribeDataTrackErrorCode::PROTOCOL_ERROR, - "FfiResponse subscribe_data_track missing stream"}); + return Result::failure(SubscribeDataTrackError{ + SubscribeDataTrackErrorCode::PROTOCOL_ERROR, "FfiResponse subscribe_data_track missing stream"}); } proto::OwnedDataTrackStream sub = resp.subscribe_data_track().stream(); - return Result::success(std::move(sub)); - } catch (const std::exception &e) { // NOLINT(bugprone-empty-catch) - return Result::failure(SubscribeDataTrackError{ - SubscribeDataTrackErrorCode::INTERNAL, e.what()}); + return Result::success(std::move(sub)); + } catch (const std::exception& e) { // NOLINT(bugprone-empty-catch) + return Result::failure( + SubscribeDataTrackError{SubscribeDataTrackErrorCode::INTERNAL, e.what()}); } } -std::future FfiClient::publishSipDtmfAsync( - std::uint64_t local_participant_handle, std::uint32_t code, - const std::string &digit, - const std::vector &destination_identities) { +std::future FfiClient::publishSipDtmfAsync(std::uint64_t local_participant_handle, std::uint32_t code, + const std::string& digit, + const std::vector& destination_identities) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &event) { - return event.has_publish_sip_dtmf() && - event.publish_sip_dtmf().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_publish_sip_dtmf() && event.publish_sip_dtmf().async_id() == async_id; }, - [](const proto::FfiEvent &event, std::promise &pr) { - const auto &cb = event.publish_sip_dtmf(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.publish_sip_dtmf(); if (cb.has_error() && !cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -752,12 +689,12 @@ std::future FfiClient::publishSipDtmfAsync( // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_publish_sip_dtmf(); + auto* msg = req.mutable_publish_sip_dtmf(); msg->set_local_participant_handle(local_participant_handle); msg->set_code(code); msg->set_digit(digit); msg->set_request_async_id(async_id); - for (const auto &id : destination_identities) { + for (const auto& id : destination_identities) { msg->add_destination_identities(id); } @@ -774,24 +711,21 @@ std::future FfiClient::publishSipDtmfAsync( return fut; } -std::future -FfiClient::setLocalMetadataAsync(std::uint64_t local_participant_handle, - const std::string &metadata) { +std::future FfiClient::setLocalMetadataAsync(std::uint64_t local_participant_handle, + const std::string& metadata) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &event) { - return event.has_set_local_metadata() && - event.set_local_metadata().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_set_local_metadata() && event.set_local_metadata().async_id() == async_id; }, - [](const proto::FfiEvent &event, std::promise &pr) { - const auto &cb = event.set_local_metadata(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.set_local_metadata(); if (cb.has_error() && !cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -799,7 +733,7 @@ FfiClient::setLocalMetadataAsync(std::uint64_t local_participant_handle, // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_set_local_metadata(); + auto* msg = req.mutable_set_local_metadata(); msg->set_local_participant_handle(local_participant_handle); msg->set_metadata(metadata); msg->set_request_async_id(async_id); @@ -817,9 +751,8 @@ FfiClient::setLocalMetadataAsync(std::uint64_t local_participant_handle, return fut; } -std::future -FfiClient::captureAudioFrameAsync(std::uint64_t source_handle, - const proto::AudioFrameBufferInfo &buffer) { +std::future FfiClient::captureAudioFrameAsync(std::uint64_t source_handle, + const proto::AudioFrameBufferInfo& buffer) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); @@ -827,16 +760,14 @@ FfiClient::captureAudioFrameAsync(std::uint64_t source_handle, auto fut = registerAsync( async_id, // match predicate - [async_id](const proto::FfiEvent &event) { - return event.has_capture_audio_frame() && - event.capture_audio_frame().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_capture_audio_frame() && event.capture_audio_frame().async_id() == async_id; }, // completion handler - [](const proto::FfiEvent &event, std::promise &pr) { - const auto &cb = event.capture_audio_frame(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.capture_audio_frame(); if (cb.has_error() && !cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -844,7 +775,7 @@ FfiClient::captureAudioFrameAsync(std::uint64_t source_handle, // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_capture_audio_frame(); + auto* msg = req.mutable_capture_audio_frame(); msg->set_source_handle(source_handle); msg->set_request_async_id(async_id); msg->mutable_buffer()->CopyFrom(buffer); @@ -862,12 +793,10 @@ FfiClient::captureAudioFrameAsync(std::uint64_t source_handle, return fut; } -std::future -FfiClient::performRpcAsync(std::uint64_t local_participant_handle, - const std::string &destination_identity, - const std::string &method, - const std::string &payload, - std::optional response_timeout_ms) { +std::future FfiClient::performRpcAsync(std::uint64_t local_participant_handle, + const std::string& destination_identity, const std::string& method, + const std::string& payload, + std::optional response_timeout_ms) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); @@ -875,17 +804,15 @@ FfiClient::performRpcAsync(std::uint64_t local_participant_handle, auto fut = registerAsync( async_id, // match predicate - [async_id](const proto::FfiEvent &event) { - return event.has_perform_rpc() && - event.perform_rpc().async_id() == async_id; + [async_id](const proto::FfiEvent& event) { + return event.has_perform_rpc() && event.perform_rpc().async_id() == async_id; }, - [](const proto::FfiEvent &event, std::promise &pr) { - const auto &cb = event.perform_rpc(); + [](const proto::FfiEvent& event, std::promise& pr) { + const auto& cb = event.perform_rpc(); if (cb.has_error()) { // RpcError is a proto message; convert to C++ RpcError and throw - pr.set_exception( - std::make_exception_ptr(RpcError::fromProto(cb.error()))); + pr.set_exception(std::make_exception_ptr(RpcError::fromProto(cb.error()))); return; } pr.set_value(cb.payload()); @@ -893,7 +820,7 @@ FfiClient::performRpcAsync(std::uint64_t local_participant_handle, // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_perform_rpc(); + auto* msg = req.mutable_perform_rpc(); msg->set_local_participant_handle(local_participant_handle); msg->set_destination_identity(destination_identity); msg->set_method(method); @@ -916,26 +843,23 @@ FfiClient::performRpcAsync(std::uint64_t local_participant_handle, return fut; } -std::future FfiClient::sendStreamHeaderAsync( - std::uint64_t local_participant_handle, - const proto::DataStream::Header &header, - const std::vector &destination_identities, - const std::string &sender_identity) { +std::future FfiClient::sendStreamHeaderAsync(std::uint64_t local_participant_handle, + const proto::DataStream::Header& header, + const std::vector& destination_identities, + const std::string& sender_identity) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &e) { - return e.has_send_stream_header() && - e.send_stream_header().async_id() == async_id; + [async_id](const proto::FfiEvent& e) { + return e.has_send_stream_header() && e.send_stream_header().async_id() == async_id; }, - [](const proto::FfiEvent &e, std::promise &pr) { - const auto &cb = e.send_stream_header(); + [](const proto::FfiEvent& e, std::promise& pr) { + const auto& cb = e.send_stream_header(); if (!cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -943,12 +867,12 @@ std::future FfiClient::sendStreamHeaderAsync( // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_send_stream_header(); + auto* msg = req.mutable_send_stream_header(); msg->set_local_participant_handle(local_participant_handle); *msg->mutable_header() = header; msg->set_sender_identity(sender_identity); msg->set_request_async_id(async_id); - for (const auto &id : destination_identities) { + for (const auto& id : destination_identities) { msg->add_destination_identities(id); } @@ -965,26 +889,23 @@ std::future FfiClient::sendStreamHeaderAsync( return fut; } -std::future FfiClient::sendStreamChunkAsync( - std::uint64_t local_participant_handle, - const proto::DataStream::Chunk &chunk, - const std::vector &destination_identities, - const std::string &sender_identity) { +std::future FfiClient::sendStreamChunkAsync(std::uint64_t local_participant_handle, + const proto::DataStream::Chunk& chunk, + const std::vector& destination_identities, + const std::string& sender_identity) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &e) { - return e.has_send_stream_chunk() && - e.send_stream_chunk().async_id() == async_id; + [async_id](const proto::FfiEvent& e) { + return e.has_send_stream_chunk() && e.send_stream_chunk().async_id() == async_id; }, - [](const proto::FfiEvent &e, std::promise &pr) { - const auto &cb = e.send_stream_chunk(); + [](const proto::FfiEvent& e, std::promise& pr) { + const auto& cb = e.send_stream_chunk(); if (!cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -992,12 +913,12 @@ std::future FfiClient::sendStreamChunkAsync( // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_send_stream_chunk(); + auto* msg = req.mutable_send_stream_chunk(); msg->set_local_participant_handle(local_participant_handle); *msg->mutable_chunk() = chunk; msg->set_sender_identity(sender_identity); msg->set_request_async_id(async_id); - for (const auto &id : destination_identities) { + for (const auto& id : destination_identities) { msg->add_destination_identities(id); } @@ -1014,25 +935,22 @@ std::future FfiClient::sendStreamChunkAsync( return fut; } -std::future -FfiClient::sendStreamTrailerAsync(std::uint64_t local_participant_handle, - const proto::DataStream::Trailer &trailer, - const std::string &sender_identity) { +std::future FfiClient::sendStreamTrailerAsync(std::uint64_t local_participant_handle, + const proto::DataStream::Trailer& trailer, + const std::string& sender_identity) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); // Register the async handler BEFORE sending the request auto fut = registerAsync( async_id, - [async_id](const proto::FfiEvent &e) { - return e.has_send_stream_trailer() && - e.send_stream_trailer().async_id() == async_id; + [async_id](const proto::FfiEvent& e) { + return e.has_send_stream_trailer() && e.send_stream_trailer().async_id() == async_id; }, - [](const proto::FfiEvent &e, std::promise &pr) { - const auto &cb = e.send_stream_trailer(); + [](const proto::FfiEvent& e, std::promise& pr) { + const auto& cb = e.send_stream_trailer(); if (!cb.error().empty()) { - pr.set_exception( - std::make_exception_ptr(std::runtime_error(cb.error()))); + pr.set_exception(std::make_exception_ptr(std::runtime_error(cb.error()))); return; } pr.set_value(); @@ -1040,7 +958,7 @@ FfiClient::sendStreamTrailerAsync(std::uint64_t local_participant_handle, // Build and send the request proto::FfiRequest req; - auto *msg = req.mutable_send_stream_trailer(); + auto* msg = req.mutable_send_stream_trailer(); msg->set_local_participant_handle(local_participant_handle); *msg->mutable_trailer() = trailer; msg->set_sender_identity(sender_identity); diff --git a/src/ffi_client.h b/src/ffi_client.h index 22a5c1c3..2879f2d2 100644 --- a/src/ffi_client.h +++ b/src/ffi_client.h @@ -53,30 +53,28 @@ class DataStream; struct RoomOptions; struct TrackPublishOptions; -using FfiCallbackFn = void (*)(const uint8_t *, size_t); -extern "C" void livekit_ffi_initialize(FfiCallbackFn cb, bool capture_logs, - const char *sdk, - const char *sdk_version); +using FfiCallbackFn = void (*)(const uint8_t*, size_t); +extern "C" void livekit_ffi_initialize(FfiCallbackFn cb, bool capture_logs, const char* sdk, const char* sdk_version); extern "C" void livekit_ffi_dispose(); -extern "C" void LivekitFfiCallback(const uint8_t *buf, size_t len); +extern "C" void LivekitFfiCallback(const uint8_t* buf, size_t len); // The FfiClient is used to communicate with the FFI interface of the Rust SDK // We use the generated protocol messages to facilitate the communication class FfiClient { public: using ListenerId = int; - using Listener = std::function; + using Listener = std::function; using AsyncId = std::uint64_t; ~FfiClient(); - FfiClient(const FfiClient &) = delete; - FfiClient &operator=(const FfiClient &) = delete; - FfiClient(FfiClient &&) = delete; - FfiClient &operator=(FfiClient &&) = delete; + FfiClient(const FfiClient&) = delete; + FfiClient& operator=(const FfiClient&) = delete; + FfiClient(FfiClient&&) = delete; + FfiClient& operator=(FfiClient&&) = delete; - static FfiClient &instance() noexcept { + static FfiClient& instance() noexcept { static FfiClient instance; return instance; } @@ -90,76 +88,58 @@ class FfiClient { bool isInitialized() const noexcept; - ListenerId AddListener(const Listener &listener); + ListenerId AddListener(const Listener& listener); void RemoveListener(ListenerId id); // Room APIs - std::future connectAsync(const std::string &url, - const std::string &token, - const RoomOptions &options); + std::future connectAsync(const std::string& url, const std::string& token, + const RoomOptions& options); // Track APIs std::future> getTrackStatsAsync(uintptr_t track_handle); // Participant APIs - std::future - publishTrackAsync(std::uint64_t local_participant_handle, - std::uint64_t track_handle, - const TrackPublishOptions &options); - std::future unpublishTrackAsync(std::uint64_t local_participant_handle, - const std::string &track_sid, + std::future publishTrackAsync(std::uint64_t local_participant_handle, + std::uint64_t track_handle, + const TrackPublishOptions& options); + std::future unpublishTrackAsync(std::uint64_t local_participant_handle, const std::string& track_sid, bool stop_on_unpublish); - std::future - publishDataAsync(std::uint64_t local_participant_handle, - const std::uint8_t *data_ptr, std::uint64_t data_len, - bool reliable, - const std::vector &destination_identities, - const std::string &topic); - std::future - publishSipDtmfAsync(std::uint64_t local_participant_handle, - std::uint32_t code, const std::string &digit, - const std::vector &destination_identities); - std::future - setLocalMetadataAsync(std::uint64_t local_participant_handle, - const std::string &metadata); - std::future - captureAudioFrameAsync(std::uint64_t source_handle, - const proto::AudioFrameBufferInfo &buffer); - std::future performRpcAsync( - std::uint64_t local_participant_handle, - const std::string &destination_identity, const std::string &method, - const std::string &payload, - std::optional response_timeout_ms = std::nullopt); + std::future publishDataAsync(std::uint64_t local_participant_handle, const std::uint8_t* data_ptr, + std::uint64_t data_len, bool reliable, + const std::vector& destination_identities, const std::string& topic); + std::future publishSipDtmfAsync(std::uint64_t local_participant_handle, std::uint32_t code, + const std::string& digit, + const std::vector& destination_identities); + std::future setLocalMetadataAsync(std::uint64_t local_participant_handle, const std::string& metadata); + std::future captureAudioFrameAsync(std::uint64_t source_handle, const proto::AudioFrameBufferInfo& buffer); + std::future performRpcAsync(std::uint64_t local_participant_handle, + const std::string& destination_identity, const std::string& method, + const std::string& payload, + std::optional response_timeout_ms = std::nullopt); // Data Track APIs - std::future> - publishDataTrackAsync(std::uint64_t local_participant_handle, - const std::string &track_name); + std::future> publishDataTrackAsync( + std::uint64_t local_participant_handle, const std::string& track_name); - Result - subscribeDataTrack(std::uint64_t track_handle, - std::optional buffer_size = std::nullopt); + Result subscribeDataTrack( + std::uint64_t track_handle, std::optional buffer_size = std::nullopt); // Data stream functionalities - std::future - sendStreamHeaderAsync(std::uint64_t local_participant_handle, - const proto::DataStream::Header &header, - const std::vector &destination_identities, - const std::string &sender_identity); - std::future - sendStreamChunkAsync(std::uint64_t local_participant_handle, - const proto::DataStream::Chunk &chunk, - const std::vector &destination_identities, - const std::string &sender_identity); - std::future - sendStreamTrailerAsync(std::uint64_t local_participant_handle, - const proto::DataStream::Trailer &trailer, - const std::string &sender_identity); + std::future sendStreamHeaderAsync(std::uint64_t local_participant_handle, + const proto::DataStream::Header& header, + const std::vector& destination_identities, + const std::string& sender_identity); + std::future sendStreamChunkAsync(std::uint64_t local_participant_handle, const proto::DataStream::Chunk& chunk, + const std::vector& destination_identities, + const std::string& sender_identity); + std::future sendStreamTrailerAsync(std::uint64_t local_participant_handle, + const proto::DataStream::Trailer& trailer, + const std::string& sender_identity); // Generic function for sending a request to the Rust FFI. // Note: For asynchronous requests, use the dedicated async functions instead // of sendRequest. - proto::FfiResponse sendRequest(const proto::FfiRequest &request) const; + proto::FfiResponse sendRequest(const proto::FfiRequest& request) const; private: FfiClient() = default; @@ -168,40 +148,34 @@ class FfiClient { struct PendingBase { AsyncId async_id = 0; // Client-generated async ID for cancellation virtual ~PendingBase() = default; - virtual bool matches(const proto::FfiEvent &event) const = 0; - virtual void complete(const proto::FfiEvent &event) = 0; + virtual bool matches(const proto::FfiEvent& event) const = 0; + virtual void complete(const proto::FfiEvent& event) = 0; virtual void cancel() = 0; // Cancel the pending operation }; - template struct Pending : PendingBase { + template + struct Pending : PendingBase { std::promise promise; - std::function match; - std::function &)> handler; + std::function match; + std::function&)> handler; - bool matches(const proto::FfiEvent &event) const override { - return match && match(event); - } + bool matches(const proto::FfiEvent& event) const override { return match && match(event); } - void complete(const proto::FfiEvent &event) override { - handler(event, promise); - } + void complete(const proto::FfiEvent& event) override { handler(event, promise); } void cancel() override { try { - promise.set_exception(std::make_exception_ptr( - std::runtime_error("Async operation cancelled"))); - } catch (const std::future_error &e) { + promise.set_exception(std::make_exception_ptr(std::runtime_error("Async operation cancelled"))); + } catch (const std::future_error& e) { // Unlikely to throw here as the promise should be satisfied before // cancel() Logging a debug message to avoid clang empty catch warning - LK_LOG_DEBUG("FfiClient::cancel: promise already satisfied: {}", - e.what()); + LK_LOG_DEBUG("FfiClient::cancel: promise already satisfied: {}", e.what()); } } }; template - std::future registerAsync( - AsyncId async_id, std::function match, - std::function &)> handler); + std::future registerAsync(AsyncId async_id, std::function match, + std::function&)> handler); // Generate a unique client-side async ID for request correlation AsyncId generateAsyncId(); @@ -213,12 +187,11 @@ class FfiClient { std::unordered_map listeners_; std::atomic next_listener_id{1}; mutable std::mutex lock_; - mutable std::unordered_map> - pending_by_id_; + mutable std::unordered_map> pending_by_id_; std::atomic next_async_id_{1}; - void PushEvent(const proto::FfiEvent &event) const; - friend void LivekitFfiCallback(const uint8_t *buf, size_t len); + void PushEvent(const proto::FfiEvent& event) const; + friend void LivekitFfiCallback(const uint8_t* buf, size_t len); std::atomic initialized_{false}; }; } // namespace livekit diff --git a/src/ffi_handle.cpp b/src/ffi_handle.cpp index 4c28effb..b19ebe94 100644 --- a/src/ffi_handle.cpp +++ b/src/ffi_handle.cpp @@ -15,6 +15,7 @@ */ #include "livekit/ffi_handle.h" + #include "livekit_ffi.h" namespace livekit { @@ -23,9 +24,9 @@ FfiHandle::FfiHandle(uintptr_t h) noexcept : handle_(h) {} FfiHandle::~FfiHandle() { reset(); } -FfiHandle::FfiHandle(FfiHandle &&other) noexcept : handle_(other.release()) {} +FfiHandle::FfiHandle(FfiHandle&& other) noexcept : handle_(other.release()) {} -FfiHandle &FfiHandle::operator=(FfiHandle &&other) noexcept { +FfiHandle& FfiHandle::operator=(FfiHandle&& other) noexcept { if (this != &other) { reset(other.release()); } diff --git a/src/livekit.cpp b/src/livekit.cpp index b9132efc..1bcd9df9 100644 --- a/src/livekit.cpp +++ b/src/livekit.cpp @@ -15,19 +15,20 @@ */ #include "livekit/livekit.h" + #include "ffi_client.h" #include "lk_log.h" namespace livekit { -bool initialize(const LogLevel &level, const LogSink &log_sink) { +bool initialize(const LogLevel& level, const LogSink& log_sink) { setLogLevel(level); - auto &ffi_client = FfiClient::instance(); + auto& ffi_client = FfiClient::instance(); return ffi_client.initialize(log_sink == LogSink::kCallback); } void shutdown() { - auto &ffi_client = FfiClient::instance(); + auto& ffi_client = FfiClient::instance(); ffi_client.shutdown(); detail::shutdownLogger(); } diff --git a/src/lk_log.h b/src/lk_log.h index 21a064ba..a42a441f 100644 --- a/src/lk_log.h +++ b/src/lk_log.h @@ -17,9 +17,10 @@ #ifndef LIVEKIT_LK_LOG_H #define LIVEKIT_LK_LOG_H -#include #include +#include + namespace livekit::detail { /// Returns the shared "livekit" logger instance. @@ -42,17 +43,11 @@ void shutdownLogger(); // // Default LIVEKIT_LOG_LEVEL is TRACE (nothing stripped). For release builds // consider -DLIVEKIT_LOG_LEVEL=INFO or WARN to eliminate verbose calls. -#define LK_LOG_TRACE(...) \ - SPDLOG_LOGGER_TRACE(livekit::detail::getLogger(), __VA_ARGS__) -#define LK_LOG_DEBUG(...) \ - SPDLOG_LOGGER_DEBUG(livekit::detail::getLogger(), __VA_ARGS__) -#define LK_LOG_INFO(...) \ - SPDLOG_LOGGER_INFO(livekit::detail::getLogger(), __VA_ARGS__) -#define LK_LOG_WARN(...) \ - SPDLOG_LOGGER_WARN(livekit::detail::getLogger(), __VA_ARGS__) -#define LK_LOG_ERROR(...) \ - SPDLOG_LOGGER_ERROR(livekit::detail::getLogger(), __VA_ARGS__) -#define LK_LOG_CRITICAL(...) \ - SPDLOG_LOGGER_CRITICAL(livekit::detail::getLogger(), __VA_ARGS__) +#define LK_LOG_TRACE(...) SPDLOG_LOGGER_TRACE(livekit::detail::getLogger(), __VA_ARGS__) +#define LK_LOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(livekit::detail::getLogger(), __VA_ARGS__) +#define LK_LOG_INFO(...) SPDLOG_LOGGER_INFO(livekit::detail::getLogger(), __VA_ARGS__) +#define LK_LOG_WARN(...) SPDLOG_LOGGER_WARN(livekit::detail::getLogger(), __VA_ARGS__) +#define LK_LOG_ERROR(...) SPDLOG_LOGGER_ERROR(livekit::detail::getLogger(), __VA_ARGS__) +#define LK_LOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(livekit::detail::getLogger(), __VA_ARGS__) #endif /* LIVEKIT_LK_LOG_H */ diff --git a/src/local_audio_track.cpp b/src/local_audio_track.cpp index 93808654..720b8740 100644 --- a/src/local_audio_track.cpp +++ b/src/local_audio_track.cpp @@ -24,25 +24,21 @@ namespace livekit { -LocalAudioTrack::LocalAudioTrack(FfiHandle handle, - const proto::OwnedTrack &track) - : Track(std::move(handle), track.info().sid(), track.info().name(), - fromProto(track.info().kind()), - fromProto(track.info().stream_state()), track.info().muted(), - false) {} +LocalAudioTrack::LocalAudioTrack(FfiHandle handle, const proto::OwnedTrack& track) + : Track(std::move(handle), track.info().sid(), track.info().name(), fromProto(track.info().kind()), + fromProto(track.info().stream_state()), track.info().muted(), false) {} -std::shared_ptr LocalAudioTrack::createLocalAudioTrack( - const std::string &name, const std::shared_ptr &source) { +std::shared_ptr LocalAudioTrack::createLocalAudioTrack(const std::string& name, + const std::shared_ptr& source) { proto::FfiRequest req; - auto *msg = req.mutable_create_audio_track(); + auto* msg = req.mutable_create_audio_track(); msg->set_name(name); msg->set_source_handle(static_cast(source->ffi_handle_id())); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); - const proto::OwnedTrack &owned = resp.create_audio_track().track(); + const proto::OwnedTrack& owned = resp.create_audio_track().track(); FfiHandle handle(static_cast(owned.handle().id())); - return std::shared_ptr( - new LocalAudioTrack(std::move(handle), owned)); + return std::shared_ptr(new LocalAudioTrack(std::move(handle), owned)); } void LocalAudioTrack::mute() { @@ -52,7 +48,7 @@ void LocalAudioTrack::mute() { } proto::FfiRequest req; - auto *msg = req.mutable_local_track_mute(); + auto* msg = req.mutable_local_track_mute(); msg->set_track_handle(static_cast(ffi_handle_id())); msg->set_mute(true); @@ -67,7 +63,7 @@ void LocalAudioTrack::unmute() { } proto::FfiRequest req; - auto *msg = req.mutable_local_track_mute(); + auto* msg = req.mutable_local_track_mute(); msg->set_track_handle(static_cast(ffi_handle_id())); msg->set_mute(false); @@ -75,8 +71,6 @@ void LocalAudioTrack::unmute() { setMuted(false); } -std::string LocalAudioTrack::to_string() const { - return "rtc.LocalAudioTrack(sid=" + sid() + ", name=" + name() + ")"; -} +std::string LocalAudioTrack::to_string() const { return "rtc.LocalAudioTrack(sid=" + sid() + ", name=" + name() + ")"; } } // namespace livekit \ No newline at end of file diff --git a/src/local_data_track.cpp b/src/local_data_track.cpp index 3c24a9cf..6173ab28 100644 --- a/src/local_data_track.cpp +++ b/src/local_data_track.cpp @@ -16,59 +16,52 @@ #include "livekit/local_data_track.h" -#include "livekit/data_track_error.h" -#include "lk_log.h" - #include "data_track.pb.h" #include "ffi.pb.h" #include "ffi_client.h" +#include "livekit/data_track_error.h" +#include "lk_log.h" namespace livekit { -LocalDataTrack::LocalDataTrack(const proto::OwnedLocalDataTrack &owned) +LocalDataTrack::LocalDataTrack(const proto::OwnedLocalDataTrack& owned) : handle_(static_cast(owned.handle().id())) { - const auto &pi = owned.info(); + const auto& pi = owned.info(); info_.name = pi.name(); info_.sid = pi.sid(); info_.uses_e2ee = pi.uses_e2ee(); } -Result -LocalDataTrack::tryPush(const DataTrackFrame &frame) { +Result LocalDataTrack::tryPush(const DataTrackFrame& frame) { if (!handle_.valid()) { - return Result::failure( - LocalDataTrackTryPushError{ - LocalDataTrackTryPushErrorCode::INVALID_HANDLE, - "LocalDataTrack::tryPush: invalid FFI handle"}); + return Result::failure(LocalDataTrackTryPushError{ + LocalDataTrackTryPushErrorCode::INVALID_HANDLE, "LocalDataTrack::tryPush: invalid FFI handle"}); } try { proto::FfiRequest req; - auto *msg = req.mutable_local_data_track_try_push(); + auto* msg = req.mutable_local_data_track_try_push(); msg->set_track_handle(static_cast(handle_.get())); - auto *pf = msg->mutable_frame(); + auto* pf = msg->mutable_frame(); pf->set_payload(frame.payload.data(), frame.payload.size()); if (frame.user_timestamp.has_value()) { pf->set_user_timestamp(frame.user_timestamp.value()); } const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); - const auto &r = resp.local_data_track_try_push(); + const auto& r = resp.local_data_track_try_push(); if (r.has_error()) { - return Result::failure( - LocalDataTrackTryPushError::fromProto(r.error())); + return Result::failure(LocalDataTrackTryPushError::fromProto(r.error())); } return Result::success(); - } catch (const std::exception &e) { + } catch (const std::exception& e) { return Result::failure( - LocalDataTrackTryPushError{LocalDataTrackTryPushErrorCode::INTERNAL, - e.what()}); + LocalDataTrackTryPushError{LocalDataTrackTryPushErrorCode::INTERNAL, e.what()}); } } -Result -LocalDataTrack::tryPush(std::vector &&payload, - std::optional user_timestamp) { +Result LocalDataTrack::tryPush(std::vector&& payload, + std::optional user_timestamp) { DataTrackFrame frame; frame.payload = std::move(payload); frame.user_timestamp = user_timestamp; @@ -81,7 +74,7 @@ bool LocalDataTrack::isPublished() const { } proto::FfiRequest req; - auto *msg = req.mutable_local_data_track_is_published(); + auto* msg = req.mutable_local_data_track_is_published(); msg->set_track_handle(static_cast(handle_.get())); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); @@ -94,7 +87,7 @@ void LocalDataTrack::unpublishDataTrack() { } proto::FfiRequest req; - auto *msg = req.mutable_local_data_track_unpublish(); + auto* msg = req.mutable_local_data_track_unpublish(); msg->set_track_handle(static_cast(handle_.get())); (void)FfiClient::instance().sendRequest(req); diff --git a/src/local_participant.cpp b/src/local_participant.cpp index d33b7f2a..bbeda2fb 100644 --- a/src/local_participant.cpp +++ b/src/local_participant.cpp @@ -16,6 +16,12 @@ #include "livekit/local_participant.h" +#include +#include + +#include "data_track.pb.h" +#include "ffi.pb.h" +#include "ffi_client.h" #include "livekit/ffi_handle.h" #include "livekit/local_audio_track.h" #include "livekit/local_data_track.h" @@ -23,23 +29,15 @@ #include "livekit/local_video_track.h" #include "livekit/room_delegate.h" #include "livekit/track.h" - -#include "data_track.pb.h" -#include "ffi.pb.h" -#include "ffi_client.h" #include "participant.pb.h" #include "room.pb.h" #include "room_proto_converter.h" #include "track.pb.h" #include "track_proto_converter.h" -#include -#include - namespace { -std::shared_ptr -localTrackPublication(const std::shared_ptr &t) { +std::shared_ptr localTrackPublication(const std::shared_ptr& t) { if (!t) { return nullptr; } @@ -59,67 +57,56 @@ namespace livekit { using proto::FfiRequest; using proto::FfiResponse; -LocalParticipant::LocalParticipant( - FfiHandle handle, std::string sid, std::string name, std::string identity, - std::string metadata, - std::unordered_map attributes, - ParticipantKind kind, DisconnectReason reason) - : Participant(std::move(handle), std::move(sid), std::move(name), - std::move(identity), std::move(metadata), +LocalParticipant::LocalParticipant(FfiHandle handle, std::string sid, std::string name, std::string identity, + std::string metadata, std::unordered_map attributes, + ParticipantKind kind, DisconnectReason reason) + : Participant(std::move(handle), std::move(sid), std::move(name), std::move(identity), std::move(metadata), std::move(attributes), kind, reason) {} -void LocalParticipant::publishData( - const std::vector &payload, bool reliable, - const std::vector &destination_identities, - const std::string &topic) { +void LocalParticipant::publishData(const std::vector& payload, bool reliable, + const std::vector& destination_identities, const std::string& topic) { if (payload.empty()) { return; } auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::publishData: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::publishData: invalid FFI handle"); } // Use async FFI API and block until completion. - auto fut = FfiClient::instance().publishDataAsync( - static_cast(handle_id), payload.data(), - static_cast(payload.size()), reliable, - destination_identities, topic); + auto fut = FfiClient::instance().publishDataAsync(static_cast(handle_id), payload.data(), + static_cast(payload.size()), reliable, + destination_identities, topic); fut.get(); } -void LocalParticipant::publishDtmf(int code, const std::string &digit) { +void LocalParticipant::publishDtmf(int code, const std::string& digit) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::publishDtmf: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::publishDtmf: invalid FFI handle"); } // TODO, should we take destination as inputs? const std::vector destination_identities; - auto fut = FfiClient::instance().publishSipDtmfAsync( - static_cast(handle_id), static_cast(code), - digit, destination_identities); + auto fut = FfiClient::instance().publishSipDtmfAsync(static_cast(handle_id), + static_cast(code), digit, destination_identities); fut.get(); } -void LocalParticipant::setMetadata(const std::string &metadata) { +void LocalParticipant::setMetadata(const std::string& metadata) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::setMetadata: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::setMetadata: invalid FFI handle"); } - auto fut = FfiClient::instance().setLocalMetadataAsync( - static_cast(handle_id), metadata); + auto fut = FfiClient::instance().setLocalMetadataAsync(static_cast(handle_id), metadata); fut.get(); } -void LocalParticipant::setName(const std::string &name) { +void LocalParticipant::setName(const std::string& name) { auto handle_id = ffiHandleId(); if (handle_id == 0) { throw std::runtime_error("LocalParticipant::setName: invalid FFI handle"); @@ -128,28 +115,26 @@ void LocalParticipant::setName(const std::string &name) { // No async helper defined for SetLocalName in FfiClient yet, so keep using // the direct request. FfiRequest req; - auto *msg = req.mutable_set_local_name(); + auto* msg = req.mutable_set_local_name(); msg->set_local_participant_handle(static_cast(handle_id)); msg->set_name(name); (void)FfiClient::instance().sendRequest(req); } -void LocalParticipant::setAttributes( - const std::unordered_map &attributes) { +void LocalParticipant::setAttributes(const std::unordered_map& attributes) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::setAttributes: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::setAttributes: invalid FFI handle"); } // No async helper defined for SetLocalAttributes in FfiClient yet. FfiRequest req; - auto *msg = req.mutable_set_local_attributes(); + auto* msg = req.mutable_set_local_attributes(); msg->set_local_participant_handle(static_cast(handle_id)); - for (const auto &kv : attributes) { - auto *entry = msg->add_attributes(); + for (const auto& kv : attributes) { + auto* entry = msg->add_attributes(); entry->set_key(kv.first); entry->set_value(kv.second); } @@ -162,8 +147,7 @@ void LocalParticipant::setAttributes( // ---------------------------------------------------------------------------- void LocalParticipant::setTrackSubscriptionPermissions( - bool allow_all_participants, - const std::vector &participant_permissions) { + bool allow_all_participants, const std::vector& participant_permissions) { auto handle_id = ffiHandleId(); if (handle_id == 0) { throw std::runtime_error( @@ -173,12 +157,12 @@ void LocalParticipant::setTrackSubscriptionPermissions( // No dedicated async helper; do it directly. FfiRequest req; - auto *msg = req.mutable_set_track_subscription_permissions(); + auto* msg = req.mutable_set_track_subscription_permissions(); msg->set_local_participant_handle(static_cast(handle_id)); msg->set_all_participants_allowed(allow_all_participants); - for (const auto &perm : participant_permissions) { - auto *p = msg->add_permissions(); + for (const auto& perm : participant_permissions) { + auto* p = msg->add_permissions(); p->CopyFrom(toProto(perm)); } @@ -189,27 +173,22 @@ void LocalParticipant::setTrackSubscriptionPermissions( // Track publish / unpublish // ---------------------------------------------------------------------------- -void LocalParticipant::publishTrack(const std::shared_ptr &track, - const TrackPublishOptions &options) { +void LocalParticipant::publishTrack(const std::shared_ptr& track, const TrackPublishOptions& options) { if (!track) { - throw std::invalid_argument( - "LocalParticipant::publishTrack: track is null"); + throw std::invalid_argument("LocalParticipant::publishTrack: track is null"); } auto participant_handle = ffiHandleId(); if (participant_handle == 0) { - throw std::runtime_error( - "LocalParticipant::publishTrack: invalid participant FFI handle"); + throw std::runtime_error("LocalParticipant::publishTrack: invalid participant FFI handle"); } auto track_handle = track->ffi_handle_id(); if (track_handle == 0) { - throw std::runtime_error( - "LocalParticipant::publishTrack: invalid track FFI handle"); + throw std::runtime_error("LocalParticipant::publishTrack: invalid track FFI handle"); } - auto fut = FfiClient::instance().publishTrackAsync( - static_cast(participant_handle), - static_cast(track_handle), options); + auto fut = FfiClient::instance().publishTrackAsync(static_cast(participant_handle), + static_cast(track_handle), options); // Will throw if the async op fails (error in callback). const proto::OwnedTrackPublication owned_pub = fut.get(); @@ -223,10 +202,9 @@ void LocalParticipant::publishTrack(const std::shared_ptr &track, track->setPublication(publication); } -std::shared_ptr -LocalParticipant::publishVideoTrack(const std::string &name, - const std::shared_ptr &source, - TrackSource track_source) { +std::shared_ptr LocalParticipant::publishVideoTrack(const std::string& name, + const std::shared_ptr& source, + TrackSource track_source) { auto track = LocalVideoTrack::createLocalVideoTrack(name, source); TrackPublishOptions opts; opts.source = track_source; @@ -234,10 +212,9 @@ LocalParticipant::publishVideoTrack(const std::string &name, return track; } -std::shared_ptr -LocalParticipant::publishAudioTrack(const std::string &name, - const std::shared_ptr &source, - TrackSource track_source) { +std::shared_ptr LocalParticipant::publishAudioTrack(const std::string& name, + const std::shared_ptr& source, + TrackSource track_source) { auto track = LocalAudioTrack::createLocalAudioTrack(name, source); TrackPublishOptions opts; opts.source = track_source; @@ -245,25 +222,22 @@ LocalParticipant::publishAudioTrack(const std::string &name, return track; } -void LocalParticipant::unpublishTrack(const std::string &track_sid) { +void LocalParticipant::unpublishTrack(const std::string& track_sid) { if (track_sid.empty()) { return; } auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::unpublishTrack: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::unpublishTrack: invalid FFI handle"); } - auto fut = FfiClient::instance().unpublishTrackAsync( - static_cast(handle_id), track_sid, - /*stop_on_unpublish=*/true); + auto fut = FfiClient::instance().unpublishTrackAsync(static_cast(handle_id), track_sid, + /*stop_on_unpublish=*/true); fut.get(); - if (auto it = published_tracks_by_sid_.find(track_sid); - it != published_tracks_by_sid_.end()) { + if (auto it = published_tracks_by_sid_.find(track_sid); it != published_tracks_by_sid_.end()) { if (auto t = it->second.lock()) { t->setPublication(nullptr); } @@ -273,8 +247,7 @@ void LocalParticipant::unpublishTrack(const std::string &track_sid) { LocalParticipant::PublicationMap LocalParticipant::trackPublications() const { PublicationMap out; - for (auto it = published_tracks_by_sid_.begin(); - it != published_tracks_by_sid_.end();) { + for (auto it = published_tracks_by_sid_.begin(); it != published_tracks_by_sid_.end();) { auto t = it->second.lock(); if (!t) { it = published_tracks_by_sid_.erase(it); @@ -288,33 +261,28 @@ LocalParticipant::PublicationMap LocalParticipant::trackPublications() const { return out; } -Result, PublishDataTrackError> -LocalParticipant::publishDataTrack(const std::string &name) { +Result, PublishDataTrackError> LocalParticipant::publishDataTrack( + const std::string& name) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - return Result, - PublishDataTrackError>::failure(PublishDataTrackError{ - PublishDataTrackErrorCode::INVALID_HANDLE, - "LocalParticipant::publishDataTrack: invalid FFI " - "handle"}); + return Result, PublishDataTrackError>::failure( + PublishDataTrackError{PublishDataTrackErrorCode::INVALID_HANDLE, + "LocalParticipant::publishDataTrack: invalid FFI " + "handle"}); } - auto fut = FfiClient::instance().publishDataTrackAsync( - static_cast(handle_id), name); + auto fut = FfiClient::instance().publishDataTrackAsync(static_cast(handle_id), name); auto result = fut.get(); if (!result) { - return Result, - PublishDataTrackError>::failure(std::move(result).error()); + return Result, PublishDataTrackError>::failure(std::move(result).error()); } - return Result, PublishDataTrackError>:: - success( - std::shared_ptr(new LocalDataTrack(result.value()))); + return Result, PublishDataTrackError>::success( + std::shared_ptr(new LocalDataTrack(result.value()))); } -void LocalParticipant::unpublishDataTrack( - const std::shared_ptr &track) { +void LocalParticipant::unpublishDataTrack(const std::shared_ptr& track) { if (!track) { return; } @@ -322,13 +290,11 @@ void LocalParticipant::unpublishDataTrack( track->unpublishDataTrack(); } -std::string LocalParticipant::performRpc( - const std::string &destination_identity, const std::string &method, - const std::string &payload, const std::optional &response_timeout) { +std::string LocalParticipant::performRpc(const std::string& destination_identity, const std::string& method, + const std::string& payload, const std::optional& response_timeout) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::performRpc: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::performRpc: invalid FFI handle"); } std::uint32_t timeout_ms = 0; @@ -339,37 +305,33 @@ std::string LocalParticipant::performRpc( } auto fut = FfiClient::instance().performRpcAsync( - static_cast(handle_id), destination_identity, method, - payload, + static_cast(handle_id), destination_identity, method, payload, has_timeout ? std::optional(timeout_ms) : std::nullopt); return fut.get(); } -void LocalParticipant::registerRpcMethod(const std::string &method_name, - RpcHandler handler) { +void LocalParticipant::registerRpcMethod(const std::string& method_name, RpcHandler handler) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::registerRpcMethod: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::registerRpcMethod: invalid FFI handle"); } rpc_handlers_[method_name] = std::move(handler); FfiRequest req; - auto *msg = req.mutable_register_rpc_method(); + auto* msg = req.mutable_register_rpc_method(); msg->set_local_participant_handle(static_cast(handle_id)); msg->set_method(method_name); (void)FfiClient::instance().sendRequest(req); } -void LocalParticipant::unregisterRpcMethod(const std::string &method_name) { +void LocalParticipant::unregisterRpcMethod(const std::string& method_name) { auto handle_id = ffiHandleId(); if (handle_id == 0) { - throw std::runtime_error( - "LocalParticipant::unregisterRpcMethod: invalid FFI handle"); + throw std::runtime_error("LocalParticipant::unregisterRpcMethod: invalid FFI handle"); } rpc_handlers_.erase(method_name); FfiRequest req; - auto *msg = req.mutable_unregister_rpc_method(); + auto* msg = req.mutable_unregister_rpc_method(); msg->set_local_participant_handle(static_cast(handle_id)); msg->set_method(method_name); @@ -384,9 +346,7 @@ void LocalParticipant::shutdown() { // Wait up to 5 seconds for active RPC invocations to complete. // If timeout expires, proceed anyway - late responses will fail but // at least we won't block shutdown indefinitely. - rpc_state_->cv.wait_for(lock, std::chrono::seconds(5), [this] { - return rpc_state_->active_invocations == 0; - }); + rpc_state_->cv.wait_for(lock, std::chrono::seconds(5), [this] { return rpc_state_->active_invocations == 0; }); } auto handle_id = ffiHandleId(); @@ -397,9 +357,9 @@ void LocalParticipant::shutdown() { } // Unregister all RPC methods with FFI and clear local handlers - for (const auto &pair : rpc_handlers_) { + for (const auto& pair : rpc_handlers_) { FfiRequest req; - auto *msg = req.mutable_unregister_rpc_method(); + auto* msg = req.mutable_unregister_rpc_method(); msg->set_local_participant_handle(static_cast(handle_id)); msg->set_method(pair.first); (void)FfiClient::instance().sendRequest(req); @@ -407,10 +367,9 @@ void LocalParticipant::shutdown() { rpc_handlers_.clear(); } -void LocalParticipant::handleRpcMethodInvocation( - uint64_t invocation_id, const std::string &method, - const std::string &request_id, const std::string &caller_identity, - const std::string &payload, double response_timeout_sec) { +void LocalParticipant::handleRpcMethodInvocation(uint64_t invocation_id, const std::string& method, + const std::string& request_id, const std::string& caller_identity, + const std::string& payload, double response_timeout_sec) { // Capture shared state so it outlives LocalParticipant if needed auto state = rpc_state_; @@ -440,8 +399,7 @@ void LocalParticipant::handleRpcMethodInvocation( std::optional response_error; std::optional response_payload; - const RpcInvocationData params{request_id, caller_identity, payload, - response_timeout_sec}; + const RpcInvocationData params{request_id, caller_identity, payload, response_timeout_sec}; auto it = rpc_handlers_.find(method); if (it == rpc_handlers_.end()) { // No handler registered → built-in UNSUPPORTED_METHOD @@ -450,16 +408,14 @@ void LocalParticipant::handleRpcMethodInvocation( try { // Invoke user handler: may return payload or throw RpcError response_payload = it->second(params); - } catch (const RpcError &err) { + } catch (const RpcError& err) { // Handler explicitly signalled an RPC error: forward as-is response_error = err; - } catch (const std::exception &ex) { + } catch (const std::exception& ex) { // Any other exception: wrap as built-in APPLICATION_ERROR - response_error = - RpcError::builtIn(RpcError::ErrorCode::APPLICATION_ERROR, ex.what()); + response_error = RpcError::builtIn(RpcError::ErrorCode::APPLICATION_ERROR, ex.what()); } catch (...) { - response_error = RpcError::builtIn(RpcError::ErrorCode::APPLICATION_ERROR, - "unknown error"); + response_error = RpcError::builtIn(RpcError::ErrorCode::APPLICATION_ERROR, "unknown error"); } } @@ -473,11 +429,11 @@ void LocalParticipant::handleRpcMethodInvocation( } FfiRequest req; - auto *msg = req.mutable_rpc_method_invocation_response(); + auto* msg = req.mutable_rpc_method_invocation_response(); msg->set_local_participant_handle(ffiHandleId()); msg->set_invocation_id(invocation_id); if (response_error.has_value()) { - auto *err_proto = msg->mutable_error(); + auto* err_proto = msg->mutable_error(); err_proto->CopyFrom(response_error->toProto()); } if (response_payload.has_value()) { @@ -486,8 +442,7 @@ void LocalParticipant::handleRpcMethodInvocation( FfiClient::instance().sendRequest(req); } -std::shared_ptr -LocalParticipant::findTrackPublication(const std::string &sid) const { +std::shared_ptr LocalParticipant::findTrackPublication(const std::string& sid) const { auto it = published_tracks_by_sid_.find(sid); if (it == published_tracks_by_sid_.end()) { return nullptr; diff --git a/src/local_track_publication.cpp b/src/local_track_publication.cpp index b98ead82..efe6fea9 100644 --- a/src/local_track_publication.cpp +++ b/src/local_track_publication.cpp @@ -20,15 +20,11 @@ namespace livekit { -LocalTrackPublication::LocalTrackPublication( - const proto::OwnedTrackPublication &owned) - : TrackPublication( - FfiHandle(owned.handle().id()), owned.info().sid(), - owned.info().name(), fromProto(owned.info().kind()), - fromProto(owned.info().source()), owned.info().simulcasted(), - owned.info().width(), owned.info().height(), owned.info().mime_type(), - owned.info().muted(), - static_cast(owned.info().encryption_type()), - convertAudioFeatures(owned.info().audio_features())) {} +LocalTrackPublication::LocalTrackPublication(const proto::OwnedTrackPublication& owned) + : TrackPublication(FfiHandle(owned.handle().id()), owned.info().sid(), owned.info().name(), + fromProto(owned.info().kind()), fromProto(owned.info().source()), owned.info().simulcasted(), + owned.info().width(), owned.info().height(), owned.info().mime_type(), owned.info().muted(), + static_cast(owned.info().encryption_type()), + convertAudioFeatures(owned.info().audio_features())) {} } // namespace livekit diff --git a/src/local_video_track.cpp b/src/local_video_track.cpp index cc9ca6fa..3f002c7d 100644 --- a/src/local_video_track.cpp +++ b/src/local_video_track.cpp @@ -24,25 +24,21 @@ namespace livekit { -LocalVideoTrack::LocalVideoTrack(FfiHandle handle, - const proto::OwnedTrack &track) - : Track(std::move(handle), track.info().sid(), track.info().name(), - fromProto(track.info().kind()), - fromProto(track.info().stream_state()), track.info().muted(), - false) {} +LocalVideoTrack::LocalVideoTrack(FfiHandle handle, const proto::OwnedTrack& track) + : Track(std::move(handle), track.info().sid(), track.info().name(), fromProto(track.info().kind()), + fromProto(track.info().stream_state()), track.info().muted(), false) {} -std::shared_ptr LocalVideoTrack::createLocalVideoTrack( - const std::string &name, const std::shared_ptr &source) { +std::shared_ptr LocalVideoTrack::createLocalVideoTrack(const std::string& name, + const std::shared_ptr& source) { proto::FfiRequest req; - auto *msg = req.mutable_create_video_track(); + auto* msg = req.mutable_create_video_track(); msg->set_name(name); msg->set_source_handle(static_cast(source->ffi_handle_id())); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); - const proto::OwnedTrack &owned = resp.create_video_track().track(); + const proto::OwnedTrack& owned = resp.create_video_track().track(); FfiHandle handle(static_cast(owned.handle().id())); - return std::shared_ptr( - new LocalVideoTrack(std::move(handle), owned)); + return std::shared_ptr(new LocalVideoTrack(std::move(handle), owned)); } void LocalVideoTrack::mute() { @@ -52,7 +48,7 @@ void LocalVideoTrack::mute() { } proto::FfiRequest req; - auto *msg = req.mutable_local_track_mute(); + auto* msg = req.mutable_local_track_mute(); msg->set_track_handle(static_cast(ffi_handle_id())); msg->set_mute(true); @@ -67,7 +63,7 @@ void LocalVideoTrack::unmute() { } proto::FfiRequest req; - auto *msg = req.mutable_local_track_mute(); + auto* msg = req.mutable_local_track_mute(); msg->set_track_handle(static_cast(ffi_handle_id())); msg->set_mute(false); @@ -75,8 +71,6 @@ void LocalVideoTrack::unmute() { setMuted(false); } -std::string LocalVideoTrack::to_string() const { - return "rtc.LocalVideoTrack(sid=" + sid() + ", name=" + name() + ")"; -} +std::string LocalVideoTrack::to_string() const { return "rtc.LocalVideoTrack(sid=" + sid() + ", name=" + name() + ")"; } } // namespace livekit \ No newline at end of file diff --git a/src/logging.cpp b/src/logging.cpp index f8001e7b..59c51f0e 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -16,64 +16,64 @@ #include "livekit/logging.h" -#include - #include #include #include +#include + namespace livekit { namespace { -const char *kLoggerName = "livekit"; +const char* kLoggerName = "livekit"; spdlog::level::level_enum toSpdlogLevel(LogLevel level) { switch (level) { - case LogLevel::Trace: - return spdlog::level::trace; - case LogLevel::Debug: - return spdlog::level::debug; - case LogLevel::Info: - return spdlog::level::info; - case LogLevel::Warn: - return spdlog::level::warn; - case LogLevel::Error: - return spdlog::level::err; - case LogLevel::Critical: - return spdlog::level::critical; - case LogLevel::Off: - return spdlog::level::off; + case LogLevel::Trace: + return spdlog::level::trace; + case LogLevel::Debug: + return spdlog::level::debug; + case LogLevel::Info: + return spdlog::level::info; + case LogLevel::Warn: + return spdlog::level::warn; + case LogLevel::Error: + return spdlog::level::err; + case LogLevel::Critical: + return spdlog::level::critical; + case LogLevel::Off: + return spdlog::level::off; } return spdlog::level::info; } LogLevel fromSpdlogLevel(spdlog::level::level_enum level) { switch (level) { - case spdlog::level::trace: - return LogLevel::Trace; - case spdlog::level::debug: - return LogLevel::Debug; - case spdlog::level::info: - return LogLevel::Info; - case spdlog::level::warn: - return LogLevel::Warn; - case spdlog::level::err: - return LogLevel::Error; - case spdlog::level::critical: - return LogLevel::Critical; - case spdlog::level::off: // NOLINT(bugprone-branch-clone) - return LogLevel::Off; - default: - return LogLevel::Info; + case spdlog::level::trace: + return LogLevel::Trace; + case spdlog::level::debug: + return LogLevel::Debug; + case spdlog::level::info: + return LogLevel::Info; + case spdlog::level::warn: + return LogLevel::Warn; + case spdlog::level::err: + return LogLevel::Error; + case spdlog::level::critical: + return LogLevel::Critical; + case spdlog::level::off: // NOLINT(bugprone-branch-clone) + return LogLevel::Off; + default: + return LogLevel::Info; } } -std::mutex &loggerMutex() { +std::mutex& loggerMutex() { static std::mutex mtx; return mtx; } -std::shared_ptr &loggerStorage() { +std::shared_ptr& loggerStorage() { static std::shared_ptr logger; return logger; } @@ -92,7 +92,7 @@ namespace detail { std::shared_ptr getLogger() { const std::scoped_lock lock(loggerMutex()); - auto &logger = loggerStorage(); + auto& logger = loggerStorage(); if (!logger) { logger = createDefaultLogger(); spdlog::register_logger(logger); @@ -102,7 +102,7 @@ std::shared_ptr getLogger() { void shutdownLogger() { const std::scoped_lock lock(loggerMutex()); - auto &logger = loggerStorage(); + auto& logger = loggerStorage(); if (logger) { spdlog::drop(kLoggerName); logger.reset(); @@ -111,15 +111,13 @@ void shutdownLogger() { } // namespace detail -void setLogLevel(LogLevel level) { - detail::getLogger()->set_level(toSpdlogLevel(level)); -} +void setLogLevel(LogLevel level) { detail::getLogger()->set_level(toSpdlogLevel(level)); } LogLevel getLogLevel() { return fromSpdlogLevel(detail::getLogger()->level()); } void setLogCallback(LogCallback callback) { const std::scoped_lock lock(loggerMutex()); - auto &logger = loggerStorage(); + auto& logger = loggerStorage(); auto current_level = logger ? logger->level() : spdlog::level::info; if (logger) { @@ -128,9 +126,8 @@ void setLogCallback(LogCallback callback) { if (callback) { auto sink = std::make_shared( - [cb = std::move(callback)](const spdlog::details::log_msg &msg) { - cb(fromSpdlogLevel(msg.level), - std::string(msg.logger_name.data(), msg.logger_name.size()), + [cb = std::move(callback)](const spdlog::details::log_msg& msg) { + cb(fromSpdlogLevel(msg.level), std::string(msg.logger_name.data(), msg.logger_name.size()), std::string(msg.payload.data(), msg.payload.size())); }); logger = std::make_shared(kLoggerName, sink); diff --git a/src/remote_audio_track.cpp b/src/remote_audio_track.cpp index a5e2b2dc..cfb7b4d4 100644 --- a/src/remote_audio_track.cpp +++ b/src/remote_audio_track.cpp @@ -23,12 +23,9 @@ namespace livekit { -RemoteAudioTrack::RemoteAudioTrack(const proto::OwnedTrack &track) - : Track(FfiHandle{static_cast(track.handle().id())}, - track.info().sid(), track.info().name(), - fromProto(track.info().kind()), - fromProto(track.info().stream_state()), track.info().muted(), - true) {} +RemoteAudioTrack::RemoteAudioTrack(const proto::OwnedTrack& track) + : Track(FfiHandle{static_cast(track.handle().id())}, track.info().sid(), track.info().name(), + fromProto(track.info().kind()), fromProto(track.info().stream_state()), track.info().muted(), true) {} std::string RemoteAudioTrack::to_string() const { return "rtc.RemoteAudioTrack(sid=" + sid() + ", name=" + name() + ")"; diff --git a/src/remote_data_track.cpp b/src/remote_data_track.cpp index b00ca06e..cd2300d9 100644 --- a/src/remote_data_track.cpp +++ b/src/remote_data_track.cpp @@ -16,18 +16,17 @@ #include "livekit/remote_data_track.h" +#include + #include "data_track.pb.h" #include "ffi.pb.h" #include "ffi_client.h" -#include - namespace livekit { -RemoteDataTrack::RemoteDataTrack(const proto::OwnedRemoteDataTrack &owned) - : handle_(static_cast(owned.handle().id())), - publisher_identity_(owned.publisher_identity()) { - const auto &pi = owned.info(); +RemoteDataTrack::RemoteDataTrack(const proto::OwnedRemoteDataTrack& owned) + : handle_(static_cast(owned.handle().id())), publisher_identity_(owned.publisher_identity()) { + const auto& pi = owned.info(); info_.name = pi.name(); info_.sid = pi.sid(); info_.uses_e2ee = pi.uses_e2ee(); @@ -39,28 +38,26 @@ bool RemoteDataTrack::isPublished() const { } proto::FfiRequest req; - auto *msg = req.mutable_remote_data_track_is_published(); + auto* msg = req.mutable_remote_data_track_is_published(); msg->set_track_handle(static_cast(handle_.get())); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); return resp.remote_data_track_is_published().is_published(); } -Result, SubscribeDataTrackError> -RemoteDataTrack::subscribe(const DataTrackStream::Options &options) { +Result, SubscribeDataTrackError> RemoteDataTrack::subscribe( + const DataTrackStream::Options& options) { if (!handle_.valid()) { - return Result, - SubscribeDataTrackError>::failure(SubscribeDataTrackError{ - SubscribeDataTrackErrorCode::INVALID_HANDLE, - "RemoteDataTrack::subscribe: invalid FFI " - "handle"}); + return Result, SubscribeDataTrackError>::failure( + SubscribeDataTrackError{SubscribeDataTrackErrorCode::INVALID_HANDLE, + "RemoteDataTrack::subscribe: invalid FFI " + "handle"}); } - auto result = FfiClient::instance().subscribeDataTrack( - static_cast(handle_.get()), options.buffer_size); + auto result = + FfiClient::instance().subscribeDataTrack(static_cast(handle_.get()), options.buffer_size); if (!result) { - return Result, - SubscribeDataTrackError>::failure(std::move(result).error()); + return Result, SubscribeDataTrackError>::failure(std::move(result).error()); } const proto::OwnedDataTrackStream owned_sub = result.value(); @@ -69,8 +66,7 @@ RemoteDataTrack::subscribe(const DataTrackStream::Options &options) { auto stream = std::shared_ptr(new DataTrackStream()); stream->init(std::move(sub_handle)); - return Result, - SubscribeDataTrackError>::success(std::move(stream)); + return Result, SubscribeDataTrackError>::success(std::move(stream)); } } // namespace livekit diff --git a/src/remote_participant.cpp b/src/remote_participant.cpp index a7848874..ee44367c 100644 --- a/src/remote_participant.cpp +++ b/src/remote_participant.cpp @@ -24,31 +24,25 @@ namespace livekit { -RemoteParticipant::RemoteParticipant( - FfiHandle handle, std::string sid, std::string name, std::string identity, - std::string metadata, - std::unordered_map attributes, - ParticipantKind kind, DisconnectReason reason) - : Participant(std::move(handle), std::move(sid), std::move(name), - std::move(identity), std::move(metadata), +RemoteParticipant::RemoteParticipant(FfiHandle handle, std::string sid, std::string name, std::string identity, + std::string metadata, std::unordered_map attributes, + ParticipantKind kind, DisconnectReason reason) + : Participant(std::move(handle), std::move(sid), std::move(name), std::move(identity), std::move(metadata), std::move(attributes), kind, reason), track_publications_() {} std::string RemoteParticipant::to_string() const { std::ostringstream oss; - oss << "rtc.RemoteParticipant(sid=" << sid() << ", identity=" << identity() - << ", name=" << name() << ")"; + oss << "rtc.RemoteParticipant(sid=" << sid() << ", identity=" << identity() << ", name=" << name() << ")"; return oss.str(); } -std::ostream &operator<<(std::ostream &os, - const RemoteParticipant &participant) { +std::ostream& operator<<(std::ostream& os, const RemoteParticipant& participant) { os << participant.to_string(); return os; } -std::shared_ptr -RemoteParticipant::findTrackPublication(const std::string &sid) const { +std::shared_ptr RemoteParticipant::findTrackPublication(const std::string& sid) const { auto it = track_publications_.find(sid); if (it == track_publications_.end()) { return nullptr; diff --git a/src/remote_track_publication.cpp b/src/remote_track_publication.cpp index c57b5586..03e9f94f 100644 --- a/src/remote_track_publication.cpp +++ b/src/remote_track_publication.cpp @@ -22,25 +22,20 @@ namespace livekit { -RemoteTrackPublication::RemoteTrackPublication( - const proto::OwnedTrackPublication &owned) - : TrackPublication( - FfiHandle(owned.handle().id()), owned.info().sid(), - owned.info().name(), fromProto(owned.info().kind()), - fromProto(owned.info().source()), owned.info().simulcasted(), - owned.info().width(), owned.info().height(), owned.info().mime_type(), - owned.info().muted(), - static_cast(owned.info().encryption_type()), - convertAudioFeatures(owned.info().audio_features())) {} +RemoteTrackPublication::RemoteTrackPublication(const proto::OwnedTrackPublication& owned) + : TrackPublication(FfiHandle(owned.handle().id()), owned.info().sid(), owned.info().name(), + fromProto(owned.info().kind()), fromProto(owned.info().source()), owned.info().simulcasted(), + owned.info().width(), owned.info().height(), owned.info().mime_type(), owned.info().muted(), + static_cast(owned.info().encryption_type()), + convertAudioFeatures(owned.info().audio_features())) {} void RemoteTrackPublication::setSubscribed(bool subscribed) { if (ffiHandleId() == 0) { - throw std::runtime_error( - "RemoteTrackPublication::setSubscribed: invalid FFI handle"); + throw std::runtime_error("RemoteTrackPublication::setSubscribed: invalid FFI handle"); } proto::FfiRequest req; - auto *msg = req.mutable_set_subscribed(); + auto* msg = req.mutable_set_subscribed(); msg->set_subscribe(subscribed); msg->set_publication_handle(static_cast(ffiHandleId())); diff --git a/src/remote_video_track.cpp b/src/remote_video_track.cpp index c957c4df..9e43e47e 100644 --- a/src/remote_video_track.cpp +++ b/src/remote_video_track.cpp @@ -23,12 +23,9 @@ namespace livekit { -RemoteVideoTrack::RemoteVideoTrack(const proto::OwnedTrack &track) - : Track(FfiHandle{static_cast(track.handle().id())}, - track.info().sid(), track.info().name(), - fromProto(track.info().kind()), - fromProto(track.info().stream_state()), track.info().muted(), - true) {} +RemoteVideoTrack::RemoteVideoTrack(const proto::OwnedTrack& track) + : Track(FfiHandle{static_cast(track.handle().id())}, track.info().sid(), track.info().name(), + fromProto(track.info().kind()), fromProto(track.info().stream_state()), track.info().muted(), true) {} std::string RemoteVideoTrack::to_string() const { return "rtc.RemoteVideoTrack(sid=" + sid() + ", name=" + name() + ")"; diff --git a/src/room.cpp b/src/room.cpp index 9eae941d..d647b0fc 100644 --- a/src/room.cpp +++ b/src/room.cpp @@ -16,6 +16,11 @@ #include "livekit/room.h" +#include + +#include "data_track.pb.h" +#include "ffi.pb.h" +#include "ffi_client.h" #include "livekit/audio_stream.h" #include "livekit/e2ee.h" #include "livekit/local_data_track.h" @@ -28,10 +33,6 @@ #include "livekit/remote_video_track.h" #include "livekit/room_delegate.h" #include "livekit/room_event_types.h" - -#include "data_track.pb.h" -#include "ffi.pb.h" -#include "ffi_client.h" #include "livekit_ffi.h" #include "lk_log.h" #include "room.pb.h" @@ -39,7 +40,6 @@ #include "trace/trace_event.h" #include "track.pb.h" #include "track_proto_converter.h" -#include namespace livekit { @@ -51,26 +51,22 @@ using proto::FfiResponse; namespace { -std::shared_ptr -createRemoteParticipant(const proto::OwnedParticipant &owned) { - const auto &pinfo = owned.info(); +std::shared_ptr createRemoteParticipant(const proto::OwnedParticipant& owned) { + const auto& pinfo = owned.info(); std::unordered_map attrs; attrs.reserve(pinfo.attributes_size()); - for (const auto &kv : pinfo.attributes()) { + for (const auto& kv : pinfo.attributes()) { attrs.emplace(kv.first, kv.second); } auto kind = livekit::fromProto(pinfo.kind()); auto reason = livekit::toDisconnectReason(pinfo.disconnect_reason()); livekit::FfiHandle handle(static_cast(owned.handle().id())); - return std::make_shared( - std::move(handle), pinfo.sid(), pinfo.name(), pinfo.identity(), - pinfo.metadata(), std::move(attrs), kind, reason); + return std::make_shared(std::move(handle), pinfo.sid(), pinfo.name(), pinfo.identity(), + pinfo.metadata(), std::move(attrs), kind, reason); } } // namespace -Room::Room() - : subscription_thread_dispatcher_( - std::make_unique()) {} +Room::Room() : subscription_thread_dispatcher_(std::make_unique()) {} Room::~Room() { if (subscription_thread_dispatcher_) { @@ -101,13 +97,12 @@ Room::~Room() { // local_participant_to_cleanup is destroyed here after listener is removed } -void Room::setDelegate(RoomDelegate *delegate) { +void Room::setDelegate(RoomDelegate* delegate) { const std::scoped_lock g(lock_); delegate_ = delegate; } -bool Room::Connect(const std::string &url, const std::string &token, - const RoomOptions &options) { +bool Room::Connect(const std::string& url, const std::string& token, const RoomOptions& options) { TRACE_EVENT0("livekit", "Room::Connect"); { @@ -119,23 +114,21 @@ bool Room::Connect(const std::string &url, const std::string &token, } auto fut = FfiClient::instance().connectAsync(url, token, options); try { - auto connectCb = - fut.get(); // fut will throw if it fails to connect to the room + auto connectCb = fut.get(); // fut will throw if it fails to connect to the room - const auto &owned_room = connectCb.result().room(); - auto new_room_handle = - std::make_shared(owned_room.handle().id()); + const auto& owned_room = connectCb.result().room(); + auto new_room_handle = std::make_shared(owned_room.handle().id()); auto new_room_info = fromProto(owned_room.info()); // Setup local particpant std::unique_ptr new_local_participant; { - const auto &owned_local = connectCb.result().local_participant(); - const auto &pinfo = owned_local.info(); + const auto& owned_local = connectCb.result().local_participant(); + const auto& pinfo = owned_local.info(); // Build attributes map std::unordered_map attrs; - for (const auto &kv : pinfo.attributes()) { + for (const auto& kv : pinfo.attributes()) { attrs.emplace(kv.first, kv.second); } @@ -143,27 +136,23 @@ bool Room::Connect(const std::string &url, const std::string &token, auto reason = toDisconnectReason(pinfo.disconnect_reason()); // Participant base stores a weak_ptr, so share the room handle - FfiHandle participant_handle( - static_cast(owned_local.handle().id())); - new_local_participant = std::make_unique( - std::move(participant_handle), pinfo.sid(), pinfo.name(), - pinfo.identity(), pinfo.metadata(), std::move(attrs), kind, reason); + FfiHandle participant_handle(static_cast(owned_local.handle().id())); + new_local_participant = + std::make_unique(std::move(participant_handle), pinfo.sid(), pinfo.name(), pinfo.identity(), + pinfo.metadata(), std::move(attrs), kind, reason); } // Setup remote participants - std::unordered_map> - new_remote_participants; + std::unordered_map> new_remote_participants; { - const auto &participants = connectCb.result().participants(); + const auto& participants = connectCb.result().participants(); const std::scoped_lock g(lock_); - for (const auto &pt : participants) { - const auto &owned = pt.participant(); + for (const auto& pt : participants) { + const auto& owned = pt.participant(); auto rp = createRemoteParticipant(owned); // Add the initial remote participant tracks - for (const auto &owned_publication_info : pt.publications()) { - auto publication = - std::make_shared(owned_publication_info); - rp->mutableTrackPublications().emplace(publication->sid(), - std::move(publication)); + for (const auto& owned_publication_info : pt.publications()) { + auto publication = std::make_shared(owned_publication_info); + rp->mutableTrackPublications().emplace(publication->sid(), std::move(publication)); } new_remote_participants.emplace(rp->identity(), std::move(rp)); @@ -174,8 +163,8 @@ bool Room::Connect(const std::string &url, const std::string &token, std::unique_ptr new_e2ee_manager; if (options.encryption) { LK_LOG_INFO("creating E2eeManager"); - new_e2ee_manager = std::unique_ptr( - new E2EEManager(new_room_handle->get(), options.encryption.value())); + new_e2ee_manager = + std::unique_ptr(new E2EEManager(new_room_handle->get(), options.encryption.value())); } // Publish all state atomically under lock @@ -190,15 +179,14 @@ bool Room::Connect(const std::string &url, const std::string &token, } // Install listener (Room is fully initialized) - auto listenerId = FfiClient::instance().AddListener( - [this](const proto::FfiEvent &e) { OnEvent(e); }); + auto listenerId = FfiClient::instance().AddListener([this](const proto::FfiEvent& e) { OnEvent(e); }); { const std::scoped_lock g(lock_); listener_id_ = listenerId; } return true; - } catch (const std::exception &e) { + } catch (const std::exception& e) { // On error, set the connection_state_ to Disconnected connection_state_ = ConnectionState::Disconnected; LK_LOG_ERROR("Room::Connect failed: {}", e.what()); @@ -211,61 +199,54 @@ RoomInfoData Room::room_info() const { return room_info_; } -LocalParticipant *Room::localParticipant() const { +LocalParticipant* Room::localParticipant() const { const std::scoped_lock g(lock_); return local_participant_.get(); } -RemoteParticipant *Room::remoteParticipant(const std::string &identity) const { +RemoteParticipant* Room::remoteParticipant(const std::string& identity) const { const std::scoped_lock g(lock_); auto it = remote_participants_.find(identity); return it == remote_participants_.end() ? nullptr : it->second.get(); } -std::vector> -Room::remoteParticipants() const { +std::vector> Room::remoteParticipants() const { const std::scoped_lock guard(lock_); std::vector> out; out.reserve(remote_participants_.size()); - for (const auto &kv : remote_participants_) { + for (const auto& kv : remote_participants_) { out.push_back(kv.second); } return out; } -E2EEManager *Room::e2eeManager() const { +E2EEManager* Room::e2eeManager() const { const std::scoped_lock g(lock_); return e2ee_manager_.get(); } -void Room::registerTextStreamHandler(const std::string &topic, - TextStreamHandler handler) { +void Room::registerTextStreamHandler(const std::string& topic, TextStreamHandler handler) { const std::scoped_lock g(lock_); - auto [it, inserted] = - text_stream_handlers_.emplace(topic, std::move(handler)); + auto [it, inserted] = text_stream_handlers_.emplace(topic, std::move(handler)); if (!inserted) { - throw std::runtime_error("text stream handler for topic '" + topic + - "' already set"); + throw std::runtime_error("text stream handler for topic '" + topic + "' already set"); } } -void Room::unregisterTextStreamHandler(const std::string &topic) { +void Room::unregisterTextStreamHandler(const std::string& topic) { const std::scoped_lock g(lock_); text_stream_handlers_.erase(topic); } -void Room::registerByteStreamHandler(const std::string &topic, - ByteStreamHandler handler) { +void Room::registerByteStreamHandler(const std::string& topic, ByteStreamHandler handler) { const std::scoped_lock g(lock_); - auto [it, inserted] = - byte_stream_handlers_.emplace(topic, std::move(handler)); + auto [it, inserted] = byte_stream_handlers_.emplace(topic, std::move(handler)); if (!inserted) { - throw std::runtime_error("byte stream handler for topic '" + topic + - "' already set"); + throw std::runtime_error("byte stream handler for topic '" + topic + "' already set"); } } -void Room::unregisterByteStreamHandler(const std::string &topic) { +void Room::unregisterByteStreamHandler(const std::string& topic) { const std::scoped_lock g(lock_); byte_stream_handlers_.erase(topic); } @@ -274,95 +255,73 @@ void Room::unregisterByteStreamHandler(const std::string &topic) { // Frame callback registration // ------------------------------------------------------------------- -void Room::setOnAudioFrameCallback(const std::string &participant_identity, - TrackSource source, - AudioFrameCallback callback, - const AudioStream::Options &opts) { +void Room::setOnAudioFrameCallback(const std::string& participant_identity, TrackSource source, + AudioFrameCallback callback, const AudioStream::Options& opts) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->setOnAudioFrameCallback( - participant_identity, source, std::move(callback), opts); + subscription_thread_dispatcher_->setOnAudioFrameCallback(participant_identity, source, std::move(callback), opts); } } -void Room::setOnAudioFrameCallback(const std::string &participant_identity, - const std::string &track_name, - AudioFrameCallback callback, - const AudioStream::Options &opts) { +void Room::setOnAudioFrameCallback(const std::string& participant_identity, const std::string& track_name, + AudioFrameCallback callback, const AudioStream::Options& opts) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->setOnAudioFrameCallback( - participant_identity, track_name, std::move(callback), opts); + subscription_thread_dispatcher_->setOnAudioFrameCallback(participant_identity, track_name, std::move(callback), + opts); } } -void Room::setOnVideoFrameCallback(const std::string &participant_identity, - TrackSource source, - VideoFrameCallback callback, - const VideoStream::Options &opts) { +void Room::setOnVideoFrameCallback(const std::string& participant_identity, TrackSource source, + VideoFrameCallback callback, const VideoStream::Options& opts) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->setOnVideoFrameCallback( - participant_identity, source, std::move(callback), opts); + subscription_thread_dispatcher_->setOnVideoFrameCallback(participant_identity, source, std::move(callback), opts); } } -void Room::setOnVideoFrameCallback(const std::string &participant_identity, - const std::string &track_name, - VideoFrameCallback callback, - const VideoStream::Options &opts) { +void Room::setOnVideoFrameCallback(const std::string& participant_identity, const std::string& track_name, + VideoFrameCallback callback, const VideoStream::Options& opts) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->setOnVideoFrameCallback( - participant_identity, track_name, std::move(callback), opts); + subscription_thread_dispatcher_->setOnVideoFrameCallback(participant_identity, track_name, std::move(callback), + opts); } } -void Room::setOnVideoFrameEventCallback(const std::string &participant_identity, - const std::string &track_name, - VideoFrameEventCallback callback, - const VideoStream::Options &opts) { +void Room::setOnVideoFrameEventCallback(const std::string& participant_identity, const std::string& track_name, + VideoFrameEventCallback callback, const VideoStream::Options& opts) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->setOnVideoFrameEventCallback( - participant_identity, track_name, std::move(callback), opts); + subscription_thread_dispatcher_->setOnVideoFrameEventCallback(participant_identity, track_name, std::move(callback), + opts); } } -void Room::clearOnAudioFrameCallback(const std::string &participant_identity, - TrackSource source) { +void Room::clearOnAudioFrameCallback(const std::string& participant_identity, TrackSource source) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->clearOnAudioFrameCallback( - participant_identity, source); + subscription_thread_dispatcher_->clearOnAudioFrameCallback(participant_identity, source); } } -void Room::clearOnAudioFrameCallback(const std::string &participant_identity, - const std::string &track_name) { +void Room::clearOnAudioFrameCallback(const std::string& participant_identity, const std::string& track_name) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->clearOnAudioFrameCallback( - participant_identity, track_name); + subscription_thread_dispatcher_->clearOnAudioFrameCallback(participant_identity, track_name); } } -void Room::clearOnVideoFrameCallback(const std::string &participant_identity, - TrackSource source) { +void Room::clearOnVideoFrameCallback(const std::string& participant_identity, TrackSource source) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->clearOnVideoFrameCallback( - participant_identity, source); + subscription_thread_dispatcher_->clearOnVideoFrameCallback(participant_identity, source); } } -void Room::clearOnVideoFrameCallback(const std::string &participant_identity, - const std::string &track_name) { +void Room::clearOnVideoFrameCallback(const std::string& participant_identity, const std::string& track_name) { if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->clearOnVideoFrameCallback( - participant_identity, track_name); + subscription_thread_dispatcher_->clearOnVideoFrameCallback(participant_identity, track_name); } } -DataFrameCallbackId -Room::addOnDataFrameCallback(const std::string &participant_identity, - const std::string &track_name, - DataFrameCallback callback) { +DataFrameCallbackId Room::addOnDataFrameCallback(const std::string& participant_identity, const std::string& track_name, + DataFrameCallback callback) { if (subscription_thread_dispatcher_) { - return subscription_thread_dispatcher_->addOnDataFrameCallback( - participant_identity, track_name, std::move(callback)); + return subscription_thread_dispatcher_->addOnDataFrameCallback(participant_identity, track_name, + std::move(callback)); } return std::numeric_limits::max(); } @@ -373,10 +332,10 @@ void Room::removeOnDataFrameCallback(DataFrameCallbackId id) { } } -void Room::OnEvent(const FfiEvent &event) { +void Room::OnEvent(const FfiEvent& event) { // Take a snapshot of the delegate under lock, but do NOT call it under the // lock. - RoomDelegate *delegate_snapshot = nullptr; + RoomDelegate* delegate_snapshot = nullptr; { const std::scoped_lock guard(lock_); delegate_snapshot = delegate_; @@ -384,9 +343,9 @@ void Room::OnEvent(const FfiEvent &event) { // First, handle RPC method invocations (not part of RoomEvent). if (event.message_case() == FfiEvent::kRpcMethodInvocation) { - const auto &rpc = event.rpc_method_invocation(); + const auto& rpc = event.rpc_method_invocation(); - LocalParticipant *lp = nullptr; + LocalParticipant* lp = nullptr; { const std::scoped_lock guard(lock_); if (!local_participant_) { @@ -394,8 +353,7 @@ void Room::OnEvent(const FfiEvent &event) { } auto local_handle = local_participant_->ffiHandleId(); if (local_handle == INVALID_HANDLE || - rpc.local_participant_handle() != - static_cast(local_handle)) { + rpc.local_participant_handle() != static_cast(local_handle)) { // RPC is not targeted at this room's local participant; ignore. return; } @@ -403,1024 +361,995 @@ void Room::OnEvent(const FfiEvent &event) { } // Call outside the lock to avoid deadlocks / re-entrancy issues. - lp->handleRpcMethodInvocation( - rpc.invocation_id(), rpc.method(), rpc.request_id(), - rpc.caller_identity(), rpc.payload(), - static_cast(rpc.response_timeout_ms()) / 1000.0); + lp->handleRpcMethodInvocation(rpc.invocation_id(), rpc.method(), rpc.request_id(), rpc.caller_identity(), + rpc.payload(), static_cast(rpc.response_timeout_ms()) / 1000.0); return; } switch (event.message_case()) { - case FfiEvent::kRoomEvent: { - const proto::RoomEvent &re = event.room_event(); + case FfiEvent::kRoomEvent: { + const proto::RoomEvent& re = event.room_event(); - // Check if this event is for our room handle - { - const std::scoped_lock guard(lock_); - if (!room_handle_ || - re.room_handle() != static_cast(room_handle_->get())) { - return; - } - } - - switch (re.message_case()) { - case proto::RoomEvent::kParticipantConnected: { - std::shared_ptr new_participant; - { - const std::scoped_lock guard(lock_); - const auto &owned = re.participant_connected().info(); - // createRemoteParticipant takes proto::OwnedParticipant - new_participant = createRemoteParticipant(owned); - remote_participants_.emplace(new_participant->identity(), - new_participant); - } - ParticipantConnectedEvent ev; - ev.participant = new_participant.get(); - if (delegate_snapshot) { - delegate_snapshot->onParticipantConnected(*this, ev); - } - break; - } - case proto::RoomEvent::kParticipantDisconnected: { - std::shared_ptr removed; - DisconnectReason reason = DisconnectReason::Unknown; + // Check if this event is for our room handle { const std::scoped_lock guard(lock_); - const auto &pd = re.participant_disconnected(); - const std::string &identity = pd.participant_identity(); - reason = toDisconnectReason(pd.disconnect_reason()); - - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - removed = it->second; - remote_participants_.erase(it); - } else { - // We saw a disconnect event for a participant we don't track - // internally. This can happen on races or if we never created a - // RemoteParticipant - LK_LOG_WARN("participant_disconnected for unknown identity: {}", - identity); + if (!room_handle_ || re.room_handle() != static_cast(room_handle_->get())) { + return; } } - if (removed) { - ParticipantDisconnectedEvent ev; - ev.participant = removed.get(); - ev.reason = reason; - if (delegate_snapshot) { - delegate_snapshot->onParticipantDisconnected(*this, ev); + + switch (re.message_case()) { + case proto::RoomEvent::kParticipantConnected: { + std::shared_ptr new_participant; + { + const std::scoped_lock guard(lock_); + const auto& owned = re.participant_connected().info(); + // createRemoteParticipant takes proto::OwnedParticipant + new_participant = createRemoteParticipant(owned); + remote_participants_.emplace(new_participant->identity(), new_participant); + } + ParticipantConnectedEvent ev; + ev.participant = new_participant.get(); + if (delegate_snapshot) { + delegate_snapshot->onParticipantConnected(*this, ev); + } + break; } - } - break; - } - case proto::RoomEvent::kLocalTrackPublished: { - LocalTrackPublishedEvent ev; - { - const std::scoped_lock guard(lock_); - if (!local_participant_) { - LK_LOG_ERROR("kLocalTrackPublished: local_participant_ is nullptr"); + case proto::RoomEvent::kParticipantDisconnected: { + std::shared_ptr removed; + DisconnectReason reason = DisconnectReason::Unknown; + { + const std::scoped_lock guard(lock_); + const auto& pd = re.participant_disconnected(); + const std::string& identity = pd.participant_identity(); + reason = toDisconnectReason(pd.disconnect_reason()); + + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + removed = it->second; + remote_participants_.erase(it); + } else { + // We saw a disconnect event for a participant we don't track + // internally. This can happen on races or if we never created a + // RemoteParticipant + LK_LOG_WARN("participant_disconnected for unknown identity: {}", identity); + } + } + if (removed) { + ParticipantDisconnectedEvent ev; + ev.participant = removed.get(); + ev.reason = reason; + if (delegate_snapshot) { + delegate_snapshot->onParticipantDisconnected(*this, ev); + } + } break; } - const auto <p = re.local_track_published(); - const std::string &sid = ltp.track_sid(); - const auto pubs = local_participant_->trackPublications(); - auto it = pubs.find(sid); - if (it == pubs.end()) { - LK_LOG_WARN("local_track_published for unknown sid: {}", sid); + case proto::RoomEvent::kLocalTrackPublished: { + LocalTrackPublishedEvent ev; + { + const std::scoped_lock guard(lock_); + if (!local_participant_) { + LK_LOG_ERROR("kLocalTrackPublished: local_participant_ is nullptr"); + break; + } + const auto& ltp = re.local_track_published(); + const std::string& sid = ltp.track_sid(); + const auto pubs = local_participant_->trackPublications(); + auto it = pubs.find(sid); + if (it == pubs.end()) { + LK_LOG_WARN("local_track_published for unknown sid: {}", sid); + break; + } + ev.publication = it->second; + ev.track = ev.publication ? ev.publication->track() : nullptr; + } + if (delegate_snapshot) { + delegate_snapshot->onLocalTrackPublished(*this, ev); + } break; } - ev.publication = it->second; - ev.track = ev.publication ? ev.publication->track() : nullptr; - } - if (delegate_snapshot) { - delegate_snapshot->onLocalTrackPublished(*this, ev); - } - break; - } - case proto::RoomEvent::kLocalTrackUnpublished: { - LocalTrackUnpublishedEvent ev; - { - const std::scoped_lock guard(lock_); - if (!local_participant_) { - LK_LOG_ERROR("kLocalTrackUnpublished: local_participant_ is nullptr"); + case proto::RoomEvent::kLocalTrackUnpublished: { + LocalTrackUnpublishedEvent ev; + { + const std::scoped_lock guard(lock_); + if (!local_participant_) { + LK_LOG_ERROR("kLocalTrackUnpublished: local_participant_ is nullptr"); + break; + } + const auto& ltu = re.local_track_unpublished(); + const std::string& pub_sid = ltu.publication_sid(); + const auto pubs = local_participant_->trackPublications(); + auto it = pubs.find(pub_sid); + if (it == pubs.end()) { + LK_LOG_WARN("local_track_unpublished for unknown publication sid: {}", pub_sid); + break; + } + ev.publication = it->second; + } + if (delegate_snapshot) { + delegate_snapshot->onLocalTrackUnpublished(*this, ev); + } break; } - const auto <u = re.local_track_unpublished(); - const std::string &pub_sid = ltu.publication_sid(); - const auto pubs = local_participant_->trackPublications(); - auto it = pubs.find(pub_sid); - if (it == pubs.end()) { - LK_LOG_WARN("local_track_unpublished for unknown publication sid: {}", - pub_sid); + case proto::RoomEvent::kLocalTrackSubscribed: { + LocalTrackSubscribedEvent ev; + { + const std::scoped_lock guard(lock_); + if (!local_participant_) { + break; + } + const auto& lts = re.local_track_subscribed(); + const std::string& sid = lts.track_sid(); + const auto pubs = local_participant_->trackPublications(); + auto it = pubs.find(sid); + if (it == pubs.end()) { + LK_LOG_WARN("local_track_subscribed for unknown sid: {}", sid); + break; + } + auto publication = it->second; + ev.track = publication ? publication->track() : nullptr; + } + + if (delegate_snapshot) { + delegate_snapshot->onLocalTrackSubscribed(*this, ev); + } break; } - ev.publication = it->second; - } - if (delegate_snapshot) { - delegate_snapshot->onLocalTrackUnpublished(*this, ev); - } - break; - } - case proto::RoomEvent::kLocalTrackSubscribed: { - LocalTrackSubscribedEvent ev; - { - const std::scoped_lock guard(lock_); - if (!local_participant_) { + case proto::RoomEvent::kTrackPublished: { + TrackPublishedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& tp = re.track_published(); + const std::string& identity = tp.participant_identity(); + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + RemoteParticipant* rparticipant = it->second.get(); + const auto& owned_publication = tp.publication(); + auto rpublication = std::make_shared(owned_publication); + // Store it on the participant, keyed by SID + rparticipant->mutableTrackPublications().emplace(rpublication->sid(), std::move(rpublication)); + ev.participant = rparticipant; + ev.publication = rpublication; + } else { + // Optional: log if we get a track for an unknown participant + LK_LOG_WARN("track_published for unknown participant: {}", identity); + // Don't emit the + break; + } + } + if (delegate_snapshot) { + delegate_snapshot->onTrackPublished(*this, ev); + } break; } - const auto <s = re.local_track_subscribed(); - const std::string &sid = lts.track_sid(); - const auto pubs = local_participant_->trackPublications(); - auto it = pubs.find(sid); - if (it == pubs.end()) { - LK_LOG_WARN("local_track_subscribed for unknown sid: {}", sid); + case proto::RoomEvent::kTrackUnpublished: { + TrackUnpublishedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& tu = re.track_unpublished(); + const std::string& identity = tu.participant_identity(); + const std::string& pub_sid = tu.publication_sid(); + auto pit = remote_participants_.find(identity); + if (pit == remote_participants_.end()) { + LK_LOG_WARN("track_unpublished for unknown participant: {}", identity); + break; + } + RemoteParticipant* rparticipant = pit->second.get(); + auto& pubs = rparticipant->mutableTrackPublications(); + auto it = pubs.find(pub_sid); + if (it == pubs.end()) { + LK_LOG_WARN( + "track_unpublished for unknown publication sid {} " + "(participant {})", + pub_sid, identity); + break; + } + ev.participant = rparticipant; + ev.publication = it->second; + pubs.erase(it); + } + + if (delegate_snapshot) { + delegate_snapshot->onTrackUnpublished(*this, ev); + } break; } - auto publication = it->second; - ev.track = publication ? publication->track() : nullptr; - } + case proto::RoomEvent::kTrackSubscribed: { + const auto& ts = re.track_subscribed(); + const std::string& identity = ts.participant_identity(); + const auto& owned_track = ts.track(); + const auto& track_info = owned_track.info(); + std::shared_ptr rpublication; + RemoteParticipant* rparticipant = nullptr; + std::shared_ptr remote_track; + { + const std::scoped_lock guard(lock_); + // Find participant + auto pit = remote_participants_.find(identity); + if (pit == remote_participants_.end()) { + LK_LOG_WARN("track_subscribed for unknown participant: {}", identity); + break; + } + rparticipant = pit->second.get(); + // Find existing publication by track SID (from track_published) + auto& pubs = rparticipant->mutableTrackPublications(); + auto pubIt = pubs.find(track_info.sid()); + if (pubIt == pubs.end()) { + LK_LOG_WARN( + "track_subscribed for unknown publication sid {} " + "(participant {})", + track_info.sid(), identity); + break; + } + rpublication = pubIt->second; + + // Create RemoteVideoTrack / RemoteAudioTrack + if (track_info.kind() == proto::TrackKind::KIND_VIDEO) { + remote_track = std::make_shared(owned_track); + } else if (track_info.kind() == proto::TrackKind::KIND_AUDIO) { + remote_track = std::make_shared(owned_track); + } else { + LK_LOG_WARN("track_subscribed with unsupported kind: {}", static_cast(track_info.kind())); + break; + } + // Attach to publication, mark subscribed + rpublication->setTrack(remote_track); + rpublication->setSubscribed(true); + } - if (delegate_snapshot) { - delegate_snapshot->onLocalTrackSubscribed(*this, ev); - } - break; - } - case proto::RoomEvent::kTrackPublished: { - TrackPublishedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &tp = re.track_published(); - const std::string &identity = tp.participant_identity(); - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - RemoteParticipant *rparticipant = it->second.get(); - const auto &owned_publication = tp.publication(); - auto rpublication = - std::make_shared(owned_publication); - // Store it on the participant, keyed by SID - rparticipant->mutableTrackPublications().emplace( - rpublication->sid(), std::move(rpublication)); - ev.participant = rparticipant; + // Emit remote track_subscribed-style callback + TrackSubscribedEvent ev; + ev.track = remote_track; ev.publication = rpublication; - } else { - // Optional: log if we get a track for an unknown participant - LK_LOG_WARN("track_published for unknown participant: {}", identity); - // Don't emit the + ev.participant = rparticipant; + if (delegate_snapshot) { + delegate_snapshot->onTrackSubscribed(*this, ev); + } + + if (subscription_thread_dispatcher_ && remote_track && rpublication) { + subscription_thread_dispatcher_->handleTrackSubscribed(identity, rpublication->source(), + rpublication->name(), remote_track); + } break; } - } - if (delegate_snapshot) { - delegate_snapshot->onTrackPublished(*this, ev); - } - break; - } - case proto::RoomEvent::kTrackUnpublished: { - TrackUnpublishedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &tu = re.track_unpublished(); - const std::string &identity = tu.participant_identity(); - const std::string &pub_sid = tu.publication_sid(); - auto pit = remote_participants_.find(identity); - if (pit == remote_participants_.end()) { - LK_LOG_WARN("track_unpublished for unknown participant: {}", - identity); + case proto::RoomEvent::kTrackUnsubscribed: { + TrackUnsubscribedEvent ev; + TrackSource unsub_source = TrackSource::SOURCE_UNKNOWN; + std::string unsub_identity; + { + const std::scoped_lock guard(lock_); + const auto& tu = re.track_unsubscribed(); + unsub_identity = tu.participant_identity(); + const std::string& track_sid = tu.track_sid(); + auto pit = remote_participants_.find(unsub_identity); + if (pit == remote_participants_.end()) { + LK_LOG_WARN("track_unsubscribed for unknown participant: {}", unsub_identity); + break; + } + RemoteParticipant* rparticipant = pit->second.get(); + auto& pubs = rparticipant->mutableTrackPublications(); + auto pubIt = pubs.find(track_sid); + if (pubIt == pubs.end()) { + LK_LOG_WARN( + "track_unsubscribed for unknown publication sid {} " + "(participant {})", + track_sid, unsub_identity); + break; + } + auto publication = pubIt->second; + unsub_source = publication->source(); + auto track = publication->track(); + publication->setTrack(nullptr); + publication->setSubscribed(false); + ev.participant = rparticipant; + ev.publication = publication; + ev.track = track; + } + + if (delegate_snapshot) { + delegate_snapshot->onTrackUnsubscribed(*this, ev); + } + + if (subscription_thread_dispatcher_ && unsub_source != TrackSource::SOURCE_UNKNOWN) { + subscription_thread_dispatcher_->handleTrackUnsubscribed(unsub_identity, unsub_source, + ev.publication ? ev.publication->name() : ""); + } break; } - RemoteParticipant *rparticipant = pit->second.get(); - auto &pubs = rparticipant->mutableTrackPublications(); - auto it = pubs.find(pub_sid); - if (it == pubs.end()) { - LK_LOG_WARN("track_unpublished for unknown publication sid {} " - "(participant {})", - pub_sid, identity); + case proto::RoomEvent::kTrackSubscriptionFailed: { + TrackSubscriptionFailedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& tsf = re.track_subscription_failed(); + const std::string& identity = tsf.participant_identity(); + auto pit = remote_participants_.find(identity); + if (pit == remote_participants_.end()) { + LK_LOG_WARN("track_subscription_failed for unknown participant: {}", identity); + break; + } + ev.participant = pit->second.get(); + ev.track_sid = tsf.track_sid(); + ev.error = tsf.error(); + } + if (delegate_snapshot) { + delegate_snapshot->onTrackSubscriptionFailed(*this, ev); + } break; } - ev.participant = rparticipant; - ev.publication = it->second; - pubs.erase(it); - } + case proto::RoomEvent::kDataTrackPublished: { + const auto& rdtp = re.data_track_published(); + auto remote_track = std::shared_ptr(new RemoteDataTrack(rdtp.track())); - if (delegate_snapshot) { - delegate_snapshot->onTrackUnpublished(*this, ev); - } - break; - } - case proto::RoomEvent::kTrackSubscribed: { - const auto &ts = re.track_subscribed(); - const std::string &identity = ts.participant_identity(); - const auto &owned_track = ts.track(); - const auto &track_info = owned_track.info(); - std::shared_ptr rpublication; - RemoteParticipant *rparticipant = nullptr; - std::shared_ptr remote_track; - { - const std::scoped_lock guard(lock_); - // Find participant - auto pit = remote_participants_.find(identity); - if (pit == remote_participants_.end()) { - LK_LOG_WARN("track_subscribed for unknown participant: {}", identity); + if (subscription_thread_dispatcher_) { + subscription_thread_dispatcher_->handleDataTrackPublished(remote_track); + } + + DataTrackPublishedEvent ev; + ev.track = remote_track; + if (delegate_snapshot) { + delegate_snapshot->onDataTrackPublished(*this, ev); + } break; } - rparticipant = pit->second.get(); - // Find existing publication by track SID (from track_published) - auto &pubs = rparticipant->mutableTrackPublications(); - auto pubIt = pubs.find(track_info.sid()); - if (pubIt == pubs.end()) { - LK_LOG_WARN("track_subscribed for unknown publication sid {} " - "(participant {})", - track_info.sid(), identity); + case proto::RoomEvent::kDataTrackUnpublished: { + const auto& dtu = re.data_track_unpublished(); + + if (subscription_thread_dispatcher_) { + subscription_thread_dispatcher_->handleDataTrackUnpublished(dtu.sid()); + } + + DataTrackUnpublishedEvent ev; + ev.sid = dtu.sid(); + if (delegate_snapshot) { + delegate_snapshot->onDataTrackUnpublished(*this, ev); + } break; } - rpublication = pubIt->second; - - // Create RemoteVideoTrack / RemoteAudioTrack - if (track_info.kind() == proto::TrackKind::KIND_VIDEO) { - remote_track = std::make_shared(owned_track); - } else if (track_info.kind() == proto::TrackKind::KIND_AUDIO) { - remote_track = std::make_shared(owned_track); - } else { - LK_LOG_WARN("track_subscribed with unsupported kind: {}", - static_cast(track_info.kind())); + case proto::RoomEvent::kTrackMuted: { + TrackMutedEvent ev; + bool success = false; + { + const std::scoped_lock guard(lock_); + const auto& tm = re.track_muted(); + const std::string& identity = tm.participant_identity(); + const std::string& sid = tm.track_sid(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto pit = remote_participants_.find(identity); + if (pit != remote_participants_.end()) { + participant = pit->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("track_muted for unknown participant: {}", identity); + break; + } + auto pub = participant->findTrackPublication(sid); + if (!pub) { + LK_LOG_WARN("track_muted for unknown track sid: {}", sid); + } else { + pub->setMuted(true); + if (auto t = pub->track()) { + t->setMuted(true); + } + ev.participant = participant; + ev.publication = pub; + success = true; + } + } + if (success && delegate_snapshot) { + delegate_snapshot->onTrackMuted(*this, ev); + } break; } - // Attach to publication, mark subscribed - rpublication->setTrack(remote_track); - rpublication->setSubscribed(true); - } + case proto::RoomEvent::kTrackUnmuted: { + TrackUnmutedEvent ev; + bool success = false; + { + const std::scoped_lock guard(lock_); + const auto& tu = re.track_unmuted(); + const std::string& identity = tu.participant_identity(); + const std::string& sid = tu.track_sid(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto pit = remote_participants_.find(identity); + if (pit != remote_participants_.end()) { + participant = pit->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("track_unmuted for unknown participant: {}", identity); + break; + } - // Emit remote track_subscribed-style callback - TrackSubscribedEvent ev; - ev.track = remote_track; - ev.publication = rpublication; - ev.participant = rparticipant; - if (delegate_snapshot) { - delegate_snapshot->onTrackSubscribed(*this, ev); - } + auto pub = participant->findTrackPublication(sid); + if (!pub) { + LK_LOG_WARN("track_unmuted for unknown track sid: {}", sid); + } else { + pub->setMuted(false); + if (auto t = pub->track()) { + t->setMuted(false); + } + ev.participant = participant; + ev.publication = pub; + success = true; + } - if (subscription_thread_dispatcher_ && remote_track && rpublication) { - subscription_thread_dispatcher_->handleTrackSubscribed( - identity, rpublication->source(), rpublication->name(), - remote_track); - } - break; - } - case proto::RoomEvent::kTrackUnsubscribed: { - TrackUnsubscribedEvent ev; - TrackSource unsub_source = TrackSource::SOURCE_UNKNOWN; - std::string unsub_identity; - { - const std::scoped_lock guard(lock_); - const auto &tu = re.track_unsubscribed(); - unsub_identity = tu.participant_identity(); - const std::string &track_sid = tu.track_sid(); - auto pit = remote_participants_.find(unsub_identity); - if (pit == remote_participants_.end()) { - LK_LOG_WARN("track_unsubscribed for unknown participant: {}", - unsub_identity); + ev.participant = participant; + ev.publication = pub; + } + + if (success && delegate_snapshot) { + delegate_snapshot->onTrackUnmuted(*this, ev); + } break; } - RemoteParticipant *rparticipant = pit->second.get(); - auto &pubs = rparticipant->mutableTrackPublications(); - auto pubIt = pubs.find(track_sid); - if (pubIt == pubs.end()) { - LK_LOG_WARN("track_unsubscribed for unknown publication sid {} " - "(participant {})", - track_sid, unsub_identity); + case proto::RoomEvent::kActiveSpeakersChanged: { + ActiveSpeakersChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& asc = re.active_speakers_changed(); + for (const auto& identity : asc.participant_identities()) { + // Appears to be clang-tidy false positive + // NOLINTNEXTLINE(misc-const-correctness) + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto pit = remote_participants_.find(identity); + if (pit != remote_participants_.end()) { + participant = pit->second.get(); + } + } + if (participant) { + ev.speakers.push_back(participant); + } + } + } + if (delegate_snapshot) { + delegate_snapshot->onActiveSpeakersChanged(*this, ev); + } break; } - auto publication = pubIt->second; - unsub_source = publication->source(); - auto track = publication->track(); - publication->setTrack(nullptr); - publication->setSubscribed(false); - ev.participant = rparticipant; - ev.publication = publication; - ev.track = track; - } - - if (delegate_snapshot) { - delegate_snapshot->onTrackUnsubscribed(*this, ev); - } - - if (subscription_thread_dispatcher_ && - unsub_source != TrackSource::SOURCE_UNKNOWN) { - subscription_thread_dispatcher_->handleTrackUnsubscribed( - unsub_identity, unsub_source, - ev.publication ? ev.publication->name() : ""); - } - break; - } - case proto::RoomEvent::kTrackSubscriptionFailed: { - TrackSubscriptionFailedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &tsf = re.track_subscription_failed(); - const std::string &identity = tsf.participant_identity(); - auto pit = remote_participants_.find(identity); - if (pit == remote_participants_.end()) { - LK_LOG_WARN("track_subscription_failed for unknown participant: {}", - identity); + case proto::RoomEvent::kRoomMetadataChanged: { + RoomMetadataChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto old_metadata = room_info_.metadata; + room_info_.metadata = re.room_metadata_changed().metadata(); + ev.old_metadata = old_metadata; + ev.new_metadata = room_info_.metadata; + } + if (delegate_snapshot) { + delegate_snapshot->onRoomMetadataChanged(*this, ev); + } break; } - ev.participant = pit->second.get(); - ev.track_sid = tsf.track_sid(); - ev.error = tsf.error(); - } - if (delegate_snapshot) { - delegate_snapshot->onTrackSubscriptionFailed(*this, ev); - } - break; - } - case proto::RoomEvent::kDataTrackPublished: { - const auto &rdtp = re.data_track_published(); - auto remote_track = - std::shared_ptr(new RemoteDataTrack(rdtp.track())); - - if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->handleDataTrackPublished(remote_track); - } - - DataTrackPublishedEvent ev; - ev.track = remote_track; - if (delegate_snapshot) { - delegate_snapshot->onDataTrackPublished(*this, ev); - } - break; - } - case proto::RoomEvent::kDataTrackUnpublished: { - const auto &dtu = re.data_track_unpublished(); - - if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->handleDataTrackUnpublished(dtu.sid()); - } - - DataTrackUnpublishedEvent ev; - ev.sid = dtu.sid(); - if (delegate_snapshot) { - delegate_snapshot->onDataTrackUnpublished(*this, ev); - } - break; - } - case proto::RoomEvent::kTrackMuted: { - TrackMutedEvent ev; - bool success = false; - { - const std::scoped_lock guard(lock_); - const auto &tm = re.track_muted(); - const std::string &identity = tm.participant_identity(); - const std::string &sid = tm.track_sid(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto pit = remote_participants_.find(identity); - if (pit != remote_participants_.end()) { - participant = pit->second.get(); + case proto::RoomEvent::kRoomSidChanged: { + RoomSidChangedEvent ev; + { + const std::scoped_lock guard(lock_); + room_info_.sid = re.room_sid_changed().sid(); + ev.sid = room_info_.sid.value_or(std::string{}); + } + if (delegate_snapshot) { + delegate_snapshot->onRoomSidChanged(*this, ev); } - } - if (!participant) { - LK_LOG_WARN("track_muted for unknown participant: {}", identity); break; } - auto pub = participant->findTrackPublication(sid); - if (!pub) { - LK_LOG_WARN("track_muted for unknown track sid: {}", sid); - } else { - pub->setMuted(true); - if (auto t = pub->track()) { - t->setMuted(true); - } - ev.participant = participant; - ev.publication = pub; - success = true; + case proto::RoomEvent::kParticipantMetadataChanged: { + ParticipantMetadataChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& pm = re.participant_metadata_changed(); + const std::string& identity = pm.participant_identity(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("participant_metadata_changed for unknown participant: {}", identity); + break; + } + const std::string old_metadata = participant->metadata(); + participant->set_metadata(pm.metadata()); + ev.participant = participant; + ev.old_metadata = old_metadata; + ev.new_metadata = participant->metadata(); + } + + if (delegate_snapshot) { + delegate_snapshot->onParticipantMetadataChanged(*this, ev); + } + break; } - } - if (success && delegate_snapshot) { - delegate_snapshot->onTrackMuted(*this, ev); - } - break; - } - case proto::RoomEvent::kTrackUnmuted: { - TrackUnmutedEvent ev; - bool success = false; - { - const std::scoped_lock guard(lock_); - const auto &tu = re.track_unmuted(); - const std::string &identity = tu.participant_identity(); - const std::string &sid = tu.track_sid(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto pit = remote_participants_.find(identity); - if (pit != remote_participants_.end()) { - participant = pit->second.get(); + case proto::RoomEvent::kParticipantNameChanged: { + ParticipantNameChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& pn = re.participant_name_changed(); + const std::string& identity = pn.participant_identity(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("participant_name_changed for unknown participant: {}", identity); + break; + } + const std::string old_name = participant->name(); + participant->set_name(pn.name()); + ev.participant = participant; + ev.old_name = old_name; + ev.new_name = participant->name(); + } + if (delegate_snapshot) { + delegate_snapshot->onParticipantNameChanged(*this, ev); } + break; } - if (!participant) { - LK_LOG_WARN("track_unmuted for unknown participant: {}", identity); + case proto::RoomEvent::kParticipantAttributesChanged: { + ParticipantAttributesChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& pa = re.participant_attributes_changed(); + const std::string& identity = pa.participant_identity(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("participant_attributes_changed for unknown participant: {}", identity); + break; + } + // Build full attributes map + std::unordered_map attrs; + for (const auto& entry : pa.attributes()) { + attrs.emplace(entry.key(), entry.value()); + } + participant->set_attributes(attrs); + + // Build changed_attributes map + for (const auto& entry : pa.changed_attributes()) { + ev.changed_attributes.emplace_back(entry.key(), entry.value()); + } + ev.participant = participant; + } + if (delegate_snapshot) { + delegate_snapshot->onParticipantAttributesChanged(*this, ev); + } break; } + case proto::RoomEvent::kParticipantEncryptionStatusChanged: { + ParticipantEncryptionStatusChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& pe = re.participant_encryption_status_changed(); + const std::string& identity = pe.participant_identity(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN( + "participant_encryption_status_changed for unknown " + "participant: {}", + identity); + break; + } + ev.participant = participant; + ev.is_encrypted = pe.is_encrypted(); + } - auto pub = participant->findTrackPublication(sid); - if (!pub) { - LK_LOG_WARN("track_unmuted for unknown track sid: {}", sid); - } else { - pub->setMuted(false); - if (auto t = pub->track()) { - t->setMuted(false); - } - ev.participant = participant; - ev.publication = pub; - success = true; + if (delegate_snapshot) { + delegate_snapshot->onParticipantEncryptionStatusChanged(*this, ev); + } + break; } + case proto::RoomEvent::kConnectionQualityChanged: { + ConnectionQualityChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& cq = re.connection_quality_changed(); + const std::string& identity = cq.participant_identity(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("connection_quality_changed for unknown participant: {}", identity); + break; + } + ev.participant = participant; + ev.quality = static_cast(cq.quality()); + } - ev.participant = participant; - ev.publication = pub; - } + if (delegate_snapshot) { + delegate_snapshot->onConnectionQualityChanged(*this, ev); + } + break; + } - if (success && delegate_snapshot) { - delegate_snapshot->onTrackUnmuted(*this, ev); - } - break; - } - case proto::RoomEvent::kActiveSpeakersChanged: { - ActiveSpeakersChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &asc = re.active_speakers_changed(); - for (const auto &identity : asc.participant_identities()) { - // Appears to be clang-tidy false positive - // NOLINTNEXTLINE(misc-const-correctness) - Participant *participant = nullptr; - if (local_participant_ && - local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto pit = remote_participants_.find(identity); - if (pit != remote_participants_.end()) { - participant = pit->second.get(); + // ------------------------------------------------------------------------ + // Data packets: user vs SIP DTMF + // ------------------------------------------------------------------------ + case proto::RoomEvent::kDataPacketReceived: { + const auto& dp = re.data_packet_received(); + RemoteParticipant* rp = nullptr; + { + const std::scoped_lock guard(lock_); + auto it = remote_participants_.find(dp.participant_identity()); + if (it != remote_participants_.end()) { + rp = it->second.get(); } } - if (participant) { - ev.speakers.push_back(participant); + const auto which_val = dp.value_case(); + if (which_val == proto::DataPacketReceived::kUser && delegate_snapshot) { + const UserDataPacketEvent ev = userDataPacketFromProto(dp, rp); + delegate_snapshot->onUserPacketReceived(*this, ev); + } else if (which_val == proto::DataPacketReceived::kSipDtmf && delegate_snapshot) { + const SipDtmfReceivedEvent ev = sipDtmfFromProto(dp, rp); + delegate_snapshot->onSipDtmfReceived(*this, ev); } + break; } - } - if (delegate_snapshot) { - delegate_snapshot->onActiveSpeakersChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kRoomMetadataChanged: { - RoomMetadataChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto old_metadata = room_info_.metadata; - room_info_.metadata = re.room_metadata_changed().metadata(); - ev.old_metadata = old_metadata; - ev.new_metadata = room_info_.metadata; - } - if (delegate_snapshot) { - delegate_snapshot->onRoomMetadataChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kRoomSidChanged: { - RoomSidChangedEvent ev; - { - const std::scoped_lock guard(lock_); - room_info_.sid = re.room_sid_changed().sid(); - ev.sid = room_info_.sid.value_or(std::string{}); - } - if (delegate_snapshot) { - delegate_snapshot->onRoomSidChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kParticipantMetadataChanged: { - ParticipantMetadataChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &pm = re.participant_metadata_changed(); - const std::string &identity = pm.participant_identity(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + + // ------------------------------------------------------------------------ + // E2EE state + // ------------------------------------------------------------------------ + case proto::RoomEvent::kE2EeStateChanged: { + E2eeStateChangedEvent ev; + { + LK_LOG_DEBUG("e2ee_state_changed for participant"); + const std::scoped_lock guard(lock_); + const auto& es = re.e2ee_state_changed(); + const std::string& identity = es.participant_identity(); + Participant* participant = nullptr; + if (local_participant_ && local_participant_->identity() == identity) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("e2ee_state_changed for unknown participant: {}", identity); + break; + } + + ev.participant = participant; + ev.state = static_cast(es.state()); + } + if (delegate_snapshot) { + delegate_snapshot->onE2eeStateChanged(*this, ev); } - } - if (!participant) { - LK_LOG_WARN( - "participant_metadata_changed for unknown participant: {}", - identity); break; } - const std::string old_metadata = participant->metadata(); - participant->set_metadata(pm.metadata()); - ev.participant = participant; - ev.old_metadata = old_metadata; - ev.new_metadata = participant->metadata(); - } - if (delegate_snapshot) { - delegate_snapshot->onParticipantMetadataChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kParticipantNameChanged: { - ParticipantNameChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &pn = re.participant_name_changed(); - const std::string &identity = pn.participant_identity(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + // ------------------------------------------------------------------------ + // Connection state / lifecycle + // ------------------------------------------------------------------------ + + case proto::RoomEvent::kConnectionStateChanged: { + ConnectionStateChangedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& cs = re.connection_state_changed(); + // TODO, maybe we should update our |connection_state_| + // correspoindingly, but the this kConnectionStateChanged event is never + // triggered in my local test. + LK_LOG_DEBUG("cs.state() is {} connection_state_ is {}", static_cast(cs.state()), + static_cast(connection_state_)); + ev.state = static_cast(cs.state()); + } + if (delegate_snapshot) { + delegate_snapshot->onConnectionStateChanged(*this, ev); } - } - if (!participant) { - LK_LOG_WARN("participant_name_changed for unknown participant: {}", - identity); break; } - const std::string old_name = participant->name(); - participant->set_name(pn.name()); - ev.participant = participant; - ev.old_name = old_name; - ev.new_name = participant->name(); - } - if (delegate_snapshot) { - delegate_snapshot->onParticipantNameChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kParticipantAttributesChanged: { - ParticipantAttributesChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &pa = re.participant_attributes_changed(); - const std::string &identity = pa.participant_identity(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + case proto::RoomEvent::kDisconnected: { + DisconnectedEvent ev; + ev.reason = toDisconnectReason(re.disconnected().reason()); + if (delegate_snapshot) { + delegate_snapshot->onDisconnected(*this, ev); } + break; } - if (!participant) { - LK_LOG_WARN( - "participant_attributes_changed for unknown participant: {}", - identity); + case proto::RoomEvent::kReconnecting: { + const ReconnectingEvent ev; + if (delegate_snapshot) { + delegate_snapshot->onReconnecting(*this, ev); + } break; } - // Build full attributes map - std::unordered_map attrs; - for (const auto &entry : pa.attributes()) { - attrs.emplace(entry.key(), entry.value()); + case proto::RoomEvent::kReconnected: { + const ReconnectedEvent ev; + if (delegate_snapshot) { + delegate_snapshot->onReconnected(*this, ev); + } + break; } - participant->set_attributes(attrs); + case proto::RoomEvent::kEos: { + if (subscription_thread_dispatcher_) { + subscription_thread_dispatcher_->stopAll(); + } - // Build changed_attributes map - for (const auto &entry : pa.changed_attributes()) { - ev.changed_attributes.emplace_back(entry.key(), entry.value()); - } - ev.participant = participant; - } - if (delegate_snapshot) { - delegate_snapshot->onParticipantAttributesChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kParticipantEncryptionStatusChanged: { - ParticipantEncryptionStatusChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &pe = re.participant_encryption_status_changed(); - const std::string &identity = pe.participant_identity(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + int listener_to_remove = 0; + + // Move state out of lock scope before destroying to avoid holding lock + // during potentially long destructors + std::unique_ptr old_local_participant; + std::unordered_map> old_remote_participants; + std::shared_ptr old_room_handle; + std::unique_ptr old_e2ee_manager; + std::unordered_map> old_text_readers; + std::unordered_map> old_byte_readers; + + { + const std::scoped_lock guard(lock_); + listener_to_remove = listener_id_; + listener_id_ = 0; + + // Reset connection state + connection_state_ = ConnectionState::Disconnected; + + // Move state out for cleanup outside lock + old_local_participant = std::move(local_participant_); + old_remote_participants = std::move(remote_participants_); + old_room_handle = std::move(room_handle_); + old_e2ee_manager = std::move(e2ee_manager_); + old_text_readers = std::move(text_stream_readers_); + old_byte_readers = std::move(byte_stream_readers_); + } + + // Remove listener outside lock + if (listener_to_remove != 0) { + FfiClient::instance().RemoveListener(listener_to_remove); + } + + // Old state will be destroyed here when going out of scope + + const RoomEosEvent ev; + if (delegate_snapshot) { + delegate_snapshot->onRoomEos(*this, ev); } + break; } - if (!participant) { - LK_LOG_WARN("participant_encryption_status_changed for unknown " - "participant: {}", - identity); + case proto::RoomEvent::kChatMessage: { + // Deprecated event, do nothing. break; } - ev.participant = participant; - ev.is_encrypted = pe.is_encrypted(); - } + case proto::RoomEvent::kStreamHeaderReceived: { + const auto& sh = re.stream_header_received(); + const auto& header = sh.header(); + const std::string& participant_identity = sh.participant_identity(); + + // Snapshot handler + create reader without holding lock during user + // callback + TextStreamHandler text_cb; + ByteStreamHandler byte_cb; + std::shared_ptr text_reader; + std::shared_ptr byte_reader; + { + const std::scoped_lock guard(lock_); + + // Determine stream type from oneof in protobuf + // Adjust these names if your generated C++ uses different ones + const auto stream_type = header.content_header_case(); + if (stream_type == proto::DataStream::Header::kTextHeader) { + auto it = text_stream_handlers_.find(header.topic()); + if (it == text_stream_handlers_.end()) { + // Ignore if no callback attached + break; + } + text_cb = it->second; + + const TextStreamInfo info = makeTextInfo(header); + text_reader = std::make_shared(info); + text_stream_readers_[header.stream_id()] = text_reader; + + } else if (stream_type == proto::DataStream::Header::kByteHeader) { + auto it = byte_stream_handlers_.find(header.topic()); + if (it == byte_stream_handlers_.end()) { + break; + } + byte_cb = it->second; + const ByteStreamInfo info = makeByteInfo(header); + byte_reader = std::make_shared(info); + byte_stream_readers_[header.stream_id()] = byte_reader; + + } else { + // unknown header type: ignore + break; + } + } - if (delegate_snapshot) { - delegate_snapshot->onParticipantEncryptionStatusChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kConnectionQualityChanged: { - ConnectionQualityChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &cq = re.connection_quality_changed(); - const std::string &identity = cq.participant_identity(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + // Invoke user callback outside lock (very important) + if (text_reader) { + text_cb(text_reader, participant_identity); + } else if (byte_reader) { + byte_cb(byte_reader, participant_identity); } + break; } - if (!participant) { - LK_LOG_WARN("connection_quality_changed for unknown participant: {}", - identity); + case proto::RoomEvent::kStreamChunkReceived: { + const auto& sc = re.stream_chunk_received(); + const auto& chunk = sc.chunk(); + std::shared_ptr text_reader; + std::shared_ptr byte_reader; + { + const std::scoped_lock guard(lock_); + auto itT = text_stream_readers_.find(chunk.stream_id()); + if (itT != text_stream_readers_.end()) { + text_reader = itT->second; + } else { + auto itB = byte_stream_readers_.find(chunk.stream_id()); + if (itB != byte_stream_readers_.end()) { + byte_reader = itB->second; + } + } + } + if (text_reader) { + // chunk.content() is bytes; treat as UTF-8 string. + text_reader->onChunkUpdate(chunk.content()); + } else if (byte_reader) { + // Convert string bytes -> vector + const std::string& s = chunk.content(); + const std::vector bytes(s.begin(), s.end()); + byte_reader->onChunkUpdate(bytes); + } break; } - ev.participant = participant; - ev.quality = static_cast(cq.quality()); - } - - if (delegate_snapshot) { - delegate_snapshot->onConnectionQualityChanged(*this, ev); - } - break; - } - - // ------------------------------------------------------------------------ - // Data packets: user vs SIP DTMF - // ------------------------------------------------------------------------ - case proto::RoomEvent::kDataPacketReceived: { - const auto &dp = re.data_packet_received(); - RemoteParticipant *rp = nullptr; - { - const std::scoped_lock guard(lock_); - auto it = remote_participants_.find(dp.participant_identity()); - if (it != remote_participants_.end()) { - rp = it->second.get(); + case proto::RoomEvent::kStreamTrailerReceived: { + const auto& st = re.stream_trailer_received(); + const auto& trailer = st.trailer(); + std::shared_ptr text_reader; + std::shared_ptr byte_reader; + std::map trailer_attrs; + for (const auto& kv : trailer.attributes()) { + trailer_attrs.emplace(kv.first, kv.second); + } + { + const std::scoped_lock guard(lock_); + auto itT = text_stream_readers_.find(trailer.stream_id()); + if (itT != text_stream_readers_.end()) { + text_reader = itT->second; + text_stream_readers_.erase(itT); + } else { + auto itB = byte_stream_readers_.find(trailer.stream_id()); + if (itB != byte_stream_readers_.end()) { + byte_reader = itB->second; + byte_stream_readers_.erase(itB); + } + } + } + if (text_reader) { + text_reader->onStreamClose(trailer_attrs); + } else if (byte_reader) { + byte_reader->onStreamClose(trailer_attrs); + } + break; } - } - const auto which_val = dp.value_case(); - if (which_val == proto::DataPacketReceived::kUser && delegate_snapshot) { - const UserDataPacketEvent ev = userDataPacketFromProto(dp, rp); - delegate_snapshot->onUserPacketReceived(*this, ev); - } else if (which_val == proto::DataPacketReceived::kSipDtmf && - delegate_snapshot) { - const SipDtmfReceivedEvent ev = sipDtmfFromProto(dp, rp); - delegate_snapshot->onSipDtmfReceived(*this, ev); - } - break; - } - - // ------------------------------------------------------------------------ - // E2EE state - // ------------------------------------------------------------------------ - case proto::RoomEvent::kE2EeStateChanged: { - E2eeStateChangedEvent ev; - { - LK_LOG_DEBUG("e2ee_state_changed for participant"); - const std::scoped_lock guard(lock_); - const auto &es = re.e2ee_state_changed(); - const std::string &identity = es.participant_identity(); - Participant *participant = nullptr; - if (local_participant_ && local_participant_->identity() == identity) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + case proto::RoomEvent::kDataChannelLowThresholdChanged: { + auto ev = fromProto(re.data_channel_low_threshold_changed()); + if (delegate_snapshot) { + delegate_snapshot->onDataChannelBufferedAmountLowThresholdChanged(*this, ev); } + break; } - if (!participant) { - LK_LOG_WARN("e2ee_state_changed for unknown participant: {}", - identity); + case proto::RoomEvent::kByteStreamOpened: { + auto ev = fromProto(re.byte_stream_opened()); + if (delegate_snapshot) { + delegate_snapshot->onByteStreamOpened(*this, ev); + } break; } - - ev.participant = participant; - ev.state = static_cast(es.state()); - } - if (delegate_snapshot) { - delegate_snapshot->onE2eeStateChanged(*this, ev); - } - break; - } - - // ------------------------------------------------------------------------ - // Connection state / lifecycle - // ------------------------------------------------------------------------ - - case proto::RoomEvent::kConnectionStateChanged: { - ConnectionStateChangedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &cs = re.connection_state_changed(); - // TODO, maybe we should update our |connection_state_| - // correspoindingly, but the this kConnectionStateChanged event is never - // triggered in my local test. - LK_LOG_DEBUG("cs.state() is {} connection_state_ is {}", - static_cast(cs.state()), - static_cast(connection_state_)); - ev.state = static_cast(cs.state()); - } - if (delegate_snapshot) { - delegate_snapshot->onConnectionStateChanged(*this, ev); - } - break; - } - case proto::RoomEvent::kDisconnected: { - DisconnectedEvent ev; - ev.reason = toDisconnectReason(re.disconnected().reason()); - if (delegate_snapshot) { - delegate_snapshot->onDisconnected(*this, ev); - } - break; - } - case proto::RoomEvent::kReconnecting: { - const ReconnectingEvent ev; - if (delegate_snapshot) { - delegate_snapshot->onReconnecting(*this, ev); - } - break; - } - case proto::RoomEvent::kReconnected: { - const ReconnectedEvent ev; - if (delegate_snapshot) { - delegate_snapshot->onReconnected(*this, ev); - } - break; - } - case proto::RoomEvent::kEos: { - if (subscription_thread_dispatcher_) { - subscription_thread_dispatcher_->stopAll(); - } - - int listener_to_remove = 0; - - // Move state out of lock scope before destroying to avoid holding lock - // during potentially long destructors - std::unique_ptr old_local_participant; - std::unordered_map> - old_remote_participants; - std::shared_ptr old_room_handle; - std::unique_ptr old_e2ee_manager; - std::unordered_map> - old_text_readers; - std::unordered_map> - old_byte_readers; - - { - const std::scoped_lock guard(lock_); - listener_to_remove = listener_id_; - listener_id_ = 0; - - // Reset connection state - connection_state_ = ConnectionState::Disconnected; - - // Move state out for cleanup outside lock - old_local_participant = std::move(local_participant_); - old_remote_participants = std::move(remote_participants_); - old_room_handle = std::move(room_handle_); - old_e2ee_manager = std::move(e2ee_manager_); - old_text_readers = std::move(text_stream_readers_); - old_byte_readers = std::move(byte_stream_readers_); - } - - // Remove listener outside lock - if (listener_to_remove != 0) { - FfiClient::instance().RemoveListener(listener_to_remove); - } - - // Old state will be destroyed here when going out of scope - - const RoomEosEvent ev; - if (delegate_snapshot) { - delegate_snapshot->onRoomEos(*this, ev); - } - break; - } - case proto::RoomEvent::kChatMessage: { - // Deprecated event, do nothing. - break; - } - case proto::RoomEvent::kStreamHeaderReceived: { - const auto &sh = re.stream_header_received(); - const auto &header = sh.header(); - const std::string &participant_identity = sh.participant_identity(); - - // Snapshot handler + create reader without holding lock during user - // callback - TextStreamHandler text_cb; - ByteStreamHandler byte_cb; - std::shared_ptr text_reader; - std::shared_ptr byte_reader; - { - const std::scoped_lock guard(lock_); - - // Determine stream type from oneof in protobuf - // Adjust these names if your generated C++ uses different ones - const auto stream_type = header.content_header_case(); - if (stream_type == proto::DataStream::Header::kTextHeader) { - auto it = text_stream_handlers_.find(header.topic()); - if (it == text_stream_handlers_.end()) { - // Ignore if no callback attached - break; - } - text_cb = it->second; - - const TextStreamInfo info = makeTextInfo(header); - text_reader = std::make_shared(info); - text_stream_readers_[header.stream_id()] = text_reader; - - } else if (stream_type == proto::DataStream::Header::kByteHeader) { - auto it = byte_stream_handlers_.find(header.topic()); - if (it == byte_stream_handlers_.end()) { - break; - } - byte_cb = it->second; - const ByteStreamInfo info = makeByteInfo(header); - byte_reader = std::make_shared(info); - byte_stream_readers_[header.stream_id()] = byte_reader; - - } else { - // unknown header type: ignore + case proto::RoomEvent::kTextStreamOpened: { + auto ev = fromProto(re.text_stream_opened()); + if (delegate_snapshot) { + delegate_snapshot->onTextStreamOpened(*this, ev); + } break; } - } - - // Invoke user callback outside lock (very important) - if (text_reader) { - text_cb(text_reader, participant_identity); - } else if (byte_reader) { - byte_cb(byte_reader, participant_identity); - } - break; - } - case proto::RoomEvent::kStreamChunkReceived: { - const auto &sc = re.stream_chunk_received(); - const auto &chunk = sc.chunk(); - std::shared_ptr text_reader; - std::shared_ptr byte_reader; - { - const std::scoped_lock guard(lock_); - auto itT = text_stream_readers_.find(chunk.stream_id()); - if (itT != text_stream_readers_.end()) { - text_reader = itT->second; - } else { - auto itB = byte_stream_readers_.find(chunk.stream_id()); - if (itB != byte_stream_readers_.end()) { - byte_reader = itB->second; + case proto::RoomEvent::kRoomUpdated: { + auto ev = roomUpdatedFromProto(re.room_updated()); + if (delegate_snapshot) { + delegate_snapshot->onRoomUpdated(*this, ev); } + break; } - } - if (text_reader) { - // chunk.content() is bytes; treat as UTF-8 string. - text_reader->onChunkUpdate(chunk.content()); - } else if (byte_reader) { - // Convert string bytes -> vector - const std::string &s = chunk.content(); - const std::vector bytes(s.begin(), s.end()); - byte_reader->onChunkUpdate(bytes); - } - break; - } - case proto::RoomEvent::kStreamTrailerReceived: { - const auto &st = re.stream_trailer_received(); - const auto &trailer = st.trailer(); - std::shared_ptr text_reader; - std::shared_ptr byte_reader; - std::map trailer_attrs; - for (const auto &kv : trailer.attributes()) { - trailer_attrs.emplace(kv.first, kv.second); - } - { - const std::scoped_lock guard(lock_); - auto itT = text_stream_readers_.find(trailer.stream_id()); - if (itT != text_stream_readers_.end()) { - text_reader = itT->second; - text_stream_readers_.erase(itT); - } else { - auto itB = byte_stream_readers_.find(trailer.stream_id()); - if (itB != byte_stream_readers_.end()) { - byte_reader = itB->second; - byte_stream_readers_.erase(itB); + case proto::RoomEvent::kMoved: { + auto ev = roomMovedFromProto(re.moved()); + if (delegate_snapshot) { + delegate_snapshot->onRoomMoved(*this, ev); } + break; } - } - if (text_reader) { - text_reader->onStreamClose(trailer_attrs); - } else if (byte_reader) { - byte_reader->onStreamClose(trailer_attrs); - } - break; - } - case proto::RoomEvent::kDataChannelLowThresholdChanged: { - auto ev = fromProto(re.data_channel_low_threshold_changed()); - if (delegate_snapshot) { - delegate_snapshot->onDataChannelBufferedAmountLowThresholdChanged(*this, - ev); - } - break; - } - case proto::RoomEvent::kByteStreamOpened: { - auto ev = fromProto(re.byte_stream_opened()); - if (delegate_snapshot) { - delegate_snapshot->onByteStreamOpened(*this, ev); - } - break; - } - case proto::RoomEvent::kTextStreamOpened: { - auto ev = fromProto(re.text_stream_opened()); - if (delegate_snapshot) { - delegate_snapshot->onTextStreamOpened(*this, ev); - } - break; - } - case proto::RoomEvent::kRoomUpdated: { - auto ev = roomUpdatedFromProto(re.room_updated()); - if (delegate_snapshot) { - delegate_snapshot->onRoomUpdated(*this, ev); - } - break; - } - case proto::RoomEvent::kMoved: { - auto ev = roomMovedFromProto(re.moved()); - if (delegate_snapshot) { - delegate_snapshot->onRoomMoved(*this, ev); - } - break; - } - case proto::RoomEvent::kParticipantsUpdated: { - ParticipantsUpdatedEvent ev; - { - const std::scoped_lock guard(lock_); - const auto &pu = re.participants_updated(); - for (const auto &info : pu.participants()) { - const std::string &identity = info.identity(); - Participant *participant = nullptr; - - if (local_participant_ && - identity == local_participant_->identity()) { - participant = local_participant_.get(); - } else { - auto it = remote_participants_.find(identity); - if (it != remote_participants_.end()) { - participant = it->second.get(); + case proto::RoomEvent::kParticipantsUpdated: { + ParticipantsUpdatedEvent ev; + { + const std::scoped_lock guard(lock_); + const auto& pu = re.participants_updated(); + for (const auto& info : pu.participants()) { + const std::string& identity = info.identity(); + Participant* participant = nullptr; + + if (local_participant_ && identity == local_participant_->identity()) { + participant = local_participant_.get(); + } else { + auto it = remote_participants_.find(identity); + if (it != remote_participants_.end()) { + participant = it->second.get(); + } + } + if (!participant) { + LK_LOG_WARN("kParticipantsUpdated: participant does not exist: {}", identity); + continue; + } + + participant->set_name(info.name()); + participant->set_metadata(info.metadata()); + + std::unordered_map attrs; + attrs.reserve(info.attributes_size()); + for (const auto& kv : info.attributes()) { + attrs.emplace(kv.first, kv.second); + } + participant->set_attributes(std::move(attrs)); + participant->set_kind(fromProto(info.kind())); + participant->set_disconnect_reason(toDisconnectReason(info.disconnect_reason())); + + ev.participants.push_back(participant); } } - if (!participant) { - LK_LOG_WARN("kParticipantsUpdated: participant does not exist: {}", - identity); - continue; - } - - participant->set_name(info.name()); - participant->set_metadata(info.metadata()); - - std::unordered_map attrs; - attrs.reserve(info.attributes_size()); - for (const auto &kv : info.attributes()) { - attrs.emplace(kv.first, kv.second); + if (delegate_snapshot) { + delegate_snapshot->onParticipantsUpdated(*this, ev); } - participant->set_attributes(std::move(attrs)); - participant->set_kind(fromProto(info.kind())); - participant->set_disconnect_reason( - toDisconnectReason(info.disconnect_reason())); - - ev.participants.push_back(participant); + break; } + + case proto::RoomEvent::MESSAGE_NOT_SET: + default: + break; } - if (delegate_snapshot) { - delegate_snapshot->onParticipantsUpdated(*this, ev); - } + break; } - case proto::RoomEvent::MESSAGE_NOT_SET: default: break; - } - - break; - } - - default: - break; } } diff --git a/src/room_event_converter.cpp b/src/room_event_converter.cpp index 075adad5..305fb964 100644 --- a/src/room_event_converter.cpp +++ b/src/room_event_converter.cpp @@ -24,40 +24,40 @@ namespace livekit { ConnectionQuality toConnectionQuality(proto::ConnectionQuality src) { switch (src) { - case proto::QUALITY_POOR: - return ConnectionQuality::Poor; - case proto::QUALITY_GOOD: - return ConnectionQuality::Good; - case proto::QUALITY_EXCELLENT: - return ConnectionQuality::Excellent; - case proto::QUALITY_LOST: - return ConnectionQuality::Lost; - default: - return ConnectionQuality::Good; + case proto::QUALITY_POOR: + return ConnectionQuality::Poor; + case proto::QUALITY_GOOD: + return ConnectionQuality::Good; + case proto::QUALITY_EXCELLENT: + return ConnectionQuality::Excellent; + case proto::QUALITY_LOST: + return ConnectionQuality::Lost; + default: + return ConnectionQuality::Good; } } ConnectionState toConnectionState(proto::ConnectionState src) { switch (src) { - case proto::CONN_DISCONNECTED: - return ConnectionState::Disconnected; - case proto::CONN_CONNECTED: - return ConnectionState::Connected; - case proto::CONN_RECONNECTING: - return ConnectionState::Reconnecting; - default: - return ConnectionState::Disconnected; + case proto::CONN_DISCONNECTED: + return ConnectionState::Disconnected; + case proto::CONN_CONNECTED: + return ConnectionState::Connected; + case proto::CONN_RECONNECTING: + return ConnectionState::Reconnecting; + default: + return ConnectionState::Disconnected; } } DataPacketKind toDataPacketKind(proto::DataPacketKind src) { switch (src) { - case proto::KIND_LOSSY: - return DataPacketKind::Lossy; - case proto::KIND_RELIABLE: // NOLINT(bugprone-branch-clone) - return DataPacketKind::Reliable; - default: - return DataPacketKind::Reliable; + case proto::KIND_LOSSY: + return DataPacketKind::Lossy; + case proto::KIND_RELIABLE: // NOLINT(bugprone-branch-clone) + return DataPacketKind::Reliable; + default: + return DataPacketKind::Reliable; } } @@ -73,7 +73,7 @@ DisconnectReason toDisconnectReason(proto::DisconnectReason /*src*/) { // --------- basic helper conversions --------- -TranscriptionSegmentData fromProto(const proto::TranscriptionSegment &src) { +TranscriptionSegmentData fromProto(const proto::TranscriptionSegment& src) { TranscriptionSegmentData out; out.id = src.id(); out.text = src.text(); @@ -84,7 +84,7 @@ TranscriptionSegmentData fromProto(const proto::TranscriptionSegment &src) { return out; } -ChatMessageData fromProto(const proto::ChatMessage &src) { +ChatMessageData fromProto(const proto::ChatMessage& src) { ChatMessageData out; out.id = src.id(); out.timestamp = src.timestamp(); @@ -101,11 +101,11 @@ ChatMessageData fromProto(const proto::ChatMessage &src) { return out; } -UserPacketData fromProto(const proto::UserPacket &src) { +UserPacketData fromProto(const proto::UserPacket& src) { UserPacketData out; // TODO, double check following code is safe - const auto &buf = src.data().data(); - auto ptr = reinterpret_cast(buf.data_ptr()); + const auto& buf = src.data().data(); + auto ptr = reinterpret_cast(buf.data_ptr()); auto len = static_cast(buf.data_len()); out.data.assign(ptr, ptr + len); if (src.has_topic()) { @@ -114,7 +114,7 @@ UserPacketData fromProto(const proto::UserPacket &src) { return out; } -SipDtmfData fromProto(const proto::SipDTMF &src) { +SipDtmfData fromProto(const proto::SipDTMF& src) { SipDtmfData out; out.code = src.code(); if (src.has_digit()) { @@ -123,17 +123,15 @@ SipDtmfData fromProto(const proto::SipDTMF &src) { return out; } -RoomInfoData fromProto(const proto::RoomInfo &src) { +RoomInfoData fromProto(const proto::RoomInfo& src) { RoomInfoData out; if (src.has_sid()) { out.sid = src.sid(); } out.name = src.name(); out.metadata = src.metadata(); - out.lossy_dc_buffered_amount_low_threshold = - src.lossy_dc_buffered_amount_low_threshold(); - out.reliable_dc_buffered_amount_low_threshold = - src.reliable_dc_buffered_amount_low_threshold(); + out.lossy_dc_buffered_amount_low_threshold = src.lossy_dc_buffered_amount_low_threshold(); + out.reliable_dc_buffered_amount_low_threshold = src.reliable_dc_buffered_amount_low_threshold(); out.empty_timeout = src.empty_timeout(); out.departure_timeout = src.departure_timeout(); out.max_participants = src.max_participants(); @@ -144,14 +142,14 @@ RoomInfoData fromProto(const proto::RoomInfo &src) { return out; } -AttributeEntry fromProto(const proto::AttributesEntry &src) { +AttributeEntry fromProto(const proto::AttributesEntry& src) { AttributeEntry a; a.key = src.key(); a.value = src.value(); return a; } -DataStreamHeaderData fromProto(const proto::DataStream_Header &src) { +DataStreamHeaderData fromProto(const proto::DataStream_Header& src) { DataStreamHeaderData out; out.stream_id = src.stream_id(); out.timestamp = src.timestamp(); @@ -160,47 +158,46 @@ DataStreamHeaderData fromProto(const proto::DataStream_Header &src) { if (src.has_total_length()) { out.total_length = src.total_length(); } - for (const auto &kv : src.attributes()) { + for (const auto& kv : src.attributes()) { out.attributes.emplace(kv.first, kv.second); } // content_header oneof switch (src.content_header_case()) { - case proto::DataStream_Header::kTextHeader: { - out.content_type = DataStreamHeaderData::ContentType::Text; - const auto &t = src.text_header(); - out.operation_type = - static_cast(t.operation_type()); - if (t.has_version()) { - out.version = t.version(); + case proto::DataStream_Header::kTextHeader: { + out.content_type = DataStreamHeaderData::ContentType::Text; + const auto& t = src.text_header(); + out.operation_type = static_cast(t.operation_type()); + if (t.has_version()) { + out.version = t.version(); + } + if (t.has_reply_to_stream_id()) { + out.reply_to_stream_id = t.reply_to_stream_id(); + } + for (const auto& id : t.attached_stream_ids()) { + out.attached_stream_ids.push_back(id); + } + if (t.has_generated()) { + out.generated = t.generated(); + } + break; } - if (t.has_reply_to_stream_id()) { - out.reply_to_stream_id = t.reply_to_stream_id(); + case proto::DataStream_Header::kByteHeader: { + out.content_type = DataStreamHeaderData::ContentType::Byte; + const auto& b = src.byte_header(); + out.name = b.name(); + break; } - for (const auto &id : t.attached_stream_ids()) { - out.attached_stream_ids.push_back(id); - } - if (t.has_generated()) { - out.generated = t.generated(); - } - break; - } - case proto::DataStream_Header::kByteHeader: { - out.content_type = DataStreamHeaderData::ContentType::Byte; - const auto &b = src.byte_header(); - out.name = b.name(); - break; - } - case proto::DataStream_Header::CONTENT_HEADER_NOT_SET: - default: - out.content_type = DataStreamHeaderData::ContentType::None; - break; + case proto::DataStream_Header::CONTENT_HEADER_NOT_SET: + default: + out.content_type = DataStreamHeaderData::ContentType::None; + break; } return out; } -DataStreamChunkData fromProto(const proto::DataStream_Chunk &src) { +DataStreamChunkData fromProto(const proto::DataStream_Chunk& src) { DataStreamChunkData out; out.stream_id = src.stream_id(); out.chunk_index = src.chunk_index(); @@ -214,11 +211,11 @@ DataStreamChunkData fromProto(const proto::DataStream_Chunk &src) { return out; } -DataStreamTrailerData fromProto(const proto::DataStream_Trailer &src) { +DataStreamTrailerData fromProto(const proto::DataStream_Trailer& src) { DataStreamTrailerData out; out.stream_id = src.stream_id(); out.reason = src.reason(); - for (const auto &kv : src.attributes()) { + for (const auto& kv : src.attributes()) { out.attributes.emplace(kv.first, kv.second); } return out; @@ -226,7 +223,7 @@ DataStreamTrailerData fromProto(const proto::DataStream_Trailer &src) { // --------- event conversions --------- -ParticipantConnectedEvent fromProto(const proto::ParticipantConnected &src) { +ParticipantConnectedEvent fromProto(const proto::ParticipantConnected& src) { ParticipantConnectedEvent ev; // src.info() is OwnedParticipant; you can fill more fields once you inspect // it. For now, leave metadata/name/identity as TODO. @@ -234,48 +231,46 @@ ParticipantConnectedEvent fromProto(const proto::ParticipantConnected &src) { return ev; } -ParticipantDisconnectedEvent -fromProto(const proto::ParticipantDisconnected &src) { +ParticipantDisconnectedEvent fromProto(const proto::ParticipantDisconnected& src) { ParticipantDisconnectedEvent ev; ev.participant_identity = src.participant_identity(); ev.reason = toDisconnectReason(src.disconnect_reason()); return ev; } -LocalTrackPublishedEvent fromProto(const proto::LocalTrackPublished &src) { +LocalTrackPublishedEvent fromProto(const proto::LocalTrackPublished& src) { LocalTrackPublishedEvent ev; ev.track_sid = src.track_sid(); return ev; } -LocalTrackUnpublishedEvent fromProto(const proto::LocalTrackUnpublished &src) { +LocalTrackUnpublishedEvent fromProto(const proto::LocalTrackUnpublished& src) { LocalTrackUnpublishedEvent ev; ev.publication_sid = src.publication_sid(); return ev; } -LocalTrackSubscribedEvent fromProto(const proto::LocalTrackSubscribed &src) { +LocalTrackSubscribedEvent fromProto(const proto::LocalTrackSubscribed& src) { LocalTrackSubscribedEvent ev; ev.track_sid = src.track_sid(); return ev; } -TrackUnpublishedEvent fromProto(const proto::TrackUnpublished &src) { +TrackUnpublishedEvent fromProto(const proto::TrackUnpublished& src) { TrackUnpublishedEvent ev; ev.participant_identity = src.participant_identity(); ev.publication_sid = src.publication_sid(); return ev; } -TrackUnsubscribedEvent fromProto(const proto::TrackUnsubscribed &src) { +TrackUnsubscribedEvent fromProto(const proto::TrackUnsubscribed& src) { TrackUnsubscribedEvent ev; ev.participant_identity = src.participant_identity(); ev.track_sid = src.track_sid(); return ev; } -TrackSubscriptionFailedEvent -fromProto(const proto::TrackSubscriptionFailed &src) { +TrackSubscriptionFailedEvent fromProto(const proto::TrackSubscriptionFailed& src) { TrackSubscriptionFailedEvent ev; ev.participant_identity = src.participant_identity(); ev.track_sid = src.track_sid(); @@ -283,106 +278,101 @@ fromProto(const proto::TrackSubscriptionFailed &src) { return ev; } -TrackMutedEvent fromProto(const proto::TrackMuted &src) { +TrackMutedEvent fromProto(const proto::TrackMuted& src) { TrackMutedEvent ev; ev.participant_identity = src.participant_identity(); ev.track_sid = src.track_sid(); return ev; } -TrackUnmutedEvent fromProto(const proto::TrackUnmuted &src) { +TrackUnmutedEvent fromProto(const proto::TrackUnmuted& src) { TrackUnmutedEvent ev; ev.participant_identity = src.participant_identity(); ev.track_sid = src.track_sid(); return ev; } -ActiveSpeakersChangedEvent fromProto(const proto::ActiveSpeakersChanged &src) { +ActiveSpeakersChangedEvent fromProto(const proto::ActiveSpeakersChanged& src) { ActiveSpeakersChangedEvent ev; - for (const auto &id : src.participant_identities()) { + for (const auto& id : src.participant_identities()) { ev.participant_identities.push_back(id); } return ev; } -RoomMetadataChangedEvent fromProto(const proto::RoomMetadataChanged &src) { +RoomMetadataChangedEvent fromProto(const proto::RoomMetadataChanged& src) { RoomMetadataChangedEvent ev; ev.metadata = src.metadata(); return ev; } -RoomSidChangedEvent fromProto(const proto::RoomSidChanged &src) { +RoomSidChangedEvent fromProto(const proto::RoomSidChanged& src) { RoomSidChangedEvent ev; ev.sid = src.sid(); return ev; } -ParticipantMetadataChangedEvent -fromProto(const proto::ParticipantMetadataChanged &src) { +ParticipantMetadataChangedEvent fromProto(const proto::ParticipantMetadataChanged& src) { ParticipantMetadataChangedEvent ev; ev.participant_identity = src.participant_identity(); ev.metadata = src.metadata(); return ev; } -ParticipantNameChangedEvent -fromProto(const proto::ParticipantNameChanged &src) { +ParticipantNameChangedEvent fromProto(const proto::ParticipantNameChanged& src) { ParticipantNameChangedEvent ev; ev.participant_identity = src.participant_identity(); ev.name = src.name(); return ev; } -ParticipantAttributesChangedEvent -fromProto(const proto::ParticipantAttributesChanged &src) { +ParticipantAttributesChangedEvent fromProto(const proto::ParticipantAttributesChanged& src) { ParticipantAttributesChangedEvent ev; ev.participant_identity = src.participant_identity(); - for (const auto &a : src.attributes()) { + for (const auto& a : src.attributes()) { ev.attributes.push_back(fromProto(a)); } - for (const auto &a : src.changed_attributes()) { + for (const auto& a : src.changed_attributes()) { ev.changed_attributes.push_back(fromProto(a)); } return ev; } -ParticipantEncryptionStatusChangedEvent -fromProto(const proto::ParticipantEncryptionStatusChanged &src) { +ParticipantEncryptionStatusChangedEvent fromProto(const proto::ParticipantEncryptionStatusChanged& src) { ParticipantEncryptionStatusChangedEvent ev; ev.participant_identity = src.participant_identity(); ev.is_encrypted = src.is_encrypted(); return ev; } -ConnectionQualityChangedEvent -fromProto(const proto::ConnectionQualityChanged &src) { +ConnectionQualityChangedEvent fromProto(const proto::ConnectionQualityChanged& src) { ConnectionQualityChangedEvent ev; ev.participant_identity = src.participant_identity(); ev.quality = toConnectionQuality(src.quality()); return ev; } -DataPacketReceivedEvent fromProto(const proto::DataPacketReceived &src) { +DataPacketReceivedEvent fromProto(const proto::DataPacketReceived& src) { DataPacketReceivedEvent ev; ev.kind = toDataPacketKind(src.kind()); ev.participant_identity = src.participant_identity(); switch (src.value_case()) { - case proto::DataPacketReceived::kUser: - ev.user = fromProto(src.user()); - break; - case proto::DataPacketReceived::kSipDtmf: - ev.sip_dtmf = fromProto(src.sip_dtmf()); - break; - case proto::DataPacketReceived::VALUE_NOT_SET: - default: - break; + case proto::DataPacketReceived::kUser: + ev.user = fromProto(src.user()); + break; + case proto::DataPacketReceived::kSipDtmf: + ev.sip_dtmf = fromProto(src.sip_dtmf()); + break; + case proto::DataPacketReceived::VALUE_NOT_SET: + default: + break; } return ev; } -TranscriptionReceivedEvent fromProto(const proto::TranscriptionReceived &src) { +TranscriptionReceivedEvent fromProto(const proto::TranscriptionReceived& src) { TranscriptionReceivedEvent ev; if (src.has_participant_identity()) { ev.participant_identity = src.participant_identity(); @@ -390,70 +380,60 @@ TranscriptionReceivedEvent fromProto(const proto::TranscriptionReceived &src) { if (src.has_track_sid()) { ev.track_sid = src.track_sid(); } - for (const auto &seg : src.segments()) { + for (const auto& seg : src.segments()) { ev.segments.push_back(fromProto(seg)); } return ev; } -ConnectionStateChangedEvent -fromProto(const proto::ConnectionStateChanged &src) { +ConnectionStateChangedEvent fromProto(const proto::ConnectionStateChanged& src) { ConnectionStateChangedEvent ev; ev.state = toConnectionState(src.state()); return ev; } -DisconnectedEvent fromProto(const proto::Disconnected &src) { +DisconnectedEvent fromProto(const proto::Disconnected& src) { DisconnectedEvent ev; ev.reason = toDisconnectReason(src.reason()); return ev; } -ReconnectingEvent fromProto(const proto::Reconnecting & /*src*/) { - return ReconnectingEvent{}; -} +ReconnectingEvent fromProto(const proto::Reconnecting& /*src*/) { return ReconnectingEvent{}; } -ReconnectedEvent fromProto(const proto::Reconnected & /*src*/) { - return ReconnectedEvent{}; -} +ReconnectedEvent fromProto(const proto::Reconnected& /*src*/) { return ReconnectedEvent{}; } -RoomEosEvent fromProto(const proto::RoomEOS & /*src*/) { - return RoomEosEvent{}; -} +RoomEosEvent fromProto(const proto::RoomEOS& /*src*/) { return RoomEosEvent{}; } -DataStreamHeaderReceivedEvent -fromProto(const proto::DataStreamHeaderReceived &src) { +DataStreamHeaderReceivedEvent fromProto(const proto::DataStreamHeaderReceived& src) { DataStreamHeaderReceivedEvent ev; ev.participant_identity = src.participant_identity(); ev.header = fromProto(src.header()); return ev; } -DataStreamChunkReceivedEvent -fromProto(const proto::DataStreamChunkReceived &src) { +DataStreamChunkReceivedEvent fromProto(const proto::DataStreamChunkReceived& src) { DataStreamChunkReceivedEvent ev; ev.participant_identity = src.participant_identity(); ev.chunk = fromProto(src.chunk()); return ev; } -DataStreamTrailerReceivedEvent -fromProto(const proto::DataStreamTrailerReceived &src) { +DataStreamTrailerReceivedEvent fromProto(const proto::DataStreamTrailerReceived& src) { DataStreamTrailerReceivedEvent ev; ev.participant_identity = src.participant_identity(); ev.trailer = fromProto(src.trailer()); return ev; } -DataChannelBufferedAmountLowThresholdChangedEvent -fromProto(const proto::DataChannelBufferedAmountLowThresholdChanged &src) { +DataChannelBufferedAmountLowThresholdChangedEvent fromProto( + const proto::DataChannelBufferedAmountLowThresholdChanged& src) { DataChannelBufferedAmountLowThresholdChangedEvent ev; ev.kind = toDataPacketKind(src.kind()); ev.threshold = src.threshold(); return ev; } -ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened &src) { +ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened& src) { ByteStreamOpenedEvent ev; // TODO: map reader handle once OwnedByteStreamReader is known // ev.reader_handle = src.reader().handle().id(); @@ -461,7 +441,7 @@ ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened &src) { return ev; } -TextStreamOpenedEvent fromProto(const proto::TextStreamOpened &src) { +TextStreamOpenedEvent fromProto(const proto::TextStreamOpened& src) { TextStreamOpenedEvent ev; // TODO: map reader handle once OwnedTextStreamReader is known // ev.reader_handle = src.reader().handle().id(); @@ -469,36 +449,36 @@ TextStreamOpenedEvent fromProto(const proto::TextStreamOpened &src) { return ev; } -RoomUpdatedEvent roomUpdatedFromProto(const proto::RoomInfo &src) { +RoomUpdatedEvent roomUpdatedFromProto(const proto::RoomInfo& src) { RoomUpdatedEvent ev; ev.info = fromProto(src); return ev; } -RoomMovedEvent roomMovedFromProto(const proto::RoomInfo &src) { +RoomMovedEvent roomMovedFromProto(const proto::RoomInfo& src) { RoomMovedEvent ev; ev.info = fromProto(src); return ev; } -ParticipantsUpdatedEvent fromProto(const proto::ParticipantsUpdated &src) { +ParticipantsUpdatedEvent fromProto(const proto::ParticipantsUpdated& src) { ParticipantsUpdatedEvent ev; // We only know that it has ParticipantInfo participants = 1; // TODO: fill real identities once you inspect proto::ParticipantInfo - for (const auto &p : src.participants()) { + for (const auto& p : src.participants()) { ev.participant_identities.push_back(p.identity()); } return ev; } -E2eeStateChangedEvent fromProto(const proto::E2eeStateChanged &src) { +E2eeStateChangedEvent fromProto(const proto::E2eeStateChanged& src) { E2eeStateChangedEvent ev; ev.participant_identity = src.participant_identity(); ev.state = toEncryptionState(src.state()); return ev; } -ChatMessageReceivedEvent fromProto(const proto::ChatMessageReceived &src) { +ChatMessageReceivedEvent fromProto(const proto::ChatMessageReceived& src) { ChatMessageReceivedEvent ev; ev.message = fromProto(src.message()); ev.participant_identity = src.participant_identity(); diff --git a/src/room_proto_converter.cpp b/src/room_proto_converter.cpp index ed5ef96b..048b855c 100644 --- a/src/room_proto_converter.cpp +++ b/src/room_proto_converter.cpp @@ -24,8 +24,7 @@ namespace livekit { namespace { -std::vector -toProto(const PacketTrailerFeatures &features) { +std::vector toProto(const PacketTrailerFeatures& features) { std::vector out; out.reserve(2); if (features.user_timestamp) { @@ -37,19 +36,18 @@ toProto(const PacketTrailerFeatures &features) { return out; } -PacketTrailerFeatures -fromProto(const google::protobuf::RepeatedField &features) { +PacketTrailerFeatures fromProto(const google::protobuf::RepeatedField& features) { PacketTrailerFeatures out{}; for (const int feature : features) { switch (feature) { - case proto::PacketTrailerFeature::PTF_USER_TIMESTAMP: - out.user_timestamp = true; - break; - case proto::PacketTrailerFeature::PTF_FRAME_ID: - out.frame_id = true; - break; - default: - break; + case proto::PacketTrailerFeature::PTF_USER_TIMESTAMP: + out.user_timestamp = true; + break; + case proto::PacketTrailerFeature::PTF_FRAME_ID: + out.frame_id = true; + break; + default: + break; } } return out; @@ -61,40 +59,40 @@ fromProto(const google::protobuf::RepeatedField &features) { ConnectionQuality toConnectionQuality(proto::ConnectionQuality in) { switch (in) { - case proto::QUALITY_POOR: - return ConnectionQuality::Poor; - case proto::QUALITY_GOOD: - return ConnectionQuality::Good; - case proto::QUALITY_EXCELLENT: - return ConnectionQuality::Excellent; - case proto::QUALITY_LOST: - return ConnectionQuality::Lost; - default: - return ConnectionQuality::Good; + case proto::QUALITY_POOR: + return ConnectionQuality::Poor; + case proto::QUALITY_GOOD: + return ConnectionQuality::Good; + case proto::QUALITY_EXCELLENT: + return ConnectionQuality::Excellent; + case proto::QUALITY_LOST: + return ConnectionQuality::Lost; + default: + return ConnectionQuality::Good; } } ConnectionState toConnectionState(proto::ConnectionState in) { switch (in) { - case proto::CONN_DISCONNECTED: - return ConnectionState::Disconnected; - case proto::CONN_CONNECTED: - return ConnectionState::Connected; - case proto::CONN_RECONNECTING: - return ConnectionState::Reconnecting; - default: - return ConnectionState::Disconnected; + case proto::CONN_DISCONNECTED: + return ConnectionState::Disconnected; + case proto::CONN_CONNECTED: + return ConnectionState::Connected; + case proto::CONN_RECONNECTING: + return ConnectionState::Reconnecting; + default: + return ConnectionState::Disconnected; } } DataPacketKind toDataPacketKind(proto::DataPacketKind in) { switch (in) { - case proto::KIND_LOSSY: - return DataPacketKind::Lossy; - case proto::KIND_RELIABLE: // NOLINT(bugprone-branch-clone) - return DataPacketKind::Reliable; - default: - return DataPacketKind::Reliable; + case proto::KIND_LOSSY: + return DataPacketKind::Lossy; + case proto::KIND_RELIABLE: // NOLINT(bugprone-branch-clone) + return DataPacketKind::Reliable; + default: + return DataPacketKind::Reliable; } } @@ -105,12 +103,12 @@ DisconnectReason toDisconnectReason(proto::DisconnectReason /*in*/) { // --------- basic helper conversions --------- -UserPacketData fromProto(const proto::UserPacket &in) { +UserPacketData fromProto(const proto::UserPacket& in) { UserPacketData out; // TODO, double check following code is safe - const auto &buf = in.data().data(); + const auto& buf = in.data().data(); // NOLINTNEXTLINE(performance-no-int-to-ptr) - const auto *ptr = reinterpret_cast(buf.data_ptr()); + const auto* ptr = reinterpret_cast(buf.data_ptr()); auto len = static_cast(buf.data_len()); out.data.assign(ptr, ptr + len); if (in.has_topic()) { @@ -119,7 +117,7 @@ UserPacketData fromProto(const proto::UserPacket &in) { return out; } -SipDtmfData fromProto(const proto::SipDTMF &in) { +SipDtmfData fromProto(const proto::SipDTMF& in) { SipDtmfData out; out.code = in.code(); if (in.has_digit()) { @@ -128,17 +126,15 @@ SipDtmfData fromProto(const proto::SipDTMF &in) { return out; } -RoomInfoData fromProto(const proto::RoomInfo &in) { +RoomInfoData fromProto(const proto::RoomInfo& in) { RoomInfoData out; if (in.has_sid()) { out.sid = in.sid(); } out.name = in.name(); out.metadata = in.metadata(); - out.lossy_dc_buffered_amount_low_threshold = - in.lossy_dc_buffered_amount_low_threshold(); - out.reliable_dc_buffered_amount_low_threshold = - in.reliable_dc_buffered_amount_low_threshold(); + out.lossy_dc_buffered_amount_low_threshold = in.lossy_dc_buffered_amount_low_threshold(); + out.reliable_dc_buffered_amount_low_threshold = in.reliable_dc_buffered_amount_low_threshold(); out.empty_timeout = in.empty_timeout(); out.departure_timeout = in.departure_timeout(); out.max_participants = in.max_participants(); @@ -149,14 +145,14 @@ RoomInfoData fromProto(const proto::RoomInfo &in) { return out; } -AttributeEntry fromProto(const proto::AttributesEntry &in) { +AttributeEntry fromProto(const proto::AttributesEntry& in) { AttributeEntry a; a.key = in.key(); a.value = in.value(); return a; } -DataStreamHeaderData fromProto(const proto::DataStream_Header &in) { +DataStreamHeaderData fromProto(const proto::DataStream_Header& in) { DataStreamHeaderData out; out.stream_id = in.stream_id(); out.timestamp = in.timestamp(); @@ -165,47 +161,46 @@ DataStreamHeaderData fromProto(const proto::DataStream_Header &in) { if (in.has_total_length()) { out.total_length = in.total_length(); } - for (const auto &kv : in.attributes()) { + for (const auto& kv : in.attributes()) { out.attributes.emplace(kv.first, kv.second); } // content_header oneof switch (in.content_header_case()) { - case proto::DataStream_Header::kTextHeader: { - out.content_type = DataStreamHeaderData::ContentType::Text; - const auto &t = in.text_header(); - out.operation_type = - static_cast(t.operation_type()); - if (t.has_version()) { - out.version = t.version(); - } - if (t.has_reply_to_stream_id()) { - out.reply_to_stream_id = t.reply_to_stream_id(); - } - for (const auto &id : t.attached_stream_ids()) { - out.attached_stream_ids.push_back(id); + case proto::DataStream_Header::kTextHeader: { + out.content_type = DataStreamHeaderData::ContentType::Text; + const auto& t = in.text_header(); + out.operation_type = static_cast(t.operation_type()); + if (t.has_version()) { + out.version = t.version(); + } + if (t.has_reply_to_stream_id()) { + out.reply_to_stream_id = t.reply_to_stream_id(); + } + for (const auto& id : t.attached_stream_ids()) { + out.attached_stream_ids.push_back(id); + } + if (t.has_generated()) { + out.generated = t.generated(); + } + break; } - if (t.has_generated()) { - out.generated = t.generated(); + case proto::DataStream_Header::kByteHeader: { + out.content_type = DataStreamHeaderData::ContentType::Byte; + const auto& b = in.byte_header(); + out.name = b.name(); + break; } - break; - } - case proto::DataStream_Header::kByteHeader: { - out.content_type = DataStreamHeaderData::ContentType::Byte; - const auto &b = in.byte_header(); - out.name = b.name(); - break; - } - case proto::DataStream_Header::CONTENT_HEADER_NOT_SET: - default: - out.content_type = DataStreamHeaderData::ContentType::None; - break; + case proto::DataStream_Header::CONTENT_HEADER_NOT_SET: + default: + out.content_type = DataStreamHeaderData::ContentType::None; + break; } return out; } -DataStreamChunkData fromProto(const proto::DataStream_Chunk &in) { +DataStreamChunkData fromProto(const proto::DataStream_Chunk& in) { DataStreamChunkData out; out.stream_id = in.stream_id(); out.chunk_index = in.chunk_index(); @@ -219,11 +214,11 @@ DataStreamChunkData fromProto(const proto::DataStream_Chunk &in) { return out; } -DataStreamTrailerData fromProto(const proto::DataStream_Trailer &in) { +DataStreamTrailerData fromProto(const proto::DataStream_Trailer& in) { DataStreamTrailerData out; out.stream_id = in.stream_id(); out.reason = in.reason(); - for (const auto &kv : in.attributes()) { + for (const auto& kv : in.attributes()) { out.attributes.emplace(kv.first, kv.second); } return out; @@ -231,67 +226,60 @@ DataStreamTrailerData fromProto(const proto::DataStream_Trailer &in) { // --------- event conversions --------- -RoomSidChangedEvent fromProto(const proto::RoomSidChanged &in) { +RoomSidChangedEvent fromProto(const proto::RoomSidChanged& in) { RoomSidChangedEvent ev; ev.sid = in.sid(); return ev; } -ConnectionStateChangedEvent fromProto(const proto::ConnectionStateChanged &in) { +ConnectionStateChangedEvent fromProto(const proto::ConnectionStateChanged& in) { ConnectionStateChangedEvent ev; ev.state = toConnectionState(in.state()); return ev; } -DisconnectedEvent fromProto(const proto::Disconnected &in) { +DisconnectedEvent fromProto(const proto::Disconnected& in) { DisconnectedEvent ev; ev.reason = toDisconnectReason(in.reason()); return ev; } -ReconnectingEvent fromProto(const proto::Reconnecting & /*in*/) { - return ReconnectingEvent{}; -} +ReconnectingEvent fromProto(const proto::Reconnecting& /*in*/) { return ReconnectingEvent{}; } -ReconnectedEvent fromProto(const proto::Reconnected & /*in*/) { - return ReconnectedEvent{}; -} +ReconnectedEvent fromProto(const proto::Reconnected& /*in*/) { return ReconnectedEvent{}; } -RoomEosEvent fromProto(const proto::RoomEOS & /*in*/) { return RoomEosEvent{}; } +RoomEosEvent fromProto(const proto::RoomEOS& /*in*/) { return RoomEosEvent{}; } -DataStreamHeaderReceivedEvent -fromProto(const proto::DataStreamHeaderReceived &in) { +DataStreamHeaderReceivedEvent fromProto(const proto::DataStreamHeaderReceived& in) { DataStreamHeaderReceivedEvent ev; ev.participant_identity = in.participant_identity(); ev.header = fromProto(in.header()); return ev; } -DataStreamChunkReceivedEvent -fromProto(const proto::DataStreamChunkReceived &in) { +DataStreamChunkReceivedEvent fromProto(const proto::DataStreamChunkReceived& in) { DataStreamChunkReceivedEvent ev; ev.participant_identity = in.participant_identity(); ev.chunk = fromProto(in.chunk()); return ev; } -DataStreamTrailerReceivedEvent -fromProto(const proto::DataStreamTrailerReceived &in) { +DataStreamTrailerReceivedEvent fromProto(const proto::DataStreamTrailerReceived& in) { DataStreamTrailerReceivedEvent ev; ev.participant_identity = in.participant_identity(); ev.trailer = fromProto(in.trailer()); return ev; } -DataChannelBufferedAmountLowThresholdChangedEvent -fromProto(const proto::DataChannelBufferedAmountLowThresholdChanged &in) { +DataChannelBufferedAmountLowThresholdChangedEvent fromProto( + const proto::DataChannelBufferedAmountLowThresholdChanged& in) { DataChannelBufferedAmountLowThresholdChangedEvent ev; ev.kind = toDataPacketKind(in.kind()); ev.threshold = in.threshold(); return ev; } -ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened &in) { +ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened& in) { ByteStreamOpenedEvent ev; // TODO: map reader handle once OwnedByteStreamReader is known // ev.reader_handle = in.reader().handle().id(); @@ -299,7 +287,7 @@ ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened &in) { return ev; } -TextStreamOpenedEvent fromProto(const proto::TextStreamOpened &in) { +TextStreamOpenedEvent fromProto(const proto::TextStreamOpened& in) { TextStreamOpenedEvent ev; // TODO: map reader handle once OwnedTextStreamReader is known // ev.reader_handle = in.reader().handle().id(); @@ -307,13 +295,13 @@ TextStreamOpenedEvent fromProto(const proto::TextStreamOpened &in) { return ev; } -RoomUpdatedEvent roomUpdatedFromProto(const proto::RoomInfo &in) { +RoomUpdatedEvent roomUpdatedFromProto(const proto::RoomInfo& in) { RoomUpdatedEvent ev; ev.info = fromProto(in); return ev; } -RoomMovedEvent roomMovedFromProto(const proto::RoomInfo &in) { +RoomMovedEvent roomMovedFromProto(const proto::RoomInfo& in) { RoomMovedEvent ev; ev.info = fromProto(in); return ev; @@ -321,33 +309,33 @@ RoomMovedEvent roomMovedFromProto(const proto::RoomInfo &in) { // ---------------- Room Options ---------------- -proto::AudioEncoding toProto(const AudioEncodingOptions &in) { +proto::AudioEncoding toProto(const AudioEncodingOptions& in) { proto::AudioEncoding msg; msg.set_max_bitrate(in.max_bitrate); return msg; } -AudioEncodingOptions fromProto(const proto::AudioEncoding &in) { +AudioEncodingOptions fromProto(const proto::AudioEncoding& in) { AudioEncodingOptions out; out.max_bitrate = in.max_bitrate(); return out; } -proto::VideoEncoding toProto(const VideoEncodingOptions &in) { +proto::VideoEncoding toProto(const VideoEncodingOptions& in) { proto::VideoEncoding msg; msg.set_max_bitrate(in.max_bitrate); msg.set_max_framerate(in.max_framerate); return msg; } -VideoEncodingOptions fromProto(const proto::VideoEncoding &in) { +VideoEncodingOptions fromProto(const proto::VideoEncoding& in) { VideoEncodingOptions out; out.max_bitrate = in.max_bitrate(); out.max_framerate = in.max_framerate(); return out; } -proto::TrackPublishOptions toProto(const TrackPublishOptions &in) { +proto::TrackPublishOptions toProto(const TrackPublishOptions& in) { proto::TrackPublishOptions msg; if (in.video_encoding) { msg.mutable_video_encoding()->CopyFrom(toProto(*in.video_encoding)); @@ -376,14 +364,13 @@ proto::TrackPublishOptions toProto(const TrackPublishOptions &in) { if (in.preconnect_buffer) { msg.set_preconnect_buffer(*in.preconnect_buffer); } - for (const proto::PacketTrailerFeature feature : - toProto(in.packet_trailer_features)) { + for (const proto::PacketTrailerFeature feature : toProto(in.packet_trailer_features)) { msg.add_packet_trailer_features(feature); } return msg; } -TrackPublishOptions fromProto(const proto::TrackPublishOptions &in) { +TrackPublishOptions fromProto(const proto::TrackPublishOptions& in) { TrackPublishOptions out; if (in.has_video_encoding()) { out.video_encoding = fromProto(in.video_encoding()); @@ -416,19 +403,18 @@ TrackPublishOptions fromProto(const proto::TrackPublishOptions &in) { return out; } -UserDataPacketEvent userDataPacketFromProto(const proto::DataPacketReceived &in, - RemoteParticipant *participant) { +UserDataPacketEvent userDataPacketFromProto(const proto::DataPacketReceived& in, RemoteParticipant* participant) { UserDataPacketEvent ev; ev.kind = static_cast(in.kind()); ev.participant = participant; ev.topic = in.user().topic(); // Copy bytes - const auto &owned = in.user().data(); - const auto &info = owned.data(); + const auto& owned = in.user().data(); + const auto& info = owned.data(); if (info.data_ptr() != 0 && info.data_len() > 0) { // NOLINTNEXTLINE(performance-no-int-to-ptr) - const auto *ptr = reinterpret_cast(info.data_ptr()); + const auto* ptr = reinterpret_cast(info.data_ptr()); auto len = static_cast(info.data_len()); ev.data.assign(ptr, ptr + len); } else { @@ -438,8 +424,7 @@ UserDataPacketEvent userDataPacketFromProto(const proto::DataPacketReceived &in, return ev; } -SipDtmfReceivedEvent sipDtmfFromProto(const proto::DataPacketReceived &in, - RemoteParticipant *participant) { +SipDtmfReceivedEvent sipDtmfFromProto(const proto::DataPacketReceived& in, RemoteParticipant* participant) { SipDtmfReceivedEvent ev; ev.participant = participant; ev.code = static_cast(in.sip_dtmf().code()); @@ -447,16 +432,15 @@ SipDtmfReceivedEvent sipDtmfFromProto(const proto::DataPacketReceived &in, return ev; } -std::map -toAttrMap(const proto::DataStream::Trailer &trailer) { +std::map toAttrMap(const proto::DataStream::Trailer& trailer) { std::map out; - for (const auto &kv : trailer.attributes()) { + for (const auto& kv : trailer.attributes()) { out.emplace(kv.first, kv.second); } return out; } -TextStreamInfo makeTextInfo(const proto::DataStream::Header &header) { +TextStreamInfo makeTextInfo(const proto::DataStream::Header& header) { TextStreamInfo info; info.stream_id = header.stream_id(); info.mime_type = header.mime_type(); @@ -467,18 +451,18 @@ TextStreamInfo makeTextInfo(const proto::DataStream::Header &header) { info.size = static_cast(header.total_length()); } - for (const auto &kv : header.attributes()) { + for (const auto& kv : header.attributes()) { info.attributes.emplace(kv.first, kv.second); } - for (const auto &id : header.text_header().attached_stream_ids()) { + for (const auto& id : header.text_header().attached_stream_ids()) { info.attachments.push_back(id); } return info; } -ByteStreamInfo makeByteInfo(const proto::DataStream::Header &header) { +ByteStreamInfo makeByteInfo(const proto::DataStream::Header& header) { ByteStreamInfo info; info.stream_id = header.stream_id(); info.mime_type = header.mime_type(); @@ -489,7 +473,7 @@ ByteStreamInfo makeByteInfo(const proto::DataStream::Header &header) { info.size = static_cast(header.total_length()); } - for (const auto &kv : header.attributes()) { + for (const auto& kv : header.attributes()) { info.attributes.emplace(kv.first, kv.second); } diff --git a/src/room_proto_converter.h b/src/room_proto_converter.h index 23f8b0e5..8df7c795 100644 --- a/src/room_proto_converter.h +++ b/src/room_proto_converter.h @@ -16,11 +16,11 @@ #pragma once +#include + #include "livekit/room_event_types.h" #include "room.pb.h" -#include - namespace livekit { enum class RpcErrorCode; @@ -35,64 +35,57 @@ ConnectionState toConnectionState(proto::ConnectionState in); DataPacketKind toDataPacketKind(proto::DataPacketKind in); DisconnectReason toDisconnectReason(proto::DisconnectReason in); -UserPacketData fromProto(const proto::UserPacket &in); -SipDtmfData fromProto(const proto::SipDTMF &in); -RoomInfoData fromProto(const proto::RoomInfo &in); +UserPacketData fromProto(const proto::UserPacket& in); +SipDtmfData fromProto(const proto::SipDTMF& in); +RoomInfoData fromProto(const proto::RoomInfo& in); -DataStreamHeaderData fromProto(const proto::DataStream_Header &in); -DataStreamChunkData fromProto(const proto::DataStream_Chunk &in); -DataStreamTrailerData fromProto(const proto::DataStream_Trailer &in); +DataStreamHeaderData fromProto(const proto::DataStream_Header& in); +DataStreamChunkData fromProto(const proto::DataStream_Chunk& in); +DataStreamTrailerData fromProto(const proto::DataStream_Trailer& in); // --------- event conversions (RoomEvent.oneof message) --------- -RoomSidChangedEvent fromProto(const proto::RoomSidChanged &in); +RoomSidChangedEvent fromProto(const proto::RoomSidChanged& in); -ConnectionStateChangedEvent fromProto(const proto::ConnectionStateChanged &in); -DisconnectedEvent fromProto(const proto::Disconnected &in); -ReconnectingEvent fromProto(const proto::Reconnecting &in); -ReconnectedEvent fromProto(const proto::Reconnected &in); -RoomEosEvent fromProto(const proto::RoomEOS &in); +ConnectionStateChangedEvent fromProto(const proto::ConnectionStateChanged& in); +DisconnectedEvent fromProto(const proto::Disconnected& in); +ReconnectingEvent fromProto(const proto::Reconnecting& in); +ReconnectedEvent fromProto(const proto::Reconnected& in); +RoomEosEvent fromProto(const proto::RoomEOS& in); -DataStreamHeaderReceivedEvent -fromProto(const proto::DataStreamHeaderReceived &in); -DataStreamChunkReceivedEvent -fromProto(const proto::DataStreamChunkReceived &in); -DataStreamTrailerReceivedEvent -fromProto(const proto::DataStreamTrailerReceived &in); +DataStreamHeaderReceivedEvent fromProto(const proto::DataStreamHeaderReceived& in); +DataStreamChunkReceivedEvent fromProto(const proto::DataStreamChunkReceived& in); +DataStreamTrailerReceivedEvent fromProto(const proto::DataStreamTrailerReceived& in); -DataChannelBufferedAmountLowThresholdChangedEvent -fromProto(const proto::DataChannelBufferedAmountLowThresholdChanged &in); +DataChannelBufferedAmountLowThresholdChangedEvent fromProto( + const proto::DataChannelBufferedAmountLowThresholdChanged& in); -ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened &in); -TextStreamOpenedEvent fromProto(const proto::TextStreamOpened &in); +ByteStreamOpenedEvent fromProto(const proto::ByteStreamOpened& in); +TextStreamOpenedEvent fromProto(const proto::TextStreamOpened& in); -RoomUpdatedEvent -roomUpdatedFromProto(const proto::RoomInfo &in); // room_updated -RoomMovedEvent roomMovedFromProto(const proto::RoomInfo &in); // moved +RoomUpdatedEvent roomUpdatedFromProto(const proto::RoomInfo& in); // room_updated +RoomMovedEvent roomMovedFromProto(const proto::RoomInfo& in); // moved // --------- room options conversions --------- -proto::AudioEncoding toProto(const AudioEncodingOptions &in); -AudioEncodingOptions fromProto(const proto::AudioEncoding &in); +proto::AudioEncoding toProto(const AudioEncodingOptions& in); +AudioEncodingOptions fromProto(const proto::AudioEncoding& in); -proto::VideoEncoding toProto(const VideoEncodingOptions &in); -VideoEncodingOptions fromProto(const proto::VideoEncoding &in); +proto::VideoEncoding toProto(const VideoEncodingOptions& in); +VideoEncodingOptions fromProto(const proto::VideoEncoding& in); -proto::TrackPublishOptions toProto(const TrackPublishOptions &in); -TrackPublishOptions fromProto(const proto::TrackPublishOptions &in); +proto::TrackPublishOptions toProto(const TrackPublishOptions& in); +TrackPublishOptions fromProto(const proto::TrackPublishOptions& in); // --------- room Data Packet conversions --------- -UserDataPacketEvent userDataPacketFromProto(const proto::DataPacketReceived &in, - RemoteParticipant *participant); +UserDataPacketEvent userDataPacketFromProto(const proto::DataPacketReceived& in, RemoteParticipant* participant); -SipDtmfReceivedEvent sipDtmfFromProto(const proto::DataPacketReceived &in, - RemoteParticipant *participant); +SipDtmfReceivedEvent sipDtmfFromProto(const proto::DataPacketReceived& in, RemoteParticipant* participant); // --------- room Data Stream conversions --------- -std::map -toAttrMap(const proto::DataStream::Trailer &trailer); -ByteStreamInfo makeByteInfo(const proto::DataStream::Header &header); -TextStreamInfo makeTextInfo(const proto::DataStream::Header &header); +std::map toAttrMap(const proto::DataStream::Trailer& trailer); +ByteStreamInfo makeByteInfo(const proto::DataStream::Header& header); +TextStreamInfo makeTextInfo(const proto::DataStream::Header& header); } // namespace livekit diff --git a/src/rpc_error.cpp b/src/rpc_error.cpp index 1e521cd5..82e7abdf 100644 --- a/src/rpc_error.cpp +++ b/src/rpc_error.cpp @@ -21,18 +21,16 @@ namespace livekit { RpcError::RpcError(std::uint32_t code, std::string message, std::string data) - : std::runtime_error(message), code_(code), message_(std::move(message)), - data_(std::move(data)) {} + : std::runtime_error(message), code_(code), message_(std::move(message)), data_(std::move(data)) {} RpcError::RpcError(ErrorCode code, std::string message, std::string data) - : RpcError(static_cast(code), std::move(message), - std::move(data)) {} + : RpcError(static_cast(code), std::move(message), std::move(data)) {} std::uint32_t RpcError::code() const noexcept { return code_; } -const std::string &RpcError::message() const noexcept { return message_; } +const std::string& RpcError::message() const noexcept { return message_; } -const std::string &RpcError::data() const noexcept { return data_; } +const std::string& RpcError::data() const noexcept { return data_; } proto::RpcError RpcError::toProto() const { proto::RpcError err; @@ -47,40 +45,40 @@ proto::RpcError RpcError::toProto() const { return err; } -RpcError RpcError::fromProto(const proto::RpcError &err) { +RpcError RpcError::fromProto(const proto::RpcError& err) { // proto::RpcError.data() will return empty string if unset, which is fine. return RpcError(err.code(), err.message(), err.data()); } -RpcError RpcError::builtIn(ErrorCode code, const std::string &data) { - const char *msg = defaultMessageFor(code); +RpcError RpcError::builtIn(ErrorCode code, const std::string& data) { + const char* msg = defaultMessageFor(code); return RpcError(code, msg ? std::string(msg) : std::string{}, data); } -const char *RpcError::defaultMessageFor(ErrorCode code) { +const char* RpcError::defaultMessageFor(ErrorCode code) { switch (code) { - case ErrorCode::APPLICATION_ERROR: - return "Application error in method handler"; - case ErrorCode::CONNECTION_TIMEOUT: - return "Connection timeout"; - case ErrorCode::RESPONSE_TIMEOUT: - return "Response timeout"; - case ErrorCode::RECIPIENT_DISCONNECTED: - return "Recipient disconnected"; - case ErrorCode::RESPONSE_PAYLOAD_TOO_LARGE: - return "Response payload too large"; - case ErrorCode::SEND_FAILED: - return "Failed to send"; - case ErrorCode::UNSUPPORTED_METHOD: - return "Method not supported at destination"; - case ErrorCode::RECIPIENT_NOT_FOUND: - return "Recipient not found"; - case ErrorCode::REQUEST_PAYLOAD_TOO_LARGE: - return "Request payload too large"; - case ErrorCode::UNSUPPORTED_SERVER: - return "RPC not supported by server"; - case ErrorCode::UNSUPPORTED_VERSION: - return "Unsupported RPC version"; + case ErrorCode::APPLICATION_ERROR: + return "Application error in method handler"; + case ErrorCode::CONNECTION_TIMEOUT: + return "Connection timeout"; + case ErrorCode::RESPONSE_TIMEOUT: + return "Response timeout"; + case ErrorCode::RECIPIENT_DISCONNECTED: + return "Recipient disconnected"; + case ErrorCode::RESPONSE_PAYLOAD_TOO_LARGE: + return "Response payload too large"; + case ErrorCode::SEND_FAILED: + return "Failed to send"; + case ErrorCode::UNSUPPORTED_METHOD: + return "Method not supported at destination"; + case ErrorCode::RECIPIENT_NOT_FOUND: + return "Recipient not found"; + case ErrorCode::REQUEST_PAYLOAD_TOO_LARGE: + return "Request payload too large"; + case ErrorCode::UNSUPPORTED_SERVER: + return "RPC not supported by server"; + case ErrorCode::UNSUPPORTED_VERSION: + return "Unsupported RPC version"; } // Should be unreachable if all enum values are covered. diff --git a/src/stats.cpp b/src/stats.cpp index 4d3b762a..fa31f113 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -27,161 +27,160 @@ namespace { DataChannelState fromProto(livekit::proto::DataChannelState s) { using P = livekit::proto::DataChannelState; switch (s) { - case P::DC_CONNECTING: - return DataChannelState::Connecting; - case P::DC_OPEN: - return DataChannelState::Open; - case P::DC_CLOSING: - return DataChannelState::Closing; - case P::DC_CLOSED: - return DataChannelState::Closed; - default: - return DataChannelState::Unknown; + case P::DC_CONNECTING: + return DataChannelState::Connecting; + case P::DC_OPEN: + return DataChannelState::Open; + case P::DC_CLOSING: + return DataChannelState::Closing; + case P::DC_CLOSED: + return DataChannelState::Closed; + default: + return DataChannelState::Unknown; } } QualityLimitationReason fromProto(livekit::proto::QualityLimitationReason r) { using P = livekit::proto::QualityLimitationReason; switch (r) { - case P::LIMITATION_NONE: - return QualityLimitationReason::None; - case P::LIMITATION_CPU: - return QualityLimitationReason::Cpu; - case P::LIMITATION_BANDWIDTH: - return QualityLimitationReason::Bandwidth; - case P::LIMITATION_OTHER: // NOLINT(bugprone-branch-clone) - return QualityLimitationReason::Other; - default: - return QualityLimitationReason::Other; + case P::LIMITATION_NONE: + return QualityLimitationReason::None; + case P::LIMITATION_CPU: + return QualityLimitationReason::Cpu; + case P::LIMITATION_BANDWIDTH: + return QualityLimitationReason::Bandwidth; + case P::LIMITATION_OTHER: // NOLINT(bugprone-branch-clone) + return QualityLimitationReason::Other; + default: + return QualityLimitationReason::Other; } } IceRole fromProto(livekit::proto::IceRole r) { using P = livekit::proto::IceRole; switch (r) { - case P::ICE_CONTROLLING: - return IceRole::Controlling; - case P::ICE_CONTROLLED: - return IceRole::Controlled; - case P::ICE_UNKNOWN: - default: - return IceRole::Unknown; + case P::ICE_CONTROLLING: + return IceRole::Controlling; + case P::ICE_CONTROLLED: + return IceRole::Controlled; + case P::ICE_UNKNOWN: + default: + return IceRole::Unknown; } } DtlsTransportState fromProto(livekit::proto::DtlsTransportState s) { using P = livekit::proto::DtlsTransportState; switch (s) { - case P::DTLS_TRANSPORT_NEW: - return DtlsTransportState::New; - case P::DTLS_TRANSPORT_CONNECTING: - return DtlsTransportState::Connecting; - case P::DTLS_TRANSPORT_CONNECTED: - return DtlsTransportState::Connected; - case P::DTLS_TRANSPORT_CLOSED: - return DtlsTransportState::Closed; - case P::DTLS_TRANSPORT_FAILED: - return DtlsTransportState::Failed; - default: - return DtlsTransportState::Unknown; + case P::DTLS_TRANSPORT_NEW: + return DtlsTransportState::New; + case P::DTLS_TRANSPORT_CONNECTING: + return DtlsTransportState::Connecting; + case P::DTLS_TRANSPORT_CONNECTED: + return DtlsTransportState::Connected; + case P::DTLS_TRANSPORT_CLOSED: + return DtlsTransportState::Closed; + case P::DTLS_TRANSPORT_FAILED: + return DtlsTransportState::Failed; + default: + return DtlsTransportState::Unknown; } } IceTransportState fromProto(livekit::proto::IceTransportState s) { using P = livekit::proto::IceTransportState; switch (s) { - case P::ICE_TRANSPORT_NEW: - return IceTransportState::New; - case P::ICE_TRANSPORT_CHECKING: - return IceTransportState::Checking; - case P::ICE_TRANSPORT_CONNECTED: - return IceTransportState::Connected; - case P::ICE_TRANSPORT_COMPLETED: - return IceTransportState::Completed; - case P::ICE_TRANSPORT_DISCONNECTED: - return IceTransportState::Disconnected; - case P::ICE_TRANSPORT_FAILED: - return IceTransportState::Failed; - case P::ICE_TRANSPORT_CLOSED: - return IceTransportState::Closed; - default: - return IceTransportState::Unknown; + case P::ICE_TRANSPORT_NEW: + return IceTransportState::New; + case P::ICE_TRANSPORT_CHECKING: + return IceTransportState::Checking; + case P::ICE_TRANSPORT_CONNECTED: + return IceTransportState::Connected; + case P::ICE_TRANSPORT_COMPLETED: + return IceTransportState::Completed; + case P::ICE_TRANSPORT_DISCONNECTED: + return IceTransportState::Disconnected; + case P::ICE_TRANSPORT_FAILED: + return IceTransportState::Failed; + case P::ICE_TRANSPORT_CLOSED: + return IceTransportState::Closed; + default: + return IceTransportState::Unknown; } } DtlsRole fromProto(livekit::proto::DtlsRole r) { using P = livekit::proto::DtlsRole; switch (r) { - case P::DTLS_CLIENT: - return DtlsRole::Client; - case P::DTLS_SERVER: - return DtlsRole::Server; - case P::DTLS_UNKNOWN: - default: - return DtlsRole::Unknown; + case P::DTLS_CLIENT: + return DtlsRole::Client; + case P::DTLS_SERVER: + return DtlsRole::Server; + case P::DTLS_UNKNOWN: + default: + return DtlsRole::Unknown; } } IceCandidatePairState fromProto(livekit::proto::IceCandidatePairState s) { using P = livekit::proto::IceCandidatePairState; switch (s) { - case P::PAIR_FROZEN: - return IceCandidatePairState::Frozen; - case P::PAIR_WAITING: - return IceCandidatePairState::Waiting; - case P::PAIR_IN_PROGRESS: - return IceCandidatePairState::InProgress; - case P::PAIR_FAILED: - return IceCandidatePairState::Failed; - case P::PAIR_SUCCEEDED: - return IceCandidatePairState::Succeeded; - default: - return IceCandidatePairState::Unknown; + case P::PAIR_FROZEN: + return IceCandidatePairState::Frozen; + case P::PAIR_WAITING: + return IceCandidatePairState::Waiting; + case P::PAIR_IN_PROGRESS: + return IceCandidatePairState::InProgress; + case P::PAIR_FAILED: + return IceCandidatePairState::Failed; + case P::PAIR_SUCCEEDED: + return IceCandidatePairState::Succeeded; + default: + return IceCandidatePairState::Unknown; } } IceCandidateType fromProto(livekit::proto::IceCandidateType t) { using P = livekit::proto::IceCandidateType; switch (t) { - case P::HOST: - return IceCandidateType::Host; - case P::SRFLX: - return IceCandidateType::Srflx; - case P::PRFLX: - return IceCandidateType::Prflx; - case P::RELAY: - return IceCandidateType::Relay; - default: - return IceCandidateType::Unknown; + case P::HOST: + return IceCandidateType::Host; + case P::SRFLX: + return IceCandidateType::Srflx; + case P::PRFLX: + return IceCandidateType::Prflx; + case P::RELAY: + return IceCandidateType::Relay; + default: + return IceCandidateType::Unknown; } } -IceServerTransportProtocol -fromProto(livekit::proto::IceServerTransportProtocol p) { +IceServerTransportProtocol fromProto(livekit::proto::IceServerTransportProtocol p) { using P = livekit::proto::IceServerTransportProtocol; switch (p) { - case P::TRANSPORT_UDP: - return IceServerTransportProtocol::Udp; - case P::TRANSPORT_TCP: - return IceServerTransportProtocol::Tcp; - case P::TRANSPORT_TLS: - return IceServerTransportProtocol::Tls; - default: - return IceServerTransportProtocol::Unknown; + case P::TRANSPORT_UDP: + return IceServerTransportProtocol::Udp; + case P::TRANSPORT_TCP: + return IceServerTransportProtocol::Tcp; + case P::TRANSPORT_TLS: + return IceServerTransportProtocol::Tls; + default: + return IceServerTransportProtocol::Unknown; } } IceTcpCandidateType fromProto(livekit::proto::IceTcpCandidateType t) { using P = livekit::proto::IceTcpCandidateType; switch (t) { - case P::CANDIDATE_ACTIVE: - return IceTcpCandidateType::Active; - case P::CANDIDATE_PASSIVE: - return IceTcpCandidateType::Passive; - case P::CANDIDATE_SO: - return IceTcpCandidateType::So; - default: - return IceTcpCandidateType::Unknown; + case P::CANDIDATE_ACTIVE: + return IceTcpCandidateType::Active; + case P::CANDIDATE_PASSIVE: + return IceTcpCandidateType::Passive; + case P::CANDIDATE_SO: + return IceTcpCandidateType::So; + default: + return IceTcpCandidateType::Unknown; } } @@ -191,14 +190,14 @@ IceTcpCandidateType fromProto(livekit::proto::IceTcpCandidateType t) { // Leaf conversions // ---------------------- -RtcStatsData fromProto(const proto::RtcStatsData &s) { +RtcStatsData fromProto(const proto::RtcStatsData& s) { RtcStatsData out; out.id = s.id(); out.timestamp_ms = s.timestamp(); return out; } -CodecStats fromProto(const proto::CodecStats &s) { +CodecStats fromProto(const proto::CodecStats& s) { CodecStats out; out.payload_type = s.payload_type(); out.transport_id = s.transport_id(); @@ -209,7 +208,7 @@ CodecStats fromProto(const proto::CodecStats &s) { return out; } -RtpStreamStats fromProto(const proto::RtpStreamStats &s) { +RtpStreamStats fromProto(const proto::RtpStreamStats& s) { RtpStreamStats out; out.ssrc = s.ssrc(); out.kind = s.kind(); @@ -218,7 +217,7 @@ RtpStreamStats fromProto(const proto::RtpStreamStats &s) { return out; } -ReceivedRtpStreamStats fromProto(const proto::ReceivedRtpStreamStats &s) { +ReceivedRtpStreamStats fromProto(const proto::ReceivedRtpStreamStats& s) { ReceivedRtpStreamStats out; out.packets_received = s.packets_received(); out.packets_lost = s.packets_lost(); @@ -226,7 +225,7 @@ ReceivedRtpStreamStats fromProto(const proto::ReceivedRtpStreamStats &s) { return out; } -InboundRtpStreamStats fromProto(const proto::InboundRtpStreamStats &s) { +InboundRtpStreamStats fromProto(const proto::InboundRtpStreamStats& s) { InboundRtpStreamStats out; out.track_identifier = s.track_identifier(); out.mid = s.mid(); @@ -275,8 +274,7 @@ InboundRtpStreamStats fromProto(const proto::InboundRtpStreamStats &s) { out.decoder_implementation = s.decoder_implementation(); out.playout_id = s.playout_id(); out.power_efficient_decoder = s.power_efficient_decoder(); - out.frames_assembled_from_multiple_packets = - s.frames_assembled_from_multiple_packets(); + out.frames_assembled_from_multiple_packets = s.frames_assembled_from_multiple_packets(); out.total_assembly_time = s.total_assembly_time(); out.retransmitted_packets_received = s.retransmitted_packets_received(); out.retransmitted_bytes_received = s.retransmitted_bytes_received(); @@ -285,14 +283,14 @@ InboundRtpStreamStats fromProto(const proto::InboundRtpStreamStats &s) { return out; } -SentRtpStreamStats fromProto(const proto::SentRtpStreamStats &s) { +SentRtpStreamStats fromProto(const proto::SentRtpStreamStats& s) { SentRtpStreamStats out; out.packets_sent = s.packets_sent(); out.bytes_sent = s.bytes_sent(); return out; } -OutboundRtpStreamStats fromProto(const proto::OutboundRtpStreamStats &s) { +OutboundRtpStreamStats fromProto(const proto::OutboundRtpStreamStats& s) { OutboundRtpStreamStats out; out.mid = s.mid(); out.media_source_id = s.media_source_id(); @@ -316,11 +314,10 @@ OutboundRtpStreamStats fromProto(const proto::OutboundRtpStreamStats &s) { out.total_packet_send_delay = s.total_packet_send_delay(); out.quality_limitation_reason = fromProto(s.quality_limitation_reason()); out.quality_limitation_durations.clear(); - for (const auto &kv : s.quality_limitation_durations()) { + for (const auto& kv : s.quality_limitation_durations()) { out.quality_limitation_durations.emplace(kv.first, kv.second); } - out.quality_limitation_resolution_changes = - s.quality_limitation_resolution_changes(); + out.quality_limitation_resolution_changes = s.quality_limitation_resolution_changes(); out.nack_count = s.nack_count(); out.fir_count = s.fir_count(); out.pli_count = s.pli_count(); @@ -331,8 +328,7 @@ OutboundRtpStreamStats fromProto(const proto::OutboundRtpStreamStats &s) { return out; } -RemoteInboundRtpStreamStats -fromProto(const proto::RemoteInboundRtpStreamStats &s) { +RemoteInboundRtpStreamStats fromProto(const proto::RemoteInboundRtpStreamStats& s) { RemoteInboundRtpStreamStats out; out.local_id = s.local_id(); out.round_trip_time = s.round_trip_time(); @@ -342,8 +338,7 @@ fromProto(const proto::RemoteInboundRtpStreamStats &s) { return out; } -RemoteOutboundRtpStreamStats -fromProto(const proto::RemoteOutboundRtpStreamStats &s) { +RemoteOutboundRtpStreamStats fromProto(const proto::RemoteOutboundRtpStreamStats& s) { RemoteOutboundRtpStreamStats out; out.local_id = s.local_id(); out.remote_timestamp = s.remote_timestamp(); @@ -354,14 +349,14 @@ fromProto(const proto::RemoteOutboundRtpStreamStats &s) { return out; } -MediaSourceStats fromProto(const proto::MediaSourceStats &s) { +MediaSourceStats fromProto(const proto::MediaSourceStats& s) { MediaSourceStats out; out.track_identifier = s.track_identifier(); out.kind = s.kind(); return out; } -AudioSourceStats fromProto(const proto::AudioSourceStats &s) { +AudioSourceStats fromProto(const proto::AudioSourceStats& s) { AudioSourceStats out; out.audio_level = s.audio_level(); out.total_audio_energy = s.total_audio_energy(); @@ -375,7 +370,7 @@ AudioSourceStats fromProto(const proto::AudioSourceStats &s) { return out; } -VideoSourceStats fromProto(const proto::VideoSourceStats &s) { +VideoSourceStats fromProto(const proto::VideoSourceStats& s) { VideoSourceStats out; out.width = s.width(); out.height = s.height(); @@ -384,7 +379,7 @@ VideoSourceStats fromProto(const proto::VideoSourceStats &s) { return out; } -AudioPlayoutStats fromProto(const proto::AudioPlayoutStats &s) { +AudioPlayoutStats fromProto(const proto::AudioPlayoutStats& s) { AudioPlayoutStats out; out.kind = s.kind(); out.synthesized_samples_duration = s.synthesized_samples_duration(); @@ -395,14 +390,14 @@ AudioPlayoutStats fromProto(const proto::AudioPlayoutStats &s) { return out; } -PeerConnectionStats fromProto(const proto::PeerConnectionStats &s) { +PeerConnectionStats fromProto(const proto::PeerConnectionStats& s) { PeerConnectionStats out; out.data_channels_opened = s.data_channels_opened(); out.data_channels_closed = s.data_channels_closed(); return out; } -DataChannelStats fromProto(const proto::DataChannelStats &s) { +DataChannelStats fromProto(const proto::DataChannelStats& s) { DataChannelStats out; out.label = s.label(); out.protocol = s.protocol(); @@ -419,7 +414,7 @@ DataChannelStats fromProto(const proto::DataChannelStats &s) { return out; } -TransportStats fromProto(const proto::TransportStats &s) { +TransportStats fromProto(const proto::TransportStats& s) { TransportStats out; out.packets_sent = s.packets_sent(); out.packets_received = s.packets_received(); @@ -448,7 +443,7 @@ TransportStats fromProto(const proto::TransportStats &s) { return out; } -CandidatePairStats fromProto(const proto::CandidatePairStats &s) { +CandidatePairStats fromProto(const proto::CandidatePairStats& s) { CandidatePairStats out; out.transport_id = s.transport_id(); out.local_candidate_id = s.local_candidate_id(); @@ -479,7 +474,7 @@ CandidatePairStats fromProto(const proto::CandidatePairStats &s) { return out; } -IceCandidateStats fromProto(const proto::IceCandidateStats &s) { +IceCandidateStats fromProto(const proto::IceCandidateStats& s) { IceCandidateStats out; out.transport_id = s.transport_id(); out.address = s.address(); @@ -509,7 +504,7 @@ IceCandidateStats fromProto(const proto::IceCandidateStats &s) { return out; } -CertificateStats fromProto(const proto::CertificateStats &s) { +CertificateStats fromProto(const proto::CertificateStats& s) { CertificateStats out; out.fingerprint = s.fingerprint(); out.fingerprint_algorithm = s.fingerprint_algorithm(); @@ -518,7 +513,7 @@ CertificateStats fromProto(const proto::CertificateStats &s) { return out; } -StreamStats fromProto(const proto::StreamStats &s) { +StreamStats fromProto(const proto::StreamStats& s) { StreamStats out; out.id = s.id(); out.stream_identifier = s.stream_identifier(); @@ -529,127 +524,127 @@ StreamStats fromProto(const proto::StreamStats &s) { // High-level RtcStats fromProto // ---------------------- -RtcStats fromProto(const proto::RtcStats &s) { +RtcStats fromProto(const proto::RtcStats& s) { using P = proto::RtcStats; switch (s.stats_case()) { - case P::kCodec: { - RtcCodecStats out; - out.rtc = fromProto(s.codec().rtc()); - out.codec = fromProto(s.codec().codec()); - return RtcStats{std::move(out)}; - } - case P::kInboundRtp: { - RtcInboundRtpStats out; - out.rtc = fromProto(s.inbound_rtp().rtc()); - out.stream = fromProto(s.inbound_rtp().stream()); - out.received = fromProto(s.inbound_rtp().received()); - out.inbound = fromProto(s.inbound_rtp().inbound()); - return RtcStats{std::move(out)}; - } - case P::kOutboundRtp: { - RtcOutboundRtpStats out; - out.rtc = fromProto(s.outbound_rtp().rtc()); - out.stream = fromProto(s.outbound_rtp().stream()); - out.sent = fromProto(s.outbound_rtp().sent()); - out.outbound = fromProto(s.outbound_rtp().outbound()); - return RtcStats{std::move(out)}; - } - case P::kRemoteInboundRtp: { - RtcRemoteInboundRtpStats out; - out.rtc = fromProto(s.remote_inbound_rtp().rtc()); - out.stream = fromProto(s.remote_inbound_rtp().stream()); - out.received = fromProto(s.remote_inbound_rtp().received()); - out.remote_inbound = fromProto(s.remote_inbound_rtp().remote_inbound()); - return RtcStats{std::move(out)}; - } - case P::kRemoteOutboundRtp: { - RtcRemoteOutboundRtpStats out; - out.rtc = fromProto(s.remote_outbound_rtp().rtc()); - out.stream = fromProto(s.remote_outbound_rtp().stream()); - out.sent = fromProto(s.remote_outbound_rtp().sent()); - out.remote_outbound = fromProto(s.remote_outbound_rtp().remote_outbound()); - return RtcStats{std::move(out)}; - } - case P::kMediaSource: { - RtcMediaSourceStats out; - out.rtc = fromProto(s.media_source().rtc()); - out.source = fromProto(s.media_source().source()); - out.audio = fromProto(s.media_source().audio()); - out.video = fromProto(s.media_source().video()); - return RtcStats{std::move(out)}; - } - case P::kMediaPlayout: { - RtcMediaPlayoutStats out; - out.rtc = fromProto(s.media_playout().rtc()); - out.audio_playout = fromProto(s.media_playout().audio_playout()); - return RtcStats{std::move(out)}; - } - case P::kPeerConnection: { - RtcPeerConnectionStats out; - out.rtc = fromProto(s.peer_connection().rtc()); - out.pc = fromProto(s.peer_connection().pc()); - return RtcStats{std::move(out)}; - } - case P::kDataChannel: { - RtcDataChannelStats out; - out.rtc = fromProto(s.data_channel().rtc()); - out.dc = fromProto(s.data_channel().dc()); - return RtcStats{std::move(out)}; - } - case P::kTransport: { - RtcTransportStats out; - out.rtc = fromProto(s.transport().rtc()); - out.transport = fromProto(s.transport().transport()); - return RtcStats{std::move(out)}; - } - case P::kCandidatePair: { - RtcCandidatePairStats out; - out.rtc = fromProto(s.candidate_pair().rtc()); - out.candidate_pair = fromProto(s.candidate_pair().candidate_pair()); - return RtcStats{std::move(out)}; - } - case P::kLocalCandidate: { - RtcLocalCandidateStats out; - out.rtc = fromProto(s.local_candidate().rtc()); - out.candidate = fromProto(s.local_candidate().candidate()); - return RtcStats{std::move(out)}; - } - case P::kRemoteCandidate: { - RtcRemoteCandidateStats out; - out.rtc = fromProto(s.remote_candidate().rtc()); - out.candidate = fromProto(s.remote_candidate().candidate()); - return RtcStats{std::move(out)}; - } - case P::kCertificate: { - RtcCertificateStats out; - out.rtc = fromProto(s.certificate().rtc()); - out.certificate = fromProto(s.certificate().certificate()); - return RtcStats{std::move(out)}; - } - case P::kStream: { - RtcStreamStats out; - out.rtc = fromProto(s.stream().rtc()); - out.stream = fromProto(s.stream().stream()); - return RtcStats{std::move(out)}; - } - case P::kTrack: - // Deprecated; fall through to default - case P::STATS_NOT_SET: - default: { - // You might want to handle this differently (throw, assert, etc.) - RtcCodecStats dummy{}; - dummy.rtc = RtcStatsData{}; - dummy.codec = CodecStats{}; - return RtcStats{std::move(dummy)}; - } - } -} - -std::vector fromProto(const std::vector &src) { + case P::kCodec: { + RtcCodecStats out; + out.rtc = fromProto(s.codec().rtc()); + out.codec = fromProto(s.codec().codec()); + return RtcStats{std::move(out)}; + } + case P::kInboundRtp: { + RtcInboundRtpStats out; + out.rtc = fromProto(s.inbound_rtp().rtc()); + out.stream = fromProto(s.inbound_rtp().stream()); + out.received = fromProto(s.inbound_rtp().received()); + out.inbound = fromProto(s.inbound_rtp().inbound()); + return RtcStats{std::move(out)}; + } + case P::kOutboundRtp: { + RtcOutboundRtpStats out; + out.rtc = fromProto(s.outbound_rtp().rtc()); + out.stream = fromProto(s.outbound_rtp().stream()); + out.sent = fromProto(s.outbound_rtp().sent()); + out.outbound = fromProto(s.outbound_rtp().outbound()); + return RtcStats{std::move(out)}; + } + case P::kRemoteInboundRtp: { + RtcRemoteInboundRtpStats out; + out.rtc = fromProto(s.remote_inbound_rtp().rtc()); + out.stream = fromProto(s.remote_inbound_rtp().stream()); + out.received = fromProto(s.remote_inbound_rtp().received()); + out.remote_inbound = fromProto(s.remote_inbound_rtp().remote_inbound()); + return RtcStats{std::move(out)}; + } + case P::kRemoteOutboundRtp: { + RtcRemoteOutboundRtpStats out; + out.rtc = fromProto(s.remote_outbound_rtp().rtc()); + out.stream = fromProto(s.remote_outbound_rtp().stream()); + out.sent = fromProto(s.remote_outbound_rtp().sent()); + out.remote_outbound = fromProto(s.remote_outbound_rtp().remote_outbound()); + return RtcStats{std::move(out)}; + } + case P::kMediaSource: { + RtcMediaSourceStats out; + out.rtc = fromProto(s.media_source().rtc()); + out.source = fromProto(s.media_source().source()); + out.audio = fromProto(s.media_source().audio()); + out.video = fromProto(s.media_source().video()); + return RtcStats{std::move(out)}; + } + case P::kMediaPlayout: { + RtcMediaPlayoutStats out; + out.rtc = fromProto(s.media_playout().rtc()); + out.audio_playout = fromProto(s.media_playout().audio_playout()); + return RtcStats{std::move(out)}; + } + case P::kPeerConnection: { + RtcPeerConnectionStats out; + out.rtc = fromProto(s.peer_connection().rtc()); + out.pc = fromProto(s.peer_connection().pc()); + return RtcStats{std::move(out)}; + } + case P::kDataChannel: { + RtcDataChannelStats out; + out.rtc = fromProto(s.data_channel().rtc()); + out.dc = fromProto(s.data_channel().dc()); + return RtcStats{std::move(out)}; + } + case P::kTransport: { + RtcTransportStats out; + out.rtc = fromProto(s.transport().rtc()); + out.transport = fromProto(s.transport().transport()); + return RtcStats{std::move(out)}; + } + case P::kCandidatePair: { + RtcCandidatePairStats out; + out.rtc = fromProto(s.candidate_pair().rtc()); + out.candidate_pair = fromProto(s.candidate_pair().candidate_pair()); + return RtcStats{std::move(out)}; + } + case P::kLocalCandidate: { + RtcLocalCandidateStats out; + out.rtc = fromProto(s.local_candidate().rtc()); + out.candidate = fromProto(s.local_candidate().candidate()); + return RtcStats{std::move(out)}; + } + case P::kRemoteCandidate: { + RtcRemoteCandidateStats out; + out.rtc = fromProto(s.remote_candidate().rtc()); + out.candidate = fromProto(s.remote_candidate().candidate()); + return RtcStats{std::move(out)}; + } + case P::kCertificate: { + RtcCertificateStats out; + out.rtc = fromProto(s.certificate().rtc()); + out.certificate = fromProto(s.certificate().certificate()); + return RtcStats{std::move(out)}; + } + case P::kStream: { + RtcStreamStats out; + out.rtc = fromProto(s.stream().rtc()); + out.stream = fromProto(s.stream().stream()); + return RtcStats{std::move(out)}; + } + case P::kTrack: + // Deprecated; fall through to default + case P::STATS_NOT_SET: + default: { + // You might want to handle this differently (throw, assert, etc.) + RtcCodecStats dummy{}; + dummy.rtc = RtcStatsData{}; + dummy.codec = CodecStats{}; + return RtcStats{std::move(dummy)}; + } + } +} + +std::vector fromProto(const std::vector& src) { std::vector out; out.reserve(src.size()); - for (const auto &s : src) { + for (const auto& s : src) { out.push_back(fromProto(s)); } return out; diff --git a/src/subscription_thread_dispatcher.cpp b/src/subscription_thread_dispatcher.cpp index 91877877..aa7703a3 100644 --- a/src/subscription_thread_dispatcher.cpp +++ b/src/subscription_thread_dispatcher.cpp @@ -16,27 +16,30 @@ #include "livekit/subscription_thread_dispatcher.h" +#include +#include +#include + #include "livekit/data_track_frame.h" #include "livekit/data_track_stream.h" #include "livekit/remote_data_track.h" #include "livekit/track.h" #include "lk_log.h" -#include -#include -#include - namespace livekit { namespace { -const char *trackKindName(TrackKind kind) { - if (kind == TrackKind::KIND_AUDIO) +const char* trackKindName(TrackKind kind) { + if (kind == TrackKind::KIND_AUDIO) { return "audio"; - if (kind == TrackKind::KIND_VIDEO) + } + if (kind == TrackKind::KIND_VIDEO) { return "video"; - if (kind == TrackKind::KIND_UNKNOWN) + } + if (kind == TrackKind::KIND_UNKNOWN) { return "unknown"; + } return "unsupported"; } @@ -54,24 +57,23 @@ SubscriptionThreadDispatcher::~SubscriptionThreadDispatcher() { } // NOLINTEND(bugprone-exception-escape) -void SubscriptionThreadDispatcher::setOnAudioFrameCallback( - const std::string &participant_identity, TrackSource source, - AudioFrameCallback callback, const AudioStream::Options &opts) { +void SubscriptionThreadDispatcher::setOnAudioFrameCallback(const std::string& participant_identity, TrackSource source, + AudioFrameCallback callback, + const AudioStream::Options& opts) { const CallbackKey key{participant_identity, source, ""}; const std::scoped_lock lock(lock_); const bool replacing = audio_callbacks_.find(key) != audio_callbacks_.end(); audio_callbacks_[key] = RegisteredAudioCallback{std::move(callback), opts}; - LK_LOG_DEBUG("Registered audio frame callback for participant={} source={} " - "replacing_existing={} total_audio_callbacks={}", - participant_identity, static_cast(source), replacing, - audio_callbacks_.size()); + LK_LOG_DEBUG( + "Registered audio frame callback for participant={} source={} " + "replacing_existing={} total_audio_callbacks={}", + participant_identity, static_cast(source), replacing, audio_callbacks_.size()); } -void SubscriptionThreadDispatcher::setOnAudioFrameCallback( - const std::string &participant_identity, const std::string &track_name, - AudioFrameCallback callback, const AudioStream::Options &opts) { - const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; +void SubscriptionThreadDispatcher::setOnAudioFrameCallback(const std::string& participant_identity, + const std::string& track_name, AudioFrameCallback callback, + const AudioStream::Options& opts) { + const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; const std::scoped_lock lock(lock_); const bool replacing = audio_callbacks_.find(key) != audio_callbacks_.end(); audio_callbacks_[key] = RegisteredAudioCallback{std::move(callback), opts}; @@ -81,9 +83,9 @@ void SubscriptionThreadDispatcher::setOnAudioFrameCallback( participant_identity, track_name, replacing, audio_callbacks_.size()); } -void SubscriptionThreadDispatcher::setOnVideoFrameCallback( - const std::string &participant_identity, TrackSource source, - VideoFrameCallback callback, const VideoStream::Options &opts) { +void SubscriptionThreadDispatcher::setOnVideoFrameCallback(const std::string& participant_identity, TrackSource source, + VideoFrameCallback callback, + const VideoStream::Options& opts) { const CallbackKey key{participant_identity, source, ""}; const std::scoped_lock lock(lock_); const bool replacing = video_callbacks_.find(key) != video_callbacks_.end(); @@ -92,17 +94,17 @@ void SubscriptionThreadDispatcher::setOnVideoFrameCallback( VideoFrameEventCallback{}, opts, }; - LK_LOG_DEBUG("Registered legacy video frame callback for participant={} " - "source={} replacing_existing={} total_video_callbacks={}", - participant_identity, static_cast(source), replacing, - video_callbacks_.size()); + LK_LOG_DEBUG( + "Registered legacy video frame callback for participant={} " + "source={} replacing_existing={} total_video_callbacks={}", + participant_identity, static_cast(source), replacing, video_callbacks_.size()); } -void SubscriptionThreadDispatcher::setOnVideoFrameEventCallback( - const std::string &participant_identity, const std::string &track_name, - VideoFrameEventCallback callback, const VideoStream::Options &opts) { - const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; +void SubscriptionThreadDispatcher::setOnVideoFrameEventCallback(const std::string& participant_identity, + const std::string& track_name, + VideoFrameEventCallback callback, + const VideoStream::Options& opts) { + const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; const std::scoped_lock lock(lock_); const bool replacing = video_callbacks_.find(key) != video_callbacks_.end(); video_callbacks_[key] = RegisteredVideoCallback{ @@ -116,11 +118,10 @@ void SubscriptionThreadDispatcher::setOnVideoFrameEventCallback( participant_identity, track_name, replacing, video_callbacks_.size()); } -void SubscriptionThreadDispatcher::setOnVideoFrameCallback( - const std::string &participant_identity, const std::string &track_name, - VideoFrameCallback callback, const VideoStream::Options &opts) { - const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; +void SubscriptionThreadDispatcher::setOnVideoFrameCallback(const std::string& participant_identity, + const std::string& track_name, VideoFrameCallback callback, + const VideoStream::Options& opts) { + const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; const std::scoped_lock lock(lock_); const bool replacing = video_callbacks_.find(key) != video_callbacks_.end(); video_callbacks_[key] = RegisteredVideoCallback{ @@ -134,8 +135,8 @@ void SubscriptionThreadDispatcher::setOnVideoFrameCallback( participant_identity, track_name, replacing, video_callbacks_.size()); } -void SubscriptionThreadDispatcher::clearOnAudioFrameCallback( - const std::string &participant_identity, TrackSource source) { +void SubscriptionThreadDispatcher::clearOnAudioFrameCallback(const std::string& participant_identity, + TrackSource source) { const CallbackKey key{participant_identity, source, ""}; std::thread old_thread; bool removed_callback = false; @@ -146,18 +147,17 @@ void SubscriptionThreadDispatcher::clearOnAudioFrameCallback( LK_LOG_DEBUG( "Clearing audio frame callback for participant={} source={} " "removed_callback={} stopped_reader={} remaining_audio_callbacks={}", - participant_identity, static_cast(source), removed_callback, - old_thread.joinable(), audio_callbacks_.size()); + participant_identity, static_cast(source), removed_callback, old_thread.joinable(), + audio_callbacks_.size()); } if (old_thread.joinable()) { old_thread.join(); } } -void SubscriptionThreadDispatcher::clearOnAudioFrameCallback( - const std::string &participant_identity, const std::string &track_name) { - const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; +void SubscriptionThreadDispatcher::clearOnAudioFrameCallback(const std::string& participant_identity, + const std::string& track_name) { + const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; std::thread old_thread; bool removed_callback = false; { @@ -167,16 +167,15 @@ void SubscriptionThreadDispatcher::clearOnAudioFrameCallback( LK_LOG_DEBUG( "Clearing audio frame callback for participant={} track_name={} " "removed_callback={} stopped_reader={} remaining_audio_callbacks={}", - participant_identity, track_name, removed_callback, - old_thread.joinable(), audio_callbacks_.size()); + participant_identity, track_name, removed_callback, old_thread.joinable(), audio_callbacks_.size()); } if (old_thread.joinable()) { old_thread.join(); } } -void SubscriptionThreadDispatcher::clearOnVideoFrameCallback( - const std::string &participant_identity, TrackSource source) { +void SubscriptionThreadDispatcher::clearOnVideoFrameCallback(const std::string& participant_identity, + TrackSource source) { const CallbackKey key{participant_identity, source, ""}; std::thread old_thread; bool removed_callback = false; @@ -187,18 +186,17 @@ void SubscriptionThreadDispatcher::clearOnVideoFrameCallback( LK_LOG_DEBUG( "Clearing video frame callback for participant={} source={} " "removed_callback={} stopped_reader={} remaining_video_callbacks={}", - participant_identity, static_cast(source), removed_callback, - old_thread.joinable(), video_callbacks_.size()); + participant_identity, static_cast(source), removed_callback, old_thread.joinable(), + video_callbacks_.size()); } if (old_thread.joinable()) { old_thread.join(); } } -void SubscriptionThreadDispatcher::clearOnVideoFrameCallback( - const std::string &participant_identity, const std::string &track_name) { - const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; +void SubscriptionThreadDispatcher::clearOnVideoFrameCallback(const std::string& participant_identity, + const std::string& track_name) { + const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; std::thread old_thread; bool removed_callback = false; { @@ -208,17 +206,16 @@ void SubscriptionThreadDispatcher::clearOnVideoFrameCallback( LK_LOG_DEBUG( "Clearing video frame callback for participant={} track_name={} " "removed_callback={} stopped_reader={} remaining_video_callbacks={}", - participant_identity, track_name, removed_callback, - old_thread.joinable(), video_callbacks_.size()); + participant_identity, track_name, removed_callback, old_thread.joinable(), video_callbacks_.size()); } if (old_thread.joinable()) { old_thread.join(); } } -void SubscriptionThreadDispatcher::handleTrackSubscribed( - const std::string &participant_identity, TrackSource source, - const std::string &track_name, const std::shared_ptr &track) { +void SubscriptionThreadDispatcher::handleTrackSubscribed(const std::string& participant_identity, TrackSource source, + const std::string& track_name, + const std::shared_ptr& track) { if (!track) { LK_LOG_WARN( "Ignoring subscribed track dispatch for participant={} source={} " @@ -227,20 +224,16 @@ void SubscriptionThreadDispatcher::handleTrackSubscribed( return; } - LK_LOG_DEBUG("Handling subscribed track for participant={} source={} kind={}", - participant_identity, static_cast(source), - trackKindName(track->kind())); + LK_LOG_DEBUG("Handling subscribed track for participant={} source={} kind={}", participant_identity, + static_cast(source), trackKindName(track->kind())); - CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; + CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; const CallbackKey fallback_key{participant_identity, source, ""}; std::thread old_thread; { const std::scoped_lock lock(lock_); - if ((track->kind() == TrackKind::KIND_AUDIO && - audio_callbacks_.find(key) == audio_callbacks_.end()) || - (track->kind() == TrackKind::KIND_VIDEO && - video_callbacks_.find(key) == video_callbacks_.end())) { + if ((track->kind() == TrackKind::KIND_AUDIO && audio_callbacks_.find(key) == audio_callbacks_.end()) || + (track->kind() == TrackKind::KIND_VIDEO && video_callbacks_.find(key) == video_callbacks_.end())) { key = fallback_key; } old_thread = startReaderLocked(key, track); @@ -250,11 +243,9 @@ void SubscriptionThreadDispatcher::handleTrackSubscribed( } } -void SubscriptionThreadDispatcher::handleTrackUnsubscribed( - const std::string &participant_identity, TrackSource source, - const std::string &track_name) { - const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, - track_name}; +void SubscriptionThreadDispatcher::handleTrackUnsubscribed(const std::string& participant_identity, TrackSource source, + const std::string& track_name) { + const CallbackKey key{participant_identity, TrackSource::SOURCE_UNKNOWN, track_name}; const CallbackKey fallback_key{participant_identity, source, ""}; std::thread old_thread; std::thread fallback_old_thread; @@ -262,10 +253,11 @@ void SubscriptionThreadDispatcher::handleTrackUnsubscribed( const std::scoped_lock lock(lock_); old_thread = extractReaderThreadLocked(key); fallback_old_thread = extractReaderThreadLocked(fallback_key); - LK_LOG_DEBUG("Handling unsubscribed track for participant={} source={} " - "track_name={} stopped_reader={} fallback_stopped_reader={}", - participant_identity, static_cast(source), track_name, - old_thread.joinable(), fallback_old_thread.joinable()); + LK_LOG_DEBUG( + "Handling unsubscribed track for participant={} source={} " + "track_name={} stopped_reader={} fallback_stopped_reader={}", + participant_identity, static_cast(source), track_name, old_thread.joinable(), + fallback_old_thread.joinable()); } if (old_thread.joinable()) { old_thread.join(); @@ -279,9 +271,9 @@ void SubscriptionThreadDispatcher::handleTrackUnsubscribed( // Data track callback registration // ------------------------------------------------------------------- -DataFrameCallbackId SubscriptionThreadDispatcher::addOnDataFrameCallback( - const std::string &participant_identity, const std::string &track_name, - DataFrameCallback callback) { +DataFrameCallbackId SubscriptionThreadDispatcher::addOnDataFrameCallback(const std::string& participant_identity, + const std::string& track_name, + DataFrameCallback callback) { std::thread old_thread; DataFrameCallbackId id; { @@ -292,8 +284,7 @@ DataFrameCallbackId SubscriptionThreadDispatcher::addOnDataFrameCallback( auto track_it = remote_data_tracks_.find(key); if (track_it != remote_data_tracks_.end()) { - old_thread = startDataReaderLocked(id, key, track_it->second, - data_callbacks_[id].callback); + old_thread = startDataReaderLocked(id, key, track_it->second, data_callbacks_[id].callback); } } if (old_thread.joinable()) { @@ -302,8 +293,7 @@ DataFrameCallbackId SubscriptionThreadDispatcher::addOnDataFrameCallback( return id; } -void SubscriptionThreadDispatcher::removeOnDataFrameCallback( - DataFrameCallbackId id) { +void SubscriptionThreadDispatcher::removeOnDataFrameCallback(DataFrameCallbackId id) { std::thread old_thread; { const std::scoped_lock lock(lock_); @@ -315,16 +305,14 @@ void SubscriptionThreadDispatcher::removeOnDataFrameCallback( } } -void SubscriptionThreadDispatcher::handleDataTrackPublished( - const std::shared_ptr &track) { +void SubscriptionThreadDispatcher::handleDataTrackPublished(const std::shared_ptr& track) { if (!track) { LK_LOG_WARN("handleDataTrackPublished called with null track"); return; } - LK_LOG_INFO("Handling data track published: \"{}\" from \"{}\" (sid={})", - track->info().name, track->publisherIdentity(), - track->info().sid); + LK_LOG_INFO("Handling data track published: \"{}\" from \"{}\" (sid={})", track->info().name, + track->publisherIdentity(), track->info().sid); std::vector old_threads; { @@ -332,7 +320,7 @@ void SubscriptionThreadDispatcher::handleDataTrackPublished( const DataCallbackKey key{track->publisherIdentity(), track->info().name}; remote_data_tracks_[key] = track; - for (auto &[id, reg] : data_callbacks_) { + for (auto& [id, reg] : data_callbacks_) { if (reg.key == key) { auto t = startDataReaderLocked(id, key, track, reg.callback); if (t.joinable()) { @@ -341,21 +329,19 @@ void SubscriptionThreadDispatcher::handleDataTrackPublished( } } } - for (auto &t : old_threads) { + for (auto& t : old_threads) { t.join(); } } -void SubscriptionThreadDispatcher::handleDataTrackUnpublished( - const std::string &sid) { +void SubscriptionThreadDispatcher::handleDataTrackUnpublished(const std::string& sid) { LK_LOG_INFO("Handling data track unpublished: sid={}", sid); std::vector old_threads; { const std::scoped_lock lock(lock_); - for (auto it = active_data_readers_.begin(); - it != active_data_readers_.end();) { - auto &reader = it->second; + for (auto it = active_data_readers_.begin(); it != active_data_readers_.end();) { + auto& reader = it->second; if (reader->remote_track && reader->remote_track->info().sid == sid) { { const std::scoped_lock sub_guard(reader->sub_mutex); @@ -371,15 +357,14 @@ void SubscriptionThreadDispatcher::handleDataTrackUnpublished( ++it; } } - for (auto it = remote_data_tracks_.begin(); it != remote_data_tracks_.end(); - ++it) { + for (auto it = remote_data_tracks_.begin(); it != remote_data_tracks_.end(); ++it) { if (it->second && it->second->info().sid == sid) { remote_data_tracks_.erase(it); break; } } } - for (auto &t : old_threads) { + for (auto& t : old_threads) { t.join(); } } @@ -388,14 +373,14 @@ void SubscriptionThreadDispatcher::stopAll() { std::vector threads; { const std::scoped_lock lock(lock_); - LK_LOG_DEBUG("Stopping all subscription readers active_readers={} " - "active_data_readers={} audio_callbacks={} " - "video_callbacks={} data_callbacks={}", - active_readers_.size(), active_data_readers_.size(), - audio_callbacks_.size(), video_callbacks_.size(), - data_callbacks_.size()); - - for (auto &[key, reader] : active_readers_) { + LK_LOG_DEBUG( + "Stopping all subscription readers active_readers={} " + "active_data_readers={} audio_callbacks={} " + "video_callbacks={} data_callbacks={}", + active_readers_.size(), active_data_readers_.size(), audio_callbacks_.size(), video_callbacks_.size(), + data_callbacks_.size()); + + for (auto& [key, reader] : active_readers_) { if (reader.audio_stream) { reader.audio_stream->close(); } @@ -410,7 +395,7 @@ void SubscriptionThreadDispatcher::stopAll() { audio_callbacks_.clear(); video_callbacks_.clear(); - for (auto &[id, reader] : active_data_readers_) { + for (auto& [id, reader] : active_data_readers_) { { const std::scoped_lock sub_guard(reader->sub_mutex); if (reader->stream) { @@ -425,27 +410,26 @@ void SubscriptionThreadDispatcher::stopAll() { data_callbacks_.clear(); remote_data_tracks_.clear(); } - for (auto &thread : threads) { + for (auto& thread : threads) { thread.join(); } LK_LOG_DEBUG("Stopped {} subscription reader threads", threads.size()); } -std::thread SubscriptionThreadDispatcher::extractReaderThreadLocked( - const CallbackKey &key) { +std::thread SubscriptionThreadDispatcher::extractReaderThreadLocked(const CallbackKey& key) { auto it = active_readers_.find(key); if (it == active_readers_.end()) { - LK_LOG_TRACE("No active reader to extract for participant={} source={} " - "track_name={}", - key.participant_identity, static_cast(key.source), - key.track_name); + LK_LOG_TRACE( + "No active reader to extract for participant={} source={} " + "track_name={}", + key.participant_identity, static_cast(key.source), key.track_name); return {}; } - LK_LOG_DEBUG("Extracting active reader for participant={} source={} " - "track_name={}", - key.participant_identity, static_cast(key.source), - key.track_name); + LK_LOG_DEBUG( + "Extracting active reader for participant={} source={} " + "track_name={}", + key.participant_identity, static_cast(key.source), key.track_name); ActiveReader reader = std::move(it->second); active_readers_.erase(it); @@ -458,25 +442,26 @@ std::thread SubscriptionThreadDispatcher::extractReaderThreadLocked( return std::move(reader.thread); } -std::thread SubscriptionThreadDispatcher::startReaderLocked( - const CallbackKey &key, const std::shared_ptr &track) { +std::thread SubscriptionThreadDispatcher::startReaderLocked(const CallbackKey& key, + const std::shared_ptr& track) { if (track->kind() == TrackKind::KIND_AUDIO) { auto it = audio_callbacks_.find(key); if (it == audio_callbacks_.end()) { - LK_LOG_TRACE("Skipping audio reader start for participant={} source={} " - "because no audio callback is registered", - key.participant_identity, static_cast(key.source)); + LK_LOG_TRACE( + "Skipping audio reader start for participant={} source={} " + "because no audio callback is registered", + key.participant_identity, static_cast(key.source)); return {}; } - return startAudioReaderLocked(key, track, it->second.callback, - it->second.options); + return startAudioReaderLocked(key, track, it->second.callback, it->second.options); } if (track->kind() == TrackKind::KIND_VIDEO) { auto it = video_callbacks_.find(key); if (it == video_callbacks_.end()) { - LK_LOG_TRACE("Skipping video reader start for participant={} source={} " - "because no video callback is registered", - key.participant_identity, static_cast(key.source)); + LK_LOG_TRACE( + "Skipping video reader start for participant={} source={} " + "because no video callback is registered", + key.participant_identity, static_cast(key.source)); return {}; } return startVideoReaderLocked(key, track, it->second); @@ -496,26 +481,26 @@ std::thread SubscriptionThreadDispatcher::startReaderLocked( return {}; } -std::thread SubscriptionThreadDispatcher::startAudioReaderLocked( - const CallbackKey &key, const std::shared_ptr &track, - const AudioFrameCallback &cb, const AudioStream::Options &opts) { - LK_LOG_DEBUG("Starting audio reader for participant={} source={}", - key.participant_identity, static_cast(key.source)); +std::thread SubscriptionThreadDispatcher::startAudioReaderLocked(const CallbackKey& key, + const std::shared_ptr& track, + const AudioFrameCallback& cb, + const AudioStream::Options& opts) { + LK_LOG_DEBUG("Starting audio reader for participant={} source={}", key.participant_identity, + static_cast(key.source)); auto old_thread = extractReaderThreadLocked(key); if (static_cast(active_readers_.size()) >= kMaxActiveReaders) { LK_LOG_ERROR( "Cannot start audio reader for {} source={}: active reader limit ({}) " "reached", - key.participant_identity, static_cast(key.source), - kMaxActiveReaders); + key.participant_identity, static_cast(key.source), kMaxActiveReaders); return old_thread; } const auto stream = AudioStream::fromTrack(track, opts); if (!stream) { - LK_LOG_ERROR("Failed to create AudioStream for {} source={}", - key.participant_identity, static_cast(key.source)); + LK_LOG_ERROR("Failed to create AudioStream for {} source={}", key.participant_identity, + static_cast(key.source)); return old_thread; } @@ -531,54 +516,52 @@ std::thread SubscriptionThreadDispatcher::startAudioReaderLocked( // fault, not application logic -- suppressed at the lambda level. reader.thread = std::thread([stream, cb, participant_identity, source]() { try { - LK_LOG_DEBUG("Audio reader thread started for participant={} source={}", - participant_identity, static_cast(source)); + LK_LOG_DEBUG("Audio reader thread started for participant={} source={}", participant_identity, + static_cast(source)); AudioFrameEvent ev; while (stream->read(ev)) { try { cb(ev.frame); - } catch (const std::exception &e) { + } catch (const std::exception& e) { LK_LOG_ERROR("Audio frame callback exception: {}", e.what()); } } - LK_LOG_DEBUG("Audio reader thread exiting for participant={} source={}", - participant_identity, static_cast(source)); - } catch (const std::exception &e) { - LK_LOG_ERROR("Audio reader thread terminating due to exception: {}", - e.what()); + LK_LOG_DEBUG("Audio reader thread exiting for participant={} source={}", participant_identity, + static_cast(source)); + } catch (const std::exception& e) { + LK_LOG_ERROR("Audio reader thread terminating due to exception: {}", e.what()); } catch (...) { LK_LOG_ERROR("Audio reader thread terminating due to unknown exception"); } }); // NOLINTEND(bugprone-lambda-function-name,bugprone-exception-escape) active_readers_[key] = std::move(reader); - LK_LOG_DEBUG("Started audio reader for participant={} source={} " - "active_readers={}", - key.participant_identity, static_cast(key.source), - active_readers_.size()); + LK_LOG_DEBUG( + "Started audio reader for participant={} source={} " + "active_readers={}", + key.participant_identity, static_cast(key.source), active_readers_.size()); return old_thread; } -std::thread SubscriptionThreadDispatcher::startVideoReaderLocked( - const CallbackKey &key, const std::shared_ptr &track, - const RegisteredVideoCallback &callback) { - LK_LOG_DEBUG("Starting video reader for participant={} source={}", - key.participant_identity, static_cast(key.source)); +std::thread SubscriptionThreadDispatcher::startVideoReaderLocked(const CallbackKey& key, + const std::shared_ptr& track, + const RegisteredVideoCallback& callback) { + LK_LOG_DEBUG("Starting video reader for participant={} source={}", key.participant_identity, + static_cast(key.source)); auto old_thread = extractReaderThreadLocked(key); if (static_cast(active_readers_.size()) >= kMaxActiveReaders) { LK_LOG_ERROR( "Cannot start video reader for {} source={}: active reader limit ({}) " "reached", - key.participant_identity, static_cast(key.source), - kMaxActiveReaders); + key.participant_identity, static_cast(key.source), kMaxActiveReaders); return old_thread; } auto stream = VideoStream::fromTrack(track, callback.options); if (!stream) { - LK_LOG_ERROR("Failed to create VideoStream for {} source={}", - key.participant_identity, static_cast(key.source)); + LK_LOG_ERROR("Failed to create VideoStream for {} source={}", key.participant_identity, + static_cast(key.source)); return old_thread; } @@ -592,11 +575,10 @@ std::thread SubscriptionThreadDispatcher::startVideoReaderLocked( // Mirrors the audio reader: outer try/catch contains escapes from // stream->read, LK_LOG, etc. Residual diagnostic from spdlog's own // formatter is an unrelated logger-fault path and is suppressed. - reader.thread = std::thread([stream = std::move(stream), legacy_cb, event_cb, - participant_identity, source]() { + reader.thread = std::thread([stream = std::move(stream), legacy_cb, event_cb, participant_identity, source]() { try { - LK_LOG_DEBUG("Video reader thread started for participant={} source={}", - participant_identity, static_cast(source)); + LK_LOG_DEBUG("Video reader thread started for participant={} source={}", participant_identity, + static_cast(source)); VideoFrameEvent ev; while (stream->read(ev)) { try { @@ -605,25 +587,24 @@ std::thread SubscriptionThreadDispatcher::startVideoReaderLocked( } else if (legacy_cb) { legacy_cb(ev.frame, ev.timestamp_us); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { LK_LOG_ERROR("Video frame callback exception: {}", e.what()); } } - LK_LOG_DEBUG("Video reader thread exiting for participant={} source={}", - participant_identity, static_cast(source)); - } catch (const std::exception &e) { - LK_LOG_ERROR("Video reader thread terminating due to exception: {}", - e.what()); + LK_LOG_DEBUG("Video reader thread exiting for participant={} source={}", participant_identity, + static_cast(source)); + } catch (const std::exception& e) { + LK_LOG_ERROR("Video reader thread terminating due to exception: {}", e.what()); } catch (...) { LK_LOG_ERROR("Video reader thread terminating due to unknown exception"); } }); // NOLINTEND(bugprone-lambda-function-name,bugprone-exception-escape) active_readers_[key] = std::move(reader); - LK_LOG_DEBUG("Started video reader for participant={} source={} " - "active_readers={}", - key.participant_identity, static_cast(key.source), - active_readers_.size()); + LK_LOG_DEBUG( + "Started video reader for participant={} source={} " + "active_readers={}", + key.participant_identity, static_cast(key.source), active_readers_.size()); return old_thread; } @@ -631,8 +612,7 @@ std::thread SubscriptionThreadDispatcher::startVideoReaderLocked( // Data track reader helpers // ------------------------------------------------------------------- -std::thread SubscriptionThreadDispatcher::extractDataReaderThreadLocked( - DataFrameCallbackId id) { +std::thread SubscriptionThreadDispatcher::extractDataReaderThreadLocked(DataFrameCallbackId id) { auto it = active_data_readers_.find(id); if (it == active_data_readers_.end()) { return {}; @@ -648,13 +628,10 @@ std::thread SubscriptionThreadDispatcher::extractDataReaderThreadLocked( return std::move(reader->thread); } -std::thread SubscriptionThreadDispatcher::extractDataReaderThreadLocked( - const DataCallbackKey &key) { - for (auto it = active_data_readers_.begin(); it != active_data_readers_.end(); - ++it) { +std::thread SubscriptionThreadDispatcher::extractDataReaderThreadLocked(const DataCallbackKey& key) { + for (auto it = active_data_readers_.begin(); it != active_data_readers_.end(); ++it) { if (it->second && it->second->remote_track && - it->second->remote_track->publisherIdentity() == - key.participant_identity && + it->second->remote_track->publisherIdentity() == key.participant_identity && it->second->remote_track->info().name == key.track_name) { auto reader = std::move(it->second); active_data_readers_.erase(it); @@ -670,23 +647,21 @@ std::thread SubscriptionThreadDispatcher::extractDataReaderThreadLocked( return {}; } -std::thread SubscriptionThreadDispatcher::startDataReaderLocked( - DataFrameCallbackId id, const DataCallbackKey &key, - const std::shared_ptr &track, - const DataFrameCallback &cb) { +std::thread SubscriptionThreadDispatcher::startDataReaderLocked(DataFrameCallbackId id, const DataCallbackKey& key, + const std::shared_ptr& track, + const DataFrameCallback& cb) { auto old_thread = extractDataReaderThreadLocked(id); - const int total_active = static_cast(active_readers_.size()) + - static_cast(active_data_readers_.size()); + const int total_active = static_cast(active_readers_.size()) + static_cast(active_data_readers_.size()); if (total_active >= kMaxActiveReaders) { - LK_LOG_ERROR("Cannot start data reader for {} track={}: active reader " - "limit ({}) reached", - key.participant_identity, key.track_name, kMaxActiveReaders); + LK_LOG_ERROR( + "Cannot start data reader for {} track={}: active reader " + "limit ({}) reached", + key.participant_identity, key.track_name, kMaxActiveReaders); return old_thread; } - LK_LOG_INFO("Starting data reader for \"{}\" track=\"{}\"", - key.participant_identity, key.track_name); + LK_LOG_INFO("Starting data reader for \"{}\" track=\"{}\"", key.participant_identity, key.track_name); auto reader = std::make_shared(); reader->remote_track = track; @@ -694,22 +669,19 @@ std::thread SubscriptionThreadDispatcher::startDataReaderLocked( auto track_name = key.track_name; // NOLINTBEGIN(bugprone-lambda-function-name) reader->thread = std::thread([reader, track, cb, identity, track_name]() { - LK_LOG_INFO("Data reader thread: subscribing to \"{}\" track=\"{}\"", - identity, track_name); + LK_LOG_INFO("Data reader thread: subscribing to \"{}\" track=\"{}\"", identity, track_name); std::shared_ptr stream; auto subscribe_result = track->subscribe(); if (!subscribe_result) { - const auto &error = subscribe_result.error(); + const auto& error = subscribe_result.error(); LK_LOG_ERROR( "Failed to subscribe to data track \"{}\" from \"{}\": code={} " "message={}", - track_name, identity, static_cast(error.code), - error.message); + track_name, identity, static_cast(error.code), error.message); return; } stream = subscribe_result.value(); - LK_LOG_INFO("Data reader thread: subscribed to \"{}\" track=\"{}\"", - identity, track_name); + LK_LOG_INFO("Data reader thread: subscribed to \"{}\" track=\"{}\"", identity, track_name); { const std::scoped_lock guard(reader->sub_mutex); @@ -720,12 +692,11 @@ std::thread SubscriptionThreadDispatcher::startDataReaderLocked( while (stream->read(frame)) { try { cb(frame.payload, frame.user_timestamp); - } catch (const std::exception &e) { + } catch (const std::exception& e) { LK_LOG_ERROR("Data frame callback exception: {}", e.what()); } } - LK_LOG_INFO("Data reader thread exiting for \"{}\" track=\"{}\"", identity, - track_name); + LK_LOG_INFO("Data reader thread exiting for \"{}\" track=\"{}\"", identity, track_name); }); // NOLINTEND(bugprone-lambda-function-name) active_data_readers_[id] = reader; diff --git a/src/trace/event_tracer.cpp b/src/trace/event_tracer.cpp index 9fbc959d..14522a24 100644 --- a/src/trace/event_tracer.cpp +++ b/src/trace/event_tracer.cpp @@ -15,7 +15,6 @@ */ #include "event_tracer.h" -#include "event_tracer_internal.h" #include #include @@ -31,6 +30,8 @@ #include #include +#include "event_tracer_internal.h" + #ifdef _WIN32 #include #else @@ -68,8 +69,7 @@ uint32_t GetCurrentThreadId() { uint64_t GetTimestampMicros() { auto now = std::chrono::steady_clock::now(); auto duration = now.time_since_epoch(); - return std::chrono::duration_cast(duration) - .count(); + return std::chrono::duration_cast(duration).count(); } // Internal trace event structure @@ -90,46 +90,44 @@ struct TraceEventData { }; // Escape a string for JSON -std::string JsonEscape(const std::string &s) { +std::string JsonEscape(const std::string& s) { std::ostringstream oss; for (const char c : s) { switch (c) { - case '"': - oss << "\\\""; - break; - case '\\': - oss << "\\\\"; - break; - case '\b': - oss << "\\b"; - break; - case '\f': - oss << "\\f"; - break; - case '\n': - oss << "\\n"; - break; - case '\r': - oss << "\\r"; - break; - case '\t': - oss << "\\t"; - break; - default: - if ('\x00' <= c && c <= '\x1f') { - oss << "\\u" << std::hex << std::setw(4) << std::setfill('0') - << static_cast(c); - } else { - oss << c; - } + case '"': + oss << "\\\""; + break; + case '\\': + oss << "\\\\"; + break; + case '\b': + oss << "\\b"; + break; + case '\f': + oss << "\\f"; + break; + case '\n': + oss << "\\n"; + break; + case '\r': + oss << "\\r"; + break; + case '\t': + oss << "\\t"; + break; + default: + if ('\x00' <= c && c <= '\x1f') { + oss << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast(c); + } else { + oss << c; + } } } return oss.str(); } // Convert argument value to JSON based on type -std::string ArgValueToJson(unsigned char type, uint64_t value, - const std::string &string_value) { +std::string ArgValueToJson(unsigned char type, uint64_t value, const std::string& string_value) { constexpr unsigned char TRACE_VALUE_TYPE_BOOL = 1; constexpr unsigned char TRACE_VALUE_TYPE_UINT = 2; constexpr unsigned char TRACE_VALUE_TYPE_INT = 3; @@ -140,40 +138,40 @@ std::string ArgValueToJson(unsigned char type, uint64_t value, std::ostringstream oss; switch (type) { - case TRACE_VALUE_TYPE_BOOL: - oss << (value ? "true" : "false"); - break; - case TRACE_VALUE_TYPE_UINT: - oss << value; - break; - case TRACE_VALUE_TYPE_INT: - oss << static_cast(value); - break; - case TRACE_VALUE_TYPE_DOUBLE: { - union { - uint64_t u; - double d; - } converter; - converter.u = value; - oss << std::setprecision(17) << converter.d; - break; - } - case TRACE_VALUE_TYPE_POINTER: - oss << "\"0x" << std::hex << value << "\""; - break; - case TRACE_VALUE_TYPE_STRING: - case TRACE_VALUE_TYPE_COPY_STRING: - oss << "\"" << JsonEscape(string_value) << "\""; - break; - default: - oss << value; - break; + case TRACE_VALUE_TYPE_BOOL: + oss << (value ? "true" : "false"); + break; + case TRACE_VALUE_TYPE_UINT: + oss << value; + break; + case TRACE_VALUE_TYPE_INT: + oss << static_cast(value); + break; + case TRACE_VALUE_TYPE_DOUBLE: { + union { + uint64_t u; + double d; + } converter; + converter.u = value; + oss << std::setprecision(17) << converter.d; + break; + } + case TRACE_VALUE_TYPE_POINTER: + oss << "\"0x" << std::hex << value << "\""; + break; + case TRACE_VALUE_TYPE_STRING: + case TRACE_VALUE_TYPE_COPY_STRING: + oss << "\"" << JsonEscape(string_value) << "\""; + break; + default: + oss << value; + break; } return oss.str(); } // Format a single event as JSON -std::string FormatEventJson(const TraceEventData &event, uint64_t start_time) { +std::string FormatEventJson(const TraceEventData& event, uint64_t start_time) { std::ostringstream oss; oss << "{"; oss << R"("ph":")" << event.phase << "\","; @@ -190,11 +188,11 @@ std::string FormatEventJson(const TraceEventData &event, uint64_t start_time) { if (event.num_args > 0) { oss << ",\"args\":{"; for (int i = 0; i < event.num_args && i < 2; ++i) { - if (i > 0) + if (i > 0) { oss << ","; + } oss << "\"" << JsonEscape(event.arg_names[i]) << "\":"; - oss << ArgValueToJson(event.arg_types[i], event.arg_values[i], - event.arg_string_values[i]); + oss << ArgValueToJson(event.arg_types[i], event.arg_values[i], event.arg_string_values[i]); } oss << "}"; } @@ -234,9 +232,7 @@ void WriterThreadFunc() { // Wait for events or shutdown { std::unique_lock lock(g_mutex); - g_cv.wait(lock, [] { - return !g_event_queue.empty() || g_shutdown_requested.load(); - }); + g_cv.wait(lock, [] { return !g_event_queue.empty() || g_shutdown_requested.load(); }); // Drain the queue into a local batch while (!g_event_queue.empty()) { @@ -246,7 +242,7 @@ void WriterThreadFunc() { } // Write batch to file (outside the lock) - for (const auto &event : batch) { + for (const auto& event : batch) { if (g_trace_file.is_open()) { if (!g_first_event) { g_trace_file << ","; @@ -269,14 +265,13 @@ void WriterThreadFunc() { } // namespace -void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, - AddTraceEventPtr add_trace_event_ptr) { +void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, AddTraceEventPtr add_trace_event_ptr) { const std::scoped_lock lock(g_mutex); g_custom_get_category_enabled = get_category_enabled_ptr; g_custom_add_trace_event = add_trace_event_ptr; } -const unsigned char *EventTracer::GetCategoryEnabled(const char *name) { +const unsigned char* EventTracer::GetCategoryEnabled(const char* name) { // If custom tracer is set, use it if (g_custom_get_category_enabled) { return g_custom_get_category_enabled(name); @@ -302,7 +297,7 @@ const unsigned char *EventTracer::GetCategoryEnabled(const char *name) { } // Check for wildcard matches (e.g., "livekit.*" matches "livekit.connect") - for (const auto &pattern : g_enabled_categories) { + for (const auto& pattern : g_enabled_categories) { if (pattern.back() == '*') { const std::string prefix = pattern.substr(0, pattern.size() - 1); if (category_name.compare(0, prefix.size(), prefix) == 0) { @@ -314,17 +309,13 @@ const unsigned char *EventTracer::GetCategoryEnabled(const char *name) { return &g_disabled_byte; } -void EventTracer::AddTraceEvent(char phase, - const unsigned char *category_enabled, - const char *name, unsigned long long id, - int num_args, const char **arg_names, - const unsigned char *arg_types, - const unsigned long long *arg_values, +void EventTracer::AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, + unsigned long long id, int num_args, const char** arg_names, + const unsigned char* arg_types, const unsigned long long* arg_values, unsigned char flags) { // If custom tracer is set, use it if (g_custom_add_trace_event) { - g_custom_add_trace_event(phase, category_enabled, name, id, num_args, - arg_names, arg_types, arg_values, flags); + g_custom_add_trace_event(phase, category_enabled, name, id, num_args, arg_names, arg_types, arg_values, flags); return; } @@ -358,7 +349,7 @@ void EventTracer::AddTraceEvent(char phase, // Handle string arguments if (arg_types && (arg_types[i] == 6 || arg_types[i] == 7)) { // NOLINTNEXTLINE(performance-no-int-to-ptr) - const char *str_val = reinterpret_cast(arg_values[i]); + const char* str_val = reinterpret_cast(arg_values[i]); if (str_val) { event.arg_string_values[i] = str_val; } @@ -376,8 +367,7 @@ void EventTracer::AddTraceEvent(char phase, namespace internal { -bool StartTracing(const std::string &file_path, - const std::vector &categories) { +bool StartTracing(const std::string& file_path, const std::vector& categories) { const std::scoped_lock lock(g_mutex); // Don't start if already running @@ -400,7 +390,7 @@ bool StartTracing(const std::string &file_path, // Set enabled categories g_enabled_categories.clear(); - for (const auto &cat : categories) { + for (const auto& cat : categories) { g_enabled_categories.insert(cat); } @@ -438,9 +428,7 @@ void StopTracing() { g_enabled_categories.clear(); } -bool IsTracingEnabled() { - return g_tracing_enabled.load(std::memory_order_acquire); -} +bool IsTracingEnabled() { return g_tracing_enabled.load(std::memory_order_acquire); } } // namespace internal diff --git a/src/trace/event_tracer.h b/src/trace/event_tracer.h index 181abf22..2bb93e82 100644 --- a/src/trace/event_tracer.h +++ b/src/trace/event_tracer.h @@ -53,35 +53,28 @@ namespace livekit { namespace trace { -typedef const unsigned char *(*GetCategoryEnabledPtr)(const char *name); -typedef void (*AddTraceEventPtr)(char phase, - const unsigned char *category_enabled, - const char *name, unsigned long long id, - int num_args, const char **arg_names, - const unsigned char *arg_types, - const unsigned long long *arg_values, +typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name); +typedef void (*AddTraceEventPtr)(char phase, const unsigned char* category_enabled, const char* name, + unsigned long long id, int num_args, const char** arg_names, + const unsigned char* arg_types, const unsigned long long* arg_values, unsigned char flags); // User of LiveKit SDK can call this method to setup custom event tracing. // // This method must be called before any tracing begins. Functions // provided should be thread-safe. -LIVEKIT_EXPORT void -SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, - AddTraceEventPtr add_trace_event_ptr); +LIVEKIT_EXPORT void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, + AddTraceEventPtr add_trace_event_ptr); // This class defines interface for the event tracing system to call // internally. Do not call these methods directly. class EventTracer { public: - static const unsigned char *GetCategoryEnabled(const char *name); + static const unsigned char* GetCategoryEnabled(const char* name); - static void AddTraceEvent(char phase, const unsigned char *category_enabled, - const char *name, unsigned long long id, - int num_args, const char **arg_names, - const unsigned char *arg_types, - const unsigned long long *arg_values, - unsigned char flags); + static void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, + int num_args, const char** arg_names, const unsigned char* arg_types, + const unsigned long long* arg_values, unsigned char flags); }; } // namespace trace diff --git a/src/trace/event_tracer_internal.h b/src/trace/event_tracer_internal.h index e01d76b3..1eff80b6 100644 --- a/src/trace/event_tracer_internal.h +++ b/src/trace/event_tracer_internal.h @@ -34,8 +34,7 @@ namespace livekit::trace::internal { * @return true if tracing started successfully, false if already running or * file error */ -bool StartTracing(const std::string &file_path, - const std::vector &categories); +bool StartTracing(const std::string& file_path, const std::vector& categories); /** * Stop tracing and flush all pending events. diff --git a/src/trace/trace_event.h b/src/trace/trace_event.h index 6944ba16..bc1bb57d 100644 --- a/src/trace/trace_event.h +++ b/src/trace/trace_event.h @@ -24,9 +24,10 @@ #ifndef LIVEKIT_TRACE_TRACE_EVENT_H_ #define LIVEKIT_TRACE_TRACE_EVENT_H_ -#include "event_tracer.h" #include #include + +#include "event_tracer.h" #if defined(TRACE_EVENT0) #error "Another copy of trace_event.h has already been included." #endif @@ -156,50 +157,37 @@ // for details. // By default, const char* argument values are assumed to have long-lived scope // and will not be copied. Use this macro to force a const char* to be copied. -#define TRACE_STR_COPY(str) \ - webrtc::trace_event_internal::TraceStringWithCopy(str) +#define TRACE_STR_COPY(str) webrtc::trace_event_internal::TraceStringWithCopy(str) // By default, uint64 ID argument values are not mangled with the Process ID in // TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling. -#define TRACE_ID_MANGLE(id) \ - webrtc::trace_event_internal::TraceID::ForceMangle(id) +#define TRACE_ID_MANGLE(id) webrtc::trace_event_internal::TraceID::ForceMangle(id) // Records a pair of begin and end events called "name" for the current // scope, with 0, 1 or 2 associated arguments. If the category is not // enabled, then this does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. -#define TRACE_EVENT0(category, name) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name) -#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ +#define TRACE_EVENT0(category, name) INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name) +#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val) #define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, arg2_name, arg2_val) // Same as TRACE_EVENT except that they are not included in official builds. #ifdef OFFICIAL_BUILD #define UNSHIPPED_TRACE_EVENT0(category, name) (void)0 #define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) (void)0 -#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - (void)0 +#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) (void)0 #define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) (void)0 -#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ - (void)0 -#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - (void)0 +#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) (void)0 +#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) (void)0 #else #define UNSHIPPED_TRACE_EVENT0(category, name) TRACE_EVENT0(category, name) -#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) \ - TRACE_EVENT1(category, name, arg1_name, arg1_val) -#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ +#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) TRACE_EVENT1(category, name, arg1_name, arg1_val) +#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) -#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) \ - TRACE_EVENT_INSTANT0(category, name) -#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ +#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) TRACE_EVENT_INSTANT0(category, name) +#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) -#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ +#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) #endif // Records a single event called "name" immediately, with 0, 1 or 2 @@ -207,110 +195,78 @@ // does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. -#define TRACE_EVENT_INSTANT0(category, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ +#define TRACE_EVENT_INSTANT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ arg2_name, arg2_val) -#define TRACE_EVENT_COPY_INSTANT0(category, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, \ - TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ +#define TRACE_EVENT_COPY_INSTANT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records a single BEGIN event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this // does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. -#define TRACE_EVENT_BEGIN0(category, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ +#define TRACE_EVENT_BEGIN0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ arg2_name, arg2_val) -#define TRACE_EVENT_COPY_BEGIN0(category, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, \ - TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ +#define TRACE_EVENT_COPY_BEGIN0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records a single END event for "name" immediately. If the category // is not enabled, then this does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. -#define TRACE_EVENT_END0(category, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ +#define TRACE_EVENT_END0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ arg2_name, arg2_val) -#define TRACE_EVENT_COPY_END0(category, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, \ - TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ +#define TRACE_EVENT_COPY_END0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records the value of a counter called "name" immediately. Value // must be representable as a 32 bit integer. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. -#define TRACE_COUNTER1(category, name, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, \ - TRACE_EVENT_FLAG_NONE, "value", \ +#define TRACE_COUNTER1(category, name, value) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, TRACE_EVENT_FLAG_NONE, "value", \ static_cast(value)) -#define TRACE_COPY_COUNTER1(category, name, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, \ - TRACE_EVENT_FLAG_COPY, "value", \ +#define TRACE_COPY_COUNTER1(category, name, value) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, TRACE_EVENT_FLAG_COPY, "value", \ static_cast(value)) // Records the values of a multi-parted counter called "name" immediately. // The UI will treat value1 and value2 as parts of a whole, displaying their // values as a stacked-bar chart. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. -#define TRACE_COUNTER2(category, name, value1_name, value1_val, value2_name, \ - value2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, \ - TRACE_EVENT_FLAG_NONE, value1_name, \ - static_cast(value1_val), value2_name, \ - static_cast(value2_val)) -#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, \ - TRACE_EVENT_FLAG_COPY, value1_name, \ - static_cast(value1_val), value2_name, \ - static_cast(value2_val)) +#define TRACE_COUNTER2(category, name, value1_name, value1_val, value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, TRACE_EVENT_FLAG_NONE, value1_name, \ + static_cast(value1_val), value2_name, static_cast(value2_val)) +#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category, name, TRACE_EVENT_FLAG_COPY, value1_name, \ + static_cast(value1_val), value2_name, static_cast(value2_val)) // Records the value of a counter called "name" immediately. Value // must be representable as a 32 bit integer. // - category and name strings must have application lifetime (statics or @@ -319,13 +275,11 @@ // be a pointer or an integer value up to 64 bits. If it's a pointer, the bits // will be xored with a hash of the process ID so that the same pointer on // two different processes will not collide. -#define TRACE_COUNTER_ID1(category, name, id, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, \ - id, TRACE_EVENT_FLAG_NONE, "value", \ +#define TRACE_COUNTER_ID1(category, name, id, value) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, id, TRACE_EVENT_FLAG_NONE, "value", \ static_cast(value)) -#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, \ - id, TRACE_EVENT_FLAG_COPY, "value", \ +#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, id, TRACE_EVENT_FLAG_COPY, "value", \ static_cast(value)) // Records the values of a multi-parted counter called "name" immediately. // The UI will treat value1 and value2 as parts of a whole, displaying their @@ -336,18 +290,12 @@ // be a pointer or an integer value up to 64 bits. If it's a pointer, the bits // will be xored with a hash of the process ID so that the same pointer on // two different processes will not collide. -#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, \ - id, TRACE_EVENT_FLAG_NONE, value1_name, \ - static_cast(value1_val), value2_name, \ - static_cast(value2_val)) -#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, \ - id, TRACE_EVENT_FLAG_COPY, value1_name, \ - static_cast(value1_val), value2_name, \ - static_cast(value2_val)) +#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, id, TRACE_EVENT_FLAG_NONE, value1_name, \ + static_cast(value1_val), value2_name, static_cast(value2_val)) +#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category, name, id, TRACE_EVENT_FLAG_COPY, value1_name, \ + static_cast(value1_val), value2_name, static_cast(value2_val)) // Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this // does nothing. @@ -365,77 +313,56 @@ // drawn on the thread defined in the ASYNC_BEGIN event), but all events in that // operation must use the same |name| and |id|. Each event can have its own // args. -#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ - arg1_val) -#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ - arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ - arg1_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ - arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val) +#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) // Records a single ASYNC_STEP event for |step| immediately. If the category // is not enabled, then this does nothing. The |name| and |id| must match the // ASYNC_BEGIN event above. The |step| param identifies this step within the // async event. This should be called at the beginning of the next phase of an // asynchronous operation. -#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, \ - name, id, TRACE_EVENT_FLAG_NONE, "step", \ +#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, name, id, TRACE_EVENT_FLAG_NONE, "step", \ step) -#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, \ - name, id, TRACE_EVENT_FLAG_NONE, "step", \ +#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, name, id, TRACE_EVENT_FLAG_NONE, "step", \ step, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, \ - name, id, TRACE_EVENT_FLAG_COPY, "step", \ +#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, name, id, TRACE_EVENT_FLAG_COPY, "step", \ step) -#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, \ - name, id, TRACE_EVENT_FLAG_COPY, "step", \ +#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, category, name, id, TRACE_EVENT_FLAG_COPY, "step", \ step, arg1_name, arg1_val) // Records a single ASYNC_END event for "name" immediately. If the category // is not enabled, then this does nothing. -#define TRACE_EVENT_ASYNC_END0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, \ - name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ +#define TRACE_EVENT_ASYNC_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ arg1_val) -#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ +#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, \ - name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ +#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ arg1_val) -#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ +#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, category, name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ arg1_val, arg2_name, arg2_val) // Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this @@ -456,77 +383,54 @@ // macros. When the operation completes, call FLOW_END. An async operation can // span threads and processes, but all events in that operation must use the // same |name| and |id|. Each event can have its own args. -#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ +#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ arg1_val) -#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ +#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ +#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ arg1_val) -#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ +#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ arg1_val, arg2_name, arg2_val) // Records a single FLOW_STEP event for |step| immediately. If the category // is not enabled, then this does nothing. The |name| and |id| must match the // FLOW_BEGIN event above. The |step| param identifies this step within the // async event. This should be called at the beginning of the next phase of an // asynchronous operation. -#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ - name, id, TRACE_EVENT_FLAG_NONE, "step", \ - step) -#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ - name, id, TRACE_EVENT_FLAG_NONE, "step", \ +#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) +#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, name, id, TRACE_EVENT_FLAG_NONE, "step", \ step, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ - name, id, TRACE_EVENT_FLAG_COPY, "step", \ - step) -#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ - name, id, TRACE_EVENT_FLAG_COPY, "step", \ +#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) +#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, name, id, TRACE_EVENT_FLAG_COPY, "step", \ step, arg1_name, arg1_val) // Records a single FLOW_END event for "name" immediately. If the category // is not enabled, then this does nothing. -#define TRACE_EVENT_FLOW_END0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ - id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ - id, TRACE_EVENT_FLAG_NONE, arg1_name, \ +#define TRACE_EVENT_FLOW_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ arg1_val) -#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ - id, TRACE_EVENT_FLAG_NONE, arg1_name, \ +#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ - id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ - id, TRACE_EVENT_FLAG_COPY, arg1_name, \ +#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ arg1_val) -#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ - id, TRACE_EVENT_FLAG_COPY, arg1_name, \ +#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ arg1_val, arg2_name, arg2_val) //////////////////////////////////////////////////////////////////////////////// // Implementation specific tracing API definitions. @@ -540,8 +444,7 @@ // for best performance when tracing is disabled. // const unsigned char* // TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name) -#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \ - webrtc::EventTracer::GetCategoryEnabled +#define TRACE_EVENT_API_GET_CATEGORY_ENABLED webrtc::EventTracer::GetCategoryEnabled // Add a trace event to the platform tracing system. // void TRACE_EVENT_API_ADD_TRACE_EVENT( // char phase, @@ -560,55 +463,46 @@ // variable a unique name based on the line number to prevent name collissions. #define INTERNAL_TRACE_EVENT_UID3(a, b) trace_event_unique_##a##b #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b) -#define INTERNAL_TRACE_EVENT_UID(name_prefix) \ - INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) +#define INTERNAL_TRACE_EVENT_UID(name_prefix) INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) // Implementation detail: internal macro to create static category. -#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \ - static const unsigned char *INTERNAL_TRACE_EVENT_UID(catstatic) = 0; \ - if (!INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - INTERNAL_TRACE_EVENT_UID(catstatic) = \ - TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); \ +#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \ + static const unsigned char* INTERNAL_TRACE_EVENT_UID(catstatic) = 0; \ + if (!INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + INTERNAL_TRACE_EVENT_UID(catstatic) = TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); \ } // Implementation detail: internal macro to create static category and add // event if the category is enabled. -#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - webrtc::trace_event_internal::AddTraceEvent( \ - phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ - webrtc::trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \ - } \ +#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + webrtc::trace_event_internal::AddTraceEvent(phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ + webrtc::trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \ + } \ } while (0) // Implementation detail: internal macro to create static category and add begin // event if the category is enabled. Also adds the end event when the scope // ends. -#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ - webrtc::trace_event_internal::TraceEndOnScopeClose INTERNAL_TRACE_EVENT_UID( \ - profileScope); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - webrtc::trace_event_internal::AddTraceEvent( \ - TRACE_EVENT_PHASE_BEGIN, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ - webrtc::trace_event_internal::kNoEventId, TRACE_EVENT_FLAG_NONE, \ - ##__VA_ARGS__); \ - INTERNAL_TRACE_EVENT_UID(profileScope) \ - .Initialize(INTERNAL_TRACE_EVENT_UID(catstatic), name); \ +#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + webrtc::trace_event_internal::TraceEndOnScopeClose INTERNAL_TRACE_EVENT_UID(profileScope); \ + if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + webrtc::trace_event_internal::AddTraceEvent(TRACE_EVENT_PHASE_BEGIN, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ + webrtc::trace_event_internal::kNoEventId, TRACE_EVENT_FLAG_NONE, \ + ##__VA_ARGS__); \ + INTERNAL_TRACE_EVENT_UID(profileScope).Initialize(INTERNAL_TRACE_EVENT_UID(catstatic), name); \ } // Implementation detail: internal macro to create static category and add // event if the category is enabled. -#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \ - ...) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ - webrtc::trace_event_internal::TraceID trace_event_trace_id( \ - id, &trace_event_flags); \ - webrtc::trace_event_internal::AddTraceEvent( \ - phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ - trace_event_trace_id.data(), trace_event_flags, ##__VA_ARGS__); \ - } \ +#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ + webrtc::trace_event_internal::TraceID trace_event_trace_id(id, &trace_event_flags); \ + webrtc::trace_event_internal::AddTraceEvent(phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ + trace_event_trace_id.data(), trace_event_flags, ##__VA_ARGS__); \ + } \ } while (0) // Notes regarding the following definitions: // New values can be added and propagated to third party libraries, but existing @@ -657,63 +551,31 @@ class TraceID { explicit ForceMangle(unsigned int id) : data_(id) {} explicit ForceMangle(unsigned short id) : data_(id) {} explicit ForceMangle(unsigned char id) : data_(id) {} - explicit ForceMangle(long long id) - : data_(static_cast(id)) {} - explicit ForceMangle(long id) - : data_(static_cast(id)) {} + explicit ForceMangle(long long id) : data_(static_cast(id)) {} + explicit ForceMangle(long id) : data_(static_cast(id)) {} explicit ForceMangle(int id) : data_(static_cast(id)) {} - explicit ForceMangle(short id) - : data_(static_cast(id)) {} - explicit ForceMangle(signed char id) - : data_(static_cast(id)) {} + explicit ForceMangle(short id) : data_(static_cast(id)) {} + explicit ForceMangle(signed char id) : data_(static_cast(id)) {} unsigned long long data() const { return data_; } private: unsigned long long data_; }; - explicit TraceID(const void *id, unsigned char *flags) - : data_(static_cast( - reinterpret_cast(id))) { - *flags |= TRACE_EVENT_FLAG_MANGLE_ID; - } - explicit TraceID(ForceMangle id, unsigned char *flags) : data_(id.data()) { + explicit TraceID(const void* id, unsigned char* flags) + : data_(static_cast(reinterpret_cast(id))) { *flags |= TRACE_EVENT_FLAG_MANGLE_ID; } - explicit TraceID(unsigned long long id, unsigned char *flags) : data_(id) { - (void)flags; - } - explicit TraceID(unsigned long id, unsigned char *flags) : data_(id) { - (void)flags; - } - explicit TraceID(unsigned int id, unsigned char *flags) : data_(id) { - (void)flags; - } - explicit TraceID(unsigned short id, unsigned char *flags) : data_(id) { - (void)flags; - } - explicit TraceID(unsigned char id, unsigned char *flags) : data_(id) { - (void)flags; - } - explicit TraceID(long long id, unsigned char *flags) - : data_(static_cast(id)) { - (void)flags; - } - explicit TraceID(long id, unsigned char *flags) - : data_(static_cast(id)) { - (void)flags; - } - explicit TraceID(int id, unsigned char *flags) - : data_(static_cast(id)) { - (void)flags; - } - explicit TraceID(short id, unsigned char *flags) - : data_(static_cast(id)) { - (void)flags; - } - explicit TraceID(signed char id, unsigned char *flags) - : data_(static_cast(id)) { - (void)flags; - } + explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) { *flags |= TRACE_EVENT_FLAG_MANGLE_ID; } + explicit TraceID(unsigned long long id, unsigned char* flags) : data_(id) { (void)flags; } + explicit TraceID(unsigned long id, unsigned char* flags) : data_(id) { (void)flags; } + explicit TraceID(unsigned int id, unsigned char* flags) : data_(id) { (void)flags; } + explicit TraceID(unsigned short id, unsigned char* flags) : data_(id) { (void)flags; } + explicit TraceID(unsigned char id, unsigned char* flags) : data_(id) { (void)flags; } + explicit TraceID(long long id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } + explicit TraceID(long id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } + explicit TraceID(int id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } + explicit TraceID(short id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } + explicit TraceID(signed char id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } unsigned long long data() const { return data_; } private: @@ -725,36 +587,33 @@ union TraceValueUnion { unsigned long long as_uint; long long as_int; double as_double; - const void *as_pointer; - const char *as_string; + const void* as_pointer; + const char* as_string; }; // Simple container for const char* that should be copied instead of retained. class TraceStringWithCopy { public: - explicit TraceStringWithCopy(const char *str) : str_(str) {} - operator const char *() const { return str_; } + explicit TraceStringWithCopy(const char* str) : str_(str) {} + operator const char*() const { return str_; } private: - const char *str_; + const char* str_; }; // Define SetTraceValue for each allowed type. It stores the type and // value in the return arguments. This allows this API to avoid declaring any // structures so that it is portable to third_party libraries. -#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, union_member, \ - value_type_id) \ - static inline void SetTraceValue(actual_type arg, unsigned char *type, \ - unsigned long long *value) { \ - TraceValueUnion type_value; \ - type_value.union_member = arg; \ - *type = value_type_id; \ - *value = type_value.as_uint; \ +#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, union_member, value_type_id) \ + static inline void SetTraceValue(actual_type arg, unsigned char* type, unsigned long long* value) { \ + TraceValueUnion type_value; \ + type_value.union_member = arg; \ + *type = value_type_id; \ + *value = type_value.as_uint; \ } // Simpler form for int types that can be safely casted. -#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, value_type_id) \ - static inline void SetTraceValue(actual_type arg, unsigned char *type, \ - unsigned long long *value) { \ - *type = value_type_id; \ - *value = static_cast(arg); \ +#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, value_type_id) \ + static inline void SetTraceValue(actual_type arg, unsigned char* type, unsigned long long* value) { \ + *type = value_type_id; \ + *value = static_cast(arg); \ } INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT) @@ -768,17 +627,13 @@ INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) -INTERNAL_DECLARE_SET_TRACE_VALUE(const void *, as_pointer, - TRACE_VALUE_TYPE_POINTER) -INTERNAL_DECLARE_SET_TRACE_VALUE(const char *, as_string, - TRACE_VALUE_TYPE_STRING) -INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy &, as_string, - TRACE_VALUE_TYPE_COPY_STRING) +INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, TRACE_VALUE_TYPE_POINTER) +INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, TRACE_VALUE_TYPE_STRING) +INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string, TRACE_VALUE_TYPE_COPY_STRING) #undef INTERNAL_DECLARE_SET_TRACE_VALUE #undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT // std::string version of SetTraceValue so that trace arguments can be strings. -static inline void SetTraceValue(const std::string &arg, unsigned char *type, - unsigned long long *value) { +static inline void SetTraceValue(const std::string& arg, unsigned char* type, unsigned long long* value) { TraceValueUnion type_value; type_value.as_string = arg.c_str(); *type = TRACE_VALUE_TYPE_COPY_STRING; @@ -789,39 +644,32 @@ static inline void SetTraceValue(const std::string &arg, unsigned char *type, // std::string. In order to store pointers to the internal c_str and pass // through to the tracing API, the arg_values must live throughout // these procedures. -static inline void AddTraceEvent(char phase, - const unsigned char *category_enabled, - const char *name, unsigned long long id, - unsigned char flags) { - TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, - kZeroNumArgs, NULL, NULL, NULL, flags); +static inline void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, + unsigned long long id, unsigned char flags) { + TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, kZeroNumArgs, NULL, NULL, NULL, flags); } template -static inline void -AddTraceEvent(char phase, const unsigned char *category_enabled, - const char *name, unsigned long long id, unsigned char flags, - const char *arg1_name, const ARG1_TYPE &arg1_val) { +static inline void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, + unsigned long long id, unsigned char flags, const char* arg1_name, + const ARG1_TYPE& arg1_val) { const int num_args = 1; unsigned char arg_types[1]; unsigned long long arg_values[1]; SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); - TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, num_args, - &arg1_name, arg_types, arg_values, flags); + TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, num_args, &arg1_name, arg_types, arg_values, + flags); } template -static inline void -AddTraceEvent(char phase, const unsigned char *category_enabled, - const char *name, unsigned long long id, unsigned char flags, - const char *arg1_name, const ARG1_TYPE &arg1_val, - const char *arg2_name, const ARG2_TYPE &arg2_val) { +static inline void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, + unsigned long long id, unsigned char flags, const char* arg1_name, + const ARG1_TYPE& arg1_val, const char* arg2_name, const ARG2_TYPE& arg2_val) { const int num_args = 2; - const char *arg_names[2] = {arg1_name, arg2_name}; + const char* arg_names[2] = {arg1_name, arg2_name}; unsigned char arg_types[2]; unsigned long long arg_values[2]; SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); - TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, num_args, - arg_names, arg_types, arg_values, flags); + TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, num_args, arg_names, arg_types, arg_values, flags); } // Used by TRACE_EVENTx macro. Do not use directly. class TraceEndOnScopeClose { @@ -829,10 +677,11 @@ class TraceEndOnScopeClose { // Note: members of data_ intentionally left uninitialized. See Initialize. TraceEndOnScopeClose() : p_data_(NULL) {} ~TraceEndOnScopeClose() { - if (p_data_) + if (p_data_) { AddEventIfEnabled(); + } } - void Initialize(const unsigned char *category_enabled, const char *name) { + void Initialize(const unsigned char* category_enabled, const char* name) { data_.category_enabled = category_enabled; data_.name = name; p_data_ = &data_; @@ -843,9 +692,8 @@ class TraceEndOnScopeClose { void AddEventIfEnabled() { // Only called when p_data_ is non-null. if (*p_data_->category_enabled) { - TRACE_EVENT_API_ADD_TRACE_EVENT( - TRACE_EVENT_PHASE_END, p_data_->category_enabled, p_data_->name, - kNoEventId, kZeroNumArgs, NULL, NULL, NULL, TRACE_EVENT_FLAG_NONE); + TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, p_data_->category_enabled, p_data_->name, kNoEventId, + kZeroNumArgs, NULL, NULL, NULL, TRACE_EVENT_FLAG_NONE); } } // This Data struct workaround is to avoid initializing all the members @@ -854,10 +702,10 @@ class TraceEndOnScopeClose { // members of this class instead, compiler warnings occur about potential // uninitialized accesses. struct Data { - const unsigned char *category_enabled; - const char *name; + const unsigned char* category_enabled; + const char* name; }; - Data *p_data_; + Data* p_data_; Data data_; }; } // namespace trace_event_internal diff --git a/src/trace/tracing.cpp b/src/trace/tracing.cpp index a753e2bf..4c2af2bc 100644 --- a/src/trace/tracing.cpp +++ b/src/trace/tracing.cpp @@ -15,12 +15,12 @@ */ #include "livekit/tracing.h" + #include "trace/event_tracer_internal.h" namespace livekit { -bool startTracing(const std::string &trace_file_path, - const std::vector &categories) { +bool startTracing(const std::string& trace_file_path, const std::vector& categories) { return trace::internal::StartTracing(trace_file_path, categories); } diff --git a/src/track.cpp b/src/track.cpp index 2dd403d9..d223ba76 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -16,21 +16,25 @@ #include "livekit/track.h" -#include "ffi_client.h" #include #include -namespace livekit { +#include "ffi_client.h" -Track::Track(FfiHandle handle, std::string sid, std::string name, - TrackKind kind, StreamState state, bool muted, bool remote) - : handle_(std::move(handle)), sid_(std::move(sid)), name_(std::move(name)), - kind_(kind), state_(state), muted_(muted), remote_(remote) {} +namespace livekit { -void Track::setPublicationFields(std::optional source, - std::optional simulcasted, - std::optional width, - std::optional height, +Track::Track(FfiHandle handle, std::string sid, std::string name, TrackKind kind, StreamState state, bool muted, + bool remote) + : handle_(std::move(handle)), + sid_(std::move(sid)), + name_(std::move(name)), + kind_(kind), + state_(state), + muted_(muted), + remote_(remote) {} + +void Track::setPublicationFields(std::optional source, std::optional simulcasted, + std::optional width, std::optional height, std::optional mime_type) { source_ = source; simulcasted_ = simulcasted; diff --git a/src/track_proto_converter.cpp b/src/track_proto_converter.cpp index d95b8568..567cd68b 100644 --- a/src/track_proto_converter.cpp +++ b/src/track_proto_converter.cpp @@ -20,21 +20,19 @@ namespace livekit { -proto::ParticipantTrackPermission -toProto(const ParticipantTrackPermission &in) { +proto::ParticipantTrackPermission toProto(const ParticipantTrackPermission& in) { proto::ParticipantTrackPermission out; out.set_participant_identity(in.participant_identity); if (in.allow_all.has_value()) { out.set_allow_all(*in.allow_all); } - for (const auto &sid : in.allowed_track_sids) { + for (const auto& sid : in.allowed_track_sids) { out.add_allowed_track_sids(sid); } return out; } -ParticipantTrackPermission -fromProto(const proto::ParticipantTrackPermission &in) { +ParticipantTrackPermission fromProto(const proto::ParticipantTrackPermission& in) { ParticipantTrackPermission out; out.participant_identity = in.participant_identity(); if (in.has_allow_all()) { @@ -43,7 +41,7 @@ fromProto(const proto::ParticipantTrackPermission &in) { out.allow_all = std::nullopt; } out.allowed_track_sids.reserve(in.allowed_track_sids_size()); - for (const auto &sid : in.allowed_track_sids()) { + for (const auto& sid : in.allowed_track_sids()) { out.allowed_track_sids.push_back(sid); } return out; @@ -51,71 +49,70 @@ fromProto(const proto::ParticipantTrackPermission &in) { TrackKind fromProto(proto::TrackKind in) { switch (in) { - case proto::TrackKind::KIND_AUDIO: - return TrackKind::KIND_AUDIO; - case proto::TrackKind::KIND_VIDEO: - return TrackKind::KIND_VIDEO; - case proto::TrackKind::KIND_UNKNOWN: // NOLINT(bugprone-branch-clone) - return TrackKind::KIND_UNKNOWN; - default: - return TrackKind::KIND_UNKNOWN; + case proto::TrackKind::KIND_AUDIO: + return TrackKind::KIND_AUDIO; + case proto::TrackKind::KIND_VIDEO: + return TrackKind::KIND_VIDEO; + case proto::TrackKind::KIND_UNKNOWN: // NOLINT(bugprone-branch-clone) + return TrackKind::KIND_UNKNOWN; + default: + return TrackKind::KIND_UNKNOWN; } } StreamState fromProto(proto::StreamState in) { switch (in) { - case proto::StreamState::STATE_ACTIVE: - return StreamState::STATE_ACTIVE; - case proto::StreamState::STATE_PAUSED: - return StreamState::STATE_PAUSED; - case proto::StreamState::STATE_UNKNOWN: // NOLINT(bugprone-branch-clone) - return StreamState::STATE_UNKNOWN; - default: - return StreamState::STATE_UNKNOWN; + case proto::StreamState::STATE_ACTIVE: + return StreamState::STATE_ACTIVE; + case proto::StreamState::STATE_PAUSED: + return StreamState::STATE_PAUSED; + case proto::StreamState::STATE_UNKNOWN: // NOLINT(bugprone-branch-clone) + return StreamState::STATE_UNKNOWN; + default: + return StreamState::STATE_UNKNOWN; } } TrackSource fromProto(proto::TrackSource in) { switch (in) { - case proto::TrackSource::SOURCE_CAMERA: - return TrackSource::SOURCE_CAMERA; - case proto::TrackSource::SOURCE_MICROPHONE: - return TrackSource::SOURCE_MICROPHONE; - case proto::TrackSource::SOURCE_SCREENSHARE: - return TrackSource::SOURCE_SCREENSHARE; - case proto::TrackSource::SOURCE_SCREENSHARE_AUDIO: - return TrackSource::SOURCE_SCREENSHARE_AUDIO; - case proto::TrackSource::SOURCE_UNKNOWN: // NOLINT(bugprone-branch-clone) - return TrackSource::SOURCE_UNKNOWN; - default: - return TrackSource::SOURCE_UNKNOWN; + case proto::TrackSource::SOURCE_CAMERA: + return TrackSource::SOURCE_CAMERA; + case proto::TrackSource::SOURCE_MICROPHONE: + return TrackSource::SOURCE_MICROPHONE; + case proto::TrackSource::SOURCE_SCREENSHARE: + return TrackSource::SOURCE_SCREENSHARE; + case proto::TrackSource::SOURCE_SCREENSHARE_AUDIO: + return TrackSource::SOURCE_SCREENSHARE_AUDIO; + case proto::TrackSource::SOURCE_UNKNOWN: // NOLINT(bugprone-branch-clone) + return TrackSource::SOURCE_UNKNOWN; + default: + return TrackSource::SOURCE_UNKNOWN; } } AudioTrackFeature fromProto(proto::AudioTrackFeature in) { switch (in) { - case proto::TF_STEREO: - return AudioTrackFeature::TF_STEREO; - case proto::TF_NO_DTX: - return AudioTrackFeature::TF_NO_DTX; - case proto::TF_AUTO_GAIN_CONTROL: - return AudioTrackFeature::TF_AUTO_GAIN_CONTROL; - case proto::TF_ECHO_CANCELLATION: - return AudioTrackFeature::TF_ECHO_CANCELLATION; - case proto::TF_NOISE_SUPPRESSION: - return AudioTrackFeature::TF_NOISE_SUPPRESSION; - case proto::TF_ENHANCED_NOISE_CANCELLATION: - return AudioTrackFeature::TF_ENHANCED_NOISE_CANCELLATION; - case proto::TF_PRECONNECT_BUFFER: - return AudioTrackFeature::TF_PRECONNECT_BUFFER; - default: - // Defensive fallback – pick something valid instead of UB. - return AudioTrackFeature::TF_STEREO; + case proto::TF_STEREO: + return AudioTrackFeature::TF_STEREO; + case proto::TF_NO_DTX: + return AudioTrackFeature::TF_NO_DTX; + case proto::TF_AUTO_GAIN_CONTROL: + return AudioTrackFeature::TF_AUTO_GAIN_CONTROL; + case proto::TF_ECHO_CANCELLATION: + return AudioTrackFeature::TF_ECHO_CANCELLATION; + case proto::TF_NOISE_SUPPRESSION: + return AudioTrackFeature::TF_NOISE_SUPPRESSION; + case proto::TF_ENHANCED_NOISE_CANCELLATION: + return AudioTrackFeature::TF_ENHANCED_NOISE_CANCELLATION; + case proto::TF_PRECONNECT_BUFFER: + return AudioTrackFeature::TF_PRECONNECT_BUFFER; + default: + // Defensive fallback – pick something valid instead of UB. + return AudioTrackFeature::TF_STEREO; } } -std::vector -convertAudioFeatures(const google::protobuf::RepeatedField &features) { +std::vector convertAudioFeatures(const google::protobuf::RepeatedField& features) { std::vector out; out.reserve(features.size()); for (const int v : features) { @@ -126,18 +123,18 @@ convertAudioFeatures(const google::protobuf::RepeatedField &features) { ParticipantKind fromProto(proto::ParticipantKind in) { switch (in) { - case proto::ParticipantKind::PARTICIPANT_KIND_STANDARD: - return ParticipantKind::Standard; - case proto::ParticipantKind::PARTICIPANT_KIND_INGRESS: - return ParticipantKind::Ingress; - case proto::ParticipantKind::PARTICIPANT_KIND_EGRESS: - return ParticipantKind::Egress; - case proto::ParticipantKind::PARTICIPANT_KIND_SIP: - return ParticipantKind::Sip; - case proto::ParticipantKind::PARTICIPANT_KIND_AGENT: - return ParticipantKind::Agent; - default: - return ParticipantKind::Standard; + case proto::ParticipantKind::PARTICIPANT_KIND_STANDARD: + return ParticipantKind::Standard; + case proto::ParticipantKind::PARTICIPANT_KIND_INGRESS: + return ParticipantKind::Ingress; + case proto::ParticipantKind::PARTICIPANT_KIND_EGRESS: + return ParticipantKind::Egress; + case proto::ParticipantKind::PARTICIPANT_KIND_SIP: + return ParticipantKind::Sip; + case proto::ParticipantKind::PARTICIPANT_KIND_AGENT: + return ParticipantKind::Agent; + default: + return ParticipantKind::Standard; } } diff --git a/src/track_proto_converter.h b/src/track_proto_converter.h index ef4180ca..6d72b556 100644 --- a/src/track_proto_converter.h +++ b/src/track_proto_converter.h @@ -26,13 +26,11 @@ TrackKind fromProto(proto::TrackKind in); StreamState fromProto(proto::StreamState in); TrackSource fromProto(proto::TrackSource in); AudioTrackFeature fromProto(proto::AudioTrackFeature in); -std::vector -convertAudioFeatures(const google::protobuf::RepeatedField &features); +std::vector convertAudioFeatures(const google::protobuf::RepeatedField& features); // Participant Utils ParticipantKind fromProto(proto::ParticipantKind kind); -proto::ParticipantTrackPermission toProto(const ParticipantTrackPermission &in); -ParticipantTrackPermission -fromProto(const proto::ParticipantTrackPermission &in); +proto::ParticipantTrackPermission toProto(const ParticipantTrackPermission& in); +ParticipantTrackPermission fromProto(const proto::ParticipantTrackPermission& in); } // namespace livekit \ No newline at end of file diff --git a/src/track_publication.cpp b/src/track_publication.cpp index 8722a5b1..0eddd1e2 100644 --- a/src/track_publication.cpp +++ b/src/track_publication.cpp @@ -18,15 +18,20 @@ namespace livekit { -TrackPublication::TrackPublication( - FfiHandle handle, std::string sid, std::string name, TrackKind kind, - TrackSource source, bool simulcasted, std::uint32_t width, - std::uint32_t height, std::string mime_type, bool muted, - EncryptionType encryption_type, - std::vector audio_features) - : handle_(std::move(handle)), sid_(std::move(sid)), name_(std::move(name)), - kind_(kind), source_(source), simulcasted_(simulcasted), width_(width), - height_(height), mime_type_(std::move(mime_type)), muted_(muted), +TrackPublication::TrackPublication(FfiHandle handle, std::string sid, std::string name, TrackKind kind, + TrackSource source, bool simulcasted, std::uint32_t width, std::uint32_t height, + std::string mime_type, bool muted, EncryptionType encryption_type, + std::vector audio_features) + : handle_(std::move(handle)), + sid_(std::move(sid)), + name_(std::move(name)), + kind_(kind), + source_(source), + simulcasted_(simulcasted), + width_(width), + height_(height), + mime_type_(std::move(mime_type)), + muted_(muted), encryption_type_(encryption_type), audio_features_(std::move(audio_features)) {} diff --git a/src/video_frame.cpp b/src/video_frame.cpp index 761ad622..6f90c6b8 100644 --- a/src/video_frame.cpp +++ b/src/video_frame.cpp @@ -31,68 +31,65 @@ namespace { // Compute total buffer size in bytes for (width, height, type). std::size_t computeBufferSize(int width, int height, VideoBufferType type) { if (width <= 0 || height <= 0) { - throw std::invalid_argument( - "VideoFrame: width and height must be positive"); + throw std::invalid_argument("VideoFrame: width and height must be positive"); } const auto w = static_cast(width); const auto h = static_cast(height); switch (type) { - case VideoBufferType::ARGB: - case VideoBufferType::ABGR: - case VideoBufferType::RGBA: - case VideoBufferType::BGRA: - // 4 bytes per pixel - return w * h * 4; - - case VideoBufferType::RGB24: - case VideoBufferType::I444: - // 3 bytes per pixel (RGB24: packed; I444: Y+U+V all full resolution) - return w * h * 3; - - case VideoBufferType::I420: - // Y (1 byte) + U (1 byte) + V (1 byte) - case VideoBufferType::NV12: { - // Y (1 byte) + UV interleaved (2 bytes per chroma sample) - const std::size_t chroma_w = (w + 1) / 2; - const std::size_t chroma_h = (h + 1) / 2; - return w * h + chroma_w * chroma_h * 2; - } + case VideoBufferType::ARGB: + case VideoBufferType::ABGR: + case VideoBufferType::RGBA: + case VideoBufferType::BGRA: + // 4 bytes per pixel + return w * h * 4; + + case VideoBufferType::RGB24: + case VideoBufferType::I444: + // 3 bytes per pixel (RGB24: packed; I444: Y+U+V all full resolution) + return w * h * 3; + + case VideoBufferType::I420: + // Y (1 byte) + U (1 byte) + V (1 byte) + case VideoBufferType::NV12: { + // Y (1 byte) + UV interleaved (2 bytes per chroma sample) + const std::size_t chroma_w = (w + 1) / 2; + const std::size_t chroma_h = (h + 1) / 2; + return w * h + chroma_w * chroma_h * 2; + } - case VideoBufferType::I010: { - // 16 bits per sample in memory - // Y: 2 bytes per sample, U & V: 2 bytes per sample - const std::size_t chroma_w = (w + 1) / 2; - const std::size_t chroma_h = (h + 1) / 2; - return w * h * 2 + chroma_w * chroma_h * 4; - } + case VideoBufferType::I010: { + // 16 bits per sample in memory + // Y: 2 bytes per sample, U & V: 2 bytes per sample + const std::size_t chroma_w = (w + 1) / 2; + const std::size_t chroma_h = (h + 1) / 2; + return w * h * 2 + chroma_w * chroma_h * 4; + } - case VideoBufferType::I420A: { - // Y full, U & V 2x2, plus alpha full res - const std::size_t chroma_w = (w + 1) / 2; - const std::size_t chroma_h = (h + 1) / 2; - // Y + A are full resolution, U + V subsampled - return w * h * 2 + chroma_w * chroma_h * 2; - } + case VideoBufferType::I420A: { + // Y full, U & V 2x2, plus alpha full res + const std::size_t chroma_w = (w + 1) / 2; + const std::size_t chroma_h = (h + 1) / 2; + // Y + A are full resolution, U + V subsampled + return w * h * 2 + chroma_w * chroma_h * 2; + } - case VideoBufferType::I422: { - // Y full, U & V subsampled horizontally only - const std::size_t chroma_w = (w + 1) / 2; - return w * h + chroma_w * h * 2; - } + case VideoBufferType::I422: { + // Y full, U & V subsampled horizontally only + const std::size_t chroma_w = (w + 1) / 2; + return w * h + chroma_w * h * 2; + } - default: - throw std::runtime_error("VideoFrame: unsupported VideoBufferType"); + default: + throw std::runtime_error("VideoFrame: unsupported VideoBufferType"); } } // Compute plane layout for (base_ptr, width, height, type) -std::vector -computePlaneInfos(uintptr_t base, int width, int height, VideoBufferType type) { +std::vector computePlaneInfos(uintptr_t base, int width, int height, VideoBufferType type) { std::vector planes; if (!base || width <= 0 || height <= 0) { - LK_LOG_WARN("VideoFrame: invalid planeInfos input (ptr={}, w={}, h={})", - base, width, height); + LK_LOG_WARN("VideoFrame: invalid planeInfos input (ptr={}, w={}, h={})", base, width, height); return planes; } const auto w = static_cast(width); @@ -103,165 +100,165 @@ computePlaneInfos(uintptr_t base, int width, int height, VideoBufferType type) { }; switch (type) { - case VideoBufferType::ARGB: - case VideoBufferType::ABGR: - case VideoBufferType::RGBA: - case VideoBufferType::BGRA: { - const uint32_t stride = w * 4; - const uint32_t size = stride * h; - pushPlane(base, stride, size); - break; - } + case VideoBufferType::ARGB: + case VideoBufferType::ABGR: + case VideoBufferType::RGBA: + case VideoBufferType::BGRA: { + const uint32_t stride = w * 4; + const uint32_t size = stride * h; + pushPlane(base, stride, size); + break; + } - case VideoBufferType::RGB24: { - const uint32_t stride = w * 3; - const uint32_t size = stride * h; - pushPlane(base, stride, size); - break; - } + case VideoBufferType::RGB24: { + const uint32_t stride = w * 3; + const uint32_t size = stride * h; + pushPlane(base, stride, size); + break; + } - case VideoBufferType::I420: { - const uint32_t chroma_w = (w + 1) / 2; - const uint32_t chroma_h = (h + 1) / 2; - - // Y - const uint32_t y_stride = w; - const uint32_t y_size = w * h; - const uintptr_t y_ptr = base; - pushPlane(y_ptr, y_stride, y_size); - - // U - const uint32_t u_stride = chroma_w; - const uint32_t u_size = chroma_w * chroma_h; - const uintptr_t u_ptr = y_ptr + y_size; - pushPlane(u_ptr, u_stride, u_size); - - // V - const uint32_t v_stride = chroma_w; - const uint32_t v_size = chroma_w * chroma_h; - const uintptr_t v_ptr = u_ptr + u_size; - pushPlane(v_ptr, v_stride, v_size); - break; - } + case VideoBufferType::I420: { + const uint32_t chroma_w = (w + 1) / 2; + const uint32_t chroma_h = (h + 1) / 2; + + // Y + const uint32_t y_stride = w; + const uint32_t y_size = w * h; + const uintptr_t y_ptr = base; + pushPlane(y_ptr, y_stride, y_size); + + // U + const uint32_t u_stride = chroma_w; + const uint32_t u_size = chroma_w * chroma_h; + const uintptr_t u_ptr = y_ptr + y_size; + pushPlane(u_ptr, u_stride, u_size); + + // V + const uint32_t v_stride = chroma_w; + const uint32_t v_size = chroma_w * chroma_h; + const uintptr_t v_ptr = u_ptr + u_size; + pushPlane(v_ptr, v_stride, v_size); + break; + } - case VideoBufferType::I420A: { - const uint32_t chroma_w = (w + 1) / 2; - const uint32_t chroma_h = (h + 1) / 2; - - // Y - const uint32_t y_stride = w; - const uint32_t y_size = w * h; - const uintptr_t y_ptr = base; - pushPlane(y_ptr, y_stride, y_size); - - // U - const uint32_t u_stride = chroma_w; - const uint32_t u_size = chroma_w * chroma_h; - const uintptr_t u_ptr = y_ptr + y_size; - pushPlane(u_ptr, u_stride, u_size); - - // V - const uint32_t v_stride = chroma_w; - const uint32_t v_size = chroma_w * chroma_h; - const uintptr_t v_ptr = u_ptr + u_size; - pushPlane(v_ptr, v_stride, v_size); - - // A (full res) - const uint32_t a_stride = w; - const uint32_t a_size = w * h; - const uintptr_t a_ptr = v_ptr + v_size; - pushPlane(a_ptr, a_stride, a_size); - break; - } + case VideoBufferType::I420A: { + const uint32_t chroma_w = (w + 1) / 2; + const uint32_t chroma_h = (h + 1) / 2; + + // Y + const uint32_t y_stride = w; + const uint32_t y_size = w * h; + const uintptr_t y_ptr = base; + pushPlane(y_ptr, y_stride, y_size); + + // U + const uint32_t u_stride = chroma_w; + const uint32_t u_size = chroma_w * chroma_h; + const uintptr_t u_ptr = y_ptr + y_size; + pushPlane(u_ptr, u_stride, u_size); + + // V + const uint32_t v_stride = chroma_w; + const uint32_t v_size = chroma_w * chroma_h; + const uintptr_t v_ptr = u_ptr + u_size; + pushPlane(v_ptr, v_stride, v_size); + + // A (full res) + const uint32_t a_stride = w; + const uint32_t a_size = w * h; + const uintptr_t a_ptr = v_ptr + v_size; + pushPlane(a_ptr, a_stride, a_size); + break; + } - case VideoBufferType::I422: { - const uint32_t chroma_w = (w + 1) / 2; - - // Y - const uint32_t y_stride = w; - const uint32_t y_size = w * h; - const uintptr_t y_ptr = base; - pushPlane(y_ptr, y_stride, y_size); - - // U - const uint32_t u_stride = chroma_w; - const uint32_t u_size = chroma_w * h; - const uintptr_t u_ptr = y_ptr + y_size; - pushPlane(u_ptr, u_stride, u_size); - - // V - const uint32_t v_stride = chroma_w; - const uint32_t v_size = chroma_w * h; - const uintptr_t v_ptr = u_ptr + u_size; - pushPlane(v_ptr, v_stride, v_size); - break; - } + case VideoBufferType::I422: { + const uint32_t chroma_w = (w + 1) / 2; + + // Y + const uint32_t y_stride = w; + const uint32_t y_size = w * h; + const uintptr_t y_ptr = base; + pushPlane(y_ptr, y_stride, y_size); + + // U + const uint32_t u_stride = chroma_w; + const uint32_t u_size = chroma_w * h; + const uintptr_t u_ptr = y_ptr + y_size; + pushPlane(u_ptr, u_stride, u_size); + + // V + const uint32_t v_stride = chroma_w; + const uint32_t v_size = chroma_w * h; + const uintptr_t v_ptr = u_ptr + u_size; + pushPlane(v_ptr, v_stride, v_size); + break; + } - case VideoBufferType::I444: { - // All planes full-res - const uint32_t y_stride = w; - const uint32_t y_size = w * h; - const uintptr_t y_ptr = base; - pushPlane(y_ptr, y_stride, y_size); - - const uint32_t u_stride = w; - const uint32_t u_size = w * h; - const uintptr_t u_ptr = y_ptr + y_size; - pushPlane(u_ptr, u_stride, u_size); - - const uint32_t v_stride = w; - const uint32_t v_size = w * h; - const uintptr_t v_ptr = u_ptr + u_size; - pushPlane(v_ptr, v_stride, v_size); - break; - } + case VideoBufferType::I444: { + // All planes full-res + const uint32_t y_stride = w; + const uint32_t y_size = w * h; + const uintptr_t y_ptr = base; + pushPlane(y_ptr, y_stride, y_size); + + const uint32_t u_stride = w; + const uint32_t u_size = w * h; + const uintptr_t u_ptr = y_ptr + y_size; + pushPlane(u_ptr, u_stride, u_size); + + const uint32_t v_stride = w; + const uint32_t v_size = w * h; + const uintptr_t v_ptr = u_ptr + u_size; + pushPlane(v_ptr, v_stride, v_size); + break; + } - case VideoBufferType::I010: { - // 16-bit per sample - const uint32_t chroma_w = (w + 1) / 2; - const uint32_t chroma_h = (h + 1) / 2; - - // Y - const uint32_t y_stride = w * 2; - const uint32_t y_size = w * h * 2; - const uintptr_t y_ptr = base; - pushPlane(y_ptr, y_stride, y_size); - - // U - const uint32_t u_stride = chroma_w * 2; - const uint32_t u_size = chroma_w * chroma_h * 2; - const uintptr_t u_ptr = y_ptr + y_size; - pushPlane(u_ptr, u_stride, u_size); - - // V - const uint32_t v_stride = chroma_w * 2; - const uint32_t v_size = chroma_w * chroma_h * 2; - const uintptr_t v_ptr = u_ptr + u_size; - pushPlane(v_ptr, v_stride, v_size); - break; - } + case VideoBufferType::I010: { + // 16-bit per sample + const uint32_t chroma_w = (w + 1) / 2; + const uint32_t chroma_h = (h + 1) / 2; + + // Y + const uint32_t y_stride = w * 2; + const uint32_t y_size = w * h * 2; + const uintptr_t y_ptr = base; + pushPlane(y_ptr, y_stride, y_size); + + // U + const uint32_t u_stride = chroma_w * 2; + const uint32_t u_size = chroma_w * chroma_h * 2; + const uintptr_t u_ptr = y_ptr + y_size; + pushPlane(u_ptr, u_stride, u_size); + + // V + const uint32_t v_stride = chroma_w * 2; + const uint32_t v_size = chroma_w * chroma_h * 2; + const uintptr_t v_ptr = u_ptr + u_size; + pushPlane(v_ptr, v_stride, v_size); + break; + } - case VideoBufferType::NV12: { - const uint32_t chroma_w = (w + 1) / 2; - const uint32_t chroma_h = (h + 1) / 2; - - // Y - const uint32_t y_stride = w; - const uint32_t y_size = w * h; - const uintptr_t y_ptr = base; - pushPlane(y_ptr, y_stride, y_size); - - // UV interleaved - const uint32_t uv_stride = chroma_w * 2; - const uint32_t uv_size = chroma_w * chroma_h * 2; - const uintptr_t uv_ptr = y_ptr + y_size; - pushPlane(uv_ptr, uv_stride, uv_size); - break; - } + case VideoBufferType::NV12: { + const uint32_t chroma_w = (w + 1) / 2; + const uint32_t chroma_h = (h + 1) / 2; + + // Y + const uint32_t y_stride = w; + const uint32_t y_size = w * h; + const uintptr_t y_ptr = base; + pushPlane(y_ptr, y_stride, y_size); + + // UV interleaved + const uint32_t uv_stride = chroma_w * 2; + const uint32_t uv_size = chroma_w * chroma_h * 2; + const uintptr_t uv_ptr = y_ptr + y_size; + pushPlane(uv_ptr, uv_stride, uv_size); + break; + } - default: - // Unknown or unsupported -> no planes - break; + default: + // Unknown or unsupported -> no planes + break; } return planes; @@ -273,16 +270,15 @@ computePlaneInfos(uintptr_t base, int width, int height, VideoBufferType type) { // VideoFrame implementation // ---------------------------------------------------------------------------- -VideoFrame::VideoFrame() - : width_{0}, height_{0}, type_{VideoBufferType::BGRA}, data_{} {} +VideoFrame::VideoFrame() : width_{0}, height_{0}, type_{VideoBufferType::BGRA}, data_{} {} -VideoFrame::VideoFrame(int width, int height, VideoBufferType type, - std::vector data) +VideoFrame::VideoFrame(int width, int height, VideoBufferType type, std::vector data) : width_(width), height_(height), type_(type), data_(std::move(data)) { const std::size_t expected = computeBufferSize(width_, height_, type_); if (data_.size() < expected) { - throw std::invalid_argument("VideoFrame: provided data is too small for " - "the specified format and size"); + throw std::invalid_argument( + "VideoFrame: provided data is too small for " + "the specified format and size"); } } @@ -317,8 +313,8 @@ VideoFrame VideoFrame::convert(VideoBufferType dst, bool flip_y) const { return convertViaFfi(*this, dst, flip_y); } -VideoFrame VideoFrame::fromOwnedInfo(const proto::OwnedVideoBuffer &owned) { - const auto &info = owned.info(); +VideoFrame VideoFrame::fromOwnedInfo(const proto::OwnedVideoBuffer& owned) { + const auto& info = owned.info(); const int width = static_cast(info.width()); const int height = static_cast(info.height()); const VideoBufferType type = fromProto(info.type()); @@ -328,32 +324,31 @@ VideoFrame VideoFrame::fromOwnedInfo(const proto::OwnedVideoBuffer &owned) { if (info.components_size() > 0) { // Multi-plane (e.g. I420, NV12, etc.). We pack planes back-to-back. std::size_t total_size = 0; - for (const auto &comp : info.components()) { + for (const auto& comp : info.components()) { total_size += static_cast(comp.size()); } buffer.resize(total_size); std::size_t offset = 0; - for (const auto &comp : info.components()) { + for (const auto& comp : info.components()) { const auto sz = static_cast(comp.size()); - const auto *src_ptr = + const auto* src_ptr = // NOLINTNEXTLINE(performance-no-int-to-ptr) - reinterpret_cast(comp.data_ptr()); + reinterpret_cast(comp.data_ptr()); std::memcpy(buffer.data() + offset, src_ptr, sz); offset += sz; } } else { // Packed format: treat top-level data_ptr as a single contiguous buffer. - const auto *src_ptr = + const auto* src_ptr = // NOLINTNEXTLINE(performance-no-int-to-ptr) - reinterpret_cast(info.data_ptr()); + reinterpret_cast(info.data_ptr()); std::size_t total_size = 0; if (info.has_stride()) { // Use stride * height as total size (includes per-row padding if any). - total_size = static_cast(info.stride()) * - static_cast(height); + total_size = static_cast(info.stride()) * static_cast(height); } else { // Use our generic buffer-size helper (width/height/type). total_size = computeBufferSize(width, height, type); @@ -365,8 +360,7 @@ VideoFrame VideoFrame::fromOwnedInfo(const proto::OwnedVideoBuffer &owned) { // Release the FFI-owned buffer after copying the data. { - const FfiHandle owned_handle( - static_cast(owned.handle().id())); + const FfiHandle owned_handle(static_cast(owned.handle().id())); // owned_handle destroyed at end of scope → native buffer disposed. } diff --git a/src/video_source.cpp b/src/video_source.cpp index edcd7680..468b900d 100644 --- a/src/video_source.cpp +++ b/src/video_source.cpp @@ -26,11 +26,9 @@ namespace livekit { -VideoSource::VideoSource(int width, int height) - : width_(width), height_(height) { - +VideoSource::VideoSource(int width, int height) : width_(width), height_(height) { proto::FfiRequest req; - auto *msg = req.mutable_new_video_source(); + auto* msg = req.mutable_new_video_source(); msg->set_type(proto::VideoSourceType::VIDEO_SOURCE_NATIVE); msg->mutable_resolution()->set_width(width_); msg->mutable_resolution()->set_height(height_); @@ -43,15 +41,14 @@ VideoSource::VideoSource(int width, int height) handle_ = FfiHandle(resp.new_video_source().source().handle().id()); } -void VideoSource::captureFrame(const VideoFrame &frame, - const VideoCaptureOptions &options) { +void VideoSource::captureFrame(const VideoFrame& frame, const VideoCaptureOptions& options) { if (!handle_) { return; } const proto::VideoBufferInfo buf = toProto(frame); proto::FfiRequest req; - auto *msg = req.mutable_capture_video_frame(); + auto* msg = req.mutable_capture_video_frame(); msg->set_source_handle(handle_.get()); msg->mutable_buffer()->CopyFrom(buf); msg->set_timestamp_us(options.timestamp_us); @@ -65,9 +62,7 @@ void VideoSource::captureFrame(const VideoFrame &frame, } } -void VideoSource::captureFrame(const VideoFrame &frame, - std::int64_t timestamp_us, - VideoRotation rotation) { +void VideoSource::captureFrame(const VideoFrame& frame, std::int64_t timestamp_us, VideoRotation rotation) { captureFrame(frame, VideoCaptureOptions{timestamp_us, rotation}); } diff --git a/src/video_stream.cpp b/src/video_stream.cpp index a3bce022..db08a685 100644 --- a/src/video_stream.cpp +++ b/src/video_stream.cpp @@ -31,17 +31,14 @@ using proto::FfiEvent; using proto::FfiRequest; using proto::VideoStreamEvent; -std::shared_ptr -VideoStream::fromTrack(const std::shared_ptr &track, - const Options &options) { +std::shared_ptr VideoStream::fromTrack(const std::shared_ptr& track, const Options& options) { auto stream = std::shared_ptr(new VideoStream()); stream->initFromTrack(track, options); return stream; } -std::shared_ptr -VideoStream::fromParticipant(Participant &participant, TrackSource track_source, - const Options &options) { +std::shared_ptr VideoStream::fromParticipant(Participant& participant, TrackSource track_source, + const Options& options) { auto stream = std::shared_ptr(new VideoStream()); stream->initFromParticipant(participant, track_source, options); return stream; @@ -49,7 +46,7 @@ VideoStream::fromParticipant(Participant &participant, TrackSource track_source, VideoStream::~VideoStream() { close(); } -VideoStream::VideoStream(VideoStream &&other) noexcept { +VideoStream::VideoStream(VideoStream&& other) noexcept { const std::scoped_lock lock(other.mutex_); queue_ = std::move(other.queue_); capacity_ = other.capacity_; @@ -62,9 +59,10 @@ VideoStream::VideoStream(VideoStream &&other) noexcept { other.closed_ = true; } -VideoStream &VideoStream::operator=(VideoStream &&other) noexcept { - if (this == &other) +VideoStream& VideoStream::operator=(VideoStream&& other) noexcept { + if (this == &other) { return *this; + } close(); @@ -88,7 +86,7 @@ VideoStream &VideoStream::operator=(VideoStream &&other) noexcept { // --------------------- Public API --------------------- -bool VideoStream::read(VideoFrameEvent &out) { +bool VideoStream::read(VideoFrameEvent& out) { std::unique_lock lock(mutex_); cv_.wait(lock, [this] { return !queue_.empty() || eof_ || closed_; }); @@ -128,48 +126,41 @@ void VideoStream::close() { // --------------------- Internal helpers --------------------- -void VideoStream::initFromTrack(const std::shared_ptr &track, - const Options &options) { +void VideoStream::initFromTrack(const std::shared_ptr& track, const Options& options) { capacity_ = options.capacity; // Subscribe to FFI events, this is essential to get video frames from FFI. - listener_id_ = FfiClient::instance().AddListener( - [this](const proto::FfiEvent &e) { this->onFfiEvent(e); }); + listener_id_ = FfiClient::instance().AddListener([this](const proto::FfiEvent& e) { this->onFfiEvent(e); }); // Send FFI request to create a new video stream bound to this track FfiRequest req; - auto *new_video_stream = req.mutable_new_video_stream(); - new_video_stream->set_track_handle( - static_cast(track->ffi_handle_id())); + auto* new_video_stream = req.mutable_new_video_stream(); + new_video_stream->set_track_handle(static_cast(track->ffi_handle_id())); new_video_stream->set_type(proto::VideoStreamType::VIDEO_STREAM_NATIVE); new_video_stream->set_normalize_stride(true); new_video_stream->set_format(toProto(options.format)); auto resp = FfiClient::instance().sendRequest(req); if (!resp.has_new_video_stream()) { - LK_LOG_ERROR( - "VideoStream::initFromTrack: FFI response missing new_video_stream()"); + LK_LOG_ERROR("VideoStream::initFromTrack: FFI response missing new_video_stream()"); throw std::runtime_error("new_video_stream FFI request failed"); } // Adjust field names to match your proto exactly: - const auto &stream = resp.new_video_stream().stream(); + const auto& stream = resp.new_video_stream().stream(); stream_handle_ = FfiHandle(static_cast(stream.handle().id())); // TODO, do we need to cache the metadata from stream.info ? } -void VideoStream::initFromParticipant(Participant &participant, - TrackSource track_source, - const Options &options) { +void VideoStream::initFromParticipant(Participant& participant, TrackSource track_source, const Options& options) { capacity_ = options.capacity; // 1) Subscribe to FFI events - listener_id_ = FfiClient::instance().AddListener( - [this](const FfiEvent &e) { this->onFfiEvent(e); }); + listener_id_ = FfiClient::instance().AddListener([this](const FfiEvent& e) { this->onFfiEvent(e); }); // 2) Send FFI request to create a video stream from participant + track // source FfiRequest req; - auto *vs = req.mutable_video_stream_from_participant(); + auto* vs = req.mutable_video_stream_from_participant(); vs->set_participant_handle(participant.ffiHandleId()); vs->set_type(proto::VideoStreamType::VIDEO_STREAM_NATIVE); vs->set_track_source(static_cast(track_source)); @@ -178,23 +169,23 @@ void VideoStream::initFromParticipant(Participant &participant, auto resp = FfiClient::instance().sendRequest(req); // Adjust field names to match your proto exactly: - const auto &stream = resp.video_stream_from_participant().stream(); + const auto& stream = resp.video_stream_from_participant().stream(); stream_handle_ = FfiHandle(static_cast(stream.handle().id())); } -void VideoStream::onFfiEvent(const proto::FfiEvent &event) { +void VideoStream::onFfiEvent(const proto::FfiEvent& event) { // Filter for video_stream_event first. if (event.message_case() != FfiEvent::kVideoStreamEvent) { return; } - const auto &vse = event.video_stream_event(); + const auto& vse = event.video_stream_event(); // Check if this event is for our stream handle. if (vse.stream_handle() != static_cast(stream_handle_.get())) { return; } // Handle frame_received or eos. if (vse.has_frame_received()) { - const auto &fr = vse.frame_received(); + const auto& fr = vse.frame_received(); // Convert owned buffer->VideoFrame via a helper. // You should implement this static function in your VideoFrame class. @@ -211,7 +202,7 @@ void VideoStream::onFfiEvent(const proto::FfiEvent &event) { } } -void VideoStream::pushFrame(VideoFrameEvent &&ev) { +void VideoStream::pushFrame(VideoFrameEvent&& ev) { { const std::scoped_lock lock(mutex_); diff --git a/src/video_utils.cpp b/src/video_utils.cpp index 1f7b3636..19bd4300 100644 --- a/src/video_utils.cpp +++ b/src/video_utils.cpp @@ -29,65 +29,64 @@ namespace livekit { proto::VideoBufferType toProto(const VideoBufferType t) { switch (t) { - case VideoBufferType::ARGB: - return proto::VideoBufferType::ARGB; - case VideoBufferType::ABGR: - return proto::VideoBufferType::ABGR; - case VideoBufferType::RGBA: - return proto::VideoBufferType::RGBA; - case VideoBufferType::BGRA: - return proto::VideoBufferType::BGRA; - case VideoBufferType::RGB24: - return proto::VideoBufferType::RGB24; - case VideoBufferType::I420: - return proto::VideoBufferType::I420; - case VideoBufferType::I420A: - return proto::VideoBufferType::I420A; - case VideoBufferType::I422: - return proto::VideoBufferType::I422; - case VideoBufferType::I444: - return proto::VideoBufferType::I444; - case VideoBufferType::I010: - return proto::VideoBufferType::I010; - case VideoBufferType::NV12: - return proto::VideoBufferType::NV12; - default: - throw std::runtime_error("Unknown VideoBufferType in toProto"); + case VideoBufferType::ARGB: + return proto::VideoBufferType::ARGB; + case VideoBufferType::ABGR: + return proto::VideoBufferType::ABGR; + case VideoBufferType::RGBA: + return proto::VideoBufferType::RGBA; + case VideoBufferType::BGRA: + return proto::VideoBufferType::BGRA; + case VideoBufferType::RGB24: + return proto::VideoBufferType::RGB24; + case VideoBufferType::I420: + return proto::VideoBufferType::I420; + case VideoBufferType::I420A: + return proto::VideoBufferType::I420A; + case VideoBufferType::I422: + return proto::VideoBufferType::I422; + case VideoBufferType::I444: + return proto::VideoBufferType::I444; + case VideoBufferType::I010: + return proto::VideoBufferType::I010; + case VideoBufferType::NV12: + return proto::VideoBufferType::NV12; + default: + throw std::runtime_error("Unknown VideoBufferType in toProto"); } } // Map proto enum -> SDK enum VideoBufferType fromProto(const proto::VideoBufferType t) { switch (t) { - case proto::VideoBufferType::ARGB: - return VideoBufferType::ARGB; - case proto::VideoBufferType::ABGR: - return VideoBufferType::ABGR; - case proto::VideoBufferType::RGBA: - return VideoBufferType::RGBA; - case proto::VideoBufferType::BGRA: - return VideoBufferType::BGRA; - case proto::VideoBufferType::RGB24: - return VideoBufferType::RGB24; - case proto::VideoBufferType::I420: - return VideoBufferType::I420; - case proto::VideoBufferType::I420A: - return VideoBufferType::I420A; - case proto::VideoBufferType::I422: - return VideoBufferType::I422; - case proto::VideoBufferType::I444: - return VideoBufferType::I444; - case proto::VideoBufferType::I010: - return VideoBufferType::I010; - case proto::VideoBufferType::NV12: - return VideoBufferType::NV12; - default: - throw std::runtime_error("Unknown proto::VideoBufferType in fromProto"); + case proto::VideoBufferType::ARGB: + return VideoBufferType::ARGB; + case proto::VideoBufferType::ABGR: + return VideoBufferType::ABGR; + case proto::VideoBufferType::RGBA: + return VideoBufferType::RGBA; + case proto::VideoBufferType::BGRA: + return VideoBufferType::BGRA; + case proto::VideoBufferType::RGB24: + return VideoBufferType::RGB24; + case proto::VideoBufferType::I420: + return VideoBufferType::I420; + case proto::VideoBufferType::I420A: + return VideoBufferType::I420A; + case proto::VideoBufferType::I422: + return VideoBufferType::I422; + case proto::VideoBufferType::I444: + return VideoBufferType::I444; + case proto::VideoBufferType::I010: + return VideoBufferType::I010; + case proto::VideoBufferType::NV12: + return VideoBufferType::NV12; + default: + throw std::runtime_error("Unknown proto::VideoBufferType in fromProto"); } } -std::optional -toProto(const std::optional &metadata) { +std::optional toProto(const std::optional& metadata) { if (!metadata.has_value()) { return std::nullopt; } @@ -107,8 +106,7 @@ toProto(const std::optional &metadata) { return proto_metadata; } -std::optional -fromProto(const proto::FrameMetadata &metadata) { +std::optional fromProto(const proto::FrameMetadata& metadata) { VideoFrameMetadata out; if (metadata.has_user_timestamp()) { out.user_timestamp_us = metadata.user_timestamp(); @@ -124,7 +122,7 @@ fromProto(const proto::FrameMetadata &metadata) { return out; } -proto::VideoBufferInfo toProto(const VideoFrame &frame) { +proto::VideoBufferInfo toProto(const VideoFrame& frame) { proto::VideoBufferInfo info; const int w = frame.width(); @@ -139,8 +137,8 @@ proto::VideoBufferInfo toProto(const VideoFrame &frame) { // Compute plane layout for the current format const auto planes = frame.planeInfos(); - for (const auto &plane : planes) { - auto *cmpt = info.add_components(); + for (const auto& plane : planes) { + auto* cmpt = info.add_components(); cmpt->set_data_ptr(static_cast(plane.data_ptr)); cmpt->set_stride(plane.stride); cmpt->set_size(plane.size); @@ -149,25 +147,25 @@ proto::VideoBufferInfo toProto(const VideoFrame &frame) { // Stride for main packed formats. std::uint32_t stride = 0; switch (frame.type()) { - case VideoBufferType::ARGB: - case VideoBufferType::ABGR: - case VideoBufferType::RGBA: - case VideoBufferType::BGRA: - stride = static_cast(w) * 4; - break; - case VideoBufferType::RGB24: - stride = static_cast(w) * 3; - break; - default: - stride = 0; // not used / unknown for planar formats - break; + case VideoBufferType::ARGB: + case VideoBufferType::ABGR: + case VideoBufferType::RGBA: + case VideoBufferType::BGRA: + stride = static_cast(w) * 4; + break; + case VideoBufferType::RGB24: + stride = static_cast(w) * 3; + break; + default: + stride = 0; // not used / unknown for planar formats + break; } info.set_stride(stride); return info; } -VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer &owned) { - const auto &info = owned.info(); +VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer& owned) { + const auto& info = owned.info(); const int width = static_cast(info.width()); const int height = static_cast(info.height()); @@ -177,7 +175,7 @@ VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer &owned) { VideoFrame frame = VideoFrame::create(width, height, type); // Copy from the FFI-provided buffer into our own backing storage - auto *dst = frame.data(); + auto* dst = frame.data(); const std::size_t dst_size = frame.dataSize(); const auto src_ptr = info.data_ptr(); @@ -185,7 +183,7 @@ VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer &owned) { throw std::runtime_error("fromOwnedProto: info.data_ptr is null"); } // NOLINTNEXTLINE(performance-no-int-to-ptr) - const auto *src = reinterpret_cast(src_ptr); + const auto* src = reinterpret_cast(src_ptr); std::memcpy(dst, src, dst_size); @@ -198,20 +196,18 @@ VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer &owned) { return frame; } -VideoFrame convertViaFfi(const VideoFrame &frame, VideoBufferType dst, - bool flip_y) { +VideoFrame convertViaFfi(const VideoFrame& frame, VideoBufferType dst, bool flip_y) { proto::FfiRequest req; - auto *vc = req.mutable_video_convert(); + auto* vc = req.mutable_video_convert(); vc->set_flip_y(flip_y); vc->set_dst_type(toProto(dst)); vc->mutable_buffer()->CopyFrom(toProto(frame)); const proto::FfiResponse resp = FfiClient::instance().sendRequest(req); if (!resp.has_video_convert()) { - throw std::runtime_error( - "convertViaFfi: FfiResponse missing video_convert"); + throw std::runtime_error("convertViaFfi: FfiResponse missing video_convert"); } - const auto &vc_resp = resp.video_convert(); + const auto& vc_resp = resp.video_convert(); if (!vc_resp.error().empty()) { throw std::runtime_error("convertViaFfi: " + vc_resp.error()); } diff --git a/src/video_utils.h b/src/video_utils.h index fe273d66..c2c9bcfb 100644 --- a/src/video_utils.h +++ b/src/video_utils.h @@ -23,15 +23,12 @@ namespace livekit { // Video FFI Utils -proto::VideoBufferInfo toProto(const VideoFrame &frame); -VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer &owned); -VideoFrame convertViaFfi(const VideoFrame &frame, VideoBufferType dst, - bool flip_y); +proto::VideoBufferInfo toProto(const VideoFrame& frame); +VideoFrame fromOwnedProto(const proto::OwnedVideoBuffer& owned); +VideoFrame convertViaFfi(const VideoFrame& frame, VideoBufferType dst, bool flip_y); proto::VideoBufferType toProto(const VideoBufferType t); VideoBufferType fromProto(const proto::VideoBufferType t); -std::optional -toProto(const std::optional &metadata); -std::optional -fromProto(const proto::FrameMetadata &metadata); +std::optional toProto(const std::optional& metadata); +std::optional fromProto(const proto::FrameMetadata& metadata); } // namespace livekit From 4e5068bc109afae3c0a8ff74c597e7b44269b882 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 6 May 2026 20:05:04 -0600 Subject: [PATCH 6/6] Try larger runner --- .github/workflows/builds.yml | 2 +- .github/workflows/tests.yml | 261 +++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index dfcfe6be..7d739a95 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -75,7 +75,7 @@ jobs: name: linux-arm64 build_cmd: ./build.sh release-all build_dir: build-release - - os: macos-latest + - os: macos-latest-xlarge name: macos-arm64 build_cmd: ./build.sh release-all build_dir: build-release diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..8cac920c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,261 @@ +name: Tests + +on: + push: + branches: ["main"] + paths: + - src/** + - include/** + - client-sdk-rust/** + - CMakeLists.txt + - CMakePresets.json + - build.sh + - build.cmd + - vcpkg.json + - .token_helpers/** + - .github/workflows/tests.yml + pull_request: + branches: ["main"] + paths: + - src/** + - include/** + - client-sdk-rust/** + - CMakeLists.txt + - CMakePresets.json + - build.sh + - build.cmd + - vcpkg.json + - .token_helpers/** + - .github/workflows/tests.yml + workflow_dispatch: + +permissions: + contents: read + actions: read + packages: read + +env: + CARGO_TERM_COLOR: always + # vcpkg binary caching for Windows (mirrors builds.yml) + VCPKG_DEFAULT_TRIPLET: x64-windows-static-md + VCPKG_DEFAULT_HOST_TRIPLET: x64-windows-static-md + VCPKG_TARGET_TRIPLET: x64-windows-static-md + +jobs: + test: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + name: linux-x64 + build_cmd: ./build.sh release-tests + e2e-testing: true + - os: ubuntu-24.04-arm + name: linux-arm64 + build_cmd: ./build.sh release-tests + e2e-testing: true + - os: macos-latest-xlarge + name: macos-arm64 + build_cmd: ./build.sh release-tests + e2e-testing: true + - os: macos-26-large + name: macos-x64 + build_cmd: ./build.sh release-tests --macos-arch x86_64 + # See builds.yml for why we pin windows-2022 instead of + # windows-latest (VS 17 vs. VS 18 / Visual Studio 2026). + - os: windows-2022 + name: windows-x64 + build_cmd: .\build.cmd release-tests + + name: Test (${{ matrix.name }}) + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout (with submodules) + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + submodules: recursive + fetch-depth: 1 + + - name: Pull LFS files + run: git lfs pull + + # ---------- vcpkg caching for Windows (mirrors builds.yml) ---------- + - name: Export GitHub Actions cache environment variables + if: runner.os == 'Windows' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Setup vcpkg (Windows only) + if: runner.os == 'Windows' + uses: lukka/run-vcpkg@6fe69898af670ac05f4a8427cc5cff4fb361cee5 # v11.5 + with: + vcpkgGitCommitId: 'fb87e2bb3fe69e16c224989acb5a61349166c782' + + # ---------- OS-specific deps ---------- + - name: Install deps (Ubuntu) + if: runner.os == 'Linux' + run: | + set -eux + sudo apt-get update + sudo apt-get install -y \ + build-essential cmake ninja-build pkg-config \ + llvm-dev libclang-dev clang \ + libva-dev libdrm-dev libgbm-dev libx11-dev libgl1-mesa-dev \ + libxext-dev libxcomposite-dev libxdamage-dev libxfixes-dev \ + libxrandr-dev libxi-dev libxkbcommon-dev \ + libasound2-dev libpulse-dev \ + libssl-dev \ + libprotobuf-dev protobuf-compiler \ + libabsl-dev \ + libwayland-dev libdecor-0-dev \ + libspdlog-dev \ + jq + + - name: Install deps (macOS) + if: runner.os == 'macOS' + run: | + set -eux + brew update + brew install cmake ninja protobuf abseil spdlog jq + + # ---------- Rust toolchain ---------- + - name: Install Rust (stable) + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: stable + + - name: Install Rust cross-compilation target + if: matrix.name == 'macos-x64' + run: rustup target add x86_64-apple-darwin + + # ---------- Cache Cargo ---------- + - name: Cache Cargo + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + workspaces: client-sdk-rust -> target + + # ---------- Build environment setup ---------- + - name: Set Linux build environment + if: runner.os == 'Linux' + run: | + echo "CXXFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV + echo "CFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV + LLVM_VERSION=$(llvm-config --version | cut -d. -f1) + echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> $GITHUB_ENV + + # ---------- Build (release-tests: tests on, examples off) ---------- + - name: Build tests (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + chmod +x build.sh + ${{ matrix.build_cmd }} + + - name: Build tests (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: ${{ matrix.build_cmd }} + + # ---------- Run unit tests ---------- + - name: Run unit tests (Unix) + if: runner.os != 'Windows' + timeout-minutes: 1 + shell: bash + run: | + build-release/bin/livekit_unit_tests \ + --gtest_output=xml:build-release/unit-test-results.xml + + - name: Run unit tests (Windows) + if: runner.os == 'Windows' + timeout-minutes: 1 + shell: pwsh + run: | + build-release\bin\livekit_unit_tests.exe ` + --gtest_output="xml:build-release\unit-test-results.xml" + + # ---------- Install + start livekit-server for integration tests ---------- + - name: Install livekit-server and lk CLI + if: matrix.e2e-testing + shell: bash + run: | + set -euxo pipefail + if [[ "$RUNNER_OS" == "Linux" ]]; then + # Linux: official install scripts. lk's installer parses the GitHub + # API JSON with jq (already installed above). + curl -sSL https://get.livekit.io | bash + curl -sSL https://get.livekit.io/cli | bash + else + # macOS: Homebrew formulas. Server install script aborts on Darwin. + brew install livekit livekit-cli + fi + livekit-server --version + lk --version + + - name: Start livekit-server + if: matrix.e2e-testing + shell: bash + env: + LIVEKIT_CONFIG: "enable_data_tracks: true" + run: | + set -euxo pipefail + # Background the server with nohup so it survives this step's shell + # exit and remains running for the integration-test step. + nohup livekit-server --dev > livekit-server.log 2>&1 & + echo $! > livekit-server.pid + # Port 7880 is a WebSocket endpoint, so a TCP-connect probe is the + # most reliable readiness signal. + for i in $(seq 1 30); do + if nc -z 127.0.0.1 7880 >/dev/null 2>&1; then + echo "livekit-server is ready" + exit 0 + fi + sleep 1 + done + echo "::error::livekit-server failed to start within 30s" + tail -n 200 livekit-server.log || true + exit 1 + + - name: Run integration tests + if: matrix.e2e-testing + timeout-minutes: 5 + shell: bash + env: + RUST_LOG: "metrics=debug" + run: | + set -euo pipefail + source .token_helpers/set_data_track_test_tokens.bash + build-release/bin/livekit_integration_tests \ + --gtest_filter='DataTrackScenarios/DataTrackTransportTest.PublishesAndReceivesFramesEndToEnd/*' \ + --gtest_output=xml:build-release/integration-test-results.xml + + - name: Stop livekit-server + if: always() && matrix.e2e-testing + shell: bash + run: | + if [ -f livekit-server.pid ]; then + kill "$(cat livekit-server.pid)" 2>/dev/null || true + rm -f livekit-server.pid + fi + + - name: Dump livekit-server log on failure + if: failure() && matrix.e2e-testing + shell: bash + run: tail -n 500 livekit-server.log || true + + # ---------- Upload results ---------- + - name: Upload test results + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: test-results-${{ matrix.name }} + path: | + build-release/unit-test-results.xml + build-release/integration-test-results.xml + livekit-server.log + if-no-files-found: ignore + retention-days: 7