Merge pull request #44 from outis1one/claude/mumble-kiosk-setup-01RUgNotdEkjq4KfNRBeqDyK
Claude/mumble kiosk setup 01 r ug notd ekjq4 kf nr beq dy k
This commit is contained in:
@@ -226,6 +226,46 @@ curl http://localhost:8011/api/channel?channel=General/Support
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Warnings (Usually Non-Fatal)
|
||||
|
||||
These warnings often appear but don't prevent talkkonnect from working:
|
||||
|
||||
**`Unable to Unmute failed to execute "pactl set-sink-mute 0 0"`**
|
||||
- TalkKonnect is trying to unmute your audio output
|
||||
- This usually fails because the sink index is wrong or pactl isn't accessible
|
||||
- **Audio typically works anyway** - this is just a cosmetic error
|
||||
- To fix: Run `./fix_talkkonnect_audio.sh` to check your audio configuration
|
||||
|
||||
**`Unable to Find Channel Name: Root`**
|
||||
- Just a warning - connection usually succeeds anyway
|
||||
- The channel exists but talkkonnect didn't detect it during initial scan
|
||||
- You'll see a follow-up message showing successful connection
|
||||
|
||||
**`Failed to connect PipeWire event context (errno: 112)`**
|
||||
- TalkKonnect is trying to use PipeWire but can't access the session
|
||||
- Usually happens when running as a service without proper environment
|
||||
- **If you see `Speaking ->` messages, audio is working!**
|
||||
- To fix: Ensure XDG_RUNTIME_DIR is set correctly in systemd service
|
||||
|
||||
### Audio Troubleshooting
|
||||
|
||||
Run the audio diagnostic script:
|
||||
```bash
|
||||
./fix_talkkonnect_audio.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
- Check PipeWire/PulseAudio session status
|
||||
- List available audio devices
|
||||
- Show current talkkonnect configuration
|
||||
- Provide specific recommendations
|
||||
|
||||
**Quick audio test:**
|
||||
```bash
|
||||
# Test as the kiosk user (replace with your user)
|
||||
sudo -u kiosk XDG_RUNTIME_DIR=/run/user/$(id -u kiosk) speaker-test -t wav -c 2 -l 1
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env bash
|
||||
# ======================================================================
|
||||
# File: fix_talkkonnect_audio.sh
|
||||
# Purpose: Fix talkkonnect audio configuration
|
||||
# ======================================================================
|
||||
|
||||
echo "======================================================================="
|
||||
echo "TalkKonnect Audio Configuration Fix"
|
||||
echo "======================================================================="
|
||||
echo ""
|
||||
|
||||
# Prompt for target user
|
||||
read -p "Which user is talkkonnect running as? [kiosk]: " TARGET_USER
|
||||
TARGET_USER=${TARGET_USER:-kiosk}
|
||||
|
||||
# Verify the target user exists
|
||||
if ! id "$TARGET_USER" &>/dev/null; then
|
||||
echo "[!] Error: User '$TARGET_USER' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_UID=$(id -u "$TARGET_USER")
|
||||
TARGET_HOME=$(eval echo ~"$TARGET_USER")
|
||||
CONFIG_FILE="$TARGET_HOME/.config/talkkonnect/talkkonnect.xml"
|
||||
|
||||
echo "[+] Target user: $TARGET_USER (UID: $TARGET_UID)"
|
||||
echo "[+] Config file: $CONFIG_FILE"
|
||||
echo ""
|
||||
|
||||
# Check PipeWire session
|
||||
echo "[1] Checking PipeWire/PulseAudio session..."
|
||||
if [ -S "/run/user/$TARGET_UID/pipewire-0" ]; then
|
||||
echo " ✓ PipeWire socket found: /run/user/$TARGET_UID/pipewire-0"
|
||||
HAS_PIPEWIRE=true
|
||||
else
|
||||
echo " ✗ No PipeWire socket found at /run/user/$TARGET_UID/pipewire-0"
|
||||
HAS_PIPEWIRE=false
|
||||
fi
|
||||
|
||||
if [ -S "/run/user/$TARGET_UID/pulse/native" ]; then
|
||||
echo " ✓ PulseAudio socket found: /run/user/$TARGET_UID/pulse/native"
|
||||
HAS_PULSE=true
|
||||
else
|
||||
echo " ✗ No PulseAudio socket found"
|
||||
HAS_PULSE=false
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check audio devices as target user
|
||||
echo "[2] Checking audio devices for user $TARGET_USER..."
|
||||
echo ""
|
||||
echo "Available ALSA output devices:"
|
||||
sudo -u "$TARGET_USER" XDG_RUNTIME_DIR=/run/user/$TARGET_UID aplay -L 2>/dev/null | grep -E "^(default|hw:|pulse)" | head -10
|
||||
echo ""
|
||||
|
||||
echo "Available ALSA input devices:"
|
||||
sudo -u "$TARGET_USER" XDG_RUNTIME_DIR=/run/user/$TARGET_UID arecord -L 2>/dev/null | grep -E "^(default|hw:|pulse)" | head -10
|
||||
echo ""
|
||||
|
||||
# If PipeWire/Pulse is available, check sinks
|
||||
if [ "$HAS_PIPEWIRE" = true ] || [ "$HAS_PULSE" = true ]; then
|
||||
echo "PipeWire/PulseAudio sinks:"
|
||||
sudo -u "$TARGET_USER" XDG_RUNTIME_DIR=/run/user/$TARGET_UID pactl list sinks short 2>/dev/null || echo "(pactl not available)"
|
||||
echo ""
|
||||
|
||||
echo "PipeWire/PulseAudio sources:"
|
||||
sudo -u "$TARGET_USER" XDG_RUNTIME_DIR=/run/user/$TARGET_UID pactl list sources short 2>/dev/null || echo "(pactl not available)"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check current config
|
||||
echo "[3] Current talkkonnect audio configuration:"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
echo ""
|
||||
echo "Input device:"
|
||||
grep -A1 '<input>' "$CONFIG_FILE" | grep 'device=' | sed 's/.*device="\([^"]*\)".*/ \1/'
|
||||
|
||||
echo ""
|
||||
echo "Output device:"
|
||||
grep -A1 '<output>' "$CONFIG_FILE" | grep 'device=' | sed 's/.*device="\([^"]*\)".*/ \1/'
|
||||
echo ""
|
||||
else
|
||||
echo " Config file not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Recommendations
|
||||
echo "======================================================================="
|
||||
echo "Recommendations"
|
||||
echo "======================================================================="
|
||||
echo ""
|
||||
|
||||
if [ "$HAS_PIPEWIRE" = false ] && [ "$HAS_PULSE" = false ]; then
|
||||
echo "⚠️ No PipeWire or PulseAudio session found"
|
||||
echo ""
|
||||
echo "Option 1: Use direct ALSA (best for dedicated audio hardware)"
|
||||
echo " Edit $CONFIG_FILE"
|
||||
echo " Change both input and output device to: hw:0,0"
|
||||
echo ""
|
||||
echo "Option 2: Start PipeWire for the $TARGET_USER user"
|
||||
echo " Ensure $TARGET_USER has an active graphical session"
|
||||
echo ""
|
||||
else
|
||||
echo "✓ Audio system detected (PipeWire/PulseAudio)"
|
||||
echo ""
|
||||
echo "The 'Unable to Unmute' error is usually non-fatal."
|
||||
echo "If audio is working, you can ignore it."
|
||||
echo ""
|
||||
echo "To fix the unmute error, you can:"
|
||||
echo " 1. Keep device as 'default' (usually works)"
|
||||
echo " 2. OR use specific device like 'pulse' or 'hw:0,0'"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Testing audio output as $TARGET_USER:"
|
||||
echo " sudo -u $TARGET_USER XDG_RUNTIME_DIR=/run/user/$TARGET_UID speaker-test -t wav -c 2 -l 1"
|
||||
echo ""
|
||||
|
||||
echo "Testing audio input as $TARGET_USER:"
|
||||
echo " sudo -u $TARGET_USER XDG_RUNTIME_DIR=/run/user/$TARGET_UID arecord -d 3 -f cd test.wav && aplay test.wav"
|
||||
echo ""
|
||||
|
||||
echo "To edit config:"
|
||||
echo " sudo nano $CONFIG_FILE"
|
||||
echo ""
|
||||
|
||||
echo "After making changes, restart talkkonnect:"
|
||||
echo " sudo systemctl restart talkkonnect"
|
||||
echo ""
|
||||
Executable
+183
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
# ======================================================================
|
||||
# File: fix_talkkonnect_now.sh
|
||||
# Purpose: Quick fix for current talkkonnect issues
|
||||
# ======================================================================
|
||||
|
||||
echo "======================================================================="
|
||||
echo "TalkKonnect Quick Fix Script"
|
||||
echo "======================================================================="
|
||||
echo ""
|
||||
|
||||
TARGET_USER="${1:-kiosk}"
|
||||
CONFIG_FILE="/home/$TARGET_USER/.config/talkkonnect/talkkonnect.xml"
|
||||
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "[!] Config file not found: $CONFIG_FILE"
|
||||
echo "[!] Looking for alternative locations..."
|
||||
|
||||
if [ -f "/home/$TARGET_USER/talkkonnect.xml" ]; then
|
||||
CONFIG_FILE="/home/$TARGET_USER/talkkonnect.xml"
|
||||
echo "[+] Found config at: $CONFIG_FILE"
|
||||
else
|
||||
echo "[!] No config file found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[+] Using config: $CONFIG_FILE"
|
||||
echo ""
|
||||
|
||||
# Fix 1: Enable insecure mode for self-signed certificates
|
||||
echo "[1/4] Fixing certificate issue..."
|
||||
if grep -q "<insecure>false</insecure>" "$CONFIG_FILE"; then
|
||||
sudo sed -i 's|<insecure>false</insecure>|<insecure>true</insecure>|g' "$CONFIG_FILE"
|
||||
echo " ✓ Set insecure=true (allows self-signed certificates)"
|
||||
elif ! grep -q "<insecure>" "$CONFIG_FILE"; then
|
||||
sudo sed -i 's|</account>| <insecure>true</insecure>\n </account>|' "$CONFIG_FILE"
|
||||
echo " ✓ Added insecure=true setting"
|
||||
else
|
||||
echo " ✓ Certificate setting already correct"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Fix 2: Check if using SuperUser account
|
||||
echo "[2/4] Checking account settings..."
|
||||
if grep -q "<username>SuperUser</username>" "$CONFIG_FILE"; then
|
||||
echo " ⚠️ WARNING: You're trying to connect as 'SuperUser'"
|
||||
echo " SuperUser is the SERVER ADMIN account, not a client account."
|
||||
echo ""
|
||||
echo " To fix:"
|
||||
echo " 1. Connect with Mumble desktop/mobile app as SuperUser"
|
||||
echo " 2. Create a regular user account or allow unregistered users"
|
||||
echo " 3. Use that account for talkkonnect, not SuperUser"
|
||||
echo ""
|
||||
read -p " Change username now? (y/n): " change_user
|
||||
if [[ "$change_user" =~ ^[Yy]$ ]]; then
|
||||
read -p " Enter new username: " new_username
|
||||
sudo sed -i "s|<username>.*</username>|<username>$new_username</username>|" "$CONFIG_FILE"
|
||||
read -s -p " Enter password (blank if none): " new_password
|
||||
echo
|
||||
sudo sed -i "s|<password>.*</password>|<password>$new_password</password>|" "$CONFIG_FILE"
|
||||
echo " ✓ Username updated"
|
||||
fi
|
||||
else
|
||||
CURRENT_USER=$(grep "<username>" "$CONFIG_FILE" | sed 's/.*<username>\(.*\)<\/username>/\1/')
|
||||
echo " ✓ Username: $CURRENT_USER (not SuperUser - good!)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Fix 3: Check and fix ownership
|
||||
echo "[3/4] Fixing file permissions..."
|
||||
sudo chown -R "$TARGET_USER:$TARGET_USER" "$(dirname $CONFIG_FILE)"
|
||||
sudo chmod 644 "$CONFIG_FILE"
|
||||
echo " ✓ Ownership set to $TARGET_USER"
|
||||
echo ""
|
||||
|
||||
# Fix 4: Check systemd service
|
||||
echo "[4/4] Checking systemd service..."
|
||||
SERVICE_FILE="/etc/systemd/system/talkkonnect.service"
|
||||
|
||||
if [ ! -f "$SERVICE_FILE" ]; then
|
||||
echo " ⚠️ Systemd service not found"
|
||||
echo " Creating service file..."
|
||||
|
||||
TARGET_UID=$(id -u "$TARGET_USER")
|
||||
TARGET_HOME="/home/$TARGET_USER"
|
||||
|
||||
# Determine which binary to use
|
||||
if [ -f "/usr/local/bin/talkkonnect" ]; then
|
||||
BINARY_PATH="/usr/local/bin/talkkonnect"
|
||||
elif [ -f "$TARGET_HOME/go/bin/talkkonnect" ]; then
|
||||
BINARY_PATH="$TARGET_HOME/go/bin/talkkonnect"
|
||||
else
|
||||
echo " ✗ Talkkonnect binary not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo tee "$SERVICE_FILE" > /dev/null <<EOFSVC
|
||||
[Unit]
|
||||
Description=TalkKonnect Headless Mumble Transceiver
|
||||
After=network-online.target sound.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$TARGET_USER
|
||||
Group=$TARGET_USER
|
||||
WorkingDirectory=$TARGET_HOME
|
||||
ExecStart=$BINARY_PATH -config $CONFIG_FILE
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
Environment="XDG_RUNTIME_DIR=/run/user/$TARGET_UID"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOFSVC
|
||||
|
||||
echo " ✓ Service file created"
|
||||
fi
|
||||
|
||||
# Reload and enable service
|
||||
echo " Reloading systemd..."
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
if ! systemctl is-enabled --quiet talkkonnect 2>/dev/null; then
|
||||
echo " Enabling talkkonnect service..."
|
||||
sudo systemctl enable talkkonnect
|
||||
echo " ✓ Service enabled (will start on boot)"
|
||||
fi
|
||||
|
||||
# Check if service is running
|
||||
if systemctl is-active --quiet talkkonnect 2>/dev/null; then
|
||||
echo " Restarting talkkonnect service..."
|
||||
sudo systemctl restart talkkonnect
|
||||
sleep 3
|
||||
else
|
||||
echo " Starting talkkonnect service..."
|
||||
sudo systemctl start talkkonnect
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
if systemctl is-active --quiet talkkonnect 2>/dev/null; then
|
||||
echo " ✓ Service is RUNNING"
|
||||
else
|
||||
echo " ✗ Service failed to start"
|
||||
echo ""
|
||||
echo "Check logs with: sudo journalctl -u talkkonnect -n 50"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "======================================================================="
|
||||
echo "✓ Quick Fix Complete!"
|
||||
echo "======================================================================="
|
||||
echo ""
|
||||
echo "Changes made:"
|
||||
echo " 1. ✓ Set <insecure>true</insecure> (allows self-signed certs)"
|
||||
echo " 2. ✓ Fixed file ownership"
|
||||
echo " 3. ✓ Created/updated systemd service"
|
||||
echo " 4. ✓ Enabled and started talkkonnect service"
|
||||
echo ""
|
||||
echo "Important Notes:"
|
||||
echo ""
|
||||
echo "❌ SUPERUSER ISSUE:"
|
||||
echo " 'SuperUser' is the Mumble SERVER ADMIN account."
|
||||
echo " You CANNOT use it as a regular client."
|
||||
echo ""
|
||||
echo " To fix:"
|
||||
echo " 1. Use Mumble desktop/mobile app to connect as SuperUser"
|
||||
echo " 2. Create a regular user account on the server"
|
||||
echo " 3. OR configure server to allow unregistered users"
|
||||
echo " 4. Update talkkonnect config to use the regular account"
|
||||
echo ""
|
||||
echo "Check status:"
|
||||
echo " sudo systemctl status talkkonnect"
|
||||
echo ""
|
||||
echo "View logs:"
|
||||
echo " sudo journalctl -u talkkonnect -f"
|
||||
echo ""
|
||||
echo "Edit config:"
|
||||
echo " sudo nano $CONFIG_FILE"
|
||||
echo ""
|
||||
+129
-146
@@ -194,6 +194,9 @@ MURMURCONF
|
||||
### TALKKONNECT CLIENT INSTALLATION
|
||||
################################################################################
|
||||
|
||||
# This is the replacement install_talkkonnect_with_config() function
|
||||
# Copy this into setup_intercom.sh starting at line 197
|
||||
|
||||
install_talkkonnect_with_config() {
|
||||
local server_addr="$1"
|
||||
local server_port="$2"
|
||||
@@ -206,56 +209,58 @@ install_talkkonnect_with_config() {
|
||||
echo " INSTALLING TALKKONNECT CLIENT"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo
|
||||
echo "Using proven installation method (same as talkkonnect_complete_install.sh)..."
|
||||
echo
|
||||
|
||||
echo "[1/4] Installing Go..."
|
||||
if ! command -v go &>/dev/null; then
|
||||
wget -q https://golang.org/dl/go1.23.4.linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
|
||||
rm go1.23.4.linux-amd64.tar.gz
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/go.sh
|
||||
log_success "Go installed"
|
||||
# Get target user info
|
||||
local TARGET_USER="$KIOSK_USER"
|
||||
local TARGET_UID=$(id -u "$TARGET_USER")
|
||||
local TARGET_HOME="/home/$TARGET_USER"
|
||||
local CONFIG_DIR="$TARGET_HOME/.config/talkkonnect"
|
||||
|
||||
# Verify home directory exists
|
||||
if [ ! -d "$TARGET_HOME" ]; then
|
||||
log_error "Home directory does not exist: $TARGET_HOME"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
|
||||
# --- System Prep ------------------------------------------------------
|
||||
echo "[1/7] Installing system dependencies..."
|
||||
sudo apt update
|
||||
sudo apt install -y wget git build-essential pkg-config \
|
||||
libasound2-dev libopus-dev libopus0 libopusfile-dev \
|
||||
libpipewire-0.3-dev libevdev-dev libopenal-dev alsa-utils
|
||||
|
||||
# --- Go Installation --------------------------------------------------
|
||||
echo "[2/7] Installing Go 1.24.1..."
|
||||
if ! command -v go &>/dev/null || ! go version | grep -q "go1.24"; then
|
||||
sudo rm -rf /usr/local/go
|
||||
wget -q https://go.dev/dl/go1.24.1.linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local -xzf go1.24.1.linux-amd64.tar.gz
|
||||
rm -f go1.24.1.linux-amd64.tar.gz
|
||||
sudo ln -sf /usr/local/go/bin/go /usr/bin/go
|
||||
export PATH="/usr/local/go/bin:$PATH"
|
||||
log_success "Go 1.24.1 installed"
|
||||
else
|
||||
log_success "Go already installed"
|
||||
fi
|
||||
|
||||
echo "[2/4] Installing audio dependencies..."
|
||||
sudo apt install -y libopenal-dev libopus-dev libopus0 libopusfile-dev alsa-utils portaudio19-dev git build-essential pkg-config
|
||||
# --- Clone TalkKonnect ------------------------------------------------
|
||||
echo "[3/7] Cloning talkkonnect repository..."
|
||||
cd ~
|
||||
if [ -d "talkkonnect" ]; then
|
||||
rm -rf talkkonnect
|
||||
fi
|
||||
git clone https://github.com/talkkonnect/talkkonnect.git
|
||||
cd talkkonnect
|
||||
|
||||
echo "[3/4] Cloning and building talkkonnect..."
|
||||
# --- Patch gopus for x86_64 -------------------------------------------
|
||||
echo "[4/7] Applying x86_64 Opus patch..."
|
||||
go mod vendor
|
||||
|
||||
echo "Building (this takes 5-10 minutes)..."
|
||||
|
||||
# Build as kiosk user with proper environment (using their home directory to avoid permission issues)
|
||||
sudo -u "$KIOSK_USER" bash -c "
|
||||
export PATH=/usr/local/go/bin:\$PATH
|
||||
export HOME=/home/$KIOSK_USER
|
||||
export GOPATH=/home/$KIOSK_USER/go
|
||||
export CGO_ENABLED=1
|
||||
|
||||
mkdir -p /home/$KIOSK_USER/go/bin
|
||||
|
||||
# Clone to kiosk user's home directory (avoids /tmp permission issues)
|
||||
cd /home/$KIOSK_USER || exit 1
|
||||
|
||||
if [[ -d talkkonnect ]]; then
|
||||
echo 'Removing existing talkkonnect directory...'
|
||||
rm -rf talkkonnect
|
||||
fi
|
||||
|
||||
git clone https://github.com/talkkonnect/talkkonnect.git
|
||||
cd talkkonnect || exit 1
|
||||
|
||||
echo 'Creating vendored dependencies...'
|
||||
go mod vendor
|
||||
|
||||
# Apply critical x86_64 Opus patch
|
||||
echo 'Applying x86_64 Opus compatibility patch...'
|
||||
if [[ -f vendor/github.com/talkkonnect/gopus/opus_nonshared.go ]]; then
|
||||
cp vendor/github.com/talkkonnect/gopus/opus_nonshared.go \
|
||||
vendor/github.com/talkkonnect/gopus/opus_nonshared.go.backup
|
||||
|
||||
cat > vendor/github.com/talkkonnect/gopus/opus_nonshared.go << 'EOFOPUS'
|
||||
if [ -d "vendor/github.com/talkkonnect/gopus" ]; then
|
||||
cat > vendor/github.com/talkkonnect/gopus/opus_nonshared.go << 'EOFOPUS'
|
||||
// +build amd64,cgo 386,cgo
|
||||
|
||||
package gopus
|
||||
@@ -316,11 +321,11 @@ package gopus
|
||||
// void gopus_decoder_resetstate(OpusDecoder *decoder) {
|
||||
// opus_decoder_ctl(decoder, OPUS_RESET_STATE);
|
||||
// }
|
||||
import \"C\"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
\"errors\"
|
||||
\"unsafe\"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Application int
|
||||
@@ -466,14 +471,14 @@ func CountFrames(data []byte) (int, error) {
|
||||
}
|
||||
|
||||
var (
|
||||
ErrBadArgument = errors.New(\"bad argument\")
|
||||
ErrSmallBuffer = errors.New(\"buffer is too small\")
|
||||
ErrInternal = errors.New(\"internal error\")
|
||||
ErrInvalidPacket = errors.New(\"invalid packet\")
|
||||
ErrUnimplemented = errors.New(\"unimplemented\")
|
||||
ErrInvalidState = errors.New(\"invalid state\")
|
||||
ErrAllocFail = errors.New(\"allocation failed\")
|
||||
ErrUnknown = errors.New(\"unknown error\")
|
||||
ErrBadArgument = errors.New("bad argument")
|
||||
ErrSmallBuffer = errors.New("buffer is too small")
|
||||
ErrInternal = errors.New("internal error")
|
||||
ErrInvalidPacket = errors.New("invalid packet")
|
||||
ErrUnimplemented = errors.New("unimplemented")
|
||||
ErrInvalidState = errors.New("invalid state")
|
||||
ErrAllocFail = errors.New("allocation failed")
|
||||
ErrUnknown = errors.New("unknown error")
|
||||
)
|
||||
|
||||
func getErr(code C.int) error {
|
||||
@@ -499,83 +504,69 @@ func getErr(code C.int) error {
|
||||
}
|
||||
}
|
||||
EOFOPUS
|
||||
echo 'Opus patch applied'
|
||||
else
|
||||
echo 'Warning: gopus not found in vendor directory'
|
||||
fi
|
||||
log_success "Opus patch applied"
|
||||
fi
|
||||
|
||||
# Set CGO flags for Opus
|
||||
export CGO_CFLAGS=\"\$(pkg-config --cflags opus)\"
|
||||
export CGO_LDFLAGS=\"\$(pkg-config --libs opus) -lm\"
|
||||
# --- Build TalkKonnect ------------------------------------------------
|
||||
echo "[5/7] Building talkkonnect (this may take a few minutes)..."
|
||||
cd ~/talkkonnect/cmd/talkkonnect
|
||||
|
||||
# Build in the cmd/talkkonnect directory with vendored dependencies
|
||||
cd cmd/talkkonnect || exit 1
|
||||
export CGO_ENABLED=1
|
||||
export CGO_CFLAGS="$(pkg-config --cflags opus)"
|
||||
export CGO_LDFLAGS="$(pkg-config --libs opus) -lm"
|
||||
|
||||
echo 'Compiling with vendored dependencies...'
|
||||
go build -mod=vendor -v -o ~/talkkonnect-binary . 2>&1 | tail -20
|
||||
go build -mod=vendor -v -o ~/talkkonnect-binary . 2>&1 | tail -20
|
||||
|
||||
if [[ ! -f ~/talkkonnect-binary ]]; then
|
||||
echo 'Build failed - binary not created'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 'Build successful'
|
||||
"
|
||||
|
||||
local build_result=$?
|
||||
|
||||
if [[ $build_result -ne 0 ]]; then
|
||||
log_error "Build failed"
|
||||
echo
|
||||
echo "Troubleshooting:"
|
||||
echo " 1. Check Go version: go version"
|
||||
echo " 2. Ensure build tools: sudo apt install build-essential"
|
||||
echo " 3. Check logs above for specific errors"
|
||||
if [ ! -f ~/talkkonnect-binary ]; then
|
||||
log_error "Build failed!"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Stop any running talkkonnect before installing
|
||||
echo "Installing binary..."
|
||||
# Stop any running instances
|
||||
if systemctl is-active --quiet talkkonnect 2>/dev/null; then
|
||||
echo "Stopping existing talkkonnect service..."
|
||||
sudo systemctl stop talkkonnect
|
||||
fi
|
||||
|
||||
# Kill any stray processes
|
||||
if pgrep -x talkkonnect > /dev/null 2>&1; then
|
||||
echo "Killing running talkkonnect processes..."
|
||||
if pgrep -x talkkonnect > /dev/null; then
|
||||
sudo pkill -9 talkkonnect
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Now install as kiosk user
|
||||
sudo -u "$KIOSK_USER" bash -c "
|
||||
cp ~/talkkonnect-binary ~/go/bin/talkkonnect
|
||||
chmod +x ~/go/bin/talkkonnect
|
||||
rm ~/talkkonnect-binary
|
||||
"
|
||||
# Install binary
|
||||
sudo cp ~/talkkonnect-binary /usr/local/bin/talkkonnect
|
||||
sudo chmod +x /usr/local/bin/talkkonnect
|
||||
rm ~/talkkonnect-binary
|
||||
log_success "Binary installed to /usr/local/bin/talkkonnect"
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log_error "Failed to install binary"
|
||||
pause
|
||||
return 1
|
||||
# --- User Permissions -------------------------------------------------
|
||||
echo "[6/7] Setting up permissions..."
|
||||
if ! groups "$TARGET_USER" | grep -q input; then
|
||||
sudo usermod -a -G input "$TARGET_USER"
|
||||
log_success "Added $TARGET_USER to 'input' group"
|
||||
fi
|
||||
if ! groups "$TARGET_USER" | grep -q audio; then
|
||||
sudo usermod -a -G audio "$TARGET_USER"
|
||||
log_success "Added $TARGET_USER to 'audio' group"
|
||||
fi
|
||||
|
||||
log_success "talkkonnect built successfully"
|
||||
# --- Configuration ----------------------------------------------------
|
||||
echo "[7/7] Creating configuration..."
|
||||
|
||||
echo "[4/4] Creating configuration..."
|
||||
# Create config directory as target user
|
||||
if [ "$TARGET_USER" != "$USER" ]; then
|
||||
sudo -u "$TARGET_USER" mkdir -p "$CONFIG_DIR"
|
||||
else
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
fi
|
||||
|
||||
# Create config directory for logs
|
||||
sudo -u "$KIOSK_USER" mkdir -p /home/$KIOSK_USER/.config/talkkonnect
|
||||
|
||||
sudo -u "$KIOSK_USER" tee /home/$KIOSK_USER/talkkonnect.xml > /dev/null <<TKXML
|
||||
# Create config file with provided settings
|
||||
sudo tee "$CONFIG_DIR/talkkonnect.xml" > /dev/null <<EOFXML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="talkkonnect/xml">
|
||||
<global>
|
||||
<software>
|
||||
<settings outputdevice="default"
|
||||
logfilenameandpath="/home/$KIOSK_USER/.config/talkkonnect/talkkonnect.log"
|
||||
logfilenameandpath="$CONFIG_DIR/talkkonnect.log"
|
||||
logging="both"
|
||||
daemonize="false"
|
||||
cancelconnect="false"
|
||||
@@ -584,8 +575,7 @@ EOFOPUS
|
||||
<autoprovisioning enabled="false"/>
|
||||
</software>
|
||||
<hardware>
|
||||
<settings targetboard="pc"
|
||||
voiceactivitytimersecs="200"/>
|
||||
<settings targetboard="pc" voiceactivitytimersecs="200"/>
|
||||
<io>
|
||||
<pins enabled="false"/>
|
||||
</io>
|
||||
@@ -616,18 +606,11 @@ EOFOPUS
|
||||
|
||||
<audio>
|
||||
<input>
|
||||
<settings enabled="true"
|
||||
device="default"
|
||||
samplerate="48000"
|
||||
channels="1"
|
||||
codec="opus"
|
||||
framespersecond="50"/>
|
||||
<settings enabled="true" device="default" samplerate="48000"
|
||||
channels="1" codec="opus" framespersecond="50"/>
|
||||
</input>
|
||||
<output>
|
||||
<settings enabled="true"
|
||||
device="default"
|
||||
samplerate="48000"
|
||||
channels="1"/>
|
||||
<settings enabled="true" device="default" samplerate="48000" channels="1"/>
|
||||
</output>
|
||||
</audio>
|
||||
|
||||
@@ -636,48 +619,45 @@ EOFOPUS
|
||||
</ptt>
|
||||
|
||||
<voiceactivity enabled="true">
|
||||
<settings threshold="0.3"
|
||||
holdtimems="1000"
|
||||
holdtimeoutms="2000"/>
|
||||
<settings threshold="0.3" holdtimems="1000" holdtimeoutms="2000"/>
|
||||
</voiceactivity>
|
||||
|
||||
<sounds enabled="false"/>
|
||||
|
||||
<txtts enabled="false"/>
|
||||
|
||||
<smtp enabled="false"/>
|
||||
|
||||
<api enabled="false"/>
|
||||
|
||||
<printxml enabled="false"/>
|
||||
|
||||
</document>
|
||||
TKXML
|
||||
EOFXML
|
||||
|
||||
# Set ownership
|
||||
sudo chown -R "$TARGET_USER:$TARGET_USER" "$CONFIG_DIR"
|
||||
sudo chmod 755 "$CONFIG_DIR"
|
||||
sudo chmod 644 "$CONFIG_DIR/talkkonnect.xml"
|
||||
|
||||
# Create systemd service
|
||||
sudo tee /etc/systemd/system/talkkonnect.service > /dev/null <<EOF
|
||||
sudo tee /etc/systemd/system/talkkonnect.service > /dev/null <<EOFSVC
|
||||
[Unit]
|
||||
Description=talkkonnect Mumble Client
|
||||
After=network.target sound.target pipewire.service
|
||||
Wants=pipewire.service
|
||||
Description=TalkKonnect Headless Mumble Transceiver
|
||||
After=network-online.target sound.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$KIOSK_USER
|
||||
Environment="PATH=/usr/local/go/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/home/$KIOSK_USER"
|
||||
Environment="GOPATH=/home/$KIOSK_USER/go"
|
||||
WorkingDirectory=/home/$KIOSK_USER
|
||||
ExecStartPre=/bin/sleep 10
|
||||
ExecStart=/home/$KIOSK_USER/go/bin/talkkonnect -config /home/$KIOSK_USER/talkkonnect.xml
|
||||
User=$TARGET_USER
|
||||
Group=$TARGET_USER
|
||||
WorkingDirectory=$TARGET_HOME
|
||||
ExecStart=/usr/local/bin/talkkonnect -config $CONFIG_DIR/talkkonnect.xml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
Environment="XDG_RUNTIME_DIR=/run/user/$TARGET_UID"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
EOFSVC
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable talkkonnect
|
||||
@@ -685,24 +665,27 @@ EOF
|
||||
|
||||
sleep 3
|
||||
|
||||
log_success "talkkonnect installed"
|
||||
log_success "talkkonnect installed successfully!"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " Server: $server_addr:$server_port"
|
||||
echo " PTT Key: Spacebar"
|
||||
echo " Username: $tk_user"
|
||||
echo " Channel: $tk_channel"
|
||||
echo " Config: $CONFIG_DIR/talkkonnect.xml"
|
||||
echo " Binary: /usr/local/bin/talkkonnect"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo
|
||||
|
||||
# Show status
|
||||
echo
|
||||
if systemctl is-active --quiet talkkonnect; then
|
||||
log_success "Service started successfully"
|
||||
log_success "Service is running"
|
||||
echo "View logs: sudo journalctl -u talkkonnect -f"
|
||||
else
|
||||
log_warning "Service may have issues - check logs:"
|
||||
echo " sudo journalctl -u talkkonnect -n 50"
|
||||
log_warning "Service may have issues"
|
||||
echo "Check logs: sudo journalctl -u talkkonnect -n 50"
|
||||
fi
|
||||
|
||||
pause
|
||||
}
|
||||
|
||||
install_talkkonnect_only() {
|
||||
echo
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
|
||||
Executable
+1207
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,492 @@
|
||||
# This is the replacement install_talkkonnect_with_config() function
|
||||
# Copy this into setup_intercom.sh starting at line 197
|
||||
|
||||
install_talkkonnect_with_config() {
|
||||
local server_addr="$1"
|
||||
local server_port="$2"
|
||||
local tk_user="$3"
|
||||
local tk_pass="$4"
|
||||
local tk_channel="$5"
|
||||
|
||||
echo
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " INSTALLING TALKKONNECT CLIENT"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo
|
||||
echo "Using proven installation method (same as talkkonnect_complete_install.sh)..."
|
||||
echo
|
||||
|
||||
# Get target user info
|
||||
local TARGET_USER="$KIOSK_USER"
|
||||
local TARGET_UID=$(id -u "$TARGET_USER")
|
||||
local TARGET_HOME="/home/$TARGET_USER"
|
||||
local CONFIG_DIR="$TARGET_HOME/.config/talkkonnect"
|
||||
|
||||
# Verify home directory exists
|
||||
if [ ! -d "$TARGET_HOME" ]; then
|
||||
log_error "Home directory does not exist: $TARGET_HOME"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
|
||||
# --- System Prep ------------------------------------------------------
|
||||
echo "[1/7] Installing system dependencies..."
|
||||
sudo apt update
|
||||
sudo apt install -y wget git build-essential pkg-config \
|
||||
libasound2-dev libopus-dev libopus0 libopusfile-dev \
|
||||
libpipewire-0.3-dev libevdev-dev libopenal-dev alsa-utils
|
||||
|
||||
# --- Go Installation --------------------------------------------------
|
||||
echo "[2/7] Installing Go 1.24.1..."
|
||||
if ! command -v go &>/dev/null || ! go version | grep -q "go1.24"; then
|
||||
sudo rm -rf /usr/local/go
|
||||
wget -q https://go.dev/dl/go1.24.1.linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local -xzf go1.24.1.linux-amd64.tar.gz
|
||||
rm -f go1.24.1.linux-amd64.tar.gz
|
||||
sudo ln -sf /usr/local/go/bin/go /usr/bin/go
|
||||
export PATH="/usr/local/go/bin:$PATH"
|
||||
log_success "Go 1.24.1 installed"
|
||||
else
|
||||
log_success "Go already installed"
|
||||
fi
|
||||
|
||||
# --- Clone TalkKonnect ------------------------------------------------
|
||||
echo "[3/7] Cloning talkkonnect repository..."
|
||||
cd ~
|
||||
if [ -d "talkkonnect" ]; then
|
||||
rm -rf talkkonnect
|
||||
fi
|
||||
git clone https://github.com/talkkonnect/talkkonnect.git
|
||||
cd talkkonnect
|
||||
|
||||
# --- Patch gopus for x86_64 -------------------------------------------
|
||||
echo "[4/7] Applying x86_64 Opus patch..."
|
||||
go mod vendor
|
||||
|
||||
if [ -d "vendor/github.com/talkkonnect/gopus" ]; then
|
||||
cat > vendor/github.com/talkkonnect/gopus/opus_nonshared.go << 'EOFOPUS'
|
||||
// +build amd64,cgo 386,cgo
|
||||
|
||||
package gopus
|
||||
|
||||
// #cgo pkg-config: opus
|
||||
// #cgo LDFLAGS: -lm
|
||||
//
|
||||
// #include <stdio.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <opus.h>
|
||||
//
|
||||
// enum {
|
||||
// gopus_ok = OPUS_OK,
|
||||
// gopus_bad_arg = OPUS_BAD_ARG,
|
||||
// gopus_small_buffer = OPUS_BUFFER_TOO_SMALL,
|
||||
// gopus_internal = OPUS_INTERNAL_ERROR,
|
||||
// gopus_invalid_packet = OPUS_INVALID_PACKET,
|
||||
// gopus_unimplemented = OPUS_UNIMPLEMENTED,
|
||||
// gopus_invalid_state = OPUS_INVALID_STATE,
|
||||
// gopus_alloc_fail = OPUS_ALLOC_FAIL,
|
||||
// };
|
||||
//
|
||||
// enum {
|
||||
// gopus_application_voip = OPUS_APPLICATION_VOIP,
|
||||
// gopus_application_audio = OPUS_APPLICATION_AUDIO,
|
||||
// gopus_restricted_lowdelay = OPUS_APPLICATION_RESTRICTED_LOWDELAY,
|
||||
// gopus_bitrate_max = OPUS_BITRATE_MAX,
|
||||
// };
|
||||
//
|
||||
// void gopus_setvbr(OpusEncoder *encoder, int vbr) {
|
||||
// opus_encoder_ctl(encoder, OPUS_SET_VBR(vbr));
|
||||
// }
|
||||
//
|
||||
// void gopus_setbitrate(OpusEncoder *encoder, int bitrate) {
|
||||
// opus_encoder_ctl(encoder, OPUS_SET_BITRATE(bitrate));
|
||||
// }
|
||||
//
|
||||
// opus_int32 gopus_bitrate(OpusEncoder *encoder) {
|
||||
// opus_int32 bitrate;
|
||||
// opus_encoder_ctl(encoder, OPUS_GET_BITRATE(&bitrate));
|
||||
// return bitrate;
|
||||
// }
|
||||
//
|
||||
// void gopus_setapplication(OpusEncoder *encoder, int application) {
|
||||
// opus_encoder_ctl(encoder, OPUS_SET_APPLICATION(application));
|
||||
// }
|
||||
//
|
||||
// opus_int32 gopus_application(OpusEncoder *encoder) {
|
||||
// opus_int32 application;
|
||||
// opus_encoder_ctl(encoder, OPUS_GET_APPLICATION(&application));
|
||||
// return application;
|
||||
// }
|
||||
//
|
||||
// void gopus_encoder_resetstate(OpusEncoder *encoder) {
|
||||
// opus_encoder_ctl(encoder, OPUS_RESET_STATE);
|
||||
// }
|
||||
//
|
||||
// void gopus_decoder_resetstate(OpusDecoder *decoder) {
|
||||
// opus_decoder_ctl(decoder, OPUS_RESET_STATE);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Application int
|
||||
|
||||
const (
|
||||
Voip Application = C.gopus_application_voip
|
||||
Audio Application = C.gopus_application_audio
|
||||
RestrictedLowDelay Application = C.gopus_restricted_lowdelay
|
||||
)
|
||||
|
||||
const (
|
||||
BitrateMaximum = C.gopus_bitrate_max
|
||||
)
|
||||
|
||||
type Encoder struct {
|
||||
data []byte
|
||||
cEncoder *C.struct_OpusEncoder
|
||||
}
|
||||
|
||||
func NewEncoder(sampleRate, channels int, application Application) (*Encoder, error) {
|
||||
encoder := &Encoder{}
|
||||
encoder.data = make([]byte, int(C.opus_encoder_get_size(C.int(channels))))
|
||||
encoder.cEncoder = (*C.struct_OpusEncoder)(unsafe.Pointer(&encoder.data[0]))
|
||||
|
||||
ret := C.opus_encoder_init(encoder.cEncoder, C.opus_int32(sampleRate), C.int(channels), C.int(application))
|
||||
if err := getErr(ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return encoder, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) Encode(pcm []int16, frameSize, maxDataBytes int) ([]byte, error) {
|
||||
pcmPtr := (*C.opus_int16)(unsafe.Pointer(&pcm[0]))
|
||||
|
||||
data := make([]byte, maxDataBytes)
|
||||
dataPtr := (*C.uchar)(unsafe.Pointer(&data[0]))
|
||||
|
||||
encodedC := C.opus_encode(e.cEncoder, pcmPtr, C.int(frameSize), dataPtr, C.opus_int32(len(data)))
|
||||
encoded := int(encodedC)
|
||||
|
||||
if encoded < 0 {
|
||||
return nil, getErr(C.int(encodedC))
|
||||
}
|
||||
return data[0:encoded], nil
|
||||
}
|
||||
|
||||
func (e *Encoder) SetVbr(vbr bool) {
|
||||
var cVbr C.int
|
||||
if vbr {
|
||||
cVbr = 1
|
||||
} else {
|
||||
cVbr = 0
|
||||
}
|
||||
C.gopus_setvbr(e.cEncoder, cVbr)
|
||||
}
|
||||
|
||||
func (e *Encoder) SetBitrate(bitrate int) {
|
||||
C.gopus_setbitrate(e.cEncoder, C.int(bitrate))
|
||||
}
|
||||
|
||||
func (e *Encoder) Bitrate() int {
|
||||
return int(C.gopus_bitrate(e.cEncoder))
|
||||
}
|
||||
|
||||
func (e *Encoder) SetApplication(application Application) {
|
||||
C.gopus_setapplication(e.cEncoder, C.int(application))
|
||||
}
|
||||
|
||||
func (e *Encoder) Application() Application {
|
||||
return Application(C.gopus_application(e.cEncoder))
|
||||
}
|
||||
|
||||
func (e *Encoder) ResetState() {
|
||||
C.gopus_encoder_resetstate(e.cEncoder)
|
||||
}
|
||||
|
||||
type Decoder struct {
|
||||
data []byte
|
||||
cDecoder *C.struct_OpusDecoder
|
||||
channels int
|
||||
}
|
||||
|
||||
func NewDecoder(sampleRate, channels int) (*Decoder, error) {
|
||||
decoder := &Decoder{}
|
||||
decoder.data = make([]byte, int(C.opus_decoder_get_size(C.int(channels))))
|
||||
decoder.cDecoder = (*C.struct_OpusDecoder)(unsafe.Pointer(&decoder.data[0]))
|
||||
|
||||
ret := C.opus_decoder_init(decoder.cDecoder, C.opus_int32(sampleRate), C.int(channels))
|
||||
if err := getErr(ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoder.channels = channels
|
||||
|
||||
return decoder, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) Decode(data []byte, frameSize int, fec bool) ([]int16, error) {
|
||||
var dataPtr *C.uchar
|
||||
if len(data) > 0 {
|
||||
dataPtr = (*C.uchar)(unsafe.Pointer(&data[0]))
|
||||
}
|
||||
dataLen := C.opus_int32(len(data))
|
||||
|
||||
output := make([]int16, d.channels*frameSize)
|
||||
outputPtr := (*C.opus_int16)(unsafe.Pointer(&output[0]))
|
||||
|
||||
var cFec C.int
|
||||
if fec {
|
||||
cFec = 1
|
||||
} else {
|
||||
cFec = 0
|
||||
}
|
||||
|
||||
cRet := C.opus_decode(d.cDecoder, dataPtr, dataLen, outputPtr, C.int(frameSize), cFec)
|
||||
ret := int(cRet)
|
||||
|
||||
if ret < 0 {
|
||||
return nil, getErr(cRet)
|
||||
}
|
||||
return output[:ret*d.channels], nil
|
||||
}
|
||||
|
||||
func (d *Decoder) ResetState() {
|
||||
C.gopus_decoder_resetstate(d.cDecoder)
|
||||
}
|
||||
|
||||
func GetSamplesPerFrame(data []byte, samplingRate int) (int, error) {
|
||||
dataPtr := (*C.uchar)(unsafe.Pointer(&data[0]))
|
||||
cSamplingRate := C.opus_int32(samplingRate)
|
||||
cRet := C.opus_packet_get_samples_per_frame(dataPtr, cSamplingRate)
|
||||
return int(cRet), nil
|
||||
}
|
||||
|
||||
func CountFrames(data []byte) (int, error) {
|
||||
dataPtr := (*C.uchar)(unsafe.Pointer(&data[0]))
|
||||
cLen := C.opus_int32(len(data))
|
||||
|
||||
cRet := C.opus_packet_get_nb_frames(dataPtr, cLen)
|
||||
if err := getErr(cRet); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(cRet), nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrBadArgument = errors.New("bad argument")
|
||||
ErrSmallBuffer = errors.New("buffer is too small")
|
||||
ErrInternal = errors.New("internal error")
|
||||
ErrInvalidPacket = errors.New("invalid packet")
|
||||
ErrUnimplemented = errors.New("unimplemented")
|
||||
ErrInvalidState = errors.New("invalid state")
|
||||
ErrAllocFail = errors.New("allocation failed")
|
||||
ErrUnknown = errors.New("unknown error")
|
||||
)
|
||||
|
||||
func getErr(code C.int) error {
|
||||
switch code {
|
||||
case C.gopus_ok:
|
||||
return nil
|
||||
case C.gopus_bad_arg:
|
||||
return ErrBadArgument
|
||||
case C.gopus_small_buffer:
|
||||
return ErrSmallBuffer
|
||||
case C.gopus_internal:
|
||||
return ErrInternal
|
||||
case C.gopus_invalid_packet:
|
||||
return ErrInvalidPacket
|
||||
case C.gopus_unimplemented:
|
||||
return ErrUnimplemented
|
||||
case C.gopus_invalid_state:
|
||||
return ErrInvalidState
|
||||
case C.gopus_alloc_fail:
|
||||
return ErrAllocFail
|
||||
default:
|
||||
return ErrUnknown
|
||||
}
|
||||
}
|
||||
EOFOPUS
|
||||
log_success "Opus patch applied"
|
||||
fi
|
||||
|
||||
# --- Build TalkKonnect ------------------------------------------------
|
||||
echo "[5/7] Building talkkonnect (this may take a few minutes)..."
|
||||
cd ~/talkkonnect/cmd/talkkonnect
|
||||
|
||||
export CGO_ENABLED=1
|
||||
export CGO_CFLAGS="$(pkg-config --cflags opus)"
|
||||
export CGO_LDFLAGS="$(pkg-config --libs opus) -lm"
|
||||
|
||||
go build -mod=vendor -v -o ~/talkkonnect-binary . 2>&1 | tail -20
|
||||
|
||||
if [ ! -f ~/talkkonnect-binary ]; then
|
||||
log_error "Build failed!"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Stop any running instances
|
||||
if systemctl is-active --quiet talkkonnect 2>/dev/null; then
|
||||
sudo systemctl stop talkkonnect
|
||||
fi
|
||||
if pgrep -x talkkonnect > /dev/null; then
|
||||
sudo pkill -9 talkkonnect
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Install binary
|
||||
sudo cp ~/talkkonnect-binary /usr/local/bin/talkkonnect
|
||||
sudo chmod +x /usr/local/bin/talkkonnect
|
||||
rm ~/talkkonnect-binary
|
||||
log_success "Binary installed to /usr/local/bin/talkkonnect"
|
||||
|
||||
# --- User Permissions -------------------------------------------------
|
||||
echo "[6/7] Setting up permissions..."
|
||||
if ! groups "$TARGET_USER" | grep -q input; then
|
||||
sudo usermod -a -G input "$TARGET_USER"
|
||||
log_success "Added $TARGET_USER to 'input' group"
|
||||
fi
|
||||
if ! groups "$TARGET_USER" | grep -q audio; then
|
||||
sudo usermod -a -G audio "$TARGET_USER"
|
||||
log_success "Added $TARGET_USER to 'audio' group"
|
||||
fi
|
||||
|
||||
# --- Configuration ----------------------------------------------------
|
||||
echo "[7/7] Creating configuration..."
|
||||
|
||||
# Create config directory as target user
|
||||
if [ "$TARGET_USER" != "$USER" ]; then
|
||||
sudo -u "$TARGET_USER" mkdir -p "$CONFIG_DIR"
|
||||
else
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
fi
|
||||
|
||||
# Create config file with provided settings
|
||||
sudo tee "$CONFIG_DIR/talkkonnect.xml" > /dev/null <<EOFXML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="talkkonnect/xml">
|
||||
<global>
|
||||
<software>
|
||||
<settings outputdevice="default"
|
||||
logfilenameandpath="$CONFIG_DIR/talkkonnect.log"
|
||||
logging="both"
|
||||
daemonize="false"
|
||||
cancelconnect="false"
|
||||
simplexwithvox="false"
|
||||
nextserverindex="0"/>
|
||||
<autoprovisioning enabled="false"/>
|
||||
</software>
|
||||
<hardware>
|
||||
<settings targetboard="pc" voiceactivitytimersecs="200"/>
|
||||
<io>
|
||||
<pins enabled="false"/>
|
||||
</io>
|
||||
</hardware>
|
||||
</global>
|
||||
|
||||
<accounts>
|
||||
<account name="default" default="true">
|
||||
<serverandport>$server_addr:$server_port</serverandport>
|
||||
<username>$tk_user</username>
|
||||
<password>$tk_pass</password>
|
||||
<insecure>true</insecure>
|
||||
<register>false</register>
|
||||
<certificate></certificate>
|
||||
<channel>$tk_channel</channel>
|
||||
<ident></ident>
|
||||
<tokens enabled="false"></tokens>
|
||||
<voicetargets enabled="false">
|
||||
<id id="1" iscurrent="false" name="default">
|
||||
<channels></channels>
|
||||
<users></users>
|
||||
</id>
|
||||
</voicetargets>
|
||||
</account>
|
||||
</accounts>
|
||||
|
||||
<beacon enabled="false"/>
|
||||
|
||||
<audio>
|
||||
<input>
|
||||
<settings enabled="true" device="default" samplerate="48000"
|
||||
channels="1" codec="opus" framespersecond="50"/>
|
||||
</input>
|
||||
<output>
|
||||
<settings enabled="true" device="default" samplerate="48000" channels="1"/>
|
||||
</output>
|
||||
</audio>
|
||||
|
||||
<ptt enabled="false">
|
||||
<usbkeyboard enabled="false"/>
|
||||
</ptt>
|
||||
|
||||
<voiceactivity enabled="true">
|
||||
<settings threshold="0.3" holdtimems="1000" holdtimeoutms="2000"/>
|
||||
</voiceactivity>
|
||||
|
||||
<sounds enabled="false"/>
|
||||
<txtts enabled="false"/>
|
||||
<smtp enabled="false"/>
|
||||
<api enabled="false"/>
|
||||
<printxml enabled="false"/>
|
||||
|
||||
</document>
|
||||
EOFXML
|
||||
|
||||
# Set ownership
|
||||
sudo chown -R "$TARGET_USER:$TARGET_USER" "$CONFIG_DIR"
|
||||
sudo chmod 755 "$CONFIG_DIR"
|
||||
sudo chmod 644 "$CONFIG_DIR/talkkonnect.xml"
|
||||
|
||||
# Create systemd service
|
||||
sudo tee /etc/systemd/system/talkkonnect.service > /dev/null <<EOFSVC
|
||||
[Unit]
|
||||
Description=TalkKonnect Headless Mumble Transceiver
|
||||
After=network-online.target sound.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$TARGET_USER
|
||||
Group=$TARGET_USER
|
||||
WorkingDirectory=$TARGET_HOME
|
||||
ExecStart=/usr/local/bin/talkkonnect -config $CONFIG_DIR/talkkonnect.xml
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
Environment="XDG_RUNTIME_DIR=/run/user/$TARGET_UID"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOFSVC
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable talkkonnect
|
||||
sudo systemctl start talkkonnect
|
||||
|
||||
sleep 3
|
||||
|
||||
log_success "talkkonnect installed successfully!"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " Server: $server_addr:$server_port"
|
||||
echo " Username: $tk_user"
|
||||
echo " Channel: $tk_channel"
|
||||
echo " Config: $CONFIG_DIR/talkkonnect.xml"
|
||||
echo " Binary: /usr/local/bin/talkkonnect"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo
|
||||
|
||||
# Show status
|
||||
if systemctl is-active --quiet talkkonnect; then
|
||||
log_success "Service is running"
|
||||
echo "View logs: sudo journalctl -u talkkonnect -f"
|
||||
else
|
||||
log_warning "Service may have issues"
|
||||
echo "Check logs: sudo journalctl -u talkkonnect -n 50"
|
||||
fi
|
||||
|
||||
pause
|
||||
}
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
# ======================================================================
|
||||
# File: update_setup_intercom.sh
|
||||
# Purpose: Replace talkkonnect installation function with proven method
|
||||
# ======================================================================
|
||||
|
||||
echo "Updating setup_intercom.sh with proven talkkonnect installation method..."
|
||||
echo ""
|
||||
|
||||
# Backup original
|
||||
cp setup_intercom.sh setup_intercom.sh.backup
|
||||
echo "[+] Created backup: setup_intercom.sh.backup"
|
||||
|
||||
# The function starts at line 197 and ends at line 732 (before install_talkkonnect_only)
|
||||
# We'll extract the header, insert the new function, then append the rest
|
||||
|
||||
# Get everything before the function (lines 1-196)
|
||||
head -n 196 setup_intercom.sh > setup_intercom.sh.new
|
||||
|
||||
# Add the new function
|
||||
cat setup_intercom_talkkonnect_function.txt >> setup_intercom.sh.new
|
||||
|
||||
# Add everything after line 732 (from install_talkkonnect_only onwards)
|
||||
tail -n +733 setup_intercom.sh >> setup_intercom.sh.new
|
||||
|
||||
# Replace the original
|
||||
mv setup_intercom.sh.new setup_intercom.sh
|
||||
chmod +x setup_intercom.sh
|
||||
|
||||
echo "[+] Updated setup_intercom.sh with proven installation method"
|
||||
echo ""
|
||||
echo "Changes made:"
|
||||
echo " ✓ Uses working Opus patch from talkkonnect_complete_install.sh"
|
||||
echo " ✓ Installs to /usr/local/bin/talkkonnect"
|
||||
echo " ✓ Config in ~/.config/talkkonnect/"
|
||||
echo " ✓ Sets <insecure>true</insecure> by default (for self-signed certs)"
|
||||
echo " ✓ Proper XDG_RUNTIME_DIR in systemd service"
|
||||
echo " ✓ Enables service automatically"
|
||||
echo " ✓ Better error handling and user feedback"
|
||||
echo ""
|
||||
echo "The old version is saved as: setup_intercom.sh.backup"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user