1
0
Fork 0

Final experiments with Voctomix

experiments
Ambrose Chua 2020-02-03 22:04:12 +08:00
parent 3dbc68cc4c
commit a4e4d8f4f1
26 changed files with 369 additions and 179 deletions

View File

@ -1,5 +1,5 @@
[recorders:children]
testgroup
[recorders]
#pricklypear
user@10.20.0.117 room_id=test
#voctomix_sources="[ { 'name': 'audio', 'kind': 'tcp', 'volume': '1.0' }, { 'name': 'cam1', 'kind': 'v4l2', 'device': '/dev/v4l/by-id/usb-Creative_Labs_VF0470_Live__Cam_Notebook-video-index0', 'width': '640', 'height': '480', 'framerate': '30/1' }, { 'name': 'slides', 'kind': 'v4l2', 'device': '/dev/v4l/by-id/usb-VXIS_Inc_ACASIS-video-index0', 'width': '1280', 'height': '720', 'framerate': '30/1' } ]"
[testgroup]
user@10.10.2.5 room_id=test

View File

@ -7,3 +7,6 @@ event:
voctomix:
version: "voctomix2"
# Meta
ansible_python_interpreter: auto

View File

@ -2,22 +2,15 @@
room_id: unknown
# Disable to block starting of voctocore and voctogui
voctocore_enabled: true
voctogui_enabled: true
# Default sources. Each subgroup can have its own sources
voctomix_sources:
- name: audio
- name: cam1
kind: tcp
volume: 1.0
- name: cam1
kind: v4l2
device: /dev/v4l/by-id/usb-Creative_Labs_VF0470_Live__Cam_Notebook-video-index0
width: 640
height: 480
framerate: 30/1
- name: slides
kind: v4l2
device: /dev/v4l/by-id/usb-VXIS_Inc_ACASIS-video-index0
width: 1280
height: 720
framerate: 30/1
kind: tcp
volume: 1.0

3
ansible/play Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
ansible-playbook -Kbf 1 -u user -i "$1" "$2"

View File

@ -0,0 +1,12 @@
---
- hosts: recorders
roles:
- role: recorder
- role: monitoring-client
tasks:
- name: reboot after setup
reboot:
vars:
voctocore_enabled: false
voctogui_enabled: false

View File

@ -0,0 +1,9 @@
---
- hosts: recorders
roles:
- role: recorder
- role: monitoring-client
vars:
voctocore_enabled: false
voctogui_enabled: false

View File

@ -2,3 +2,4 @@
- hosts: recorders
roles:
- role: recorder
- role: monitoring-client

View File

@ -0,0 +1,2 @@
---

View File

@ -0,0 +1,31 @@
# MANAGED BY ANSIBLE
# GDM configuration storage
#
# See /usr/share/gdm/gdm.schemas for a list of available options.
[daemon]
# Uncomment the line below to force the login screen to use Xorg
#WaylandEnable=false
# Enabling automatic login
AutomaticLoginEnable = true
AutomaticLogin = mixer
# Enabling timed login
# TimedLoginEnable = true
# TimedLogin = user1
# TimedLoginDelay = 10
[security]
[xdmcp]
[chooser]
[debug]
# Uncomment the line below to turn on debugging
# More verbose logs
# Additionally lets the X server dump core if it crashes
#Enable=true

View File

@ -1,14 +1,21 @@
---
- name: create artwork directory
file: dest=/opt/voctomix/artwork state=directory
owner=root group=root mode=0755
file:
dest: /opt/voctomix/artwork
state: directory
owner: root
group: root
mode: u=rwx,g=rx,o=rx
- name: copy backgrounds
copy: src=../../../artwork/{{ event.id }}/{{ item }}.png
dest=/opt/voctomix/artwork/
copy:
src: ../../../artwork/{{ event.id }}/{{ item }}.png
dest: /opt/voctomix/artwork/
owner: root
group: root
mode: u=rw,g=r,o=r
with_items:
- side-by-side-reverse
- side-by-side
- blank

