Nimbin[12]?Web & Tools / Browser / commits / d2cd563

Browser git · main

Minimal browser in C (mini and big variant)

browser c · first commit 2026-08-25 · last commit 2026-10-29 (4 days ago) · synced 6 hours ago · upstream: github.com/nimbin2/Browser

C 96.1% Markdown 3.7%
git clone https://git.christianimmanuel.de/web-tools/Browser.gitwget https://git.christianimmanuel.de/web-tools/Browser/archive/Browser.tar.gz

Debugging streaming issue

Christian Immanuel · 2026-10-29 20:59 · d2cd5636d4d925e17a128e76bd11e2d5e4da4368

 Makefile      |  2 +-
 README.md     | 30 +++++++++++++++++++-----------
 browser-big.c | 27 ++++++++++++++++++++++++---
 3 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/Makefile b/Makefile
index d48c593..1aa8a82 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CC      ?= gcc
 CFLAGS  ?= -O2 -Wall -Wextra -rdynamic
 PREFIX  ?= /usr
 
-VERSION  := 4.40.0
+VERSION  := 4.41.0
 SOURCES  := browser_core.c browser_core.h browser-mini.c browser-big.c Makefile
 BUILD_ID := $(shell cat $(SOURCES) 2>/dev/null | md5sum | cut -c1-7)
 
diff --git a/README.md b/README.md
index 6328076..6082349 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ make                # build both
 make install        # into /usr/bin (PREFIX=... to change)
 make uninstall
 make clean
-make version        # 4.40.0 (build …), md5 of the sources
+make version        # 4.41.0 (build …), md5 of the sources
 ```
 
 ## Usage
@@ -187,18 +187,26 @@ browser-big URL --rtc-trace 2>&1 | tee /tmp/bb.log
 - `in-video.dec` climbing, `video-state.frames` at 0: decoded, never shown.
 - `in-video.fir` climbing, `keys` still: no keyframe arrives.
 
-**A frozen picture, audio still playing.** Repeated samples are not
-printed, so a freeze stops the log instead of filling it. One line is
-let through when the counters stop and one when they move again:
+**A frozen picture, audio still playing.** Grep for `stuck`. The
+receive path is checked at three points and `stuck` names the one that
+stopped:
 
-- `video-state` `stuck: true`, `dframes: 0`, `in-video.dec` climbing:
-  frames decode, the element never presents them. Our bug.
-- `in-video.bytes` climbing, `dec` flat: packets arrive, the decoder
-  does not advance. Usually codec or keyframe.
-- `rtc-stats` `stuck: true`: nothing arrives any more. The page or the
-  server stopped sending.
+| `stuck` | Where it stopped |
+| --- | --- |
+| `nothing arriving` | No bytes. Page or server stopped sending |
+| `arriving, no frame assembled` | Packets arrive, never form a frame |
+| `assembled, not decoding` | Whole frames arrive, decoder will not advance |
+
+A fourth point is the element itself: `video-state` with `stuck: true`
+and `dframes: 0` while `in-video.dec` still climbs means frames decode
+and are never presented.
+
+Supporting counters on `in-video`: `recv` frames assembled (`-1` if
+WebKit does not report it), `fdrop` dropped, `jbd`/`jbe` jitter buffer
+delay and frames out, `dectime` total decode ms, `frz`/`frzms` freeze
+count and duration, `rtx` retransmits received.
 
-The timestamp on the `stuck` line is when the picture froze.
+The timestamp on the first `stuck` line is when the picture froze.
 
 **Without a server:**
 `browser-big https://webrtc.github.io/samples/src/content/peerconnection/pc1/ --rtc-trace`.
diff --git a/browser-big.c b/browser-big.c
index 6e5c342..6887d40 100644
--- a/browser-big.c
+++ b/browser-big.c
@@ -846,8 +846,25 @@ static const char *SHIM_JS =
 "                         keys:s.keyFramesEncoded||0,"
 "                         limited:s.qualityLimitationReason||null,"
 "                         target:s.targetBitrate||0};}"
+/*
+ * recv is framesReceived - whole frames the depacketizer put back
+ * together - and it sits between bytes and dec. Without it a stalled
+ * stream is ambiguous: packets arriving while dec stands still can
+ * mean the frames never assemble or that they assemble and the decoder
+ * refuses them, and those have nothing to do with each other. WebKit
+ * may not report it, so -1 says "not answered" rather than zero.
+ */
 "          else if(s.type==='inbound-rtp'){any=true;"
 "            o['in-'+k]={ssrc:s.ssrc||0,bytes:s.bytesReceived||0,dec:s.framesDecoded||0,"
+"                        recv:(s.framesReceived===undefined?-1:s.framesReceived),"
+"                        asm:s.framesAssembledFromMultiplePackets||0,"
+"                        fdrop:s.framesDropped||0,fps:s.framesPerSecond||0,"
+"                        jbd:Math.round((s.jitterBufferDelay||0)*1000),"
+"                        jbe:s.jitterBufferEmittedCount||0,"
+"                        dectime:Math.round((s.totalDecodeTime||0)*1000),"
+"                        frz:s.freezeCount||0,"
+"                        frzms:Math.round((s.totalFreezesDuration||0)*1000),"
+"                        rtx:s.retransmittedPacketsReceived||0,"
 "                        keys:s.keyFramesDecoded||0,w:s.frameWidth||0,h:s.frameHeight||0,"
 "                        pkts:s.packetsReceived||0,lost:s.packetsLost||0,"
 "                        disc:s.packetsDiscarded||0,"
@@ -879,9 +896,13 @@ static const char *SHIM_JS =
  * simply stop printing at the moment they get interesting.
  */
 "        var key=JSON.stringify(o),p=last[i]||{},iv=o['in-video'];"
-"        var rx=iv?(iv.bytes+'/'+iv.pkts+'/'+iv.dec):null;"
-"        o.stuck=(rx!==null&&rx===p.rx);"
-"        var rep=(key!==p.key)||(!!o.stuck!==!!p.stuck);"
+"        var rx=iv?[iv.bytes,iv.pkts,iv.recv,iv.dec].join('/'):null;"
+"        o.stuck=false;"
+"        if(iv&&p.rx){var q=p.rx.split('/');"
+"          o.stuck=(iv.bytes==q[0])?'nothing arriving':"
+"                  (iv.recv>=0&&iv.recv==q[2])?'arriving, no frame assembled':"
+"                  (iv.dec==q[3])?'assembled, not decoding':false;}"
+"        var rep=(key!==p.key)||(String(o.stuck)!==String(p.stuck));"
 "        last[i]={key:key,rx:rx,stuck:o.stuck};"
 "        if(rep)post(o);"
 "      }).catch(function(e){"