Skip to content

Opus output is written in host byte order but consumed as little-endian PCM #132

Description

@mguaylam

Read-confirmed, not reproduced — saying so up front, because the two sibling defects below were reproduced and this one was not.

SendspinDecoder::decode() in src/decoder.cpp hands libopus the output buffer through a native-width cast:

int output_frames = opus_decode(
    this->opus_decoder_buf_.as<OpusDecoder>(), data, data_size, (int16_t*)output_buffer,
    this->current_stream_info_.bytes_to_frames(output_buffer_size), 0);

opus_decode() writes opus_int16 in the host's byte order — that is its documented contract, not an inference. The buffer it fills is then consumed as little-endian PCM: a host sink opens SND_PCM_FORMAT_S16_LE, and the Sendspin PCM encoding is little-endian throughout.

On a little-endian build those agree and nothing is wrong. On a big-endian one every decoded Opus sample reaches the device with its bytes reversed.

Nothing byte-swaps between the two, as far as I can see. If there is a swap somewhere I have missed, I would be glad to be corrected — that is the main reason I am filing this rather than a pull request.

Why I think it is worth looking at

The same shape of defect exists in two places around it, and in both I was able to demonstrate it rather than argue it:

Three places, one pattern: the careful path is byte-wise and the convenient path is a cast. This one is the third, and it is the only one of the three I did not manage to put under a test, because doing so means cross-building libopus for a big-endian target rather than compiling one self-contained file.

Context

Found packaging sendspin-cli for OpenWrt. ath79 — MIPS 24Kc, big-endian, still on kernel 6.18 — is a common host for this sort of thing: an older router with a USB port and a cheap DAC. My package carries @!BIG_ENDIAN for now, so it is simply not offered there rather than offered and wrong. I would rather drop that guard.

Happy to test a branch on real big-endian hardware, or to build the cross-compiled libopus harness if that would help more than it costs.

Environment

Library sendspin-cpp v0.8.0, as pinned by sendspin-cli 0.3.0
Where src/decoder.cpp, the opus_decode() call in SendspinDecoder::decode()
Consumer ALSA sink opening SND_PCM_FORMAT_S16_LE

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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