View File

@ -1,7 +0,0 @@
---
- name: install general packages
apt:
state: latest
name:
- git

View File

@ -0,0 +1,10 @@
---
- name: generate hosts file
template:
src: etc-hosts.j2
dest: /etc/hosts
- name: set hostname to room_id
hostname:
name: "room-{{ room_id }}"

View File

@ -1,7 +1,9 @@
---
- include: general.yml
- include: user.yml
- include: hostname.yml
- include: packages.yml
- include: voctomix.yml
- include: voctocore.yml
- include: artwork.yml
#- include: voctogui.yml
- include: voctocore.yml
- include: voctogui.yml
- include: sources.yml

View File

@ -1,5 +1,12 @@
---
- name: installed packages required to be a mixer
- name: install general packages
apt:
state: latest
name:
- git
- name: install packages required to be a mixer
apt:
state: latest
name:
@ -8,8 +15,9 @@
- gstreamer1.0-plugins-good
- gstreamer1.0-plugins-ugly
- gstreamer1.0-alsa
- gstreamer1.0-pulseaudio
- gstreamer1.0-libav
- gstreamer1.0-tools
- gstreamer1.0-gl
- libgstreamer1.0-0
- python3
- python3-gi

View File

@ -0,0 +1,39 @@
---
- name: create cam1 systemd-unit
template: src="cam1.service.j2"
dest="/etc/systemd/system/voctomix-cam1.service"
mode=0644 owner=root group=root
- name: create slides systemd-unit
template: src="slides.service.j2"
dest="/etc/systemd/system/voctomix-slides.service"
mode=0644 owner=root group=root
- name: reload systemd daemon
command: systemctl daemon-reload
changed_when: false
- name: enable & (re)start voctomix-cam1.service
service: name=voctomix-cam1.service
enabled=yes
state=restarted
when: voctocore_enabled == true
- name: disable & stop voctomix-cam1.service
service: name=voctomix-cam1.service
enabled=no
state=stopped
when: voctocore_enabled != true
- name: enable & (re)start voctomix-slides.service
service: name=voctomix-slides.service
enabled=yes
state=restarted
when: voctocore_enabled == true
- name: disable & stop voctomix-slides.service
service: name=voctomix-slides.service
enabled=no
state=stopped
when: voctocore_enabled != true

View File

@ -0,0 +1,51 @@
---
- name: create mixer group
group:
name: mixer
- name: create mixer user with password mixer
user:
name: mixer
group: mixer
comment: Mixer
shell: /bin/bash
password: $6$8tFX.bXNC4348gTR$8e33nlbdydXVvFZ0VmaN9Y7H5HjMduu1Z4Ofjh13PhRFGLJ6ojubsHh1SuLZSHWzWMeUxIPEyVX6VH.UaCZe8/
- name: enable gdm autologin to mixer user
copy:
src: gdm.conf
dest: /etc/gdm3/daemon.conf
owner: root
group: root
mode: u=rw,g=r,o=r
- name: check sleep settings
command:
cmd: /usr/bin/gsettings get org.gnome.desktop.session idle-delay
become: yes
become_user: mixer
register: idle_delay_setting
changed_when: false
- name: prevent mixer from sleeping
command:
cmd: "{{ item }}"
environment:
# Required only when setting gsettings
DBUS_SESSION_BUS_ADDRESS: unix:path=/run/user/1001/bus
with_items:
- /usr/bin/gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'nothing'
- /usr/bin/gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type 'nothing'
- /usr/bin/gsettings set org.gnome.settings-daemon.plugins.power idle-dim false
- /usr/bin/gsettings set org.gnome.settings-daemon.plugins.power power-button-action 'nothing'
- /usr/bin/gsettings set org.gnome.desktop.lockdown disable-lock-screen true
- /usr/bin/gsettings set org.gnome.desktop.lockdown disable-log-out true
- /usr/bin/gsettings set org.gnome.desktop.lockdown disable-printing true
- /usr/bin/gsettings set org.gnome.desktop.lockdown disable-print-setup true
- /usr/bin/gsettings set org.gnome.desktop.lockdown disable-save-to-disk true
- /usr/bin/gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita-dark'
- /usr/bin/gsettings set org.gnome.desktop.session idle-delay 0
become: yes
become_user: mixer
when: "'uint32 0' not in idle_delay_setting.stdout"

