Initial commit: LiveStream Platform
Backend: FastAPI + SQLAlchemy + SQLite Frontend: React + Vite + Ant Design (serif Anthropic theme) Media server: MediaMTX with edge node support Load balancing: round-robin / weighted / least-conn Multicast detection with automatic fallback Transcoding support via FFmpeg (configurable quality) hls.js player with line & quality switching Admin panel with password auth Windows compatible scripts
This commit is contained in:
commit
2e4594fa77
43 files changed
+2196
No files matched your search
@@ -0,0 +1,64 @@
|
||||
import socket
|
||||
import struct
|
||||
import asyncio
|
||||
from config import settings
|
||||
|
||||
|
||||
def check_multicast_reachable(mcast_addr: str = "239.0.0.1", port: int = 9999, timeout: float = 2.0) -> bool:
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
sock.settimeout(timeout)
|
||||
ttl = struct.pack("b", 1)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
|
||||
|
||||
mreq = struct.pack("4sL", socket.inet_aton(mcast_addr), socket.INADDR_ANY)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||
|
||||
sock.sendto(b"ping", (mcast_addr, port))
|
||||
try:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
sock.close()
|
||||
return True
|
||||
except socket.timeout:
|
||||
sock.close()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class MulticastDetector:
|
||||
def __init__(self):
|
||||
self._multicast_available: bool | None = None
|
||||
|
||||
def is_available(self) -> bool:
|
||||
if self._multicast_available is not None:
|
||||
return self._multicast_available
|
||||
|
||||
if not settings.multicast_enabled:
|
||||
self._multicast_available = False
|
||||
return False
|
||||
|
||||
self._multicast_available = check_multicast_reachable()
|
||||
return self._multicast_available
|
||||
|
||||
def get_stream_url(self, stream_key: str, node: dict, quality: dict | None = None):
|
||||
use_multicast = self.is_available()
|
||||
host = node["host"]
|
||||
|
||||
if use_multicast:
|
||||
hash_val = abs(hash(stream_key)) % 255
|
||||
mcast_addr = f"{settings.multicast_address_base.rsplit('.', 1)[0]}.{hash_val + 1}"
|
||||
mcast_port = settings.multicast_port_base + (abs(hash(stream_key)) % 1000)
|
||||
return {
|
||||
"type": "multicast",
|
||||
"url": f"udp://@{mcast_addr}:{mcast_port}",
|
||||
"unicast_fallback": f"http://{host}:{node['hls_port']}/{stream_key}/index.m3u8",
|
||||
}
|
||||
|
||||
return {
|
||||
"type": "hls",
|
||||
"url": f"http://{host}:{node['hls_port']}/{stream_key}/index.m3u8",
|
||||
}
|
||||
|
||||
|
||||
multicast_detector = MulticastDetector()
|
||||
Reference in new issue
Block a user