Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions skeleton/SYSTEM/tg5040/bin/suspend
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,41 @@ sleep_retval=1

asound_state_dir=/tmp/asound-suspend

read_wakeup_count() {
local tmp="/tmp/wakeup_count.$$"
local pid

cat /sys/power/wakeup_count >"$tmp" 2>/dev/null &
pid=$!

# Guard against kernels that can block indefinitely on wakeup_count reads.
for _ in 1 2 3 4 5; do
kill -0 "$pid" 2>/dev/null || break
usleep 200000
done

if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null
wait "$pid" 2>/dev/null
rm -f "$tmp"
return 1
fi

wait "$pid" 2>/dev/null
cat "$tmp" 2>/dev/null
rm -f "$tmp"
return 0
}

log_wakeup_sources() {
local label="$1"
>&2 echo " [$label] wakeup_count: $(cat /sys/power/wakeup_count 2>/dev/null)"
local wakeup_count
wakeup_count="$(read_wakeup_count 2>/dev/null || true)"
if [ -n "$wakeup_count" ]; then
>&2 echo " [$label] wakeup_count: $wakeup_count"
else
>&2 echo " [$label] wakeup_count: unavailable (read timed out)"
fi
if [ -f /sys/power/pm_wakeup_irq ]; then
>&2 echo " [$label] last wakeup IRQ: $(cat /sys/power/pm_wakeup_irq 2>/dev/null)"
fi
Expand Down Expand Up @@ -101,7 +133,7 @@ for i in $(seq 1 $sleep_max_tries); do

# Synchronize with wakeup events: read wakeup_count and write it back.
# If a wakeup event occurred since reading, the write fails and we retry.
wakeup_count=$(cat /sys/power/wakeup_count 2>/dev/null)
wakeup_count="$(read_wakeup_count 2>/dev/null || true)"
if [ -n "$wakeup_count" ]; then
if ! echo "$wakeup_count" >/sys/power/wakeup_count 2>/dev/null; then
>&2 echo "Deep sleep: wakeup event detected before sleep (wakeup_count=$wakeup_count), retrying in 1 second"
Expand Down
20 changes: 15 additions & 5 deletions skeleton/SYSTEM/tg5040/etc/bluetooth/bt_init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
bt_hciattach="hciattach"
TRIMUI_MODEL=`strings /usr/trimui/bin/MainUI | grep ^Trimui`
DEVICE_NAME="$TRIMUI_MODEL (NextUI)"
RFKILL_BIN="/mnt/SDCARD/.system/tg5040/bin/rfkill.elf"

unblock_bluetooth() {
if [ -x "$RFKILL_BIN" ]; then
"$RFKILL_BIN" unblock bluetooth
elif command -v rfkill.elf >/dev/null 2>&1; then
Comment thread
frysee marked this conversation as resolved.
rfkill.elf unblock bluetooth
else
rfkill unblock bluetooth
fi
}

reset_bluetooth_power() {
echo 0 > /sys/class/rfkill/rfkill0/state;
Expand Down Expand Up @@ -36,7 +47,7 @@ start_hci_attach() {
}

start_bt() {
rfkill.elf unblock bluetooth
unblock_bluetooth

if [ -d "/sys/class/bluetooth/hci0" ];then
echo "Bluetooth init has been completed!!"
Expand All @@ -61,8 +72,7 @@ start_bt() {

a=`ps | grep bluealsa | grep -v grep`
[ -z "$a" ] && {
# bluealsa -p a2dp-source --keep-alive=-1 &
bluealsa -p a2dp-source &
bluealsa -p a2dp-source --keep-alive=10 &
sleep 1
# Power on adapter
bluetoothctl power on 2>/dev/null
Expand Down Expand Up @@ -98,7 +108,7 @@ start_bt() {
}

ble_start() {
rfkill.elf unblock bluetooth
unblock_bluetooth

if [ -d "/sys/class/bluetooth/hci0" ];then
echo "Bluetooth init has been completed!!"
Expand Down Expand Up @@ -173,4 +183,4 @@ case "$1" in
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
esac
36 changes: 34 additions & 2 deletions skeleton/SYSTEM/tg5050/bin/suspend
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,41 @@ sleep_retval=

asound_state_dir=/tmp/asound-suspend

read_wakeup_count() {
local tmp="/tmp/wakeup_count.$$"
local pid

cat /sys/power/wakeup_count >"$tmp" 2>/dev/null &
pid=$!

# Guard against kernels that can block indefinitely on wakeup_count reads.
for _ in 1 2 3 4 5; do
kill -0 "$pid" 2>/dev/null || break
usleep 200000
done

if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null
wait "$pid" 2>/dev/null
rm -f "$tmp"
return 1
fi

wait "$pid" 2>/dev/null
cat "$tmp" 2>/dev/null
rm -f "$tmp"
return 0
}

log_wakeup_sources() {
local label="$1"
>&2 echo " [$label] wakeup_count: $(cat /sys/power/wakeup_count 2>/dev/null)"
local wakeup_count
wakeup_count="$(read_wakeup_count 2>/dev/null || true)"
if [ -n "$wakeup_count" ]; then
>&2 echo " [$label] wakeup_count: $wakeup_count"
else
>&2 echo " [$label] wakeup_count: unavailable (read timed out)"
fi
if [ -f /sys/power/pm_wakeup_irq ]; then
>&2 echo " [$label] last wakeup IRQ: $(cat /sys/power/pm_wakeup_irq 2>/dev/null)"
fi
Expand Down Expand Up @@ -93,7 +125,7 @@ for i in $(seq 1 $sleep_max_tries); do

# Synchronize with wakeup events: read wakeup_count and write it back.
# If a wakeup event occurred since reading, the write fails and we retry.
wakeup_count=$(cat /sys/power/wakeup_count 2>/dev/null)
wakeup_count="$(read_wakeup_count 2>/dev/null || true)"
if [ -n "$wakeup_count" ]; then
if ! echo "$wakeup_count" >/sys/power/wakeup_count 2>/dev/null; then
>&2 echo "Deep sleep: wakeup event detected before sleep (wakeup_count=$wakeup_count), retrying in 1 second"
Expand Down
5 changes: 2 additions & 3 deletions skeleton/SYSTEM/tg5050/etc/bluetooth/bt_init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ start_bt() {

a=`ps | grep bluealsa | grep -v grep`
[ -z "$a" ] && {
# bluealsa -p a2dp-source --keep-alive=-1 &
bluealsa -p a2dp-source &
bluealsa -p a2dp-source --keep-alive=10 &
sleep 1
# Power on adapter
bluetoothctl power on 2>/dev/null
Expand Down Expand Up @@ -156,4 +155,4 @@ case "$1" in
;;
esac

exit 0
exit 0
40 changes: 39 additions & 1 deletion workspace/all/audiomon/audiomon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ void recoverPreviousConfig() {

connected_a2dp_mac = content.substr(pos, end - pos);
log("Restored BT state from .asoundrc: " + connected_a2dp_mac);
SetAudioSink(AUDIO_SINK_BLUETOOTH);
}

std::string pathToMac(const std::string& path) {
Expand Down Expand Up @@ -173,6 +174,36 @@ bool isUsbAudioDevice(struct udev_device* dev) {
return false;
}

// Returns false if the device is truly gone (query fails or Connected=false).
// Used to filter out transient disconnects BlueZ emits during A2DP negotiation.
bool isDeviceConnected(DBusConnection* conn, const std::string& path) {
DBusMessage* msg = dbus_message_new_method_call("org.bluez", path.c_str(),
"org.freedesktop.DBus.Properties", "Get");
if (!msg) return false;

const char* iface = "org.bluez.Device1";
const char* prop = "Connected";
dbus_message_append_args(msg,
DBUS_TYPE_STRING, &iface,
DBUS_TYPE_STRING, &prop,
DBUS_TYPE_INVALID);

DBusMessage* reply = dbus_connection_send_with_reply_and_block(conn, msg, 1000, nullptr);
dbus_message_unref(msg);
if (!reply) return false;

DBusMessageIter iter, variant;
dbus_message_iter_init(reply, &iter);
dbus_message_iter_recurse(&iter, &variant);

dbus_bool_t connected = false;
if (dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_BOOLEAN)
dbus_message_iter_get_basic(&variant, &connected);

dbus_message_unref(reply);
return connected;
}

bool hasUUID(DBusConnection* conn, const std::string& path, const std::string& uuid) {
DBusMessage* msg = dbus_message_new_method_call("org.bluez", path.c_str(), "org.freedesktop.DBus.Properties", "Get");
if (!msg) return false;
Expand Down Expand Up @@ -235,6 +266,13 @@ void handleDeviceDisconnected(DBusConnection* conn, const std::string& path) {
// device's service cache may already be gone, causing hasUUID to return false
// and silently skip the audio switch-back.
if (hasUUID(conn, path, UUID_A2DP) || (!connected_a2dp_mac.empty() && mac == connected_a2dp_mac)) {
// BlueZ emits Connected=false/true in rapid succession during A2DP profile
// negotiation (e.g. JustWorksRepairing). Verify the device is truly gone
// before tearing down the transport keep-alive and audio routing.
if (isDeviceConnected(conn, path)) {
log("Transient disconnect for " + mac + " (device still connected per BlueZ), ignoring");
return;
}
log("Audio device disconnected: " + mac);
connected_a2dp_mac.clear();
clearAudioFile();
Expand All @@ -245,7 +283,7 @@ void handleDeviceDisconnected(DBusConnection* conn, const std::string& path) {
if (system("pidof bluealsa > /dev/null 2>&1") != 0) break;
usleep(100000); // 100ms
}
system("bluealsa -p a2dp-source &");
system("bluealsa -p a2dp-source --keep-alive=10 &");

// TODO: we could maintain a stack here, if USBC was connected before and restore that instead
SetAudioSink(AUDIO_SINK_DEFAULT);
Expand Down
7 changes: 6 additions & 1 deletion workspace/all/common/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2888,7 +2888,12 @@ void SND_init(double sample_rate, double frame_rate)

LOG_info("We now have audio device #%d\n", snd.device_id);

snd.frame_count = ((float)spec_out.freq / SCREEN_FPS) * 8; // buffer size based on sample rate out (times 12 samples headroom)
// Increase headroom for BT + high-rate cores (e.g. 65536 Hz GBA input)
// to reduce underruns/crackle after resampling.
int buffer_headroom = 8;
if (PLAT_btIsConnected() && sample_rate > 48000.0)
buffer_headroom = 12;
snd.frame_count = ((float)spec_out.freq / SCREEN_FPS) * buffer_headroom;
perf.buffer_size = snd.frame_count;
snd.sample_rate_in = sample_rate;
snd.sample_rate_out = spec_out.freq;
Expand Down
12 changes: 9 additions & 3 deletions workspace/tg5040/platform/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,15 @@ void PLAT_setRumble(int strength) {
}

int PLAT_pickSampleRate(int requested, int max) {
// bluetooth: allow limiting the maximum to improve compatibility
if(PLAT_bluetoothConnected())
return MIN(requested, CFG_getBluetoothSamplingrateLimit());
// bluetooth: allow limiting the maximum to improve compatibility.
// Some cores request non-standard rates (>48k). For those, prefer 44.1k
// over 48k to avoid unstable A2DP renegotiation on certain headsets.
if(PLAT_bluetoothConnected()) {
int limit = MIN(max, CFG_getBluetoothSamplingrateLimit());
if (requested > 48000)
return MIN(44100, limit);
return MIN(requested, limit);
}

return MIN(requested, max);
}
Expand Down
12 changes: 9 additions & 3 deletions workspace/tg5050/platform/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,15 @@ void PLAT_setRumble(int strength) {
}

int PLAT_pickSampleRate(int requested, int max) {
// bluetooth: allow limiting the maximum to improve compatibility
if(PLAT_bluetoothConnected())
return MIN(requested, CFG_getBluetoothSamplingrateLimit());
// bluetooth: allow limiting the maximum to improve compatibility.
// Some cores request non-standard rates (>48k). For those, prefer 44.1k
// over 48k to avoid unstable A2DP renegotiation on certain headsets.
if(PLAT_bluetoothConnected()) {
int limit = MIN(max, CFG_getBluetoothSamplingrateLimit());
if (requested > 48000)
return MIN(44100, limit);
return MIN(requested, limit);
}

return MIN(requested, max);
}
Expand Down
Loading