View File

@ -19,10 +19,10 @@
service: name=voctomix-voctocore.service
enabled=yes
state=restarted
when: voctocore_enabled is defined
when: voctocore_enabled == true
- name: disable & stop voctomix-voctocore.service
service: name=voctomix-voctocore.service
enabled=no
state=stopped
when: voctocore_enabled is not defined
when: voctocore_enabled != true

View File

@ -18,10 +18,10 @@
service: name=voctomix-voctogui
enabled=yes
state=started
when: voctogui_enabled is defined
when: voctogui_enabled == true
- name: disable & stop voctogui service
service: name=voctomix-voctogui
enabled=no
state=stopped
when: voctogui_enabled is not defined
when: voctogui_enabled != true

View File

@ -1,17 +1,21 @@
---
# directories & code
- name: create voctomix directories
file: dest={{ item }} state=directory
owner=root group=root
file:
dest: "{{ item }}"
state: directory
owner: root
group: root
mode: u=rwx,g=rx,o=rx
with_items:
- /opt/voctomix/scripts/
- /opt/voctomix/release/
- name: checkout voctomix release
git: repo=https://github.com/voc/voctomix
dest=/opt/voctomix/release/
version={{ voctomix.version }}
force=yes
accept_hostkey=yes
git:
repo: https://github.com/voc/voctomix
dest: /opt/voctomix/release/
version: "{{ voctomix.version }}"
force: yes
accept_hostkey: yes

View File

@ -0,0 +1,15 @@
# MANAGED BY ANSIBLE
[Unit]
Description = voctomix source cam1
After=network.target
[Service]
Type = simple
ExecStart = gst-launch-1.0 -v v4l2src device=/dev/v4l/by-id/usb-Creative_Labs_VF0470_Live__Cam_Notebook-video-index0 ! image/jpeg,width=640,height=480,framerate=30/1 ! jpegparse ! jpegdec ! videoscale ! videoconvert ! video/x-raw,format=I420,width=1280,height=720,framerate=30/1,pixel-aspect-ratio=1/1,interlace-mode=progressive ! queue ! mux. alsasrc device=hw:CARD=Notebook ! audio/x-raw,format=S16LE,rate=8000,channels=1 ! audioconvert mix-matrix="<<(float)1.0>, <(float)1.0>, <(float)0.0>, <(float)0.0>>" ! audioresample ! audio/x-raw,format=S16LE,rate=48000,channels=4 ! queue ! mux. matroskamux name=mux ! tcpclientsink host=localhost port=10000
Restart = always
RestartSec = 1s
StartLimitInterval = 0
[Install]
WantedBy = multi-user.target

View File

@ -0,0 +1,4 @@
127.0.0.1 localhost room-{{ room_id }}
::1 localhost ip6-localhost ip6-loopbac room-{{ room_id }}
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

View File

