package de.duffy.screencast.miracast

import android.util.Log
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress

/**
 * Schickt die MPEG-TS-Pakete als RTP-Strom an den Fernseher - so verlangt es
 * der Wi-Fi-Display-Standard (Nutzlasttyp 33, sieben TS-Pakete je Datagramm).
 */
class RtpTsSender(private val target: InetAddress, private val targetPort: Int) {

    private val socket = DatagramSocket()
    private var sequence = 0
    private val ssrc = 0x5343_4153 // "SCAS"

    /** Port, von dem aus wir senden - den nennen wir dem Fernseher im SETUP. */
    val localPort: Int get() = socket.localPort

    fun send(tsData: ByteArray, ptsUs: Long) {
        val timestamp = (ptsUs * 90 / 1000) and 0xFFFFFFFFL
        var offset = 0
        while (offset < tsData.size) {
            val chunk = minOf(PACKETS_PER_DATAGRAM * TS_PACKET, tsData.size - offset)
            val datagram = ByteArray(12 + chunk)
            datagram[0] = 0x80.toByte()                    // Version 2
            datagram[1] = 33                               // MP2T
            datagram[2] = ((sequence shr 8) and 0xFF).toByte()
            datagram[3] = (sequence and 0xFF).toByte()
            datagram[4] = ((timestamp shr 24) and 0xFF).toByte()
            datagram[5] = ((timestamp shr 16) and 0xFF).toByte()
            datagram[6] = ((timestamp shr 8) and 0xFF).toByte()
            datagram[7] = (timestamp and 0xFF).toByte()
            datagram[8] = ((ssrc shr 24) and 0xFF).toByte()
            datagram[9] = ((ssrc shr 16) and 0xFF).toByte()
            datagram[10] = ((ssrc shr 8) and 0xFF).toByte()
            datagram[11] = (ssrc and 0xFF).toByte()
            System.arraycopy(tsData, offset, datagram, 12, chunk)
            sequence = (sequence + 1) and 0xFFFF
            offset += chunk
            try {
                socket.send(DatagramPacket(datagram, datagram.size, target, targetPort))
            } catch (e: Exception) {
                Log.w(TAG, "RTP-Paket ging nicht raus: ${e.message}")
                return
            }
        }
    }

    fun close() { try { socket.close() } catch (_: Exception) {} }

    companion object {
        private const val TAG = "RtpTsSender"
        const val TS_PACKET = 188
        const val PACKETS_PER_DATAGRAM = 7  // 7 * 188 = 1316 Byte, passt in ein Ethernet-Frame
    }
}
