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)