@ -0,0 +1,15 @@
# MANAGED BY ANSIBLE
[Unit]
Description = voctomix source slides
After=network.target
[Service]
Type = simple
ExecStart = gst-launch-1.0 -v v4l2src device=/dev/v4l/by-id/usb-VXIS_Inc_ACASIS-video-index0 ! image/jpeg,width=1280,height=720,framerate=30/1 ! jpegparse ! jpegdec ! videoscale ! videoconvert ! video/x-raw,format=I420,width=1280,height=720,framerate=30/1,pixel-aspect-ratio=1/1,interlace-mode=progressive ! queue ! mux. alsasrc device=hw:CARD=ACASIS ! audio/x-raw,format=S16LE,rate=48000,channels=2 ! audioconvert mix-matrix="<<(float)0.0, (float)0.0>, <(float)0.0, (float)0.0>, <(float)1.0, (float)0.0>, <(float)0.0, (float)1.0>>" ! audio/x-raw,format=S16LE,rate=48000,channels=4 ! queue ! mux. matroskamux name=mux ! tcpclientsink host=localhost port=10001
Restart = always
RestartSec = 1s
StartLimitInterval = 0
[Install]
WantedBy = multi-user.target

View File

@ -1,12 +1,14 @@
[mix]
videocaps=video/x-raw,format=I420,width=1920,height=1080,framerate=30/1,pixel-aspect-ratio=1/1,interlace-mode=progressive
audiocaps=audio/x-raw,format=S16LE,channels=2,layout=interleaved,rate=48000
#videocaps=video/x-raw,format=I420,width=1920,height=1080,framerate=30/1,pixel-aspect-ratio=1/1,interlace-mode=progressive
videocaps=video/x-raw,format=I420,width=1280,height=720,framerate=30/1,pixel-aspect-ratio=1/1,interlace-mode=progressive
audiocaps=audio/x-raw,format=S16LE,channels=4,layout=interleaved,rate=48000
sources={{ voctomix_sources | map(attribute = 'name') | join(',') }}
; livesources={{ (voctomix_sources | last).name }}
backgrounds=side-by-side,side-by-side-reverse
livesources={{ voctomix_sources | map(attribute = 'name') | join(',') }}
#backgrounds=side-by-side,side-by-side-reverse
# TODO: convert the rest into loops
{% for source in voctomix_sources %}
{% if source.kind == "v4l2" %}
[source.{{ source.name }}]
@ -20,206 +22,138 @@ format=YUY2
{% if source.kind == "tcp" %}
[source.{{ source.name }}]
kind=tcp
scan=progressive
volume={{ source.volume }}
{% if source.name == "cam1" %}
audio.presenter=0+1
#audio.slides=2+3
{% endif %}
{% if source.name == "slides" %}
#audio.presenter=0+1
audio.slides=2+3
{% endif %}
{% endif %}
{% endfor %}
[source.side-by-side]
#[source.side-by-side]
[source.background]
kind=img
imguri=file:///opt/voctomix/artwork/side-by-side.png
composites=fs-sbs
scan=progressive
file=/opt/voctomix/artwork/side-by-side.png
#composites=fs-sbs
[source.side-by-side-reverse]
kind=img
imguri=file:///opt/voctomix/artwork/side-by-side-reverse.png
composites=|fs-sbs
#[source.side-by-side-reverse]
#kind=img
#file=/opt/voctomix/artwork/side-by-side-reverse.png
#composites=|fs-sbs
[previews]
; disable if ui & server run on the same computer and can exchange uncompressed video frames
# disable if ui & server run on the same computer and can exchange uncompressed video frames
enabled=false
deinterlace=false
live=true
videocaps=video/x-raw,width=1024,height=576,framerate=30/1
{% if voctomix_vaapi is defined and voctomix_vaapi %}
# check `vainfo`!
vaapi=h264
{% endif %}
#live=true
#videocaps=video/x-raw,width=1024,height=576,framerate=30/1
#vaapi=h264
[blinder]
enabled=false
#[blinder]
#enabled=true
[source.blinder]
kind=img
imguri=file:///opt/voctomix/artwork/blank.png
#[source.blinder]
#kind=img
#file=/opt/voctomix/artwork/blank.png
[overlay]
path = /opt/voctomix/overlays
#[overlay]
#path = /opt/voctomix/overlays
[mirrors]
; disable if not needed
enabled = true
enabled=true
[composites]
; fullscreen source A (B is full transparent)
fs.a = *
fs.b = *
fs.alpha-b = 0
fs.noswap = true
; fullscreen source A (facing picture-in-picture)
fs-pip.a = *
fs-pip.b = 0.86/0.85 0.0
fs-pip.alpha-b = 0
fs-pip.inter = true
fs-pip.mirror = true
; fullscreen source A (facing side-by-side)
fs-sbs.a = *
fs-sbs.b = 1.0/0.5 0.0
fs-sbs.alpha-b = 0
fs-sbs.inter = true
; fullscreen source A (facing side-by-side-preview)
fs-lec.a = *
fs-lec.b = 1.0 0.0
fs-lec.alpha-b = 0
fs-lec.crop-b = 0.31/0
fs-lec.inter = true
fs-lec.mirror = true
; picture-in-picture (fullscreen source A with B as small overlay)
pip.a = *
pip.b = 0.73/0.72 0.26
pip.noswap = true
pip.mirror = true
; side-by-side (source A at left and B at right side)
sbs.a = 0.008/0.25 0.49
sbs.b = 0.503/0.25 0.49
; side-by-side-preview (source A bigger and B smaller and cropped beside)
lec.a = 0.006/0.01 0.75
lec.b = 0.60/0.42 0.56
lec.crop-b = 0.31/0
lec.mirror = true
; side-by-side-preview (source A bigger and B smaller and cropped beside)
lec_43.a = -0.125/0.0 1.0
lec_43.b = 0.60/0.42 0.56
lec_43.crop-a = 0.125/0
lec_43.crop-b = 0.31/0
lec_43.mirror = true
; fullscreen source B (overlapping A)
fs-b.a = *
fs-b.b = *
fs-b.noswap = true
; fullscreen source B (facing side-by-side)
fs-b-sbs.a = 0.0/0.5 0.0
fs-b-sbs.alpha-a = 0.0
fs-b-sbs.b = *
fs-b-sbs.inter = true
; fullscreen source B (facing side-by-side-preview)
fs-b-lec.a = 0.0/1.0 0.0
fs-b-lec.b = *
fs-b-lec.inter = true
fs-b-lec.mirror = true
; one-opon-the-other (like one-opon-the-other but overlapping)
oao.a = 0.3/0.2 0.4
oao.alpha-a = 0.5
oao.b = 0.2/0.3 0.6
oao.inter = true
oao.noswap = true
[transitions]
; list of transitions each one can be freely named and is a list of composites
; which will be morphed into an animation. Interpolation will be linear with two
; composites and B-Splines for more.
; unique name = ms, from / [... /] to
# unique name = ms, from / [... /] to
fs-fs = 750, fs / fs-b
fs-pip = 750, fs-pip / pip
fs-sbs = 750, fs-sbs / sbs
fs-b-pip = 750, fs-b / pip
fs-b-sbs = 750, fs-b-sbs / sbs
fs-lec = 750, fs-lec / lec
fs-b-lec = 750, fs-b-lec / lec
fs-lec_43 = 750, fs-lec / lec_43
fs-b-lec_43 = 750, fs-b-lec / lec_43
pip-pip = 750, pip / sbs / pip
sbs-sbs = 750, sbs / oao / sbs
_sbs-sbs = 750, ^sbs / ^oao / sbs
fs-lec = 750, fs / lec
fs-pip_ = 750, |fs-pip / |pip
fs-b-pip_ = 750, fs-b / |pip
fs-lec_ = 750, fs-lec / |lec
fs-lec_43_ = 750, fs-lec / |lec_43
fs-b-lec_ = 750, fs-b-lec / |lec
fs-b-lec_43_ = 750, fs-b-lec / |lec_43
pip-pip_ = 750, |pip / sbs / |pip
; default blending
; unique name = ms, from / [... /] to
# default blending
# unique name = ms, from / [... /] to
def = 750, * / *
[toolbar.sources.a]
buttons = cam1,slides
buttons = slides,cam1
slides.name = slides
slides.key = 1
slides.tip = Select source slides on channel A
cam1.name = cam1
cam1.key = F1
cam1.key = 2
cam1.tip = Select source cam1 on channel A
slides.name = slides
slides.key = F3
slides.tip = Select source slides on channel A
[toolbar.sources.b]
buttons = cam1,slides
cam1.name = cam1
cam1.key = 1
cam1.key = F1
cam1.tip = Select source cam1 on channel B
slides.name = slides
slides.key = 3
slides.tip = Select source slides on channel B
[toolbar.composites]
buttons = fs,sbs,lec
fs.name = FULL SCREEN
slides.name = slides
slides.key = F2
slides.tip = Select source slides on channel B
[toolbar.composites]
buttons = fs,lec
fs.name = FULL
fs.key = F5
fs.tip = Show channel A on full screen
sbs.name = SIDE BY SIDE
sbs.key = F6
sbs.tip = Put channel A beside channel B
lec.name = LECTURE
lec.key = F7
lec.key = F6
lec.tip = Put cropped channel B beside large channel A
[toolbar.mods]
buttons = mirror,ratio
mirror.name = MIRROR
mirror.key = F9
mirror.replace = lec->|lec
mirror.tip = Horizontally mirror composite\n(e.g. when speaker moves to the other side)
[toolbar.mods]
buttons = ratio
ratio.name = 4:3
ratio.replace = lec->lec_43
ratio.key = F10
ratio.key = F9
ratio.tip = Crop channel A to 4:3 ratio
[toolbar.mix]
buttons = retake,cut,trans
buttons = retake,trans
retake.name = RETAKE
retake.key = BackSpace
@ -235,6 +169,7 @@ trans.key = space
trans.tip = Use transition to cut preview composite to output
trans.expand = True
[toolbar.insert]
auto-off.name = AUTO-OFF
auto-off.key = o

