Integrate proven talkkonnect installation into setup_intercom

Completely replaced the install_talkkonnect_with_config() function in
setup_intercom.sh with the proven method from talkkonnect_complete_install.sh.

Key improvements:
- Uses working Opus patch for x86_64 architecture
- Installs to /usr/local/bin/talkkonnect (not ~/go/bin)
- Config in ~/.config/talkkonnect/ (proper XDG location)
- Sets <insecure>true</insecure> by default (handles self-signed certs)
- Proper XDG_RUNTIME_DIR in systemd service for PipeWire/audio
- Automatically enables service (starts on boot)
- Better progress feedback and error handling
- Uses Go 1.24.1 (latest stable)

The function now:
1. Installs all dependencies correctly
2. Builds with proper Opus library integration
3. Creates config with user's server/credentials from prompts
4. Sets up systemd service properly
5. Enables and starts service automatically

This makes setup_intercom.sh a complete, reliable one-stop solution
that uses the same proven method as talkkonnect_complete_install.sh
while maintaining the interactive prompt workflow.

Included files:
- setup_intercom.sh - Updated with new function
- setup_intercom.sh.backup - Backup of original
- setup_intercom_talkkonnect_function.txt - Reference for the new function
- update_setup_intercom.sh - Script used to perform the replacement
This commit is contained in:
Claude
2025-11-23 16:50:04 +00:00
parent be26312ca9
commit c07ec69eaf
4 changed files with 1869 additions and 147 deletions
+128 -147
View File
@@ -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,58 +209,58 @@ install_talkkonnect_with_config() {
echo " INSTALLING TALKKONNECT CLIENT"
echo "═══════════════════════════════════════════════════════════════"
echo
echo "Using improved talkkonnect installation method..."
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
@@ -318,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
@@ -468,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 {
@@ -501,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"
@@ -586,8 +575,7 @@ EOFOPUS
<autoprovisioning enabled="false"/>
</software>
<hardware>
<settings targetboard="pc"
voiceactivitytimersecs="200"/>
<settings targetboard="pc" voiceactivitytimersecs="200"/>
<io>
<pins enabled="false"/>
</io>
@@ -618,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>
@@ -638,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
@@ -687,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 "═══════════════════════════════════════════════════════════════"
+1207
View File
File diff suppressed because it is too large Load Diff
+492
View File
@@ -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
}
+42
View File
@@ -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 ""