Commit e509c8a95825cea371b3271752bdb1f689955165
1 parent
2558d8c8
fix(im): 修复 LiveKit 本地媒体连接与房间管理权限
- 修正 Docker Desktop 媒体候选地址 - 为管理 Token 增加房间级 roomAdmin 权限 - 更新 LiveKit PoC 配置说明
Showing
3 changed files
with
10 additions
and
4 deletions
script/livekit-poc/README.md
| ... | ... | @@ -15,7 +15,7 @@ bash verify.sh |
| 15 | 15 | - 7880:HTTP / WebSocket 信令; |
| 16 | 16 | - 7881:WebRTC TCP fallback; |
| 17 | 17 | - 7882/UDP:WebRTC 媒体; |
| 18 | -- macOS / Windows:当前 `docker-compose.yml` 走端口映射模式,webhook URL 用 `host.docker.internal:48080` 让容器访问到宿主机 yudao 后端; | |
| 18 | +- macOS / Windows:当前 `docker-compose.yml` 走端口映射模式,`rtc.node_ip` 使用 `127.0.0.1` 让浏览器访问映射后的媒体端口,webhook URL 用 `host.docker.internal:48080` 让容器访问到宿主机 yudao 后端; | |
| 19 | 19 | - macOS 上 host network(`network_mode: host`)需要 Docker Desktop 4.34+ 并在 Settings → Resources → Network 勾选「Enable host networking」,老版本静默失败(容器跑得起来但端口完全不通); |
| 20 | 20 | - Linux:可以把 `docker-compose.yml` 改成 `network_mode: host` + 删 `ports:` 段,并把 `livekit.yaml` 的 webhook URL 改为 `http://127.0.0.1:48080/admin-api/im/livekit/webhook`。 |
| 21 | 21 | ... | ... |
script/livekit-poc/livekit.yaml
| ... | ... | @@ -10,6 +10,8 @@ rtc: |
| 10 | 10 | tcp_port: 7881 |
| 11 | 11 | udp_port: 7882 |
| 12 | 12 | use_external_ip: false |
| 13 | + # macOS / Windows 端口映射模式下显式广播宿主机回环地址,避免把容器 172.x 地址发给浏览器 | |
| 14 | + node_ip: 127.0.0.1 | |
| 13 | 15 | |
| 14 | 16 | # Webhook:成员离开 / 房间结束等事件回调到 yudao 后端做业务态兜底清理 |
| 15 | 17 | # host.docker.internal 让容器访问宿主机 macOS / Windows 上的 yudao 后端 | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java
| ... | ... | @@ -208,17 +208,21 @@ public class LiveKitClient { |
| 208 | 208 | /** |
| 209 | 209 | * 签发管理 Token;用于调 Server API(DeleteRoom / ListParticipants / RemoveParticipant 等) |
| 210 | 210 | * |
| 211 | + * @param room 房间名;LiveKit 的 roomAdmin 权限必须限定到具体房间 | |
| 211 | 212 | * @return JWT 字符串 |
| 212 | 213 | */ |
| 213 | - private String signAdminToken() { | |
| 214 | + private String signAdminToken(String room) { | |
| 214 | 215 | ImProperties.Rtc cfg = imProperties.getRtc(); |
| 215 | 216 | // roomAdmin claim 给管理类 API 必备 |
| 217 | + Map<String, Object> video = new HashMap<>(); | |
| 218 | + video.put("roomAdmin", true); | |
| 219 | + video.put("room", room); | |
| 216 | 220 | long nowSec = Instant.now().getEpochSecond(); |
| 217 | 221 | return JWT.create() |
| 218 | 222 | .setIssuer(cfg.getApiKey()) |
| 219 | 223 | .setNotBefore(new Date(nowSec * 1000)) |
| 220 | 224 | .setExpiresAt(new Date((nowSec + ADMIN_TOKEN_TTL.getSeconds()) * 1000)) |
| 221 | - .setPayload("video", MapUtil.of("roomAdmin", true)) | |
| 225 | + .setPayload("video", video) | |
| 222 | 226 | .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes(StandardCharsets.UTF_8))) |
| 223 | 227 | .sign(); |
| 224 | 228 | } |
| ... | ... | @@ -232,7 +236,7 @@ public class LiveKitClient { |
| 232 | 236 | */ |
| 233 | 237 | private HttpResponse postTwirp(String path, String room) { |
| 234 | 238 | Assert.notBlank(room, "room 不可为空"); |
| 235 | - String token = signAdminToken(); | |
| 239 | + String token = signAdminToken(room); | |
| 236 | 240 | return HttpRequest.post(HttpUtils.wsUrlToHttp(imProperties.getRtc().getLivekitUrl()) + path) |
| 237 | 241 | .header("Authorization", "Bearer " + token) |
| 238 | 242 | .header("Content-Type", "application/json") | ... | ... |