Skip to content

Commit 46c19d9

Browse files
authored
Use dynamic FEC (#69)
1 parent 39da6ae commit 46c19d9

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed

app/src/main/java/com/openipc/pixelpilot/VideoActivity.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,24 @@ private void setupAdaptiveLinkSubMenu(PopupMenu popup) {
717717
return true;
718718
});
719719
}
720+
721+
// Adaptive use FEC submenu
722+
boolean fecEnabled = prefs.getBoolean("custom_fec_enabled", true);
723+
724+
MenuItem fecEnable = adaptiveMenu.add("FEC");
725+
fecEnable.setCheckable(true);
726+
fecEnable.setChecked(fecEnabled);
727+
fecEnable.setOnMenuItemClickListener(item -> {
728+
boolean newState = !item.isChecked();
729+
item.setChecked(newState);
730+
SharedPreferences.Editor editor = getSharedPreferences("general", MODE_PRIVATE).edit();
731+
editor.putBoolean("custom_fec_enabled", newState);
732+
editor.apply();
733+
// Call instance method on the WfbNgLink instance via the wfbLinkManager.
734+
wfbLink.nativeSetUseFec(newState ? 1 : 0);
735+
return true;
736+
});
737+
720738
}
721739

722740
void initDefaultOptions(){

app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#undef TAG
3434
#define TAG "pixelpilot"
3535

36+
#define CRASH() do{ int* i=0; *i = 42; }while(0)
37+
3638
std::string generate_random_string(size_t length) {
3739
const std::string characters = "abcdefghijklmnopqrstuvwxyz";
3840
std::random_device rd;
@@ -266,10 +268,16 @@ int WfbngLink::run(JNIEnv *env, jobject context, jint wifiChannel, jint bw, jint
266268
}
267269

268270
void WfbngLink::stop(JNIEnv *env, jobject context, jint fd) {
269-
if (rtl_devices.find(fd) == rtl_devices.end()) return;
271+
if (rtl_devices.find(fd) == rtl_devices.end()) {
272+
__android_log_print(ANDROID_LOG_ERROR, TAG, "rtl_devices.find(%d) == rtl_devices.end()", fd);
273+
CRASH();
274+
return;
275+
}
270276
auto dev = rtl_devices.at(fd).get();
271277
if (dev) {
272278
dev->should_stop = true;
279+
} else {
280+
__android_log_print(ANDROID_LOG_ERROR, TAG, "rtl_devices.at(%d) is nullptr", fd);
273281
}
274282
stop_adaptive_link();
275283
}
@@ -384,6 +392,76 @@ extern "C" JNIEXPORT void JNICALL Java_com_openipc_wfbngrtl8812_WfbNgLink_native
384392
native(wfbngLinkN)->initAgg();
385393
}
386394

395+
396+
class FecChangeController
397+
{
398+
public:
399+
/// \brief Query the current (possibly decayed) fec_change value.
400+
/// Call this as often as you like; the class handles its own timing.
401+
int value()
402+
{
403+
if (!mEnabled)
404+
return 0;
405+
406+
std::lock_guard<std::mutex> lock(mx_);
407+
decayLocked_();
408+
return val_;
409+
}
410+
411+
/// \brief Raise fec_change. If newValue <= current, the call is ignored.
412+
/// A successful bump resets the 5-second “hold” timer.
413+
void bump(int newValue)
414+
{
415+
std::lock_guard<std::mutex> lock(mx_);
416+
if (newValue > val_) {
417+
__android_log_print(ANDROID_LOG_ERROR, TAG, "bumping FEC: %d", newValue);
418+
419+
val_ = newValue;
420+
lastChange_ = Clock::now();
421+
}
422+
}
423+
424+
void setEnabled(bool use){
425+
mEnabled = use;
426+
}
427+
428+
private:
429+
using Clock = std::chrono::steady_clock;
430+
static constexpr std::chrono::seconds kTick{1}; // length of one hold/decay window
431+
432+
void decayLocked_()
433+
{
434+
if (val_ == 0) return;
435+
436+
auto now = Clock::now();
437+
auto elapsed = now - lastChange_;
438+
439+
// Still inside the mandatory 5-second hold? Do nothing.
440+
if (elapsed < kTick) return;
441+
442+
// How many *full* ticks have passed since lastChange_?
443+
auto ticks = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count() / kTick.count();
444+
if (ticks == 0) return; // safety net (shouldn’t hit)
445+
446+
int decayed = val_ - static_cast<int>(ticks);
447+
if (decayed < 0) decayed = 0;
448+
449+
// Commit the decay and anchor lastChange_ on the most recent tick boundary
450+
if (decayed != val_) {
451+
val_ = decayed;
452+
lastChange_ += kTick * ticks;
453+
}
454+
}
455+
456+
int val_ {0};
457+
Clock::time_point lastChange_ {Clock::now()};
458+
std::mutex mx_;
459+
bool mEnabled = true;
460+
};
461+
462+
463+
FecChangeController fec;
464+
387465
// Modified start_link_quality_thread: use adaptive_link_enabled and adaptive_tx_power
388466
void WfbngLink::start_link_quality_thread(int fd) {
389467
auto thread_func = [this, fd]() {
@@ -458,18 +536,34 @@ void WfbngLink::start_link_quality_thread(int fd) {
458536
optional idr_request_code: 4 char unique code to request 1 keyframe (no need to send special extra
459537
packets)
460538
*/
539+
540+
if (quality.lost_last_second > 2)
541+
fec.bump(5);
542+
else {
543+
if(quality.recovered_last_second > 30)
544+
fec.bump(5);
545+
if (quality.recovered_last_second > 24)
546+
fec.bump(3);
547+
if (quality.recovered_last_second > 22)
548+
fec.bump(2);
549+
if (quality.recovered_last_second > 18)
550+
fec.bump(1);
551+
if (quality.recovered_last_second < 18)
552+
fec.bump(0);
553+
}
554+
461555
snprintf(message + sizeof(len),
462556
sizeof(message) - sizeof(len),
463-
"%ld:%d:%d:%d:%d:%d:%f:0:-1:0:%s\n",
557+
"%ld:%d:%d:%d:%d:%d:%f:0:-1:%d:%s\n",
464558
static_cast<long>(currentEpoch),
465559
quality.quality,
466560
quality.quality,
467561
quality.recovered_last_second,
468562
quality.lost_last_second,
469563
quality.quality,
470564
quality.snr,
565+
fec.value(),
471566
quality.idr_code.c_str());
472-
473567
len = strlen(message + sizeof(len));
474568
len = htonl(len);
475569
memcpy(message, &len, sizeof(len));
@@ -534,3 +628,10 @@ extern "C" JNIEXPORT void JNICALL Java_com_openipc_wfbngrtl8812_WfbNgLink_native
534628
}
535629
}
536630
}
631+
632+
extern "C" JNIEXPORT void JNICALL Java_com_openipc_wfbngrtl8812_WfbNgLink_nativeSetUseFec(JNIEnv *env,
633+
jclass clazz,
634+
jlong wfbngLinkN,
635+
jint use) {
636+
fec.setEnabled(use);
637+
}

app/wfbngrtl8812/src/main/java/com/openipc/wfbngrtl8812/WfbNgLink.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class WfbNgLink implements WfbNGStatsChanged {
3939
public static native void nativeStartAdaptivelink(long nativeInstance);
4040
public static native void nativeSetAdaptiveLinkEnabled(long nativeInstance, boolean enabled);
4141
public static native void nativeSetTxPower(long nativeInstance, int power);
42+
public static native void nativeSetUseFec(long nativeInstance, int use);
4243

4344
public WfbNgLink(final AppCompatActivity parent) {
4445
this.context = parent;
@@ -70,6 +71,10 @@ public void nativeSetTxPower(int power) {
7071
nativeSetTxPower(nativeWfbngLink, power);
7172
}
7273

74+
public void nativeSetUseFec(int use) {
75+
nativeSetUseFec(nativeWfbngLink, use);
76+
}
77+
7378
public synchronized void start(int wifiChannel, int bandWidth, UsbDevice usbDevice) {
7479
Log.d(TAG, "wfb-ng monitoring on " + usbDevice.getDeviceName() + " using wifi channel " + wifiChannel);
7580
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy