|
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