[教程]在 Linux 中优先使用高质量编码(LDAC等)以解决蓝牙音质问题

结合 DeepSeek 生成的脚本,自己做了一些改动和错误修正:

#!/bin/bash
# 蓝牙音频优化脚本 v2025.6
# 功能:自动切换蓝牙设备到高质量音频模式(A2DP Sink),按配置文件给出的优先级来激活

# 初始化设置
DEBUG_MODE=false
LOG_FILE="/tmp/bluetooth_audio_optimizer.log"
export LC_ALL=C
# 设置正确的环境变量
export XDG_RUNTIME_DIR="/run/user/$(id -u)"

# 等待 PulseAudio/Pipewire 服务启动
MAX_ATTEMPTS=10
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
    if pactl info &>/dev/null; then
        break
    fi
    sleep 1
    ATTEMPT=$((ATTEMPT+1))
done

if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
    echo "$(date) - 错误:无法连接到 PulseAudio/Pipewire 服务" >&2
    exit 1
fi
# 记录日志函数
log() {
    local msg="$1"
    if $DEBUG_MODE; then
        echo -e "$(date +'%F %T'): $msg" | tee -a "$LOG_FILE"
    else
        echo -e "$msg"
    fi
}

# === 核心功能:语言无关的设备识别 ===

# 获取蓝牙MAC地址(完全语言无关)
get_bt_mac() {
    pactl list sinks | grep -m1 -oP 'api\.bluez5\.address\s*=\s*"\K([0-9A-F:]{17})'
}

# 获取蓝牙卡路径(兼容所有语言环境)
get_bt_card_path() {
    local mac
    mac=$(pactl list sinks | grep -m1 -oP 'api\.bluez5\.address\s*=\s*"\K([0-9A-F:]{17})')
    [ -n "$mac" ] && echo "bluez_card.${mac//:/_}"
}

# === A2DP/LDAC状态检测 ===

# 检测当前配置文件
get_active_profile() {
    local card_path="$1"
    pactl list cards | awk -v card="$card_path" '
        $0 ~ " " card {
            active = 0
            while (getline) {
                if (/Active Profile:/) {
                    print $3
                    exit
                }
                if (/^$/ || /^Card/) break
            }
        }
    '
}

# 检测当前编码器
get_active_codec() {
    pactl list sinks | awk '
        /api\.bluez5\.codec = "/ { 
            match($0, /"([^"]+)"/, a); 
            if (a[1] != "") print a[1]
        }' | head -1
}

# 检测支持的编码列表
get_supported_codecs() {
    local card_path="$1"
    pactl list cards | grep -A50 " $card_path" | 
        grep -oP 'bluez5\.codecs = \[\K[^\]]+' | 
        tr -d '"' | tr ',' '\n' | sed 's/^ //'
}

# === A2DP模式切换(兼容多Profile)===

switch_to_a2dp() {
    local card_path="$1"
    declare -a profile_entries
    local profile_name="" priority=""
	declare -i -x retval=1
    log "检测可用的A2DP配置并准备按优先级排序..."
    
    # 解析所有可用A2DP配置
    pactl list cards | awk -v card="$card_path" '
        $0 ~ " " card {
            in_card = 1
            next
        }
        in_card && /Profiles:/ {
            in_profiles = 1
            next
        }
        in_profiles && /^$/ {
            exit # 遇到空行结束解析
        }
        in_profiles && /available:[[:space:]]*yes/ && /a2dp-sink/ {
            # 提取配置名
            profile_name = $0
            sub(/:.*/, "", profile_name)
            gsub(/^[[:space:]]+/, "", profile_name)
            
            # 提取优先级
            match($0, /priority:[[:space:]]*([0-9]+)/, m)
            priority = m[1]
            
            if (priority == "") priority = 0 # 缺省值
            
            printf "%d:%s\n", priority, profile_name
        }
    ' | sort -t: -k1,1nr | while IFS=: read -r priority profile; do
        
        # 记录发现的配置
        # profile_entries+=("$priority:$profile")
        if [[ "$retval" == "1" ]]; then		
			log "发现高优先级配置 [优先级:${priority}]: ${profile}"		
			if pactl set-card-profile "$card_path" "$profile" 2>/dev/null; then
	            sleep 0.5 # 等待协议生效
	            log "✓ 成功激活配置: ${profile}"
	            
	            # 验证配置激活
	            local active_profile
	            active_profile=$(get_active_profile "$card_path")
	            
	            if [[ "$active_profile" == "$profile" ]]; then
	                log "✓ 配置状态已确认"
	                retval=0
	            else
	                log "⚠️ 配置激活但状态不匹配,实际配置: ${active_profile}"
	            fi
	        else
	            log "⚠️ 配置激活失败: ${profile}"
			fi
        fi
    done
    # 所有配置尝试失败
	current_profile=$(get_active_profile "$card_path")
	if [[ ! "$current_profile" == *"a2dp-sink"* ]]; then
	    log "${RED}错误:所有可用A2DP配置尝试均失败${NC}"
    		log "请检查设备兼容性:pactl list cards | grep -A30 ' $card_path'"
		return 1
	fi
    return 0
}
# === 设备重连辅助函数 ===

reconnect_bluetooth_device() {
    local mac="$1"
    log "重置蓝牙连接..."
    
    (
        echo "disconnect $mac"
        sleep 3
        echo "connect $mac"
        sleep 5
        echo "quit"
    ) | bluetoothctl > /dev/null 2>&1
    
    log "设备重连完成"
}

# === 主控制流程 ===

main() {
    log "${BLUE}=== $(date -Iseconds) 蓝牙音频优化开始 ==="
    
    # 获取设备信息
    local bt_mac
    bt_mac=$(get_bt_mac)
    if [ -z "$bt_mac" ]; then
        log "${RED}错误:未检测到已连接的蓝牙耳机"
        return 1
    fi
    log "设备MAC地址: $bt_mac"
    
    local card_path
    card_path=$(get_bt_card_path "$bt_mac")
    if [ -z "$card_path" ]; then
        log "${RED}错误:无法识别蓝牙设备路径"
        return 1
    fi
    log "设备路径: $card_path"
    
    # 检查当前配置
    local current_profile
    current_profile=$(get_active_profile "$card_path")
    local current_codec
    current_codec=$(get_active_codec "$card_path")
    log "当前配置: ${current_profile:-未知} | 编码: ${current_codec:-未知}"
    
    # 自动切换到高质量模式
    if [[ ! "$current_profile" == *"a2dp-sink"* ]]; then
        log "正在切换到高质量音频模式..."
        if ! switch_to_a2dp "$card_path"; then
            log "${YELLOW}配置切换失败,尝试设备重连..."
            reconnect_bluetooth_device "$bt_mac"
            sleep 3
            switch_to_a2dp "$card_path" || {
                log "${RED}错误:无法切换到A2DP模式"
                return 1
            }
        fi
        sleep 2 # 等待配置稳定
        log "${GREEN}✓ 已启用高质量音频配置"
    else
        log "${GREEN}✓ 已在高质量音频模式"
    fi
    
    log "${BLUE}=== 优化完成 ==="
}

# === 颜色定义 ===
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 执行主函数
if [ "$1" = "--debug" ]; then
    DEBUG_MODE=true
fi

main

后续步骤:

  • 保存脚本,然后就是加执行权限和目录的写入权限。
  • 执行 crontab -e 将脚本写入到计划任务里,每分钟检查一次。
* * * * * /opt/ldac/ldac.sh > /opt/ldac/ldac.log 2>&1

滚动至顶部