日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 音频设备管理

發布時間:2023/12/31 Android 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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()獲取
// 藍牙適配器 private BluetoothAdapter mBluetoothAdapter = null; /* * sdk版本大于等于18時,使用BluetoothManager獲取BluetoothAdapter * 小于18使用BluetoothAdapter.getDefaultAdapter()獲取 */ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);if (mBluetoothManager != null) {mBluetoothAdapter = mBluetoothManager.getAdapter();} } else {mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); }

2)判斷本地藍牙適配器是否打開

BluetoothAdapter 中的isEnabled方法,用于判斷手機本地的藍牙適配器是否打開。如果返回值為false,則代表手機本地的適配器沒有打開,也就不可能有藍牙連接。

if(mBluetoothAdapter != null && mBluetoothAdapter.isEnable()){// 藍牙適配器已經打開 }else{// 手機不支持藍牙或沒有打開藍牙適配器 }

3. BluetoothHeadset

1)獲取此類實例

  • 首先需要進行藍牙協議切換,調用BluetoothAdaptergetProfileProxy方法,將藍牙協議切換為BluetoothProfile.HEADSET協議。getProfileProxy方法需要傳入的參數:當前上下文Context,藍牙協議監聽回調函數BluetoothProfile.ServiceListener,需要切換的藍牙協議BluetoothProfile.HEADSET
  • 接著在藍牙協議切換成功的監聽回調函數中賦值;
// 藍牙耳機配置協議 private BluetoothHeadset mBluetoothHeadset = null;// 切換協議 if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {// 獲取協議,將回調函數傳入mBluetoothAdapter.getProfileProxy(mContext, mBluetoothListener, BluetoothProfile.HEADSET); }// 藍牙協議獲取成功監聽回調函數 private BluetoothProfile.ServiceListener mBluetoothListener = new BluetoothProfile.ServiceListener() {@Overridepublic void onServiceConnected(int profile, BluetoothProfile bluetoothProfile) {// 藍牙協議獲取成功時,回調此接口// 判斷是否為Headset協議if (profile == BluetoothProfile.HEADSET) {mBluetoothHeadset = (BluetoothHeadset) bluetoothProfile;}}@Overridepublic void onServiceDisconnected(int profile) {// 藍牙協議獲取失敗時,回調此接口if (profile == BluetoothProfile.HEADSET) {mBluetoothHeadset = null;}} };

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時,需要調用 BluetoothAdaptercloseProfileProxy方法將協議關閉。協議成功關閉后,依舊會走之前注冊的回調函數的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狀態。
case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: {// 獲取連接的設備名dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0);Log.i(TAG, "Headset STATE: " + state);Log.i(TAG, "BluetoothDevice: " + dev.getName() + ", " + dev.getAddress());// 獲取當前狀態switch (state) {case BluetoothHeadset.STATE_CONNECTING://連接中break;case BluetoothHeadset.STATE_CONNECTED://已連接// 切換協議if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mBluetoothHeadset == null) {// 獲取協議,將回調函數傳入mBluetoothAdapter.getProfileProxy(mContext, mBluetoothListener, BluetoothProfile.HEADSET);}break;case BluetoothHeadset.STATE_DISCONNECTED://斷開// 斷開時需要將協議關閉if (mBluetoothAdapter != null && mBluetoothHeadset != null) {mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);}break;case BluetoothHeadset.STATE_DISCONNECTING://斷開中break;}break; }case AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED: {int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);switch (state) {case AudioManager.SCO_AUDIO_STATE_CONNECTING: {break;}case AudioManager.SCO_AUDIO_STATE_CONNECTED: {break;}case AudioManager.SCO_AUDIO_STATE_DISCONNECTED: {break;}case AudioManager.SCO_AUDIO_STATE_ERROR: {break;}default:break;}break; }

3. 判斷當前連接的是有線耳機還是藍牙耳機

  • AudioManager的isWiredHeadsetOn方法可以判斷是否連接著有線耳機,使用isBluetoothScoOn和isBluetoothA2dpOn方法可以判斷是否連接著藍牙耳機。
  • 新版本的話推薦使用AudioManager.GET_DEVICES_OUTPUTS去獲取當前連接的設備信息,設備信息保存在AudioDeviceInfo中。
// 判斷是否連著有線耳機 private boolean isConnectPlugInEarphone() {if (mAudioManager == null) {return false;}if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return mAudioManager.isWiredHeadsetOn();} else {AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);for (int i = 0; i < devices.length; i++) {AudioDeviceInfo device = devices[i];if (device.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET|| device.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {return true;}}}return false; }// 判斷是否連接著藍牙耳機 private boolean isConnectBluetooth() {if (mAudioManager == null) {return false;}if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return mAudioManager.isBluetoothScoOn() || mAudioManager.isBluetoothA2dpOn();} else {AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);for (int i = 0; i < devices.length; i++) {AudioDeviceInfo device = devices[i];if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO|| device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {return true;}}}return false; }

總結

以上是生活随笔為你收集整理的Android 音频设备管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。