kwik icon indicating copy to clipboard operation
kwik copied to clipboard

Frequent data transmission can lead to connection interruption

Open jiajialaixi opened this issue 8 months ago • 10 comments

Sending audio and video frames using Quic will interrupt the transmission of data, and the data packet has been modified based on feedback from the server

`package com.saida.video_call.quic.library.quic

import android.util.Log import com.saida.play.video_play_plugin.quic.Message import com.saida.play.video_play_plugin.quic.utils.IO import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import tech.kwik.agent15.env.PlatformMapping import tech.kwik.core.ConnectionEstablishedEvent import tech.kwik.core.ConnectionListener import tech.kwik.core.ConnectionTerminatedEvent import tech.kwik.core.QuicClientConnection import tech.kwik.core.QuicStream import tech.kwik.core.log.SysOutLogger import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.io.OutputStream import java.net.URI import java.util.concurrent.locks.ReentrantLock import kotlinx.coroutines.channels.Channel import kotlin.coroutines.cancellation.CancellationException

class QUICConnection(var quicStreamInterface: QUICStreamInterface) : ConnectionListener {

companion object {
    private const val TAG = "QUICConnection"
    private var mQUICConnection: QuicClientConnection? = null
    private var mQUICStream: QuicStream? = null
    private var mQUICOutputStream: OutputStream? = null
    private var mQUICInputStream: BufferedInputStream? = null

}

private var handshakeData: ByteArray? = null
private var mLock = ReentrantLock()

fun initQUICConnection(ip: String, handshakeData1: ByteArray) {
    val connectionListener = this
    CoroutineScope(Dispatchers.IO).launch {
        PlatformMapping.usePlatformMapping(PlatformMapping.Platform.Android)
      var  log = SysOutLogger()
        log.logDebug(true)
        log.logRaw(true)
        log.logDecrypted(true)
        log.logSecrets(true)
        log.logPackets(true)
        log.logInfo(true)
        log.logWarning(true)
        log.logStats(true)
        log.logRecovery(true)
        log.logCongestionControl(true)
        log.logFlowControl(true)
        log.useRelativeTime(true)
        try {
            mQUICConnection = QuicClientConnection.newBuilder()
                .noServerCertificateCheck()
                .uri(URI.create(String.format("SaidaClient://%s", ip)))
                .defaultStreamReceiveBufferSize((1024 * 1024 * 2))
                .applicationProtocol("SaidaClient")
                .enableDatagramExtension()
                .logger(log)
                .build()

            handshakeData = handshakeData1
            mQUICConnection?.setConnectionListener(connectionListener)
            mQUICConnection?.connect()
        } catch (e: Exception) {
            Log.d(TAG, "initQUICConnection: " + e.message)
            quicStreamInterface.disconnected()
        }
    }

}



fun sendData(data: ByteArray) {
    CoroutineScope(Dispatchers.IO).launch {
        mLock.lock()
        try {
            if (mQUICOutputStream == null) {
                return@launch
            }
            mQUICOutputStream?.write(data)
            mQUICOutputStream?.flush()
        } catch (e: Exception) {
        } finally {
            mLock.unlock()
        }
    }
}


fun release() {
    mQUICOutputStream?.close()
    mQUICInputStream?.close()
    mQUICConnection?.closeAndWait()
    mQUICOutputStream = null
    mQUICConnection = null
    mQUICInputStream = null
}


override fun disconnected(connectionTerminatedEvent: ConnectionTerminatedEvent?) {
    quicStreamInterface.disconnected()
    release()
}

override fun connected(connectionEstablishedEvent: ConnectionEstablishedEvent?) {
    super.connected(connectionEstablishedEvent)
    mQUICStream = mQUICConnection?.createStream(true)
    mQUICInputStream =
        BufferedInputStream(mQUICStream!!.inputStream, 1024 * 1024 * 2)
    mQUICOutputStream = mQUICStream?.outputStream

    sendData(handshakeData!!)
    val header = ByteArray(12)
    quicStreamInterface.connected()
    CoroutineScope(Dispatchers.IO).launch {
        try {
            while (true) {
                IO.readFull(mQUICInputStream, header, 0, 12)
                val headerObj = Message.Header.newHeader(header)
                when (headerObj.subType) {
                    Message.Header.MEDIA_CONTROL_TYPE_KEY_FRAME -> {
                        quicStreamInterface.requestStreamKeyFrame()
                    }
                }
            }
        } catch (e: Exception) {
            e.message
        }
    }

}

}`

