thinkcenter-obs: build v4l2loopback 0.15.4 from source (distro dkms fails on kernel 7.x); best-effort vcam; dpkg self-heal + re-verify-on-fail

This commit is contained in:
Samuel James 2026-09-03 16:03:27 +00:00
parent f789f7bd98
commit a08788e3df

View File

@ -69,6 +69,7 @@
vars:
ansible_become_pass: "{{ hostvars['localhost'].thinkcenter_become_pass }}"
obs_ppa_codename: noble # Ubuntu base for Mint 22.3 (NOT 'zena')
v4l2_version: "0.15.4" # source build — distro dkms 0.12.7 fails on kernel 7.x
tasks:
- name: "[safety] Confirm we are on thinkcenter"
ansible.builtin.assert:
@ -113,12 +114,16 @@
retries: 3
delay: 15
- name: "[apt] Install OBS Studio + virtual-cam + ffmpeg (retry on dpkg lock)"
- name: "[apt] Repair any half-configured dpkg state before installing"
ansible.builtin.command: dpkg --configure -a
register: dpkg_repair
changed_when: "'Setting up' in (dpkg_repair.stdout | default(''))"
failed_when: false
- name: "[apt] Install OBS Studio + ffmpeg (core — must succeed; retry on lock)"
ansible.builtin.apt:
name:
- obs-studio
- v4l2loopback-dkms
- v4l2loopback-utils
- ffmpeg
state: present
register: obs_install
@ -126,7 +131,83 @@
retries: 3
delay: 15
- name: "[vcam] Configure v4l2loopback module for the OBS virtual camera"
# -----------------------------------------------------------------------
# Virtual camera (v4l2loopback) — OPTIONAL / best-effort. The Ubuntu-packaged
# v4l2loopback-dkms (0.12.7) FAILS to build on kernel 7.x (upstream changed
# the v4l2_fh_add/del signature). So we DO NOT install that package. Instead
# we build v4l2loopback {{ v4l2_version }} from source, which supports the
# new kernel API. If anything here fails, we log and continue — OBS itself
# is already installed; only the "Start Virtual Camera" button is affected.
# -----------------------------------------------------------------------
- name: "[vcam] Ensure the broken distro dkms package is not installed"
ansible.builtin.apt:
name: v4l2loopback-dkms
state: absent
purge: true
register: vcam_dkms_removed
failed_when: false
- name: "[vcam] Install build prerequisites + v4l2loopback-utils (best-effort)"
ansible.builtin.apt:
name:
- build-essential
- "linux-headers-{{ ansible_kernel }}"
- v4l2loopback-utils
state: present
register: vcam_deps
failed_when: false
until: vcam_deps is succeeded
retries: 2
delay: 10
- name: "[vcam] Is a working v4l2loopback module already present for this kernel?"
ansible.builtin.command: "modinfo -k {{ ansible_kernel }} v4l2loopback"
register: vcam_modinfo
changed_when: false
failed_when: false
- name: "[vcam] Build + install v4l2loopback {{ v4l2_version }} from source (only if missing)"
when: vcam_modinfo.rc != 0
block:
- name: "[vcam] Fetch v4l2loopback source"
ansible.builtin.get_url:
url: "https://github.com/v4l2loopback/v4l2loopback/archive/refs/tags/v{{ v4l2_version }}.tar.gz"
dest: "/tmp/v4l2loopback-{{ v4l2_version }}.tar.gz"
mode: "0644"
register: v4l2_dl
until: v4l2_dl is succeeded
retries: 3
delay: 10
- name: "[vcam] Extract source"
ansible.builtin.unarchive:
src: "/tmp/v4l2loopback-{{ v4l2_version }}.tar.gz"
dest: /tmp
remote_src: true
- name: "[vcam] Build the kernel module (make)"
ansible.builtin.command:
cmd: make
chdir: "/tmp/v4l2loopback-{{ v4l2_version }}"
register: v4l2_make
changed_when: v4l2_make.rc == 0
- name: "[vcam] Install the module + utils (make install)"
ansible.builtin.command:
cmd: make install
chdir: "/tmp/v4l2loopback-{{ v4l2_version }}"
register: v4l2_makeinstall
changed_when: v4l2_makeinstall.rc == 0
- name: "[vcam] depmod so the new module is discoverable"
ansible.builtin.command: "depmod -a {{ ansible_kernel }}"
changed_when: true
rescue:
- name: "[vcam] Source build failed — record, do NOT fail the play"
ansible.builtin.debug:
msg: "v4l2loopback source build failed; OBS is installed but the Virtual Camera won't work until this is resolved. See /tmp/v4l2loopback-{{ v4l2_version }}."
- name: "[vcam] Configure v4l2loopback module options for the OBS virtual camera"
ansible.builtin.copy:
dest: /etc/modprobe.d/obs-v4l2loopback.conf
mode: "0644"
@ -134,32 +215,69 @@
options v4l2loopback devices=1 video_nr=10 card_label="OBS Virtual Camera" exclusive_caps=1
register: vcam_conf
- name: "[vcam] Load v4l2loopback now (non-fatal if module build pending a reboot)"
- name: "[vcam] Load v4l2loopback now (best-effort)"
community.general.modprobe:
name: v4l2loopback
state: present
register: vcam_load
failed_when: false
- name: "[verify] Query obs-studio package status (dpkg, not the GUI binary)"
ansible.builtin.command: dpkg-query -W -f='${Status} ${Version}' obs-studio
register: obs_pkg
changed_when: false
failed_when: false
# --- Verify, with automatic repair + re-verify on failure ---------------
- name: "[verify] Verify OBS (auto-repair + re-verify if it fails)"
block:
- name: "[verify] Query obs-studio package status (dpkg, not the GUI binary)"
ansible.builtin.command: dpkg-query -W -f='${Status} ${Version}' obs-studio
register: obs_pkg
changed_when: false
failed_when: false
- name: "[verify] obs binary present on PATH"
ansible.builtin.command: which obs
register: obs_bin
changed_when: false
failed_when: false
- name: "[verify] obs binary present on PATH"
ansible.builtin.command: which obs
register: obs_bin
changed_when: false
failed_when: false
- name: "[verify] Assert OBS installed"
ansible.builtin.assert:
that:
- "'install ok installed' in (obs_pkg.stdout | default(''))"
- obs_bin.rc == 0
fail_msg: "OBS Studio not installed. pkg='{{ obs_pkg.stdout | default('') }}', bin rc={{ obs_bin.rc }}"
success_msg: "OBS Studio installed."
- name: "[verify] Assert OBS installed"
ansible.builtin.assert:
that:
- "'install ok installed' in (obs_pkg.stdout | default(''))"
- obs_bin.rc == 0
fail_msg: "OBS verify failed. pkg='{{ obs_pkg.stdout | default('') }}', bin rc={{ obs_bin.rc }}"
success_msg: "OBS Studio installed."
rescue:
- name: "[reverify] Repair dpkg + reinstall OBS, then re-verify"
block:
- name: "[reverify] dpkg --configure -a"
ansible.builtin.command: dpkg --configure -a
failed_when: false
changed_when: false
- name: "[reverify] apt-get install -f (fix broken deps)"
ansible.builtin.command: apt-get -y -f install
failed_when: false
changed_when: false
- name: "[reverify] Reinstall OBS + ffmpeg"
ansible.builtin.apt:
name: [obs-studio, ffmpeg]
state: present
register: obs_reinstall
until: obs_reinstall is succeeded
retries: 3
delay: 15
- name: "[reverify] Re-query package + binary"
ansible.builtin.shell: "dpkg-query -W -f='${Status}' obs-studio; echo '|'; which obs || true"
register: obs_recheck
changed_when: false
- name: "[reverify] Assert OBS present after repair"
ansible.builtin.assert:
that:
- "'install ok installed' in obs_recheck.stdout"
- "'/obs' in obs_recheck.stdout"
fail_msg: "OBS still not installed after repair attempt: {{ obs_recheck.stdout }}"
success_msg: "OBS Studio installed (after auto-repair)."
- name: "[report] OBS summary"
ansible.builtin.debug: