藍牙電話之HFP-通話

藍牙電話之HFP-通話


文章《藍牙電話之HFP-連接》裡已經對HFP的連接進行了簡單分析,這篇主要和大家探討下通話場景下的相關操作,如撥打、接聽、掛斷電話(AG側、HF側)、切換聲道這幾個場景。


藍牙通話中主要涉及到以下兩個方面的關注點:獲取當前的通話狀態和傳送通話聲音,這兩個關注點直接決定了藍牙電話應用是否能正常工作。


獲取當前的通話狀態:主要通過AT命令"+CIEV"和"+CLCC"來獲取AG側的通話狀態和信息,HF側不管如何操作都要以AG側的狀態為準。


+CIEV命令的定義如下:

藍牙電話之HFP-通話


該指令是AG側主動將通話狀態更新到HF側的,依賴於"AT+CMER"來打開AG側的更新標誌位

藍牙電話之HFP-通話


從+CIEV命令的定義不難看出,和<value>所對應的的值都在"AT+CIND=?"命令中定義清楚的,感興趣的同學可以自行查看。通話中以下三個indicator需要重點關注/<value>

藍牙電話之HFP-通話

indicator 對應的值分別是

callsetup:電話建立過程,值為2

call:通話成功,值為1

callheld:電話保持的過程,值為7


value對應的值的含義如圖所示:

藍牙電話之HFP-通話

這樣ind + value的不同組合就可以代表不同的電話場景流程。


+CLCC命令的定義如下:

藍牙電話之HFP-通話

該指令需要HF側主動通過"AT+CLCC"指令告知AG側將當前的電話信息通過"+CLCC"發送過來。接收到"+CLCC"指令,HF側就可以知道當前的電話狀態和號碼等關鍵信息。


傳送通話聲音:藍牙電話應用最根本的目的是傳輸雙方的通話聲音,既要將遠端的輸入語音經本端手機的電話模塊接收到後再通過藍牙模塊AG側傳送到HF側播放出來,也要將本端的輸出語音通過HF側傳送到AG側,再通過本端手機的電話模塊發送出去。傳輸通話音頻的通道主要是通話鏈路也就是大家平常說的SCO或eSCO鏈路。

SCO或eSCO的建立依賴於HFP協議的Service Level Connection連接成功(詳情請參考《藍牙電話之HFP-連接》),再通過HCI命令建立通話音頻鏈路。

音頻鏈路當前有兩種編碼方式,分別為CVSD和mSBC。採用哪種編碼方式是有建立連接的雙方協商決定的,AT命令"+BRSF"中HF和AG雙方會分別發送自己支持的features給對方,如果雙方都支持編碼協商即標誌位Codec Negotiation,HF側主動通過"AT+BAC"的AT命令告知AG側兩種編碼方式的編號分別為:1-CVSD,2-mSBC,並且在建立音頻鏈路時多采用mSBC的編碼方式,否則都是CVSD編碼。

音頻鏈路連接對應的HCI命令為:Setup Synchronous Connection Command,如果本端Controller支持Enhanced Setup Synchronous Connection指令(詳情請查看Read Local Supported Commands Command的HCI命令),則創建連接的HCI命令為:Enhanced Setup Synchronous Connection Command

兩種創建音頻鏈路的HCI為:

藍牙電話之HFP-通話

藍牙電話之HFP-通話


音頻鏈路SCO或eSCO建立成功後,通話語音就能在AG、HF兩側正常傳輸了。


以上就是藍牙電話通話中需要了解的最重要的兩點,HF側的上層藍牙電話應用只需監聽BluetoothHeadsetClient中定義的如下兩個廣播就可以執行上層邏輯。

<code>    /**
* Intent sent whenever state of a call changes.
*
*

It includes:
* {@link #EXTRA_CALL},
* with value of {@link BluetoothHeadsetClientCall} instance,
* representing actual call state.


*/
public static final String ACTION_CALL_CHANGED =
"android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";/<code>


<code>\t\t/**
* Intent sent whenever audio state changes.
*
*

It includes two mandatory extras:
* {@link BluetoothProfile#EXTRA_STATE},
* {@link BluetoothProfile#EXTRA_PREVIOUS_STATE},
* with possible values:
* {@link #STATE_AUDIO_CONNECTING},
* {@link #STATE_AUDIO_CONNECTED},
* {@link #STATE_AUDIO_DISCONNECTED}


*

When <code>EXTRA_STATE/<code> is set
* to

/<code>STATE_AUDIO_CONNECTED,
* it also includes {@link #EXTRA_AUDIO_WBS}
* indicating wide band speech support.
*/
public static final String ACTION_AUDIO_STATE_CHANGED =
"android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";


接下來再詳細分析下這兩個廣播是如何一步步發送出去的,見如下時序圖。

藍牙電話之HFP-通話

廣播上報時序圖


下面以場景為視角簡單分析上述兩點在其中的作用及流程,編碼方式都是mSBC。

1、 撥打電話-AG

撥打電話大體分為撥號、響鈴、通話這三個部分,狀態變化後AG側都會主動通知HF側,HF側再通過"AT+CLCC"獲取詳細的電話參數信息。

藍牙電話之HFP-通話

2、 撥打電話-HF

HF側的撥打電話和AG側比較起來就多了一個步驟,通過AT命令"ATD"將需要撥打的電話信息發送到AG側,然後通過手機的電話模塊呼出電話。

藍牙電話應用層調用BluetoothHeadsetClient.dial()後,只需監聽相應廣播即可。

藍牙電話之HFP-通話

3、 接聽電話

來電接聽這裡還需要我們瞭解In-Band Ring來電響鈴功能,該功能支持在來電時將手機上設置的響鈴鈴聲通過藍牙傳送到HF側,從而在設備端播出該鈴聲。AG在"BRSF"交互features時,如果In-Band Ring Tone Capability標誌位設置成 true 則代表支持該功能,所以藍牙電話應用根據自身的配置來進行取捨。

接聽來電的方式就兩種,手機上接聽或車機來電提醒界面(車機語音控制)接聽,這樣的話HF側的操作流程對比AG側也就是多了步將接聽的動作以AT命令"ATA"發送給手機執行接聽流程。

車載端接聽來電則藍牙電話應用層調用BluetoothHeadsetClient.acceptCall()後監聽相應廣播即可。

HF側接聽來電-In-Band Ringing

藍牙電話之HFP-通話

HF側接聽來電-No In-Band Ringing

藍牙電話之HFP-通話

AG側接聽來電

藍牙電話之HFP-通話


4、 掛斷電話

電話掛斷和接聽來電類似,HF側操作也是通過AT命令"AT+CHUP"將掛斷電話操作告知AG側,真正的電話掛斷操作是有手機的電話模塊來執行的。

藍牙電話應用層只需要調用BluetoothHeadsetClient.terminateCall()完監聽AG_CALL_CHANGE廣播即可。

藍牙電話之HFP-通話

5、 切換聲道

聲道的切換就是通話語音從手機端切到車載端播放,或反之從車載端切到手機端播放。由於通話音頻數據的傳輸是在SCO鏈路上進行的,所以建立SCO就代表通話語音切到車載端播放,斷開SCO就代表通話語音切到手機上播放。

建立和斷開SCO的操作雙方都可以操作,從而HF側的藍牙電話應用只需關心BluetoothHeadsetClient中的connectAudio()和disconnectAudio()這兩個接口就可實現上述功能。

藍牙電話之HFP-通話


藍牙電話通話的相關分析大概就這樣了,對此感興趣的同學可以私信我一起探討哦。


分享到:


相關文章: