利用KBSA解決Windows下藍芽音箱自動關閉問題(AASBS專案改良)

一直以來都使用用藍芽音箱來做為自己Windows電腦的音源播放設備,用起來一切都好,但有一個非常惱人的問題,普遍來說藍芽喇叭會因為節能省電的問題,就算播放設備已經透過藍芽配對完成,過了一段時間若沒有播放音樂就會自動關閉(關機、斷線),這問題幾乎發生在很多品牌的藍芽音箱上(畢竟音箱最初的目的是被設計用來可攜,所以節能是必要因素),而低價的藍芽喇叭通常沒有設計讓你可以取消自動關機的功能。

改進AASBS專案進化成KBSA專案,解決藍芽音箱自動關閉問題

前專案Anti Auto-Shutdown of Bluetooth Speakers;AASBS其實運行上也沒有太大的問題,但因為當初架構設計上有許多簡化之處,導致有時無法觀測Windows Service的運行狀態,在執行期也很難進行同步的聲音播放測試,因此把整個專案打掉重建改成KBSA專案。

新的KBSA專案把本來載入外部音源檔案改成由程式動態產生正弦波,並添加了NamePipe方便觀察Windows Services在執行期的行為,並重新針對許多可能崩潰錯誤之處進行錯誤攔截,最後並優化了播放器的資源釋放,最終反映編譯過的總體積相較AASBS上縮小了88.5%之多,KBSA執行檔只有14KB。

原始碼就不在此討論了,本文章只討論KBSA的實際使用方式。

下載並安裝KBSA;Keep Bluetooth Speaker Awake

  1. 點選KBSA下載並進行解壓縮後,你應該會看到KeepBluetoothSpeakerAwake.exe

  2. KeepBluetoothSpeakerAwake.exe放置到你喜歡的資料夾,例如在%USERPROFILE%\Documents底下建立一個資料夾放置檔案是不錯的選擇。

  3. 接下來其實都透過這個exe檔呈現的指令辦事就好了,除了檔案權限設定外,他也會幫你計算路徑並指示你如何送出指令來安裝成Windows Service,如下圖所示:

  1. 完成後基本上就可以看到服務已經在背景開始執行了。

驗證KBSA是否可以在本機播放喇叭

這支KeepBluetoothSpeakerAwake.exe另外提供本機測試運行模式,當你在cmd視窗執行其實就是進入Windows Console mode,你可以透過輸入頻率與播放時間長度來測試程式碼是否可以在本機播放聲音,這樣就可以確定程式碼的運行邏輯是沒有問題的,當然前提是你的藍芽喇叭已經配對完成了。

如果在這個模式沒有輸入任何參數只有按下Enter的話,就會聽到預設的一個短音嗶聲

透過NamePipe具名管道查看服務執行狀況

Windows Service的運行狀態通常是很難觀察的,尤其是當你沒有在服務裡面寫入任何Log檔案的情況下,這時候KBSA內建的NamePipe架構就可以派上用場了。請把下列的Script貼到檔案命名為KBSA.ps1即可查看服務的運行狀態:

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

$pipeServer = "."
$pipeName = "KeepBluetoothSpeakerAwake"
$bufferSize = 1024
$disconnectTimeout = 180
Write-Host "*** NamedPipe Client ***`n"
$disconnectStartTime = $null

while ($true) {
  Write-Host ("Connecting to named pipe ($pipeName)...")
  try {
    $pipe = New-Object System.IO.Pipes.NamedPipeClientStream($pipeServer, $pipeName, [System.IO.Pipes.PipeDirection]::In)
    $pipe.Connect(5000)
    $disconnectStartTime = $null
    Write-Host "Connected, starting to receive messages...`n"
    while ($pipe.IsConnected) {
      $buffer = New-Object byte[] $bufferSize
      $bytesRead = $pipe.Read($buffer, 0, $bufferSize)
      if ($bytesRead -gt 0) {
        $receivedData = [System.Text.Encoding]::UTF8.GetString($buffer, 0, $bytesRead)
        [Console]::Write($receivedData)
      }
    }
    Write-Host "`nServer disconnected.`n"
    $pipe.Dispose()
    $disconnectStartTime = Get-Date
  }
  catch {
    if (-not $disconnectStartTime) {
      $disconnectStartTime = Get-Date
    }
    if ($pipe) {
      $pipe.Dispose()
    }
  }

  $elapsed = (Get-Date) - $disconnectStartTime
  if ($elapsed.TotalSeconds -ge $disconnectTimeout) {
    Write-Host ("Disconnection time exceeded $disconnectTimeout seconds. Exiting.")
    break
  }
  else {
    Write-Host ("Waiting for next connection. Elapsed time: {0:N0} seconds.`n" -f $elapsed.TotalSeconds)
    Start-Sleep -Seconds 5
  }
}

如果藍芽喇叭還是持續會自動關機

如果你安裝服務後發現,好像有時候這個服務有用(例如Windows未登入的時候藍芽喇叭也不會自動關機),但反而是有時候在桌面工作的時候會不定時自己關機,甚至在觀看有聲音的Youtube時候自己竟然關機了。這時候有兩個問題點可以請您檢查一下:

關閉藍芽喇叭的允許獨佔模式

有些藍芽喇叭的驅動程式會有一個允許應用程式獨佔這個裝置的選項,這個選項如果被勾選了的話,當你在桌面上播放有聲音的影片或是音樂時候(這隻程式有可能占用音訊),會有可能引發服務失效,導致藍芽喇叭還是會自動關機!請把這個選項取消勾選後再試試看。

移除Spotify桌面APP

如果你有在使用Spotify桌面APP的話,請把他移除掉改從Web Browser端播放。因為Spotify桌面APP會使用Bit-Perfect、Spotify Connect等技術,目前已經證實會占用音訊,甚至你停止播放但讓Spotify在背景待命時候,他仍會持續播放靜音音訊來佔用喇叭,假設你目前仍然在觀看Youtube持續播放聲音,藍芽喇叭仍會被這個靜音的訊號誤導自己沒有正在播放聲音,於是就自己關機了。

Kbsa BluetoothSpeakerAutoShutdown WindowsService KeepBluetoothSpeakerAwake NamedPipeMonitoring SineWaveAudioGeneration AudioPlaybackValidation ServiceRuntimeObservation ConsoleModeTesting ResourceReleaseOptimization AudioExclusiveMode SpotifyDesktopApp BitPerfectAudio OccupiedAudioChannel SilentAudioInterference