天天看點

安卓藍牙sco vohci設計實作

​ 大家都知道, sco/esco可以分别通過pcm/i2s和vohci來支援. 最近, 某廠因為慣性設計, PCB線路圖漏了PCM連接配接并不改硬體, 是以隻能要求支援vohci. 再加上公司自身也要做好這種儲備, 是以就在安卓平台上移植并開發了vohci功能.

​ 除了安卓需要開發這個功能外, 藍牙晶片本身也是需要支援才可以的. 目前驗證過博通/RK/AIC藍牙晶片支援. RTK看驅動代碼應該以前是開發過的, 提供的思路也很好. 但不知為何,現在RTK回應是不支援了…

1 PCM通路原理

首先, 我們看PCM通路下, 整個安卓平台支援起來的原理:

以上, sco/esco是直接通過kernel的alsa驅動, 寫到藍牙控制器的pcm接口上了. 現在vohci沒有了pcm硬體接口, 按照正常想法, 需要bluedroid收發語音資料, 并參考tinyalsa_hal或者a2dp alsa應用接口, 開發播放和錄音的子產品, 但這樣開發起來應該比較費時, 而且bluedroid改動應該比較多, 不怎麼好.

2 Vohci通路原理

參考原先移植過的藍牙語音遙控器驅動應用和代碼, 語音資料可以走bluedroid再到kernel, 由kernel再對接到tinyalsa_hal. 這樣可以充分利用原來的通路和架構, 邏輯也比較清晰.

這裡面重要的工作, 是kernel怎麼對接bluedroid和tinyalsa_hal. 是以可以開發一個虛拟的alsa聲霸卡驅動, 讓bluedroid發送hci rx語音資料到asla聲霸卡, 并從聲霸卡接收語音資料, 發送到藍牙控制器中.

2.1 bluedroid處理

Bluedroid處理的關鍵, 是收取語音的HCI資料, 發送到kernel, 反之亦然. 是以, 這裡通過一個檔案節點(這裡是字元檔案), 把收到的控制器語音資料發送到alsa驅動; 并通過這個節點, 收取alsa驅動的資料, 發送到藍牙控制器晶片.

可能大家會問, 上面說的是讀寫同一個檔案節點, 那讀寫的資料會不會是同一份? 不會的, 具體下一節描述.

2.2 kernel alsa虛拟聲霸卡驅動

為了同tinyalsa_hal互動, 就必須有一個聲霸卡可供讀寫資料. 是以必須實作一個虛拟的vohci聲霸卡驅動. 同時, alsa資料内容需要綁定到字元檔案裝置節點上, 應用寫聲霸卡的資料綁定到字元裝置讀取通道上, 而應用讀聲霸卡的語音資料則綁定到字元裝置寫通道上.

以上虛拟聲霸卡和字元裝置因為要綁定, 是以還有一根雙向的虛線, 由于markdown序列圖不好畫, 是以作罷.

2.3 tinyalsa_hal處理

在RK平台上, 聲霸卡一般是兩聲道, 由于虛拟聲霸卡驅動實作的也是兩聲道, 是以tinyalsa_hal無需特别處理, 隻需要把聲霸卡加到聲霸卡即可. 當然, 這裡前提是tinyalsa_hal已經支援藍牙hfp sco pcm語音, 如果沒有支援, 參考前面那篇<…16k … HFP PCM語音通話支援>那篇.

代碼比較簡單, 如下:

diff --git a/tinyalsa_hal/audio_hw.c b/tinyalsa_hal/audio_hw.c
index 441f5f0..e9f5922 100755
--- a/tinyalsa_hal/audio_hw.c
+++ b/tinyalsa_hal/audio_hw.c
@@ -325,6 +325,7 @@ struct dev_proc_info SPDIF_OUT_NAME[] =
 struct dev_proc_info BT_OUT_NAME[] =
 {
     {"rockchipbt", NULL,},
+    {"sndscohci", NULL},/*keep it behind rockchipbt*/
     {NULL, NULL}, /* Note! Must end with NULL, else will cause crash */
 };
 
@@ -359,7 +360,8 @@ struct dev_proc_info HDMI_IN_NAME[] =
 
 struct dev_proc_info BT_IN_NAME[] =
 {
-    {"rockchipbt", NULL},
+    {"rockchipbt", NULL,},
+    {"sndscohci", NULL},/*keep it behind rockchipbt*/
     {NULL, NULL}, /* Note! Must end with NULL, else will cause crash */
 };
 
diff --git a/tinyalsa_hal/audio_hw.h b/tinyalsa_hal/audio_hw.h
index f23f529..7b8963a 100755
--- a/tinyalsa_hal/audio_hw.h
+++ b/tinyalsa_hal/audio_hw.h
@@ -190,15 +190,15 @@ struct pcm_config pcm_config_hfp = {
 struct pcm_config pcm_config_ap_sco = {
     .channels = 2,
     .rate = 8000,
-    .period_size = 160,
-    .period_count = 4,
+    .period_size = 480,
+    .period_count = 2,
 };
 
 struct pcm_config pcm_config_in_bt = {
     .channels = 2,
     .rate = 8000,
-    .period_size = 120,
-    .period_count = 4,
+    .period_size = 480,
+    .period_count = 2,
     .format = PCM_FORMAT_S16_LE,
 };
           

3 代碼實作

3.1 bluedroid

這部分代碼早期bluedroid是有的, 但是google後來删除了. 不過, ESP的bluedroid代碼還是保留了, 目前還能支援SCO的HCI流控, buffer的協商等.隻不過ESP語音的處理是bluedroid發送到應用層處理, 而我們這裡是和/dev/hci_sco_dev裝置檔案互動, 并驅動内部轉到虛拟聲霸卡驅動.

需要注意的是, RK平台是兩聲道聲霸卡, 而HCI是單聲道, 是以bluedroid需要做好聲道資料的轉換工作.

另外, 我們添加了一個persist.bluetooth.vohci的設定, 設定到enabled, bluedroid自動走vohci, 反之走PCM. 這樣達到PCM和vohci的自動相容.

3.2 虛拟聲霸卡驅動

聲霸卡驅動實作為加載并sco連接配接後, 才會看到聲霸卡, 不打開是看不見聲霸卡的, 這樣上層tinyalsa_hal可以相容PCM sco聲霸卡的情況.

同樣要注意, RK平台tinyalsa_hal的兩聲道立體聲實作, 為了避免上層不必要的改動, 聲霸卡驅動也實作為兩聲道立體聲.

3.3 tinyalsa_hal

如2.3節說明.

3.4 其他

安卓平台有些權限需要添加, 具體在device/rockchip目錄下添加.

目的是加載聲霸卡驅動後, 自動修改/dev/hci_sco_dev為bluetooth:net_bt使用者組權限. 其他還有selinux的一些設定, 就不贅述.

4 結束

原理應該比較清楚了. 大家應該可以開始實作了. 虛拟聲霸卡的驅動代碼如果不會, 可以參考rtk的USB藍牙聲霸卡驅動; 或者aic的聲霸卡驅動.

最後, 如果您不想改, 并可能想支援各種藍牙HCI模組,又恰好是RK的客戶, 可以嘗試聯系RK, 擷取相應代碼.