车载蓝牙音乐流程简单分析
关键类:
/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
一、音乐播放状态
CPP中通过JNI接口将接从手机端接收来的播放状态回调到AvrcpControllerService的onPlayStatusChanged方法,然后通过状态机AvrcpControllerStateMachine处理。
// Called by JNI on changes of play status
private synchronized void onPlayStatusChanged(byte[] address, byte playStatus) {
if (DBG) {
Log.d(TAG, "onPlayStatusChanged " + playStatus);
}
int playbackState = PlaybackStateCompat.STATE_NONE;
switch (playStatus) {
case JNI_PLAY_STATUS_STOPPED:
playbackState = PlaybackStateCompat.STATE_STOPPED;
break;
case JNI_PLAY_STATUS_PLAYING:
playbackState = PlaybackStateCompat.STATE_PLAYING;
break;
case JNI_PLAY_STATUS_PAUSED:
playbackState = PlaybackStateCompat.STATE_PAUSED;
break;
case JNI_PLAY_STATUS_FWD_SEEK:
playbackState = PlaybackStateCompat.STATE_FAST_FORWARDING;
break;
case JNI_PLAY_STATUS_REV_SEEK:
playbackState = PlaybackStateCompat.STATE_REWINDING;
break;
default:
playbackState = PlaybackStateCompat.STATE_NONE;
}
BluetoothDevice device = mAdapter.getRemoteDevice(address);
AvrcpControllerStateMachine stateMachine = getStateMachine(device);
if (stateMachine != null) {
stateMachine.sendMessage(
AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED, playbackState);
}
}
AvrcpControllerStateMachine.java中Connected内部类的processMessage方法中,调BluetoothMediaBrowserService类的方法将播放状态通知到UI应用,如果是播放状态,要申请音频焦点。
case MESSAGE_PROCESS_PLAY_STATUS_CHANGED:
mAddressedPlayer.setPlayStatus(msg.arg1);
if (!isActive()) {
sendMessage(MSG_AVRCP_PASSTHRU,
AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
return true;
}
PlaybackStateCompat playbackState = mAddressedPlayer.getPlaybackState();
// 将播放状态通过mediasession通知给UI
BluetoothMediaBrowserService.notifyChanged(playbackState);
// 获取当前的音频焦点状态
int focusState = AudioManager.ERROR;
A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
if (a2dpSinkService != null) {
focusState = a2dpSinkService.getFocusState();
}
if (focusState == AudioManager.ERROR) {
sendMessage(MSG_AVRCP_PASSTHRU,
AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
return true;
}
if (playbackState.getState() == PlaybackStateCompat.STATE_PLAYING
&& focusState == AudioManager.AUDIOFOCUS_NONE) {
// 申请音频焦点
if (shouldRequestFocus()) {
requestAudioFocus();
} else {
sendMessage(MSG_AVRCP_PASSTHRU,
AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
}
}
return true;
BluetoothMediaBrowserService是MediaSession框架的一个服务,UI端通过MediaSession框架绑定该服务就可以监听蓝牙音频的播放状态,控制蓝牙音频的播放。
BluetoothMediaBrowserService的notifyChanged方法中通过MediaSession框架将播放状态通知到UI端。
static synchronized void notifyChanged(PlaybackStateCompat playbackState) {
Log.d(TAG, "notifyChanged PlaybackState" + playbackState);
if (sBluetoothMediaBrowserService != null) {
sBluetoothMediaBrowserService.mSession.setPlaybackState(playbackState);
} else {
Log.w(TAG, "notifyChanged Unavailable");
}
}
二、音频焦点申请
上面播放状态处理的逻辑中会调到A2dpSinkService的requestAudioFocus方法
/**
* Request audio focus such that the designated device can stream audio
*/
public void requestAudioFocus(BluetoothDevice device, boolean request) {
synchronized (mStreamHandlerLock) {
if (mA2dpSinkStreamHandler == null) return;
mA2dpSinkStreamHandler.requestAudioFocus(request);
}
}
A2dpSinkStreamHandler
private synchronized int requestAudioFocus() {
if (DBG) Log.d(TAG, "requestAudioFocus()");
// Bluetooth A2DP may carry Music, Audio Books, Navigation, or other sounds so mark content
// type unknown.
AudioAttributes streamAttributes =
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.build();
// Bluetooth ducking is handled at the native layer at the request of AudioManager.
AudioFocusRequest focusRequest =
new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).setAudioAttributes(
streamAttributes)
.setOnAudioFocusChangeListener(mAudioFocusListener, this)
.build();
int focusRequestStatus = mAudioManager.requestAudioFocus(focusRequest);
// If the request is granted begin streaming immediately and schedule an upgrade.
if (focusRequestStatus == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
startFluorideStreaming();
mAudioFocus = AudioManager.AUDIOFOCUS_GAIN;
}
return focusRequestStatus;
}
三、播放控制
UI通过MediaSession框架绑定到BluetoothMediaBrowserService服务,BluetoothMediaBrowserService中的MediaSessionCompat对象是关键,MediaSessionCompat.CallBack是专门接收MediaSession客户端的指令并处理的。AvrcpControllerStateMachine的setActive方法中,会将MediaSessionCompat.CallBack对象传给BluetoothMediaBrowserService的MediaSessionCompat。
BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
MediaSessionCompat.Callback mSessionCallbacks = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
logD("onPlay");
requestAudioFocus();
sendMessage(MSG_AVRCP_PASSTHRU, AvrcpControllerService.PASS_THRU_CMD_ID_PLAY);
}
@Override
public void onPause() {
logD("onPause");
sendMessage(MSG_AVRCP_PASSTHRU, AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
}
};
public boolean processMessage(Message msg) {
logD(STATE_TAG + " processMessage " + msg.what);
switch (msg.what) {
case MSG_AVRCP_PASSTHRU:
passThru(msg.arg1);
return true;
}
}
而后调AvrcpControllerService类的sendPassThroughCommandNative方法将指令通过JNI接口发给CPP层。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!