|
33 | 33 | #undef TAG |
34 | 34 | #define TAG "pixelpilot" |
35 | 35 |
|
| 36 | +#define CRASH() do{ int* i=0; *i = 42; }while(0) |
| 37 | + |
36 | 38 | std::string generate_random_string(size_t length) { |
37 | 39 | const std::string characters = "abcdefghijklmnopqrstuvwxyz"; |
38 | 40 | std::random_device rd; |
@@ -266,10 +268,16 @@ int WfbngLink::run(JNIEnv *env, jobject context, jint wifiChannel, jint bw, jint |
266 | 268 | } |
267 | 269 |
|
268 | 270 | 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 | + } |
270 | 276 | auto dev = rtl_devices.at(fd).get(); |
271 | 277 | if (dev) { |
272 | 278 | dev->should_stop = true; |
| 279 | + } else { |
| 280 | + __android_log_print(ANDROID_LOG_ERROR, TAG, "rtl_devices.at(%d) is nullptr", fd); |
273 | 281 | } |
274 | 282 | stop_adaptive_link(); |
275 | 283 | } |
@@ -384,6 +392,76 @@ extern "C" JNIEXPORT void JNICALL Java_com_openipc_wfbngrtl8812_WfbNgLink_native |
384 | 392 | native(wfbngLinkN)->initAgg(); |
385 | 393 | } |
386 | 394 |
|
| 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 | + |
387 | 465 | // Modified start_link_quality_thread: use adaptive_link_enabled and adaptive_tx_power |
388 | 466 | void WfbngLink::start_link_quality_thread(int fd) { |
389 | 467 | auto thread_func = [this, fd]() { |
@@ -458,18 +536,34 @@ void WfbngLink::start_link_quality_thread(int fd) { |
458 | 536 | optional idr_request_code: 4 char unique code to request 1 keyframe (no need to send special extra |
459 | 537 | packets) |
460 | 538 | */ |
| 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 | + |
461 | 555 | snprintf(message + sizeof(len), |
462 | 556 | 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", |
464 | 558 | static_cast<long>(currentEpoch), |
465 | 559 | quality.quality, |
466 | 560 | quality.quality, |
467 | 561 | quality.recovered_last_second, |
468 | 562 | quality.lost_last_second, |
469 | 563 | quality.quality, |
470 | 564 | quality.snr, |
| 565 | + fec.value(), |
471 | 566 | quality.idr_code.c_str()); |
472 | | - |
473 | 567 | len = strlen(message + sizeof(len)); |
474 | 568 | len = htonl(len); |
475 | 569 | memcpy(message, &len, sizeof(len)); |
@@ -534,3 +628,10 @@ extern "C" JNIEXPORT void JNICALL Java_com_openipc_wfbngrtl8812_WfbNgLink_native |
534 | 628 | } |
535 | 629 | } |
536 | 630 | } |
| 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 | +} |
0 commit comments