Initial commit: FaceTime HD camera driver and OBS performance scripts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
4d04b06d41
2 changed files with 556 additions and 0 deletions
451
facetimehd-installer.sh
Executable file
451
facetimehd-installer.sh
Executable file
|
|
@ -0,0 +1,451 @@
|
|||
#!/bin/bash
|
||||
|
||||
# FaceTime HD Camera Installation Script for Linux Kernel 6.8+
|
||||
# Compatible with MacBook Air A1466 EMC 3178 and similar models
|
||||
# Author: System Script
|
||||
# Version: 1.0
|
||||
# Last Updated: 2025
|
||||
|
||||
set -e
|
||||
|
||||
# Color codes for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Script name for logging
|
||||
SCRIPT_NAME=$(basename "$0")
|
||||
LOG_FILE="/tmp/facetimehd-install-$(date +%Y%m%d-%H%M%S).log"
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${BLUE}[${SCRIPT_NAME}]${NC} $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[✓]${NC} $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[✗]${NC} $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[!]${NC} $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Function to check if running as root
|
||||
check_root() {
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
print_error "This script should not be run as root!"
|
||||
print_status "Please run without sudo: ./$SCRIPT_NAME"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to detect distribution
|
||||
detect_distro() {
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
OS=$NAME
|
||||
VER=$VERSION_ID
|
||||
else
|
||||
print_error "Cannot detect distribution"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check kernel version
|
||||
check_kernel() {
|
||||
KERNEL_VERSION=$(uname -r)
|
||||
KERNEL_MAJOR=$(echo $KERNEL_VERSION | cut -d. -f1)
|
||||
KERNEL_MINOR=$(echo $KERNEL_VERSION | cut -d. -f2)
|
||||
|
||||
print_status "Detected kernel version: $KERNEL_VERSION"
|
||||
|
||||
if [[ $KERNEL_MAJOR -lt 5 ]] || ([[ $KERNEL_MAJOR -eq 5 ]] && [[ $KERNEL_MINOR -lt 7 ]]); then
|
||||
print_warning "Kernel version is older than 5.7, using legacy installation method"
|
||||
USE_LEGACY=true
|
||||
else
|
||||
USE_LEGACY=false
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if camera is already working
|
||||
check_camera() {
|
||||
if [ -e /dev/video0 ] || [ -e /dev/video1 ]; then
|
||||
if lsmod | grep -q facetimehd; then
|
||||
print_warning "FaceTime HD camera driver appears to be already installed"
|
||||
read -p "Do you want to reinstall? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_status "Exiting..."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check and disable Secure Boot if needed
|
||||
check_secure_boot() {
|
||||
if command -v mokutil &> /dev/null; then
|
||||
if mokutil --sb-state 2>&1 | grep -q "SecureBoot enabled"; then
|
||||
print_warning "Secure Boot is enabled. The camera driver may not load."
|
||||
print_status "You have three options:"
|
||||
echo " 1. Disable Secure Boot in BIOS/UEFI (recommended)"
|
||||
echo " 2. Sign the kernel module (advanced)"
|
||||
echo " 3. Continue anyway (module may not load)"
|
||||
read -p "Choose option (1-3): " -n 1 -r
|
||||
echo
|
||||
case $REPLY in
|
||||
1)
|
||||
print_status "Please reboot and disable Secure Boot in BIOS/UEFI settings"
|
||||
print_status "Then run this script again"
|
||||
exit 0
|
||||
;;
|
||||
2)
|
||||
SIGN_MODULE=true
|
||||
;;
|
||||
3)
|
||||
print_warning "Continuing with Secure Boot enabled..."
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to install dependencies
|
||||
install_dependencies() {
|
||||
print_status "Installing required dependencies..."
|
||||
|
||||
if [[ "$OS" == "Ubuntu" ]] || [[ "$OS" == "Linux Mint" ]] || [[ "$OS" == "Debian"* ]]; then
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
git \
|
||||
curl \
|
||||
xz-utils \
|
||||
cpio \
|
||||
make \
|
||||
gcc \
|
||||
linux-headers-$(uname -r) \
|
||||
libssl-dev \
|
||||
checkinstall \
|
||||
build-essential \
|
||||
dkms \
|
||||
v4l-utils || {
|
||||
print_error "Failed to install dependencies"
|
||||
exit 1
|
||||
}
|
||||
elif [[ "$OS" == "Fedora" ]]; then
|
||||
sudo dnf install -y \
|
||||
git \
|
||||
curl \
|
||||
xz \
|
||||
cpio \
|
||||
make \
|
||||
gcc \
|
||||
kernel-devel-$(uname -r) \
|
||||
openssl-devel \
|
||||
dkms \
|
||||
v4l-utils || {
|
||||
print_error "Failed to install dependencies"
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
print_error "Unsupported distribution: $OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "Dependencies installed successfully"
|
||||
}
|
||||
|
||||
# Function to remove old installations
|
||||
cleanup_old_installation() {
|
||||
print_status "Cleaning up old installations..."
|
||||
|
||||
# Unload module if loaded
|
||||
if lsmod | grep -q facetimehd; then
|
||||
sudo modprobe -r facetimehd 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Remove old DKMS installations
|
||||
if dkms status | grep -q facetimehd; then
|
||||
sudo dkms remove facetimehd/0.6.13 --all 2>/dev/null || true
|
||||
sudo dkms remove facetimehd/0.1 --all 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Remove old files
|
||||
sudo rm -rf /usr/src/facetimehd* 2>/dev/null || true
|
||||
sudo rm -f /lib/modules/*/extra/facetimehd.ko* 2>/dev/null || true
|
||||
|
||||
print_success "Cleanup completed"
|
||||
}
|
||||
|
||||
# Function to download and install firmware
|
||||
install_firmware() {
|
||||
print_status "Downloading and installing camera firmware..."
|
||||
|
||||
WORK_DIR=$(mktemp -d)
|
||||
cd "$WORK_DIR"
|
||||
|
||||
# Clone firmware repository
|
||||
git clone https://github.com/patjak/facetimehd-firmware.git || {
|
||||
print_error "Failed to download firmware repository"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd facetimehd-firmware
|
||||
|
||||
# Build and install firmware
|
||||
make || {
|
||||
print_error "Failed to build firmware"
|
||||
exit 1
|
||||
}
|
||||
|
||||
sudo make install || {
|
||||
print_error "Failed to install firmware"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Verify firmware installation
|
||||
if [ ! -f /lib/firmware/facetimehd/firmware.bin ]; then
|
||||
print_warning "Firmware not found in expected location, creating symlink..."
|
||||
sudo mkdir -p /lib/firmware/facetimehd
|
||||
if [ -f /usr/lib/firmware/facetimehd/firmware.bin ]; then
|
||||
sudo ln -sf /usr/lib/firmware/facetimehd/firmware.bin /lib/firmware/facetimehd/firmware.bin
|
||||
else
|
||||
print_error "Firmware installation failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
print_success "Firmware installed successfully"
|
||||
cd ~
|
||||
rm -rf "$WORK_DIR"
|
||||
}
|
||||
|
||||
# Function to install driver for kernel 6.8+
|
||||
install_driver() {
|
||||
print_status "Downloading and installing FaceTime HD driver..."
|
||||
|
||||
WORK_DIR=$(mktemp -d)
|
||||
cd "$WORK_DIR"
|
||||
|
||||
# For kernel 6.8+, try the updated repository first
|
||||
if [[ $KERNEL_MAJOR -ge 6 ]] && [[ $KERNEL_MINOR -ge 8 ]]; then
|
||||
print_status "Using updated driver for kernel 6.8+"
|
||||
|
||||
# Try multiple repositories in order of compatibility
|
||||
REPOS=(
|
||||
"https://github.com/patjak/facetimehd.git"
|
||||
"https://github.com/kekrby/facetimehd.git"
|
||||
"https://github.com/bartkessels/facetimehd.git"
|
||||
)
|
||||
|
||||
CLONED=false
|
||||
for repo in "${REPOS[@]}"; do
|
||||
print_status "Trying repository: $repo"
|
||||
if git clone "$repo" facetimehd 2>/dev/null; then
|
||||
CLONED=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$CLONED" = false ]; then
|
||||
print_error "Failed to download any driver repository"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# For older kernels, use the standard repository
|
||||
git clone https://github.com/patjak/facetimehd.git || {
|
||||
print_error "Failed to download driver repository"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
cd facetimehd
|
||||
|
||||
# Apply patches for kernel 6.8+ if needed
|
||||
if [[ $KERNEL_MAJOR -ge 6 ]]; then
|
||||
print_status "Applying kernel 6.x compatibility patches..."
|
||||
|
||||
# Fix for VFL_TYPE_GRABBER deprecation
|
||||
if grep -q "VFL_TYPE_GRABBER" fthd_v4l2.c 2>/dev/null; then
|
||||
sed -i 's/VFL_TYPE_GRABBER/VFL_TYPE_VIDEO/g' fthd_v4l2.c
|
||||
fi
|
||||
|
||||
# Fix for other kernel 6.x API changes
|
||||
if grep -q "v4l2_device_release" fthd_v4l2.c 2>/dev/null; then
|
||||
sed -i 's/v4l2_device_release/video_device_release/g' fthd_v4l2.c
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install via DKMS
|
||||
print_status "Installing driver via DKMS..."
|
||||
|
||||
DRIVER_VERSION="0.6.13"
|
||||
sudo cp -r . "/usr/src/facetimehd-$DRIVER_VERSION"
|
||||
|
||||
# Create DKMS configuration if it doesn't exist
|
||||
if [ ! -f "/usr/src/facetimehd-$DRIVER_VERSION/dkms.conf" ]; then
|
||||
sudo tee "/usr/src/facetimehd-$DRIVER_VERSION/dkms.conf" > /dev/null <<EOF
|
||||
PACKAGE_NAME="facetimehd"
|
||||
PACKAGE_VERSION="$DRIVER_VERSION"
|
||||
BUILT_MODULE_NAME[0]="facetimehd"
|
||||
DEST_MODULE_LOCATION[0]="/extra"
|
||||
AUTOINSTALL="yes"
|
||||
MAKE="make -C \${kernel_source_dir} M=\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION}/build modules"
|
||||
CLEAN="make -C \${kernel_source_dir} M=\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION}/build clean"
|
||||
EOF
|
||||
fi
|
||||
|
||||
sudo dkms add -m facetimehd -v "$DRIVER_VERSION" || {
|
||||
print_error "Failed to add driver to DKMS"
|
||||
exit 1
|
||||
}
|
||||
|
||||
sudo dkms build -m facetimehd -v "$DRIVER_VERSION" || {
|
||||
print_error "Failed to build driver with DKMS"
|
||||
exit 1
|
||||
}
|
||||
|
||||
sudo dkms install -m facetimehd -v "$DRIVER_VERSION" || {
|
||||
print_error "Failed to install driver with DKMS"
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_success "Driver installed successfully"
|
||||
cd ~
|
||||
rm -rf "$WORK_DIR"
|
||||
}
|
||||
|
||||
# Function to configure module loading
|
||||
configure_module() {
|
||||
print_status "Configuring module loading..."
|
||||
|
||||
# Blacklist conflicting modules
|
||||
echo 'blacklist bdc_pci' | sudo tee /etc/modprobe.d/blacklist-facetimehd.conf > /dev/null
|
||||
|
||||
# Add facetimehd to modules
|
||||
if ! grep -q "^facetimehd$" /etc/modules 2>/dev/null; then
|
||||
echo 'facetimehd' | sudo tee -a /etc/modules > /dev/null
|
||||
fi
|
||||
|
||||
# Load the module
|
||||
print_status "Loading FaceTime HD module..."
|
||||
sudo modprobe -r bdc_pci 2>/dev/null || true
|
||||
sudo modprobe facetimehd || {
|
||||
print_error "Failed to load module"
|
||||
print_status "Check dmesg for errors: sudo dmesg | tail -20"
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_success "Module configured and loaded"
|
||||
}
|
||||
|
||||
# Function to verify installation
|
||||
verify_installation() {
|
||||
print_status "Verifying installation..."
|
||||
|
||||
# Check if module is loaded
|
||||
if ! lsmod | grep -q facetimehd; then
|
||||
print_error "Module is not loaded"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for video device
|
||||
if [ ! -e /dev/video0 ] && [ ! -e /dev/video1 ] && [ ! -e /dev/video2 ]; then
|
||||
print_error "No video device found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get video device
|
||||
VIDEO_DEVICE=$(ls /dev/video* 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$VIDEO_DEVICE" ]; then
|
||||
print_success "Camera device found at: $VIDEO_DEVICE"
|
||||
|
||||
# Show camera information
|
||||
print_status "Camera information:"
|
||||
v4l2-ctl -d "$VIDEO_DEVICE" --info 2>/dev/null || true
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to test camera
|
||||
test_camera() {
|
||||
print_status "Would you like to test the camera now? (y/N): "
|
||||
read -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
VIDEO_DEVICE=$(ls /dev/video* 2>/dev/null | head -1)
|
||||
|
||||
if command -v cheese &> /dev/null; then
|
||||
print_status "Starting Cheese..."
|
||||
cheese &
|
||||
elif command -v guvcview &> /dev/null; then
|
||||
print_status "Starting guvcview..."
|
||||
guvcview &
|
||||
else
|
||||
print_warning "No camera application found. Install cheese or guvcview to test."
|
||||
print_status "You can install with: sudo apt install cheese"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main installation flow
|
||||
main() {
|
||||
clear
|
||||
echo "======================================"
|
||||
echo "FaceTime HD Camera Installation Script"
|
||||
echo "======================================"
|
||||
echo
|
||||
print_status "Log file: $LOG_FILE"
|
||||
echo
|
||||
|
||||
# Pre-installation checks
|
||||
check_root
|
||||
detect_distro
|
||||
check_kernel
|
||||
check_camera
|
||||
check_secure_boot
|
||||
|
||||
# Installation
|
||||
install_dependencies
|
||||
cleanup_old_installation
|
||||
install_firmware
|
||||
install_driver
|
||||
configure_module
|
||||
|
||||
# Post-installation
|
||||
if verify_installation; then
|
||||
print_success "Installation completed successfully!"
|
||||
echo
|
||||
print_status "Camera should now be working."
|
||||
print_status "You can test it with applications like:"
|
||||
echo " - cheese"
|
||||
echo " - guvcview"
|
||||
echo " - Google Chrome/Chromium"
|
||||
echo " - Firefox"
|
||||
echo
|
||||
test_camera
|
||||
else
|
||||
print_error "Installation completed but verification failed"
|
||||
print_status "Please check the log file: $LOG_FILE"
|
||||
print_status "And kernel messages: sudo dmesg | grep -i facetime"
|
||||
fi
|
||||
|
||||
echo
|
||||
print_status "If you encounter issues, please check:"
|
||||
echo " 1. Secure Boot status (disable if enabled)"
|
||||
echo " 2. Kernel messages: sudo dmesg | grep -i facetime"
|
||||
echo " 3. Module status: lsmod | grep facetimehd"
|
||||
echo " 4. Log file: $LOG_FILE"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
105
obs-performance-script.sh
Executable file
105
obs-performance-script.sh
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
#!/bin/bash
|
||||
# OBS Performance Script for Linux Mint Cinnamon
|
||||
# Fixed version for newer Cinnamon versions
|
||||
|
||||
# Color codes for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${GREEN}OBS Performance Optimizer for Linux Mint Cinnamon${NC}"
|
||||
echo "=================================================="
|
||||
|
||||
# Check if OBS is installed
|
||||
if ! command -v obs-studio &> /dev/null && ! command -v flatpak run com.obsproject.Studio &> /dev/null; then
|
||||
echo -e "${RED}Error: OBS Studio not found!${NC}"
|
||||
echo "Install with: sudo apt install obs-studio"
|
||||
echo "Or: flatpak install flathub com.obsproject.Studio"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect OBS installation type
|
||||
if command -v obs-studio &> /dev/null; then
|
||||
OBS_COMMAND="obs-studio"
|
||||
elif flatpak list | grep -q "com.obsproject.Studio"; then
|
||||
OBS_COMMAND="flatpak run com.obsproject.Studio"
|
||||
else
|
||||
OBS_COMMAND="obs" # fallback
|
||||
fi
|
||||
|
||||
# Store original settings (using correct keys for newer Cinnamon)
|
||||
echo -e "${YELLOW}Saving current desktop settings...${NC}"
|
||||
|
||||
# Check Cinnamon version and use appropriate settings
|
||||
if gsettings list-keys org.cinnamon.desktop.wm.preferences | grep -q "compositor-manager"; then
|
||||
# Newer Cinnamon
|
||||
ORIGINAL_COMPOSITOR=$(gsettings get org.cinnamon.desktop.wm.preferences compositor-manager 2>/dev/null || echo "true")
|
||||
COMPOSITOR_KEY="org.cinnamon.desktop.wm.preferences compositor-manager"
|
||||
else
|
||||
# Try muffin settings
|
||||
ORIGINAL_COMPOSITOR="true"
|
||||
COMPOSITOR_KEY=""
|
||||
fi
|
||||
|
||||
ORIGINAL_UNREDIRECT=$(gsettings get org.cinnamon.muffin unredirect-fullscreen-windows 2>/dev/null || echo "false")
|
||||
|
||||
echo "Unredirect: $ORIGINAL_UNREDIRECT"
|
||||
|
||||
# Apply performance settings
|
||||
echo -e "\n${YELLOW}Applying performance optimizations...${NC}"
|
||||
|
||||
# Disable effects using available methods
|
||||
if [ -n "$COMPOSITOR_KEY" ]; then
|
||||
gsettings set $COMPOSITOR_KEY false 2>/dev/null && echo -e "${GREEN}✓ Compositor disabled${NC}"
|
||||
else
|
||||
# Alternative: disable effects
|
||||
gsettings set org.cinnamon enable-effects false 2>/dev/null && echo -e "${GREEN}✓ Desktop effects disabled${NC}"
|
||||
fi
|
||||
|
||||
# Set unredirect for fullscreen
|
||||
gsettings set org.cinnamon.muffin unredirect-fullscreen-windows true 2>/dev/null && echo -e "${GREEN}✓ Fullscreen unredirect enabled${NC}"
|
||||
|
||||
# Alternative compositor control for Cinnamon
|
||||
if command -v cinnamon-settings &> /dev/null; then
|
||||
# Try to disable vsync through muffin dconf settings
|
||||
dconf write /org/cinnamon/muffin/sync-to-vblank false 2>/dev/null
|
||||
fi
|
||||
|
||||
# Set CPU governor to performance if available
|
||||
if [ -f /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor ]; then
|
||||
echo -e "\n${YELLOW}Setting CPU to performance mode (may require password)${NC}"
|
||||
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ CPU performance mode set${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Launch OBS with optimized environment
|
||||
echo -e "\n${GREEN}Launching OBS with optimized settings...${NC}"
|
||||
echo "==========================================="
|
||||
echo "Using command: $OBS_COMMAND"
|
||||
|
||||
# Run OBS with performance environment variables
|
||||
env vblank_mode=0 \
|
||||
__GL_SYNC_TO_VBLANK=0 \
|
||||
__GL_THREADED_OPTIMIZATIONS=1 \
|
||||
PULSE_LATENCY_MSEC=30 \
|
||||
$OBS_COMMAND
|
||||
|
||||
# Restore original settings after OBS closes
|
||||
echo -e "\n${YELLOW}OBS closed. Restoring original settings...${NC}"
|
||||
|
||||
if [ -n "$COMPOSITOR_KEY" ]; then
|
||||
gsettings set $COMPOSITOR_KEY "$ORIGINAL_COMPOSITOR" 2>/dev/null
|
||||
else
|
||||
gsettings set org.cinnamon enable-effects true 2>/dev/null
|
||||
fi
|
||||
|
||||
gsettings set org.cinnamon.muffin unredirect-fullscreen-windows "$ORIGINAL_UNREDIRECT" 2>/dev/null
|
||||
|
||||
# Restore vsync if it was modified
|
||||
dconf write /org/cinnamon/muffin/sync-to-vblank true 2>/dev/null
|
||||
|
||||
echo -e "${GREEN}✓ Desktop settings restored${NC}"
|
||||
echo -e "${GREEN}Done!${NC}"
|
||||
Loading…
Add table
Reference in a new issue