#!/usr/bin/python3

import time
import threading
from scapy.all import sniff, UDP
import subprocess

# CONFIGURATION
interface = "eth0"  # Set to your interface name
check_interval = 5  # Time interval in seconds
max_http_bandwidth = 10000  # in kbit/sec (3 Mbps)
min_http_bandwidth = 3000   # in kbit/sec
rtp_packets_per_step = 100  # sensitivity
bandwidth_step_kbit = 250
no_rtp_reset_threshold = 3  # intervals (e.g., 3 * 5s = 15s of no RTP → reset)

# STATE
rtp_packet_count = 0
no_rtp_intervals = 0
bandwidth_limited = False

lock = threading.Lock()

def is_rtp_packet(packet):
    if packet.haslayer(UDP):
        udp = packet[UDP]
        return 16000 <= udp.dport <= 42000 or 16000 <= udp.sport <= 42000
    return False

def packet_counter(packet):
    global rtp_packet_count
    if is_rtp_packet(packet):
        with lock:
            rtp_packet_count += 1

def monitor_rtp():
    print("🎧 Listening for RTP packets (UDP 16000–42000)...")
    sniff(filter="udp", prn=packet_counter, store=False)

def apply_tc_limit(rate_kbit):
    # Remove previous qdisc if exists
    subprocess.run(["tc", "qdisc", "del", "dev", interface, "root"], stderr=subprocess.DEVNULL)
    print(f"🚦 Throttling HTTP/HTTPS to {rate_kbit} kbit/sec")

    # Apply tbf for rate limiting (all traffic unless filtered)
    subprocess.run([
        "tc", "qdisc", "add", "dev", interface, "root", "tbf",
        "rate", f"{rate_kbit}kbit", "burst", "32kbit", "latency", "400ms"
    ])

def remove_tc_limit():
    subprocess.run(["tc", "qdisc", "del", "dev", interface, "root"], stderr=subprocess.DEVNULL)
    print("✅ RTP traffic gone. HTTP/HTTPS throttling removed (restored full bandwidth).")

def adjust_bandwidth():
    global rtp_packet_count, no_rtp_intervals, bandwidth_limited

    while True:
        time.sleep(check_interval)

        with lock:
            current_rtp = rtp_packet_count
            rtp_packet_count = 0

        if current_rtp > 0:
            no_rtp_intervals = 0
            steps = current_rtp // rtp_packets_per_step
            reduction = steps * bandwidth_step_kbit
            new_bandwidth = max(min_http_bandwidth, max_http_bandwidth - reduction)
            apply_tc_limit(new_bandwidth)
            bandwidth_limited = True
            print(f"[INFO] RTP={current_rtp} pkts → Throttle to {new_bandwidth} kbit/sec")
        else:
            no_rtp_intervals += 1
            print(f"[INFO] No RTP packets. Inactive count = {no_rtp_intervals}")
            if no_rtp_intervals >= no_rtp_reset_threshold and bandwidth_limited:
                remove_tc_limit()
                bandwidth_limited = False

def main():
    threading.Thread(target=monitor_rtp, daemon=True).start()
    adjust_bandwidth()

if __name__ == "__main__":
    main()

