diff --git a/docker-compose.yaml b/docker-compose.yaml index 0af55e9..a42a9a2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -51,6 +51,7 @@ services: - snoopBack snoop-api: + restart: unless-stopped build: context: ./server dockerfile: Dockerfile @@ -61,6 +62,7 @@ services: VAULT_TOKEN: "root" VAULT_KV_PATH: "kv/data/snoop" MINIO_ENDPOINT: "http://minio:9000" + JWT_SECRET: ${JWT_SECRET} env_file: - .env depends_on: @@ -75,6 +77,7 @@ services: web: + restart: unless-stopped build: context: ./management-ui dockerfile: Dockerfile @@ -95,12 +98,47 @@ services: networks: - proxy + mediamtx: + image: bluenviron/mediamtx:latest + # restart: unless-stopped + # Expose default listeners for all common protocols + ports: + - "8554:8554" # RTSP + - "1935:1935" # RTMP + - "8888:8888" # HLS / LL-HLS (HTTP) + - "8889:8889" # WebRTC HTTP (WHIP/WHEP/pages) + - "8189:8189/udp" # WebRTC ICE UDP + - "8890:8890/udp" # SRT + - "9997:9997" # Control API (enabled in config below; map if you want to access from host) + volumes: + - ./mediamtx/mediamtx.yml:/mediamtx.yml:ro,Z + - mediamtx-recordings:/recordings + networks: + - proxy + - snoopBack + rclone: + image: rclone/rclone:latest + command: rcd --rc-addr=:5572 --rc-no-auth + environment: + RCLONE_CONFIG_MINIO_TYPE: s3 + RCLONE_CONFIG_MINIO_PROVIDER: Minio + RCLONE_CONFIG_MINIO_ENDPOINT: http://minio:9000 + RCLONE_CONFIG_MINIO_ACCESS_KEY_ID: minioadmin + RCLONE_CONFIG_MINIO_SECRET_ACCESS_KEY: minioadmin + RCLONE_CONFIG_MINIO_REGION: us-east-1 + RCLONE_CONFIG_MINIO_FORCE_PATH_STYLE: "true" + volumes: + - mediamtx-recordings:/recordings + networks: + - snoopBack + - proxy volumes: pgdata: miniodata: vault-data: + mediamtx-recordings: networks: proxy: diff --git a/mediamtx/mediamtx.yml b/mediamtx/mediamtx.yml new file mode 100644 index 0000000..bf3168d --- /dev/null +++ b/mediamtx/mediamtx.yml @@ -0,0 +1,63 @@ +logLevel: info + +# Enable Control API (useful for debugging; bound to localhost by default) +api: yes +apiAddress: :9997 + +# RTSP / RTMP / HLS +rtsp: yes +rtspAddress: :8554 +rtmp: yes +rtmpAddress: :1935 +hls: yes +hlsAddress: :8888 +hlsVariant: lowLatency + +# WebRTC (browser-friendly) +webrtc: yes +webrtcAddress: :8889 +webrtcLocalUDPAddress: :8189 +# Optional: add a STUN server if behind NAT +# webrtcICEServers2: +# - url: stun:stun.l.google.com:19302 + +# SRT (for resilient ingest) +srt: yes +srtAddress: :8890 + +authMethod: http +authHTTPAddress: http://snoop-api:8080/mediamtx/auth + +# Recording (optional) +pathDefaults: + # record settings (per concurrent path/stream) + record: yes + recordFormat: fmp4 + recordPath: /recordings/%path/%Y-%m-%d_%H-%M-%S-%f + recordSegmentDuration: 10m + recordDeleteAfter: 7d + + # upload each completed segment to MinIO under: + # livestream// +# runOnRecordSegmentComplete: > +# sh -c 'd="$(dirname "$MTX_SEGMENT_PATH")"; +# f="$(basename "$MTX_SEGMENT_PATH")"; +# curl -s -H "Content-Type: application/json" +# -X POST "http://rclone:5572/operations/copyfile?_async=true" +# -d "{\"srcFs\":\"$d\",\"srcRemote\":\"$f\", +# \"dstFs\":\"minio:livestream\", +# \"dstRemote\":\"$MTX_PATH/$f\"}"' + + runOnRecordSegmentCreate: > + sh -c 'd="$(dirname "$MTX_SEGMENT_PATH")"; + f="$(basename "$MTX_SEGMENT_PATH")"; + curl -s -H "Content-Type: application/json" + -X POST "http://rclone:5572/operations/copyfile?_async=true" + -d "{\"srcFs\":\"$d\",\"srcRemote\":\"$f\", + \"dstFs\":\"minio:livestream\", + \"dstRemote\":\"$MTX_PATH/$f\"}"' + +# Allow all paths by default +paths: + all: + source: publisher \ No newline at end of file diff --git a/nginx/dev.conf b/nginx/dev.conf index 38d8882..572d4b1 100644 --- a/nginx/dev.conf +++ b/nginx/dev.conf @@ -40,4 +40,17 @@ server { proxy_read_timeout 3600s; proxy_send_timeout 3600s; } + + # --- LIVE --- + # HLS playlist/segments + location /hls/ { + proxy_pass http://mediamtx:8888/; + proxy_http_version 1.1; + } + + # WebRTC WHIP/WHEP/test pages + location /webrtc/ { + proxy_pass http://mediamtx:8889/; + proxy_http_version 1.1; + } } \ No newline at end of file