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