Skip to content
Draft
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
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ A meeting recording and transcription app for Linux. Records microphone and syst
- **Device Hot-Plug**: Automatically detects when audio devices are connected/disconnected
- **Pause/Resume**: Pause recording during breaks without creating multiple files

## System Requirements

Quinoa works on modern Linux distributions. It explicitly requires **PipeWire** for audio capture.

### Ubuntu Compatibility

- **Ubuntu 22.10 and newer**: PipeWire is the default. Works out of the box.
- **Ubuntu 22.04 LTS**: Uses PulseAudio by default. You must enable PipeWire:
```bash
# Install PipeWire and compatibility layer
sudo apt install pipewire pipewire-pulse

# Enable and start the service
systemctl --user --now enable pipewire pipewire-pulse
```

## Architecture

```
Expand Down Expand Up @@ -89,6 +105,8 @@ sudo dnf install pipewire-devel
sudo apt install libpipewire-0.3-dev
```

> **Note**: If you are on Ubuntu 22.04, ensure you have enabled PipeWire as described in [System Requirements](#system-requirements).

### Building

```bash
Expand Down
48 changes: 48 additions & 0 deletions quinoa/compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Compatibility checks for system requirements."""

import os
import shutil
import subprocess
import sys


def is_linux() -> bool:
"""Check if running on Linux."""
return sys.platform.startswith("linux")


def is_pipewire_installed() -> bool:
"""Check if PipeWire is installed."""
return shutil.which("pipewire") is not None


def is_pipewire_running() -> bool:
"""Check if PipeWire daemon is running."""
# Method 1: Check for socket
runtime_dir = os.environ.get("XDG_RUNTIME_DIR")
if runtime_dir:
socket_path = os.path.join(runtime_dir, "pipewire-0")
if os.path.exists(socket_path):
return True

# Method 2: Check process list (fallback)
try:
# pgrep is widely available on Linux
subprocess.check_call(["pgrep", "-x", "pipewire"], stdout=subprocess.DEVNULL)
return True
except (subprocess.CalledProcessError, FileNotFoundError):
pass

return False


def get_distro_name() -> str:
"""Get the distribution name (e.g. 'Ubuntu', 'Fedora')."""
try:
with open("/etc/os-release") as f:
for line in f:
if line.startswith("NAME="):
return line.split("=")[1].strip().strip('"')
except Exception:
pass
return "Linux"
51 changes: 49 additions & 2 deletions quinoa/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import sys

from PyQt6.QtCore import QTimer
from PyQt6.QtWidgets import QApplication
from PyQt6.QtWidgets import QApplication, QMessageBox

from quinoa.compatibility import get_distro_name, is_pipewire_installed, is_pipewire_running
from quinoa.logging import logger, setup_logging
from quinoa.ui.main_window import MainWindow


def main():
Expand All @@ -19,6 +19,53 @@ def main():
setup_logging(verbose=args.verbose)

app = QApplication(sys.argv)

# Check for PipeWire availability
if not is_pipewire_running():
msg = "PipeWire audio service is not running."
info = "Quinoa requires PipeWire for audio recording."

if not is_pipewire_installed():
info += "\n\nPipeWire does not appear to be installed."
distro = get_distro_name()
if "Ubuntu" in distro:
info += "\nOn Ubuntu 22.04 or earlier, you may need to install 'pipewire' and 'pipewire-pulse'."
else:
info += "\n\nPipeWire is installed but the service is not active."
info += "\nTry running: systemctl --user start pipewire"

# If in test mode, just log it. If interactive, show warning.
if args.test:
logger.warning(f"{msg} {info}")
else:
mbox = QMessageBox()
mbox.setIcon(QMessageBox.Icon.Warning)
mbox.setWindowTitle("PipeWire Missing")
mbox.setText(msg)
mbox.setInformativeText(info)
mbox.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel)
ret = mbox.exec()
if ret == QMessageBox.StandardButton.Cancel:
sys.exit(1)

try:
from quinoa.ui.main_window import MainWindow
except ImportError as e:
logger.error(f"Failed to load application: {e}")
if "libpipewire" in str(e) or "quinoa_audio" in str(e):
mbox = QMessageBox()
mbox.setIcon(QMessageBox.Icon.Critical)
mbox.setWindowTitle("Dependency Error")
mbox.setText("Failed to load audio component.")
info = f"Error: {e}\n\nThis usually means the PipeWire shared libraries are missing."
distro = get_distro_name()
if "Ubuntu" in distro:
info += "\n\nOn Ubuntu, try installing: libpipewire-0.3-0 or libpipewire-0.3-dev"
mbox.setInformativeText(info)
mbox.exec()
sys.exit(1)
raise

window = MainWindow()
window.show()

Expand Down