Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
with:
persist-credentials: false
- run: rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --component clippy --no-self-update
- run: cargo clippy --all-targets --locked -- -D warnings
- run: cargo clippy --workspace --all-targets --locked -- -D warnings

test:
needs: changes
Expand All @@ -79,7 +79,7 @@ jobs:
with:
persist-credentials: false
- run: rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --no-self-update
- run: cargo test --locked
- run: cargo test --workspace --locked

# Builds and tests with the oldest Rust that Cargo.toml's rust-version claims.
msrv:
Expand All @@ -94,7 +94,7 @@ jobs:
msrv=$(sed -n 's/^rust-version = "\(.*\)"/\1/p' Cargo.toml)
test -n "$msrv"
rustup toolchain install "$msrv" --profile minimal --no-self-update
cargo "+$msrv" test --locked
cargo "+$msrv" test --workspace --locked

# The one check the main ruleset requires. Code changes need fmt, clippy, test and msrv to
# succeed; docs-only changes need them skipped. Anything else fails.
Expand Down
63 changes: 57 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ on:
- scripts/**
- Cargo.toml
- Cargo.lock
- crates/*/Cargo.toml
- README.md
- CHANGELOG.md
- LICENSE
Expand Down Expand Up @@ -115,13 +116,13 @@ jobs:
rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal
--component rustfmt --component clippy --no-self-update
- run: cargo fmt --check
- run: cargo clippy --all-targets --locked -- -D warnings
- run: cargo test --locked
- run: cargo clippy --workspace --all-targets --locked -- -D warnings
- run: cargo test --workspace --locked
- run: |
msrv=$(sed -n 's/^rust-version = "\(.*\)"/\1/p' Cargo.toml)
test -n "$msrv"
rustup toolchain install "$msrv" --profile minimal --no-self-update
cargo "+$msrv" test --locked
cargo "+$msrv" test --workspace --locked

