1. 程式人生 > >Android 藍芽開發(九)A2DP基本功能

Android 藍芽開發(九)A2DP基本功能

本文主要是Android做為Audio Source端,A2DP的基本操作:包括連線、斷開連線、設定優先順序、獲取優先順序、獲取A2DP連線狀態、獲取A2DP連線的裝置列表等功能。

1 簡介

A2DP全名是Advanced Audio Distribution Profile,高質量音訊資料傳輸的協議,其定義裡了傳送單聲道或立體聲等高質量音訊(區別於藍牙SCO鏈路上傳輸的普通語音)資訊的協議和過程。A2DP的典型應用是將音樂播放器的音訊資料傳送到耳機或音箱。
A2DP定義了兩種角色:

Audio Source(音訊源) 音訊的輸入端對音訊資料進行編碼,傳送到Sink端。
Audio Sink(音訊接收器) 接收到音訊資料後,進行解碼操作還原出音訊。

2 A2DP profile

要想操作A2DP相關,首先要獲取A2DP代理物件,獲取代理物件的方法比較簡單,如下:

mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if(!mBtAdapter.isEnabled()){
    //彈出對話方塊提示使用者是後開啟  
    Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
    startActivityForResult(enabler, 1);
}
//獲取A2DP代理物件
mBtAdapter.getProfileProxy
(mContext, mListener, BluetoothProfile.A2DP);

getProfileProxy並不會直接返回A2DP代理物件,而是通過mListener中回撥獲取。

private ServiceListener mListener = new ServiceListener() {
    @Override
    public void onServiceDisconnected(int profile) {
        if(profile == BluetoothProfile.A2DP){
            mA2dp = null;
        }
    }
    @Override
public void onServiceConnected(int profile, BluetoothProfile proxy) { if(profile == BluetoothProfile.A2DP){ mA2dp = (BluetoothA2dp) proxy; //轉換 } } };

成功會回撥mListener中的onServiceConnected函式,判斷proflie是否為BluetoothProfile.A2DP,轉換為BluetoothA2dp物件。通過代理物件即可進行A2DP的相關操作了。

3 A2DP操作

A2DP連線首先需要與藍芽耳機進行配對,如何配對這裡就不細說了。
我這裡是連線到之前配對過的一個裝置。裝置名稱為:

private final String BT_NAME = "QCY-QY7";

獲取該裝置,首先獲取配對的藍芽裝置,然後遍歷這些藍芽裝置,找出藍芽名稱符合條件的裝置,就是要操作的裝置,

//獲取配對的藍芽裝置
Set<BluetoothDevice> bondDevice = mBtAdapter.getBondedDevices();
for(BluetoothDevice device:bondDevice){
    //獲取指定名稱的裝置
    if(BT_NAME.equals(device.getName())){
        mConnectDevice = device;
    }
}

mConnectDevice為要操作的裝置。
1 A2DP連線

private void connectA2dp(BluetoothDevice device){
    setPriority(mConnectDevice, 100); //設定priority
    try {
        //通過反射獲取BluetoothA2dp中connect方法(hide的),進行連線。
        Method connectMethod =BluetoothA2dp.class.getMethod("connect",
                BluetoothDevice.class);
        connectMethod.invoke(mA2dp, device);
    } catch (Exception e) {
        e.printStackTrace();
    } 
}

BluetoothA2dp中的connect方法是hide的,不能直接訪問,需要通過反射的機制獲取該方法進行連線。連線成功後手機可以播放音樂,聲音就會從藍芽耳機出來。
2 斷開連線

private void disConnectA2dp(BluetoothDevice device){
    setPriority(mConnectDevice, 0);
    try {
        //通過反射獲取BluetoothA2dp中connect方法(hide的),斷開連線。
        Method connectMethod =BluetoothA2dp.class.getMethod("disconnect",
                BluetoothDevice.class);
        connectMethod.invoke(mA2dp, device);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

BluetoothA2dp中的disconnect方法也是hide的,與connect類似。
3 設定優先順序

變數
PRIORITY_OFF 0
PRIORITY_ON 100
PRIORITY_AUTO_CONNECT 1000
PRIORITY_UNDEFINED -1

設定優先順序是必要的,否則可能導致連線或斷開連線失敗等問題。

public void setPriority(BluetoothDevice device, int priority) {
    if (mA2dp == null) return;
    try {//通過反射獲取BluetoothA2dp中setPriority方法(hide的),設定優先順序
        Method connectMethod =BluetoothA2dp.class.getMethod("setPriority", 
                BluetoothDevice.class,int.class);
        connectMethod.invoke(mA2dp, device, priority);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

4 獲取優先順序

public int getPriority(BluetoothDevice device) {
    int priority = 0;
    if (mA2dp == null) return priority;
    try {//通過反射獲取BluetoothA2dp中getPriority方法(hide的),獲取優先順序
        Method connectMethod =BluetoothA2dp.class.getMethod("getPriority", 
                BluetoothDevice.class);
        priority = (Integer) connectMethod.invoke(mA2dp, device);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return priority;
}

5 獲取與某裝置A2DP連線狀態

mA2dp.getConnectionState(device);

6 獲取連線裝置列表

//返回值型別List<BluetoothDevice>
mA2dp.getConnectedDevices();

7 A2DP是否正在傳送音訊流

//返回值型別boolean,表示裝置是否在通過A2DP傳送音訊流。
mA2dp.isA2dpPlaying(device);
4 狀態監聽

通過廣播接收者監聽A2DP連線狀態的改變,A2DP播放狀態的改變。

private void initReceiver(){
    //註冊廣播接收者監聽狀態改變
    IntentFilter filter = new IntentFilter(BluetoothA2dp.
            ACTION_CONNECTION_STATE_CHANGED);
    filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
    registerReceiver(mReceiver, filter);
}

廣播接收者,通過intent獲取狀態值。

private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.i(TAG,"onReceive action="+action);
        //A2DP連線狀態改變
        if(action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)){
            int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED);
            Log.i(TAG,"connect state="+state);
        }else if(action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)){
            //A2DP播放狀態改變
            int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_NOT_PLAYING);
            Log.i(TAG,"play state="+state);
        }
    }
};

歡迎掃一掃關注我的微信公眾號,定期推送優質技術文章:

這裡寫圖片描述