@urun-sh/core 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.1
4
+
5
+ - **FIX: a re-dial no longer leaves the playout element bound to a DEAD track**
6
+ (urun-infra#2132; the prod qwen-voice "assistant audio drops mid-session and
7
+ never self-heals, reload fixes it" signature). `recvTransport.consume()` /
8
+ `consumeData()` are ASYNC — mediasoup-client renegotiates the recv
9
+ PeerConnection to add the transceiver — so a consume ISSUED on the leg that is
10
+ about to die can still be in flight when a dropped signaling socket re-dials
11
+ and `_cleanupMedia()` replaces the whole leg. That late consumer resolved onto
12
+ a transport the session no longer owns and was registered ANYWAY, LAST: it
13
+ overwrote `_tracksByName`, emitted the final `'track'` event, and leaked into
14
+ the live consumer set. Its track reads `readyState === 'live'` (nothing
15
+ stopped it — its consumer was not in `_consumers` when the cleanup ran), so
16
+ every liveness filter above the seam accepted it: `<Video>` / `<Audio>` swap
17
+ tracks into the ONE persistent `MediaStream` that stays the element's
18
+ `srcObject`, so the healthy, decoding track of the NEW leg was removed and a
19
+ track belonging to a closed PeerConnection put in its place. The rendered
20
+ frame froze while the downlink stayed perfectly healthy (SFU `packetsSent`
21
+ climbing, consumer `framesDecoded` climbing, `pliCount 0`,
22
+ `attachedToMediaElement: false` on every RTCPeerConnection), and the
23
+ components' missed-event poll could never heal it because `getTrackByName()`
24
+ kept answering with the stale track — only a page reload recovered.
25
+
26
+ Both consume paths now carry a LEG FENCE across their await, through
27
+ mediasoup's own identity rather than a timer or a poller: a consumer belongs
28
+ to the transport that created it, so a consumer whose transport is no longer
29
+ this session's recv transport (or is closed, or whose dial generation has been
30
+ superseded, or which landed after an intentional disconnect) is closed through
31
+ mediasoup-client's own per-consumer lifecycle — which stops its track — and is
32
+ never registered. The data twin matters just as much: a superseded
33
+ `consumeData` used to install a DEAD channel as a named stream's data lane,
34
+ silently swallowing every later payload on that name.
35
+
3
36
  ## 0.4.0
4
37
 
5
38
  - **BREAKING: `SessionPhaseName` loses `'ended'` and `'expired'`** (#392, #398 —