# One job per package format and architecture: a failure reruns only that job.
binary:
Expand Down Expand Up @@ -200,7 +201,7 @@ jobs:
mkdir dist
# no rebuild: package the binary from the binary job (artifacts drop the mode)
chmod +x target/release/obsbot4linux
cargo deb --no-build --deb-revision "" -o "dist/obsbot4linux_${ver}_$DEB.deb"
cargo deb -p obsbot4linux --no-build --deb-revision "" -o "dist/obsbot4linux_${ver}_$DEB.deb"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: dist-deb-${{ matrix.arch }}
Expand Down Expand Up @@ -237,7 +238,7 @@ jobs:
ver=$VER
mkdir dist
chmod +x target/release/obsbot4linux
cargo generate-rpm -o "dist/obsbot4linux-$ver-1.$ARCH.rpm"
cargo generate-rpm -p crates/obsbot4linux -o "dist/obsbot4linux-$ver-1.$ARCH.rpm"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: dist-rpm-${{ matrix.arch }}
Expand Down Expand Up @@ -276,10 +277,60 @@ jobs:
path: dist/*
if-no-files-found: error

# Lists the files of every package and compares the list with packaging/contents.txt, so that
# a change to what a package holds shows up in review. A release needs it too.
contents:
needs: [version, binary, deb, rpm, arch]
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: dist
pattern: dist-*
merge-multiple: true
- run: sudo apt-get install -y --no-install-recommends libarchive-tools
# [profile.release] strip = true must reach every package (cargo ignores a member
# manifest's profile, and the file list alone would not show it)
- name: The packaged binaries are stripped
run: |
for pkg in dist/obsbot4linux*; do
case $pkg in
*.deb) bsdtar -xOf "$pkg" 'data.tar*' > payload ;;
*) cp "$pkg" payload ;;
esac
bin=$(bsdtar -tf payload | grep -E '(usr/bin|-linux)/obsbot4linux$')
bsdtar -xOf payload "$bin" > obsbot4linux.bin
info=$(file -b obsbot4linux.bin)
echo "$pkg: $info"
case $info in
*', stripped') ;;
*) echo "::error::$pkg ships an unstripped binary"; exit 1 ;;
esac
done
rm -f payload obsbot4linux.bin
- name: Compare the package contents
env:
VER: ${{ needs.version.outputs.ver }}
run: |
scripts/package-contents.sh dist "$VER" > contents.txt
cat contents.txt
diff -u packaging/contents.txt contents.txt
# the list itself, also when it differs, to update packaging/contents.txt from
- if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: package-contents
path: contents.txt
if-no-files-found: error

# Tags only: a pull request builds the packages above and publishes nothing.
release:
if: startsWith(github.ref, 'refs/tags/')
needs: [binary, deb, rpm, arch]
needs: [binary, deb, rpm, arch, contents]
runs-on: ubuntu-22.04
timeout-minutes: 15
permissions:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ All notable changes to OBSBot4Linux. The format follows

- The repository moved to github.com/hellwand/obsbot4linux on 2026-11-12; the old address redirects (the link change itself landed in #109).
- README and package text now say "most settings OBSBOT Center offers" and link `docs/center-parity.md` for the gaps; they also state the glibc 2.34 floor, how to switch to the socket units while the widget's daemon runs, to restart the daemon after an upgrade (socket users: `systemctl --user restart obsbot4linux.service`; a daemon started by `watch` ends with the shell's unit), that `zoom F --speed S` and `zoom stop` leave the AI mode alone, the `device busy` window of the on-air probe on uvcvideo up to 6.16, and the order of auto and manual image controls (#121).
- The source is a cargo workspace now: `crates/obsbot-device` holds the camera access,
`crates/obsbot4linux` the CLI and the daemon. The program, its output and the packages do not
change.

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Every change goes through an issue and a pull request, also the maintainer's:

1. Open an issue: what is wrong or missing, how to reproduce it, which camera and firmware.
2. Open a pull request against `main` whose description starts with `Fixes #<issue>`.
3. CI must be green (`cargo fmt --check`, `cargo clippy --all-targets --locked -- -D warnings`,
`cargo test`, and `cargo test` again with the `rust-version` from `Cargo.toml`).
3. CI must be green (`cargo fmt --check`, `cargo clippy --workspace --all-targets --locked -- -D warnings`,
`cargo test --workspace`, and `cargo test --workspace` again with the `rust-version` from `Cargo.toml`).
Changes that only touch docs (Markdown files, `LICENSE`, `docs/`) skip those four; the
`required` check still reports. No changelog entry is enforced per pull request; the release
tag needs its `CHANGELOG.md` section.
Expand Down
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 8 additions & 40 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,57 +1,25 @@
[package]
name = "obsbot4linux"
[workspace]
resolver = "3"
members = ["crates/obsbot-device", "crates/obsbot4linux"]

[workspace.package]
version = "0.13.2"
edition = "2024"
rust-version = "1.88"
description = "Control OBSBOT webcams on Linux from the console and the DMS widget"
authors = ["Thomas Kroll"]
license = "GPL-3.0-or-later"
repository = "https://github.com/hellwand/obsbot4linux"
homepage = "https://github.com/hellwand/obsbot4linux"
readme = "README.md"
publish = false

[lib]
name = "obsbot4linux"
path = "src/lib.rs"

[[bin]]
name = "obsbot4linux"
path = "src/main.rs"

[dependencies]
[workspace.dependencies]
obsbot-device = { path = "crates/obsbot-device" }
clap = { version = "4", features = ["derive"] }
nix = { version = "0.31", features = ["fs", "ioctl"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
hex = "0.4"

[profile.release]
strip = true

[dev-dependencies]
hex = "0.4"

[package.metadata.deb]
maintainer = "Thomas Kroll <t.kroll@outlook.com>"
section = "video"
extended-description = "Most settings OBSBOT Center offers, from the console and from the DMS bar widget.\nWhat is missing: https://github.com/hellwand/obsbot4linux/blob/main/docs/center-parity.md\nThe obsbot4linux daemon (systemd user socket) owns the camera state."
depends = "$auto"
license-file = ["LICENSE", "0"]
assets = [
["target/release/obsbot4linux", "usr/bin/", "755"],
["packaging/systemd/obsbot4linux.service", "usr/lib/systemd/user/", "644"],
["packaging/systemd/obsbot4linux.socket", "usr/lib/systemd/user/", "644"],
["README.md", "usr/share/doc/obsbot4linux/", "644"],
["CHANGELOG.md", "usr/share/doc/obsbot4linux/", "644"],
]

[package.metadata.generate-rpm]
assets = [
{ source = "target/release/obsbot4linux", dest = "/usr/bin/obsbot4linux", mode = "755" },
{ source = "packaging/systemd/obsbot4linux.service", dest = "/usr/lib/systemd/user/obsbot4linux.service", mode = "644" },
{ source = "packaging/systemd/obsbot4linux.socket", dest = "/usr/lib/systemd/user/obsbot4linux.socket", mode = "644" },
{ source = "README.md", dest = "/usr/share/doc/obsbot4linux/README.md", mode = "644", doc = true },
{ source = "CHANGELOG.md", dest = "/usr/share/doc/obsbot4linux/CHANGELOG.md", mode = "644", doc = true },
{ source = "LICENSE", dest = "/usr/share/licenses/obsbot4linux/LICENSE", mode = "644" },
]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ it does not arm the flag but consumes one that a recall or `0x6604` armed earlie
goes Static on arrival; afterwards tracking may stay suspended, since the view's actions name no
AI mode, as with `startup go`. Not seen so far: tracking stayed on after a `zone view go` in AI normal. The flag part is still to be confirmed.

Adding a model: an entry in `MODELS` in `src/models.rs` (name, USB id, by-id and card name
Adding a model: an entry in `MODELS` in `crates/obsbot-device/src/registry.rs` (name, USB id, by-id and card name
patterns) makes it detected. Its commands and status decoding differ per camera and today exist
for the Tiny 2 Lite only; the plan is one module per model behind the same commands, once a
camera is at hand to capture and test (see [CONTRIBUTING.md](CONTRIBUTING.md)).
Expand Down
21 changes: 21 additions & 0 deletions crates/obsbot-device/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "obsbot-device"
description = "Camera access for obsbot4linux: transport, frame codec and the camera models"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
publish.workspace = true

[dependencies]
clap.workspace = true
nix.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true

[dev-dependencies]
hex.workspace = true
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions src/device.rs → crates/obsbot-device/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! number only. flock is advisory; streaming applications do not take it and are not held up.

use crate::error::{Error, Result};
use crate::models::{self, Model};
use crate::registry::{self, Model};
use nix::errno::Errno;
use nix::fcntl::{Flock, FlockArg};
use nix::{ioctl_read, ioctl_readwrite};
Expand Down Expand Up @@ -160,7 +160,7 @@ pub fn detect() -> Option<Detected> {
if let Ok(file) = File::open(&path)
&& let Some((card, caps)) = card_name(&file)
&& caps & V4L2_CAP_META_CAPTURE == 0
&& let Some(model) = models::from_card(&card)
&& let Some(model) = registry::from_card(&card)
{
return Some(Detected {
model,
Expand All @@ -176,7 +176,7 @@ pub fn detect() -> Option<Detected> {
fn first_by_id(mut links: Vec<PathBuf>) -> Option<Detected> {
links.sort();
links.into_iter().find_map(|device| {
let model = models::from_by_id(&device.file_name()?.to_string_lossy())?;
let model = registry::from_by_id(&device.file_name()?.to_string_lossy())?;
Some(Detected { model, device })
})
}
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions crates/obsbot-device/src/family/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later

//! Building blocks that are not tied to one camera model: the frame codec and the on-air probe.

pub mod frame;
pub mod streaming;
File renamed without changes.
15 changes: 9 additions & 6 deletions src/lib.rs → crates/obsbot-device/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
//! Control library for the OBSBOT Tiny 2 Lite.

pub mod camera;
pub mod commands;
pub mod device;
pub mod error;
pub mod frame;
pub mod models;
pub mod presets;
pub mod state;

pub mod family;
pub use family::{frame, streaming};

pub mod device;
pub mod registry;

pub mod commands;
pub mod presets;
pub mod status;
pub mod streaming;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading