| 92 | } |
| 93 | |
| 94 | void PanadapterStream::init() |
| 95 | { |
| 96 | if (!m_socket) { |
| 97 | m_socket = new QUdpSocket(this); |
| 98 | } |
| 99 | if (!m_wanRegisterTimer) { |
| 100 | m_wanRegisterTimer = new QTimer(this); |
| 101 | } |
| 102 | if (!m_wanPingTimer) { |
| 103 | m_wanPingTimer = new QTimer(this); |
| 104 | } |
| 105 | if (!m_routedPrimeTimer) { |
| 106 | m_routedPrimeTimer = new QTimer(this); |
| 107 | } |
| 108 | |
| 109 | // Pick up the persisted PLC toggle. Default true — strictly better in |
| 110 | // the failure mode and a no-op when no packets are lost. (#2731) |
| 111 | m_plcEnabled.store( |
| 112 | AppSettings::instance().value("AudioPacketLossConcealment", "True") |
| 113 | .toString() == "True"); |
| 114 | |
| 115 | // Seed the receive-buffer request from the persisted operator setting; each |
| 116 | // bind path then applies it via applyReceiveBufferSize(). (#3810) |
| 117 | m_desiredRcvBufBytes = NetworkSettings::vitaReceiveBufferBytes(); |
| 118 | |
| 119 | connect(m_socket, &QUdpSocket::readyRead, |
| 120 | this, &PanadapterStream::onDatagramReady); |
| 121 | |
| 122 | // WAN UDP register: send "client udp_register handle=0x<handle>" every 50ms |
| 123 | // until first VITA-49 packet arrives (confirms radio knows our address). |
| 124 | connect(m_wanRegisterTimer, &QTimer::timeout, this, [this] { |
| 125 | if (m_radioAddress.isNull() || m_wanClientHandle == 0) return; |
| 126 | const QString hex = QString::number(m_wanClientHandle, 16).toUpper(); |
| 127 | const QByteArray cmd = QStringLiteral("client udp_register handle=0x%1").arg(hex).toUtf8(); |
| 128 | const qint64 sent = m_socket->writeDatagram(cmd, m_radioAddress, m_radioPort); |
| 129 | if (sent > 0) |
| 130 | m_totalTxBytes.fetch_add(sent); |
| 131 | }); |
| 132 | |
| 133 | // WAN ping keepalive: send "client ping handle=0x<handle>" every 5s |
| 134 | // to maintain NAT pinhole after registration is confirmed. |
| 135 | connect(m_wanPingTimer, &QTimer::timeout, this, [this] { |
| 136 | if (m_radioAddress.isNull() || m_wanClientHandle == 0) return; |
| 137 | const QString hex = QString::number(m_wanClientHandle, 16).toUpper(); |
| 138 | const QByteArray cmd = QStringLiteral("client ping handle=0x%1").arg(hex).toUtf8(); |
| 139 | m_socket->writeDatagram(cmd, m_radioAddress, m_radioPort); |
| 140 | m_totalTxBytes.fetch_add(cmd.size()); |
| 141 | qCDebug(lcVita49) << "PanadapterStream: WAN ping keepalive" |
| 142 | << "(totalRx:" << m_totalRxBytes.load() << "bytes)"; |
| 143 | }); |
| 144 | |
| 145 | connect(m_routedPrimeTimer, &QTimer::timeout, this, [this] { |
| 146 | if (m_isWanMode || m_hasReceivedPacket || m_radioAddress.isNull()) |
| 147 | return; |
| 148 | if (!m_routedPrimeElapsed.isValid() || m_routedPrimeElapsed.elapsed() >= 2000) { |
| 149 | m_routedPrimeTimer->stop(); |
| 150 | return; |
| 151 | } |