From 772ca4c34f2bf4f44400e33fc204a11daac41cc8 Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 09:49:01 -0300 Subject: [PATCH 01/39] ignore tags file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 60737d8..8481892 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ donut # Dependency directories (remove the comment below to include it) # vendor/ +tags From 675f91df7e79ea10ab7344513966588691693d63 Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 09:49:13 -0300 Subject: [PATCH 02/39] add docker compose --- Dockerfile | 27 +++++++++++++++------------ Makefile | 4 ++++ docker-compose.yaml | 31 +++++++++++++++++++++++++++++++ ffmpeg_srt_live_listener.sh | 8 ++++++++ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 Makefile create mode 100644 docker-compose.yaml create mode 100755 ffmpeg_srt_live_listener.sh diff --git a/Dockerfile b/Dockerfile index 58ec867..de2e683 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,33 +1,36 @@ -FROM golang:1.19 AS builder +FROM ubuntu:20.04 AS builder -ENV SRT_VERSION="v1.5.0" +ENV SRT_VERSION="v1.5.3" +ENV SRT_FOLDER="/opt/srt_lib" -RUN apt-get update && \ +RUN apt-get clean && apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y \ tclsh pkg-config cmake libssl-dev build-essential git \ && apt-get clean RUN \ - cd /opt && \ - git clone https://github.com/asticode/go-astisrt.git && \ - cd go-astisrt && \ - make install-srt version="${SRT_VERSION}" && \ - mv tmp/${SRT_VERSION} /opt/srt && \ - cd .. && \ - rm -rf go-astisrt + mkdir -p "${SRT_FOLDER}" && \ + git clone --depth 1 --branch "${SRT_VERSION}" https://github.com/Haivision/srt && \ + cd srt && \ + ./configure --prefix=. $(configure) && \ + make && \ + make install FROM golang:1.19 ENV WD=/usr/src/app WORKDIR ${WD} RUN mkdir srt-lib -COPY --from=builder /opt/srt /opt/srt +COPY --from=builder /srt /opt/srt +# To find where the srt.h and libsrt.so were you can +# find / -name srt.h +# find / -name libsrt.so +# inside the container docker run -it --rm -t bash ENV GOPROXY=direct ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/srt/lib/" ENV CGO_CFLAGS="-I/opt/srt/include/" ENV CGO_LDFLAGS="-L/opt/srt/lib/" -ENV PKG_CONFIG_PATH="/opt/srt/lib/pkgconfig" COPY . ./donut WORKDIR ${WD}/donut diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9cae02d --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +run: + docker-compose stop && docker-compose down && docker-compose build && docker-compose up + +.PHONY: run diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..b576ff2 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,31 @@ +version: '2.1' + +services: + app: + build: + context: . + working_dir: "/app" + volumes: + - "./:/app/" + ports: + - "8080:8080" + - "8081:8081" + - "8081:8081/udp" + + origin: # simulating an srt origin live transmission + image: jrottenberg/ffmpeg:4.4-alpine + entrypoint: sh + command: "/scripts/ffmpeg_srt_live_listener.sh" + volumes: + - "./:/scripts" + environment: + - SRT_LISTENING_PORT=40052 + - SRT_LISTENING_HOST=0.0.0.0 + - SRT_LISTENING_LATENCY_US=400000 + ports: + - "40052:40052/udp" + depends_on: + - app + links: + - app + diff --git a/ffmpeg_srt_live_listener.sh b/ffmpeg_srt_live_listener.sh new file mode 100755 index 0000000..0631f6e --- /dev/null +++ b/ffmpeg_srt_live_listener.sh @@ -0,0 +1,8 @@ +ffmpeg -hide_banner -loglevel verbose \ + -re -f lavfi -i "testsrc2=size=1280x720:rate=30,format=yuv420p" \ + -f lavfi -i "sine=frequency=1000:sample_rate=44100" \ + -c:v libx264 -preset veryfast -tune zerolatency -profile:v baseline \ + -b:v 1400k -bufsize 2800k -x264opts keyint=30:min-keyint=30:scenecut=-1 \ + -c:a aac -b:a 128k \ + -f mpegts "srt://${SRT_LISTENING_HOST}:${SRT_LISTENING_PORT}?mode=listener&latency=${SRT_LISTENING_LATENCY_US}" + From 6700fe02e22fe0572696183476a4b483b5885314 Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 10:11:02 -0300 Subject: [PATCH 03/39] ignore mac files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8481892..8c0bba5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ donut # Dependency directories (remove the comment below to include it) # vendor/ tags + +.DS_Store From ebd83e607aa66973eaf5789f37394c184dfb0cca Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 10:12:33 -0300 Subject: [PATCH 04/39] add documentation --- README.md | 70 ++++++++++++++++++++++++++- imgs/docker-compose-donut-setup.webp | Bin 0 -> 33798 bytes 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 imgs/docker-compose-donut-setup.webp diff --git a/README.md b/README.md index 6542349..69999e5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,61 @@ $ go install github.com/flavioribeiro/donut@latest ``` Once installed, execute `donut`. This will be in your `$GOPATH/bin`. The default will be `~/go/bin/donut` -### Install & Run using Docker +#### Troubleshooting locally + +##### Mac + +If you're facing issues while trying to run it locally, such as: + +``` +mod/github.com/asticode/go-astisrt@v0.3.0/pkg/callbacks.go:4:11: fatal error: 'srt/srt.h' file not found + #include + ^~~~~~~~~~~ +1 error generated. +``` + +``` +./main.go:117:2: undefined: setCors +./main.go:135:3: undefined: errorToHTTP +./main.go:147:3: undefined: errorToHTTP +./main.go:154:3: undefined: errorToHTTP +./main.go:158:3: undefined: errorToHTTP +./main.go:165:3: undefined: errorToHTTP +./main.go:174:18: undefined: assertSignalingCorrect +``` + +``` +/opt/homebrew/Cellar/go/1.21.6/libexec/pkg/tool/darwin_arm64/link: running cc failed: exit status 1 +ld: warning: ignoring duplicate libraries: '-lsrt' +ld: library 'srt' not found +clang: error: linker command failed with exit code 1 (use -v to see invocation) +``` + +You can try to use the [docker-compose](#run-using-docker), but if you want to run it locally you might must provide path to the linker. + +```bash + +# Find where the headers and libraries files are located at. If you can't find, install them with brew. +sudo find /opt/homebrew/ -name srt.h +sudo find /opt/ -name libsrt.a + +# Add the required flags so the compiler/linker can find the needed files. +CGO_LDFLAGS="-L/opt/homebrew/Cellar/srt/1.5.3/lib -lsrt" CGO_CFLAGS="-I/opt/homebrew//Cellar/srt/1.5.3/include/" go run main.go helpers.go + +``` + +You can run ffmpeg locally to simulate an SRT live transmission: + +```bash +ffmpeg -hide_banner -loglevel verbose \ + -re -f lavfi -i "testsrc2=size=1280x720:rate=30,format=yuv420p" \ + -f lavfi -i "sine=frequency=1000:sample_rate=44100" \ + -c:v libx264 -preset veryfast -tune zerolatency -profile:v baseline \ + -b:v 1400k -bufsize 2800k -x264opts keyint=30:min-keyint=30:scenecut=-1 \ + -c:a aac -b:a 128k -f mpegts 'srt://0.0.0.0:40052?mode=listener&latency=400000' +``` + +### Run using Docker Alternatively, you can build a docker image. Docker will take care of downloading the dependencies (including the libsrt) and compiling donut for you. @@ -24,3 +78,17 @@ $ docker run -it -p 8080:8080 donut ### Open the Web UI Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in your details for your SRT listener configuration and hit connect. + +### Install & Run using Docker Compose + +Docker-compose can simulate an SRT live transmission and run the donut in separate containers. + +``` +$ make run +``` + +#### Open the Web UI +Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in with the SRT listener configuration and hit connect. + +![donut docker-compose setup](/imgs/docker-compose-donut-setup.webp "donut docker-compose setup") + diff --git a/imgs/docker-compose-donut-setup.webp b/imgs/docker-compose-donut-setup.webp new file mode 100644 index 0000000000000000000000000000000000000000..8544c028eaad6dd523b3c96b0932f3b3fc27ff3c GIT binary patch literal 33798 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 z+W-In0000000010@Bjb+000000000000000000000000000000000000000000000 E06qu=vH$=8 literal 0 HcmV?d00001 From 86eb38c14c26e9cf8645391c871ca5e74bcee25b Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 10:14:36 -0300 Subject: [PATCH 05/39] move troubleshooting to lower sections --- README.md | 57 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 69999e5..b0d7a3a 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,36 @@ $ go install github.com/flavioribeiro/donut@latest ``` Once installed, execute `donut`. This will be in your `$GOPATH/bin`. The default will be `~/go/bin/donut` -#### Troubleshooting locally -##### Mac +### Run using Docker + +Alternatively, you can build a docker image. Docker will take care of downloading the dependencies (including the libsrt) and compiling donut for you. + +``` +$ docker build -t donut . +$ docker run -it -p 8080:8080 donut +``` + +### Open the Web UI +Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in your details for your SRT listener configuration and hit connect. + +### Install & Run using Docker Compose + +Docker-compose can simulate an SRT live transmission and run the donut in separate containers. + +``` +$ make run +``` + +#### Open the Web UI +Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in with the SRT listener configuration and hit connect. + +![donut docker-compose setup](/imgs/docker-compose-donut-setup.webp "donut docker-compose setup") + + +### Troubleshooting locally + +#### Mac If you're facing issues while trying to run it locally, such as: @@ -66,29 +93,3 @@ ffmpeg -hide_banner -loglevel verbose \ -b:v 1400k -bufsize 2800k -x264opts keyint=30:min-keyint=30:scenecut=-1 \ -c:a aac -b:a 128k -f mpegts 'srt://0.0.0.0:40052?mode=listener&latency=400000' ``` - -### Run using Docker - -Alternatively, you can build a docker image. Docker will take care of downloading the dependencies (including the libsrt) and compiling donut for you. - -``` -$ docker build -t donut . -$ docker run -it -p 8080:8080 donut -``` - -### Open the Web UI -Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in your details for your SRT listener configuration and hit connect. - -### Install & Run using Docker Compose - -Docker-compose can simulate an SRT live transmission and run the donut in separate containers. - -``` -$ make run -``` - -#### Open the Web UI -Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in with the SRT listener configuration and hit connect. - -![donut docker-compose setup](/imgs/docker-compose-donut-setup.webp "donut docker-compose setup") - From eb97fe454e2b55783730c7fd8843a797cf266f6b Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 10:24:55 -0300 Subject: [PATCH 06/39] fix readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0d7a3a..1182ebc 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ $ go install github.com/flavioribeiro/donut@latest Once installed, execute `donut`. This will be in your `$GOPATH/bin`. The default will be `~/go/bin/donut` -### Run using Docker +### Install & Run using Docker Alternatively, you can build a docker image. Docker will take care of downloading the dependencies (including the libsrt) and compiling donut for you. @@ -26,7 +26,7 @@ $ docker run -it -p 8080:8080 donut ### Open the Web UI Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in your details for your SRT listener configuration and hit connect. -### Install & Run using Docker Compose +### Run using docker-compose Docker-compose can simulate an SRT live transmission and run the donut in separate containers. @@ -70,7 +70,7 @@ ld: library 'srt' not found clang: error: linker command failed with exit code 1 (use -v to see invocation) ``` -You can try to use the [docker-compose](#run-using-docker), but if you want to run it locally you might must provide path to the linker. +You can try to use the [docker-compose](#run-using-docker-compose), but if you want to run it locally you might must provide path to the linker. ```bash From 495b91b54a04757d5e638d3cc023693913760963 Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Wed, 24 Jan 2024 23:39:57 -0300 Subject: [PATCH 07/39] Add data flow documentation --- HOW_IT_WORKS.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 HOW_IT_WORKS.md diff --git a/HOW_IT_WORKS.md b/HOW_IT_WORKS.md new file mode 100644 index 0000000..b694745 --- /dev/null +++ b/HOW_IT_WORKS.md @@ -0,0 +1,32 @@ +# Data flow diagram + +```mermaid +sequenceDiagram + actor User + + box Navy WebRTC + participant locahost8080 + participant donut-video + end + + locahost8080->>+locahost8080: setup ice 8081/udp and 8081/tcp + User->>+locahost8080: feed SRT host, port, and id + User->>+locahost8080: click on [connect] + locahost8080->>+donut-video: play + donut-video->>+donut-video: web rtc createOffer + donut-video->>+locahost8080: POST /doSignaling {srtOffer} + locahost8080->>+locahost8080: process {srtOffer} + locahost8080->>+locahost8080: create video track + locahost8080->>+locahost8080: set remote {srtOffer} + locahost8080->>+locahost8080: set local {answer} + locahost8080->>+SRT: connect + + loop SRT to WebRTC + locahost8080-->SRT: SRT | WebRTC + locahost8080-->locahost8080: WebRTC.WriteSample(SRT.PES.Data) + end + + locahost8080->>+donut-video: {local description} + + donut-video-->>donut-video: WebRTC.ontrack(video) +``` From ac13f5ce62586c40e67966447971b11e56c6a37e Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Thu, 25 Jan 2024 08:46:23 -0300 Subject: [PATCH 08/39] move readme image to .github --- {imgs => .github}/docker-compose-donut-setup.webp | Bin README.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename {imgs => .github}/docker-compose-donut-setup.webp (100%) diff --git a/imgs/docker-compose-donut-setup.webp b/.github/docker-compose-donut-setup.webp similarity index 100% rename from imgs/docker-compose-donut-setup.webp rename to .github/docker-compose-donut-setup.webp diff --git a/README.md b/README.md index 1182ebc..0d222e2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ $ make run #### Open the Web UI Open [http://localhost:8080](http://localhost:8080). You will see three text boxes. Fill in with the SRT listener configuration and hit connect. -![donut docker-compose setup](/imgs/docker-compose-donut-setup.webp "donut docker-compose setup") +![donut docker-compose setup](/.github/docker-compose-donut-setup.webp "donut docker-compose setup") ### Troubleshooting locally From c7e32f3c9226925bd8f1095b4685f3360369cb3c Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Thu, 25 Jan 2024 08:53:04 -0300 Subject: [PATCH 09/39] move ffmpeg to the scripts folder --- docker-compose.yaml | 2 +- .../ffmpeg_srt_live_listener.sh | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ffmpeg_srt_live_listener.sh => scripts/ffmpeg_srt_live_listener.sh (100%) diff --git a/docker-compose.yaml b/docker-compose.yaml index b576ff2..0d56f69 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -17,7 +17,7 @@ services: entrypoint: sh command: "/scripts/ffmpeg_srt_live_listener.sh" volumes: - - "./:/scripts" + - "./scripts:/scripts" environment: - SRT_LISTENING_PORT=40052 - SRT_LISTENING_HOST=0.0.0.0 diff --git a/ffmpeg_srt_live_listener.sh b/scripts/ffmpeg_srt_live_listener.sh similarity index 100% rename from ffmpeg_srt_live_listener.sh rename to scripts/ffmpeg_srt_live_listener.sh From 65a4be16af211e7bc706fba6ae3655c7f1758bd8 Mon Sep 17 00:00:00 2001 From: Leandro Moreira Date: Thu, 25 Jan 2024 09:22:08 -0300 Subject: [PATCH 10/39] add more components to how it works --- HOW_IT_WORKS.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/HOW_IT_WORKS.md b/HOW_IT_WORKS.md index b694745..8970b1a 100644 --- a/HOW_IT_WORKS.md +++ b/HOW_IT_WORKS.md @@ -3,30 +3,39 @@ ```mermaid sequenceDiagram actor User - - box Navy WebRTC - participant locahost8080 + + box Navy Browser + participant browser participant donut-video end - locahost8080->>+locahost8080: setup ice 8081/udp and 8081/tcp - User->>+locahost8080: feed SRT host, port, and id - User->>+locahost8080: click on [connect] - locahost8080->>+donut-video: play + locahost8080->>+locahost8080: setup local ICE 8081/udp and 8081/tcp + browser->>+locahost8080: GET / + locahost8080->>+browser: 200 /index.html + User->>+browser: feed SRT host, port, and id + User->>+browser: click on [connect] + browser->>+donut-video: play + + Note over locahost8080,donut-video: WebRTC connection setup + donut-video->>+donut-video: web rtc createOffer donut-video->>+locahost8080: POST /doSignaling {srtOffer} locahost8080->>+locahost8080: process {srtOffer} locahost8080->>+locahost8080: create video track locahost8080->>+locahost8080: set remote {srtOffer} locahost8080->>+locahost8080: set local {answer} + locahost8080->>+donut-video: {local description} + + Note over locahost8080,donut-video: WebRTC connection setup + locahost8080->>+SRT: connect loop SRT to WebRTC - locahost8080-->SRT: SRT | WebRTC - locahost8080-->locahost8080: WebRTC.WriteSample(SRT.PES.Data) + locahost8080-->SRT: SRT | WebRTC + locahost8080-->browser: WebRTC.WriteSample(SRT.PES.Data) end - - locahost8080->>+donut-video: {local description} donut-video-->>donut-video: WebRTC.ontrack(video) + donut-video-->>browser: renders video at the