Make executables ready for static linking (#307)

* Disable CGO (C libs) for coordinator

Needed for static linking.

* Fix "error strings should not be capitalized (ST1005)"

* Fix SA1015

Using time.Tick leaks the underlying ticker, consider using it only in endless functions, tests and the main package, and use time.NewTicker here (SA1015)

* Fix SA9004

Only the first constant in this group has an explicit type (SA9004).

* Remove unused code in the webrtc package

* Fix S1000

Should use a simple channel send/receive instead of select with a single case (S1000).

* Force dir creation/check for core downloader

* Update Makefile release script

* Disable ASLR for worker builds

* Remove WORKER_BUILD_PARAMS flag from the CI

* Don't force recompilation in release

* Add Debian packages installer script

* Build worker app without libopusfile

* Test worker app without libopusfile

* Add opus wrapper without opusfile

* Make install.sh executable

* Add opus lib in Win builds

* Make insecure HTTPS requests when downloading libs

* Add ca-certificates for Docker build stage

go mod download works only with SSL certificates installed.

* Move libx264 wrapper into the repo

That way we can get rid of a lot of not needed external Go dependencies.

* Update the dependencies
This commit is contained in:
sergystepanov 2021-04-06 18:16:52 +03:00 committed by Sergey Stepanov
parent d778a7e084
commit 602b9ea47c
No known key found for this signature in database
GPG key ID: A56B4929BAA8556B
20 changed files with 1278 additions and 212 deletions

View file

@ -33,12 +33,12 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y make pkg-config libvpx-dev libx264-dev libopus-dev libopusfile-dev libsdl2-dev libgl1-mesa-glx
sudo apt-get install -y make pkg-config libvpx-dev libx264-dev libopus-dev libsdl2-dev libgl1-mesa-glx
- name: Get MacOS dev libraries and tools
if: matrix.os == 'macos-latest'
run: |
brew install pkg-config libvpx x264 opus opusfile sdl2
brew install pkg-config libvpx x264 opus sdl2
- name: Get Windows dev libraries and tools
if: matrix.os == 'windows-latest'
@ -52,8 +52,8 @@ jobs:
mingw-w64-x86_64-pkg-config
mingw-w64-x86_64-dlfcn
mingw-w64-x86_64-libvpx
mingw-w64-x86_64-opus
mingw-w64-x86_64-x264-git
mingw-w64-x86_64-opusfile
mingw-w64-x86_64-SDL2
- name: Get Windows OpenGL drivers
@ -77,7 +77,7 @@ jobs:
if: matrix.step == 'build' && matrix.os == 'windows-latest'
shell: msys2 {0}
run: |
make WORKER_BUILD_PARAMS=-buildmode=exe build
make build
- name: Build Linux app
if: matrix.step == 'build' && matrix.os == 'ubuntu-latest'
@ -95,19 +95,19 @@ jobs:
env:
MESA_GL_VERSION_OVERRIDE: 3.3COMPAT
run: |
go test -run TestAllEmulatorRooms ./pkg/worker/room -v -renderFrames -autoGlContext -outputPath "../../../_rendered"
GL_CTX=-autoGlContext make verify-cores
- name: Verify core rendering (ubuntu-latest)
if: matrix.step == 'check' && matrix.os == 'ubuntu-latest' && always()
env:
MESA_GL_VERSION_OVERRIDE: 3.3COMPAT
run: |
xvfb-run --auto-servernum go test -run TestAllEmulatorRooms ./pkg/worker/room -v -renderFrames -autoGlContext -outputPath "../../../_rendered"
GL_CTX=-autoGlContext xvfb-run --auto-servernum make verify-cores
- name: Verify core rendering (macos-latest)
if: matrix.step == 'check' && matrix.os == 'macos-latest' && always()
run: |
go test -run TestAllEmulatorRooms ./pkg/worker/room -v -renderFrames -outputPath "../../../_rendered"
make verify-cores
- uses: actions/upload-artifact@v2
if: matrix.step == 'check' && always()

31
Dockerfile vendored
View file

@ -9,32 +9,32 @@ WORKDIR ${BUILD_PATH}
# system libs layer
RUN apt-get update && apt-get install --no-install-recommends -y \
gcc \
ca-certificates \
libopus-dev \
libsdl2-dev \
libvpx-dev \
libx264-dev \
make \
pkg-config \
wget \
ca-certificates \
libvpx-dev \
libx264-dev \
libopus-dev \
libopusfile-dev \
libsdl2-dev \
&& rm -rf /var/lib/apt/lists/*
# go setup layer
ARG GO=go1.16.2.linux-amd64.tar.gz
ARG GO=go1.16.3.linux-amd64.tar.gz
RUN wget -q https://golang.org/dl/$GO \
&& rm -rf /usr/local/go \
&& tar -C /usr/local -xzf $GO \
&& rm $GO
ENV PATH="${PATH}:/usr/local/go/bin"
RUN go version
# go deps layer
COPY go.mod go.sum ./
RUN go mod download
# app build layer
COPY ./ ./
COPY pkg ./pkg
COPY cmd ./cmd
COPY Makefile .
RUN make build
# base image
@ -42,16 +42,9 @@ FROM debian:bullseye-slim
ARG BUILD_PATH
WORKDIR /usr/local/share/cloud-game
RUN apt-get update && apt-get install --no-install-recommends -y \
ca-certificates \
libvpx6 \
libx264-160 \
libopus0 \
libopusfile0 \
libsdl2-2.0-0 \
libgl1-mesa-glx \
xvfb \
&& rm -rf /var/lib/apt/lists/*
COPY scripts/install.sh install.sh
RUN bash install.sh && \
rm -rf /var/lib/apt/lists/* install.sh
COPY --from=build ${BUILD_PATH}/bin/ ./
RUN cp -s $(pwd)/* /usr/local/bin

21
Makefile vendored
View file

@ -60,17 +60,17 @@ clean:
@go clean ./cmd/*
build:
go build -a -tags netgo -ldflags '-w' -o bin/coordinator ./cmd/coordinator
go build ${WORKER_BUILD_PARAMS} -a -tags netgo -ldflags '-w' -o bin/worker ./cmd/worker
CGO_ENABLED=0 go build -ldflags '-w -s' -o bin/coordinator$(EXT) ./cmd/coordinator
go build -buildmode=exe -tags static -ldflags '-w -s' -o bin/worker$(EXT) ./cmd/worker
dev.tools:
./hack/scripts/install_tools.sh
verify-cores:
go test -run TestAllEmulatorRooms ./pkg/worker/room -v -renderFrames $(GL_CTX) -outputPath "../../../_rendered"
dev.build: compile build
dev.build-local:
go build -o bin/coordinator ./cmd/coordinator
go build ${WORKER_BUILD_PARAMS} -o bin/worker ./cmd/worker
CGO_ENABLED=0 go build -o bin/coordinator ./cmd/coordinator
go build -buildmode=exe -o bin/worker ./cmd/worker
dev.run: dev.build-local
./bin/coordinator --v=5 &
@ -86,13 +86,15 @@ dev.run-docker:
# Folder structure:
# - assets/
# - games/ (shared between both executables)
# - emulator/libretro/cores/ (filtered by extension)
# - cores/ (filtered by extension)
# - web/
# - coordinator
# - worker
# - config.yaml (shared)
#
# Config params:
# - RELEASE_DIR: the name of the output folder (default: release).
# - CONFIG_DIR: search dir for core config files.
# - DLIB_TOOL: the name of a dynamic lib copy tool (with params) (e.g., ldd -x -y; defalut: ldd).
# - DLIB_SEARCH_PATTERN: a grep filter of the output of the DLIB_TOOL (e.g., mylib.so; default: .*so).
# Be aware that this search pattern will return only matched regular expression part and not the whole line.
@ -100,15 +102,18 @@ dev.run-docker:
# Makefile special symbols should be escaped with \.
# - DLIB_ALTER: a special flag to use altered dynamic copy lib tool for macOS only.
# - CORE_EXT: a glob pattern to filter the cores that are copied into the release.
# - CFG_EXT: a glob pattern to copy config file into the release (default: *.cfg).
#
# Example:
# make release DLIB_TOOL="ldd -x" DLIB_SEARCH_PATTERN=/usr/lib.*\\\\s CORE_EXT=*.so
#
RELEASE_DIR ?= release
CONFIG_DIR = configs
DLIB_TOOL ?= ldd
DLIB_SEARCH_PATTERN ?= .*so
DLIB_ALTER ?= false
CORE_EXT ?= *_libretro.so
CFG_EXT ?= *.cfg
COORDINATOR_DIR = ./$(RELEASE_DIR)
WORKER_DIR = ./$(RELEASE_DIR)
CORES_DIR = assets/cores
@ -133,6 +138,8 @@ release: clean build
cp -R ./$(GAMES_DIR) $(WORKER_DIR)/assets
endif
mkdir -p $(WORKER_DIR)/$(CORES_DIR)
cp ./$(CORES_DIR)/$(CFG_EXT) $(WORKER_DIR)/$(CORES_DIR)
ifneq (,$(wildcard ./$(CORES_DIR)/$(CORE_EXT)))
cp -R ./$(CORES_DIR)/$(CORE_EXT) $(WORKER_DIR)/$(CORES_DIR)
endif
cp ./$(CONFIG_DIR)/config.yaml ./$(RELEASE_DIR)

6
README.md vendored
View file

@ -45,13 +45,13 @@ Install Golang https://golang.org/doc/install . Because the project uses GoModul
* Install [libvpx](https://www.webmproject.org/code/), [libx264](https://www.videolan.org/developers/x264.html), [libopus](http://opus-codec.org/), [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/), [sdl2](https://wiki.libsdl.org/Installation)
```
# Ubuntu / Windows (WSL2)
apt-get install -y make gcc pkg-config libvpx-dev libx264-dev libopus-dev libopusfile-dev libsdl2-dev
apt-get install -y make gcc pkg-config libvpx-dev libx264-dev libopus-dev libsdl2-dev
# MacOS
brew install pkg-config libvpx x264 opus opusfile sdl2
brew install pkg-config libvpx x264 opus sdl2
# Windows (MSYS2)
pacman -Sy --noconfirm --needed git make mingw-w64-x86_64-{gcc,pkg-config,dlfcn,libvpx,x264-git,opusfile,SDL2}
pacman -Sy --noconfirm --needed git make mingw-w64-x86_64-{gcc,pkg-config,dlfcn,libvpx,opus,x264-git,SDL2}
```
Because the coordinator and workers need to run simultaneously. Workers connect to the coordinator.

View file

@ -6,6 +6,7 @@ import (
"math/rand"
"os"
"os/signal"
"syscall"
"time"
config "github.com/giongto35/cloud-game/v2/pkg/config/coordinator"
@ -35,12 +36,18 @@ func main() {
os.Exit(1)
}
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
select {
case <-stop:
glog.Infoln("Received SIGTERM, Quiting Coordinator")
o.Shutdown()
cancelCtx()
}
signals := make(chan os.Signal, 1)
done := make(chan struct{}, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-signals
glog.V(4).Infof("[coordinator] Shutting down [os:%v]", sig)
done <- struct{}{}
}()
<-done
o.Shutdown()
cancelCtx()
}

View file

@ -6,6 +6,7 @@ import (
"math/rand"
"os"
"os/signal"
"syscall"
"time"
config "github.com/giongto35/cloud-game/v2/pkg/config/worker"
@ -35,14 +36,20 @@ func run() {
wrk := worker.New(ctx, conf)
wrk.Run()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
select {
case <-stop:
glog.V(4).Info("[worker] Shutting down")
wrk.Shutdown()
cancelCtx()
}
signals := make(chan os.Signal, 1)
done := make(chan struct{}, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-signals
glog.V(4).Infof("[worker] Shutting down [os:%v]", sig)
done <- struct{}{}
}()
<-done
wrk.Shutdown()
cancelCtx()
}
func main() {

23
go.mod vendored
View file

@ -3,7 +3,7 @@ module github.com/giongto35/cloud-game/v2
go 1.13
require (
cloud.google.com/go v0.80.0 // indirect
cloud.google.com/go v0.81.0 // indirect
cloud.google.com/go/storage v1.14.0
github.com/cavaliercoder/grab v1.0.1-0.20201108051000-98a5bfe305ec
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3
@ -12,30 +12,27 @@ require (
github.com/gofrs/flock v0.8.0
github.com/gofrs/uuid v4.0.0+incompatible
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/kkyr/fig v0.2.0
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pelletier/go-toml v1.9.0 // indirect
github.com/pion/dtls/v2 v2.0.9 // indirect
github.com/pion/interceptor v0.0.12
github.com/pion/rtp v1.6.2
github.com/pion/sctp v1.7.12 // indirect
github.com/pion/udp v0.1.1 // indirect
github.com/pion/webrtc/v3 v3.0.19
github.com/pion/webrtc/v3 v3.0.20
github.com/prometheus/client_golang v1.10.0
github.com/prometheus/common v0.20.0 // indirect
github.com/sergystepanov/x264-go/v2 v2.0.0-20210221160055-cd2aaf7070fc
github.com/spf13/pflag v1.0.5
github.com/veandco/go-sdl2 v0.4.5
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20210330142815-c8897c278d10 // indirect
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 // indirect
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect
google.golang.org/api v0.43.0 // indirect
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee // indirect
gopkg.in/hraban/opus.v2 v2.0.0-20201025103112-d779bb1cc5a2
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/genproto v0.0.0-20210405174219-a39eb2f71cb9 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

55
go.sum vendored
View file

@ -18,8 +18,8 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.80.0 h1:kAdyAMrj9CjqOSGiluseVjIgAyQ3uxADYtUYR6MwYeY=
cloud.google.com/go v0.80.0/go.mod h1:fqpb6QRi1CFGAMXDoE72G+b+Ybv7dMB/T1tbExDHktI=
cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -42,7 +42,6 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@ -113,7 +112,6 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/gl v0.0.0-20210315015930-ae072cafe09d h1:o81yRlBATU4PRn97lydmsq8hTRNXI4wlR/VvUQhFRVY=
github.com/go-gl/gl v0.0.0-20210315015930-ae072cafe09d/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
@ -141,8 +139,9 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@ -261,7 +260,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5V3lRzakvEyr49P7hHRYoHtPr8zvj/7JodCoRzw=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkyr/fig v0.2.0 h1:t/5yENaBw8ATXbQSWpPqwXLCn6wdhEi6jWXRfUgytZI=
@ -276,7 +274,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@ -332,15 +329,16 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0=
github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
github.com/pion/dtls/v2 v2.0.8 h1:reGe8rNIMfO/UAeFLqO61tl64t154Qfkr4U3Gzu1tsg=
github.com/pion/dtls/v2 v2.0.8/go.mod h1:QuDII+8FVvk9Dp5t5vYIMTo7hh7uBkra+8QIm7QGm10=
github.com/pion/dtls/v2 v2.0.9 h1:7Ow+V++YSZQMYzggI0P9vLJz/hUFcffsfGMfT/Qy+u8=
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
github.com/pion/ice/v2 v2.0.16 h1:K6bzD8ef9vMKbGMTHaUweHXEyuNGnvr2zdqKoLKZPn0=
github.com/pion/ice/v2 v2.0.16/go.mod h1:SJNJzC27gDZoOW0UoxIoC8Hf2PDxG28hQyNdSexDu38=
github.com/pion/interceptor v0.0.12 h1:eC1iVneBIAQJEfaNAfDqAncJWhMDAnaXPRCJsltdokE=
@ -356,7 +354,6 @@ github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE
github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U=
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.12 h1:GsatLufywVruXbZZT1CKg+Jr8ZTkwiPnmUC/oO9+uuY=
github.com/pion/sctp v1.7.12/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
@ -375,8 +372,8 @@ github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyr
github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.0.19 h1:h3EOMuMNYkJ0X2w1iKNGGBLFN7M/Max0vNUF9IUXqBc=
github.com/pion/webrtc/v3 v3.0.19/go.mod h1:P/aoizAjeMUh61uAH58BRypn97IKjcLtIAm/mHqovJw=
github.com/pion/webrtc/v3 v3.0.20 h1:Jj0sk45MqQdkR24E1wbFRmOzb1Lv258ot9zd2fYB/Pw=
github.com/pion/webrtc/v3 v3.0.20/go.mod h1:0eJnCpQrUMpRnvyonw4ZiWClToerpixrZ2KcoTxvX9M=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -421,8 +418,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergystepanov/x264-go/v2 v2.0.0-20210221160055-cd2aaf7070fc h1:WCNpo7QJb7uAA8qMgTBe459EDJCwarm/wbPERNPSt00=
github.com/sergystepanov/x264-go/v2 v2.0.0-20210221160055-cd2aaf7070fc/go.mod h1:WfHP0dmR01K6NQeOyZf5oZdWvnlmSt/th1puDtIeJbI=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -570,8 +565,9 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210330142815-c8897c278d10 h1:j6SlnKgJhONcqBZAH/cLNz6hg79L7Q18RY4BiN0r0LI=
golang.org/x/net v0.0.0-20210330142815-c8897c278d10/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -583,8 +579,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 h1:D7nTwh4J0i+5mW4Zjzn5omvlr6YBcWywE6KOcatyNxY=
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -641,7 +637,6 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -651,12 +646,11 @@ golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210314195730-07df6a141424/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg=
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -665,8 +659,9 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -751,7 +746,6 @@ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.42.0/go.mod h1:+Oj4s6ch2SEGtPjGqfUfZonBH0GjQH89gTeKKAEGZKI=
google.golang.org/api v0.43.0 h1:4sAyIHT6ZohtAQDoxws+ez7bROYmUlOVvsUscYCDTqA=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@ -803,11 +797,10 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210312152112-fc591d9ea70f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a/go.mod h1:f2Bd7+2PlaVKmvKQ52aspJZXIDaRQBVdOOBfJ5i8OEs=
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee h1:vVeMwkgjjF0rgUTvAJkHJC5hUf50yFdZFDpBgK2kVXI=
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210405174219-a39eb2f71cb9 h1:Uga0hMhZnzB159cnlmhVPgEmZTwoZqwOb7e0pu+rlNI=
google.golang.org/genproto v0.0.0-20210405174219-a39eb2f71cb9/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -854,8 +847,6 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/hraban/opus.v2 v2.0.0-20201025103112-d779bb1cc5a2 h1:sxrRNhZ+cNxxLwPw/vV8gNsz+bbqRQiZHBYBJfpyNoQ=
gopkg.in/hraban/opus.v2 v2.0.0-20201025103112-d779bb1cc5a2/go.mod h1:/L5E7a21VWl8DeuCPKxQBdVG5cy+L0MRZ08B1wnqt7g=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=

View file

@ -293,14 +293,14 @@ func (o *Server) getWorkerFromAddress(address string) *WorkerClient {
func (o *Server) findBestServerFromBrowser(workerClients map[string]*WorkerClient, client *BrowserClient, zone string) (string, error) {
// TODO: Find best Server by latency, currently return by ping
if len(workerClients) == 0 {
return "", errors.New("No server found")
return "", errors.New("no server found")
}
latencies := o.getLatencyMapFromBrowser(workerClients, client)
client.Println("Latency map", latencies)
if len(latencies) == 0 {
return "", errors.New("No server found")
return "", errors.New("no server found")
}
var bestWorker *WorkerClient

View file

@ -43,7 +43,10 @@ type (
PacketHandler func(resp WSPacket) (req WSPacket)
)
var EmptyPacket = WSPacket{}
var (
EmptyPacket = WSPacket{}
HeartbeatPacket = WSPacket{ID: "heartbeat"}
)
const WSWait = 20 * time.Second
@ -153,20 +156,22 @@ func (c *Client) SyncSend(request WSPacket) (response WSPacket) {
// }
//}
// Heartbeat maintains connection to server
// Heartbeat maintains connection to coordinator.
// Blocking.
func (c *Client) Heartbeat() {
// send heartbeat every 1s
timer := time.Tick(time.Second)
for range timer {
t := time.NewTicker(time.Second)
// don't wait 1 second
c.Send(HeartbeatPacket, nil)
for {
select {
case <-c.Done:
log.Println("Close heartbeat")
t.Stop()
log.Printf("Close heartbeat")
return
default:
case <-t.C:
c.Send(HeartbeatPacket, nil)
}
// !to resolve cycle deps
c.Send(WSPacket{ID: "heartbeat"}, nil)
}
}

View file

@ -1,7 +1,9 @@
package backend
import (
"crypto/tls"
"log"
"net/http"
"github.com/cavaliercoder/grab"
)
@ -12,8 +14,17 @@ type GrabDownloader struct {
}
func NewGrabDownloader() GrabDownloader {
client := grab.Client{
UserAgent: "Cloud-Game/2.2",
HTTPClient: &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
},
}
return GrabDownloader{
client: grab.NewClient(),
client: &client,
concurrency: 5,
}
}

872
pkg/encoder/h264/libx264.go Normal file
View file

@ -0,0 +1,872 @@
// Implements cgo bindings for [x264](https://www.videolan.org/developers/x264.html) library.
package h264
/*
#cgo pkg-config: x264
#cgo CFLAGS: -Wall -O3
#include "stdint.h"
#include "x264.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"
const Build = C.X264_BUILD
/* T is opaque handler for encoder */
type T struct{}
/****************************************************************************
* NAL structure and functions
****************************************************************************/
/* enum nal_unit_type_e */
const (
NalUnknown = 0
NalSlice = 1
NalSliceDpa = 2
NalSliceDpb = 3
NalSliceDpc = 4
NalSliceIdr = 5 /* ref_idc != 0 */
NalSei = 6 /* ref_idc == 0 */
NalSps = 7
NalPps = 8
NalAud = 9
NalFiller = 12
/* ref_idc == 0 for 6,9,10,11,12 */
)
/* enum nal_priority_e */
const (
NalPriorityDisposable = 0
NalPriorityLow = 1
NalPriorityHigh = 2
NalPriorityHighest = 3
)
/* The data within the payload is already NAL-encapsulated; the ref_idc and type
* are merely in the struct for easy access by the calling application.
* All data returned in an x264_nal_t, including the data in p_payload, is no longer
* valid after the next call to x264_encoder_encode. Thus it must be used or copied
* before calling x264_encoder_encode or x264_encoder_headers again. */
type Nal struct {
IRefIdc int32 /* nal_priority_e */
IType int32 /* nal_unit_type_e */
BLongStartcode int32
IFirstMb int32 /* If this NAL is a slice, the index of the first MB in the slice. */
ILastMb int32 /* If this NAL is a slice, the index of the last MB in the slice. */
/* Size of payload (including any padding) in bytes. */
IPayload int32
/* If param->b_annexb is set, Annex-B bytestream with startcode.
* Otherwise, startcode is replaced with a 4-byte size.
* This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */
/* C.uint8_t */
PPayload unsafe.Pointer
/* Size of padding in bytes. */
IPadding int32
}
/****************************************************************************
* Encoder parameters
****************************************************************************/
/* CPU flags */
const (
/* x86 */
CpuMmx uint32 = 1 << 0
CpuMmx2 uint32 = 1 << 1 /* MMX2 aka MMXEXT aka ISSE */
CpuMmxext = CpuMmx2
CpuSse uint32 = 1 << 2
CpuSse2 uint32 = 1 << 3
CpuLzcnt uint32 = 1 << 4
CpuSse3 uint32 = 1 << 5
CpuSsse3 uint32 = 1 << 6
CpuSse4 uint32 = 1 << 7 /* SSE4.1 */
CpuSse42 uint32 = 1 << 8 /* SSE4.2 */
CpuAvx uint32 = 1 << 9 /* Requires OS support even if YMM registers aren't used */
CpuXop uint32 = 1 << 10 /* AMD XOP */
CpuFma4 uint32 = 1 << 11 /* AMD FMA4 */
CpuFma3 uint32 = 1 << 12
CpuBmi1 uint32 = 1 << 13
CpuBmi2 uint32 = 1 << 14
CpuAvx2 uint32 = 1 << 15
CpuAvx512 uint32 = 1 << 16 /* AVX-512 {F, CD, BW, DQ, VL}, requires OS support */
/* x86 modifiers */
CpuCacheline32 uint32 = 1 << 17 /* avoid memory loads that span the border between two cachelines */
CpuCacheline64 uint32 = 1 << 18 /* 32/64 is the size of a cacheline in bytes */
CpuSse2IsSlow uint32 = 1 << 19 /* avoid most SSE2 functions on Athlon64 */
CpuSse2IsFast uint32 = 1 << 20 /* a few functions are only faster on Core2 and Phenom */
CpuSlowShuffle uint32 = 1 << 21 /* The Conroe has a slow shuffle unit (relative to overall SSE performance) */
CpuStackMod4 uint32 = 1 << 22 /* if stack is only mod4 and not mod16 */
CpuSlowAtom uint32 = 1 << 23 /* The Atom is terrible: slow SSE unaligned loads, slow
* SIMD multiplies, slow SIMD variable shifts, slow pshufb,
* cacheline split penalties -- gather everything here that
* isn't shared by other CPUs to avoid making half a dozen
* new SLOW flags. */
CpuSlowPshufb uint32 = 1 << 24 /* such as on the Intel Atom */
CpuSlowPalignr uint32 = 1 << 25 /* such as on the AMD Bobcat */
/* PowerPC */
CpuAltivec uint32 = 0x0000001
/* ARM and AArch64 */
CpuArmv6 uint32 = 0x0000001
CpuNeon uint32 = 0x0000002 /* ARM NEON */
CpuFastNeonMrc uint32 = 0x0000004 /* Transfer from NEON to ARM register is fast (Cortex-A9) */
CpuArmv8 uint32 = 0x0000008
/* MIPS */
CpuMsa uint32 = 0x0000001 /* MIPS MSA */
/* Analyse flags */
AnalyseI4x4 uint32 = 0x0001 /* Analyse i4x4 */
AnalyseI8x8 uint32 = 0x0002 /* Analyse i8x8 (requires 8x8 transform) */
AnalysePsub16x16 uint32 = 0x0010 /* Analyse p16x8, p8x16 and p8x8 */
AnalysePsub8x8 uint32 = 0x0020 /* Analyse p8x4, p4x8, p4x4 */
AnalyseBsub16x16 uint32 = 0x0100 /* Analyse b16x8, b8x16 and b8x8 */
DirectPredNone = 0
DirectPredSpatial = 1
DirectPredTemporal = 2
DirectPredAuto = 3
MeDia = 0
MeHex = 1
MeUmh = 2
MeEsa = 3
MeTesa = 4
CqmFlat = 0
CqmJvt = 1
CqmCustom = 2
RcCqp = 0
RcCrf = 1
RcAbr = 2
QpAuto = 0
AqNone = 0
AqVariance = 1
AqAutovariance = 2
AqAutovarianceBiased = 3
BAdaptNone = 0
BAdaptFast = 1
BAdaptTrellis = 2
WeightpNone = 0
WeightpSimple = 1
WeightpSmart = 2
BPyramidNone = 0
BPyramidStrict = 1
BPyramidNormal = 2
KeyintMinAuto = 0
KeyintMaxInfinite = 1 << 30
/* AVC-Intra flavors */
AvcintraFlavorPanasonic = 0
AvcintraFlavorSony = 1
/* !to add missing names */
/* static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 }; */
/* static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 }; */
/* static const char * const x264_b_pyramid_names[] = { "none", "strict", "normal", 0 }; */
/* static const char * const x264_overscan_names[] = { "undef", "show", "crop", 0 }; */
/* static const char * const x264_vidformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", 0 }; */
/* static const char * const x264_fullrange_names[] = { "off", "on", 0 }; */
/* static const char * const x264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020", "smpte428", "smpte431", "smpte432", 0 }; */
/* static const char * const x264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316", "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", "smpte2084", "smpte428", "arib-std-b67", 0 }; */
/* static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c", "smpte2085", "chroma-derived-nc", "chroma-derived-c", "ICtCp", 0 }; */
/* static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; */
/* static const char * const x264_avcintra_flavor_names[] = { "panasonic", "sony", 0 }; */
/* Colorspace type */
CspMask = 0x00ff /* */
CspNone = 0x0000 /* Invalid mode */
CspI400 = 0x0001 /* monochrome 4:0:0 */
CspI420 = 0x0002 /* yuv 4:2:0 planar */
CspYv12 = 0x0003 /* yvu 4:2:0 planar */
CspNv12 = 0x0004 /* yuv 4:2:0, with one y plane and one packed u+v */
CspNv21 = 0x0005 /* yuv 4:2:0, with one y plane and one packed v+u */
CspI422 = 0x0006 /* yuv 4:2:2 planar */
CspYv16 = 0x0007 /* yvu 4:2:2 planar */
CspNv16 = 0x0008 /* yuv 4:2:2, with one y plane and one packed u+v */
CspYuyv = 0x0009 /* yuyv 4:2:2 packed */
CspUyvy = 0x000a /* uyvy 4:2:2 packed */
CspV210 = 0x000b /* 10-bit yuv 4:2:2 packed in 32 */
CspI444 = 0x000c /* yuv 4:4:4 planar */
CspYv24 = 0x000d /* yvu 4:4:4 planar */
CspBgr = 0x000e /* packed bgr 24bits */
CspBgra = 0x000f /* packed bgr 32bits */
CspRgb = 0x0010 /* packed rgb 24bits */
CspMax = 0x0011 /* end of list */
CspVflip = 0x1000 /* the csp is vertically flipped */
CspHighDepth = 0x2000 /* the csp has a depth of 16 bits per pixel component */
/* Slice type */
TypeAuto = 0x0000 /* Let x264 choose the right type */
TypeIdr = 0x0001
TypeI = 0x0002
TypeP = 0x0003
TypeBref = 0x0004 /* Non-disposable B-frame */
TypeB = 0x0005
TypeKeyframe = 0x0006 /* IDR or I depending on b_open_gop option */
/* !to reimplement macro */
/* #define IS_X264_TYPE_I(x) ((x)==X264_TYPE_I || (x)==X264_TYPE_IDR || (x)==X264_TYPE_KEYFRAME) */
/* #define IS_X264_TYPE_B(x) ((x)==X264_TYPE_B || (x)==X264_TYPE_BREF) */
/* Log level */
LogNone = -1
LogError = 0
LogWarning = 1
LogInfo = 2
LogDebug = 3
/* Threading */
ThreadsAuto = 0 /* Automatically select optimal number of threads */
SyncLookaheadAuto = -1 /* Automatically select optimal lookahead thread buffer size */
/* HRD */
NalHrdNone = 0
NalHrdVbr = 1
NalHrdCbr = 2
)
const (
/* The macroblock is constant and remains unchanged from the previous frame. */
MbinfoConstant = 1 << 0
/* More flags may be added in the future. */
)
/* Zones: override ratecontrol or other options for specific sections of the video.
* See x264_encoder_reconfig() for which options can be changed.
* If zones overlap, whichever comes later in the list takes precedence. */
type Zone struct {
IStart, IEnd int32 /* range of frame numbers */
BForceQp int32 /* whether to use qp vs bitrate factor */
IQp int32
FBitrateFactor float32
Param *Param
}
type Param struct {
/* CPU flags */
Cpu uint32
IThreads int32 /* encode multiple frames in parallel */
ILookaheadThreads int32 /* multiple threads for lookahead analysis */
BSlicedThreads int32 /* Whether to use slice-based threading. */
BDeterministic int32 /* whether to allow non-deterministic optimizations when threaded */
BCpuIndependent int32 /* force canonical behavior rather than cpu-dependent optimal algorithms */
ISyncLookahead int32 /* threaded lookahead buffer */
/* Video Properties */
IWidth int32
IHeight int32
ICsp int32 /* CSP of encoded bitstream */
IBitdepth int32
ILevelIdc int32
IFrameTotal int32 /* number of frames to encode if known, else 0 */
/* NAL HRD
* Uses Buffering and Picture Timing SEIs to signal HRD
* The HRD in H.264 was not designed with VFR in mind.
* It is therefore not recommended to use NAL HRD with VFR.
* Furthermore, reconfiguring the VBV (via x264_encoder_reconfig)
* will currently generate invalid HRD. */
INalHrd int32
Vui struct {
/* they will be reduced to be 0 < x <= 65535 and prime */
ISarHeight int32
ISarWidth int32
IOverscan int32 /* 0=undef, 1=no overscan, 2=overscan */
/* see h264 annex E for the values of the following */
IVidformat int32
BFullrange int32
IColorprim int32
ITransfer int32
IColmatrix int32
IChromaLoc int32 /* both top & bottom */
}
/* Bitstream parameters */
IFrameReference int32 /* Maximum number of reference frames */
IDpbSize int32 /* Force a DPB size larger than that implied by B-frames and reference frames.
* Useful in combination with interactive error resilience. */
IKeyintMax int32 /* Force an IDR keyframe at this interval */
IKeyintMin int32 /* Scenecuts closer together than this are coded as I, not IDR. */
IScenecutThreshold int32 /* how aggressively to insert extra I frames */
BIntraRefresh int32 /* Whether or not to use periodic intra refresh instead of IDR frames. */
IBframe int32 /* how many b-frame between 2 references pictures */
IBframeAdaptive int32
IBframeBias int32
IBframePyramid int32 /* Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal */
BOpenGop int32
BBlurayCompat int32
IAvcintraClass int32
IAvcintraFlavor int32
BDeblockingFilter int32
IDeblockingFilterAlphac0 int32 /* [-6, 6] -6 light filter, 6 strong */
IDeblockingFilterBeta int32 /* [-6, 6] idem */
BCabac int32
ICabacInitIdc int32
BInterlaced int32
BConstrainedIntra int32
ICqmPreset int32
PszCqmFile *int8 /* filename (in UTF-8) of CQM file, JM format */
Cqm4iy [16]byte /* used only if i_cqm_preset == X264_CQM_CUSTOM */
Cqm4py [16]byte
Cqm4ic [16]byte
Cqm4pc [16]byte
Cqm8iy [64]byte
Cqm8py [64]byte
Cqm8ic [64]byte
Cqm8pc [64]byte
/* Log */
PfLog *[0]byte
PLogPrivate unsafe.Pointer
ILogLevel int32
BFullRecon int32 /* fully reconstruct frames, even when not necessary for encoding. Implied by psz_dump_yuv */
PszDumpYuv *int8 /* filename (in UTF-8) for reconstructed frames */
/* Encoder analyser parameters */
Analyse struct {
Intra uint32 /* intra partitions */
Inter uint32 /* inter partitions */
BTransform8x8 int32
IWeightedPred int32 /* weighting for P-frames */
BWeightedBipred int32 /* implicit weighting for B-frames */
IDirectMvPred int32 /* spatial vs temporal mv prediction */
IChromaQpOffset int32
IMeMethod int32 /* motion estimation algorithm to use (X264_ME_*) */
IMeRange int32 /* integer pixel motion estimation search range (from predicted mv) */
IMvRange int32 /* maximum length of a mv (in pixels). -1 = auto, based on level */
IMvRangeThread int32 /* minimum space between threads. -1 = auto, based on number of threads. */
ISubpelRefine int32 /* subpixel motion estimation quality */
BChromaMe int32 /* chroma ME for subpel and mode decision in P-frames */
BMixedReferences int32 /* allow each mb partition to have its own reference number */
ITrellis int32 /* trellis RD quantization */
BFastPskip int32 /* early SKIP detection on P-frames */
BDctDecimate int32 /* transform coefficient thresholding on P-frames */
INoiseReduction int32 /* adaptive pseudo-deadzone */
FPsyRd float32 /* Psy RD strength */
FPsyTrellis float32 /* Psy trellis strength */
BPsy int32 /* Toggle all psy optimizations */
BMbInfo int32 /* Use input mb_info data in x264_picture_t */
BMbInfoUpdate int32 /* Update the values in mb_info according to the results of encoding. */
/* the deadzone size that will be used in luma quantization */
ILumaDeadzone [2]int32
BPsnr int32 /* compute and print PSNR stats */
BSsim int32 /* compute and print SSIM stats */
}
/* Rate control parameters */
Rc struct {
IRcMethod int32 /* X264_RC_* */
IQpConstant int32 /* 0=lossless */
IQpMin int32 /* min allowed QP value */
IQpMax int32 /* max allowed QP value */
IQpStep int32 /* max QP step between frames */
IBitrate int32
FRfConstant float32 /* 1pass VBR, nominal QP */
FRfConstantMax float32 /* In CRF mode, maximum CRF as caused by VBV */
FRateTolerance float32
IVbvMaxBitrate int32
IVbvBufferSize int32
FVbvBufferInit float32 /* <=1: fraction of buffer_size. >1: kbit */
FIpFactor float32
FPbFactor float32
/* VBV filler: force CBR VBV and use filler bytes to ensure hard-CBR.
* Implied by NAL-HRD CBR. */
BFiller int32
IAqMode int32 /* psy adaptive QP. (X264_AQ_*) */
FAqStrength float32
BMbTree int32 /* Macroblock-tree ratecontrol. */
ILookahead int32
/* 2pass */
BStatWrite int32 /* Enable stat writing in psz_stat_out */
PszStatOut *int8 /* output filename (in UTF-8) of the 2pass stats file */
BStatRead int32 /* Read stat from psz_stat_in and use it */
PszStatIn *int8 /* input filename (in UTF-8) of the 2pass stats file */
/* 2pass params (same as ffmpeg ones) */
FQcompress float32 /* 0.0 => cbr, 1.0 => constant qp */
FQblur float32 /* temporally blur quants */
FComplexityBlur float32 /* temporally blur complexity */
Zones *Zone /* ratecontrol overrides */
IZones int32 /* number of zone_t's */
PszZones *int8 /* alternate method of specifying zones */
}
/* Cropping Rectangle parameters: added to those implicitly defined by
non-mod16 video resolutions. */
CropRect struct {
ILeft int32
ITop int32
IRight int32
IBottom int32
}
/* frame packing arrangement flag */
IFramePacking int32
/* alternative transfer SEI */
IAlternativeTransfer int32
/* Muxing parameters */
BAud int32 /* generate access unit delimiters */
BRepeatHeaders int32 /* put SPS/PPS before each keyframe */
BAnnexb int32 /* if set, place start codes (4 bytes) before NAL units,
* otherwise place size (4 bytes) before NAL units. */
ISpsId int32 /* SPS and PPS id number */
BVfrInput int32 /* VFR input. If 1, use timebase and timestamps for ratecontrol purposes.
* If 0, use fps only. */
BPulldown int32 /* use explicity set timebase for CFR */
IFpsNum uint32
IFpsDen uint32
ITimebaseNum uint32 /* Timebase numerator */
ITimebaseDen uint32 /* Timebase denominator */
BTff int32
/* Pulldown:
* The correct pic_struct must be passed with each input frame.
* The input timebase should be the timebase corresponding to the output framerate. This should be constant.
* e.g. for 3:2 pulldown timebase should be 1001/30000
* The PTS passed with each frame must be the PTS of the frame after pulldown is applied.
* Frame doubling and tripling require b_vfr_input set to zero (see H.264 Table D-1)
*
* Pulldown changes are not clearly defined in H.264. Therefore, it is the calling app's responsibility to manage this.
*/
BPicStruct int32
/* Fake Interlaced.
*
* Used only when b_interlaced=0. Setting this flag makes it possible to flag the stream as PAFF interlaced yet
* encode all frames progressively. It is useful for encoding 25p and 30p Blu-Ray streams.
*/
BFakeInterlaced int32
/* Don't optimize header parameters based on video content, e.g. ensure that splitting an input video, compressing
* each part, and stitching them back together will result in identical SPS/PPS. This is necessary for stitching
* with container formats that don't allow multiple SPS/PPS. */
BStitchable int32
BOpencl int32 /* use OpenCL when available */
IOpenclDevice int32 /* specify count of GPU devices to skip, for CLI users */
OpenclDeviceId unsafe.Pointer /* pass explicit cl_device_id as void*, for API users */
PszClbinFile *int8 /* filename (in UTF-8) of the compiled OpenCL kernel cache file */
/* Slicing parameters */
iSliceMaxSize int32 /* Max size per slice in bytes; includes estimated NAL overhead. */
iSliceMaxMbs int32 /* Max number of MBs per slice; overrides iSliceCount. */
iSliceMinMbs int32 /* Min number of MBs per slice */
iSliceCount int32 /* Number of slices per frame: forces rectangular slices. */
iSliceCountMax int32 /* Absolute cap on slices per frame; stops applying slice-max-size
* and slice-max-mbs if this is reached. */
ParamFree *func(arg unsafe.Pointer)
NaluProcess *func(H []T, Nal []Nal, Opaque unsafe.Pointer)
Opaque unsafe.Pointer
}
/****************************************************************************
* H.264 level restriction information
****************************************************************************/
type Level struct {
LevelIdc byte
Mbps int32 /* max macroblock processing rate (macroblocks/sec) */
FrameSize int32 /* max frame size (macroblocks) */
Dpb int32 /* max decoded picture buffer (mbs) */
Bitrate int32 /* max bitrate (kbit/sec) */
Cpb int32 /* max vbv buffer (kbit) */
MvRange uint16 /* max vertical mv component range (pixels) */
MvsPer2mb byte /* max mvs per 2 consecutive mbs. */
SliceRate byte /* ?? */
Mincr byte /* min compression ratio */
Bipred8x8 byte /* limit bipred to >=8x8 */
Direct8x8 byte /* limit b_direct to >=8x8 */
FrameOnly byte /* forbid interlacing */
}
type PicStruct int32
const (
PicStructAuto = iota // automatically decide (default)
PicStructProgressive = 1 // progressive frame
// "TOP" and "BOTTOM" are not supported in x264 (PAFF only)
PicStructTopBottom = 4 // top field followed by bottom
PicStructBottomTop = 5 // bottom field followed by top
PicStructTopBottomTop = 6 // top field, bottom field, top field repeated
PicStructBottomTopBottom = 7 // bottom field, top field, bottom field repeated
PicStructDouble = 8 // double frame
PicStructTriple = 9 // triple frame
)
type Hrd struct {
CpbInitialArrivalTime float64
CpbFinalArrivalTime float64
CpbRemovalTime float64
DpbOutputTime float64
}
/* Arbitrary user SEI:
* Payload size is in bytes and the payload pointer must be valid.
* Payload types and syntax can be found in Annex D of the H.264 Specification.
* SEI payload alignment bits as described in Annex D must be included at the
* end of the payload if needed.
* The payload should not be NAL-encapsulated.
* Payloads are written first in order of input, apart from in the case when HRD
* is enabled where payloads are written after the Buffering Period SEI. */
type SeiPayload struct {
PayloadSize int32
PayloadType int32
Payload *byte
}
type Sei struct {
NumPayloads int32
Payloads *SeiPayload
/* In: optional callback to free each payload AND x264_sei_payload_t when used. */
SeiFree *func(arg0 unsafe.Pointer)
}
type Image struct {
ICsp int32 /* Colorspace */
IPlane int32 /* Number of image planes */
IStride [4]int32 /* Strides for each plane */
Plane [4]unsafe.Pointer /* Pointers to each plane */
}
/* All arrays of data here are ordered as follows:
* each array contains one offset per macroblock, in raster scan order. In interlaced
* mode, top-field MBs and bottom-field MBs are interleaved at the row level.
* Macroblocks are 16x16 blocks of pixels (with respect to the luma plane). For the
* purposes of calculating the number of macroblocks, width and height are rounded up to
* the nearest 16. If in interlaced mode, height is rounded up to the nearest 32 instead. */
type ImageProperties struct {
/* In: an array of quantizer offsets to be applied to this image during encoding.
* These are added on top of the decisions made by x264.
* Offsets can be fractional; they are added before QPs are rounded to integer.
* Adaptive quantization must be enabled to use this feature. Behavior if quant
* offsets differ between encoding passes is undefined. */
QuantOffsets *float32
/* In: optional callback to free quant_offsets when used.
* Useful if one wants to use a different quant_offset array for each frame. */
QuantOffsetsFree *func(arg0 unsafe.Pointer)
/* In: optional array of flags for each macroblock.
* Allows specifying additional information for the encoder such as which macroblocks
* remain unchanged. Usable flags are listed below.
* x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track
* extra data internally to make full use of this information.
*
* Out: if b_mb_info_update is set, x264 will update this array as a result of encoding.
*
* For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded
* pixels have changed. This can be useful for e.g. noting which areas of the
* frame need to actually be blitted. Note: this intentionally ignores the effects
* of deblocking for the current frame, which should be fine unless one needs exact
* pixel-perfect accuracy.
*
* Results for MBINFO_CONSTANT are currently only set for P-frames, and are not
* guaranteed to enumerate all blocks which haven't changed. (There may be false
* negatives, but no false positives.)
*/
MbInfo *byte
/* In: optional callback to free mb_info when used. */
MbInfoFree *func(arg0 unsafe.Pointer)
/* Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set) */
FSsim float64
/* Out: Average PSNR of the frame (if x264_param_t.b_psnr is set) */
FPsnrAvg float64
/* Out: PSNR of Y, U, and V (if x264_param_t.b_psnr is set) */
FPsnr [3]float64
/* Out: Average effective CRF of the encoded frame */
FCrfAvg float64
}
type Picture struct {
/* In: force picture type (if not auto)
* If x264 encoding parameters are violated in the forcing of picture types,
* x264 will correct the input picture type and log a warning.
* Out: type of the picture encoded */
IType int32
/* In: force quantizer for != X264_QP_AUTO */
IQpplus1 int32
/* In: pic_struct, for pulldown/doubling/etc...used only if b_pic_struct=1.
* use pic_struct_e for pic_struct inputs
* Out: pic_struct element associated with frame */
IPicStruct int32
/* Out: whether this frame is a keyframe. Important when using modes that result in
* SEI recovery points being used instead of IDR frames. */
BKeyframe int32
/* In: user pts, Out: pts of encoded picture (user)*/
IPts int64
/* Out: frame dts. When the pts of the first frame is close to zero,
* initial frames may have a negative dts which must be dealt with by any muxer */
IDts int64
/* In: custom encoding parameters to be set from this frame forwards
(in coded order, not display order). If NULL, continue using
parameters from the previous frame. Some parameters, such as
aspect ratio, can only be changed per-GOP due to the limitations
of H.264 itself; in this case, the caller must force an IDR frame
if it needs the changed parameter to apply immediately. */
Param *Param
/* In: raw image data */
/* Out: reconstructed image data. x264 may skip part of the reconstruction process,
e.g. deblocking, in frames where it isn't necessary. To force complete
reconstruction, at a small speed cost, set b_full_recon. */
Img Image
/* In: optional information to modify encoder decisions for this frame
* Out: information about the encoded frame */
Prop ImageProperties
/* Out: HRD timing information. Output only when i_nal_hrd is set. */
Hrdiming Hrd
/* In: arbitrary user SEI (e.g subtitles, AFDs) */
ExtraSei Sei
/* private user data. copied from input to output frames. */
Opaque unsafe.Pointer
}
func (p *Picture) freePlane(n int) {
C.free(p.Img.Plane[n])
}
func (t *T) cptr() *C.x264_t { return (*C.x264_t)(unsafe.Pointer(t)) }
func (n *Nal) cptr() *C.x264_nal_t { return (*C.x264_nal_t)(unsafe.Pointer(n)) }
func (p *Param) cptr() *C.x264_param_t { return (*C.x264_param_t)(unsafe.Pointer(p)) }
func (p *Picture) cptr() *C.x264_picture_t { return (*C.x264_picture_t)(unsafe.Pointer(p)) }
// NalEncode - encode Nal.
func NalEncode(h *T, dst []byte, nal *Nal) {
ch := h.cptr()
cdst := (*C.uint8_t)(unsafe.Pointer(&dst[0]))
cnal := nal.cptr()
C.x264_nal_encode(ch, cdst, cnal)
}
// ParamDefault - fill Param with default values and do CPU detection.
func ParamDefault(param *Param) {
C.x264_param_default(param.cptr())
}
// ParamParse - set one parameter by name. Returns 0 on success.
func ParamParse(param *Param, name string, value string) int32 {
cparam := param.cptr()
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cvalue := C.CString(value)
defer C.free(unsafe.Pointer(cvalue))
ret := C.x264_param_parse(cparam, cname, cvalue)
v := (int32)(ret)
return v
}
// ParamDefaultPreset - the same as ParamDefault, but also use the passed preset and tune to modify the default settings
// (either can be nil, which implies no preset or no tune, respectively).
//
// Currently available presets are, ordered from fastest to slowest:
// "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo".
//
// Currently available tunings are:
// "film", "animation", "grain", "stillimage", "psnr", "ssim", "fastdecode", "zerolatency".
//
// Returns 0 on success, negative on failure (e.g. invalid preset/tune name).
func ParamDefaultPreset(param *Param, preset string, tune string) int32 {
cparam := param.cptr()
cpreset := C.CString(preset)
defer C.free(unsafe.Pointer(cpreset))
ctune := C.CString(tune)
defer C.free(unsafe.Pointer(ctune))
ret := C.x264_param_default_preset(cparam, cpreset, ctune)
v := (int32)(ret)
return v
}
// ParamApplyFastfirstpass - if first-pass mode is set (rc.b_stat_read == 0, rc.b_stat_write == 1),
// modify the encoder settings to disable options generally not useful on the first pass.
func ParamApplyFastfirstpass(param *Param) {
cparam := param.cptr()
C.x264_param_apply_fastfirstpass(cparam)
}
// ParamApplyProfile - applies the restrictions of the given profile.
//
// Currently available profiles are, from most to least restrictive:
// "baseline", "main", "high", "high10", "high422", "high444".
// (can be nil, in which case the function will do nothing).
//
// Returns 0 on success, negative on failure (e.g. invalid profile name).
func ParamApplyProfile(param *Param, profile string) int32 {
cparam := param.cptr()
cprofile := C.CString(profile)
defer C.free(unsafe.Pointer(cprofile))
ret := C.x264_param_apply_profile(cparam, cprofile)
v := (int32)(ret)
return v
}
// PictureInit - initialize an Picture. Needs to be done if the calling application
// allocates its own Picture as opposed to using PictureAlloc.
func PictureInit(pic *Picture) {
cpic := pic.cptr()
C.x264_picture_init(cpic)
}
// PictureAlloc - alloc data for a Picture. You must call PictureClean on it.
// Returns 0 on success, or -1 on malloc failure or invalid colorspace.
func PictureAlloc(pic *Picture, iCsp int32, iWidth int32, iHeight int32) int32 {
cpic := pic.cptr()
ciCsp := (C.int)(iCsp)
ciWidth := (C.int)(iWidth)
ciHeight := (C.int)(iHeight)
ret := C.x264_picture_alloc(cpic, ciCsp, ciWidth, ciHeight)
v := (int32)(ret)
return v
}
// PictureClean - free associated resource for a Picture allocated with PictureAlloc ONLY.
func PictureClean(pic *Picture) {
cpic := pic.cptr()
C.x264_picture_clean(cpic)
}
// EncoderOpen - create a new encoder handler, all parameters from Param are copied.
func EncoderOpen(param *Param) *T {
cparam := param.cptr()
ret := C.x264_encoder_open(cparam)
v := *(**T)(unsafe.Pointer(&ret))
return v
}
// EncoderReconfig - various parameters from Param are copied.
// Returns 0 on success, negative on parameter validation error.
func EncoderReconfig(enc *T, param *Param) int32 {
cenc := enc.cptr()
cparam := param.cptr()
ret := C.x264_encoder_reconfig(cenc, cparam)
v := (int32)(ret)
return v
}
// EncoderParameters - copies the current internal set of parameters to the pointer provided.
func EncoderParameters(enc *T, param *Param) {
cenc := enc.cptr()
cparam := param.cptr()
C.x264_encoder_parameters(cenc, cparam)
}
// EncoderHeaders - return the SPS and PPS that will be used for the whole stream.
// Returns the number of bytes in the returned NALs or negative on error.
func EncoderHeaders(enc *T, ppNal []*Nal, piNal *int32) int32 {
cenc := enc.cptr()
cppNal := (**C.x264_nal_t)(unsafe.Pointer(&ppNal[0]))
cpiNal := (*C.int)(unsafe.Pointer(piNal))
ret := C.x264_encoder_headers(cenc, cppNal, cpiNal)
v := (int32)(ret)
return v
}
// EncoderEncode - encode one picture.
// Returns the number of bytes in the returned NALs, negative on error and zero if no NAL units returned.
func EncoderEncode(enc *T, ppNal []*Nal, piNal *int32, picIn *Picture, picOut *Picture) int32 {
cenc := enc.cptr()
cppNal := (**C.x264_nal_t)(unsafe.Pointer(&ppNal[0]))
cpiNal := (*C.int)(unsafe.Pointer(piNal))
cpicIn := picIn.cptr()
cpicOut := picOut.cptr()
ret := C.x264_encoder_encode(cenc, cppNal, cpiNal, cpicIn, cpicOut)
v := (int32)(ret)
return v
}
// EncoderClose - close an encoder handler.
func EncoderClose(enc *T) {
cenc := enc.cptr()
C.x264_encoder_close(cenc)
}
// EncoderDelayedFrames - return the number of currently delayed (buffered) frames.
// This should be used at the end of the stream, to know when you have all the encoded frames.
func EncoderDelayedFrames(enc *T) int32 {
cenc := enc.cptr()
ret := C.x264_encoder_delayed_frames(cenc)
v := (int32)(ret)
return v
}
// EncoderMaximumDelayedFrames - return the maximum number of delayed (buffered) frames that can occur with the current parameters.
func EncoderMaximumDelayedFrames(enc *T) int32 {
cenc := enc.cptr()
ret := C.x264_encoder_maximum_delayed_frames(cenc)
v := (int32)(ret)
return v
}
// EncoderIntraRefresh - If an intra refresh is not in progress, begin one with the next P-frame.
// If an intra refresh is in progress, begin one as soon as the current one finishes.
// Requires that BIntraRefresh be set.
//
// Should not be called during an x264_encoder_encode.
func EncoderIntraRefresh(enc *T) {
cenc := enc.cptr()
C.x264_encoder_intra_refresh(cenc)
}
// EncoderInvalidateReference - An interactive error resilience tool, designed for use in a low-latency one-encoder-few-clients system.
// Should not be called during an EncoderEncode, but multiple calls can be made simultaneously.
//
// Returns 0 on success, negative on failure.
func EncoderInvalidateReference(enc *T, pts int) int32 {
cenc := enc.cptr()
cpts := (C.int64_t)(pts)
ret := C.x264_encoder_invalidate_reference(cenc, cpts)
v := (int32)(ret)
return v
}

View file

@ -1,30 +1,27 @@
package h264
// #include <stdlib.h>
import "C"
import (
"fmt"
"log"
x264 "github.com/sergystepanov/x264-go/v2/x264c/external"
)
type H264 struct {
ref *x264.T
ref *T
width int32
lumaSize int32
chromaSize int32
csp int32
nnals int32
nals []*x264.Nal
nals []*Nal
// keep monotonic pts to suppress warnings
pts int64
}
func NewEncoder(width, height int, options ...Option) (encoder *H264, err error) {
libVersion := int(x264.Build)
libVersion := int(Build)
if libVersion < 150 {
return nil, fmt.Errorf("x264: the library version should be newer than v150, you have got version %v", libVersion)
@ -46,20 +43,20 @@ func NewEncoder(width, height int, options ...Option) (encoder *H264, err error)
}
if opts.LogLevel > 0 {
log.Printf("x264: build v%v", x264.Build)
log.Printf("x264: build v%v", Build)
}
param := x264.Param{}
param := Param{}
if opts.Preset != "" && opts.Tune != "" {
if x264.ParamDefaultPreset(&param, opts.Preset, opts.Tune) < 0 {
if ParamDefaultPreset(&param, opts.Preset, opts.Tune) < 0 {
return nil, fmt.Errorf("x264: invalid preset/tune name")
}
} else {
x264.ParamDefault(&param)
ParamDefault(&param)
}
if opts.Profile != "" {
if x264.ParamApplyProfile(&param, opts.Profile) < 0 {
if ParamApplyProfile(&param, opts.Profile) < 0 {
return nil, fmt.Errorf("x264: invalid profile name")
}
}
@ -68,7 +65,7 @@ func NewEncoder(width, height int, options ...Option) (encoder *H264, err error)
param.IBitdepth = 8
if libVersion > 155 {
param.ICsp = x264.CspI420
param.ICsp = CspI420
} else {
param.ICsp = 1
}
@ -76,21 +73,21 @@ func NewEncoder(width, height int, options ...Option) (encoder *H264, err error)
param.IHeight = int32(height)
param.ILogLevel = opts.LogLevel
param.Rc.IRcMethod = x264.RcCrf
param.Rc.IRcMethod = RcCrf
param.Rc.FRfConstant = float32(opts.Crf)
encoder = &H264{
csp: param.ICsp,
lumaSize: int32(width * height),
chromaSize: int32(width*height) / 4,
nals: make([]*x264.Nal, 1),
nals: make([]*Nal, 1),
width: int32(width),
}
var picIn x264.Picture
x264.PictureInit(&picIn)
var picIn Picture
PictureInit(&picIn)
if encoder.ref = x264.EncoderOpen(&param); encoder.ref == nil {
if encoder.ref = EncoderOpen(&param); encoder.ref == nil {
err = fmt.Errorf("x264: cannot open the encoder")
return
}
@ -98,7 +95,7 @@ func NewEncoder(width, height int, options ...Option) (encoder *H264, err error)
}
func (e *H264) Encode(yuv []byte) []byte {
var picIn, picOut x264.Picture
var picIn, picOut Picture
picIn.Img.ICsp = e.csp
picIn.Img.IPlane = 3
@ -114,12 +111,12 @@ func (e *H264) Encode(yuv []byte) []byte {
e.pts++
defer func() {
C.free(picIn.Img.Plane[0])
C.free(picIn.Img.Plane[1])
C.free(picIn.Img.Plane[2])
picIn.freePlane(0)
picIn.freePlane(1)
picIn.freePlane(2)
}()
if ret := x264.EncoderEncode(e.ref, e.nals, &e.nnals, &picIn, &picOut); ret > 0 {
if ret := EncoderEncode(e.ref, e.nals, &e.nnals, &picIn, &picOut); ret > 0 {
return C.GoBytes(e.nals[0].PPayload, C.int(ret))
// ret should be equal to writer writes
}
@ -127,6 +124,6 @@ func (e *H264) Encode(yuv []byte) []byte {
}
func (e *H264) Shutdown() error {
x264.EncoderClose(e.ref)
EncoderClose(e.ref)
return nil
}

View file

@ -3,12 +3,10 @@ package opus
import (
"fmt"
"log"
"gopkg.in/hraban/opus.v2"
)
type Encoder struct {
*opus.Encoder
*LibOpusEncoder
channels int
inFrequency int
@ -22,26 +20,26 @@ type Encoder struct {
}
func NewEncoder(inputSampleRate, outputSampleRate, channels int, options ...func(*Encoder) error) (Encoder, error) {
encoder, err := opus.NewEncoder(
encoder, err := NewOpusEncoder(
outputSampleRate,
channels,
// be aware that low delay option is not optimized for voice
opus.AppRestrictedLowdelay,
AppRestrictedLowdelay,
)
if err != nil {
return Encoder{}, err
}
enc := &Encoder{
Encoder: encoder,
buffer: Buffer{Data: make([]int16, inputSampleRate*20/1000*channels)},
channels: channels,
inFrequency: inputSampleRate,
outFrequency: outputSampleRate,
outBufferSize: 1024,
onFullBuffer: func(data []byte) {},
LibOpusEncoder: encoder,
buffer: Buffer{Data: make([]int16, inputSampleRate*20/1000*channels)},
channels: channels,
inFrequency: inputSampleRate,
outFrequency: outputSampleRate,
outBufferSize: 1024,
onFullBuffer: func(data []byte) {},
}
_ = enc.SetMaxBandwidth(opus.Fullband)
_ = enc.SetMaxBandwidth(FullBand)
_ = enc.SetBitrate(192000)
_ = enc.SetComplexity(10)
@ -92,7 +90,7 @@ func (e *Encoder) Encode(pcm []int16) ([]byte, error) {
pcm = resampleFn(pcm, e.resampleBufSize)
}
data := make([]byte, e.outBufferSize)
n, err := e.Encoder.Encode(pcm, data)
n, err := e.LibOpusEncoder.Encode(pcm, data)
if err != nil {
return []byte{}, err
}
@ -100,16 +98,16 @@ func (e *Encoder) Encode(pcm []int16) ([]byte, error) {
}
func (e *Encoder) GetInfo() string {
bitrate, _ := e.Encoder.Bitrate()
complexity, _ := e.Encoder.Complexity()
dtx, _ := e.Encoder.DTX()
fec, _ := e.Encoder.InBandFEC()
maxBandwidth, _ := e.Encoder.MaxBandwidth()
lossPercent, _ := e.Encoder.PacketLossPerc()
sampleRate, _ := e.Encoder.SampleRate()
bitrate, _ := e.LibOpusEncoder.Bitrate()
complexity, _ := e.LibOpusEncoder.Complexity()
dtx, _ := e.LibOpusEncoder.DTX()
fec, _ := e.LibOpusEncoder.FEC()
maxBandwidth, _ := e.LibOpusEncoder.MaxBandwidth()
lossPercent, _ := e.LibOpusEncoder.PacketLossPerc()
sampleRate, _ := e.LibOpusEncoder.SampleRate()
return fmt.Sprintf(
"Bitrate: %v bps, Complexity: %v, DTX: %v, FEC: %v, Max bandwidth: *%v, Loss%%: %v, Rate: %v Hz",
bitrate, complexity, dtx, fec, maxBandwidth, lossPercent, sampleRate,
"%v, Bitrate: %v bps, Complexity: %v, DTX: %v, FEC: %v, Max bandwidth: *%v, Loss%%: %v, Rate: %v Hz",
CodecVersion(), bitrate, complexity, dtx, fec, maxBandwidth, lossPercent, sampleRate,
)
}

199
pkg/encoder/opus/opus.go Normal file
View file

@ -0,0 +1,199 @@
package opus
/*
#cgo pkg-config: opus
#include <opus.h>
int bridge_encoder_get_bitrate(OpusEncoder *st, opus_int32 *bitrate) { return opus_encoder_ctl(st, OPUS_GET_BITRATE(bitrate)); }
int bridge_encoder_get_complexity(OpusEncoder *st, opus_int32 *complexity) { return opus_encoder_ctl(st, OPUS_GET_COMPLEXITY(complexity)); }
int bridge_encoder_get_dtx(OpusEncoder *st, opus_int32 *dtx) { return opus_encoder_ctl(st, OPUS_GET_DTX(dtx)); }
int bridge_encoder_get_inband_fec(OpusEncoder *st, opus_int32 *fec) { return opus_encoder_ctl(st, OPUS_GET_INBAND_FEC(fec)); }
int bridge_encoder_get_max_bandwidth(OpusEncoder *st, opus_int32 *max_bw) { return opus_encoder_ctl(st, OPUS_GET_MAX_BANDWIDTH(max_bw)); }
int bridge_encoder_get_packet_loss_perc(OpusEncoder *st, opus_int32 *loss_perc) { return opus_encoder_ctl(st, OPUS_GET_PACKET_LOSS_PERC(loss_perc)); }
int bridge_encoder_get_sample_rate(OpusEncoder *st, opus_int32 *sample_rate) { return opus_encoder_ctl(st, OPUS_GET_SAMPLE_RATE(sample_rate)); }
int bridge_encoder_set_bitrate(OpusEncoder *st, opus_int32 bitrate) { return opus_encoder_ctl(st, OPUS_SET_BITRATE(bitrate)); }
int bridge_encoder_set_complexity(OpusEncoder *st, opus_int32 complexity) { return opus_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity)); }
int bridge_encoder_set_dtx(OpusEncoder *st, opus_int32 use_dtx) { return opus_encoder_ctl(st, OPUS_SET_DTX(use_dtx)); }
int bridge_encoder_set_inband_fec(OpusEncoder *st, opus_int32 fec) { return opus_encoder_ctl(st, OPUS_SET_INBAND_FEC(fec)); }
int bridge_encoder_set_max_bandwidth(OpusEncoder *st, opus_int32 max_bw) { return opus_encoder_ctl(st, OPUS_SET_MAX_BANDWIDTH(max_bw)); }
int bridge_encoder_set_packet_loss_perc(OpusEncoder *st, opus_int32 loss_perc) { return opus_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(loss_perc)); }
*/
import "C"
import (
"fmt"
"unsafe"
)
type (
Application int
Bandwidth int
Bitrate int
Error int
)
const (
// Optimize encoding for VoIP
AppVoIP = Application(C.OPUS_APPLICATION_VOIP)
// Optimize encoding for non-voice signals like music
AppAudio = Application(C.OPUS_APPLICATION_AUDIO)
// Optimize encoding for low latency applications
AppRestrictedLowdelay = Application(C.OPUS_APPLICATION_RESTRICTED_LOWDELAY)
// Auto/default setting
BitrateAuto = Bitrate(-1000)
BitrateMax = Bitrate(-1)
// 20 kHz bandpass
FullBand = Bandwidth(C.OPUS_BANDWIDTH_FULLBAND)
)
const (
ErrorOK = Error(C.OPUS_OK)
ErrorBadArg = Error(C.OPUS_BAD_ARG)
ErrorBufferTooSmall = Error(C.OPUS_BUFFER_TOO_SMALL)
ErrorInternalError = Error(C.OPUS_INTERNAL_ERROR)
ErrorInvalidPacket = Error(C.OPUS_INVALID_PACKET)
ErrorUnimplemented = Error(C.OPUS_UNIMPLEMENTED)
ErrorInvalidState = Error(C.OPUS_INVALID_STATE)
ErrorAllocFail = Error(C.OPUS_ALLOC_FAIL)
)
type LibOpusEncoder struct {
buf []byte
channels int
ptr *C.struct_OpusEncoder
}
// NewOpusEncoder creates new Opus encoder.
func NewOpusEncoder(sampleRate int, channels int, app Application) (*LibOpusEncoder, error) {
var enc LibOpusEncoder
if enc.ptr != nil {
return nil, fmt.Errorf("opus: encoder reinit")
}
enc.channels = channels
// !to check mem leak
enc.buf = make([]byte, C.opus_encoder_get_size(C.int(channels)))
enc.ptr = (*C.OpusEncoder)(unsafe.Pointer(&enc.buf[0]))
err := unwrap(C.opus_encoder_init(enc.ptr, C.opus_int32(sampleRate), C.int(channels), C.int(app)))
if err != nil {
return nil, fmt.Errorf("opus: initializatoin error (%v)", err)
}
return &enc, nil
}
// Encode converts raw PCM samples into the supplied Opus buffer.
// Returns the number of bytes converted.
func (enc *LibOpusEncoder) Encode(pcm []int16, data []byte) (rez int, err error) {
if len(pcm) == 0 {
return
}
samples := C.int(len(pcm) / enc.channels)
n := C.opus_encode(enc.ptr, (*C.opus_int16)(&pcm[0]), samples, (*C.uchar)(&data[0]), C.opus_int32(cap(data)))
if n > 0 {
rez = int(n)
}
return rez, unwrap(n)
}
// SampleRate returns the sample rate of the encoder.
func (enc *LibOpusEncoder) SampleRate() (int, error) {
var sampleRate C.opus_int32
res := C.bridge_encoder_get_sample_rate(enc.ptr, &sampleRate)
return int(sampleRate), unwrap(res)
}
// Bitrate returns the bitrate of the encoder.
func (enc *LibOpusEncoder) Bitrate() (int, error) {
var bitrate C.opus_int32
res := C.bridge_encoder_get_bitrate(enc.ptr, &bitrate)
return int(bitrate), unwrap(res)
}
// SetBitrate sets the bitrate of the encoder.
// BitrateMax / BitrateAuto can be used here.
func (enc *LibOpusEncoder) SetBitrate(b Bitrate) error {
return unwrap(C.bridge_encoder_set_bitrate(enc.ptr, C.opus_int32(b)))
}
// Complexity returns the value of the complexity.
func (enc *LibOpusEncoder) Complexity() (int, error) {
var complexity C.opus_int32
res := C.bridge_encoder_get_complexity(enc.ptr, &complexity)
return int(complexity), unwrap(res)
}
// SetComplexity sets the complexity factor for the encoder.
// Complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest.
func (enc *LibOpusEncoder) SetComplexity(complexity int) error {
return unwrap(C.bridge_encoder_set_complexity(enc.ptr, C.opus_int32(complexity)))
}
// DTX says if discontinuous transmission is enabled.
func (enc *LibOpusEncoder) DTX() (bool, error) {
var dtx C.opus_int32
res := C.bridge_encoder_get_dtx(enc.ptr, &dtx)
return dtx > 0, unwrap(res)
}
// SetDTX switches discontinuous transmission.
func (enc *LibOpusEncoder) SetDTX(dtx bool) error {
var i int
if dtx {
i = 1
}
return unwrap(C.bridge_encoder_set_dtx(enc.ptr, C.opus_int32(i)))
}
// MaxBandwidth returns the maximum allowed bandpass value.
func (enc *LibOpusEncoder) MaxBandwidth() (Bandwidth, error) {
var b C.opus_int32
res := C.bridge_encoder_get_max_bandwidth(enc.ptr, &b)
return Bandwidth(b), unwrap(res)
}
// SetMaxBandwidth sets the upper limit of the bandpass.
func (enc *LibOpusEncoder) SetMaxBandwidth(b Bandwidth) error {
return unwrap(C.bridge_encoder_set_max_bandwidth(enc.ptr, C.opus_int32(b)))
}
// FEC says if forward error correction (FEC) is enabled.
func (enc *LibOpusEncoder) FEC() (bool, error) {
var fec C.opus_int32
res := C.bridge_encoder_get_inband_fec(enc.ptr, &fec)
return fec > 0, unwrap(res)
}
// SetFEC switches the forward error correction (FEC).
func (enc *LibOpusEncoder) SetFEC(fec bool) error {
var i int
if fec {
i = 1
}
return unwrap(C.bridge_encoder_set_inband_fec(enc.ptr, C.opus_int32(i)))
}
// PacketLossPerc returns configured packet loss percentage.
func (enc *LibOpusEncoder) PacketLossPerc() (int, error) {
var lossPerc C.opus_int32
res := C.bridge_encoder_get_packet_loss_perc(enc.ptr, &lossPerc)
return int(lossPerc), unwrap(res)
}
// SetPacketLossPerc sets expected packet loss percentage.
func (enc *LibOpusEncoder) SetPacketLossPerc(lossPerc int) error {
return unwrap(C.bridge_encoder_set_packet_loss_perc(enc.ptr, C.opus_int32(lossPerc)))
}
func (e Error) Error() string {
return fmt.Sprintf("opus: %v", C.GoString(C.opus_strerror(C.int(e))))
}
func unwrap(error C.int) (err error) {
if error < C.OPUS_OK {
err = Error(int(error))
}
return
}
func CodecVersion() string { return C.GoString(C.opus_get_version_string()) }

View file

@ -6,8 +6,8 @@ type Env string
const (
Dev Env = "dev"
Staging = "staging"
Production = "prod"
Staging Env = "staging"
Production Env = "prod"
)
func (env *Env) AnyOf(what ...Env) bool {

View file

@ -1,43 +0,0 @@
// credit to https://github.com/poi5305/go-yuv2webRTC/blob/master/webrtc/webrtc.go
package webrtc
import (
"bytes"
"compress/gzip"
"io/ioutil"
)
func zip(in []byte) []byte {
var b bytes.Buffer
gz := gzip.NewWriter(&b)
_, err := gz.Write(in)
if err != nil {
panic(err)
}
err = gz.Flush()
if err != nil {
panic(err)
}
err = gz.Close()
if err != nil {
panic(err)
}
return b.Bytes()
}
func unzip(in []byte) []byte {
var b bytes.Buffer
_, err := b.Write(in)
if err != nil {
panic(err)
}
r, err := gzip.NewReader(&b)
if err != nil {
panic(err)
}
res, err := ioutil.ReadAll(r)
if err != nil {
panic(err)
}
return res
}

View file

@ -31,7 +31,6 @@ type WebRTC struct {
cfg webrtcConfig.Config
tsInterceptor itc.ReTime
isConnected bool
isClosed bool
// for yuvI420 image
ImageChannel chan WebFrame
AudioChannel chan []byte
@ -39,9 +38,9 @@ type WebRTC struct {
//VoiceOutChannel chan []byte
InputChannel chan []byte
Done bool
lastTime time.Time
curFPS int
Done bool
//lastTime time.Time
//curFPS int
RoomID string
@ -152,6 +151,9 @@ func (w *WebRTC) StartClient(isMobile bool, iceCB OnIceCallback) (string, error)
// create data channel for input, and register callbacks
// order: true, negotiated: false, id: random
inputTrack, err := w.connection.CreateDataChannel("game-input", nil)
if err != nil {
return "", err
}
inputTrack.OnOpen(func() {
log.Printf("Data channel '%s'-'%d' open.\n", inputTrack.Label(), inputTrack.ID())
@ -295,7 +297,7 @@ func (w *WebRTC) AddCandidate(candidate string) error {
// StopClient disconnect
func (w *WebRTC) StopClient() {
// if stopped, bypass
if w.isConnected == false {
if !w.isConnected {
return
}
@ -382,10 +384,10 @@ func (w *WebRTC) startStreaming(vp8Track *webrtc.TrackLocalStaticSample, opusTra
//}()
}
func (w *WebRTC) calculateFPS() int {
elapsedTime := time.Now().Sub(w.lastTime)
w.lastTime = time.Now()
curFPS := time.Second / elapsedTime
w.curFPS = int(float32(w.curFPS)*0.9 + float32(curFPS)*0.1)
return w.curFPS
}
//func (w *WebRTC) calculateFPS() int {
// elapsedTime := time.Now().Sub(w.lastTime)
// w.lastTime = time.Now()
// curFPS := time.Second / elapsedTime
// w.curFPS = int(float32(w.curFPS)*0.9 + float32(curFPS)*0.1)
// return w.curFPS
//}

View file

@ -88,6 +88,12 @@ func (h *Handler) Prepare() {
log.Printf("Starting Libretro cores sync...")
coreManager := remotehttp.NewRemoteHttpManager(h.cfg.Emulator.Libretro)
// make a dir for cores
dir := coreManager.Conf.GetCoresStorePath()
if err := os.MkdirAll(dir, os.ModeDir); err != nil {
log.Printf("error: couldn't make %v directory", dir)
return
}
if err := coreManager.Sync(); err != nil {
log.Printf("error: cores sync has failed, %v", err)
}

17
scripts/install.sh vendored Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env bash
echo This script should install application dependencies for Debian-based systems
if [ $(id -u) -ne 0 ]
then
echo "error: run with sudo or root"
exit 1
fi
apt-get update
apt-get install --no-install-recommends -y \
libvpx6 \
libx264-160 \
libopus0 \
libsdl2-2.0-0 \
libgl1-mesa-glx \
xvfb