**
Android 8.1开启Bluetooth A2DP sink功能
**
Android O源码已经支持A2DP sink,只需要开启就可以了
一个是BTA_AV_SINK_INCLUDED设为TRUE,BTA_AV_SINK_INCLUDED在\system\bt\include的bt_target.h
另外一个是bluetooth app这边的profile_supported_a2dp_sink需设为true开启这个profile
但是实际上光开启这两个值A2DP sink是不能工作的,我用的是RK3399,不知道其他平台是不是OK的
调试发现这个btif_av_init只会执行一次,也就是加了source之后sink是加不进来了,因为这个if判断执行过一次就不会再成立了,这个设计的初衷不知道是不是source和sink只能有一个,因为我这边发现打开sink后,source是有问题的,看起来是不能使用了,目前是暂时把这个判断拿掉了,因为我们source端没什么要求应该是用不上,但是sink端是一定需要的
/*******************************************************************************
*
* Function btif_av_init
*
* Description Initializes btif AV if not already done
*
* Returns bt_status_t
*
******************************************************************************/
bt_status_t btif_av_init(int service_id) {
if (btif_av_cb.sm_handle == NULL) {
alarm_free(av_open_on_rc_timer);
av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");
switch (service_id) {
case BTA_A2DP_SOURCE_SERVICE_ID:
if (!btif_a2dp_source_startup())
return BT_STATUS_FAIL; // Already running
break;
case BTA_A2DP_SINK_SERVICE_ID:
if (!btif_a2dp_sink_startup())
return BT_STATUS_FAIL; // Already running
break;
default:
break;
}
btif_enable_service(service_id);
/* Also initialize the AV state machine */
btif_av_cb.sm_handle = btif_sm_init(
(const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
}
return BT_STATUS_SUCCESS;
}
修改完这个后A2DP sink profile是有了,另外的手机也可以连上,数据也有传到我们的板子上,就是没有声音,调试发现就是播放没有执行
播放函数在pachages\appsBluetooth\src\com\android\bluetooth\a2dpsink\A2dpSinkStreamHandler.java
@Override
public void handleMessage(Message message) {
if (DBG) {
Log.d(TAG, " process message: " + message.what);
Log.d(TAG, " audioFocus = " + mAudioFocus);
}
switch (message.what) {
case SRC_STR_START:
// Audio stream has started, stop it if we don't have focus.
mStreamAvailable = true;
+++++
/*if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
requestAudioFocus();
}*/
+++++
if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
sendAvrcpPause();
} else {
startAvrcpUpdates();
}
break;
case SRC_STR_STOP:
// Audio stream has stopped, maintain focus but stop avrcp updates.
mStreamAvailable = false;
stopAvrcpUpdates();
break;
case SNK_PLAY:
// Local play command, gain focus and start avrcp updates.
if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
requestAudioFocus();
}
startAvrcpUpdates();
break;
case SNK_PAUSE:
// Local pause command, maintain focus but stop avrcp updates.
stopAvrcpUpdates();
break;
case SRC_PLAY:
// Remote play command, if we have audio focus update avrcp, otherwise send pause.
if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
sendAvrcpPause();
} else {
startAvrcpUpdates();
}
break;
case SRC_PAUSE:
// Remote pause command, stop avrcp updates.
stopAvrcpUpdates();
break;
case DISCONNECT:
// Remote device has disconnected, restore everything to default state.
sendAvrcpPause();
stopAvrcpUpdates();
abandonAudioFocus();
mSentPause = false;
break;
case AUDIO_FOCUS_CHANGE:
// message.obj is the newly granted audio focus.
switch ((int) message.obj) {
case AudioManager.AUDIOFOCUS_GAIN:
// Begin playing audio, if we paused the remote, send a play now.
startAvrcpUpdates();
startFluorideStreaming();
if (mSentPause) {
sendAvrcpPlay();
mSentPause = false;
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Make the volume duck.
int duckPercent = mContext.getResources().getInteger(
R.integer.a2dp_sink_duck_percent);
if (duckPercent < 0 || duckPercent > 100) {
Log.e(TAG, "Invalid duck percent using default.");
duckPercent = DEFAULT_DUCK_PERCENT;
}
float duckRatio = (duckPercent / 100.0f);
if (DBG) {
Log.d(TAG, "Setting reduce gain on transient loss gain=" + duckRatio);
}
setFluorideAudioTrackGain(duckRatio);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Temporary loss of focus, if we are actively streaming pause the remote
// and make sure we resume playback when we regain focus.
if (mStreamAvailable) {
sendAvrcpPause();
mSentPause = true;
}
stopFluorideStreaming();
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Permanent loss of focus probably due to another audio app, abandon focus
// and stop playback.
mAudioFocus = AudioManager.AUDIOFOCUS_NONE;
abandonAudioFocus();
sendAvrcpPause();
break;
}
break;
default:
Log.w(TAG, "Received unexpected event: " + message.what);
}
}
开始播放后mAudioFocus 为0,就不会进到startAvrcpUpdates();,现在是在前面去requestAudioFocus();,这样在手机上播放的声音就都要RK3399的板子上了。
目前没有发现什么问题,有问题一起讨论哈!