Hi guys, I meet some trouble, when try to connect ...
# ask-ai
r
Hi guys, I meet some trouble, when try to connect the livekit from esp32. I am testing
livekit/livekit=0.3.6
on an ESP32-S3 Lichuang board. Current setup: - Board:
lichuang_esp32s3
- ESP-IDF:
v5.5.3
- SDK dependency:
livekit/livekit=0.3.6
- LiveKit Cloud URL:
<wss://bo-996enr6g.livekit.cloud>
- Auth during development: LiveKit sandbox token server - Agent dispatch:
Jordan-19de
- ICE setting: relay-only enabled I already confirmed these parts are working: - Wi-Fi connects successfully - The device gets an IP address, for example
10.0.0.44
- LiveKit signaling connects successfully - TLS certificate validation succeeds -
401 Unauthorized
is no longer happening after switching away from an embedded expiring JWT - A desktop client on the same network can join the same LiveKit project and talk to the same agent normally The remaining problem is that the ESP32 reaches the RTC phase, then disconnects and starts reconnecting. Representative serial log sequence:
Copy code
text
livekit_signaling: Connecting to server: <wss://bo-996enr6g.livekit.cloud/rtc>?...
esp-x509-crt-bundle: Certificate validated
DTLS: Init SRTP OK
livekit_engine: Subscribing to audio track
AGENT: Start agent as Controlling/Controlled
Get candidate success ...
TURN relay candidates acquired from 140.238.63.214:...
Skip TCP stun server turns:otokyo1b.turn.livekit.cloud:443?transport=tcp
Skip TCP stun server turns:bo-996enr6g.turn.livekit.cloud:443?transport=tcp
publisher offer generated
subscriber answer generated
peer state: 1 -> 4
transport_ws: esp_transport_ws_poll_connection_closed: unexpected data readable on socket=54
websocket_client: Connection terminated while waiting for clean TCP close
UDP: Failed to select: Bad file number
livekit_engine: Reconnect ... reason=4
livekit_room_v2: Failure reason: RTC
What seems important to me: - This is no longer an auth problem. - The device gets past signaling and into DTLS/SRTP and ICE/TURN work. - TURN relay candidates are acquired successfully. - The failure seems to happen after SDP exchange begins and peer state advances. - Then the WebSocket side closes unexpectedly, and sometimes the UDP path reports
Bad file number
. My questions: 1. Is this a known issue or limitation for
livekit/livekit=0.3.6
on ESP32-S3? 2. Are there recommended
esp_peer
/ ICE settings for LiveKit Cloud on ESP32-S3, especially for relay-only mode? 3. Is skipping TCP TURN candidates expected here, or could that be related? 4. Does
transport_ws: unexpected data readable on socket
usually indicate a signaling transport problem, or is it often secondary to an RTC teardown? 5. Has anyone seen
UDP: Failed to select: Bad file number
in the ESP32 client during reconnect or peer restart? Any pointers on where to inspect next in
esp_peer
, ICE transport, or the LiveKit ESP32 client would help.
✅ 1
t
Thanks for reaching out, dean. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — this is a very clear report and the logs help a lot. I’ll respond to each of your numbered questions, point out the likely causes, and give next steps and focused diagnostics you can run on the ESP32 to narrow this down. Quick acknowledgement of what I’m responding to • You’ve confirmed signaling, TLS validation, DTLS/SRTP init, and TURN relay candidates succeed, but the device reaches RTC state then disconnects and reconnects. The key symptoms are the WebSocket closing with “unexpected data readable on socket” and occasional “UDP: Failed to select: Bad file number.” Answers and guidance 1) Is this a known issue or limitation for livekit/livekit=0.3.6 on ESP32‑S3? • There is no explicit confirmation that 0.3.6 has a known, documented bug that causes this exact RTC teardown on ESP32‑S3. The ESP32 SDK integration is optimized for constrained devices and can be sensitive to underlying WebRTC/esp_peer and network stack behavior. • What I can say: ESP32 deployments are more likely to run into resource / socket lifecycle issues during ICE/DTLS transitions or reconnections. That makes it plausible the behavior is caused by the embedded stack (esp_peer/esp-idf/LWIP) encountering socket state or descriptor issues during the SDP/ICE finalization or shortly after. 2) Recommended esp_peer / ICE settings for LiveKit Cloud on ESP32‑S3, especially relay‑only • Relay-only mode is supported and TURN relay candidates are expected when you force relay. • Recommended checks and settings: ◦ Prefer TURN over TLS (443) if you must traverse firewalls — ensure TLS TURN is reachable from the device. ◦ Keep ICE timeouts and retransmit values conservative for constrained devices (increase timeouts slightly so ICE/DTLS have time to complete under CPU/network load). ◦ Ensure the esp_peer/esp-idf components are up-to-date (esp_peer and WebRTC layers receive fixes that affect stability). ◦ Limit simultaneous heavy operations during ICE/DTLS handshake (e.g., avoid CPU-heavy tasks while the peer state is transitioning). • I can help suggest exact esp_peer option names/settings if you share the current ICE and esp_peer configuration you’re using. 3) Is skipping TCP TURN candidates expected here, or could that be related? • Skipping TCP TURN candidates can be expected depending on how the esp_peer stack is configured. Many embedded stacks prioritize UDP/UDP-TURN and may skip TCP variants unless explicitly enabled. • If your network blocks UDP and you rely on TCP/TLS TURN, skipping TCP TURN candidates would be a problem — verify whether TCP/TLS TURN is enabled and allowed by your esp_peer config. • Action: confirm whether the client is configured to accept TCP/TLS TURN (port 443) candidates. If not enabled, enable them and retest (especially useful in restrictive networks). 4) Does
transport_ws: unexpected data readable on socket
usually indicate a signaling transport problem, or is it often secondary to an RTC teardown? • This log often appears as a symptom, not necessarily the root cause. Common patterns: ◦ A media/ICE/DTLS failure triggers the client to teardown and reconnect signaling; the websocket stack then notices unexpected data or an unclean state and logs that message. ◦ Alternatively, a real signaling-layer interruption can also cause the RTC to tear down. • Given your sequence (DTLS/SRTP OK, TURN candidates acquired, SDP exchange, then websocket close), it’s more likely the websocket closure is secondary — a media transport failure (ICE/DTLS/UDP socket lifecycle) causes the higher-level connection to restart, and the websocket stack logs the socket state error during the teardown/reconnect. • To verify: enable verbose websocket/signaling logging and correlate timestamps with DTLS/ICE logs. If websocket close entries come after ICE/DTLS errors, the websocket message is secondary. 5) Has anyone seen
UDP: Failed to select: Bad file number
in the ESP32 client during reconnect or peer restart? • That exact message isn’t documented as a LiveKit-specific error, but it strongly suggests a socket/file-descriptor lifecycle problem at the LWIP/esp-idf level (for example, using a socket after it was closed or not initialized). • Likely causes: ◦ A socket was closed while select()/poll still tried to use it during reconnection. ◦ Race conditions in socket cleanup during ICE restart or peer disconnect/reconnect. ◦ Running out of file descriptors or improper error handling when recreating sockets. • Diagnostics to focus on: ◦ Turn on verbose LWIP and esp_peer logging to capture socket create/close calls and any errno around select() failures. ◦ Check for code paths where sockets are closed asynchronously (e.g., in timers or callbacks) while another task still uses them. Concrete next steps and tests (short list) 1. Enable verbose logging: ◦ esp_peer/WebRTC layers, LWIP (socket layer), and websocket/signaling. Correlate exact timestamps to see which error precedes the other. 1. Verify TURN transport capabilities: ◦ Confirm whether TCP/TLS TURN (port 443) is enabled in your esp_peer config. If skipped, enable it and test in case UDP is blocked or unstable. 1. Increase ICE/DTLS timeouts: ◦ Slightly increase ICE checks/timeouts so the constrained device has more time to complete exchange under load. 1. Reproduce with a minimal test: ◦ Run a minimal repro that only performs signaling → ICE → DTLS without starting heavy capture/encode tasks. If stable, the issue is likely resource/CPU related. 1. Watch socket lifecycle: ◦ Add logs around socket create/close calls (or enable LWIP socket tracing) to capture when a UDP socket is closed relative to the “Bad file number” message. 1. Try alternative network path: ◦ If possible, test with a different network or temporarily allow non-relay ICE to see whether the problem reproduces only under relay-only mode. 1. Share config and extra logs: ◦ If you can, share the esp_peer/ICE config snippet (which candidates/transports are enabled) and a slightly longer timestamped log around the failure. I can point to exact places to add debug logs or which options to toggle. If you want, I can: • Walk through the exact esp_peer configuration keys to change for enabling TCP/TLS TURN and adjusting ICE timeouts. • Help parse an extended log (10–20 seconds before/after the failure) to identify the ordering of DTLS/ICE vs websocket errors. Thanks again — you’ve done the right thing by isolating auth/signaling and confirming TURN candidates. If you send the esp_peer config and a timestamped extended log snippet, I’ll give precise edits to try next. Sources: LiveKit SDK for ESP32: bringing voice AI to embedded devices | LiveKit | Firewall Tips, with interactive elements
r
ok, I will try some solutions you proposed.
t
Thanks — that sounds great. I’m glad you’ll try those steps. If you’d like, I can help in two follow-up ways — tell me which you prefer or do both: • Guide: I can walk you through exact esp_peer/ICE config edits (how to enable TCP/TLS TURN, which timeout values to change) and the exact verbose logging switches to turn on in esp_peer and LWIP. • Triage logs: After you run a test, paste a timestamped 10–20s log snippet (covering just before the SDP exchange through the reconnect). I’ll examine the ordering of DTLS/ICE errors vs websocket close and point to the most likely root cause and next actions. Quick reminders while you test: • Try a minimal repro (signaling → ICE/DTLS) with capture/encode disabled to see if CPU/load contributes. • Make sure TCP/TLS TURN (443) is enabled if your network may block UDP. • Enable verbose socket/LWIP logging so the “Bad file number” can be traced to an exact socket create/close. Tell me which follow-up you want (config edits or log analysis) and share the config/logs when ready — I’ll help you iterate. , with interactive elements
r
I have already deployed this round of RTC convergence experiments onto the board, and have completed actual compilation, flashing, and serial verification. In
Kconfig.projbuild:53
, I exposed key
esp_peer
parameters:
no_auto_reconnect
,
keep_role
,
ipv6_support
,
max_candidates
, and
alive_binding_retries
. In
peer.c:39
, I wired these parameters into
esp_peer_default_cfg_t
and added higher-signal RTC logging. At the same time, in
peer.c:544
, I added a filter: when
ipv6_support = n
, remote IPv6 candidates are discarded directly. The default values are now:
relay-only = y
,
no_auto_reconnect = y
,
keep_role = y
,
ipv6_support = n
,
max_candidates = 6
,
alive_binding_retries = 10
, and these have been written into
sdkconfig.defaults
. • I also updated the English forum post content in
livekit_rtc_disconnect_forum_post.md:1
. The conclusions from this round of testing are now clearer: There are no issues with 401, token, signaling, TLS, or TURN acquisition. The new configuration has taken effect in practice; the serial output shows:
no_auto_reconnect=1 keep_role=1 ipv6=0 max_candidates=6 alive_binding_retries=10
. Remote IPv6 candidates are explicitly discarded, but the issue still reproduces. • The initial failure point is neither WebSocket nor “Bad file number.” It is now clear that the subscriber peer fails with
CONNECT_FAILED
directly during the PAIRING stage.
transport_ws: unexpected data readable on socket
and
UDP: Failed to select: Bad file number
both occur during the teardown/reconnect phase after the RTC failure, and appear to be secondary symptoms. • The most suspicious area at present is SDP / data channel interoperability on the subscriber side. The serial log still shows entries like
Extract SDP: ... audio_mid=255 ... data_mid=255
, and the subscriber answer only returns an audio m-line, without application / datachannel. I have completed this build + flash + monitor cycle. As a next step, I suggest a minimal A/B test: disable the data channel only on the subscriber peer and check whether the transition from PAIRING → CONNECT_FAILED disappears. If you agree, I can proceed with this modification in the next iteration.
t
Thanks — this is excellent progress and your observations are very helpful. You’re correct to treat the websocket and "Bad file number" logs as secondary given they appear during teardown. Your focus on the subscriber path and the SDP/datachannel mismatch is the right next hypothesis. I agree with your A/B plan: disable the data channel on the subscriber only and test whether PAIRING → CONNECT_FAILED stops occurring. Doing that will clearly show whether datachannel negotiation on the subscriber is triggering the failure. Suggested steps and a couple of focused checks to make the A/B test maximally informative 1) Disable datachannel on subscriber only • Change the subscriber-side generation of the SDP answer so the application m-line / datachannel is not included (or set
datachannel
capability to false in the peer config). • Keep the publisher unchanged (still offering the datachannel). • Rebuild/flash and capture a timestamped serial log covering the entire exchange from signaling through the PAIRING result. 2) What to watch for in the logs • Whether the subscriber’s SDP answer still lists an application m-line or
data_mid
. If you removed it correctly, the answer should only include the audio m-line. • Whether the peer state advances beyond PAIRING or immediately moves to CONNECT_FAILED. • Any DTLS/ICE errors immediately before the CONNECT_FAILED message — note exact timestamps. 3) Additional small variants to try (if the basic A/B doesn’t fully isolate) • Disable datachannel on both sides to see if the issue disappears entirely. • If disabling solves it, re-enable but force the datachannel to use negotiated SCTP settings (different max channels or in-band vs out-of-band negotiation) — this helps identify whether specific datachannel parameters cause the failure. • Try changing
max_candidates
down to 2 or 3 temporarily to reduce candidate churn while testing datachannel interactions (you’ve already reduced to 6; lowering further can simplify ICE behavior). 4) Potential causes if datachannel is implicated • Incomplete or incompatible SDP attributes for application m-line (e.g., missing sctp-port, msid or mismatched
data_mid
) that the esp_peer subscriber can’t handle. • A resource / timing issue when initializing SCTP/datachannel on the subscriber while also handling DTLS/Opus setup, causing a handshake timeout and immediate CONNECT_FAILED. • A bug in datachannel transport handling in esp_peer on the subscriber path that triggers a pairing failure when application m-line is present. 5) If the A/B shows disabling datachannel fixes the failure • Share the subscriber SDP answer (the raw SDP snippet) and the corresponding publisher offer. I can point to specific SDP lines/attributes that may be incompatible and suggest exact edits or workaround config flags to use in esp_peer. • Also share any SCTP/datachannel-related config keys in your esp_peer config so I can recommend adjustments (e.g., negotiated channels, ordered/unordered settings, or SCTP port settings). If you want, I can provide the exact minimal change to apply in your peer.c to stop adding application/datachannel in the subscriber answer — tell me how you currently set the datachannel capability in code (or paste the small config snippet) and I’ll give the exact edit. Nice work so far — this is the right experimental approach. Run the A/B and paste the key 10–20s log snippet (timestamps + the SDP offer/answer) and I’ll analyze the SDP and next steps. , with interactive elements
r
已经继续跑完了,板子也重刷并实测了。 当前结论很明确:这不是 401,也基本不是 datachannel。真实串口里已经确认两侧都是 data_channel=0,而且 publisher offer / subscriber answer 都只剩 audio,但 subscriber 还是先进入 PAIRING,随后立刻 CONNECT_FAILED。最 关键的几条证据是: - livekit_peer.pub: RTC peer config ... data_channel=0 - livekit_peer.sub: RTC peer config ... data_channel=0 - PEER_DEF: Extract SDP: stream_count=1, audio_mid=255 ... data_mid=255 - livekit_peer.sub: RTC state changed to PAIRING (4) - livekit_peer.sub: RTC state changed to CONNECT_FAILED (8) - 后面的 transport_ws ... unexpected data readable on socket 和 UDP: Failed to select: Bad file number 都出现在 RTC 失败之后,所以现在更像次生现象,不像根因
t
谢谢 — 你做得非常细致,信息也很充分。下面我对你最新结论做回应、给出有针对性的排查建议和下一步可做的最小变更/日志点,以便尽快定位 PAIRING -> CONNECT_FAILED 的根因。 我已注意到(你确认的重点) • 不是 401 / token 问题;signaling/TLS/turn 候选都已成功。 • data_channel 已显式禁用(两端均为 data_channel=0),publisher 的 offer / subscriber 的 answer 只剩 audio。 • subscriber 进入 PAIRING(4)后立即变为 CONNECT_FAILED(8)。 • websocket 的 “unexpected data readable” 和 “Bad file number” 都是 RTC 失败后的次生现象。 基于这些事实,最可能的方向(按概率与可验证性排序) • 1) Subscriber 在 PAIRING 阶段遇到 DTLS/SCTP/ICE 协商或本地资源/定时问题导致超时或立即失败(尽管看似已完成 TURN/DTLS init,但某些 DTLS 握手的后续验证或 SRTP 轨道绑定可能失败)。 • 2) esp_peer 在处理最终 SDP/ICE pair(尤其是 role/ICE 控制权、port/socket 绑定或 SRTP/SRTCP 键安装)时出现 socket/描述符或 race 条件,直接触发 CONNECT_FAILED。 • 3) SDP 的某些隐含字段(例如 audio m-line 的方向、rtpmap、crypto/DTLS 指示或 mid/ssrc 相关)在 subscriber 侧被误解析或造成不兼容,从而导致后续握手被判为失败(尽管 audio m-line 存在,但缺少必须的属性)。 建议的下一步诊断(按优先级) 1) 打开最高级别的 DTLS / SRTP / ICE / esp_peer 日志(时间序列) • 目的:确认在 PAIRING -> CONNECT_FAILED 的窗口内,是否有 DTLS 握手失败(证书/指纹不匹配、证书链问题、或 DTLS 记录解析错误)、ICE 关联失败、或 SRTP key 安装失败的明确 errno/错误码。 • 建议包含:esp_peer 的 DTLS debug、ICE candidate/state 打印、以及任何关于 role (controlling/controlled) 或 rtp/transceiver 绑定的日志。 • 时间段:从 signaling 完成 SDP 交换起到 CONNECT_FAILED 的 5–10 秒内(包含前后 2 秒作为上下文)。 2) 打印并比对完整的 offer / answer SDP(publisher offer 与 subscriber answer) • 目标:人眼快速比对是否有缺失的关键属性(比如 audio m= line 的 sendrecv/recvonly/sendonly、不一致的 codec payload types、缺少 rtcp-mux、或不一致的 a=mid / a=ssrc)。 • 请把相关 SDP 的关键段(m=audio 开头的整段 + session-level a=fingerprint/ice/ice-ufrag/ice-pwd)贴出来。我会帮你逐行确认是否有不兼容项。 3) 检查 role 与 ICE 控制权细节 • 观察日志中控制权是如何分配的(你之前有 “AGENT: Start agent as Controlling/Controlled” 的输出),确认 subscriber 在 PAIRING 时 role 与 publisher 的预期一致。role mismatch 有时会导致 DTLS/ICE 快速失败。 • 你可以临时强制 keep_role=1(你已有该选项),并记录两端在 SDP 中的
a=setup:active|passive
值,确认 DTLS active/passive 配置是互补的。 4) 进一步缩小范围的 A/B 测试(最小改动) • A. 维持当前 relay-only,但在 subscriber 端延后开始本地音频(或完全不启动 capture/encoder),仅执行信令+SDP+ICE/DTLS 建立,观察是否仍然失败(验证是否是资源/CPU 导致)。 • B. 在 subscriber 端尝试短暂允许非‑relay(即允许 host/srflx)以确认是否仅在 relay-only 路径下重现。若非-relay 可成功,则指向 TURN relay 特殊路径或 TURN/TCP handling 问题。 • C. 如果可行,尝试把
max_candidates
再降至 2 来减少 candidate 数量,看是否改变行为(帮助确认是否 candidate 选择或 socket 创建/关闭 race)。 5) 针对 “PAIRING 时直接 CONNECT_FAILED” 的具体日志点 • 增加日志在以下代码点(若你已经能定位到 peer state 变更处,直接在 state transition 周围): ◦ SDP answer 接收后开始处理的入口处(打印所有被解析的 ice candidates 列表与 their transport/addr/port)。 ◦ DTLS 握手开始、每个阶段(ClientHello/ServerHello/Verify)与最终成功/失败回调处。 ◦ SRTP key install 成功/失败处。 • 捕获任何返回的 errno 或 ioctl/select/poll 的失败值(尤其是在 socket bind/connect 或 select 调用处)。 如果这些步骤中你希望我直接给出具体代码级修改,我可以: • 给出在 peer.c 添加更多 DTLS/ICE 状态打印的精确 patch(例如在 DTLS 错误路径打印 mbedtls 错误码或 esp_peer 返回值)。 • 或者给出一个最小的测试补丁:在 subscriber 在 PAIRING 阶段把所有 non-audio m-lines 显式忽略并且把 RTCP mux 设置为 on/off 看差异(但目前你说已经是纯 audio,所以这一步可能没必要)。 如果你愿意发: • 一份 timestamped 的、从 SDP 交换开始到 CONNECT_FAILED 的完整串口日志(含你已增加的 RTC verbose),以及 publisher offer 与 subscriber answer 的原始 SDP,我会逐行分析并指出最可能导致失败的字段或时间点。 最后,短结论与下一步建议 • 结论:目前看起来不是 auth 或 datachannel,而更像是 subscriber 在 PAIRING 阶段某一步 DTLS/ICE/SRTP 的最终绑定或本地 socket/资源问题导致的立即失败。websocket/Bad file number 为次生现象。 • 下一步:按上面 1–5 顺序先开更高详细级别的 DTLS/ICE 日志并贴出 SDP + 关键时间窗口日志;如果你愿意我也可以直接给出需要插入的 debug log 代码片段。 你想先把完整的 SDP 与 5–10s 的详细时间窗口日志贴上来吗?或者我直接把需要添加的日志打印补丁发给你以便下次刷入?哪种方式对你更方便,我就按那方式继续。 , with interactive elements
r
- livekit_peer.pub: RTC peer config ... data_channel=0 - livekit_peer.sub: RTC peer config ... data_channel=0 - PEER_DEF: Extract SDP: stream_count=1, audio_mid=255 ... data_mid=255 - livekit_peer.sub: RTC state changed to PAIRING (4) - livekit_peer.sub: RTC state changed to CONNECT_FAILED (8) - 后面的 transport_ws ... unexpected data readable on socket 和 UDP: Failed to select: Bad file number
t
谢谢,你的复现和日志说明得非常清楚 — 这有助于快速缩小范围。 我会先简短确认我在回复中针对的要点,然后给出接下来的具体诊断步骤和可选的最小代码补丁,帮助你在 PAIRING -> CONNECT_FAILED 的窗口内找到根因。 确认我在回应的要点 • 两端都禁用了 data_channel(data_channel=0),offer/answer 现在只包含 audio。 • subscriber 进入 PAIRING(4)后立即变成 CONNECT_FAILED(8)。 • websocket 的 “unexpected data readable” 与 “Bad file number” 都是后续 teardown 的次生现象。 • 目前最可疑的是在 PAIRING 阶段 DTLS/ICE/SRTP 绑定或 socket/资源/时序问题导致的即时失败;也可能为 SDP 某些隐含字段解析不一致。 优先级与目标 • 目标:在 PAIRING -> CONNECT_FAILED 发生的 5–10s 窗口内捕获能说明根因的 DTLS/ICE/SRTP 级别日志或 SDP 差异。 • 优先级从高到低:1) DTLS 握手失败信息 2) ICE 关联/绑定失败信息 3) SRTP key 安装失败 4) SDP 属性不兼容 5) 本地 socket/descriptor race 导致 select()/poll 错误 建议的具体诊断步骤(按顺序执行) 1) 开最大级别日志(立即执行) • 打开 esp_peer 的 DTLS、ICE、SRTP、以及 LWIP 的 socket 日志(verbose/DEBUG)。 • 目标是看到 DTLS handshake 的每个步骤(ClientHello/ServerHello/verify/fingerprint check)和 ICE candidate pair 建立的成功或失败。 • 捕获时间窗口:从 signaling 完成 SDP 交换起到 CONNECT_FAILED(包含前后各 2s),整段日志贴出来。 2) 导出并贴上原始 SDP(offer 与 answer) • 把 publisher 的 offer 和 subscriber 的 answer 的完整原始 SDP 贴上(包括 session-level a=fingerprint、ice-ufrag/pwd、以及 m=audio 段内所有 a= 行)。 • 我会逐行对比并指出可能的不一致或缺失(例如 direction、rtpmap、rtcp-mux、a=mid、a=ssrc、crypto/ fingerprint 字段等)。 3) 在 state transition 点增加更细粒度日志(如果第1步还不够) • 在 peer 状态从 PAIRING -> CONNECT_FAILED 的代码路径周围,加入日志打印: ◦ 收到并解析的全部 candidates 列表(addr/port/transport/type)。 ◦ DTLS 指纹比较结果与 `a=setup`(active/passive)值。 ◦ SRTP key install 调用的返回值 / errno。 ◦ select()/poll 返回值及其 errno(尤其在报 “Bad file number” 前后的调用)。 4) 快速 A/B 变体(并行测试,便于排除) • A: 在 subscriber 端完全不启动本地音频 capture/encoder(只做信令+ICE/DTLS),看是否依然失败(判断是否为资源/CPU 导致)。 • B: 暂时允许 host/srflx 候选(非 relay-only)看是否可成功建立(若成功,指向 TURN relay 特有的实现差异或 socket usage)。 • C: 将
max_candidates
降到 2,减少 candidate 数量,看是否有差异(帮助排除 candidate 绑定 race)。 5) 如果可能,收集下列额外信息 • subscriber 在 PAIRING 入口前后的
a=setup
值(active/passive)以及日志中显示的 role(controlling/controlled)。 • 是否看到任何 DTLS 错误码(例如 mbedtls 的返回码),或 ICE pair state 明确的 FAILED/CONNECTED 标志。 可选最小代码补丁(便于下一次刷入) • 我可以给出两段你可以直接插入的日志 patch: 1) 在 DTLS 握手成功/失败处打印 mbedtls 返回码与 human-readable 描述。 2) 在 ICE candidate pairing 的每一步打印 candidate local/remote 地址与 pair 状态变更。 • 如果你愿意,我现在就把这两个短补丁(C 代码片段,能直接贴到 peer.c 的相应位置)发给你,便于下次刷入后立即获得更有意义的输出。 短结论(当前最可信假设) • subscriber 在 PAIRING 阶段因 DTLS/ICE/SRTP 的某一步失败而立刻报 CONNECT_FAILED。websocket/Bad file number 为断开后清理引起的次生日志。下一步通过更高等级的 DTLS/ICE/SRTP 日志 + SDP 对比可以迅速定位是握手协议不兼容、role/`a=setup` mismatch、还是 socket lifecycle race。 你想先哪一步? • 我现在把需要插入的两个最小日志补丁发给你(你可以直接贴入 peer.c 并刷入),还是你先贴出 publisher offer 与 subscriber answer 的原始 SDP 及 5–10s 串口日志片段让我分析?哪种对你更方便,我就立刻准备相应内容。, with interactive elements
r
PAIRING -> CONNECT_FAILED
t
谢谢,你把关键现象简明地重申出来了:subscriber 在 PAIRING -> CONNECT_FAILED。这让我可以直接给出下一步最有价值且可立刻执行的操作来定位根因,并请求两份关键输出以便我做逐行分析. 我建议你先做两件事(都只需短时间改动/重刷),然后把结果贴上来: 1) 开最高级别的 DTLS/ICE/SRTP/LWIP/esp_peer 日志并抓取 5–10 秒的串口日志 • 打开 verbose/DEBUG 日志,包含至少: ◦ DTLS 握手(ClientHello/ServerHello/Verify/fingerprint 比较); ◦ ICE candidate pairing / pair state changes(local/remote addresses/ports 与 pair result); ◦ SRTP 密钥安装成功/失败; ◦ LWIP / socket 层 select()/poll 返回值与 errno。 • 捕获时间窗口:从 SDP 交换完成(offer/answer 发送/接收)开始,直到 CONNECT_FAILED,并在前后各保留 ~2 秒上下文(总计 6–12 秒)。 • 目的:确认在 PAIRING -> CONNECT_FAILED 之间是否出现明确的 DTLS/ICE/SRTP 错误或 socket errno(这将直接指向根因)。 2) 导出并贴出原始 SDP(publisher 的 offer 与 subscriber 的 answer) • 把两端的完整原始 SDP 完整粘贴(包含 session-level a=fingerprint、ice-ufrag/ice-pwd、所有 m= 段及其 a= 行)。 • 我会逐行对比并指出: ◦ a=setup(active/passive)是否互补; ◦ fingerprint/alg 是否匹配并被正确解析; ◦ audio m= 段的 direction(sendrecv/recvonly 等)、codec payload 类型是否对齐; ◦ 是否缺少 rtcp-mux、ssrc 或其他必须属性导致绑定失败。 如果你能把上面两样东西贴上来,我会逐行分析并指出最可能的失败点与精确的修复或补丁建议。 —— 如果你想我也可以先给你两个可直接打补丁的短代码片段(用在 peer.c),方便下次刷入立即产出更有意义的日志: • 补丁 A(DTLS):在 DTLS 成功/失败回调处打印 mbedtls 返回码与可读错误说明(帮助确认是否为证书/指纹/handshake 解析错误)。 • 补丁 B(ICE):在每次 candidate pairing 成功/失败时打印 local/remote candidate tuple(addr:port/transport/type)以及 pair state 变更。 你想先贴日志/SDP 让我分析,还是我把这两个小补丁发给你以便下次直接收集更详细信息?两种我都可以马上准备。 , with interactive elements