Android 9.0 10蓝牙音乐获取歌手、歌曲等信息

Android 9.0中蓝牙音乐其实实现很简单,蓝牙远程服务处理在Bluetooth中。
修改代码路径:

android/packages/apps/Bluetooth./jni/com_android_bluetooth_avrcp_controller.cpp
android/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java

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 (!sCallbackEnv.valid()) return;

  ScopedLocalRef<jbyteArray> addr(
      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
  if (!addr.get()) {
    ALOGE("Fail to get new array ");
    return;
  }

  ScopedLocalRef<jintArray> attribIds(sCallbackEnv.get(),
                                      sCallbackEnv->NewIntArray(num_attr));
  if (!attribIds.get()) {
    ALOGE(" failed to set new array for attribIds");
    return;
  }
  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                   (jbyte*)&bd_addr.address);

  jclass strclazz = sCallbackEnv->FindClass("java/lang/String");
  ScopedLocalRef<jobjectArray> stringArray(
      sCallbackEnv.get(),
      sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0));
  if (!stringArray.get()) {
    ALOGE(" failed to get String array");
    return;
  }

  for (jint i = 0; i < num_attr; i++) {
    ScopedLocalRef<jstring> str(
        sCallbackEnv.get(),
        sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text)));
    if (!str.get()) {
      ALOGE("Unable to get str");
      return;
    }
    sCallbackEnv->SetIntArrayRegion(attribIds.get(), i, 1,
                                    (jint*)&(p_attrs[i].attr_id));
    sCallbackEnv->SetObjectArrayElement(stringArray.get(), i, str.get());
  }

  sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handletrackchanged,
                               addr.get(), (jbyte)(num_attr), attribIds.get(),
                               stringArray.get());
}

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、AvrcpControllerService.java中找到onTrackChanged方法,该方法就是获取蓝牙音乐的一些信息

   private synchronized void onTrackChanged(byte[] address, byte numAttributes, int[] attributes,
            String[] attribVals) {
        if (DBG) {
            Log.d(TAG, "onTrackChanged");
        }
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        if (device != null && !device.equals(mConnectedDevice)) {
            Log.e(TAG, "onTrackChanged device not found " + address);
            return;
        }
        //该方法就是把蓝牙音乐的信息传递给java层
     	getElementAttrRsp(attributes,attribVals,numAttributes);
        List<Integer> attrList = new ArrayList<>();
        for (int attr : attributes) {
            
            attrList.add(attr);
        }
        List<String> attrValList = Arrays.asList(attribVals);
       
        TrackInfo trackInfo = new TrackInfo(attrList, attrValList);
        if (VDBG) {
            Log.d(TAG, "onTrackChanged " + trackInfo);
        }
      
        Message msg = mAvrcpCtSm.obtainMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_TRACK_CHANGED, trackInfo);
        mAvrcpCtSm.sendMessage(msg);
    }

7、AvrcpControllerService.java中找到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("com.android.getelementattrrsp");
        intent.putExtra("artist", artist);
        intent.putExtra("trackTitle",trackTitle);
        intent.putExtra("album",album);
        Log.d(TAG,"getElementAttrRsp,artist: " + artist + ",trackTitle: " + trackTitle + ",album: " + album);
        intent.addFlags(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]
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值