Merge "Remove additional handle mapping between C++ and Python"
diff --git a/audio_bluetooth_hw/device_port_proxy.cc b/audio_bluetooth_hw/device_port_proxy.cc
index c082815..6e7c0d6 100644
--- a/audio_bluetooth_hw/device_port_proxy.cc
+++ b/audio_bluetooth_hw/device_port_proxy.cc
@@ -37,7 +37,8 @@
 using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
 using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
 using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
-using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using SampleRate = ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
 using BluetoothAudioStatus =
     ::android::hardware::bluetooth::audio::V2_0::Status;
 using ControlResultCallback = std::function<void(
@@ -46,29 +47,33 @@
 
 namespace {
 
-unsigned int SampleRateToAudioFormat(SampleRate sample_rate) {
+unsigned int SampleRateToAudioFormat(SampleRate_2_1 sample_rate) {
   switch (sample_rate) {
-    case SampleRate::RATE_16000:
+    case SampleRate_2_1::RATE_8000:
+      return 8000;
+    case SampleRate_2_1::RATE_16000:
       return 16000;
-    case SampleRate::RATE_24000:
+    case SampleRate_2_1::RATE_24000:
       return 24000;
-    case SampleRate::RATE_44100:
+    case SampleRate_2_1::RATE_32000:
+      return 32000;
+    case SampleRate_2_1::RATE_44100:
       return 44100;
-    case SampleRate::RATE_48000:
+    case SampleRate_2_1::RATE_48000:
       return 48000;
-    case SampleRate::RATE_88200:
+    case SampleRate_2_1::RATE_88200:
       return 88200;
-    case SampleRate::RATE_96000:
+    case SampleRate_2_1::RATE_96000:
       return 96000;
-    case SampleRate::RATE_176400:
+    case SampleRate_2_1::RATE_176400:
       return 176400;
-    case SampleRate::RATE_192000:
+    case SampleRate_2_1::RATE_192000:
       return 192000;
     default:
       return kBluetoothDefaultSampleRate;
   }
 }
-audio_channel_mask_t ChannelModeToAudioFormat(ChannelMode channel_mode) {
+audio_channel_mask_t OutputChannelModeToAudioFormat(ChannelMode channel_mode) {
   switch (channel_mode) {
     case ChannelMode::MONO:
       return AUDIO_CHANNEL_OUT_MONO;
@@ -79,6 +84,17 @@
   }
 }
 
+audio_channel_mask_t InputChannelModeToAudioFormat(ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::MONO:
+      return AUDIO_CHANNEL_IN_MONO;
+    case ChannelMode::STEREO:
+      return AUDIO_CHANNEL_IN_STEREO;
+    default:
+      return kBluetoothDefaultInputChannelModeMask;
+  }
+}
+
 audio_format_t BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample) {
   switch (bits_per_sample) {
     case BitsPerSample::BITS_16:
@@ -97,12 +113,12 @@
 
 }  // namespace
 
-BluetoothAudioPortOut::BluetoothAudioPortOut()
-    : state_(BluetoothStreamState::DISABLED),
-      session_type_(SessionType_2_1::UNKNOWN),
-      cookie_(android::bluetooth::audio::kObserversCookieUndefined) {}
+BluetoothAudioPort::BluetoothAudioPort()
+    : cookie_(android::bluetooth::audio::kObserversCookieUndefined),
+      state_(BluetoothStreamState::DISABLED),
+      session_type_(SessionType_2_1::UNKNOWN) {}
 
-bool BluetoothAudioPortOut::SetUp(audio_devices_t devices) {
+bool BluetoothAudioPort::SetUp(audio_devices_t devices) {
   if (!init_session_type(devices)) return false;
 
   state_ = BluetoothStreamState::STANDBY;
@@ -110,7 +126,7 @@
   auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
                                          const BluetoothAudioStatus& status) {
     if (!port->in_use()) {
-      LOG(ERROR) << "control_result_cb: BluetoothAudioPortOut is not in use";
+      LOG(ERROR) << "control_result_cb: BluetoothAudioPort is not in use";
       return;
     }
     if (port->cookie_ != cookie) {
@@ -122,7 +138,7 @@
   };
   auto session_changed_cb = [port = this](uint16_t cookie) {
     if (!port->in_use()) {
-      LOG(ERROR) << "session_changed_cb: BluetoothAudioPortOut is not in use";
+      LOG(ERROR) << "session_changed_cb: BluetoothAudioPort is not in use";
       return;
     }
     if (port->cookie_ != cookie) {
@@ -142,7 +158,7 @@
   return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
 }
 
-bool BluetoothAudioPortOut::init_session_type(audio_devices_t device) {
+bool BluetoothAudioPort::init_session_type(audio_devices_t device) {
   switch (device) {
     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
@@ -169,7 +185,7 @@
   return true;
 }
 
-void BluetoothAudioPortOut::TearDown() {
+void BluetoothAudioPort::TearDown() {
   if (!in_use()) {
     LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
                << ", cookie=" << StringPrintf("%#hx", cookie_) << " unknown monitor";
@@ -182,10 +198,10 @@
   cookie_ = android::bluetooth::audio::kObserversCookieUndefined;
 }
 
-void BluetoothAudioPortOut::ControlResultHandler(
+void BluetoothAudioPort::ControlResultHandler(
     const BluetoothAudioStatus& status) {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPortis not in use";
     return;
   }
   std::unique_lock<std::mutex> port_lock(cv_mutex_);
@@ -228,9 +244,9 @@
   internal_cv_.notify_all();
 }
 
-void BluetoothAudioPortOut::SessionChangedHandler() {
+void BluetoothAudioPort::SessionChangedHandler() {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use";
     return;
   }
   std::unique_lock<std::mutex> port_lock(cv_mutex_);
@@ -246,7 +262,7 @@
   internal_cv_.notify_all();
 }
 
-bool BluetoothAudioPortOut::in_use() const {
+bool BluetoothAudioPort::in_use() const {
   return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
 }
 
@@ -259,32 +275,75 @@
     return false;
   }
 
-  const AudioConfiguration& hal_audio_cfg =
-      BluetoothAudioSessionControl_2_1::GetAudioConfig(session_type_);
+  const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration&
+      hal_audio_cfg =
+          BluetoothAudioSessionControl_2_1::GetAudioConfig(session_type_);
   if (hal_audio_cfg.getDiscriminator() !=
-      AudioConfiguration::hidl_discriminator::pcmConfig) {
+      ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
+          hidl_discriminator::pcmConfig) {
     audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
     audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
     audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
     return false;
   }
-  const PcmParameters& pcm_cfg = hal_audio_cfg.pcmConfig();
+  const ::android::hardware::bluetooth::audio::V2_1::PcmParameters& pcm_cfg =
+      hal_audio_cfg.pcmConfig();
   LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
                << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", PcmConfig=["
                << toString(pcm_cfg) << "]";
-  if (pcm_cfg.sampleRate == SampleRate::RATE_UNKNOWN ||
+  if (pcm_cfg.sampleRate == SampleRate_2_1::RATE_UNKNOWN ||
       pcm_cfg.channelMode == ChannelMode::UNKNOWN ||
       pcm_cfg.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
     return false;
   }
   audio_cfg->sample_rate = SampleRateToAudioFormat(pcm_cfg.sampleRate);
   audio_cfg->channel_mask =
-      (is_stereo_to_mono_ ? AUDIO_CHANNEL_OUT_STEREO : ChannelModeToAudioFormat(pcm_cfg.channelMode));
+      (is_stereo_to_mono_
+           ? AUDIO_CHANNEL_OUT_STEREO
+           : OutputChannelModeToAudioFormat(pcm_cfg.channelMode));
   audio_cfg->format = BitsPerSampleToAudioFormat(pcm_cfg.bitsPerSample);
   return true;
 }
 
-bool BluetoothAudioPortOut::CondwaitState(BluetoothStreamState state) {
+bool BluetoothAudioPortIn::LoadAudioConfig(audio_config_t* audio_cfg) const {
+  if (!in_use()) {
+    LOG(ERROR) << __func__ << ": BluetoothAudioPortIn is not in use";
+    audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
+    audio_cfg->channel_mask = kBluetoothDefaultInputChannelModeMask;
+    audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
+    return false;
+  }
+
+  const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration&
+      hal_audio_cfg =
+          BluetoothAudioSessionControl_2_1::GetAudioConfig(session_type_);
+  if (hal_audio_cfg.getDiscriminator() !=
+      ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
+          hidl_discriminator::pcmConfig) {
+    audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
+    audio_cfg->channel_mask = kBluetoothDefaultInputChannelModeMask;
+    audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
+    return false;
+  }
+  const ::android::hardware::bluetooth::audio::V2_1::PcmParameters& pcm_cfg =
+      hal_audio_cfg.pcmConfig();
+  LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
+               << ", cookie=" << StringPrintf("%#hx", cookie_)
+               << ", state=" << state_ << ", PcmConfig=[" << toString(pcm_cfg)
+               << "]";
+  if (pcm_cfg.sampleRate == SampleRate_2_1::RATE_UNKNOWN ||
+      pcm_cfg.channelMode == ChannelMode::UNKNOWN ||
+      pcm_cfg.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+    return false;
+  }
+
+  audio_cfg->sample_rate = SampleRateToAudioFormat(pcm_cfg.sampleRate);
+  audio_cfg->channel_mask = InputChannelModeToAudioFormat(pcm_cfg.channelMode);
+  audio_cfg->format = BitsPerSampleToAudioFormat(pcm_cfg.bitsPerSample);
+  return true;
+}
+
+bool BluetoothAudioPort::CondwaitState(BluetoothStreamState state) {
   bool retval;
   std::unique_lock<std::mutex> port_lock(cv_mutex_);
   switch (state) {
@@ -313,9 +372,9 @@
   return retval;  // false if any failure like timeout
 }
 
-bool BluetoothAudioPortOut::Start() {
+bool BluetoothAudioPort::Start() {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use";
     return false;
   }
 
@@ -344,9 +403,9 @@
   return retval;  // false if any failure like timeout
 }
 
-bool BluetoothAudioPortOut::Suspend() {
+bool BluetoothAudioPort::Suspend() {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use";
     return false;
   }
 
@@ -374,9 +433,9 @@
   return retval;  // false if any failure like timeout
 }
 
-void BluetoothAudioPortOut::Stop() {
+void BluetoothAudioPort::Stop() {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use";
     return;
   }
   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
@@ -406,11 +465,17 @@
          2;
 }
 
-bool BluetoothAudioPortOut::GetPresentationPosition(uint64_t* delay_ns,
-                                                    uint64_t* bytes,
-                                                    timespec* timestamp) const {
+size_t BluetoothAudioPortIn::ReadData(void* buffer, size_t bytes) const {
+  if (!in_use()) return 0;
+  return BluetoothAudioSessionControl_2_1::InReadPcmData(session_type_, buffer,
+                                                         bytes);
+}
+
+bool BluetoothAudioPort::GetPresentationPosition(uint64_t* delay_ns,
+                                                 uint64_t* bytes,
+                                                 timespec* timestamp) const {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use";
     return false;
   }
   bool retval = BluetoothAudioSessionControl_2_1::GetPresentationPosition(
@@ -423,10 +488,10 @@
   return retval;
 }
 
-void BluetoothAudioPortOut::UpdateMetadata(
+void BluetoothAudioPort::UpdateMetadata(
     const source_metadata* source_metadata) const {
   if (!in_use()) {
-    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+    LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use";
     return;
   }
   LOG(DEBUG) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
@@ -436,9 +501,9 @@
                                                          source_metadata);
 }
 
-BluetoothStreamState BluetoothAudioPortOut::GetState() const { return state_; }
+BluetoothStreamState BluetoothAudioPort::GetState() const { return state_; }
 
-void BluetoothAudioPortOut::SetState(BluetoothStreamState state) {
+void BluetoothAudioPort::SetState(BluetoothStreamState state) {
   state_ = state;
 }
 
diff --git a/audio_bluetooth_hw/device_port_proxy.h b/audio_bluetooth_hw/device_port_proxy.h
index 25f5376..3541573 100644
--- a/audio_bluetooth_hw/device_port_proxy.h
+++ b/audio_bluetooth_hw/device_port_proxy.h
@@ -35,24 +35,24 @@
 // Session Control. All methods are not thread safe, so users must acquire a
 // lock. Note: currently, in stream_apis.cc, if GetState() is only used for
 // verbose logging, it is not locked, so the state may not be synchronized.
-class BluetoothAudioPortOut {
+class BluetoothAudioPort {
  public:
-  BluetoothAudioPortOut();
-  ~BluetoothAudioPortOut() = default;
+  BluetoothAudioPort();
+  virtual ~BluetoothAudioPort() = default;
 
-  // Fetch output control / data path of BluetoothAudioPortOut and setup
+  // Fetch output control / data path of BluetoothAudioPort and setup
   // callbacks into BluetoothAudioProvider. If SetUp() returns false, the audio
-  // HAL must delete this BluetoothAudioPortOut and return EINVAL to caller
+  // HAL must delete this BluetoothAudioPort and return EINVAL to caller
   bool SetUp(audio_devices_t devices);
 
-  // Unregister this BluetoothAudioPortOut from BluetoothAudioSessionControl.
-  // Audio HAL must delete this BluetoothAudioPortOut after calling this.
+  // Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
+  // Audio HAL must delete this BluetoothAudioPort after calling this.
   void TearDown();
 
   // When the Audio framework / HAL tries to query audio config about format,
   // channel mask and sample rate, it uses this function to fetch from the
   // Bluetooth stack
-  bool LoadAudioConfig(audio_config_t* audio_cfg) const;
+  virtual bool LoadAudioConfig(audio_config_t* audio_cfg) const = 0;
 
   // WAR to support Mono mode / 16 bits per sample
   void ForcePcmStereoToMono(bool force) {
@@ -92,21 +92,22 @@
            session_type_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH;
   }
 
- private:
+ protected:
+  uint16_t cookie_;
   BluetoothStreamState state_;
   SessionType_2_1 session_type_;
-  uint16_t cookie_;
-  mutable std::mutex cv_mutex_;
-  std::condition_variable internal_cv_;
   // WR to support Mono: True if fetching Stereo and mixing into Mono
   bool is_stereo_to_mono_ = false;
+  bool in_use() const;
+
+ private:
+  mutable std::mutex cv_mutex_;
+  std::condition_variable internal_cv_;
 
   // Check and initialize session type for |devices| If failed, this
-  // BluetoothAudioPortOut is not initialized and must be deleted.
+  // BluetoothAudioPort is not initialized and must be deleted.
   bool init_session_type(audio_devices_t device);
 
-  bool in_use() const;
-
   bool CondwaitState(BluetoothStreamState state);
 
   void ControlResultHandler(
@@ -114,6 +115,24 @@
   void SessionChangedHandler();
 };
 
+class BluetoothAudioPortOut : public BluetoothAudioPort {
+ public:
+  ~BluetoothAudioPortOut() = default;
+
+  // The audio data path to the Bluetooth stack (Software encoding)
+  size_t WriteData(const void* buffer, size_t bytes) const;
+  bool LoadAudioConfig(audio_config_t* audio_cfg) const;
+};
+
+class BluetoothAudioPortIn : public BluetoothAudioPort {
+ public:
+  ~BluetoothAudioPortIn() = default;
+
+  // The audio data path from the Bluetooth stack (Software decoded)
+  size_t ReadData(void* buffer, size_t bytes) const;
+  bool LoadAudioConfig(audio_config_t* audio_cfg) const;
+};
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace android
diff --git a/audio_bluetooth_hw/stream_apis.h b/audio_bluetooth_hw/stream_apis.h
index c894d1e..7b51663 100644
--- a/audio_bluetooth_hw/stream_apis.h
+++ b/audio_bluetooth_hw/stream_apis.h
@@ -31,6 +31,8 @@
 constexpr unsigned int kBluetoothDefaultOutputBufferMs = 10;
 constexpr audio_channel_mask_t kBluetoothDefaultOutputChannelModeMask =
     AUDIO_CHANNEL_OUT_STEREO;
+constexpr audio_channel_mask_t kBluetoothDefaultInputChannelModeMask =
+    AUDIO_CHANNEL_IN_MONO;
 
 enum class BluetoothStreamState : uint8_t {
   DISABLED = 0,  // This stream is closing or set param "suspend=true"
diff --git a/gd/cert/py_le_acl_manager.py b/gd/cert/py_le_acl_manager.py
index e6cc8ee..c52a5ab 100644
--- a/gd/cert/py_le_acl_manager.py
+++ b/gd/cert/py_le_acl_manager.py
@@ -81,7 +81,7 @@
     def close(self):
         safeClose(self.incoming_connection_event_stream)
         for v in self.outgoing_connection_event_streams.values():
-            safeClose(v)
+            safeClose(v[0])
         for connection in self.active_connections:
             safeClose(connection)
 
@@ -98,10 +98,16 @@
         self.listen_for_incoming_connections()
         return self.complete_incoming_connection()
 
+    def cancel_connection(self, token):
+        assertThat(token in self.outgoing_connection_event_streams).isTrue()
+        pair = self.outgoing_connection_event_streams.pop(token)
+        safeClose(pair[0])
+        self.le_acl_manager.CancelConnection(pair[1])
+
     def initiate_connection(self, remote_addr):
         assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse()
         self.outgoing_connection_event_streams[self.next_token] = EventStream(
-            self.le_acl_manager.CreateConnection(remote_addr))
+            self.le_acl_manager.CreateConnection(remote_addr)), remote_addr
         token = self.next_token
         self.next_token += 1
         return token
@@ -128,5 +134,5 @@
 
     def complete_outgoing_connection(self, token):
         assertThat(self.outgoing_connection_event_streams[token]).isNotNone()
-        event_stream = self.outgoing_connection_event_streams.pop(token)
+        event_stream = self.outgoing_connection_event_streams.pop(token)[0]
         return self.complete_connection(event_stream)
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
index 03a2582..76a8021 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -1792,6 +1792,14 @@
   ErrorCode status = link_layer_controller_.SetLeConnect(false);
   send_event_(bluetooth::hci::LeCreateConnectionCancelCompleteBuilder::Create(
       kNumCommandPackets, status));
+
+  send_event_(bluetooth::hci::LeConnectionCompleteBuilder::Create(
+      ErrorCode::UNKNOWN_CONNECTION, kReservedHandle,
+      bluetooth::hci::Role::CENTRAL,
+      bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS,
+      bluetooth::hci::Address(), 1 /* connection_interval */,
+      2 /* connection_latency */, 3 /* supervision_timeout*/,
+      static_cast<bluetooth::hci::ClockAccuracy>(0x00)));
 }
 
 void DualModeController::LeReadConnectListSize(CommandView command) {
@@ -1933,17 +1941,21 @@
   ASSERT(command_view.GetScanningPhys() == 1);
   ASSERT(parameters.size() == 1);
 
-  link_layer_controller_.SetLeScanType(
-      static_cast<uint8_t>(parameters[0].le_scan_type_));
-  link_layer_controller_.SetLeScanInterval(parameters[0].le_scan_interval_);
-  link_layer_controller_.SetLeScanWindow(parameters[0].le_scan_window_);
-  link_layer_controller_.SetLeAddressType(command_view.GetOwnAddressType());
-  link_layer_controller_.SetLeScanFilterPolicy(
-      static_cast<uint8_t>(command_view.GetScanningFilterPolicy()));
-  auto packet =
+  auto status = ErrorCode::SUCCESS;
+  if (link_layer_controller_.GetLeScanEnable() == OpCode::NONE) {
+    link_layer_controller_.SetLeScanType(
+        static_cast<uint8_t>(parameters[0].le_scan_type_));
+    link_layer_controller_.SetLeScanInterval(parameters[0].le_scan_interval_);
+    link_layer_controller_.SetLeScanWindow(parameters[0].le_scan_window_);
+    link_layer_controller_.SetLeAddressType(command_view.GetOwnAddressType());
+    link_layer_controller_.SetLeScanFilterPolicy(
+        static_cast<uint8_t>(command_view.GetScanningFilterPolicy()));
+  } else {
+    status = ErrorCode::COMMAND_DISALLOWED;
+  }
+  send_event_(
       bluetooth::hci::LeSetExtendedScanParametersCompleteBuilder::Create(
-          kNumCommandPackets, ErrorCode::SUCCESS);
-  send_event_(std::move(packet));
+          kNumCommandPackets, status));
 }
 
 void DualModeController::LeSetExtendedScanEnable(CommandView command) {
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
index bd4b584..1f2da36 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
@@ -237,6 +237,8 @@
       bluetooth::hci::Enable enable,
       const std::vector<bluetooth::hci::EnabledSet>& enabled_sets);
 
+  bluetooth::hci::OpCode GetLeScanEnable() { return le_scan_enable_; }
+
   void SetLeScanEnable(bluetooth::hci::OpCode enabling_opcode) {
     le_scan_enable_ = enabling_opcode;
   }