diff --git a/Startup/deltarune.webm b/Startup/deltarune.webm index 6d78625..c77a1c1 100644 Binary files a/Startup/deltarune.webm and b/Startup/deltarune.webm differ diff --git a/Startup/shell.qml b/Startup/shell.qml index 0319ce6..a64a26c 100644 --- a/Startup/shell.qml +++ b/Startup/shell.qml @@ -24,12 +24,14 @@ PanelWindow { aboveWindows: true focusable: true - property string bluetoothTargetName: "JBL Tune 525BT" - property int bluetoothTimeoutMs: 5000 + property var bluetoothTargetNames: ["JBL Tune 525BT", "JBL GO"] + property int bluetoothConnectAttemptMs: 3000 property bool waitingForBluetooth: true property bool animationLaunchScheduled: false property bool animationStarted: false property bool bluetoothConnectRequested: false + property int bluetoothTargetAttemptIndex: 0 + property string bluetoothActiveTargetName: "" function bluetoothModelCount() { if (bluetoothDeviceRepeater) @@ -54,44 +56,67 @@ PanelWindow { return ""; } - function findTargetBluetoothDevice() { + function findBluetoothDeviceByName(targetName) { for (var i = 0; i < bluetoothModelCount(); i++) { var device = bluetoothDeviceAt(i); var deviceName = bluetoothDeviceName(device); console.log("Startup BT: candidate", i, deviceName, device ? Boolean(device.connected) : false); - if (deviceName === bluetoothTargetName) + if (deviceName === targetName) return device; } - console.log("Startup BT: target not found", bluetoothTargetName, "count", bluetoothModelCount()); + console.log("Startup BT: target not found", targetName, "count", bluetoothModelCount()); return null; } + function findConnectedPreferredBluetoothDevice() { + for (var i = 0; i < bluetoothTargetNames.length; i++) { + var device = findBluetoothDeviceByName(bluetoothTargetNames[i]); + if (device && device.connected) + return device; + } + return null; + } + + function resetBluetoothAttemptState() { + bluetoothConnectRequested = false; + bluetoothTargetAttemptIndex = 0; + bluetoothActiveTargetName = ""; + bluetoothConnectAttemptTimer.stop(); + } + function maybeStartBluetoothOrSkip() { - console.log("Startup BT: maybeStartBluetoothOrSkip", "waiting", waitingForBluetooth, "requested", bluetoothConnectRequested); + console.log("Startup BT: maybeStartBluetoothOrSkip", "waiting", waitingForBluetooth, "requested", bluetoothConnectRequested, "active", bluetoothActiveTargetName, "attemptIndex", bluetoothTargetAttemptIndex); if (!waitingForBluetooth) return; - const device = findTargetBluetoothDevice(); - if (!device) { - console.log("Startup BT: no matching device yet"); - return; - } - - console.log("Startup BT: matched device", bluetoothDeviceName(device), "connected", Boolean(device.connected)); - - if (device.connected) { - console.log("Startup BT: already connected, starting animation"); + const connectedDevice = findConnectedPreferredBluetoothDevice(); + if (connectedDevice) { + console.log("Startup BT: preferred device connected, starting animation", bluetoothDeviceName(connectedDevice)); beginAnimation(); return; } - if (!bluetoothConnectRequested) { - bluetoothConnectRequested = true; - console.log("Startup BT: requesting connect", bluetoothDeviceName(device)); - device.connect(); - } else { - console.log("Startup BT: connect already requested, waiting"); + if (bluetoothConnectRequested) { + console.log("Startup BT: connect already requested, waiting on", bluetoothActiveTargetName); + return; } + + for (var i = bluetoothTargetAttemptIndex; i < bluetoothTargetNames.length; i++) { + var targetName = bluetoothTargetNames[i]; + var targetDevice = findBluetoothDeviceByName(targetName); + if (!targetDevice) + continue; + + bluetoothConnectRequested = true; + bluetoothTargetAttemptIndex = i; + bluetoothActiveTargetName = targetName; + bluetoothConnectAttemptTimer.restart(); + console.log("Startup BT: requesting connect", targetName); + targetDevice.connect(); + return; + } + + console.log("Startup BT: no preferred devices available yet"); } function beginAnimation() { @@ -100,7 +125,7 @@ PanelWindow { return; waitingForBluetooth = false; bluetoothRetryTimer.stop(); - bluetoothTimeoutTimer.stop(); + bluetoothConnectAttemptTimer.stop(); animationLaunchScheduled = true; startupDelayTimer.restart(); } @@ -127,7 +152,7 @@ PanelWindow { } Component.onCompleted: { - console.log("Startup: overlay completed", "btCount", bluetoothModelCount(), "target", bluetoothTargetName); + console.log("Startup: overlay completed", "btCount", bluetoothModelCount(), "targets", JSON.stringify(bluetoothTargetNames)); maybeStartBluetoothOrSkip(); } @@ -161,7 +186,7 @@ PanelWindow { function onCountChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices count changed", overlay.bluetoothModelCount(), "repeater", bluetoothDeviceRepeater.count); - overlay.bluetoothConnectRequested = false; + overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } @@ -169,7 +194,7 @@ PanelWindow { function onModelReset() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices model reset"); - overlay.bluetoothConnectRequested = false; + overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } @@ -177,7 +202,7 @@ PanelWindow { function onRowsInserted() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows inserted"); - overlay.bluetoothConnectRequested = false; + overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } @@ -185,7 +210,7 @@ PanelWindow { function onRowsRemoved() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows removed"); - overlay.bluetoothConnectRequested = false; + overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } @@ -209,14 +234,17 @@ PanelWindow { function onConnectedChanged() { console.log("Startup BT: connected changed", overlay.bluetoothDeviceName(device), Boolean(device ? device.connected : false)); - if (overlay.waitingForBluetooth) + if (overlay.waitingForBluetooth) { + if (Boolean(device ? device.connected : false)) + overlay.bluetoothConnectAttemptTimer.stop(); overlay.maybeStartBluetoothOrSkip(); + } } function onNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: name changed", overlay.bluetoothDeviceName(device)); - overlay.bluetoothConnectRequested = false; + overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } @@ -224,7 +252,7 @@ PanelWindow { function onDeviceNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: deviceName changed", overlay.bluetoothDeviceName(device)); - overlay.bluetoothConnectRequested = false; + overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } @@ -238,7 +266,7 @@ PanelWindow { autoPlay: false videoOutput: videoOutput playbackRate: 1 - audioOutput: AudioOutput {} + audioOutput: startupAudioOutput onPlaybackStateChanged: a => { console.log("Startup: playback state changed", player.playbackState); if (player.playbackState === MediaPlayer.StoppedState) @@ -248,7 +276,7 @@ PanelWindow { Timer { id: startupDelayTimer - interval: 1000 + interval: 1500 repeat: false onTriggered: { console.log("Startup: startup delay elapsed, playing video"); @@ -270,22 +298,37 @@ PanelWindow { return; } console.log("Startup BT: retry timer fired"); - overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } Timer { - id: bluetoothTimeoutTimer - interval: overlay.bluetoothTimeoutMs - running: true + id: bluetoothConnectAttemptTimer + interval: overlay.bluetoothConnectAttemptMs + running: false repeat: false onTriggered: { - console.log("Startup BT: timeout reached", overlay.bluetoothTimeoutMs); - overlay.beginAnimation(); + console.log("Startup BT: connect attempt timed out", overlay.bluetoothActiveTargetName); + overlay.bluetoothConnectRequested = false; + overlay.bluetoothActiveTargetName = ""; + overlay.bluetoothTargetAttemptIndex = Math.min(overlay.bluetoothTargetAttemptIndex + 1, overlay.bluetoothTargetNames.length); + overlay.maybeStartBluetoothOrSkip(); } } + MediaDevices { + id: mediaDevices + onDefaultAudioOutputChanged: { + console.log("Startup Audio: default output changed", mediaDevices.defaultAudioOutput.description); + startupAudioOutput.device = mediaDevices.defaultAudioOutput; + } + } + + AudioOutput { + id: startupAudioOutput + device: mediaDevices.defaultAudioOutput + } + VideoOutput { id: videoOutput anchors.fill: parent