log:

log.log

jiajialaixi avatar Apr 10 '25 07:04 jiajialaixi

Can you explain what you mean by

  • Quic will interrupt the transmission of data
  • the data packet has been modified

Try to make it very concrete. What do see, what is happening that you didn't expect? How did you notice? Do you have some "evidence", e.g. a WireShark capture that shows what is going on? Why do you think the problem is in Kwik?

I would really like to investigate, but I need more information; now I don't need were to start.

Cheers Peter

ptrd avatar Apr 10 '25 10:04 ptrd

I notice you enable the datagram extension. Do you really use it? Datagram extension is sending data unreliably by design!

ptrd avatar Apr 10 '25 10:04 ptrd

quic-log.zip I deleted the datagram but still encountered this issue. Currently, I obtained the data through WireShark

jiajialaixi avatar Apr 10 '25 12:04 jiajialaixi

To make sense of the pcap, i also need the keys. You can let kwik export the keys.

And you still need to explain what exactly your problem is, as i asked in the previous comment. I don't have a crystal ball, for me to investigate an issue, I do need to know what exactly the issue is.

ptrd avatar Apr 10 '25 13:04 ptrd

Hi @jiajialaixi

Any update? If you found/fixed the issue yourself, please let me know so we can close this issue.

ptrd avatar Apr 13 '25 19:04 ptrd

I haven't found where the problem lies yet. Currently, there is a packet sticking issue with the data I transmit using TCP. If I replace the corresponding transmission function with KWIK, this problem will also occur. However, using TCP's middle function setTcpNoDelay can solve the corresponding packet sticking issue. KWIK has not found any API to handle this function yet

jiajialaixi avatar Apr 15 '25 14:04 jiajialaixi

Simulate sending 320 bytes of audio in 40 milliseconds and 5000 bytes of video data in 25 milliseconds to reproduce

jiajialaixi avatar Apr 15 '25 14:04 jiajialaixi

I don't understand what you mean by "packet sticking". There is no delay in current version of Kwik, when you write one byte, it is sent immediately.

How are these 320 bytes sent? One block of 320 bytes, or 10 times 32 bytes, how big was the delay in between, etc. What is going wrong exactly? What do you see what is happening or is not happening? If bytes are not received, which bytes? Just the last part, or bytes somewhere in the middle of the data? Don't say: bytes are not sent, if you are not sure this is the case, maybe there is a bug in your receiver that makes it look these bytes are not received. By precise about what you see.

Please configure kwik to write the secrets to a file, record a session with WireShark and provide me with the pcap and the secrets. This will give facts that might help to track down the issue.

You need to be much more specific and precise. Kwik sends files of all kinds of sizes and in with all kinds of network conditions without any error, this is tested 3x a day with the interop tests (https://interop.seemann.io), so if you experience data loss, there is something very special about your case, which we need to find. I cannot find a problem when I do not understand what the problem exactly is. Talking "sticking packets" does not help, I need facts. E.g. "I sent 320 bytes of data and I received only 269 and when I compare data sent and data received it seems that 41 consecutive bytes in the middle of these 320 byte are missing. It can't be a bug in my server because ....... The WireShark capture shows that for stream 4, the bytes at position 120 - 160 in the stream are never sent". Ok?

ptrd avatar Apr 15 '25 19:04 ptrd

Any news @jiajialaixi ?

ptrd avatar Apr 22 '25 18:04 ptrd

The same connection works fine on Java, but there is a current issue on Android that has not been identified yet

jiajialaixi avatar Apr 27 '25 01:04 jiajialaixi