Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 615fdc12 authored by Jakub Tyszkowski's avatar Jakub Tyszkowski
Browse files

LeAudio: Improve the debug state dumps and logs

- reduce the number of system calls (dprintf) on dumpsys when accessing
  file descriptor
- make the state dumping functions available in regular debug printing
  without the need for file descriptors (usable for state printing
  during debbugging)
- rearrange and cleanup the LE Audio dumpsys output
- improve some regular logs for readability (incl. mono location)
- indicate codec extensibility status (enabled/disabled)

Bug: 374933885
Test: m -j
Flag: Exempt; No functional changes
Change-Id: I5ba5b54f175df374cc5fdd26e543e75e42ed0844
parent 6976c730
Loading
Loading
Loading
Loading
+2 −4
Original line number Original line Diff line number Diff line
@@ -51,15 +51,13 @@ void GmapClient::AddFromStorage(const RawAddress &addr, const uint8_t role,
  UGT_feature_handle_ = UGT_feature_handle;
  UGT_feature_handle_ = UGT_feature_handle;
}
}


void GmapClient::DebugDump(int fd) {
void GmapClient::DebugDump(std::stringstream &stream) {
  std::stringstream stream;
  if (!IsGmapClientEnabled()) {
  if (!IsGmapClientEnabled()) {
    dprintf(fd, "%s", "GmapClient not enabled");
    stream << "GmapClient not enabled\n";
    return;
    return;
  }
  }
  stream << "GmapClient device: " << addr_ << ", Role: " << role_ << ", ";
  stream << "GmapClient device: " << addr_ << ", Role: " << role_ << ", ";
  stream << "UGT Feature: " << UGT_feature_ << "\n";
  stream << "UGT Feature: " << UGT_feature_ << "\n";
  dprintf(fd, "%s", stream.str().c_str());
}
}


bool GmapClient::IsGmapClientEnabled() {
bool GmapClient::IsGmapClientEnabled() {
+63 −42
Original line number Original line Diff line number Diff line
@@ -352,6 +352,7 @@ public:
            close_vbc_timeout_, timeoutMs,
            close_vbc_timeout_, timeoutMs,
            [](void*) {
            [](void*) {
              if (instance) {
              if (instance) {
                log::debug("Reconfigure after VBC close");
                instance->ReconfigureAfterVbcClose();
                instance->ReconfigureAfterVbcClose();
              }
              }
            },
            },
@@ -382,7 +383,9 @@ public:
            suspend_timeout_, timeoutMs,
            suspend_timeout_, timeoutMs,
            [](void* data) {
            [](void* data) {
              if (instance) {
              if (instance) {
                instance->GroupStop(PTR_TO_INT(data));
                auto const group_id = PTR_TO_INT(data);
                log::debug("No resume request received. Stop the group ID: {}", group_id);
                instance->GroupStop(group_id);
              }
              }
            },
            },
            INT_TO_PTR(active_group_id_));
            INT_TO_PTR(active_group_id_));
@@ -3298,7 +3301,7 @@ public:
  }
  }


  void scheduleAttachDeviceToTheStream(const RawAddress& addr) {
  void scheduleAttachDeviceToTheStream(const RawAddress& addr) {
    log::info("Device {} scheduler for stream", addr);
    log::info("Device {} is scheduled for streaming", addr);
    do_in_main_thread_delayed(base::BindOnce(&LeAudioClientImpl::restartAttachToTheStream,
    do_in_main_thread_delayed(base::BindOnce(&LeAudioClientImpl::restartAttachToTheStream,
                                             weak_factory_.GetWeakPtr(), addr),
                                             weak_factory_.GetWeakPtr(), addr),
                              std::chrono::milliseconds(kDeviceAttachDelayMs));
                              std::chrono::milliseconds(kDeviceAttachDelayMs));
@@ -3883,64 +3886,79 @@ public:
    stack::l2cap::get_interface().L2CA_SetEcosystemBaseInterval(0 /* clear recommendation */);
    stack::l2cap::get_interface().L2CA_SetEcosystemBaseInterval(0 /* clear recommendation */);
  }
  }


  void printCurrentStreamConfiguration(int fd) {
  void printCurrentStreamConfiguration(std::stringstream& stream) {
    std::stringstream stream;
    auto config_printer = [&stream](LeAudioCodecConfiguration& conf) {
    auto config_printer = [&stream](LeAudioCodecConfiguration& conf) {
      stream << "\tsample rate: " << +conf.sample_rate << ",\tchan: " << +conf.num_channels
      stream << "\tsample rate: " << +conf.sample_rate << ", chan: " << +conf.num_channels
             << ",\tbits: " << +conf.bits_per_sample
             << ", bits: " << +conf.bits_per_sample
             << ",\tdata_interval_us: " << +conf.data_interval_us << "\n";
             << ", data_interval_us: " << +conf.data_interval_us << "\n";
    };
    };


    stream << " Speaker codec config (audio framework) \n";
    stream << "\n";
    stream << "  Speaker codec config (audio framework):\n";
    stream << "\taudio sender state: " << audio_sender_state_ << "\n";
    stream << "\taudio sender state: " << audio_sender_state_ << "\n";
    config_printer(audio_framework_source_config);
    config_printer(audio_framework_source_config);


    stream << " Microphone codec config (audio framework) \n";
    stream << "  Microphone codec config (audio framework):\n";
    stream << "\taudio receiver state: " << audio_receiver_state_ << "\n";
    stream << "\taudio receiver state: " << audio_receiver_state_ << "\n";
    config_printer(audio_framework_sink_config);
    config_printer(audio_framework_sink_config);


    stream << " Speaker codec config (SW encoder)\n";
    stream << "  Speaker codec config (SW encoder):\n";
    config_printer(current_encoder_config_);
    config_printer(current_encoder_config_);


    stream << " Microphone codec config (SW decoder)\n";
    stream << "  Microphone codec config (SW decoder):\n";
    config_printer(current_decoder_config_);
    config_printer(current_decoder_config_);

    dprintf(fd, "%s", stream.str().c_str());
  }
  }


  void Dump(int fd) {
  void Dump(int fd) {
    dprintf(fd, "  APP ID: %d \n", gatt_if_);
    std::stringstream stream;
    dprintf(fd, "  Active group: %d\n", active_group_id_);

    dprintf(fd, "  reconnection mode: %s \n",
    stream << "  APP ID: " << +gatt_if_ << "\n";
            (reconnection_mode_ == BTM_BLE_BKG_CONNECT_ALLOW_LIST ? "Allow List"
    stream << "  TBS state: " << (in_call_ ? " In call" : "No calls") << "\n";
                                                                  : "Targeted Announcements"));
    stream << "  Active group: " << +active_group_id_ << "\n";
    dprintf(fd, "  configuration: %s  (0x%08x)\n",
    stream << "  Reconnection mode: "
            bluetooth::common::ToString(configuration_context_type_).c_str(),
           << (reconnection_mode_ == BTM_BLE_BKG_CONNECT_ALLOW_LIST ? "Allow List"
            static_cast<uint16_t>(configuration_context_type_));
                                                                    : "Targeted Announcements")
    dprintf(fd, "  local source metadata context type mask: %s\n",
           << "\n";
            local_metadata_context_types_.source.to_string().c_str());
    stream << "  Configuration: " << bluetooth::common::ToString(configuration_context_type_)
    dprintf(fd, "  local sink metadata context type mask: %s\n",
           << " (" << loghex(static_cast<uint16_t>(configuration_context_type_)) << ")\n";
            local_metadata_context_types_.sink.to_string().c_str());
    stream << "  Local source metadata context type mask: "
    dprintf(fd, "  TBS state: %s\n", in_call_ ? " In call" : "No calls");
           << local_metadata_context_types_.source.to_string() << "\n";
    dprintf(fd, "  Sink listening mode: %s\n", sink_monitor_mode_ ? "true" : "false");
    stream << "  Local sink metadata context type mask: "
           << local_metadata_context_types_.sink.to_string() << "\n";
    stream << "  Sink listening mode: " << (sink_monitor_mode_ ? "true" : "false") << "\n";
    if (sink_monitor_notified_status_) {
    if (sink_monitor_notified_status_) {
      dprintf(fd, "  Local sink notified state: %d\n",
      stream << "  Local sink notified state: "
              static_cast<int>(sink_monitor_notified_status_.value()));
             << static_cast<int>(sink_monitor_notified_status_.value()) << "\n";
    }
    stream << "  Source monitor mode: " << (source_monitor_mode_ ? "true" : "false") << "\n";

    auto codec_loc = CodecManager::GetInstance()->GetCodecLocation();
    if (codec_loc == bluetooth::le_audio::types::CodecLocation::HOST) {
      stream << "  Codec location: HOST\n";
    } else if (codec_loc == bluetooth::le_audio::types::CodecLocation::CONTROLLER) {
      stream << "  Codec location: CONTROLLER\n";
    } else if (codec_loc == bluetooth::le_audio::types::CodecLocation::ADSP) {
      stream << "  Codec location: ADSP"
             << (CodecManager::GetInstance()->IsUsingCodecExtensibility() ? " (codec extensibility)"
                                                                          : "")
             << "\n";
    } else {
      dprintf(fd, "  Codec location: UNKNOWN\n");
    }
    }
    dprintf(fd, "  Source monitor mode: %s\n", source_monitor_mode_ ? "true" : "false");

    dprintf(fd, "  Codec extensibility: %s\n",
    stream << "  Start time: ";
            CodecManager::GetInstance()->IsUsingCodecExtensibility() ? "true" : "false");
    dprintf(fd, "  Start time: ");
    for (auto t : stream_start_history_queue_) {
    for (auto t : stream_start_history_queue_) {
      dprintf(fd, ", %d ms", static_cast<int>(t));
      stream << static_cast<int>(t) << " ms, ";
    }
    }
    dprintf(fd, "\n");
    stream << "\n";
    printCurrentStreamConfiguration(fd);
    printCurrentStreamConfiguration(stream);
    dprintf(fd, "  ----------------\n ");
    stream << "\n";
    dprintf(fd, "  LE Audio Groups:\n");
    aseGroups_.Dump(stream, active_group_id_);
    aseGroups_.Dump(fd, active_group_id_);
    stream << "\n ";
    dprintf(fd, "\n  Not grouped devices:\n");
    stream << "  Not grouped devices:\n";
    leAudioDevices_.Dump(fd, bluetooth::groups::kGroupUnknown);
    leAudioDevices_.Dump(stream, bluetooth::groups::kGroupUnknown);

    dprintf(fd, "%s", stream.str().c_str());


    if (leAudioHealthStatus_) {
    if (leAudioHealthStatus_) {
      leAudioHealthStatus_->DebugDump(fd);
      leAudioHealthStatus_->DebugDump(fd);
@@ -4057,7 +4075,9 @@ public:
              disable_timer_, kAudioDisableTimeoutMs,
              disable_timer_, kAudioDisableTimeoutMs,
              [](void* data) {
              [](void* data) {
                if (instance) {
                if (instance) {
                  instance->GroupSuspend(PTR_TO_INT(data));
                  auto const group_id = PTR_TO_INT(data);
                  log::debug("No resume request received. Suspend the group ID: {}", group_id);
                  instance->GroupSuspend(group_id);
                }
                }
              },
              },
              INT_TO_PTR(active_group_id_));
              INT_TO_PTR(active_group_id_));
@@ -4612,6 +4632,7 @@ public:
    }
    }


    StopSuspendTimeout();
    StopSuspendTimeout();
    /* If group suspend is scheduled, cancel as we are stopping it anyway */


    /* Need to reconfigure stream. At this point pre_configuration_context_type shall be set */
    /* Need to reconfigure stream. At this point pre_configuration_context_type shall be set */


+37 −42
Original line number Original line Diff line number Diff line
@@ -2101,7 +2101,7 @@ void LeAudioDeviceGroup::PrintDebugState(void) const {
            << bluetooth::common::ToString(GetSupportedContexts())
            << bluetooth::common::ToString(GetSupportedContexts())
            << ", \n group available contexts: "
            << ", \n group available contexts: "
            << bluetooth::common::ToString(GetAvailableContexts())
            << bluetooth::common::ToString(GetAvailableContexts())
            << ", \n group allowed contexts: "
            << ", \n group user allowed contexts: "
            << bluetooth::common::ToString(GetAllowedContextMask())
            << bluetooth::common::ToString(GetAllowedContextMask())
            << ", \n configuration context type: "
            << ", \n configuration context type: "
            << bluetooth::common::ToString(GetConfigurationContextType())
            << bluetooth::common::ToString(GetConfigurationContextType())
@@ -2142,42 +2142,29 @@ void LeAudioDeviceGroup::PrintDebugState(void) const {
  }
  }
}
}


void LeAudioDeviceGroup::Dump(int fd, int active_group_id) const {
void LeAudioDeviceGroup::Dump(std::stringstream& stream, int active_group_id) const {
  bool is_active = (group_id_ == active_group_id);
  bool is_active = (group_id_ == active_group_id);
  std::stringstream stream, stream_pacs;
  auto active_conf = GetActiveConfiguration();
  auto active_conf = GetActiveConfiguration();


  stream << "\n    == Group id: " << group_id_ << (is_enabled_ ? " enabled" : " disabled")
  stream << "     Group id: " << group_id_ << ", " << (is_enabled_ ? "Enabled" : "Disabled")
         << " == " << (is_active ? ",\tActive\n" : ",\tInactive\n") << "      state: " << GetState()
         << ", " << (is_active ? "Active\n" : "Inactive\n") << "      Current state: " << GetState()
         << ",\ttarget state: " << GetTargetState() << ",\tcig state: " << cig.GetState() << "\n"
         << ",\ttarget state: " << GetTargetState() << ",\tcig state: " << cig.GetState() << "\n"
         << "      group supported contexts: " << GetSupportedContexts() << "\n"
         << "      Group supported contexts: " << GetSupportedContexts() << "\n"
         << "      group available contexts: " << GetAvailableContexts() << "\n"
         << "      Group available contexts: " << GetAvailableContexts() << "\n"
         << "      group allowed contexts: " << GetAllowedContextMask() << "\n"
         << "      Group user allowed contexts: " << GetAllowedContextMask() << "\n"
         << "      configuration context type: "
         << "      Configuration context type: "
         << bluetooth::common::ToString(GetConfigurationContextType()).c_str() << "\n"
         << bluetooth::common::ToString(GetConfigurationContextType()).c_str() << "\n"
         << "      active configuration name: " << (active_conf ? active_conf->name : " not set")
         << "      Active configuration name:\t" << (active_conf ? active_conf->name : "Not set")
         << "\n"
         << "\n"
         << "      stream configuration: "
         << "      Stream configuration:\t\t"
         << (stream_conf.conf != nullptr ? stream_conf.conf->name : " unknown ") << "\n"
         << (stream_conf.conf != nullptr ? stream_conf.conf->name : "Not set ") << "\n"
         << "      codec id: " << +(stream_conf.codec_id.coding_format)
         << "      Codec ID: " << +(stream_conf.codec_id.coding_format)
         << ",\tpending_configuration: " << stream_conf.pending_configuration << "\n"
         << ",\tpending reconfiguration: " << stream_conf.pending_configuration << "\n"
         << "      num of devices(connected): " << Size() << "(" << NumOfConnected() << ")\n"
         << "      Num of devices:\t" << Size() << " (" << NumOfConnected() << " connected)\n"
         << ",     num of sinks(connected): " << stream_conf.stream_params.sink.num_of_devices
         << "      Num of sinks:\t" << stream_conf.stream_params.sink.num_of_devices << " ("
         << "(" << stream_conf.stream_params.sink.stream_locations.size() << ")\n"
         << stream_conf.stream_params.sink.stream_locations.size() << " connected)\n"
         << "      num of sources(connected): " << stream_conf.stream_params.source.num_of_devices
         << "      Num of sources:\t" << stream_conf.stream_params.source.num_of_devices << " ("
         << "(" << stream_conf.stream_params.source.stream_locations.size() << ")\n"
         << stream_conf.stream_params.source.stream_locations.size() << " connected)";
         << "      allocated CISes: " << static_cast<int>(cig.cises.size());

  if (cig.cises.size() > 0) {
    stream << "\n\t == CISes == ";
    for (auto cis : cig.cises) {
      stream << "\n\t cis id: " << static_cast<int>(cis.id)
             << ",\ttype: " << static_cast<int>(cis.type)
             << ",\tconn_handle: " << static_cast<int>(cis.conn_handle)
             << ",\taddr: " << ADDRESS_TO_LOGGABLE_STR(cis.addr);
    }
    stream << "\n\t ====";
  }


  if (GetFirstActiveDevice() != nullptr) {
  if (GetFirstActiveDevice() != nullptr) {
    uint32_t sink_delay;
    uint32_t sink_delay;
@@ -2190,21 +2177,27 @@ void LeAudioDeviceGroup::Dump(int fd, int active_group_id) const {
      stream << "\n      presentation_delay for source (microphone): " << source_delay << " us";
      stream << "\n      presentation_delay for source (microphone): " << source_delay << " us";
    }
    }
  }
  }
  stream << "\n";


  stream << "\n      == devices: ==";
  stream << "      == CISes (" << static_cast<int>(cig.cises.size()) << "):";

  if (cig.cises.size() > 0) {
  dprintf(fd, "%s", stream.str().c_str());
    for (auto cis : cig.cises) {
      stream << "\n\t cis id: " << static_cast<int>(cis.id)
             << ",\ttype: " << static_cast<int>(cis.type)
             << ",\tconn_handle: " << static_cast<int>(cis.conn_handle)
             << ",\taddr: " << ADDRESS_TO_LOGGABLE_STR(cis.addr);
    }
  }
  stream << "\n";


  for (const auto& device_iter : leAudioDevices_) {
  for (const auto& device_iter : leAudioDevices_) {
    device_iter.lock()->Dump(fd);
    device_iter.lock()->Dump(stream);
  }
  }


  for (const auto& device_iter : leAudioDevices_) {
  for (const auto& device_iter : leAudioDevices_) {
    auto device = device_iter.lock();
    device_iter.lock()->DumpPacsDebugState(stream);
    stream_pacs << "\n\taddress: " << device->address_;
    device->DumpPacsDebugState(stream_pacs);
  }
  }
  dprintf(fd, "%s", stream_pacs.str().c_str());
  stream << "\n";
}
}


LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) {
LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) {
@@ -2244,19 +2237,21 @@ void LeAudioDeviceGroups::Cleanup(void) {
  groups_.clear();
  groups_.clear();
}
}


void LeAudioDeviceGroups::Dump(int fd, int active_group_id) const {
void LeAudioDeviceGroups::Dump(std::stringstream& stream, int active_group_id) const {
  /* Dump first active group */
  /* Dump first active group */
  stream << "  == Active Groups:\n";
  for (auto& g : groups_) {
  for (auto& g : groups_) {
    if (g->group_id_ == active_group_id) {
    if (g->group_id_ == active_group_id) {
      g->Dump(fd, active_group_id);
      g->Dump(stream, active_group_id);
      break;
      break;
    }
    }
  }
  }


  /* Dump non active group */
  /* Dump non active group */
  stream << "  == Inactive Groups:\n";
  for (auto& g : groups_) {
  for (auto& g : groups_) {
    if (g->group_id_ != active_group_id) {
    if (g->group_id_ != active_group_id) {
      g->Dump(fd, active_group_id);
      g->Dump(stream, active_group_id);
    }
    }
  }
  }
}
}
+2 −2
Original line number Original line Diff line number Diff line
@@ -407,7 +407,7 @@ public:
  bool IsReleasingOrIdle(void) const;
  bool IsReleasingOrIdle(void) const;


  void PrintDebugState(void) const;
  void PrintDebugState(void) const;
  void Dump(int fd, int active_group_id) const;
  void Dump(std::stringstream& stream, int active_group_id) const;


  /* Codec configuration matcher supporting the legacy configuration provider
  /* Codec configuration matcher supporting the legacy configuration provider
   * mechanism for the non-vendor and software codecs. Only if the codec
   * mechanism for the non-vendor and software codecs. Only if the codec
@@ -499,7 +499,7 @@ public:
  size_t Size() const;
  size_t Size() const;
  bool IsAnyInTransition() const;
  bool IsAnyInTransition() const;
  void Cleanup(void);
  void Cleanup(void);
  void Dump(int fd, int active_group_id) const;
  void Dump(std::stringstream& stream, int active_group_id) const;


private:
private:
  std::vector<std::unique_ptr<LeAudioDeviceGroup>> groups_;
  std::vector<std::unique_ptr<LeAudioDeviceGroup>> groups_;
+44 −49
Original line number Original line Diff line number Diff line
@@ -922,14 +922,14 @@ uint8_t LeAudioDevice::GetPhyBitmask(void) const {
void LeAudioDevice::PrintDebugState(void) {
void LeAudioDevice::PrintDebugState(void) {
  std::stringstream debug_str;
  std::stringstream debug_str;


  debug_str << " address: " << address_ << ", " << bluetooth::common::ToString(connection_state_)
  debug_str << " Address: " << address_ << ", " << bluetooth::common::ToString(connection_state_)
            << ", conn_id: " << +conn_id_ << ", mtu: " << +mtu_
            << ", conn_id: " << +conn_id_ << ", mtu: " << +mtu_
            << ", num_of_ase: " << static_cast<int>(ases_.size());
            << ", num_of_ase: " << static_cast<int>(ases_.size());


  if (ases_.size() > 0) {
  if (ases_.size() > 0) {
    debug_str << "\n  == ASEs == ";
    debug_str << "\n  == ASEs == ";
    for (auto& ase : ases_) {
    for (auto& ase : ases_) {
      debug_str << "\n  id: " << +ase.id << ", active: " << ase.active
      debug_str << "  id: " << +ase.id << ", active: " << ase.active
                << ", dir: " << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source")
                << ", dir: " << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source")
                << ", state: " << bluetooth::common::ToString(ase.state)
                << ", state: " << bluetooth::common::ToString(ase.state)
                << ", cis_id: " << +ase.cis_id << ", cis_handle: " << +ase.cis_conn_hdl
                << ", cis_id: " << +ase.cis_id << ", cis_handle: " << +ase.cis_conn_hdl
@@ -942,7 +942,7 @@ void LeAudioDevice::PrintDebugState(void) {
                << ", presentation_delay: " << +ase.qos_config.presentation_delay
                << ", presentation_delay: " << +ase.qos_config.presentation_delay
                << ", framing: " << +ase.qos_config.framing << ", phy: " << +ase.qos_config.phy
                << ", framing: " << +ase.qos_config.framing << ", phy: " << +ase.qos_config.phy
                << ", target latency: " << +ase.target_latency
                << ", target latency: " << +ase.target_latency
                << ", reconfigure: " << ase.reconfigure << "\n";
                << ", reconfigure: " << ase.reconfigure << "\n\n";
    }
    }
  }
  }


@@ -979,80 +979,81 @@ void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream,
                                       types::PublishedAudioCapabilities pacs) {
                                       types::PublishedAudioCapabilities pacs) {
  if (pacs.size() > 0) {
  if (pacs.size() > 0) {
    for (auto& pac : pacs) {
    for (auto& pac : pacs) {
      stream << "\n\t\tvalue handle: " << loghex(std::get<0>(pac).val_hdl)
      stream << "\t    • Value handle: " << loghex(std::get<0>(pac).val_hdl)
             << " / CCC handle: " << loghex(std::get<0>(pac).ccc_hdl);
             << ", CCC handle: " << loghex(std::get<0>(pac).ccc_hdl);


      for (auto& record : std::get<1>(pac)) {
      for (auto& record : std::get<1>(pac)) {
        stream << "\n\n\t\tCodecId(Coding format: "
        stream << "\n\t\t· CodecId (Coding format: " << loghex(record.codec_id.coding_format)
               << static_cast<int>(record.codec_id.coding_format)
               << ", Vendor company ID: " << loghex(record.codec_id.vendor_company_id)
               << ", Vendor company ID: " << static_cast<int>(record.codec_id.vendor_company_id)
               << ", Vendor codec ID: " << loghex(record.codec_id.vendor_codec_id) << ")";
               << ", Vendor codec ID: " << static_cast<int>(record.codec_id.vendor_codec_id) << ")";
        stream << "\n\t\t    Codec specific capabilities:\n";
        stream << "\n\t\t    Codec specific capabilities:\n";
        if (utils::IsCodecUsingLtvFormat(record.codec_id)) {
        if (utils::IsCodecUsingLtvFormat(record.codec_id)) {
          stream << record.codec_spec_caps.ToString("\t\t\t", types::CodecCapabilitiesLtvFormat);
          stream << record.codec_spec_caps.ToString("\t\t\t", types::CodecCapabilitiesLtvFormat);
        } else {
        } else {
          stream << "\t\t\t"
          stream << "\t\t\t"
                 << base::HexEncode(record.codec_spec_caps_raw.data(),
                 << base::HexEncode(record.codec_spec_caps_raw.data(),
                                    record.codec_spec_caps_raw.size());
                                    record.codec_spec_caps_raw.size())
                 << "\n";
        }
        }
        stream << "\t\t    Metadata: "
        stream << "\t\t    Metadata: "
               << base::HexEncode(record.metadata.data(), record.metadata.size());
               << base::HexEncode(record.metadata.data(), record.metadata.size());
      }
      }
      stream << "\n";
    }
    }
  }
  }
}
}


void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream) {
void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream) {
  stream << "\n\tSink PACs";
  stream << "      ● Device PACS, address: " << ADDRESS_TO_LOGGABLE_STR(address_) << "\n";
  stream << "\t  == Sink PACs:\n";
  DumpPacsDebugState(stream, snk_pacs_);
  DumpPacsDebugState(stream, snk_pacs_);
  stream << "\n\tSource PACs";
  stream << "\t  == Source PACs:\n";
  DumpPacsDebugState(stream, src_pacs_);
  DumpPacsDebugState(stream, src_pacs_);
}
}


static std::string locationToString(uint32_t location) {
static std::string locationToString(uint32_t location) {
  std::string result_str = "unknown location";

  if (location & codec_spec_conf::kLeAudioLocationAnyLeft &&
  if (location & codec_spec_conf::kLeAudioLocationAnyLeft &&
      location & codec_spec_conf::kLeAudioLocationAnyRight) {
      location & codec_spec_conf::kLeAudioLocationAnyRight) {
    std::string location_left_right = "left/right";
    return "left/right";
    result_str.swap(location_left_right);
  } else if (location & codec_spec_conf::kLeAudioLocationAnyLeft) {
  } else if (location & codec_spec_conf::kLeAudioLocationAnyLeft) {
    std::string location_left = "left";
    return "left";
    result_str.swap(location_left);
  } else if (location & codec_spec_conf::kLeAudioLocationAnyRight) {
  } else if (location & codec_spec_conf::kLeAudioLocationAnyRight) {
    std::string location_right = "right";
    return "right";
    result_str.swap(location_right);
  } else if (location == codec_spec_conf::kLeAudioLocationMonoAudio) {
    return "mono";
  }
  }

  return "unknown location";
  return result_str;
}
}


void LeAudioDevice::Dump(int fd) {
void LeAudioDevice::Dump(std::stringstream& stream) {
  uint16_t acl_handle =
  uint16_t acl_handle =
          get_btm_client_interface().peer.BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE);
          get_btm_client_interface().peer.BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE);
  std::string snk_location = locationToString(snk_audio_locations_.to_ulong());
  std::string snk_location = locationToString(snk_audio_locations_.to_ulong());
  std::string src_location = locationToString(src_audio_locations_.to_ulong());
  std::string src_location = locationToString(src_audio_locations_.to_ulong());


  std::stringstream stream;
  stream << "      ● Device address: " << ADDRESS_TO_LOGGABLE_STR(address_) << ", "
  stream << "\n\taddress: " << ADDRESS_TO_LOGGABLE_STR(address_) << ": " << connection_state_
         << connection_state_
         << ": " << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_))
         << ", conn_id: " << (conn_id_ == GATT_INVALID_CONN_ID ? "-1" : std::to_string(conn_id_))
         << ", acl_handle: " << std::to_string(acl_handle) << ", snk_location: " << snk_location
         << ", acl_handle: " << std::to_string(acl_handle) << ", snk_location: " << snk_location
         << ", src_location: " << src_location << ",\t" << (encrypted_ ? "Encrypted" : "Unecrypted")
         << ", src_location: " << src_location << ", mtu: " << std::to_string(mtu_) << ", "
         << ",mtu: " << std::to_string(mtu_)
         << (encrypted_ ? "Encrypted" : "Unecrypted")
         << "\n\tnumber of ases_: " << static_cast<int>(ases_.size());
         << "\n\t  Sink avail. contexts: " << common::ToString(avail_contexts_.sink)
         << "\n\t  Source avail. contexts: " << common::ToString(avail_contexts_.source) << "\n";


  if (gmap_client_ != nullptr) {
  if (gmap_client_ != nullptr) {
    gmap_client_->DebugDump(fd);
    stream << "\t  ";
    gmap_client_->DebugDump(stream);
  } else {
  } else {
    stream << "\t  ";
    stream << "GmapClient not initialized\n";
    stream << "GmapClient not initialized\n";
  }
  }


  if (ases_.size() > 0) {
  if (ases_.size() > 0) {
    stream << "\n\t== ASEs == \n\t";
    stream << "\t  == ASEs (" << static_cast<int>(ases_.size()) << "):\n";
    stream << "id  active dir     cis_id  cis_handle  sdu  latency rtn  "
    stream << "\t    id  active dir     cis_id  cis_handle  sdu  latency rtn  "
              "cis_state data_path_state";
              "cis_state            data_path_state\n";
    for (auto& ase : ases_) {
    for (auto& ase : ases_) {
      stream << std::setfill('\x20') << "\n\t" << std::left << std::setw(4)
      stream << std::setfill('\x20') << "\t    " << std::left << std::setw(4)
             << static_cast<int>(ase.id) << std::left << std::setw(7)
             << static_cast<int>(ase.id) << std::left << std::setw(7)
             << (ase.active ? "true" : "false") << std::left << std::setw(8)
             << (ase.active ? "true" : "false") << std::left << std::setw(8)
             << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") << std::left
             << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") << std::left
@@ -1060,14 +1061,10 @@ void LeAudioDevice::Dump(int fd) {
             << ase.cis_conn_hdl << std::left << std::setw(5) << ase.qos_config.max_sdu_size
             << ase.cis_conn_hdl << std::left << std::setw(5) << ase.qos_config.max_sdu_size
             << std::left << std::setw(8) << ase.qos_config.max_transport_latency << std::left
             << std::left << std::setw(8) << ase.qos_config.max_transport_latency << std::left
             << std::setw(5) << static_cast<int>(ase.qos_config.retrans_nb) << std::left
             << std::setw(5) << static_cast<int>(ase.qos_config.retrans_nb) << std::left
             << std::setw(10) << bluetooth::common::ToString(ase.cis_state) << std::setw(12)
             << std::setw(21) << bluetooth::common::ToString(ase.cis_state) << std::setw(19)
             << bluetooth::common::ToString(ase.data_path_state);
             << bluetooth::common::ToString(ase.data_path_state) << "\n";
    }
    }
  }
  }

  stream << "\n\t====";

  dprintf(fd, "%s", stream.str().c_str());
}
}


void LeAudioDevice::DisconnectAcl(void) {
void LeAudioDevice::DisconnectAcl(void) {
@@ -1341,16 +1338,14 @@ void LeAudioDevices::SetInitialGroupAutoconnectState(int group_id, int gatt_if,


size_t LeAudioDevices::Size() const { return leAudioDevices_.size(); }
size_t LeAudioDevices::Size() const { return leAudioDevices_.size(); }


void LeAudioDevices::Dump(int fd, int group_id) const {
void LeAudioDevices::Dump(std::stringstream& stream, int group_id) const {
  std::stringstream stream, stream_pacs;

  for (auto const& device : leAudioDevices_) {
  for (auto const& device : leAudioDevices_) {
    if (device->group_id_ == group_id) {
    if (device->group_id_ == group_id) {
      device->Dump(fd);
      device->Dump(stream);


      stream_pacs << "\n\taddress: " << device->address_;
      stream << "\tAddress: " << device->address_ << "\n";
      device->DumpPacsDebugState(stream_pacs);
      device->DumpPacsDebugState(stream);
      dprintf(fd, "%s", stream_pacs.str().c_str());
      stream << "\n";
    }
    }
  }
  }
}
}
Loading