1. 程式人生 > >android藍芽程式設計 重點知識 SPP A2DP UUID

android藍芽程式設計 重點知識 SPP A2DP UUID

藍芽程式設計很簡單,步驟如下:

(1).獲得本機藍芽裝置:BluetoothAdapter mBTAdp = BluetoothAdapter.getDefaultAdapter();;

(2)註冊一個發現裝置的回撥函式

getActivity().registerReceiver(mBroadcastReceiver,intentFilter);

(3)開始搜尋裝置:mBTAdp.startDiscovery();在Listview中顯示結果,點選具體條目時,返回藍芽地址:mAddr 

(4)通過mAddr獲得遠端裝置:BluetoothDevice mBTRemoteDev  = mBTAdp.getRemoteDevice(mAddr); //其中mAddr

(5)通過遠端裝置的物件,獲得Socket:mBTSocket = mBTDevInThread.createRfcommSocketToServiceRecord(uuid);

網上有很多參考程式碼,例如:http://blog.csdn.net/xzongyuan/article/details/39318649。

本文總結研究android藍芽程式設計中的疑惑:

1.rfcomm有什麼作用?它是藍芽客戶端和服務端的Socket通道。裝置pair(配對後),在android中只是bondedDevice,還沒有通訊通道。因此,RFCOMM是瞭解藍芽通訊的基礎。參考http://www.go-gddq.com/down/2013-06/13062113071155.pdf

RFCOMM是一個簡單傳輸協議,其目的為了解決如何在兩個不同裝置上的應用程式之間保證一條完整的通訊路徑,並在它們之間保持一通訊段的問題。

2.BluetoothServerSocket是什麼東西?它返回BluetoothSocket,類似於SocketServer,TCP通訊業會用到ServerSocket。它的作用就是監聽其他藍芽裝置的接入,一旦有藍芽裝置主動發起建立RFCOMM通道,它就會返回一個"新的"對應的BluetoothSocket。

使用辦法,因為是監聽,所以函式名是listen

BluetoothServerSocket tmp ;
tmp =mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
mmServerSocket =tmp;
mmServerSocket呼叫accept進行監聽,是阻塞操作,一旦有裝置發起請求,就會返回一個Socket,這個Socket也是阻塞操作,因此需要新建一個獨立執行緒進行處理。
while(true){
 BluetoothSocket  socket;
            socket = mmServerSocket.accept();                 // If a connection was accepted         
  if (socket!= null){               
	// Do work to manage the connection (in a separate thread)                
	manageConnectedSocket(socket);                
	mmServerSocket.close();               
	break;        
   }     
}


3.UUID是什麼?一個uuid對應一種service,在藍芽4.0的datasheet中有定義UUID的格式,哪個bit代表什麼功能都有清楚定義,而且有很多常用的服務已經根據datasheet定義好了值,所以你上網會查到UUID表;不過,理論上,只要兩臺裝置UUID是一致的,就能建立socket。統一格式,只是提高裝置間的相容性,避免不同service碰巧被定義為相同的uuid了。android提供的Sample——BluetoothChat就是自定義的。而一般情況,還是得符合UUID的規範,例如我設計的SPP協議通訊,這是藍芽資料傳輸的基本協議,我只需要查到SPP的uuid為:

static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";

我就不用管其他裝置的情況了。例如我設計的一塊開發板,壓根就沒提供uuid,只是提供spp的api,如果沒有統一的uuid,我就無法進行通訊了。

4.藍芽傳輸和藍芽音訊如何同時開啟?這是我的一個疑問,我用createRfcommSocketToServiceRecord建立了一個Socket連結請求,但是成功後,我只能發資料,不能把手機音訊傳到開發板。我在想,必定有某個地方建立了音訊Socket,可能是A2DP,使得音訊可以順利傳輸。經過百般搜尋,終於找到個不錯的連結

https://www.bluetooth.org/zh-cn/specification/assigned-numbers/service-discovery

AudioSource 0x110A 高階音訊分發配置檔案(A2DP) 服務類
AudioSink 0x110B 高階音訊分發配置檔案(A2DP) 服務類
SerialPort 0x1101 串列埠配置檔案(SPP)
注:SPP 1.0版中的SDP記錄範例並不包含BluetoothProfileDescriptorList屬性,但部分實施中也可將此UUID用於配置檔案識別符號。
服務類/配置檔案
從上面的定義可以看到,AudioSource和AudioSink就是A2DP的配置名稱,我把SPP的UUID改一下就得到A2DP的UUID了

static final String SPP_UUID                = "00001101-0000-1000-8000-00805F9B34FB";

static final String A2DP_SRC_UUID  = "0000110A-0000-1000-8000-00805F9B34FB";
static final String A2DP_SINK_UUID  = "0000110B-0000-1000-8000-00805F9B34FB";

5.Socket connect faild怎麼處理?我之前在用getBondedDevices獲得已經pair的裝置,然後連線,當只有一臺設別時,不需要辨別。但當我安裝APP到一臺已經配對了2個裝置的Tablet上,發現,Socket Connect time out 了。原因是,getBondedDevice返回的是一個BluetoothDevice裝置Set,我剛好獲得另外一個BluetoothDevice(不是我想連線的那臺),而另一臺裝置藍芽沒開啟,以至於我建立的Socket連線不上。

6.怎麼同時啟動SPP和音訊A2DP功能?研究了1天,終於找到辦法了,用反射機制把Android隱藏API調用出來,即可,實現程式碼:

http://blog.csdn.net/xzongyuan/article/details/39344953

參考資料:

如果能翻牆,最好去官網看Reference API,講的比較全。

http://blog.csdn.net/flyfish10000/article/details/5796168

http://blog.csdn.net/xzongyuan/article/details/39318649