Skip to content

Codec and format negotiation: default codec order, PCM byte-layout docs #90

Description

@balloob

This issue comes out of a cross-SDK conformance audit comparing every Sendspin client/server implementation (aiosendspin, sendspin-cli, sendspin-cpp, sendspin-dotnet, sendspin-go, sendspin-js, sendspin-jvm, sendspin-rs, SendspinKit) against the spec. sendspin-cpp is treated as the reference implementation throughout — it most closely matches the spec's language and is the only SDK that runs on the constrained-embedded target the spec was originally written for.

The spec is detailed about codec negotiation, but the audit surfaced
two spec-text issues (plus a universal stream/request-format gap
that's better solved by a conformance scenario — filed separately
against Sendspin/conformance). sendspin-cpp is the reference for
codec handling: textbook 24-bit unpack with sign-extension in
audio_utils.h:29-47, FLAC codec_header Base64-decode in
player_role.cpp:270-282, and embedder-supplied codec order with no
hardcoded preference.

1. Specify a default codec ordering

Clients SHOULD list supported_formats in descending preference,
with compressed codecs (opus, flac) listed before pcm unless
the client has a specific reason to prefer uncompressed (e.g. a
battery-powered device avoiding CPU-heavy decoding).

sendspin-js advertises [pcm, opus, flac] (PCM first), which means
servers will choose uncompressed over Opus by default and waste
bandwidth. sendspin-cpp's conformance harness uses opus, flac, pcm
which is the more defensible default.

2. Document the PCM byte-layout convention more visibly

The current PCM encoding note is one line buried in the player
support object section. Promote it to its own subsection — PCM byte
layout
— with worked examples for 16-, 24-, and 32-bit. The full
text we have today:

Samples are encoded as little-endian signed integers (two's complement).
24-bit samples are packed as 3 bytes per sample.

This matters: sendspin-go has no explicit 24-bit code path at all,
and the bug is latent precisely because the spec text is so easy to
miss. Worked-example code would make conformance audit-able by
inspection.


Source audit doc: docs/codec-format-negotiation.md
Full audit branch: claude/stream-sync-correction-sdks-AWoNC
Per-SDK digest: sdk-issues digest

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions