OSDN Git Service

[automerger skipped] Merge "Reset the IRK after all devices are unpaired" into pi...
authorTreeHugger Robot <treehugger-gerrit@google.com>
Wed, 8 Dec 2021 23:30:29 +0000 (23:30 +0000)
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Wed, 8 Dec 2021 23:30:29 +0000 (23:30 +0000)
am skip reason: Merged-In I8e44f010a72dcdec595d81293a05f49ccc054065 with SHA-1 6b3c0f6a36 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/bt/+/16232558

Change-Id: I6d606ed9c34f5a3449b2a9ad11eeebdfa089c250

16 files changed:
bta/av/bta_av_main.cc
device/include/interop.h
device/include/interop_database.h
device/src/interop.cc
packet/tests/avrcp/avrcp_test_packets.h
profile/avrcp/device.cc
profile/avrcp/tests/avrcp_device_test.cc
stack/a2dp/a2dp_aac.cc
stack/a2dp/a2dp_aac_encoder.cc
stack/btm/btm_acl.cc
stack/btm/btm_pm.cc
stack/include/a2dp_aac_encoder.h
stack/sdp/sdp_server.cc
stack/sdp/sdp_utils.cc
stack/sdp/sdpint.h
stack/smp/smp_br_main.cc

index 61e4b4e..f0f4640 100644 (file)
@@ -86,7 +86,7 @@
 #endif
 
 #ifndef AVRCP_DEFAULT_VERSION
-#define AVRCP_DEFAULT_VERSION AVRCP_1_4_STRING
+#define AVRCP_DEFAULT_VERSION AVRCP_1_5_STRING
 #endif
 
 /* state machine states */
index d7ca917..efbafa1 100644 (file)
@@ -99,7 +99,15 @@ typedef enum {
   // The public address of these devices are same as the Random address in ADV.
   // Then will get name by LE_Create_connection, actually fails,
   // but will block pairing.
-  INTEROP_DISABLE_NAME_REQUEST
+  INTEROP_DISABLE_NAME_REQUEST,
+
+  // Respond AVRCP profile version only 1.4 for some device.
+  INTEROP_AVRCP_1_4_ONLY,
+
+  // Disable sniff mode for headsets/car-kits
+  // Some car kits supports sniff mode but when DUT initiates sniff req
+  // Remote will go to bad state and its leads to LMP time out.
+  INTEROP_DISABLE_SNIFF
 } interop_feature_t;
 
 // Check if a given |addr| matches a known interoperability workaround as
index b4b1b07..8010bcc 100644 (file)
@@ -150,6 +150,24 @@ static const interop_addr_entry_t interop_addr_database[] = {
     // for skip name request,
     // because BR/EDR address and ADV random address are the same
     {{{0xd4, 0x7a, 0xe2, 0, 0, 0}}, 3, INTEROP_DISABLE_NAME_REQUEST},
+
+    // Lexus Carkit
+    {{{0x64, 0xd4, 0xbd, 0, 0, 0}}, 3, INTEROP_AVRCP_1_4_ONLY},
+
+    // Mazda Carkit
+    {{{0xfc, 0x35, 0xe6, 0, 0, 0}}, 3, INTEROP_AVRCP_1_4_ONLY},
+
+    // Toyota Car Audio
+    {{{0x00, 0x17, 0x53, 0, 0, 0}}, 3, INTEROP_AVRCP_1_4_ONLY},
+
+    // Honda High End Carkit
+    {{{0x9c, 0x8d, 0x7c, 0, 0, 0}}, 3, INTEROP_AVRCP_1_4_ONLY},
+
+    // Honda Civic Carkit
+    {{{0x0c, 0xd9, 0xc1, 0, 0, 0}}, 3, INTEROP_AVRCP_1_4_ONLY},
+
+    // KDDI Carkit
+    {{{0x44, 0xea, 0xd8, 0, 0, 0}}, 3, INTEROP_DISABLE_SNIFF}
 };
 
 typedef struct {
index 9a701b1..a1e45d2 100644 (file)
@@ -132,6 +132,8 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
     CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
     CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
     CASE_RETURN_STR(INTEROP_DISABLE_NAME_REQUEST)
+    CASE_RETURN_STR(INTEROP_AVRCP_1_4_ONLY)
+    CASE_RETURN_STR(INTEROP_DISABLE_SNIFF)
   }
 
   return "UNKNOWN";
index 14e30e7..9028805 100644 (file)
@@ -316,6 +316,10 @@ std::vector<uint8_t> set_addressed_player_response = {
 std::vector<uint8_t> set_browsed_player_request = {0x70, 0x00, 0x02, 0x00,
                                                    0x02};
 
+// AVRCP Set Browsed Player Request with player_id = 0
+std::vector<uint8_t> set_browsed_player_id_0_request = {0x70, 0x00, 0x02, 0x00,
+                                                        0x00};
+
 // AVRCP Set Browsed Player Response with num items = 4 and depth = 0
 std::vector<uint8_t> set_browsed_player_response = {
     0x70, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00,
index a7e0e9a..34292d2 100644 (file)
@@ -1257,6 +1257,14 @@ void Device::SetBrowsedPlayerResponse(
     return;
   }
 
+  if (pkt->GetPlayerId() == 0 && num_items == 0) {
+    // Response fail if no browsable player in Bluetooth Player
+    auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+        Status::PLAYER_NOT_BROWSABLE, 0x0000, num_items, 0, "");
+    send_message(label, true, std::move(response));
+    return;
+  }
+
   curr_browsed_player_id_ = pkt->GetPlayerId();
 
   // Clear the path and push the new root.
index d221e1b..8d70e43 100644 (file)
@@ -1035,6 +1035,44 @@ TEST_F(AvrcpDeviceTest, setAddressedPlayerTest) {
   SendMessage(1, request);
 }
 
+TEST_F(AvrcpDeviceTest, setBrowsedPlayerTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  EXPECT_CALL(interface, SetBrowsedPlayer(_, _))
+      .Times(3)
+      .WillOnce(InvokeCb<1>(true, "", 0))
+      .WillOnce(InvokeCb<1>(false, "", 0))
+      .WillOnce(InvokeCb<1>(true, "", 2));
+
+  auto not_browsable_rsp = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+      Status::PLAYER_NOT_BROWSABLE, 0x0000, 0, 0, "");
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(not_browsable_rsp))))
+      .Times(1);
+
+  auto player_id_0_request =
+      TestBrowsePacket::Make(set_browsed_player_id_0_request);
+  SendBrowseMessage(1, player_id_0_request);
+
+  auto invalid_id_rsp = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+      Status::INVALID_PLAYER_ID, 0x0000, 0, 0, "");
+  EXPECT_CALL(response_cb,
+              Call(2, true, matchPacket(std::move(invalid_id_rsp))))
+      .Times(1);
+
+  SendBrowseMessage(2, player_id_0_request);
+
+  auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+      Status::NO_ERROR, 0x0000, 2, 0, "");
+  EXPECT_CALL(response_cb, Call(3, true, matchPacket(std::move(response))))
+      .Times(1);
+
+  SendBrowseMessage(3, player_id_0_request);
+}
+
 TEST_F(AvrcpDeviceTest, volumeChangedTest) {
   MockMediaInterface interface;
   NiceMock<MockA2dpInterface> a2dp_interface;
index a7b7218..2e915b0 100644 (file)
@@ -35,6 +35,7 @@
 #include "bt_utils.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
+#include "osi/include/properties.h"
 
 #define A2DP_AAC_DEFAULT_BITRATE 320000  // 320 kbps
 #define A2DP_AAC_MIN_BITRATE 64000       // 64 kbps
@@ -50,8 +51,11 @@ typedef struct {
   btav_a2dp_codec_bits_per_sample_t bits_per_sample;
 } tA2DP_AAC_CIE;
 
+static bool aac_source_caps_configured = false;
+static tA2DP_AAC_CIE a2dp_aac_source_caps = {};
+
 /* AAC Source codec capabilities */
-static const tA2DP_AAC_CIE a2dp_aac_source_caps = {
+static const tA2DP_AAC_CIE a2dp_aac_cbr_source_caps = {
     // objectType
     A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
     // sampleRate
@@ -66,6 +70,22 @@ static const tA2DP_AAC_CIE a2dp_aac_source_caps = {
     // bits_per_sample
     BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
 
+/* AAC Source codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_vbr_source_caps = {
+    // objectType
+    A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+    // sampleRate
+    // TODO: AAC 48.0kHz sampling rate should be added back - see b/62301376
+    A2DP_AAC_SAMPLING_FREQ_44100,
+    // channelMode
+    A2DP_AAC_CHANNEL_MODE_STEREO,
+    // variableBitRateSupport
+    A2DP_AAC_VARIABLE_BIT_RATE_ENABLED,
+    // bitRate
+    A2DP_AAC_DEFAULT_BITRATE,
+    // bits_per_sample
+    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+
 /* AAC Sink codec capabilities */
 static const tA2DP_AAC_CIE a2dp_aac_sink_caps = {
     // objectType
@@ -708,7 +728,19 @@ const char* A2DP_CodecIndexStrAac(void) { return "AAC"; }
 
 const char* A2DP_CodecIndexStrAacSink(void) { return "AAC SINK"; }
 
+void aac_source_caps_initialize() {
+  if (aac_source_caps_configured) {
+    return;
+  }
+  a2dp_aac_source_caps =
+      osi_property_get_bool("persist.bluetooth.a2dp_aac.vbr_supported", false)
+          ? a2dp_aac_vbr_source_caps
+          : a2dp_aac_cbr_source_caps;
+  aac_source_caps_configured = true;
+}
+
 bool A2DP_InitCodecConfigAac(AvdtpSepConfig* p_cfg) {
+  aac_source_caps_initialize();
   if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_source_caps,
                         p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
@@ -754,6 +786,7 @@ A2dpCodecConfigAacSource::A2dpCodecConfigAacSource(
     btav_a2dp_codec_priority_t codec_priority)
     : A2dpCodecConfigAacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
                              A2DP_CodecIndexStrAac(), codec_priority, true) {
+  aac_source_caps_initialize();
   // Compute the local capability
   if (a2dp_aac_source_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1036,6 +1069,14 @@ bool A2dpCodecConfigAacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
   result_config_cie.variableBitRateSupport =
       p_a2dp_aac_caps->variableBitRateSupport &
       peer_info_cie.variableBitRateSupport;
+  if (result_config_cie.variableBitRateSupport !=
+      A2DP_AAC_VARIABLE_BIT_RATE_DISABLED) {
+    codec_config_.codec_specific_1 =
+        static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_VBR_5);
+  } else {
+    codec_config_.codec_specific_1 =
+        static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_CBR);
+  }
 
   // Set the bit rate as follows:
   // 1. If the remote device reports a bogus bit rate
@@ -1308,16 +1349,41 @@ bool A2dpCodecConfigAacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
     goto fail;
   }
 
-  if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
-                        p_result_codec_config) != A2DP_SUCCESS) {
-    goto fail;
-  }
-
   //
   // Copy the codec-specific fields if they are not zero
   //
-  if (codec_user_config_.codec_specific_1 != 0)
-    codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+  if (codec_user_config_.codec_specific_1 != 0) {
+    if (result_config_cie.variableBitRateSupport !=
+        A2DP_AAC_VARIABLE_BIT_RATE_DISABLED) {
+      auto user_bitrate_mode = codec_user_config_.codec_specific_1;
+      switch (static_cast<AacEncoderBitrateMode>(user_bitrate_mode)) {
+        case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_C:
+          // VBR is supported, and is disabled by the user preference
+          result_config_cie.variableBitRateSupport =
+              A2DP_AAC_VARIABLE_BIT_RATE_DISABLED;
+          [[fallthrough]];
+        case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_1:
+          [[fallthrough]];
+        case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_2:
+          [[fallthrough]];
+        case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_3:
+          [[fallthrough]];
+        case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_4:
+          [[fallthrough]];
+        case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_5:
+          codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+          break;
+        default:
+          codec_config_.codec_specific_1 =
+              static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_VBR_5);
+      }
+    } else {
+      // It is no needed to check the user preference when Variable Bitrate
+      // unsupported by one of source or sink
+      codec_config_.codec_specific_1 =
+          static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_CBR);
+    }
+  }
   if (codec_user_config_.codec_specific_2 != 0)
     codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
   if (codec_user_config_.codec_specific_3 != 0)
@@ -1325,6 +1391,11 @@ bool A2dpCodecConfigAacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
   if (codec_user_config_.codec_specific_4 != 0)
     codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
 
+  if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+                        p_result_codec_config) != A2DP_SUCCESS) {
+    goto fail;
+  }
+
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
@@ -1361,6 +1432,7 @@ bool A2dpCodecConfigAacBase::setPeerCodecCapabilities(
   tA2DP_AAC_CIE peer_info_cie;
   uint8_t channelMode;
   uint16_t sampleRate;
+  uint8_t variableBitRateSupport;
   const tA2DP_AAC_CIE* p_a2dp_aac_caps =
       (is_source_) ? &a2dp_aac_source_caps : &a2dp_aac_sink_caps;
 
@@ -1413,6 +1485,17 @@ bool A2dpCodecConfigAacBase::setPeerCodecCapabilities(
         BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 
+  // Compute the selectable capability - variable bitrate mode
+  variableBitRateSupport = p_a2dp_aac_caps->variableBitRateSupport &
+                           peer_info_cie.variableBitRateSupport;
+  if (variableBitRateSupport != A2DP_AAC_VARIABLE_BIT_RATE_DISABLED) {
+    codec_selectable_capability_.codec_specific_1 =
+        static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_VBR_5);
+  } else {
+    codec_selectable_capability_.codec_specific_1 =
+        static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_CBR);
+  }
+
   status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                              ota_codec_peer_capability_);
   CHECK(status == A2DP_SUCCESS);
index 665bb04..8f32c1f 100644 (file)
@@ -414,7 +414,29 @@ static void a2dp_aac_encoder_update(uint16_t peer_mtu,
               "invalid codec bit rate mode",
               __func__);
     return;  // TODO: Return an error?
+  } else if (aac_param_value == A2DP_AAC_VARIABLE_BIT_RATE_ENABLED) {
+    // VBR has 5 modes defined in external/aac/libAACenc/src/aacenc.h
+    // A2DP_AAC_VARIABLE_BIT_RATE_DISABLED is equal to AACENC_BR_MODE_CBR
+    auto bitrate_mode = a2dp_codec_config->getCodecConfig().codec_specific_1;
+    switch (static_cast<AacEncoderBitrateMode>(bitrate_mode)) {
+      case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_1:
+        [[fallthrough]];
+      case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_2:
+        [[fallthrough]];
+      case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_3:
+        [[fallthrough]];
+      case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_4:
+        [[fallthrough]];
+      case AacEncoderBitrateMode::AACENC_BR_MODE_VBR_5:
+        break;
+      default:
+        bitrate_mode =
+            static_cast<int64_t>(AacEncoderBitrateMode::AACENC_BR_MODE_VBR_5);
+    }
+    aac_param_value =
+        static_cast<uint8_t>(bitrate_mode) & ~A2DP_AAC_VARIABLE_BIT_RATE_MASK;
   }
+  LOG_INFO(LOG_TAG, "%s: AACENC_BITRATEMODE: %d", __func__, aac_param_value);
   aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
                                   AACENC_BITRATEMODE, aac_param_value);
   if (aac_error != AACENC_OK) {
@@ -740,6 +762,14 @@ void A2dpCodecConfigAacSource::debug_codec_dump(int fd) {
 
   A2dpCodecConfig::debug_codec_dump(fd);
 
+  auto codec_specific_1 = getCodecConfig().codec_specific_1;
+  dprintf(
+      fd,
+      "  AAC bitrate mode                                        : %s "
+      "(0x%" PRIx64 ")\n",
+      ((codec_specific_1 & ~A2DP_AAC_VARIABLE_BIT_RATE_MASK) == 0 ? "Constant"
+                                                                  : "Variable"),
+      codec_specific_1);
   dprintf(fd,
           "  Packet counts (expected/dropped)                        : %zu / "
           "%zu\n",
index e132f6f..2c7bebd 100644 (file)
@@ -746,7 +746,8 @@ tBTM_STATUS BTM_SetLinkPolicy(const RawAddress& remote_bda,
                     *settings);
     }
     if ((*settings & HCI_ENABLE_SNIFF_MODE) &&
-        (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) {
+        ((!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) ||
+         interop_match_addr(INTEROP_DISABLE_SNIFF, &remote_bda))) {
       *settings &= (~HCI_ENABLE_SNIFF_MODE);
       BTM_TRACE_API("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)",
                     *settings);
index 793c854..60d5b06 100644 (file)
@@ -42,6 +42,7 @@
 #include "btm_int.h"
 #include "btm_int_types.h"
 #include "btu.h"
+#include "device/include/interop.h"
 #include "hcidefs.h"
 #include "hcimsgs.h"
 #include "l2c_int.h"
@@ -177,7 +178,8 @@ tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
     /* check if the requested mode is supported */
     ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
     p_features = BTM_ReadLocalFeatures();
-    if (!(p_features[btm_pm_mode_off[ind]] & btm_pm_mode_msk[ind])) {
+    if (!(p_features[btm_pm_mode_off[ind]] & btm_pm_mode_msk[ind]) ||
+            interop_match_addr(INTEROP_DISABLE_SNIFF, &remote_bda)) {
       LOG(ERROR) << __func__ << ": pm_id " << unsigned(pm_id) << " mode "
                  << unsigned(mode) << " is not supported for " << remote_bda;
       return BTM_MODE_UNSUPPORTED;
index 143a577..5e909d8 100644 (file)
 #ifndef A2DP_AAC_ENCODER_H
 #define A2DP_AAC_ENCODER_H
 
+#include "a2dp_aac_constants.h"
 #include "a2dp_codec_api.h"
 
+// Is used in btav_a2dp_codec_config_t.codec_specific_1 when codec is AAC
+enum class AacEncoderBitrateMode : int64_t {
+  // Variable bitrate mode unsupported when used in a codec report, and upper
+  // layer can use this value as system default (keep current settings)
+  AACENC_BR_MODE_CBR = A2DP_AAC_VARIABLE_BIT_RATE_DISABLED,
+  // Constant bitrate mode when Variable bitrate mode is supported. This can
+  // also be used to disable Variable bitrate mode by upper layer
+  AACENC_BR_MODE_VBR_C = (A2DP_AAC_VARIABLE_BIT_RATE_ENABLED | 0x00),
+  // Variable bitrate mode (very low bitrate for software encoding).
+  AACENC_BR_MODE_VBR_1 = (A2DP_AAC_VARIABLE_BIT_RATE_ENABLED | 0x01),
+  // Variable bitrate mode (low bitrate for software encoding).
+  AACENC_BR_MODE_VBR_2 = (A2DP_AAC_VARIABLE_BIT_RATE_ENABLED | 0x02),
+  // Variable bitrate mode (medium bitrate for software encoding).
+  AACENC_BR_MODE_VBR_3 = (A2DP_AAC_VARIABLE_BIT_RATE_ENABLED | 0x03),
+  // Variable bitrate mode (high bitrate for software encoding).
+  AACENC_BR_MODE_VBR_4 = (A2DP_AAC_VARIABLE_BIT_RATE_ENABLED | 0x04),
+  // Variable bitrate mode (very high bitrate for software encoding).
+  AACENC_BR_MODE_VBR_5 = (A2DP_AAC_VARIABLE_BIT_RATE_ENABLED | 0x05),
+};
+
 // Loads the A2DP AAC encoder.
 // Return true on success, otherwise false.
 bool A2DP_LoadEncoderAac(void);
index 50bcfeb..2009dda 100644 (file)
@@ -29,6 +29,8 @@
 #include "bt_common.h"
 #include "bt_types.h"
 
+#include "avrc_defs.h"
+#include "device/include/interop.h"
 #include "osi/include/osi.h"
 #include "sdp_api.h"
 #include "sdpint.h"
@@ -552,6 +554,7 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
   tSDP_RECORD* p_rec;
   tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
   tSDP_ATTRIBUTE* p_attr;
+  tSDP_ATTRIBUTE attr_sav;
   bool maxxed_out = false, is_cont = false;
   uint8_t* p_seq_start;
   uint16_t seq_len, attr_len;
@@ -650,6 +653,19 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
                                        attr_seq.attr_entry[xx].end);
 
       if (p_attr) {
+        // Check if the attribute contain AVRCP profile description list
+        uint16_t avrcp_version = sdpu_is_avrcp_profile_description_list(p_attr);
+        if (avrcp_version > AVRC_REV_1_4 &&
+            interop_match_addr(INTEROP_AVRCP_1_4_ONLY,
+                               &(p_ccb->device_address))) {
+          SDP_TRACE_DEBUG(
+              "%s, device=%s is only accept AVRCP 1.4, reply AVRCP 1.4 "
+              "instead.",
+              __func__, p_ccb->device_address.ToString().c_str());
+          memcpy(&attr_sav, p_attr, sizeof(tSDP_ATTRIBUTE));
+          attr_sav.value_ptr[attr_sav.len - 1] = 0x04;
+          p_attr = &attr_sav;
+        }
         /* Check if attribute fits. Assume 3-byte value type/length */
         rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
 
@@ -829,5 +845,4 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
   /* Send the buffer through L2CAP */
   L2CA_DataWrite(p_ccb->connection_id, p_buf);
 }
-
 #endif /* SDP_SERVER_ENABLED == TRUE */
index f66a8fd..f8cde2c 100644 (file)
@@ -31,6 +31,7 @@
 #include "bt_types.h"
 #include "btif_config.h"
 
+#include "avrc_defs.h"
 #include "sdp_api.h"
 #include "sdpint.h"
 
@@ -1155,3 +1156,41 @@ uint8_t* sdpu_build_partial_attrib_entry(uint8_t* p_out, tSDP_ATTRIBUTE* p_attr,
   osi_free(p_attr_buff);
   return p_out;
 }
+/*******************************************************************************
+ *
+ * Function         sdpu_is_avrcp_profile_description_list
+ *
+ * Description      This function is to check if attirbute contain AVRCP profile
+ *                  description list
+ *
+ *                  p_attr: attibute to be check
+ *
+ * Returns          AVRCP profile version if matched, else 0
+ *
+ ******************************************************************************/
+uint16_t sdpu_is_avrcp_profile_description_list(tSDP_ATTRIBUTE* p_attr) {
+  if (p_attr->id != ATTR_ID_BT_PROFILE_DESC_LIST || p_attr->len != 8) {
+    return 0;
+  }
+
+  uint8_t* p_uuid = p_attr->value_ptr + 3;
+  // Check if AVRCP profile UUID
+  if (p_uuid[0] != 0x11 || p_uuid[1] != 0xe) {
+    return 0;
+  }
+  uint8_t p_version = *(p_uuid + 4);
+  switch (p_version) {
+    case 0x0:
+      return AVRC_REV_1_0;
+    case 0x3:
+      return AVRC_REV_1_3;
+    case 0x4:
+      return AVRC_REV_1_4;
+    case 0x5:
+      return AVRC_REV_1_5;
+    case 0x6:
+      return AVRC_REV_1_6;
+    default:
+      return 0;
+  }
+}
index af9ccb8..ea6941c 100644 (file)
@@ -235,6 +235,7 @@ extern uint16_t sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE* p_attr);
 extern uint8_t* sdpu_build_partial_attrib_entry(uint8_t* p_out,
                                                 tSDP_ATTRIBUTE* p_attr,
                                                 uint16_t len, uint16_t* offset);
+extern uint16_t sdpu_is_avrcp_profile_description_list(tSDP_ATTRIBUTE* p_attr);
 
 /* Functions provided by sdp_db.cc
  */
index b06055f..2f5fe76 100644 (file)
@@ -303,7 +303,6 @@ void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event,
   tSMP_BR_STATE curr_state = p_cb->br_state;
   tSMP_BR_SM_TBL state_table;
   uint8_t action, entry;
-  tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role];
 
   SMP_TRACE_EVENT("main %s", __func__);
   if (curr_state >= SMP_BR_STATE_MAX) {
@@ -317,6 +316,8 @@ void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event,
     return;
   }
 
+  tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role];
+
   SMP_TRACE_DEBUG("SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
                   (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
                   smp_get_br_state_name(p_cb->br_state), p_cb->br_state,