Skip to content

Restreaming to phone via Wi-Fi Hotspot or Gadget mode#116

Open
Lupinixx wants to merge 13 commits intoOpenIPC:masterfrom
Lupinixx:gstreamer-tee-restreaming
Open

Restreaming to phone via Wi-Fi Hotspot or Gadget mode#116
Lupinixx wants to merge 13 commits intoOpenIPC:masterfrom
Lupinixx:gstreamer-tee-restreaming

Conversation

@Lupinixx
Copy link

@Lupinixx Lupinixx commented Mar 11, 2026

Adds the ability to restream the live RTP video feed to a phone (or any UDP client) on the local network, with no impact on the main decode pipeline.

How it works

The GStreamer receive pipeline is extended with a second branch off the existing tee element:

udpsrc/appsrc
    └── tee
         ├── depay → parse → appsink          (main decode path)
         └── queue leaky=downstream
                  └── valve drop=true
                           └── udpsink [restream target]:5600  (restream branch)

The queue with leaky=downstream runs the restream branch on a separate thread, so any stalls on the phone side (unreachable host, slow consumer) can never back-pressure into the tee and affect main pipeline latency. The valve element keeps the branch fully gated (drop=true) until a valid target IP is confirmed, so data never flows to the placeholder 0.0.0.0 host used in the initial pipeline string.

Target discovery

Connected clients are discovered by scanning /proc/net/arp, filtered to entries on wlan0 or usb0 with a valid MAC address and a confirmed ARP flags value. The active target IP is probed every second and the udpsink host property is updated dynamically at runtime — the valve only opens once a valid IP is found.

UI

A new "Stream To" dropdown and toggle switch are added to the Wi-Fi settings page. The client list is populated when the page loads. The user can select:

Auto — automatically uses the first discovered ARP client
A specific IP — manually overrides auto-discovery (persists for the session)

Notable design decisions
All restream state (valve, sink, target IP, enable flag) is mutex-protected and fully independent from the IDR/stream-tracking logic
The valve stays closed during initial target probing so no data is ever transmitted to the placeholder host
The manual IP is cleared on each retarget probe, ensuring a changed network topology is always picked up

@speatzle
Copy link

Would you consider adding an option to permanently specify a IP to stream to? I have hacked together a similar solution for myself, but i need to stream via ethernet to a static IP which does not change. In my case the GS might get reset while it is out of my reach which would make this not very usable for me if it forgets the IP.

@Lupinixx
Copy link
Author

Would you consider adding an option to permanently specify a IP to stream to? I have hacked together a similar solution for myself, but i need to stream via ethernet to a static IP which does not change. In my case the GS might get reset while it is out of my reach which would make this not very usable for me if it forgets the IP.

This would probably be a good feature, right now it only detects IP's when the groundstation is the server/router, but when it is connected to a router as a client this won't work either. I'll look into it, no promises yet though!

@henkwiedig
Copy link
Collaborator

henkwiedig commented Mar 13, 2026

Does it make sense to swap the positions of valve and queue ?
In my testing the queue consumes ~14% cpu while idle.
I guess because it needs to evaluate if frames need to be dropped, which is useless work at that time.
When i swap the order the queue will only get data when streaming is enabled.

I get glitchy output, see example

2026-03-13.08-31-07.mp4

You see VLC captureing hdmi out and gstreamer playing the stream.

@henkwiedig
Copy link
Collaborator

Maybe also add "silent=true" to the queue.

@Lupinixx
Copy link
Author

Implemented you suggested changes, makes perfect sense.
When i restream to my PC with the sbc connected to my router (over 5ghz) i also observe a lot of streaming artifacting, but not like the artifacts you get. When i connect my phone directly to the sbcs hotspot (with 2.4ghz) and use pixelpilot, i rarely see any artifacts. Might be due to frames getting dropped from the leaky queue? Not too sure.

Here on the left the sbc over hdmi capture, and on the right the restreamed video in aviateur

2026-03-13.10-50-52.mp4

static std::string create_restream_branch() {
std::stringstream ss;
ss << " rtp_tee. ! valve name=restream_valve drop=true"
" ! queue leaky=downstream max-size-buffers=10 max-size-bytes=0 max-size-time=0 silent=true"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
" ! queue leaky=downstream max-size-buffers=10 max-size-bytes=0 max-size-time=0 silent=true"
" ! queue leaky=downstream max-size-buffers=0 max-size-bytes=0 max-size-time=1000000000 silent=true"

Played with the queue buffer settings and get way more consistent results useing this change.
Both on WLAN 2.4 and gadget.

@henkwiedig
Copy link
Collaborator

henkwiedig commented Mar 13, 2026

Maybe also a good idea to request an IDR frame when or shortly after the streaming starts so that the client can sync up quickly.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants