39 Commits

Author SHA1 Message Date
5959d056f3 Fix arm build (#302)
* WIP.

* WIP.

* WIP.
2023-04-29 18:35:11 +02:00
92ad202bfe Add version to docker build (#301)
* add version to build.

* update docs.
2023-04-29 00:12:56 +02:00
cd4acb5eec lang url parameter (#296)
* lang url parameter

* add ?lang to readme.

---------

Co-authored-by: Miroslav Šedivý <sedivy.miro@gmail.com>
2023-04-22 01:24:23 +02:00
a32be0b44a Update Dockerfile.nvidia for google-chrome 2023-04-16 00:31:05 +02:00
b2080649ea add docs fixes #275. 2023-04-10 13:05:56 +02:00
851c38b8fd update docs. 2023-04-10 13:01:00 +02:00
e2336be568 update changelog. 2023-04-09 15:45:14 +02:00
e417ec5dbe add XDG_RUNTIME_DIR to env. 2023-04-09 15:42:33 +02:00
ad7e1f2b7b allow using supervisorctl. 2023-04-09 15:24:16 +02:00
91e1a8b502 add firefox nvidia. 2023-04-09 15:22:44 +02:00
9bdf9c8851 fix nvidia google chrome version, #229. 2023-04-07 20:20:05 +02:00
c1360d3abc ensure that paths are writable by neko user, #277. 2023-04-06 00:00:59 +02:00
950095d6d8 update Dockerfile.nvidia, #274. 2023-04-03 20:06:52 +02:00
009bc20969 update docs, #273. 2023-04-02 12:35:06 +02:00
395db0fd54 version 2.8.0. 2023-04-01 23:01:10 +02:00
13fa86d543 update changelog. 2023-04-01 22:59:39 +02:00
8308c13382 update nvenc pipeline. 2023-04-01 22:59:39 +02:00
ec175909a3 improve quality a little bit 2023-04-01 22:59:39 +02:00
d2f51fa10f add h264parse to nvidia pipeline 2023-04-01 22:59:39 +02:00
70325e0277 add nvenc pipeline. 2023-04-01 22:59:39 +02:00
bdff0841ec add nvenc support for gstreamer. 2023-04-01 22:59:39 +02:00
3c17dbe282 h264 encoding profile constrained-baseline, #109. 2023-03-31 21:43:20 +02:00
887413d536 update changelog. 2023-03-27 21:55:52 +02:00
f9228e653d Merge branch 'pu/touch' 2023-03-27 21:47:49 +02:00
df634be1c5 lint. 2023-03-27 21:47:41 +02:00
2130daa02d add volume to docs. 2023-03-27 18:22:31 +02:00
aee7650d47 add touch events on touch monitor 2023-03-27 14:28:42 +02:00
98ba32c574 add url param for audio volume. 2023-03-27 13:04:11 +02:00
d08d3eccef configure pulseaudio from ENV, #267. 2023-03-26 20:13:35 +02:00
0dd9597519 create pulseaudio sink, fixes #267. 2023-03-26 18:59:10 +02:00
334fcef407 update changelog. 2023-03-25 22:21:00 +01:00
e868ad4061 Merge branch 'pu/autoplay' 2023-03-25 22:19:43 +01:00
b41d0bf956 lint fix. 2023-03-25 22:19:01 +01:00
b62fa6ab8b kde disable autolock, fixes #266. 2023-03-25 22:09:17 +01:00
8dba9cff44 revert extra controls usecase. 2023-03-25 21:53:17 +01:00
217cc451ea add autoplay audio if possible 2023-03-24 21:33:32 +01:00
1f81bd3efc hide buttons in cast mode 2023-03-24 21:15:51 +01:00
50e5483661 turn on vaapi hwenc in intel images by default. 2023-03-19 19:13:11 +01:00
Bad
d2765c30fd readd -> read 2023-03-19 18:13:06 +01:00
25 changed files with 539 additions and 147 deletions

View File

@ -27,7 +27,7 @@ RUN set -eux; apt-get update; \
#
# build server
COPY server/ .
RUN go get -v -t -d . && go build -o bin/neko cmd/neko/main.go
RUN ./build
#
# STAGE 2: CLIENT
@ -90,19 +90,18 @@ RUN set -eux; \
adduser $USERNAME video; \
adduser $USERNAME pulse; \
#
# setup pulseaudio
mkdir -p /home/$USERNAME/.config/pulse/; \
echo "default-server=unix:/tmp/pulseaudio.socket" > /home/$USERNAME/.config/pulse/client.conf; \
#
# workaround for an X11 problem: http://blog.tigerteufel.de/?p=476
mkdir /tmp/.X11-unix; \
chmod 1777 /tmp/.X11-unix; \
chown $USERNAME /tmp/.X11-unix/; \
#
# make directories for neko
mkdir -p /etc/neko /var/www /var/log/neko; \
mkdir -p /etc/neko /var/www /var/log/neko \
/tmp/runtime-$USERNAME \
/home/$USERNAME/.config/pulse \
/home/$USERNAME/.local/share/xorg; \
chmod 1777 /var/log/neko; \
chown $USERNAME /var/log/neko/; \
chown $USERNAME /var/log/neko/ /tmp/runtime-$USERNAME; \
chown -R $USERNAME:$USERNAME /home/$USERNAME; \
#
# clean up
@ -120,6 +119,8 @@ COPY .docker/base/xorg.conf /etc/neko/xorg.conf
# set default envs
ENV USER=$USERNAME
ENV DISPLAY=:99.0
ENV PULSE_SERVER=unix:/tmp/pulseaudio.socket
ENV XDG_RUNTIME_DIR=/tmp/runtime-$USERNAME
ENV NEKO_PASSWORD=neko
ENV NEKO_PASSWORD_ADMIN=admin
ENV NEKO_BIND=:8080

View File

@ -27,29 +27,32 @@ RUN set -eux; apt-get update; \
#
# build server
COPY server/ .
RUN go get -v -t -d . && go build -o bin/neko cmd/neko/main.go
RUN ./build
#
# STAGE 2: CLIENT
#
FROM node:18-bullseye-slim as client
# install dependencies
RUN set -eux; apt-get update; \
apt-get install -y --no-install-recommends python2 build-essential
WORKDIR /src
#
# install dependencies
COPY client/package*.json ./
RUN npm install
# Because client builds fail in Github Actions, therefor we build it outside of Docker.
#
# FROM node:18-bullseye-slim as client
#
# # install dependencies
# RUN set -eux; apt-get update; \
# apt-get install -y --no-install-recommends python2 build-essential
#
# WORKDIR /src
#
# #
# # install dependencies
# COPY client/package*.json ./
# RUN npm install
#
# #
# # build client
# COPY client/ .
# RUN npm run build
#
# build client
COPY client/ .
RUN npm run build
#
# STAGE 3: RUNTIME
#
@ -96,19 +99,18 @@ RUN set -eux; \
adduser $USERNAME video; \
adduser $USERNAME pulse; \
#
# setup pulseaudio
mkdir -p /home/$USERNAME/.config/pulse/; \
echo "default-server=unix:/tmp/pulseaudio.socket" > /home/$USERNAME/.config/pulse/client.conf; \
#
# workaround for an X11 problem: http://blog.tigerteufel.de/?p=476
mkdir /tmp/.X11-unix; \
chmod 1777 /tmp/.X11-unix; \
chown $USERNAME /tmp/.X11-unix/; \
#
# make directories for neko
mkdir -p /etc/neko /var/www /var/log/neko; \
mkdir -p /etc/neko /var/www /var/log/neko \
/tmp/runtime-$USERNAME \
/home/$USERNAME/.config/pulse \
/home/$USERNAME/.local/share/xorg; \
chmod 1777 /var/log/neko; \
chown $USERNAME /var/log/neko/; \
chown $USERNAME /var/log/neko/ /tmp/runtime-$USERNAME; \
chown -R $USERNAME:$USERNAME /home/$USERNAME; \
#
# clean up
@ -126,6 +128,8 @@ COPY .docker/base/xorg.conf /etc/neko/xorg.conf
# set default envs
ENV USER=$USERNAME
ENV DISPLAY=:99.0
ENV PULSE_SERVER=unix:/tmp/pulseaudio.socket
ENV XDG_RUNTIME_DIR=/tmp/runtime-$USERNAME
ENV NEKO_PASSWORD=neko
ENV NEKO_PASSWORD_ADMIN=admin
ENV NEKO_BIND=:8080
@ -133,7 +137,8 @@ ENV NEKO_BIND=:8080
#
# copy static files from previous stages
COPY --from=server /src/bin/neko /usr/bin/neko
COPY --from=client /src/dist/ /var/www
# COPY --from=client /src/dist/ /var/www
COPY client/dist/ /var/www
HEALTHCHECK --interval=10s --timeout=5s --retries=8 \
CMD wget -O - http://localhost:${NEKO_BIND#*:}/health || exit 1

View File

@ -27,7 +27,7 @@ RUN set -eux; apt-get update; \
#
# build server
COPY server/ .
RUN go get -v -t -d . && go build -o bin/neko cmd/neko/main.go
RUN ./build
#
# STAGE 2: CLIENT
@ -99,19 +99,18 @@ RUN set -eux; \
adduser $USERNAME video; \
adduser $USERNAME pulse; \
#
# setup pulseaudio
mkdir -p /home/$USERNAME/.config/pulse/; \
echo "default-server=unix:/tmp/pulseaudio.socket" > /home/$USERNAME/.config/pulse/client.conf; \
#
# workaround for an X11 problem: http://blog.tigerteufel.de/?p=476
mkdir /tmp/.X11-unix; \
chmod 1777 /tmp/.X11-unix; \
chown $USERNAME /tmp/.X11-unix/; \
#
# make directories for neko
mkdir -p /etc/neko /var/www /var/log/neko; \
mkdir -p /etc/neko /var/www /var/log/neko \
/tmp/runtime-$USERNAME \
/home/$USERNAME/.config/pulse \
/home/$USERNAME/.local/share/xorg; \
chmod 1777 /var/log/neko; \
chown $USERNAME /var/log/neko/; \
chown $USERNAME /var/log/neko/ /tmp/runtime-$USERNAME; \
chown -R $USERNAME:$USERNAME /home/$USERNAME; \
#
# clean up
@ -130,9 +129,12 @@ COPY .docker/base/intel/add-render-group.sh /usr/bin/add-render-group.sh
# set default envs
ENV USER=$USERNAME
ENV DISPLAY=:99.0
ENV PULSE_SERVER=unix:/tmp/pulseaudio.socket
ENV XDG_RUNTIME_DIR=/tmp/runtime-$USERNAME
ENV NEKO_PASSWORD=neko
ENV NEKO_PASSWORD_ADMIN=admin
ENV NEKO_BIND=:8080
ENV NEKO_HWENC=VAAPI
ENV RENDER_GID=
#

View File

@ -1,10 +1,62 @@
ARG UBUNTU_RELEASE=20.04
ARG CUDA_VERSION=11.2.2
ARG CUDA_VERSION=11.4.3
ARG VIRTUALGL_VERSION=3.1
ARG GSTREAMER_VERSION=1.20
#
# STAGE 0: Build gstreamer with nvidia plugins.
#
FROM ubuntu:${UBUNTU_RELEASE} AS gstreamer
ARG GSTREAMER_VERSION
#
# install dependencies
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
# Install essentials
curl build-essential ca-certificates git \
# Install pip and ninja
python3-pip python-gi-dev ninja-build \
# Install build deps
autopoint autoconf automake autotools-dev libtool gettext bison flex gtk-doc-tools \
# Install libraries
librtmp-dev \
libvo-aacenc-dev \
libtool-bin \
libgtk2.0-dev \
libgl1-mesa-dev \
libopus-dev \
libpulse-dev \
libssl-dev \
libx264-dev \
libvpx-dev; \
# Install meson
pip3 install meson; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
#
# build gstreamer
RUN set -eux; \
git clone --depth 1 --branch $GSTREAMER_VERSION https://gitlab.freedesktop.org/gstreamer/gstreamer.git /gstreamer/src; \
cd /gstreamer/src; \
mkdir -p /opt/gstreamer; \
meson --prefix /opt/gstreamer \
-Dgpl=enabled \
-Dugly=enabled \
-Dgst-plugins-ugly:x264=enabled \
build; \
ninja -C build; \
meson install -C build;
#
# STAGE 1: SERVER
#
FROM golang:1.18-bullseye as server
FROM golang:1.20-bullseye as server
WORKDIR /src
#
@ -30,12 +82,12 @@ RUN set -eux; apt-get update; \
#
# build server
COPY server/ .
RUN go get -v -t -d . && go build -o bin/neko cmd/neko/main.go
RUN ./build
#
# STAGE 2: CLIENT
#
FROM node:14-bullseye-slim as client
FROM node:18-bullseye-slim as client
WORKDIR /src
#
@ -51,13 +103,13 @@ RUN npm run build
#
# STAGE 3: RUNTIME
#
FROM nvcr.io/nvidia/cudagl:${CUDA_VERSION}-runtime-ubuntu${UBUNTU_RELEASE} as runtime
FROM nvidia/cuda:${CUDA_VERSION}-runtime-ubuntu${UBUNTU_RELEASE} as runtime
ARG UBUNTU_RELEASE
ARG CUDA_VERSION
ARG VIRTUALGL_VERSION
# Make all NVIDIA GPUs visible by default
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_VISIBLE_DEVICES all
# All NVIDIA driver capabilities should preferably be used, check `NVIDIA_DRIVER_CAPABILITIES` inside the container if things do not work
ENV NVIDIA_DRIVER_CAPABILITIES all
@ -75,20 +127,55 @@ ARG USERNAME=neko
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN set -eux; \
dpkg --add-architecture i386; \
apt-get update; \
apt-get install -y --no-install-recommends \
# opengl base: https://gitlab.com/nvidia/container-images/opengl/-/blob/ubuntu20.04/base/Dockerfile
libxau6 libxau6:i386 \
libxdmcp6 libxdmcp6:i386 \
libxcb1 libxcb1:i386 \
libxext6 libxext6:i386 \
libx11-6 libx11-6:i386 \
# opengl runtime: https://gitlab.com/nvidia/container-images/opengl/-/blob/ubuntu20.04/glvnd/runtime/Dockerfile
libglvnd0 libglvnd0:i386 \
libgl1 libgl1:i386 \
libglx0 libglx0:i386 \
libegl1 libegl1:i386 \
libgles2 libgles2:i386 \
# hardware accleration utilities
libglu1 libglu1:i386 \
libvulkan-dev libvulkan-dev:i386 \
mesa-utils mesa-utils-extra \
mesa-va-drivers mesa-vulkan-drivers \
vainfo vdpauinfo; \
#
# install vulkan-utils or vulkan-tools depending on ubuntu release
if [ "${UBUNTU_RELEASE}" = "18.04" ]; then \
apt-get install -y --no-install-recommends vulkan-utils; \
else \
apt-get install -y --no-install-recommends vulkan-tools; \
fi; \
#
# create symlink for libnvrtc.so (needed for cudaconvert)
find /usr/local/cuda/lib64/ -maxdepth 1 -type l -name "*libnvrtc.so.*" -exec sh -c 'ln -sf {} /usr/local/cuda/lib64/libnvrtc.so' \;; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
#
# add cuda to ld path, for gstreamer cuda plugins
ENV LD_LIBRARY_PATH="/usr/lib/x86_64-linux-gnu:/usr/lib/i386-linux-gnu${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}:/usr/local/cuda/lib:/usr/local/cuda/lib64"
RUN set -eux; \
apt-get update; \
#
# install dependencies
apt-get install -y --no-install-recommends wget ca-certificates supervisor; \
apt-get install -y --no-install-recommends pulseaudio dbus-x11 xserver-xorg-video-dummy; \
apt-get install -y --no-install-recommends libcairo2 libxcb1 libxrandr2 libxv1 libopus0 libvpx6; \
#
# hardware acclerations utilities
apt-get install -y --no-install-recommends libgtk-3-bin mesa-utils mesa-utils-extra mesa-va-drivers mesa-vulkan-drivers libvulkan-dev libvulkan-dev:i386 vdpauinfo; \
#
# gst
apt-get install -y --no-install-recommends libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-pulseaudio; \
apt-get install -y --no-install-recommends libcairo2 libxcb1 libxrandr2 libxv1 libopus0 libvpx6 libx264-155 libvo-aacenc0 librtmp1; \
apt-get install -y --no-install-recommends libgtk-3-bin software-properties-common cabextract aptitude vim curl; \
#
# install fonts
apt-get install -y --no-install-recommends \
@ -108,19 +195,18 @@ RUN set -eux; \
adduser $USERNAME video; \
adduser $USERNAME pulse; \
#
# setup pulseaudio
mkdir -p /home/$USERNAME/.config/pulse/; \
echo "default-server=unix:/tmp/pulseaudio.socket" > /home/$USERNAME/.config/pulse/client.conf; \
#
# workaround for an X11 problem: http://blog.tigerteufel.de/?p=476
mkdir /tmp/.X11-unix; \
chmod 1777 /tmp/.X11-unix; \
chown $USERNAME /tmp/.X11-unix/; \
#
# make directories for neko
mkdir -p /etc/neko /var/www /var/log/neko; \
mkdir -p /etc/neko /var/www /var/log/neko \
/tmp/runtime-$USERNAME \
/home/$USERNAME/.config/pulse \
/home/$USERNAME/.local/share/xorg; \
chmod 1777 /var/log/neko; \
chown $USERNAME /var/log/neko/; \
chown $USERNAME /var/log/neko/ /tmp/runtime-$USERNAME; \
chown -R $USERNAME:$USERNAME /home/$USERNAME; \
#
# clean up
@ -128,18 +214,18 @@ RUN set -eux; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
#
# install and configure Vulkan manually
RUN set -eux; \
apt-get update; \
if [ "${UBUNTU_RELEASE}" = "18.04" ]; then apt-get install -y --no-install-recommends vulkan-utils; else apt-get install -y --no-install-recommends vulkan-tools; fi; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*; \
#
# configure vulkan
VULKAN_API_VERSION=$(dpkg -s libvulkan1 | grep -oP 'Version: [0-9|\.]+' | grep -oP '[0-9]+(\.[0-9]+)(\.[0-9]+)'); \
mkdir -p /etc/vulkan/icd.d/; \
# configure EGL and Vulkan manually
RUN VULKAN_API_VERSION=$(dpkg -s libvulkan1 | grep -oP 'Version: [0-9|\.]+' | grep -oP '[0-9]+(\.[0-9]+)(\.[0-9]+)') && \
# Configure EGL manually
mkdir -p /usr/share/glvnd/egl_vendor.d/ && \
echo "{\n\
\"file_format_version\" : \"1.0.0\",\n\
\"ICD\": {\n\
\"library_path\": \"libEGL_nvidia.so.0\"\n\
}\n\
}" > /usr/share/glvnd/egl_vendor.d/10_nvidia.json && \
# Configure Vulkan manually
mkdir -p /etc/vulkan/icd.d/ && \
echo "{\n\
\"file_format_version\" : \"1.0.0\",\n\
\"ICD\": {\n\
@ -150,7 +236,6 @@ RUN set -eux; \
#
# install VirtualGL and make libraries available for preload
ARG VIRTUALGL_VERSION=3.1
RUN set -eux; \
apt-get update; \
wget "https://sourceforge.net/projects/virtualgl/files/virtualgl_${VIRTUALGL_VERSION}_amd64.deb"; \
@ -180,10 +265,22 @@ COPY .docker/base/nvidia/entrypoint.sh /bin/entrypoint.sh
# set default envs
ENV USER=$USERNAME
ENV DISPLAY=:99.0
ENV PULSE_SERVER=unix:/tmp/pulseaudio.socket
ENV XDG_RUNTIME_DIR=/tmp/runtime-$USERNAME
ENV NEKO_PASSWORD=neko
ENV NEKO_PASSWORD_ADMIN=admin
ENV NEKO_BIND=:8080
#
# set gstreamer envs
ENV PATH="/opt/gstreamer/bin:${PATH}"
ENV LD_LIBRARY_PATH="/opt/gstreamer/lib/x86_64-linux-gnu${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
ENV PKG_CONFIG_PATH="/opt/gstreamer/lib/x86_64-linux-gnu/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"
#
# copy gstreamer from previous stage
COPY --from=gstreamer /opt/gstreamer /opt/gstreamer
#
# copy static files from previous stages
COPY --from=server /src/bin/neko /usr/bin/neko

View File

@ -1,5 +1,8 @@
#!/usr/bin/pulseaudio -nF
### Create virtual output device sink
load-module module-null-sink sink_name=audio_output sink_properties=device.description="Virtual\ Audio\ Output"
# Allow pulse audio to be accessed via TCP (from localhost only), to allow other users to access the virtual devices
load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket auth-anonymous=1

View File

@ -54,3 +54,14 @@ stdout_logfile=/var/log/neko/neko.log
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
redirect_stderr=true
[unix_http_server]
file=/var/run/supervisor.sock
chmod=0700
chown=root:root
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

View File

@ -0,0 +1,35 @@
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG SRC_URL="https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US"
#
# install firefox
RUN set -eux; apt-get update; \
apt-get install -y --no-install-recommends openbox \
xz-utils bzip2 libgtk-3-0 libdbus-glib-1-2; \
#
# fetch latest release
wget -O /tmp/firefox-setup.tar.bz2 "${SRC_URL}"; \
mkdir /usr/lib/firefox; \
tar -xjf /tmp/firefox-setup.tar.bz2 -C /usr/lib; \
rm -f /tmp/firefox-setup.tar.bz2; \
ln -s /usr/lib/firefox/firefox /usr/bin/firefox; \
#
# create a profile directory
mkdir -p /home/neko/.mozilla/firefox/profile.default/extensions; \
chown -R neko:neko /home/neko/.mozilla/firefox/profile.default; \
#
# clean up
apt-get --purge autoremove -y xz-utils bzip2; \
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
#
# copy configuation files
COPY supervisord.nvidia.conf /etc/neko/supervisord/firefox.conf
COPY neko.js /usr/lib/firefox/mozilla.cfg
COPY autoconfig.js /usr/lib/firefox/defaults/pref/autoconfig.js
COPY policies.json /usr/lib/firefox/distribution/policies.json
COPY --chown=neko profiles.ini /home/neko/.mozilla/firefox/profiles.ini
COPY openbox.xml /etc/neko/openbox.xml

View File

@ -0,0 +1,28 @@
[program:firefox]
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
command=/bin/entrypoint.sh /usr/bin/firefox
--no-remote
-P default
--display=%(ENV_DISPLAY)s
-setDefaultBrowser
-width 1280
-height 720
stopsignal=INT
autorestart=true
priority=800
user=%(ENV_USER)s
stdout_logfile=/var/log/neko/firefox.log
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
redirect_stderr=true
[program:openbox]
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
autorestart=true
priority=300
user=%(ENV_USER)s
stdout_logfile=/var/log/neko/openbox.log
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
redirect_stderr=true

View File

@ -1,7 +1,9 @@
ARG BASE_IMAGE=m1k1o/neko:nvidia-base
FROM $BASE_IMAGE
ARG SRC_URL="https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
# latest working version with EGL: 111.0.5563.146, revert when resolved
# 112.0.5615.49 fails: https://github.com/VirtualGL/virtualgl/issues/229
ARG SRC_URL="https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_111.0.5563.146-1_amd64.deb"
#
# install google chrome

View File

@ -15,6 +15,11 @@ RUN set -eux; apt-get update; \
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
#
# disable autolock
RUN kwriteconfig5 --file /home/neko/.config/kscreenlockerrc --group Daemon --key Autolock false; \
chown neko:neko /home/neko/.config/kscreenlockerrc
#
# copy configuation files
COPY supervisord.conf /etc/neko/supervisord/kde.conf

View File

@ -13,7 +13,7 @@ env:
PLATFORMS: linux/arm64,linux/arm/v7
jobs:
build-base:
build-client:
runs-on: ubuntu-latest
#
# do not run on forks
@ -23,6 +23,41 @@ jobs:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up node
uses: actions/setup-node@v3
with:
node-version: 18.x
-
name: Build client
run: |
cd client
npm install
npm run build
-
name: Upload client dist
uses: actions/upload-artifact@v3
with:
name: client-dist
path: client/dist
build-base:
runs-on: ubuntu-latest
#
# do not run on forks
#
if: github.repository_owner == 'm1k1o'
needs: [ build-client ]
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Download client dist
uses: actions/download-artifact@v3
with:
name: client-dist
path: client/dist
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1

View File

@ -69,6 +69,8 @@ jobs:
# Will build all images even if some fail.
matrix:
include:
- tag: firefox
dockerfile: Dockerfile.nvidia
- tag: brave
dockerfile: Dockerfile.nvidia
- tag: chromium

View File

@ -1,17 +1,22 @@
<template>
<div id="neko" :class="[!hideControls && side ? 'expanded' : '']">
<div id="neko" :class="[!videoOnly && side ? 'expanded' : '']">
<template v-if="!$client.supported">
<neko-unsupported />
</template>
<template v-else>
<main class="neko-main">
<div v-if="!hideControls" class="header-container">
<div v-if="!videoOnly" class="header-container">
<neko-header />
</div>
<div class="video-container">
<neko-video ref="video" :hideControls="hideControls" @control-attempt="controlAttempt" />
<neko-video
ref="video"
:hideControls="hideControls"
:extraControls="isEmbedMode"
@control-attempt="controlAttempt"
/>
</div>
<div v-if="!hideControls" class="room-container">
<div v-if="!videoOnly" class="room-container">
<neko-members />
<div class="room-menu">
<div class="settings">
@ -26,11 +31,11 @@
</div>
</div>
</main>
<neko-side v-if="!hideControls && side" />
<neko-side v-if="!videoOnly && side" />
<neko-connect v-if="!connected" />
<neko-about v-if="about" />
<notifications
v-if="!hideControls"
v-if="!videoOnly"
group="neko"
position="top left"
style="top: 50px; pointer-events: none"
@ -176,10 +181,32 @@
shakeKbd = false
get hideControls() {
get volume() {
const numberParam = parseFloat(new URL(location.href).searchParams.get('volume') || '1.0')
return Math.max(0.0, Math.min(!isNaN(numberParam) ? numberParam * 100 : 100, 100))
}
get isCastMode() {
return !!new URL(location.href).searchParams.get('cast')
}
get isEmbedMode() {
return !!new URL(location.href).searchParams.get('embed')
}
get hideControls() {
return this.isCastMode
}
get videoOnly() {
return this.isCastMode || this.isEmbedMode
}
@Watch('volume', { immediate: true })
onVolume(volume: number) {
this.$accessor.video.setVolume(volume)
}
@Watch('hideControls', { immediate: true })
onHideControls(enabled: boolean) {
if (enabled) {

View File

@ -76,5 +76,12 @@
about() {
this.$accessor.client.toggleAbout()
}
mounted() {
const default_lang = new URL(location.href).searchParams.get('lang')
if (default_lang && this.langs.includes(default_lang)) {
this.$i18n.locale = default_lang
}
}
}
</script>

View File

@ -21,6 +21,9 @@
@mouseup.stop.prevent="onMouseUp"
@mouseenter.stop.prevent="onMouseEnter"
@mouseleave.stop.prevent="onMouseLeave"
@touchmove.stop.prevent="onTouchHandler"
@touchstart.stop.prevent="onTouchHandler"
@touchend.stop.prevent="onTouchHandler"
/>
<div v-if="!playing && playable" class="player-overlay" @click.stop.prevent="playAndUnmute">
<i class="fas fa-play-circle" />
@ -30,17 +33,17 @@
</div>
<div ref="aspect" class="player-aspect" />
</div>
<ul v-if="!fullscreen" class="video-menu top">
<ul v-if="!fullscreen && !hideControls" class="video-menu top">
<li><i @click.stop.prevent="requestFullscreen" class="fas fa-expand"></i></li>
<li v-if="admin"><i @click.stop.prevent="openResolution" class="fas fa-desktop"></i></li>
<li :class="hideControls || 'request-control'">
<li v-if="!implicitHosting" :class="extraControls || 'extra-control'">
<i
:class="[hosted && !hosting ? 'disabled' : '', !hosted && !hosting ? 'faded' : '', 'fas', 'fa-keyboard']"
@click.stop.prevent="toggleControl"
/>
</li>
</ul>
<ul v-if="!fullscreen" class="video-menu bottom">
<ul v-if="!fullscreen && !hideControls" class="video-menu bottom">
<li v-if="hosting && (!clipboard_read_available || !clipboard_write_available)">
<i @click.stop.prevent="openClipboard" class="fas fa-clipboard"></i>
</li>
@ -106,12 +109,12 @@
}
}
&.request-control {
/* usually extra controls are only shown on mobile */
&.extra-control {
display: none;
}
@media (max-width: 768px) {
&.request-control {
&.extra-control {
display: inline-block;
}
}
@ -223,13 +226,15 @@
@Ref('resolution') readonly _resolution!: Resolution
@Ref('clipboard') readonly _clipboard!: Clipboard
// all controls are hidden (e.g. for cast mode)
@Prop(Boolean) readonly hideControls!: boolean
// extra controls are shown (e.g. for embed mode)
@Prop(Boolean) readonly extraControls!: boolean
private keyboard = GuacamoleKeyboard()
private observer = new ResizeObserver(this.onResize.bind(this))
private focused = false
private fullscreen = false
private startsMuted = true
private mutedOverlay = true
get admin() {
@ -361,7 +366,6 @@
onMutedChanged(muted: boolean) {
if (this._video && this._video.muted != muted) {
this._video.muted = muted
this.startsMuted = muted
if (!muted) {
this.mutedOverlay = false
@ -392,7 +396,20 @@
try {
await this._video.play()
} catch (err: any) {
this.$accessor.video.pause()
if (!this._video.muted) {
// video.play() can fail if audio is set due restrictive
// browsers autoplay policy -> retry with muted audio
try {
this.$accessor.video.setMuted(true)
this._video.muted = true
await this._video.play()
} catch (err: any) {
// if it still fails, we're not playing anything
this.$accessor.video.pause()
}
} else {
this.$accessor.video.pause()
}
}
}
@ -431,11 +448,6 @@
this._video.addEventListener('canplaythrough', () => {
this.$accessor.video.setPlayable(true)
if (this.autoplay) {
// start as muted due to restrictive browsers autoplay policy
if (this.startsMuted && (!document.hasFocus() || !this.$accessor.active)) {
this.$accessor.video.setMuted(true)
}
this.$nextTick(() => {
this.$accessor.video.play()
})
@ -679,6 +691,35 @@
}
}
onTouchHandler(e: TouchEvent) {
let first = e.changedTouches[0]
let type = ''
switch (e.type) {
case 'touchstart':
type = 'mousedown'
break
case 'touchmove':
type = 'mousemove'
break
case 'touchend':
type = 'mouseup'
break
default:
return
}
const simulatedEvent = new MouseEvent(type, {
bubbles: true,
cancelable: true,
view: window,
screenX: first.screenX,
screenY: first.screenY,
clientX: first.clientX,
clientY: first.clientY,
})
first.target.dispatchEvent(simulatedEvent)
}
onMouseDown(e: MouseEvent) {
if (!this.hosting) {
this.$emit('control-attempt', e)

View File

@ -6,5 +6,6 @@ Vue.use(VueI18n)
export const i18n = new VueI18n({
locale: 'en',
fallbackLocale: 'en',
messages,
})

View File

@ -2,10 +2,24 @@
## master branch
### New Features
- Added nvidia support for firefox.
- Added `?lang=<lang>` parameter to the URL, which will set the language of the interface (by @mbattista).
### Misc
- Git commit and tag are now included in the build when creating a docker image.
## [n.eko v2.8.0](https://github.com/m1k1o/neko/releases/tag/v2.8.0)
### New Features
- Added AV1 tag, metadata and pipeline. Unfortunately does not work yet, since the encoding is way too slow (by @mbattista).
- Added `m1k1o/neko:kde` tag as an alternative to `m1k1o/neko:xfce`.
- New VirtualGL version 3.1 was released, adding support for Chromium browsers to use Nvidia GPU acceleration!
- Added `?embed=1` parameter to the URL, which will hide the sidebar and the top bar, so that it can be embedded in other websites.
- Added `?volume=<0-1>` parameter to the URL, which will set the inital volume of the player (by @urbanekpj).
- Touch events are now supported on mobile devices (by @urbanekpj).
- Added NVENC support, hardware h264 encoding for Nvidia GPUs!
- Fixed an issue where `nvh264enc` did not send SPS and PPS NAL units (by @mbattista).
### Bugs
- Fixed TCP mux occasional freeze by adding write buffer to it.
@ -19,6 +33,10 @@
- Updated to go 1.19 and Node 18, removed go-events as dependency (by @mbattista).
- Added adaptive framerate which now streams in the framerate you selected from the dropdown.
- Improved chinese and korean characters support.
- Disabled autolock for kde, so that it does not lock the screen when you are not using it.
- Refactored autoplay, so that it will start playing audio, if it's allowed by the browser (by @urbanekpj).
- Renamed pulseaudio sink from `auto_null` to `audio_output`, because it was ignored by KDE.
- Pulseaudio is now configured using environment variables, so that users can mount `/home/neko` without losing audio configuration.
## [n.eko v2.7](https://github.com/m1k1o/neko/releases/tag/v2.7)

View File

@ -74,7 +74,7 @@ For images with VAAPI GPU hardware acceleration using intel drivers use:
- `ghcr.io/m1k1o/neko/intel-xfce:latest`
- `ghcr.io/m1k1o/neko/intel-kde:latest`
For images with Nvidia GPU hardware acceleration using EGL use:
For images with Nvidia GPU hardware acceleration using EGL (see example below) use:
- `ghcr.io/m1k1o/neko/nvidia-chromium:latest`
- `ghcr.io/m1k1o/neko/nvidia-google-chrome:latest`
@ -131,6 +131,17 @@ services:
- UDP is generally better for latency. But some networks block UDP so it is good to have TCP available as fallback.
- Still, using `NEKO_ICELITE=true` is recommended.
### Using turn servers instead of port forwarding
- If you don't want to use port forwarding, you can use turn servers.
- But you need to have your own turn server (e.g. [cotrun](https://github.com/coturn/coturn)) or have access to one.
- They are generally not free, because they require a lot of bandwidth.
- Please make sure that you correctly escape your turn server credentials in the environment variable or use aphostrophes.
```yaml
NEKO_ICESERVERS: '[{"urls": ["turn:<MY-COTURN-SERVER>:443?transport=udp", "turn:<MY-COTURN-SERVER>:443?transport=tcp", "turns:<MY-COTURN-SERVER>:443?transport=udp", "turns:<MY-COTURN-SERVER>:443?transport=tcp"], "credential": "<MY-COTURN-CREDENTIAL"}, {"urls": ["stun:stun.nextcloud.com:443"]}]'
```
### Want to customize and install own add-ons, set custom bookmarks?
- You would need to modify the existing policy file and mount it to your container.
- For Firefox, copy [this](https://github.com/m1k1o/neko/blob/master/.docker/firefox/policies.json) file, modify and mount it as: ` -v '${PWD}/policies.json:/usr/lib/firefox/distribution/policies.json'`
@ -164,7 +175,7 @@ services:
### Nvidia GPU acceleration
You need to have nvidia-docker installed, start the container with `--gpus all` flag and use images built for nvidia (see above).
You need to have [nvidia-docker](https://github.com/NVIDIA/nvidia-docker) installed, start the container with `--gpus all` flag and use images built for nvidia (see above).
```bash
docker run -d --gpus all \
@ -176,6 +187,8 @@ docker run -d --gpus all \
-e NEKO_EPR=56000-56100 \
-e NEKO_NAT1TO1=192.168.1.10 \
-e NEKO_ICELITE=1 \
-e NEKO_VIDEO_CODEC=h264 \
-e NEKO_HWENC=nvenc \
--shm-size=2gb \
--cap-add=SYS_ADMIN \
--name neko \
@ -202,6 +215,8 @@ services:
NEKO_PASSWORD_ADMIN: admin
NEKO_EPR: 56000-56100
NEKO_NAT1TO1: 192.168.1.10
NEKO_VIDEO_CODEC: h264
NEKO_HWENC: nvenc
deploy:
resources:
reservations:
@ -211,7 +226,15 @@ services:
capabilities: [gpu]
```
Note, currently only browser GPU acceleration is supported, not encoding.
- You can verify that GPU is available inside the container by running `docker exec -it neko nvidia-smi` command.
- You can verify that GPU is used for encoding by searching for `nvh264enc` in `docker logs neko` output.
- If you don'ŧ specify `NEKO_HWENC: nvenc` environment variable, CPU encoding will be used but GPU will still be available for browser rendering.
Broadcast pipeline is not hardware accelerated by default. You can use this pipeline created by [@evilalmus](https://github.com/m1k1o/neko/issues/276#issuecomment-1498362533).
```yaml
NEKO_BROADCAST_PIPELINE: "flvmux name=mux ! rtmpsink location={url} pulsesrc device={device} ! audio/x-raw,channels=2 ! audioconvert ! voaacenc ! mux. ximagesrc display-name={display} show-pointer=false use-damage=false ! video/x-raw,framerate=30/1 ! videoconvert ! queue ! video/x-raw,format=NV12 ! nvh264enc name=encoder preset=low-latency-hq gop-size=25 spatial-aq=true temporal-aq=true bitrate=2800 vbv-buffer-size=2800 rc-mode=6 ! h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,profile=high ! h264parse ! mux."
```
### Want to use VPN for your n.eko browsing?
- Check this out: https://github.com/m1k1o/neko-vpn
@ -230,6 +253,9 @@ Note, currently only browser GPU acceleration is supported, not encoding.
- Adding `?pwd=<password>` will prefill password.
- Adding `?usr=<display-name>` will prefill username.
- Adding `?cast=1` will hide all control and show only video.
- Adding `?embed=1` will hide most additional components and show only video.
- Adding `?volume=<0-1>` will set volume to given value.
- Adding `?lang=<language>` will set language to given value.
- e.g. `http(s)://<URL:Port>/?pwd=neko&usr=guest&cast=1`
### Screen size

View File

@ -25,7 +25,7 @@ nat1to1: <ip>
- Control protection means, users can gain control only if at least one admin is in the room.
- e.g. `false`
#### `NEKO_IMPLICIT_CONTROL`:
- If enabled members can gain control implicitly, they don't needd to request control.
- If enabled members can gain control implicitly, they don't need to request control.
- e.g. `false`
#### `NEKO_LOCKS`:
- Resources, that will be locked when starting, separated by whitespace.
@ -79,13 +79,14 @@ nat1to1: <ip>
- `gstreamer1.0-plugins-good`
- `gstreamer1.0-plugins-bad`
- `gstreamer1.0-plugins-ugly`
- e.g. `ximagesrc display-name=%s show-pointer=true use-damage=false ! video/x-raw,framerate=30/1 ! videoconvert ! queue ! video/x-raw,format=NV12 ! x264enc threads=4 bitrate=3500 key-int-max=60 vbv-buf-capacity=4000 byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream`
- e.g. `ximagesrc display-name=%s show-pointer=true use-damage=false ! video/x-raw,framerate=30/1 ! videoconvert ! queue ! video/x-raw,format=NV12 ! x264enc threads=4 bitrate=3500 key-int-max=60 vbv-buf-capacity=4000 byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline`
#### `NEKO_MAX_FPS`:
- The resulting stream frames per seconds should be capped *(0 for uncapped)*.
- e.g. `0`
#### `NEKO_HWENC`:
- Use hardware accelerated encoding, for now supported only `VAAPI`.
- e.g. `VAAPI`
- none *(default CPU encoding)*
- vaapi
- nvenc
### Audio
@ -167,7 +168,7 @@ Flags:
--cert string path to the SSL cert used to secure the neko server
--control_protection control protection means, users can gain control only if at least one admin is in the room
--cors strings list of allowed origins for CORS (default [*])
--device string audio device to capture (default "auto_null.monitor")
--device string audio device to capture (default "audio_output.monitor")
--display string XDisplay to capture (default ":99.0")
--epr string limits the pool of ephemeral ports that ICE UDP connections can allocate from (default "59000-59100")
--file_transfer_enabled enable file transfer feature (default false)

View File

@ -95,9 +95,9 @@ services:
! videoconvert
! queue
! video/x-raw,framerate=30/1,format=NV12
! v4l2h264enc extra-controls="controls,h264_profile=0,video_bitrate=1250000;"
! v4l2h264enc extra-controls="controls,h264_profile=1,video_bitrate=1250000;"
! h264parse config-interval=3
! video/x-h264,profile=baseline,stream-format=byte-stream
! video/x-h264,stream-format=byte-stream,profile=constrained-baseline
NEKO_VIDEO_CODEC: h264
```

View File

@ -210,3 +210,17 @@ Most likely you forgot to add `-cap-add=SYS_ADMIN` when using chromium-based bro
```
This error originates from browser, that it could not connect to dbus. This does not affect us and can be ignored.
### Broadcast pipeline not working with some ingest servers
See [related issue](https://github.com/m1k1o/neko/issues/276).
```
Could not connect to RTMP stream "'rtmp://<ingest-url>/live/<stream-key-removed> live=1'" for writing
```
Some ingest servers require `live=1` parameter in the URL (e.g. nginx-rtmp-module). Some do not and do not accept aphostrophes (e.g. owncast). You can try to change the pipeline to:
```yaml
NEKO_BROADCAST_PIPELINE: "flvmux name=mux ! rtmpsink location={url} pulsesrc device={device} ! audio/x-raw,channels=2 ! audioconvert ! voaacenc ! mux. ximagesrc display-name={display} show-pointer=false use-damage=false ! video/x-raw,framerate=28/1 ! videoconvert ! queue ! x264enc bframes=0 key-int-max=0 byte-stream=true tune=zerolatency speed-preset=veryfast ! mux."
```

View File

@ -1,24 +1,35 @@
#!/bin/bash
set -ex
#
# aborting if any command returns a non-zero value
set -e
BUILD_TIME=`date -u +'%Y-%m-%dT%H:%M:%SZ'`
#
# set git build variables if git exists
if git status > /dev/null 2>&1 && [ -z $GIT_COMMIT ] && [ -z $GIT_BRANCH ] && [ -z $GIT_DIRTY ];
if git status > /dev/null 2>&1 && [ -z $GIT_COMMIT ] && [ -z $GIT_BRANCH ] && [ -z $GIT_TAG ];
then
GIT_COMMIT=`git rev-parse --short HEAD`
GIT_BRANCH=`git rev-parse --symbolic-full-name --abbrev-ref HEAD`
GIT_TAG=`git tag --points-at $GIT_COMMIT | head -n 1`
GIT_DIRTY=`git diff-index --quiet HEAD -- || echo "✗-"`
GIT_COMMIT="${GIT_DIRTY}${GIT_COMMIT}"
fi
#
# load dependencies
go get -v -t -d .
#
# build server
go build \
-o bin/neko \
-ldflags "
-s -w
-X 'm1k1o/neko.buildDate=${BUILD_TIME}'
-X 'm1k1o/neko.gitCommit=${GIT_DIRTY}${GIT_COMMIT}'
-X 'm1k1o/neko.gitCommit=${GIT_COMMIT}'
-X 'm1k1o/neko.gitBranch=${GIT_BRANCH}'
-X 'm1k1o/neko.gitTag=${GIT_TAG}'
" \
cmd/neko/main.go;

View File

@ -5,6 +5,7 @@ import (
"strings"
"m1k1o/neko/internal/capture/gst"
"m1k1o/neko/internal/config"
"m1k1o/neko/internal/types/codec"
)
@ -52,7 +53,7 @@ func NewBroadcastPipeline(device string, display string, pipelineSrc string, url
return pipelineStr, nil
}
func NewVideoPipeline(rtpCodec codec.RTPCodec, display string, pipelineSrc string, fps int16, bitrate uint, hwenc string) (string, error) {
func NewVideoPipeline(rtpCodec codec.RTPCodec, display string, pipelineSrc string, fps int16, bitrate uint, hwenc config.HwEnc) (string, error) {
pipelineStr := " ! appsink name=appsinkvideo"
// if using custom pipeline
@ -68,7 +69,7 @@ func NewVideoPipeline(rtpCodec codec.RTPCodec, display string, pipelineSrc strin
switch rtpCodec.Name {
case codec.VP8().Name:
if hwenc == "VAAPI" {
if hwenc == config.HwEncVAAPI {
if err := gst.CheckPlugins([]string{"ximagesrc", "vaapi"}); err != nil {
return "", err
}
@ -138,35 +139,40 @@ func NewVideoPipeline(rtpCodec codec.RTPCodec, display string, pipelineSrc strin
return "", err
}
if hwenc == "VAAPI" {
vbvbuf := uint(1000)
if bitrate > 1000 {
vbvbuf = bitrate
}
if hwenc == config.HwEncVAAPI {
if err := gst.CheckPlugins([]string{"vaapi"}); err != nil {
return "", err
}
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! vaapih264enc rate-control=vbr bitrate=%d keyframe-period=180 quality-level=7 ! video/x-h264,stream-format=byte-stream"+pipelineStr, display, fps, bitrate)
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! vaapih264enc rate-control=vbr bitrate=%d keyframe-period=180 quality-level=7 ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate)
} else if hwenc == config.HwEncNVENC {
if err := gst.CheckPlugins([]string{"nvcodec"}); err != nil {
return "", err
}
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! nvh264enc name=encoder preset=2 gop-size=25 spatial-aq=true temporal-aq=true bitrate=%d vbv-buffer-size=%d rc-mode=6 ! h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate, vbvbuf)
} else {
// https://gstreamer.freedesktop.org/documentation/openh264/openh264enc.html?gi-language=c#openh264enc
// gstreamer1.0-plugins-bad
// openh264enc multi-thread=4 complexity=high bitrate=3072000 max-bitrate=4096000
if err := gst.CheckPlugins([]string{"openh264"}); err == nil {
pipelineStr = fmt.Sprintf(videoSrc+"openh264enc multi-thread=4 complexity=high bitrate=%d max-bitrate=%d ! video/x-h264,stream-format=byte-stream"+pipelineStr, display, fps, bitrate*1000, (bitrate+1024)*1000)
pipelineStr = fmt.Sprintf(videoSrc+"openh264enc multi-thread=4 complexity=high bitrate=%d max-bitrate=%d ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate*1000, (bitrate+1024)*1000)
break
}
// https://gstreamer.freedesktop.org/documentation/x264/index.html?gi-language=c
// gstreamer1.0-plugins-ugly
// video/x-raw,format=I420 ! x264enc bframes=0 key-int-max=60 byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream
// video/x-raw,format=I420 ! x264enc bframes=0 key-int-max=60 byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline
if err := gst.CheckPlugins([]string{"x264"}); err != nil {
return "", err
}
vbvbuf := uint(1000)
if bitrate > 1000 {
vbvbuf = bitrate
}
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! x264enc threads=4 bitrate=%d key-int-max=60 vbv-buf-capacity=%d byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream"+pipelineStr, display, fps, bitrate, vbvbuf)
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! x264enc threads=4 bitrate=%d key-int-max=60 vbv-buf-capacity=%d byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate, vbvbuf)
}
default:
return "", fmt.Errorf("unknown codec %s", rtpCodec.Name)

View File

@ -2,6 +2,7 @@ package config
import (
"m1k1o/neko/internal/types/codec"
"strings"
"github.com/pion/webrtc/v3"
"github.com/rs/zerolog/log"
@ -9,13 +10,21 @@ import (
"github.com/spf13/viper"
)
type HwEnc int
const (
HwEncNone HwEnc = iota
HwEncVAAPI
HwEncNVENC
)
type Capture struct {
// video
Display string
VideoCodec codec.RTPCodec
VideoHWEnc string // TODO: Pipeline builder.
VideoBitrate uint // TODO: Pipeline builder.
VideoMaxFPS int16 // TODO: Pipeline builder.
VideoHWEnc HwEnc // TODO: Pipeline builder.
VideoBitrate uint // TODO: Pipeline builder.
VideoMaxFPS int16 // TODO: Pipeline builder.
VideoPipeline string
// audio
@ -92,7 +101,7 @@ func (Capture) Init(cmd *cobra.Command) error {
// audio
//
cmd.PersistentFlags().String("device", "auto_null.monitor", "audio device to capture")
cmd.PersistentFlags().String("device", "audio_output.monitor", "audio device to capture")
if err := viper.BindPFlag("device", cmd.PersistentFlags().Lookup("device")); err != nil {
return err
}
@ -184,11 +193,19 @@ func (s *Capture) Set() {
log.Warn().Msg("you are using deprecated config setting 'NEKO_AV1=true', use 'NEKO_VIDEO_CODEC=av1' instead")
}
videoHWEnc := ""
if viper.GetString("hwenc") == "VAAPI" {
videoHWEnc = "VAAPI"
videoHWEnc := strings.ToLower(viper.GetString("hwenc"))
switch videoHWEnc {
case "":
fallthrough
case "none":
s.VideoHWEnc = HwEncNone
case "vaapi":
s.VideoHWEnc = HwEncVAAPI
case "nvenc":
s.VideoHWEnc = HwEncNVENC
default:
log.Warn().Str("hwenc", videoHWEnc).Msgf("unknown video hw encoder, using CPU")
}
s.VideoHWEnc = videoHWEnc
s.VideoBitrate = viper.GetUint("video_bitrate")
s.VideoMaxFPS = int16(viper.GetInt("max_fps"))

View File

@ -5,6 +5,7 @@ import (
"os"
"os/signal"
"runtime"
"strings"
"m1k1o/neko/internal/capture"
"m1k1o/neko/internal/config"
@ -25,7 +26,7 @@ const Header = `&34
/ |/ / _ \/ //_/ __ \ ) ( ')
/ /| / __/ ,< / /_/ / ( / )
/_/ |_/\___/_/|_|\____/ \(__)|
&1&37 nurdism/m1k1o &33%s v%s&0
&1&37 nurdism/m1k1o &33%s %s&0
`
var (
@ -35,13 +36,8 @@ var (
gitCommit = "dev"
//
gitBranch = "dev"
// Major version when you make incompatible API changes,
major = "2"
// Minor version when you add functionality in a backwards-compatible manner, and
minor = "7"
// Patch version when you make backwards-compatible bug fixes.
patch = "0"
//
gitTag = "dev"
)
var Service *Neko
@ -49,11 +45,9 @@ var Service *Neko
func init() {
Service = &Neko{
Version: &Version{
Major: major,
Minor: minor,
Patch: patch,
GitCommit: gitCommit,
GitBranch: gitBranch,
GitTag: gitTag,
BuildDate: buildDate,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
@ -69,11 +63,9 @@ func init() {
}
type Version struct {
Major string
Minor string
Patch string
GitCommit string
GitBranch string
GitTag string
BuildDate string
GoVersion string
Compiler string
@ -81,20 +73,25 @@ type Version struct {
}
func (i *Version) String() string {
return fmt.Sprintf("%s.%s.%s %s", i.Major, i.Minor, i.Patch, i.GitCommit)
version := i.GitTag
if version == "" || version == "dev" {
version = i.GitBranch
}
return fmt.Sprintf("%s@%s", version, i.GitCommit)
}
func (i *Version) Details() string {
return fmt.Sprintf(
"%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
fmt.Sprintf("Version %s.%s.%s", i.Major, i.Minor, i.Patch),
return "\n" + strings.Join([]string{
fmt.Sprintf("Version %s", i.String()),
fmt.Sprintf("GitCommit %s", i.GitCommit),
fmt.Sprintf("GitBranch %s", i.GitBranch),
fmt.Sprintf("GitTag %s", i.GitTag),
fmt.Sprintf("BuildDate %s", i.BuildDate),
fmt.Sprintf("GoVersion %s", i.GoVersion),
fmt.Sprintf("Compiler %s", i.Compiler),
fmt.Sprintf("Platform %s", i.Platform),
)
}, "\n") + "\n"
}
type Neko struct {