Quikcast Help

Protocol evidence and compatibility decisions

Evidence identity and limits

Captured on 2026-10-07 against upstream Icecast 2.4.4 and 2.5.0, built from the pinned release archives in tools/icecast-reference/SHA256SUMS. Each run includes binary version, image ID, package inventory, configuration, generated source tone, harness snapshot, raw dialogues, event offsets, logs, summary and SHA-256 manifest. Hashes identify artifacts, not a password-storage scheme.

Primary runs are fixtures/icecast/2.4.4 and fixtures/icecast/2.5.0. Focused body-completion runs are their -followup siblings. initial-2.4.4 preserves the original short metadata reads: it demonstrates why a successful admin response and a short listener read are insufficient to prove delivery of a title change.

The machine-readable compatibility matrix (fixtures--icecast--compatibility.json) uses only observed-supported, observed-rejected, version-dependent, and unresolved. A classification describes the named behavior, not overall release quality. An accepted but corrupted chunked upload is explicitly distinguished from an HTTP rejection.

Read .request.bin and .response.bin as bytes. .events.json associates sends/receives with monotonic time and offsets. The source before_first_audio marker establishes whether a reply arrived before any payload was sent. Events are userspace observations, not packet timestamps. Volatile dates/ports must be normalized during future replay. Empty status strings in old summaries mean no response bytes observed, not an HTTP status.

These are bounded, local reference experiments with synthetic media, not a production load test or proof that Quikcast is compatible. At the milestone 1 capture boundary no Quikcast server existed. The subsequent server/client proof is recorded in milestone 3; these Icecast fixtures remain the reference evidence.

Observed source behavior

PUT without body length (observed-supported). Both releases delivered byte-identical audio through the raw EOF-delimited PUT case. In 2.4.4, the source received HTTP/1.0 200 OK with no additional headers before the first audio send. In 2.5.0, the source saw no response before/during the captured streaming window, while listeners received HTTP/1.1 200 OK and valid audio. Source response absence does not mean admission failure.

Expect handling (version-dependent acceptance sequencing). With valid credentials, 2.4.4 sent HTTP/1.1 100 Continue (Content-Length: 0), followed by HTTP/1.0 200 OK, both before first audio. In 2.5.0, the EOF-streaming case received 100 Continue with normal server headers but no final 200 in that window. Wrong credentials plus Expect returned 401 without a 100 in both focused runs.

SOURCE (observed-supported). SOURCE /station.mp3 ICE/1.0 and SOURCE /station.mp3 HTTP/1.0 both admitted a source and produced byte-identical listener audio. 2.4.4 replied HTTP/1.0 200; 2.5.0 replied HTTP/1.1 200 before audio. No SHOUTcast password-line protocol was tested or added to scope.

Basic authentication (observed-supported success; observed-rejected invalid/missing credentials). Valid machine credentials admitted source/metadata requests. Invalid/missing credentials returned 401 with a Basic challenge. The fixture called auth-missing sends an empty Basic token rather than omitting the Authorization header entirely; metadata-no-auth genuinely omits it. A fully absent source Authorization header remains a parser/auth regression case for milestone 2 rather than a claimed reference observation.

Chunked PUT (version-dependent audio integrity). Both releases admitted the request with Expect. The 2.4.4 listener body begins with the literal ASCII chunk-size line 800\r\n, and the audio comparison fails. It did not reject the request; it relayed framing bytes. The 2.5.0 listener body matches the encoded tone exactly, excluding chunk sizes/CRLF; after the terminal zero chunk the source captured a final 200. Quikcast must decode chunked framing correctly and must not emulate 2.4.4 corruption.

Finite Content-Length (version-dependent observations; incomplete coverage). In the primary 2.4.4 run, a completed finite upload remained listenable and the received bytes matched the tone. In 2.5.0, the listener saw 404 after the finite upload and the source recorded no reply. The followup records partial-body queries and write-half-close: 2.4.4 returned listener headers, while 2.5.0 returned 404 for the length-delimited partial-body query. Those focused reads received no audio before their short deadline. Do not infer the internal cause, or claim complete finite-body support/rejection from these observations. Quikcast will follow normal declared-length semantics and test live delivery during longer incremental bodies in milestone 2.

EOF/disconnect/reconnect (observed-supported). Closing the active source eventually closed its attached listener; inactive GET returned 404; a new source could claim the mount and started with empty title metadata. Half-close followups record actual source replies (including absence); they do not invent a final 200 where no bytes were captured.

Observed listener and metadata behavior

Both versions produced audio/mpeg listeners with normalized Ice/ICY station headers, icy-br:128, and ice-audio-info from the supplied source header. The fixture response includes icy-name/description/genre/url/pub. Header spelling/case is preserved in raw files, while summary keys are lowercase. Header acceptance with every possible casing or malformed structured value is not established by this sample.

Listeners without Icy-MetaData received uninterrupted encoded bytes matching the tone. ICY-enabled listeners advertised 16,000 audio bytes per interval. Initial metadata was a one-unit, padded StreamTitle=''; block, followed by zero-length blocks when unchanged. These samples did not include StreamUrl; Quikcast will not invent one.

