From b0a4e2ea93fafc4d65d474f3ada616a0ad5e19d5 Mon Sep 17 00:00:00 2001
From: Ariver <ar@Arm1.local>
Date: Sun, 12 Jul 2026 11:39:35 +0800
Subject: [PATCH] feat: bind helper stream timing markers

---
 run-local.sh |  387 +++++++++++++++++++++++++++++++++---------------------
 1 files changed, 237 insertions(+), 150 deletions(-)

diff --git a/run-local.sh b/run-local.sh
index 2e304e7..337bd55 100755
--- a/run-local.sh
+++ b/run-local.sh
@@ -1,159 +1,246 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
+#!/usr/bin/env bash
+set -euo pipefail
+
 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-WORKSPACE_ROOT="${COMBRABO_VOICE_RUNTIME_HELPER_WORKDIR:-${SCRIPT_DIR}}"
+WORKSPACE_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
 MANIFEST_PATH="${SCRIPT_DIR}/Cargo.toml"
 BINARY_PATH="${SCRIPT_DIR}/target/release/combrabo-voice-runtime-helper"
-DOCKERFILE_PATH="${SCRIPT_DIR}/Dockerfile"
-IMAGE_NAME="${COMBRABO_VOICE_RUNTIME_HELPER_IMAGE:-combrabo-voice-runtime-helper:local}"
-MODE="${COMBRABO_VOICE_RUNTIME_HELPER_MODE:-auto}"
-
-usage() {
-  cat <<'EOF'
-Usage:
-  run-local.sh [--prepare] [--rebuild]
-
-Options:
-  --prepare   Prepare the current helper runtime mode without starting the helper.
-  --rebuild   Force docker image rebuild in docker mode.
-EOF
-}
-
-PREPARE_ONLY=false
-FORCE_REBUILD=false
-
-while [[ $# -gt 0 ]]; do
-  case "$1" in
-    --prepare)
-      PREPARE_ONLY=true
-      shift
-      ;;
-    --rebuild)
-      FORCE_REBUILD=true
-      shift
-      ;;
-    -h|--help)
-      usage
-      exit 0
-      ;;
-    *)
-      echo "Unknown argument: $1" >&2
-      usage >&2
-      exit 1
-      ;;
-  esac
-done
-
-resolve_mode() {
-  local requested="$1"
-  if [[ "${requested}" != "auto" ]]; then
-    printf '%s' "${requested}"
-    return 0
-  fi
-  if [[ "$(uname -s)" == "Darwin" ]] && command -v docker >/dev/null 2>&1; then
-    printf '%s' "docker"
-    return 0
-  fi
-  printf '%s' "host"
-}
-
-prepare_host() {
-  (cd "${SCRIPT_DIR}" && cargo build --release)
-}
-
-prepare_docker() {
-  if ! command -v docker >/dev/null 2>&1; then
-    echo "Docker is required for docker helper mode, but docker is not installed." >&2
-    exit 1
-  fi
-  if [[ "${FORCE_REBUILD}" == "true" ]] || ! docker image inspect "${IMAGE_NAME}" >/dev/null 2>&1; then
-    docker build -t "${IMAGE_NAME}" "${SCRIPT_DIR}"
-  fi
-}
-
-rewrite_livekit_url_for_docker() {
-  local url="$1"
-  if [[ "${url}" =~ ^(ws|wss)://(127\.0\.0\.1|localhost)([:/].*)?$ ]]; then
-    printf '%s://host.docker.internal%s' "${BASH_REMATCH[1]}" "${BASH_REMATCH[3]:-}"
-    return 0
-  fi
-  printf '%s' "${url}"
-}
-
-run_host() {
-  if [[ ! -x "${BINARY_PATH}" ]]; then
-    prepare_host
-  fi
-  exec "${BINARY_PATH}"
-}
-
-run_docker() {
-  prepare_docker
-  local livekit_url="${CV_LIVEKIT_URL:-}"
-  local -a docker_args
-  docker_args=(
-    --rm
-    --name "cv-helper-${CV_CALL_ID:-manual}"
+DOCKERFILE_PATH="${SCRIPT_DIR}/Dockerfile"
+IMAGE_NAME="${COMBRABO_VOICE_RUNTIME_HELPER_IMAGE:-combrabo-voice-runtime-helper:local}"
+MODE="${COMBRABO_VOICE_RUNTIME_HELPER_MODE:-auto}"
+
+usage() {
+  cat <<'EOF'
+Usage:
+  run-local.sh [--prepare] [--rebuild]
+
+Options:
+  --prepare   Prepare the current helper runtime mode without starting the helper.
+  --rebuild   Force docker image rebuild in docker mode.
+EOF
+}
+
+PREPARE_ONLY=false
+FORCE_REBUILD=false
+
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+    --prepare)
+      PREPARE_ONLY=true
+      shift
+      ;;
+    --rebuild)
+      FORCE_REBUILD=true
+      shift
+      ;;
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    *)
+      echo "Unknown argument: $1" >&2
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+resolve_mode() {
+  local requested="$1"
+  if [[ "${requested}" != "auto" ]]; then
+    printf '%s' "${requested}"
+    return 0
+  fi
+  if [[ "$(uname -s)" == "Darwin" ]] && command -v docker >/dev/null 2>&1; then
+    printf '%s' "docker"
+    return 0
+  fi
+  printf '%s' "host"
+}
+
+prepare_host() {
+  (cd "${SCRIPT_DIR}" && cargo build --release)
+}
+
+prepare_docker() {
+  if ! command -v docker >/dev/null 2>&1; then
+    echo "Docker is required for docker helper mode, but docker is not installed." >&2
+    exit 1
+  fi
+  if [[ "${FORCE_REBUILD}" == "true" ]] || ! docker image inspect "${IMAGE_NAME}" >/dev/null 2>&1; then
+    docker build -t "${IMAGE_NAME}" "${SCRIPT_DIR}"
+  fi
+}
+
+rewrite_livekit_url_for_docker() {
+  local url="$1"
+  if [[ "${url}" =~ ^(ws|wss)://(127\.0\.0\.1|localhost)([:/].*)?$ ]]; then
+    printf '%s://host.docker.internal%s' "${BASH_REMATCH[1]}" "${BASH_REMATCH[3]:-}"
+    return 0
+  fi
+  printf '%s' "${url}"
+}
+
+rewrite_http_url_for_docker() {
+  local url="$1"
+  if [[ "${url}" =~ ^(http|https)://(127\.0\.0\.1|localhost)([:/].*)?$ ]]; then
+    printf '%s://host.docker.internal%s' "${BASH_REMATCH[1]}" "${BASH_REMATCH[3]:-}"
+    return 0
+  fi
+  printf '%s' "${url}"
+}
+
+is_truthy() {
+  case "${1:-}" in
+    true|TRUE|1|yes|YES|on|ON)
+      return 0
+      ;;
+    *)
+      return 1
+      ;;
+  esac
+}
+
+docker_service_host() {
+  local bind_addr="${1:-127.0.0.1:18080}"
+  if [[ "${bind_addr}" =~ ^([^:]+):([0-9]+)$ ]]; then
+    printf '%s' "${BASH_REMATCH[1]}"
+    return 0
+  fi
+  printf '%s' "127.0.0.1"
+}
+
+docker_service_port() {
+  local bind_addr="${1:-127.0.0.1:18080}"
+  if [[ "${bind_addr}" =~ ^([^:]+):([0-9]+)$ ]]; then
+    printf '%s' "${BASH_REMATCH[2]}"
+    return 0
+  fi
+  printf '%s' "18080"
+}
+
+run_host() {
+  if [[ ! -x "${BINARY_PATH}" ]]; then
+    prepare_host
+  fi
+  exec "${BINARY_PATH}"
+}
+
+run_docker() {
+  prepare_docker
+  local livekit_url="${CV_LIVEKIT_URL:-}"
+  local -a docker_args
+  docker_args=(
+    --rm
+    --name "cv-helper-${CV_CALL_ID:-manual}"
     -v "${WORKSPACE_ROOT}:${WORKSPACE_ROOT}"
-    -w "${WORKSPACE_ROOT}"
-    -e CV_CALL_ID
-    -e CV_TRACE_ID
-    -e CV_GAME_MATCH_ID
-    -e CV_LIVEKIT_URL
-    -e CV_LIVEKIT_ROOM_ID
-    -e CV_LIVEKIT_BOT_TOKEN
-    -e CV_LIVEKIT_BOT_PARTICIPANT_IDENTITY
-    -e CV_LIVEKIT_USER_PARTICIPANT_IDENTITY
-    -e CV_FIRST_AUDIO_SOURCE
+    -w "${WORKSPACE_ROOT}"
+    -e CV_CALL_ID
+    -e CV_TRACE_ID
+    -e CV_GAME_MATCH_ID
+    -e CV_LIVEKIT_URL
+    -e CV_LIVEKIT_ROOM_ID
+    -e CV_LIVEKIT_BOT_TOKEN
+    -e CV_LIVEKIT_BOT_PARTICIPANT_IDENTITY
+    -e CV_LIVEKIT_USER_PARTICIPANT_IDENTITY
+    -e CV_FIRST_AUDIO_SOURCE
     -e CV_GREETING_SOURCE
     -e CV_GREETING_AUDIO_FILE
     -e CV_GREETING_AUDIO_URL
     -e CV_GREETING_TEXT
-    -e CV_ROLE_ID
-    -e CV_DEVICE_OUTPUT_SMOKE_ENABLED
-    -e CV_DEVICE_OUTPUT_DESTINATION_IDENTITIES
+    -e CV_AUDIO_DEBUG_DUMP_DIR
+    -e CV_ENABLE_USER_AUDIO_OBSERVER
+    -e CV_ENABLE_SIMPLE_VAD
+    -e CV_VAD_RMS_THRESHOLD
+    -e CV_VAD_PEAK_THRESHOLD
+    -e CV_VAD_START_FRAMES
+    -e CV_VAD_END_SILENCE_MS
+    -e CV_VAD_MIN_SPEECH_MS
+    -e CV_VAD_MAX_TURN_MS
+    -e CV_VAD_INITIAL_IGNORE_MS
+    -e CV_VAD_GATE_UNTIL_GREETING_DONE
+    -e CV_VAD_POST_GREETING_DELAY_MS
+    -e CV_RUNTIME_TURN_BRIDGE_URL
+    -e CV_RUNTIME_TURN_BRIDGE_TOKEN
+    -e CV_RUNTIME_TURN_ARTIFACT_DIR
+    -e CV_RUNTIME_SESSION_NONCE
+    -e CV_HELPER_SERVICE_ENABLED
+    -e CV_HELPER_SERVICE_BIND
+    -e CV_HELPER_AUTH_TOKEN
+    -e CV_HELPER_AUTH_TOKEN_LOCAL_DEV
+    -e CV_TURN_BRIDGE_TOKEN_LOCAL_DEV
+    -e CV_HELPER_AUTH_TOKEN_DEV
+    -e CV_TURN_BRIDGE_TOKEN_DEV
   )
-  if [[ -n "${livekit_url}" ]]; then
-    export CV_LIVEKIT_URL="$(rewrite_livekit_url_for_docker "${livekit_url}")"
-  fi
-  if [[ -n "${CV_GREETING_AUDIO_FILE:-}" && -f "${CV_GREETING_AUDIO_FILE}" ]]; then
-    local audio_parent
-    audio_parent="$(cd "$(dirname "${CV_GREETING_AUDIO_FILE}")" && pwd)"
-    if [[ "${audio_parent}" != "${WORKSPACE_ROOT}" && "${audio_parent}" != "${WORKSPACE_ROOT}/"* ]]; then
-      docker_args+=(-v "${audio_parent}:${audio_parent}:ro")
-    fi
-  fi
-  exec docker run "${docker_args[@]}" "${IMAGE_NAME}"
-}
-
-RUNTIME_MODE="$(resolve_mode "${MODE}")"
-
-if [[ "${PREPARE_ONLY}" == "true" ]]; then
-  case "${RUNTIME_MODE}" in
-    host)
-      prepare_host
-      ;;
-    docker)
-      prepare_docker
-      ;;
-    *)
-      echo "Unsupported helper mode: ${RUNTIME_MODE}" >&2
-      exit 1
-      ;;
-  esac
-  exit 0
-fi
-
-case "${RUNTIME_MODE}" in
-  host)
-    run_host
-    ;;
-  docker)
-    run_docker
-    ;;
-  *)
-    echo "Unsupported helper mode: ${RUNTIME_MODE}" >&2
-    exit 1
-    ;;
-esac
+  if is_truthy "${CV_HELPER_SERVICE_ENABLED:-}"; then
+    local service_bind service_host service_port
+    service_bind="${CV_HELPER_SERVICE_BIND:-127.0.0.1:18080}"
+    service_host="$(docker_service_host "${service_bind}")"
+    service_port="$(docker_service_port "${service_bind}")"
+    export CV_HELPER_SERVICE_BIND="0.0.0.0:${service_port}"
+    docker_args+=(-p "${service_host}:${service_port}:${service_port}")
+  fi
+  if [[ -n "${livekit_url}" ]]; then
+    export CV_LIVEKIT_URL="$(rewrite_livekit_url_for_docker "${livekit_url}")"
+  fi
+  if [[ -n "${CV_RUNTIME_TURN_BRIDGE_URL:-}" ]]; then
+    export CV_RUNTIME_TURN_BRIDGE_URL="$(rewrite_http_url_for_docker "${CV_RUNTIME_TURN_BRIDGE_URL}")"
+  fi
+  if [[ -n "${CV_GREETING_AUDIO_FILE:-}" && -f "${CV_GREETING_AUDIO_FILE}" ]]; then
+    local audio_parent
+    audio_parent="$(cd "$(dirname "${CV_GREETING_AUDIO_FILE}")" && pwd)"
+    if [[ "${audio_parent}" != "${WORKSPACE_ROOT}" && "${audio_parent}" != "${WORKSPACE_ROOT}/"* ]]; then
+      docker_args+=(-v "${audio_parent}:${audio_parent}:ro")
+    fi
+  fi
+  if [[ -n "${CV_AUDIO_DEBUG_DUMP_DIR:-}" ]]; then
+    mkdir -p "${CV_AUDIO_DEBUG_DUMP_DIR}"
+    local debug_dump_dir
+    debug_dump_dir="$(cd "${CV_AUDIO_DEBUG_DUMP_DIR}" && pwd)"
+    export CV_AUDIO_DEBUG_DUMP_DIR="${debug_dump_dir}"
+    if [[ "${debug_dump_dir}" != "${WORKSPACE_ROOT}" && "${debug_dump_dir}" != "${WORKSPACE_ROOT}/"* ]]; then
+      docker_args+=(-v "${debug_dump_dir}:${debug_dump_dir}")
+    fi
+  fi
+  if [[ -n "${CV_RUNTIME_TURN_ARTIFACT_DIR:-}" ]]; then
+    mkdir -p "${CV_RUNTIME_TURN_ARTIFACT_DIR}"
+    local turn_artifact_dir
+    turn_artifact_dir="$(cd "${CV_RUNTIME_TURN_ARTIFACT_DIR}" && pwd)"
+    export CV_RUNTIME_TURN_ARTIFACT_DIR="${turn_artifact_dir}"
+    if [[ "${turn_artifact_dir}" != "${WORKSPACE_ROOT}" && "${turn_artifact_dir}" != "${WORKSPACE_ROOT}/"* ]]; then
+      docker_args+=(-v "${turn_artifact_dir}:${turn_artifact_dir}")
+    fi
+  fi
+  exec docker run "${docker_args[@]}" "${IMAGE_NAME}"
+}
+
+RUNTIME_MODE="$(resolve_mode "${MODE}")"
+
+if [[ "${PREPARE_ONLY}" == "true" ]]; then
+  case "${RUNTIME_MODE}" in
+    host)
+      prepare_host
+      ;;
+    docker)
+      prepare_docker
+      ;;
+    *)
+      echo "Unsupported helper mode: ${RUNTIME_MODE}" >&2
+      exit 1
+      ;;
+  esac
+  exit 0
+fi
+
+case "${RUNTIME_MODE}" in
+  host)
+    run_host
+    ;;
+  docker)
+    run_docker
+    ;;
+  *)
+    echo "Unsupported helper mode: ${RUNTIME_MODE}" >&2
+    exit 1
+    ;;
+esac

--
Gitblit v1.9.3