2019年12月2日 星期一

[Android]Android BT avrcp framework層巡禮

爬了一整圈Android BT framework的sourcecode 看到這篇,有些坑也提到了就引用分享一下 :
https://www.twblogs.net/a/5c00cab5bd9eee7aed3391cf

接收intent註冊

IntentFilter filter2 = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
//filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
//filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dpSink.ACTION_PLAYING_STATE_CHANGED);
filter.addAction(BluetoothAvrcpController.ACTION_TRACK_EVENT);
filter.addAction(BluetoothAvrcpController.ACTION_PLAYER_SETTING);
filter.addAction(Constants.ACTION_AVRCP_CMD);
mContext.registerReceiver(mBTReceiver, filter);


private BroadcastReceiver mBTReceiver = new BroadcastReceiver() {
@Override

public void onReceive(Context context, Intent intent) {

// Log.d(TAG, "mBTReceiver " + intent.getAction());

// showToast(intent.getAction());

if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction()))

{

int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);

if (state == BluetoothAdapter.STATE_ON)

{

Log.d(LOG_TAG, "BT ON");

}

else if( state == BluetoothAdapter.STATE_OFF)

{

Log.d(LOG_TAG, "BT OFF");

setBtStatus(BtStatus.BT_DISCONNECT);

}

}

else if( BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction()) ) {

int previous_state = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothA2dpSink.STATE_DISCONNECTED);

int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothA2dpSink.STATE_DISCONNECTED);

if( state == BluetoothA2dpSink.STATE_CONNECTING) {

Log.d(LOG_TAG, "A2DPSink STATE_CONNECTING");

} else if( state == BluetoothA2dpSink.STATE_CONNECTED) {

Log.d(LOG_TAG, "A2DPSink STATE_CONNECTED");

setBtStatus(BtStatus.BT_CONNECT);

} else if (state == BluetoothA2dpSink.STATE_DISCONNECTED) {

Log.d(LOG_TAG, "A2DPSink STATE_DISCONNECTED");

setBtStatus(BtStatus.BT_DISCONNECT);

}

}

else if(BluetoothA2dpSink.ACTION_PLAYING_STATE_CHANGED.equals(intent.getAction()) ) {

int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothA2dpSink.STATE_NOT_PLAYING);

BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

Log.d(LOG_TAG, String.format("ACTION_PLAYING_STATE_CHANGED state: %d", state));

if(device != null) {

if(state == BluetoothA2dpSink.STATE_PLAYING) {

Log.d(LOG_TAG, String.format("Device %s playing", device.getAddress()));

}

else if(state == BluetoothA2dpSink.STATE_NOT_PLAYING) {

Log.d(LOG_TAG, String.format("Device %s not playing", device.getAddress()));

}

}

}

else if(intent.getAction().equals(BluetoothAvrcpController.ACTION_TRACK_EVENT)) {

// Log.d(LOG_TAG, "TRACK_EVENT");

MediaMetadata metadata = intent.getParcelableExtra(BluetoothAvrcpController.EXTRA_METADATA);

// Log.v(LOG_TAG, "[Music]metadata != null) = " + (metadata != null));

if(metadata != null) {

String title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);

setMusicCoverTitle(metadata.getString(MediaMetadata.METADATA_KEY_TITLE));

// Log.v(LOG_TAG, String.format("[Music]artist: %s", artist));

// Log.v(LOG_TAG, String.format("[Music]album: %s", album));

// Log.v(LOG_TAG, String.format("[Music]duration: %s", new SimpleDateFormat("HH:mm:ss").format(duration)));

setPDuration((int)metadata.getLong(MediaMetadata.METADATA_KEY_DURATION));

}

PlaybackState playback_state = intent.getParcelableExtra(BluetoothAvrcpController.EXTRA_PLAYBACK);

// Log.v(LOG_TAG, "[Music](playback_state != null) check1 = " + (playback_state != null));

