Browser git · main
Minimal browser in C (mini and big variant)
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.gzDebugging streaming issue
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){"