From 5cc2685f03f892cb2a5ca1e60b4d440f70ed9818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=B7=A5=E7=A8=8B=E5=B8=88?= Date: Tue, 18 Aug 2026 00:31:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(livekit):=20=E7=BB=9F=E4=B8=80=E4=BF=A1?= =?UTF-8?q?=E4=BB=A4/=E5=AA=92=E4=BD=93=E7=AB=AF=E5=8F=A3=E4=B8=BA=2017880?= =?UTF-8?q?/17881/17882=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=90=AC?= =?UTF-8?q?=E5=90=8E=E5=8F=8C=E6=96=B9=E7=BD=91=E7=BB=9C=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:LiveKit 的 config/livekit.yaml 媒体端口(7881/7882)与宿主实际映射(17881/17882)不一致, 信令走 17880 能通,但媒体被宣告到 7881/7882 连不上。 - config/livekit.yaml: port/tcp_port/udp_port -> 17880/17881/17882 - docker-compose.yaml: 容器侧端口与宿主侧一致(1788x),不再重映射 - .env.example: 默认端口改为 1788x 并注明三处需一致 - scripts/selftest.sh: LK_PORT 默认值改为 17880 - scripts/fix-livekit-ports.sh: 一键备份+对齐 .env+仅重建 livekit 的修复脚本 - README: 更新端口表、客户端接入参数与排障说明 Co-authored-by: multica-agent --- .env.example | 10 ++++--- README.md | 12 ++++---- config/livekit.yaml | 13 +++++++-- docker-compose.yaml | 10 ++++--- scripts/fix-livekit-ports.sh | 56 ++++++++++++++++++++++++++++++++++++ scripts/selftest.sh | 2 +- 6 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 scripts/fix-livekit-ports.sh diff --git a/.env.example b/.env.example index 1f74bbe..4a3bf06 100644 --- a/.env.example +++ b/.env.example @@ -65,10 +65,12 @@ LOG_LEVEL=3 LIVEKIT_API_KEY=openimLKkey # secret 必须 ≥32 字符,否则 LiveKit 启动报 secret is too short LIVEKIT_API_SECRET=lk-secret-9f2c7a41d5e8b063f1a4c795e2d8b3a6 -# 三个都是宿主机映射端口;7880/7881/7882 被占用时改成 17880/17881/17882 之类即可 -LIVEKIT_PORT=7880 -LIVEKIT_RTC_TCP_PORT=7881 -LIVEKIT_RTC_UDP_PORT=7882 +# 三个端口必须与 config/livekit.yaml 的 port/tcp_port/udp_port 完全一致, +# 且与 docker-compose.yaml 的“宿主侧=容器侧”保持一致(默认 17880/17881/17882)。 +# 改端口时三个文件要一起改,否则语音通话会出现“能接听但双方网络错误”。 +LIVEKIT_PORT=17880 +LIVEKIT_RTC_TCP_PORT=17881 +LIVEKIT_RTC_UDP_PORT=17882 # ===== 公司账号服务(工号+密码登录,自研)===== # 宿主端口;管理页 http://:10010/ diff --git a/README.md b/README.md index eb29280..6e15253 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ | 10002 | TCP/HTTP | OpenIM REST API | | 10005 | TCP/HTTP | MinIO(图片/语音/文件下载) | | 10010 | TCP/HTTP | 公司账号服务(员工登录接口 + 管理页) | -| 7880 | TCP/WS | LiveKit 信令(`.env` 的 `LIVEKIT_PORT` 可改) | -| 7882 | UDP | LiveKit 语音媒体(`LIVEKIT_RTC_UDP_PORT` 可改) | -| 7881 | TCP | LiveKit 媒体备用通道(`LIVEKIT_RTC_TCP_PORT` 可改) | +| 17880 | TCP/WS | LiveKit 信令(`.env` 的 `LIVEKIT_PORT` 可改,但必须与 `config/livekit.yaml` 一致) | +| 17882 | UDP | LiveKit 语音媒体(`LIVEKIT_RTC_UDP_PORT` 可改,同上) | +| 17881 | TCP | LiveKit 媒体备用通道(`LIVEKIT_RTC_TCP_PORT` 可改,同上) | | 10004 | TCP/HTTP | MinIO 控制台(运维用,可不开放) | | 12379/12380 | TCP | Etcd(仅容器间用,建议不对外) | @@ -79,7 +79,7 @@ docker compose up -d # 再启动 - OpenIM API: `http://<服务器IP>:10002` - OpenIM WebSocket: `ws://<服务器IP>:10001` -- LiveKit: `ws://<服务器IP>:7880`(7880 为默认信令端口,可用 `.env` 的 `LIVEKIT_PORT` 改),API Key/Secret 见 `.env` 的 `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET` +- LiveKit: `ws://<服务器IP>:17880`(17880 为默认信令端口;改端口时必须 `.env` 的 `LIVEKIT_PORT`、`config/livekit.yaml` 的 `port`、`docker-compose.yaml` 的容器侧端口三者一起改),API Key/Secret 见 `.env` 的 `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET` - 测试账号:`test001` / `test002`(由自测脚本注册);语音通话时两名用户以各自 identity 进同一房间即可 ## 常见问题 @@ -87,6 +87,6 @@ docker compose up -d # 再启动 - **文件/语音能发但打不开**:`MINIO_EXTERNAL_ADDRESS` 没写成客户端能访问的 IP。改 `.env` 后 `docker compose up -d` 重建 openim-server。 - **启动报缺 `ETCD_USERNAME` / `KAFKA_USERNAME` 等警告**:未启用对应组件认证,官方说明可忽略。 - **openim-server 一直 unhealthy**:`docker exec -it openim-server mage check` 看哪项依赖没通;首次启动需等 30-60 秒。 -- **livekit 启动报 `bind ... 7880/7881: address already in use`**:服务器上这些端口被别的程序占了(`ss -tlnp | grep 788` 查占用者)。不要动别人的服务,把 `.env` 里 `LIVEKIT_PORT` / `LIVEKIT_RTC_TCP_PORT` / `LIVEKIT_RTC_UDP_PORT` 改成空闲端口(如 17880/17881/17882),再 `docker compose up -d --force-recreate livekit`。之后客户端和自测脚本都用新端口(自测脚本会自动读 `.env`)。 +- **livekit 启动报 `bind ... 7880/7881: address already in use`**:服务器上这些端口被别的程序占了(`ss -tlnp | grep 788` 查占用者)。不要动别人的服务,把端口统一改成空闲端口(如 17880/17881/17882)——注意**必须三处一起改**:`.env` 的 `LIVEKIT_PORT` / `LIVEKIT_RTC_TCP_PORT` / `LIVEKIT_RTC_UDP_PORT`、`config/livekit.yaml` 的 `port` / `tcp_port` / `udp_port`、`docker-compose.yaml` 里 livekit 的容器侧端口(保持“宿主侧=容器侧”),然后 `docker compose up -d --force-recreate livekit`。只改其中一两处会导致“能邀请、能接听,但接听后双方网络错误”。 - **livekit 日志报 `secret is too short`**:`LIVEKIT_API_SECRET` 必须 ≥32 字符,换个长密钥后重建 livekit 容器。 -- **语音通话连不上**:确认服务器 UDP 7882 放行(内网防火墙/安全组);UDP 不通时会走 TCP 7881 兜底。 +- **语音通话连不上(接听后双方网络错误)**:先确认 `.env` / `config/livekit.yaml` / `docker-compose.yaml` 三处端口一致;再确认服务器防火墙放通 `LIVEKIT_PORT`(TCP)、`LIVEKIT_RTC_TCP_PORT`(TCP)、`LIVEKIT_RTC_UDP_PORT`(UDP)(默认 17880/17881/17882)。UDP 不通时会走 TCP 兜底。 diff --git a/config/livekit.yaml b/config/livekit.yaml index 56a2bfe..7d4bd76 100644 --- a/config/livekit.yaml +++ b/config/livekit.yaml @@ -1,10 +1,17 @@ # LiveKit 服务端配置(内网部署) # API Key/Secret 通过环境变量 LIVEKIT_KEYS 注入(见 docker-compose.yaml) # 服务器对内 IP 通过启动参数 --node-ip 注入(deploy.sh 写入 .env 的 SERVER_IP) -port: 7880 +# +# 重要:这里的 port / tcp_port / udp_port 必须与 docker-compose.yaml 里 +# 容器侧端口、以及 .env 的 LIVEKIT_PORT / LIVEKIT_RTC_TCP_PORT / +# LIVEKIT_RTC_UDP_PORT 三者完全一致(默认 17880/17881/17882)。 +# LiveKit 用 --node-ip + use_external_ip:false 向客户端宣告媒体地址时, +# 只会宣告这里的端口,不会感知 Docker 宿主侧的重映射;三者不一致会导致 +# “能邀请、能接听,但接听后双方网络错误”(信令通、媒体不通)。 +port: 17880 rtc: - tcp_port: 7881 - udp_port: 7882 + tcp_port: 17881 + udp_port: 17882 # 内网部署:不做公网 IP 探测,candidate 直接使用 --node-ip use_external_ip: false room: diff --git a/docker-compose.yaml b/docker-compose.yaml index fdcc605..13c4e0f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -370,7 +370,9 @@ services: # LiveKit:语音/视频通话的 SFU,Apache 2.0,自部署。 # 客户端通过 ws://: 连接,凭 LIVEKIT_API_KEY/SECRET 签发的 token 进房。 - # 三个宿主端口都可在 .env 调整(7880/7881/7882 被其他服务占用时改映射即可,容器内端口不变)。 + # 三个端口必须与 config/livekit.yaml 里容器监听的端口完全一致(默认 17880/17881/17882), + # 即“宿主侧 = 容器侧”,不要在宿主侧做重映射;LiveKit 向客户端宣告媒体地址时只认 + # config/livekit.yaml 里的端口,重映射会导致信令通、媒体不通。 livekit: image: ${LIVEKIT_IMAGE} container_name: livekit @@ -379,9 +381,9 @@ services: environment: LIVEKIT_KEYS: "${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}" ports: - - "${LIVEKIT_PORT:-7880}:7880" # HTTP / WebSocket 信令 - - "${LIVEKIT_RTC_TCP_PORT:-7881}:7881" # RTC over TCP(UDP 不通时的备用通道) - - "${LIVEKIT_RTC_UDP_PORT:-7882}:7882/udp" # RTC 媒体(UDP 复用端口) + - "${LIVEKIT_PORT:-17880}:17880" # HTTP / WebSocket 信令 + - "${LIVEKIT_RTC_TCP_PORT:-17881}:17881" # RTC over TCP(UDP 不通时的备用通道) + - "${LIVEKIT_RTC_UDP_PORT:-17882}:17882/udp" # RTC 媒体(UDP 复用端口) volumes: - ./config/livekit.yaml:/etc/livekit.yaml networks: diff --git a/scripts/fix-livekit-ports.sh b/scripts/fix-livekit-ports.sh new file mode 100644 index 0000000..70af1eb --- /dev/null +++ b/scripts/fix-livekit-ports.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# 修复语音通话“门号不一致”(信令通、媒体不通)问题。 +# 根因:LiveKit 的 config/livekit.yaml 里媒体端口(7881/7882)与宿主实际映射(17881/17882)不一致, +# 导致 LiveKit 向客户端宣告的媒体地址连不上。 +# 修复:统一 .env / config/livekit.yaml / docker-compose.yaml 三处端口为 17880/17881/17882, +# 只重启 livekit 容器。 +# +# 用法(在服务器仓库目录里执行,且已 git pull 到含本修复的版本): +# ./scripts/fix-livekit-ports.sh +# +# 该脚本幂等,可重复执行;会先备份再改动,失败可回退。 +set -euo pipefail +cd "$(dirname "$0")/.." + +TS="$(date +%Y%m%d-%H%M%S)" +BK="backup-livekit-ports-$TS" +mkdir -p "$BK" +echo "==> 备份当前配置到 $BK/" +for f in .env config/livekit.yaml docker-compose.yaml; do + [ -f "$f" ] && cp -p "$f" "$BK/$(basename "$f")" +done +[ -f "$BK/.env" ] || echo "(未找到 .env,跳过备份)" + +# 1. 校验仓库文件已含修复(config/livekit.yaml 端口应为 17880/17881/17882) +grep -q '^port: 17880' config/livekit.yaml || { echo "✗ config/livekit.yaml 未包含 port: 17880,请先 git pull 更新仓库后再执行本脚本"; exit 1; } +grep -q 'tcp_port: 17881' config/livekit.yaml || { echo "✗ config/livekit.yaml 未包含 tcp_port: 17881"; exit 1; } +grep -q 'udp_port: 17882' config/livekit.yaml || { echo "✗ config/livekit.yaml 未包含 udp_port: 17882"; exit 1; } + +# 2. 对齐 .env 三个端口 +if [ ! -f .env ]; then + cp .env.example .env + echo "==> 未找到 .env,已从 .env.example 生成" +fi +sed -i 's|^LIVEKIT_PORT=.*|LIVEKIT_PORT=17880|' .env +sed -i 's|^LIVEKIT_RTC_TCP_PORT=.*|LIVEKIT_RTC_TCP_PORT=17881|' .env +sed -i 's|^LIVEKIT_RTC_UDP_PORT=.*|LIVEKIT_RTC_UDP_PORT=17882|' .env +# 若这三行原本不存在,则追加 +grep -q '^LIVEKIT_PORT=' .env || echo 'LIVEKIT_PORT=17880' >> .env +grep -q '^LIVEKIT_RTC_TCP_PORT=' .env || echo 'LIVEKIT_RTC_TCP_PORT=17881' >> .env +grep -q '^LIVEKIT_RTC_UDP_PORT=' .env || echo 'LIVEKIT_RTC_UDP_PORT=17882' >> .env +echo "==> .env 三个端口已设为 17880/17881/17882" + +# 3. 只重建 livekit 容器(不动其它服务) +docker compose up -d --force-recreate livekit + +# 4. 校验 +echo "==> 等待 livekit 就绪..." +sleep 3 +docker compose ps livekit +echo +echo "==> 请确认防火墙放通 17880/TCP、17881/TCP、17882/UDP(默认已在本机监听):" +ss -tlnp 2>/dev/null | grep -E ':(17880|17881)' || true +ss -ulnp 2>/dev/null | grep ':17882' || true +echo +echo "==> 完成。回退方法:" +echo " cp $BK/.env .env 2>/dev/null; git checkout -- config/livekit.yaml docker-compose.yaml; docker compose up -d --force-recreate livekit" diff --git a/scripts/selftest.sh b/scripts/selftest.sh index 48434db..415ecfb 100755 --- a/scripts/selftest.sh +++ b/scripts/selftest.sh @@ -18,7 +18,7 @@ MINIO_SK="$(env_get MINIO_SECRET_ACCESS_KEY)"; MINIO_SK="${MINIO_SK:-openIM123}" MINIO_PORT="$(env_get MINIO_PORT)"; MINIO_PORT="${MINIO_PORT:-10005}" LK_KEY="$(env_get LIVEKIT_API_KEY)" LK_SECRET="$(env_get LIVEKIT_API_SECRET)" -LK_PORT="$(env_get LIVEKIT_PORT)"; LK_PORT="${LK_PORT:-7880}" +LK_PORT="$(env_get LIVEKIT_PORT)"; LK_PORT="${LK_PORT:-17880}" LK_HTTP="http://${IP}:${LK_PORT}" LK_WS="ws://${IP}:${LK_PORT}" LK_CLI_IMAGE="livekit/livekit-cli:v2.18.2"