if(playback_state != null) {

int state = playback_state.getState();

// int position = (int)playback_state.getPosition();

if (state == PlaybackState.STATE_PLAYING) {

IsBTMusic_Play = true;

Log.v(LOG_TAG, "[Music]bt music is playing IsBTMusic_Play = " + IsBTMusic_Play);



if (mOnPlayStateChangedListener != null) {

if (getScreenTag() == ScreenTag.CID_MEDIA) {

mOnPlayStateChangedListener.onPlayStateChanged(ScreenTag.CID_MEDIA, Constants.PlayState.PLAYING);

} else if (getScreenTag() == ScreenTag.PID_MEDIA) {

mOnPlayStateChangedListener.onPlayStateChanged(ScreenTag.PID_MEDIA, Constants.PlayState.PLAYING);

}

}

}

else if (state == PlaybackState.STATE_PAUSED) {

IsBTMusic_Play = false;

Log.v(LOG_TAG, "[Music]bt music is pause IsBTMusic_Play = " + IsBTMusic_Play);



if (mOnPlayStateChangedListener != null) {

if (getScreenTag() == ScreenTag.CID_MEDIA) {

mOnPlayStateChangedListener.onPlayStateChanged(ScreenTag.CID_MEDIA, Constants.PlayState.PAUSE);

} else if (getScreenTag() == ScreenTag.PID_MEDIA) {

mOnPlayStateChangedListener.onPlayStateChanged(ScreenTag.PID_MEDIA, Constants.PlayState.PAUSE);

}

}

}

else if (state == PlaybackState.STATE_STOPPED) {

IsBTMusic_Play = false;

Log.v(LOG_TAG, "[Music]bt music is stop IsBTMusic_Play = " + IsBTMusic_Play);

}

// int position = (int)playback_state.getPosition();

// Log.v(LOG_TAG, "[Music]position: " + new SimpleDateFormat("HH:mm:ss").format(playback_state.getPosition()));

//Log.v(LOG_TAG, "duration = " + duration + "position = " + position);

setPPosition((int)playback_state.getPosition());

}}

else if( BluetoothAvrcpController.ACTION_PLAYER_SETTING.equals(intent.getAction()) ) {

BluetoothAvrcpPlayerSettings player_settings = intent.getParcelableExtra(BluetoothAvrcpController.EXTRA_PLAYER_SETTING);

refreshAvrcpSettings(player_settings);

}

else if(Constants.ACTION_AVRCP_CMD.equals(intent.getAction())) {

}}};



上層打通回控的程式
在media的page建立回控程式 我參考了網址:
https://github.com/PDi-Communication-Systems-Inc/lollipop-packages-apps-fsl_imx_demo/blob/master/A2dpSinkApp/java/com/freescale/a2dpsinkapp/MainActivity.java
看一下棒棒糖版本的回控 瞭解了 除了接收要註冊AVRCP相關的intent及Receiver外 傳送部分控件的建立必須先部屬BTAdapter 接著
if(mUBTAdapter == null) {
mUBTAdapter = BluetoothAdapter.getDefaultAdapter();
if(pAVRCPControllerService == null)
mUBTAdapter.getProfileProxy(mContext, mAvrcpControllerListener, BluetoothProfile.AVRCP_CONTROLLER);
else
Log.v(LOG_TAG, "pAVRCPControllerService is not null.");
}else{
Log.v(LOG_TAG, "mUBTAdapter is not null.");
if(pAVRCPControllerService == null)
mUBTAdapter.getProfileProxy(mContext, mAvrcpControllerListener, BluetoothProfile.AVRCP_CONTROLLER);
else
Log.v(LOG_TAG, "pAVRCPControllerService is not null.");

}


底層 :
Step011-05 10:27:30.251  3900  4295 I A2dpSinkStreamHandler: ecockpit mAudioManager.requestAudioFocus successful
11-05 10:27:30.251  3900  4295 D A2dpSinkStreamHandler: startAvrcpUpdates
11-05 10:27:30.251  3900  4295 I A2dpSinkStreamHandler: ecockpit startAvrcpUpdates, connected device number==0
=> packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink
startAvrcpUpdates() => avrcpService != null, but device number == 0 =>
Check avrcpService.getConnectedDevice().size();
11-05 10:27:30.251  3900  4295 I A2dpSinkStreamHandler: ecockpit mAudioManager.requestAudioFocus successful
11-05 10:27:30.251  3900  4295 D A2dpSinkStreamHandler: startAvrcpUpdates
11-05 10:27:30.251  3900  4295 I A2dpSinkStreamHandler: ecockpit startAvrcpUpdates, connected device number==0
=> packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink
startAvrcpUpdates() => avrcpService != null, but device number == 0 =>
Check avrcpService.getConnectedDevice().size();

Step1
Src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
getConnectedDevice():256
Searcg private mConnectedDevice who used.
onConnectionStateChanged():746
有打印scott log但未印出 追jni
=>packages/apps/Bluetooth/jni

剔除不需要找的function
目標鎖定在以下3cpp
./com_android_bluetooth_a2dp.cpp
./com_android_bluetooth_avrcp_controller.cpp
./com_android_bluetooth_a2dp_sink.cpp
其中Avrcp_controller與自己較相關./com_android_bluetooth_avrcp_controller.cpp


Step3 : Searching ‘btrc_ctrl_callbacks’@BT HAL
Step3 : Searching ‘init_ctrl’@BT HAL














沒有留言:

張貼留言