View File

@ -1,14 +1,13 @@
#MANAGED BY ANSIBLE
# MANAGED BY ANSIBLE
[Unit]
Description = voctomix core
After=network.target
Conflicts=voctocore.service
[Service]
Type = notify
WorkingDirectory = /opt/voctomix/release
ExecStart = /opt/voctomix/release/voctocore/voctocore.py --ini-file /opt/voctomix/voctocore-config.ini -vv
ExecStart = /opt/voctomix/release/voctocore/voctocore.py --ini-file /opt/voctomix/voctocore-config.ini -v
Restart = always
RestartSec = 1s
StartLimitInterval = 0

View File

@ -0,0 +1,32 @@
[server]
host=localhost
[previews]
width=280
use=true
[videodisplay]
# Use VAAPI's renderer, requires VAAPI-based previews
#system=vaapi
# Use OpenGL - most performant
system=gl
# Use XVideo - oldschool
#system=xv
# Use simple X-Images - least performant
#system=x
[mainwindow]
#width=800
#height=600
forcefullscreen=true
vumeter=all
[audio]
#forcevolumecontrol=true
#play=true
[toolbar]
close=false
ports=true
queues=true
fullscreen=false

View File

@ -0,0 +1,22 @@
# MANAGED BY ANSIBLE
[Unit]
Description = voctomix gui
After=network.target
[Service]
Type = simple
WorkingDirectory = /opt/voctomix/release
ExecStart = /opt/voctomix/release/voctogui/voctogui.py --ini-file /opt/voctomix/voctogui-config.ini -v
Restart = always
RestartSec = 1s
StartLimitInterval = 0
User=mixer
Group=mixer
Environment="DISPLAY=:0"
Environment="GTK_THEME=Adwaita:dark"
#Environment="GDK_SCALE=1"
[Install]
WantedBy = multi-user.target