-
Notifications
You must be signed in to change notification settings - Fork 57
Add Ground Station Streaming: hand video/telemetry ports to an external app #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mengelh
wants to merge
1
commit into
OpenIPC:master
Choose a base branch
from
mengelh:ground-station-streaming
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -662,6 +662,9 @@ private void showSettingsMenu(View anchor) { | |
| // UDP Forwarding submenu | ||
| setupUdpForwardingSubMenu(popup); | ||
|
|
||
| // Ground Station Streaming submenu | ||
| setupGroundStationStreamingSubMenu(popup); | ||
|
|
||
| // Help submenu | ||
| setupHelpSubMenu(popup); | ||
|
|
||
|
|
@@ -1162,12 +1165,112 @@ private void setupHelpSubMenu(PopupMenu popup) { | |
|
|
||
| /** | ||
| * Starts the native Mavlink service and posts an initial Runnable to the Handler. | ||
| * | ||
| * When telemetry streaming is enabled, wfb-ng's own mavlink_aggregator | ||
| * already forwards the raw MAVLink stream to 127.0.0.1:14550 (see | ||
| * WfbngLink::initAgg). Skip this app-internal OSD parser so it doesn't | ||
| * compete for that port. | ||
| */ | ||
| private void setupMavlink() { | ||
| if (isTelemetryStreamingEnabled()) { | ||
| return; | ||
| } | ||
| MavlinkNative.nativeStart(this); | ||
| handler.post(runnable); | ||
| } | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
| // GROUND STATION STREAMING | ||
| // ---------------------------------------------------------------------------- | ||
| // Two independent toggles, since a ground station app might only care about | ||
| // one channel (e.g. a video-only OSD box, or a telemetry-only companion | ||
| // computer). wfb-ng's own aggregators forward raw RTP/H264 and MAVLink to | ||
| // 127.0.0.1:5600/14550 unconditionally (see WfbngLink::initAgg) regardless | ||
| // of these settings -- they only decide whether this app's own in-app | ||
| // consumers compete for those same ports, so any UDP-based ground station | ||
| // app (QGroundControl, Mission Planner, a custom OSD, ...) works, not just | ||
| // QGroundControl specifically. | ||
|
|
||
| private static final String PREF_STREAM_VIDEO = "gs_stream_video"; | ||
| private static final String PREF_STREAM_TELEMETRY = "gs_stream_telemetry"; | ||
|
|
||
| public boolean isVideoStreamingEnabled() { | ||
| return getSharedPreferences("general", MODE_PRIVATE).getBoolean(PREF_STREAM_VIDEO, false); | ||
| } | ||
|
|
||
| public boolean isTelemetryStreamingEnabled() { | ||
| return getSharedPreferences("general", MODE_PRIVATE).getBoolean(PREF_STREAM_TELEMETRY, false); | ||
| } | ||
|
|
||
| /** | ||
| * True while either channel is being streamed out -- used to keep the | ||
| * USB/wfb-ng pipeline alive across pause/resume instead of stopping it | ||
| * (see onPause()/onStop()). Both channels share one adapter, so it can't | ||
| * be paused for one and kept alive for the other. | ||
| */ | ||
| private boolean isGroundStationStreamingActive() { | ||
| return isVideoStreamingEnabled() || isTelemetryStreamingEnabled(); | ||
| } | ||
|
|
||
| /** | ||
| * Persists the new video-streaming mode and applies it immediately | ||
| * instead of requiring a restart -- starting or stopping the in-app video | ||
| * player right away. | ||
| */ | ||
| private void setVideoStreamingEnabled(boolean enabled) { | ||
| getSharedPreferences("general", MODE_PRIVATE).edit().putBoolean(PREF_STREAM_VIDEO, enabled).apply(); | ||
| if (enabled) { | ||
| videoPlayer.stop(); | ||
| videoPlayer.stopAudio(); | ||
| } else { | ||
| videoPlayer.start(); | ||
| updateUdpForwardingState(); | ||
| videoPlayer.startAudio(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Persists the new telemetry-streaming mode and applies it immediately -- | ||
| * starting or stopping the in-app MAVLink OSD parser right away. | ||
| */ | ||
| private void setTelemetryStreamingEnabled(boolean enabled) { | ||
| getSharedPreferences("general", MODE_PRIVATE).edit().putBoolean(PREF_STREAM_TELEMETRY, enabled).apply(); | ||
| if (enabled) { | ||
| MavlinkNative.nativeStop(this); | ||
| handler.removeCallbacks(runnable); | ||
| } else { | ||
| MavlinkNative.nativeStart(this); | ||
| handler.post(runnable); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Settings submenu with the two streaming toggles. | ||
| */ | ||
| private void setupGroundStationStreamingSubMenu(PopupMenu popup) { | ||
| SubMenu gsMenu = popup.getMenu().addSubMenu("Ground Station Streaming"); | ||
|
|
||
| MenuItem videoItem = gsMenu.add("Video"); | ||
| videoItem.setCheckable(true); | ||
| videoItem.setChecked(isVideoStreamingEnabled()); | ||
| videoItem.setOnMenuItemClickListener(item -> { | ||
| boolean newState = !item.isChecked(); | ||
| item.setChecked(newState); | ||
| setVideoStreamingEnabled(newState); | ||
| return true; | ||
| }); | ||
|
|
||
| MenuItem telemetryItem = gsMenu.add("Telemetry"); | ||
| telemetryItem.setCheckable(true); | ||
| telemetryItem.setChecked(isTelemetryStreamingEnabled()); | ||
| telemetryItem.setOnMenuItemClickListener(item -> { | ||
| boolean newState = !item.isChecked(); | ||
| item.setChecked(newState); | ||
| setTelemetryStreamingEnabled(newState); | ||
| return true; | ||
| }); | ||
| } | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
| // BATTERY RECEIVER | ||
| // ---------------------------------------------------------------------------- | ||
|
|
@@ -1545,7 +1648,18 @@ protected void onPause() { | |
|
|
||
| videoPlayer.stop(); | ||
| videoPlayer.stopAudio(); | ||
| wfbLinkManager.stopAdapters(); | ||
| // While streaming to QGroundControl the whole point is for wfb-ng to keep | ||
| // decoding and forwarding to 127.0.0.1:5600/14550 while this Activity is | ||
| // backgrounded. Stopping/restarting the USB adapter on every pause/resume | ||
| // also hits a native teardown race in devourer's RtlJaguarDevice | ||
| // destructor (rtw_hal_deinit on a device that hasn't finished bringing up | ||
| // yet) when the two happen in quick succession. A real Foreground Service | ||
| // (Phase 4) is still needed for guaranteed survival under memory pressure | ||
| // -- this only keeps the pipeline alive across ordinary Activity | ||
| // lifecycle transitions. | ||
| if (!isGroundStationStreamingActive()) { | ||
| wfbLinkManager.stopAdapters(); | ||
| } | ||
|
Comment on lines
+1660
to
+1662
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. Exiting leaves the radio pipeline running The new lifecycle conditions skip stopAdapters() whenever either persisted streaming preference is enabled, but the activity has no destruction cleanup for the retained native link, USB connection, thread, or callback timer. Finishing or recreating the activity therefore leaves its old pipeline holding the adapter and activity context, and reopening constructs another link that attempts to use the same statically tracked device. Agent Prompt
|
||
|
|
||
| // Stop VPN service | ||
| Log.w(TAG, "onPause: stopping service"); | ||
|
|
@@ -1559,7 +1673,11 @@ protected void onStop() { | |
| MavlinkNative.nativeStop(this); | ||
| handler.removeCallbacks(runnable); | ||
| unregisterReceivers(); | ||
| wfbLinkManager.stopAdapters(); | ||
| // See the comment in onPause() -- streaming mode keeps the USB/wfb-ng | ||
| // pipeline running across ordinary lifecycle transitions. | ||
| if (!isGroundStationStreamingActive()) { | ||
| wfbLinkManager.stopAdapters(); | ||
| } | ||
| videoPlayer.stop(); | ||
| videoPlayer.stopAudio(); | ||
| super.onStop(); | ||
|
|
@@ -1576,9 +1694,15 @@ protected void onResume() { | |
| wfbLinkManager.refreshAdapters(); | ||
|
|
||
| wfbLinkManager.startAdapters(); | ||
| videoPlayer.start(); | ||
| updateUdpForwardingState(); | ||
| videoPlayer.startAudio(); | ||
| // While video streaming is enabled, skip the in-app video/audio | ||
| // receiver: wfb-ng's own video_aggregator already forwards RTP/H264 to | ||
| // 127.0.0.1:5600 (see WfbngLink::initAgg), and the ground station app | ||
| // binds that port instead. | ||
| if (!isVideoStreamingEnabled()) { | ||
| videoPlayer.start(); | ||
| updateUdpForwardingState(); | ||
| videoPlayer.startAudio(); | ||
| } | ||
|
|
||
| SharedPreferences prefs = getSharedPreferences("general", MODE_PRIVATE); | ||
| boolean odEnabled = prefs.getBoolean("od_enabled", false); | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. Telemetry never returns in-app
🐞 Bug≡ CorrectnessAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools