Android 音频设备管理
Android 音頻設備管理
一、簡介
在即使語音或者實時視頻通話中,時常需要提供以下功能:
-
手動切換聽筒或者揚聲器;
-
連接藍牙時,音頻需轉到藍牙;
-
連接有線耳機時,音頻需轉到有線耳機;
Android實現以上功能需要用到以下幾個類:
-
AudioManager:提供對音量和振鈴模式控制的訪問;
-
BluetoothManager:藍牙管理器,用于獲取BluetoothAdapter藍牙本地適配器的實例,并進行整體藍牙管理;
-
BluetoothAdapter:藍牙本地適配器,用于管理藍牙的搜索、連接等功能;
-
BluetoothHeadset:藍牙免提的配置文件,需要又聽又說則需要使用此配置類。
藍牙配置文件還有兩個:
BluetoothA2dp:藍牙立體聲音傳輸配置文件,需要只聽可以使用此配置類。
BluetoothHealth:藍牙健康設備配置文件,需要與健康設備(如心率檢測儀、血糖儀、溫度計、臺秤等)進行通信,則可以使用此配置類。
這兩個藍牙配置文件,這里用不上,所以就簡單介紹下,有興趣的可以自行學習。
二、相關類用法介紹
1. AudioManager
1)獲取此類實例
通過Context中的getSystemService接口獲取
private AudioManager mAudioManager = null; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);2)設置音頻模式
AudioManager中的setMode方法,用于設置當前的音頻的播放模式。以下是幾種常用音頻模式:
- MODE_NORMAL : 普通模式,既不是鈴聲模式也不是通話模式
- MODE_RINGTONE : 鈴聲模式
- MODE_IN_CALL : 通話模式
- MODE_IN_COMMUNICATION : 通信模式,包括音/視頻,VoIP通話.(3.0加入的,與通話模式類似)
即時語言一般使用MODE_IN_COMMUNICATION 通信模式,Android 3.0之前使用MODE_IN_CALL 通話模式。實際開發過程中,有一些機型在3.0之后也需要使用MODE_IN_CALL 通話模式,但只是少數。
if(mAudioManager != null){mAudioManager.setMOde(AudioManager.MODE_IN_COMMUNICATION); }在使用完后,需要恢復原來的模式,這里我默認恢復到MODE_NORMAL普通模式。
if(mAudioManager != null){mAudioManager.setMOde(AudioManager.MODE_NORMAL); }最好保證在同個進程中調用setMode方法。如果在不同進程中調用setMode方法,系統會將上一個調用setMode的進程的藍牙SCO數據斷開,就會導致藍牙數據斷連。
3)切換聽筒、揚聲器
AudioManager中的setSpeakerphoneOn方法,用于設置揚聲器是否打開。
// 設置聽筒出聲 if(mAudioManager != null){mAudioManager.setSpeakerphoneOn(false); }// 設置揚聲器出聲 if(mAudioManager != null){mAudioManager.setSpeakerphoneOn(true); }并且可以使用isSpeakerphoneOn方法判斷當前揚聲器是否打開
if(mAudioManager != null){if(mAudioManager.isSpeakerphoneOn()){// 目前是揚聲器出聲}else{// 目前是聽筒出聲} }切換音頻到有線耳機的操作跟切換聽筒的操作一致,只需調用setSpeakerphoneOn(false); 即可
2. BluetoothAdapter
1)獲取此類實例
- sdk版本大于等于18時,使用BluetoothManager獲取BluetoothAdapter
- sdk版本小于18時,使用BluetoothAdapter.getDefaultAdapter()獲取
2)判斷本地藍牙適配器是否打開
BluetoothAdapter 中的isEnabled方法,用于判斷手機本地的藍牙適配器是否打開。如果返回值為false,則代表手機本地的適配器沒有打開,也就不可能有藍牙連接。
if(mBluetoothAdapter != null && mBluetoothAdapter.isEnable()){// 藍牙適配器已經打開 }else{// 手機不支持藍牙或沒有打開藍牙適配器 }3. BluetoothHeadset
1)獲取此類實例
- 首先需要進行藍牙協議切換,調用BluetoothAdapter 的getProfileProxy方法,將藍牙協議切換為BluetoothProfile.HEADSET協議。getProfileProxy方法需要傳入的參數:當前上下文Context,藍牙協議監聽回調函數BluetoothProfile.ServiceListener,需要切換的藍牙協議BluetoothProfile.HEADSET;
- 接著在藍牙協議切換成功的監聽回調函數中賦值;
2)切換藍牙耳機(HEADSET協議)
一般在收到藍牙協議切換成功后,才進行藍牙耳機的切換。也就是在上一點的回調函數中獲取HEADSET協議的配置后,就進行藍牙耳機的切換。
切換藍牙耳機使用AudioManager中三個方法:setSpeakerphoneOn、startBluetooth、ScosetBluetoothScoOn。
// 切換為藍牙耳機 private void switchBluetoothEarphone() {if (mAudioManager == null || mBluetoothAdapter == null || mBluetoothHeadset == null) {return;}if(!mBluetoothAdapter.isEnabled()){return;}// 先將揚聲器關閉mAudioManager.setSpeakerphoneOn(false);// 打開藍牙SCO連接mAudioManager.startBluetoothSco();mAudioManager.setBluetoothScoOn(true); }若在藍牙耳機使用途中,想要強制切換到聽筒或揚聲器時,需要先將藍牙的SCO連接關閉,再切換聽筒或揚聲器。
// 切換為揚聲器 private void switchSpeakerphone() {if (mAudioManager == null) {return;}if (mBluetoothAdapter != null && mBluetoothHeadset != null) {mAudioManager.setBluetoothScoOn(false);mAudioManager.stopBluetoothSco();}mAudioManager.setSpeakerphoneOn(true); }// 切換為聽筒 private void switchEarphone() {if (mAudioManager == null) {return;}if (mBluetoothAdapter != null && mBluetoothHeadset != null) {mAudioManager.setBluetoothScoOn(false);mAudioManager.stopBluetoothSco();}mAudioManager.setSpeakerphoneOn(false); }3)關閉此類實例
在使用完BluetoothHeadSet時,需要調用 BluetoothAdapter的closeProfileProxy方法將協議關閉。協議成功關閉后,依舊會走之前注冊的回調函數的onServiceDisconnected方法。
// 關閉協議 if (mBluetoothAdapter != null && mBluetoothHeadset != null) {mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); }三、監聽耳機的連接與斷連
系統在耳機狀態改變時會發送相應的廣播信號。所以監聽耳機的插入拔出或者連接斷連,需要注冊一個廣播BroadcastReceiver。廣播的使用如下代碼:
/*** 注冊廣播監聽*/ private void registerBluetoothReceiver() {IntentFilter filter = new IntentFilter();filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); // BluetoothHeadset連接狀態filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);// 藍牙SCO的連接狀態filter.addAction(AudioManager.ACTION_HEADSET_PLUG);// 有線耳機的插入拔出if (mContext != null) {mContext.registerReceiver(mBluetoothReceiver, filter);} } /*** 廣播監聽設備的狀態*/ private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (intent == null) {return;}String action = intent.getAction();BluetoothDevice dev;if (action == null) {return;}switch(action){// 判斷這個action對應監聽的事件//....省略后面代碼,后續繼續展開 }} };1. 監聽有線耳機的插入與拔出
1)注冊廣播
filter.addAction(AudioManager.ACTION_HEADSET_PLUG);// 有線耳機的插入拔出2)監聽廣播
AudioManager.ACTION_HEADSET_PLUG廣播Intent中包含有參數state,表明有線耳機設備是否插入耳機孔。
case AudioManager.ACTION_HEADSET_PLUG: {if (intent.hasExtra("state")) {int state = intent.getIntExtra("state", 0);if (state == 1) {//插入耳機switchPlugInEarphones();} else if (state == 0) {//拔出耳機switchEarphone();}}break; }在開發中發現,只要手機插入過一次有線耳機,就算當前沒有拔插有線耳機,后面重新注冊廣播時,會收到一次耳機拔出的廣播。重啟手機后,這種現象就會消失,但不可能每次拔插耳機就重啟手機。
2. 監聽藍牙耳機的連接與斷連
1)注冊廣播
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); // BluetoothHeadset連接狀態 filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);// 藍牙SCO的連接狀態2)監聽廣播
- BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED 廣播intent包含當前的連接設備信息dev,以及當前的連接狀態state。切換協議后,在藍牙中途連接或者
- AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED 廣播intent包含當前切換SCO鏈路的狀態,切換成功會回調SCO_AUDIO_STATE_CONNECTED狀態,如果切換失敗或者斷開,則會回調SCO_AUDIO_STATE_DISCONNECTED狀態。
3. 判斷當前連接的是有線耳機還是藍牙耳機
- AudioManager的isWiredHeadsetOn方法可以判斷是否連接著有線耳機,使用isBluetoothScoOn和isBluetoothA2dpOn方法可以判斷是否連接著藍牙耳機。
- 新版本的話推薦使用AudioManager.GET_DEVICES_OUTPUTS去獲取當前連接的設備信息,設備信息保存在AudioDeviceInfo中。
總結
以上是生活随笔為你收集整理的Android 音频设备管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么叫资源整合?
- 下一篇: android sina oauth2.