GET /admin/metadata?mount=...&mode=updinfo&song=... succeeded using source credentials. The response was a bounded text/xml success envelope with return=1; 2.5.0 added a modules element. This narrow envelope is compatibility for this route, not broad XML administration.

Extended reads observed Artist - Title, Next Artist - Next Title, and a UTF-8 title containing an apostrophe and backslash. The captured wire preserves those quote/backslash bytes rather than inserting backslash escapes. Fields artist/title also produced Field Artist - Field Title; acceptance of album/genre does not prove that those fields were reflected in the ICY payload.

Title updates can appear after older metadata in the retained burst. The first nonempty title in a newly joined listener can therefore be historical. Extended reads are essential; do not equate metadata HTTP acknowledgment with immediate listener visibility.

Clearing is version-dependent. For song= after a nonempty title, 2.4.4 eventually emitted empty StreamTitle; 2.5.0 acknowledged success but the extended read retained the preceding title. Source reconnect reset the title in both releases. This is the behavior of the exact tested query/configuration, not a claim about every possible clearing request.

Using global source credentials to update /other.mp3, which has its own credential, returned 401. The mount-specific credential succeeded. A metadata request without Authorization returned 401. Malformed/cross-mount requests never became permission to affect other source state.

External client observations

FFmpeg 8.1.2's Icecast output used PUT, Expect: 100-continue, and an EOF-delimited body in both runs, exited successfully, and produced HTTP 200 listener streams. Its MP3 muxer added a 45-byte ID3 tag, so the whole listener body does not match the bare source-tone file. This mismatch is expected container metadata, not evidence of audio corruption; the remaining captured payload is checked separately in the matrix generator.

Curl's finite-file upload differs: the 2.4.4 sample delivered matching audio but curl hit its deliberately configured three-second deadline (exit 28); 2.5.0 returned an empty reply (exit 52) and the timed listener probe saw 404. The trace preserves the exact dialogue. Do not describe these finite-upload results as complete live curl compatibility; raw socket fixtures establish continuous PUT behavior.

Liquidsoap 2.1.3 ran in a disposable client container sharing only the reference server's network namespace. Dedicated -liquidsoap captures show successful continuous and ICY listeners on both releases, with StreamTitle='Unknown' supplied by this synthetic fixture's producer. Access logs show SOURCE over HTTP/1.0 and successful standard /admin/metadata calls. Bounded readiness probes preserve the 404s before the encoder became active; those are startup observations, not source rejection. The earlier -liquidsoap-startup datasets intentionally preserve probes that arrived too soon. Installed package versions and the actual client image ID are recorded. BUTT/player interoperability and long-duration encoder tests remain milestone-3 work, not passed tests here.

Quikcast contract chosen for review

  • Support both measured legacy SOURCE request lines, machine Basic authentication, and the bounded source header set. Use one normalization/admission/session path.

  • Framed PUT follows ordinary HTTP: validate before permitting body consumption, send 100 only for accepted Expect requests, stream decoded body bytes, and return a finite success response after body completion. Trailers and framing are bounded; conflicting lengths are rejected.

  • Raw EOF-delimited PUT and legacy SOURCE use the narrow source adapter with early 200 acceptance following measured 2.4.4 behavior. Accepted raw PUT with Expect emits 100 followed by early 200; authentication failure emits only 401. End-of-stream closes the session, and late errors cannot replace an already sent status.

  • HTTP listener status-line versions need not match Icecast release branding. Serve deterministic normal HTTP with close-delimited continuous output and available ICY station headers; preserve encoded bytes.

  • ICY milestone: explicit empty song clears the normalized title, following the observed 2.4.4 behavior. Sample the latest generation-local metadata at each listener interval; historical title/audio association in Icecast's retained burst is an intentional timing difference, not a replicated internal architecture.

  • Preserve tested UTF-8, apostrophe and backslash bytes; no guessed escaping transformation. Milestone 4 adds focused captures and tests for delimiters, payload bounds, controls, charset/query variants and precedence; its explicit differences supersede this earlier evidence gap.

  • Use the narrow metadata success envelope and source credential scope. No status-json.xsl or other admin feature is added.

This contract provides evidence to begin the MP3 slice after review. It does not waive the transport integration gate: demonstrate bounded header parsing, raw-body over-read preservation, Expect sequencing, and live framed-body delivery in tests before accepting the production adapter. Never hand an unframed source to an ordinary HTTP parser and silently treat its body as empty.

Remaining gaps

Unresolved reference coverage includes a truly absent source Authorization header, large/slow finite Content-Length uploads, metadata maximum-size/embedded-delimiter/charset variants, arbitrary casing and malformed Ice-Audio-Info, and broader player/encoder releases. These are recorded as gaps, not presumed passes. They do not authorize speculative feature implementation.

Protocol sources: official Icecast releases, Xiph PUT discussion, Hyper HTTP/1 limits, and HLS RFC 8216. Local captured bytes take precedence over general descriptions for the observed Icecast cases.

08 October 2026