Android 9.0中蓝牙音乐其实实现很简单,蓝牙远程服务处理在Bluetooth中。
修改代码路径:
android/packages/apps/Bluetooth./jni/com_android_bluetooth_avrcp_controller.cpp
android/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/
1、在com_android_bluetooth_avrcp_controller.cpp中classInitNative方法中会会初始化一些方法,其中当播放音乐发生变化时候,会通过onTrackChanged方法回调给java层
static void classInitNative(JNIEnv* env, jclass clazz) {
method_handletrackchanged =
env->GetMethodID(clazz, "onTrackChanged", "([BB[I[Ljava/lang/String;)V");
}
2、在com_android_bluetooth_avrcp_controller.cpp中命名空间中会定义一些回调java层的方法
namespace android {
static jmethodID method_handlePassthroughRsp;
static jmethodID method_onConnectionStateChanged;
static jmethodID method_getRcFeatures;
static jmethodID method_setplayerappsettingrsp;
static jmethodID method_handleplayerappsetting;
static jmethodID method_handleplayerappsettingchanged;
static jmethodID method_handleSetAbsVolume;
static jmethodID method_handleRegisterNotificationAbsVol;
static jmethodID method_handletrackchanged;
static jmethodID method_handleplaypositionchanged;
static jmethodID method_handleplaystatuschanged;
static jmethodID method_handleGetFolderItemsRsp;
static jmethodID method_handleGetPlayerItemsRsp;
static jmethodID method_handleGroupNavigationRsp;
static jmethodID method_createFromNativeMediaItem;
static jmethodID method_createFromNativeFolderItem;
static jmethodID method_createFromNativePlayerItem;
static jmethodID method_handleChangeFolderRsp;
static jmethodID method_handleSetBrowsedPlayerRsp;
static jmethodID method_handleSetAddressedPlayerRsp;
3、在com_android_bluetooth_avrcp_controller.cpp中找到method_handletrackchanged方法实现的地方,该方法最后是通过该方法回调btavrcp_track_changed_callback
static void btavrcp_track_changed_callback(const RawAddress& bd_addr,
uint8_t num_attr,
btrc_element_attr_val_t* p_attrs) {
/*
* byteArray will be formatted like this: id,len,string
* Assuming text feild to be null terminated.
*/
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!()) return;
ScopedLocalRef<jbyteArray> addr(
(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
if (!()) {
ALOGE("Fail to get new array ");
return;
}
ScopedLocalRef<jintArray> attribIds((),
sCallbackEnv->NewIntArray(num_attr));
if (!()) {
ALOGE(" failed to set new array for attribIds");
return;
}
sCallbackEnv->SetByteArrayRegion((), 0, sizeof(RawAddress),
(jbyte*)&bd_addr.address);
jclass strclazz = sCallbackEnv->FindClass("java/lang/String");
ScopedLocalRef<jobjectArray> stringArray(
(),
sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0));
if (!()) {
ALOGE(" failed to get String array");
return;
}
for (jint i = 0; i < num_attr; i++) {
ScopedLocalRef<jstring> str(
(),
sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text)));
if (!()) {
ALOGE("Unable to get str");
return;
}
sCallbackEnv->SetIntArrayRegion((), i, 1,
(jint*)&(p_attrs[i].attr_id));
sCallbackEnv->SetObjectArrayElement((), i, ());
}
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handletrackchanged,
(), (jbyte)(num_attr), (),
());
}
4、在com_android_bluetooth_avrcp_controller.cpp中sBluetoothAvrcpCallbacks方法会会定义一些回调给jiava层的方法
static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
sizeof(sBluetoothAvrcpCallbacks),
btavrcp_passthrough_response_callback,
btavrcp_groupnavigation_response_callback,
btavrcp_connection_state_callback,
btavrcp_get_rcfeatures_callback,
btavrcp_setplayerapplicationsetting_rsp_callback,
btavrcp_playerapplicationsetting_callback,
btavrcp_playerapplicationsetting_changed_callback,
btavrcp_set_abs_vol_cmd_callback,
btavrcp_register_notification_absvol_callback,
btavrcp_track_changed_callback,
btavrcp_play_position_changed_callback,
btavrcp_play_status_changed_callback,
btavrcp_get_folder_items_callback,
btavrcp_change_path_callback,
btavrcp_set_browsed_player_callback,
btavrcp_set_addressed_player_callback};
5、在com_android_bluetooth_avrcp_controller.cpp中initNative方法会初始化一些回调函数
static void initNative(JNIEnv* env, jobject object) {
jclass tmpMediaItem =
env->FindClass("android/media/browse/MediaBrowser$MediaItem");
class_MediaBrowser_MediaItem = (jclass)env->NewGlobalRef(tmpMediaItem);
jclass tmpBtPlayer =
env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpPlayer");
class_AvrcpPlayer = (jclass)env->NewGlobalRef(tmpBtPlayer);
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == NULL) {
ALOGE("Bluetooth module is not loaded");
return;
}
if (sBluetoothAvrcpInterface != NULL) {
ALOGW("Cleaning up Avrcp Interface before initializing...");
sBluetoothAvrcpInterface->cleanup();
sBluetoothAvrcpInterface = NULL;
}
if (sCallbacksObj != NULL) {
ALOGW("Cleaning up Avrcp callback object");
env->DeleteGlobalRef(sCallbacksObj);
sCallbacksObj = NULL;
}
sBluetoothAvrcpInterface =
(btrc_ctrl_interface_t*)btInf->get_profile_interface(
BT_PROFILE_AV_RC_CTRL_ID);
if (sBluetoothAvrcpInterface == NULL) {
ALOGE("Failed to get Bluetooth Avrcp Controller Interface");
return;
}
bt_status_t status =
sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks);//这里就是初始化一些回调函数
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed to initialize Bluetooth Avrcp Controller, status: %d",
status);
sBluetoothAvrcpInterface = NULL;
return;
}
sCallbacksObj = env->NewGlobalRef(object);
}
6、中找到onTrackChanged方法,该方法就是获取蓝牙音乐的一些信息
private synchronized void onTrackChanged(byte[] address, byte numAttributes, int[] attributes,
String[] attribVals) {
if (DBG) {
(TAG, "onTrackChanged");
}
BluetoothDevice device = ().getRemoteDevice(address);
if (device != null && !(mConnectedDevice)) {
(TAG, "onTrackChanged device not found " + address);
return;
}
//该方法就是把蓝牙音乐的信息传递给java层
getElementAttrRsp(attributes,attribVals,numAttributes);
List<Integer> attrList = new ArrayList<>();
for (int attr : attributes) {
(attr);
}
List<String> attrValList = (attribVals);
TrackInfo trackInfo = new TrackInfo(attrList, attrValList);
if (VDBG) {
(TAG, "onTrackChanged " + trackInfo);
}
Message msg = (
AvrcpControllerStateMachine.MESSAGE_PROCESS_TRACK_CHANGED, trackInfo);
(msg);
}
7、中找到onTrackChanged方法,然后在该方法中添加一个方法getElementAttrRsp(),这样就可以把音乐信息传递给java层
private void getElementAttrRsp(int[] attr_id,String[] textArray,byte num_attr){
String artist = null;
String trackTitle = null;
String album = null;
for (int i = 0; i < num_attr; i++){
switch (attr_id[i]) {
case JNI_MEDIA_ATTR_ID_TITLE:
trackTitle = textArray[i];
if (trackTitle == null){
trackTitle = "Unknown";
}
break;
case JNI_MEDIA_ATTR_ID_ARTIST:
artist = textArray[i];
if (artist == null){
artist = "Unknown";
}
break;
case JNI_MEDIA_ATTR_ID_ALBUM:
album = textArray[i];
if (album == null){
album = "Unknown";
}
break;
}
}
Intent intent = new Intent("");
("artist", artist);
("trackTitle",trackTitle);
("album",album);
(TAG,"getElementAttrRsp,artist: " + artist + ",trackTitle: " + trackTitle + ",album: " + album);
(Intent.FLAG_RECEIVER_FOREGROUND);
sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
}
日志:
08-09 18:30:20.791 2576 2814 D wang : onTrackChanged attrValList 7
08-09 18:30:20.792 2576 2814 D wang : onTrackChanged attrValList [热爱105°C的你, 阿肆, 热爱105°C的你, 7, 100, , 195370]
08-09 18:30:20.821 2576 2814 D wang : onTrackChanged attrValList 7
08-09 18:30:20.821 2576 2814 D wang : onTrackChanged attrValList [热爱105°C的你, 阿肆, 热爱105°C的你, 7, 100, , 195370]
08-09 18:30:20.881 2576 2814 D wang : onTrackChanged attrValList 7
08-09 18:30:20.881 2576 2814 D wang : onTrackChanged attrValList [热爱105°C的你, 阿肆, 热爱105°C的你, 7, 100, , 195370]