Skip to content

Cast sound and input: Miracast sound from a desktop, a working RokuAudioSink, touch and remote over UIBC - #2

Merged
bdbarnett merged 8 commits into
mainfrom
cast/sound-input
Oct 29, 2026
Merged

bdbarnett merged 8 commits into
mainfrom
cast/sound-input

Conversation

@bdbarnett

@bdbarnett bdbarnett commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Sound and input for the cast displays.

Miracast sound. CastDisplay(..., audio=True) carries an app's sound with the picture. On the ESP32-P4, castif reads the audio pump through a TapFeed. On a desktop, pycast muxes castif's LPCM track itself: display.pcm_out() is an audiodev PCMOutput, which miracast/board_config.py hands to audiodev, and audio="file.mp3" (or a list of ffmpeg input arguments) casts anything ffmpeg reads. The LPCM mux is byte-identical to castif's C muxer, checked against a golden capture. Heard on a Roku from Linux CPython and from Windows CPython: 30 fps, the player reports pcm, no drift, no gaps, and the speech transcribes word for word.

RokuAudioSink. It never played: the TV's player waited forever on an endless WAV. It now sends a Content-Length and real RIFF sizes, paces writes by the clock (2 s ahead, counted in bytes for arrays too), and binds on unix MicroPython. It plays on python, python.exe, micropython and micropython.exe, 3.5 to 5.5 s behind the app. The Companion channel shows sound or the picture, not both, so the roku config's TV sound is now opt-in (SOUND_ON_TV).

Input. uibcinput reads the HID report descriptors Windows sends, so a touchscreen's multitouch reports (0x13) become touches where the finger is, and remote-control reports (0x2A) become K_* keys. CastDisplay offers Windows its whole HID list, which it needs before it forwards anything.

Unit tests run in CI now (tests/): the mux, resampler, ring and paced speaker, the sink's WAV and pacing, and the descriptor parser with touch and remote reports.

Not covered here: a real touch on a Windows touchscreen (needs a person at the laptop), and the P4's sound on hardware.

…peaker

CastDisplay(audio=True) carries the app's sound with the picture. On the
P4, castif reads the audio pump through a TapFeed. On a desktop, pycast
muxes castif's LPCM track itself: display.pcm_out() is an audiodev
PCMOutput whose writes go out on the cast, and audio='file.mp3' (or ffmpeg
input arguments) casts anything ffmpeg reads.

The LPCM mux is byte-identical to castif's C muxer (tests/data golden), and
a unit-test step now runs in CI.
The TV's player waited forever on the endless WAV: it now carries a
Content-Length and real RIFF sizes (an hour of sound), and the player
starts. Writes are paced by the clock, 2 s ahead, counted in bytes for
an array too: before, an app's sound loop ran many times faster than
its sound. Unix MicroPython could not bind the port at all; it binds
0.0.0.0 by getaddrinfo now, as the frame server does.
…aths

The Companion channel plays sound or the picture, not both, so sending an
app's sound there replaced its picture. SOUND_ON_TV turns it on. The guide
says how to cast a desktop app's sound over Miracast, and cast-runtimes
has the measured sound on each runtime.
uibcinput reads the report descriptors the sender sends first, so
multitouch (report 0x13) and remote-control (0x2A) reports decode by
their real layout: each finger becomes a touch where it is, scaled from
the descriptor's range to the cast, and a remote's buttons become the
K_* keys an app already reads (arrows, OK, Back, Home, play, volume).

CastDisplay now offers Windows its whole HID list: offered the keyboard
and mouse alone, it sends their descriptors and then nothing.
@bdbarnett bdbarnett changed the title cast: sound on the Miracast cast, from the P4's pump or a desktop's speaker Cast sound and input: Miracast sound from a desktop, a working RokuAudioSink, touch and remote over UIBC Oct 29, 2026
Five fingers per 0x13 report with X and Y 0..32767, a remote of one 16-bit
consumer usage 0..0xFF, and the short 0x12 report it sends first.
The pump drives the I2S wire in stereo even for a mono app, so the cast read
the tap as mono and played an octave low; CastDisplay and drum_cast now take
it as 24 kHz stereo. RokuAudioSink imported time inside functions, which on a
board searches the filesystem each call (65 ms on the P4) and held its writes
to a tenth of the sound's rate; its server thread also spun in non-blocking
accepts. The P4 row of the sound table, measured on a Roku TV.
@bdbarnett
bdbarnett merged commit e8a7fc8 into main Oct 29, 2026
2 checks passed
@bdbarnett
bdbarnett deleted the cast/sound-input branch October 29, 2026 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant