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

Commit 8eecf85e authored by Pavlin Radoslavov's avatar Pavlin Radoslavov
Browse files

Add A2DP codec-specific information to dumpsys output

Now we print the following information:
 * Current codec name
 * Info for each supported codec:
   - Priority
   - Encoder interval (ms)
   - Codec Config: Sampling rate, Bits per sample, Channel mode (MONO/STEREO)
   - Selectable codec configuration
   - Codec's local capability
   - Packet counts (expected/dropped)
   - PCM read counts (expected/actual)
   - PCM read bytes (expected/actual)
 * LDAC codec-specific info:
   - LDAC quality mode: HIGH/MID/LOW/ABR
   - LDAC saved transmit queue length [used in ABR mode]
 * SBC codec-specific info:
   - Frames counts (expected/dropped)

Sample of the new format is below:

---
A2DP Codecs State:
  Current Codec: LDAC

A2DP LDAC State:
  Priority: 1000000
  Encoder interval (ms): 20
  Config: Rate=96000 Bits=32 Mode=STEREO
  Selectable: Rate=44100|48000|88200|96000 Bits=16|24|32 Mode=MONO|STEREO
  Local capability: Rate=44100|48000|88200|96000 Bits=16|24|32 Mode=MONO|STEREO
  Packet counts (expected/dropped)                        : 596 / 161
  PCM read counts (expected/actual)                       : 2488 / 2488
  PCM read bytes (expected/actual)                        : 2547712 / 2547712
  LDAC quality mode                                       : ABR
  LDAC saved transmit queue length                        : 0

A2DP aptX-HD State:
  Priority: 4001
  Encoder interval (ms): 0
  Config: Invalid
  Selectable: Invalid
  Local capability: Rate=44100|48000 Bits=24 Mode=STEREO
  Packet counts (expected/dropped)                        : 0 / 0
  PCM read counts (expected/actual)                       : 0 / 0
  PCM read bytes (expected/actual)                        : 0 / 0

A2DP aptX State:
  Priority: 3001
  Encoder interval (ms): 0
  Config: Rate=44100 Bits=16 Mode=STEREO
  Selectable: Rate=44100|48000 Bits=16 Mode=STEREO
  Local capability: Rate=44100|48000 Bits=16 Mode=STEREO
  Packet counts (expected/dropped)                        : 0 / 0
  PCM read counts (expected/actual)                       : 0 / 0
  PCM read bytes (expected/actual)                        : 0 / 0

A2DP AAC State:
  Priority: 2001
  Encoder interval (ms): 20
  Config: Rate=44100 Bits=16 Mode=STEREO
  Selectable: Rate=44100|48000 Bits=16 Mode=STEREO
  Local capability: Rate=44100|48000|88200|96000 Bits=16 Mode=STEREO
  Packet counts (expected/dropped)                        : 0 / 0
  PCM read counts (expected/actual)                       : 0 / 0
  PCM read bytes (expected/actual)                        : 0 / 0

A2DP SBC State:
  Priority: 1001
  Encoder interval (ms): 20
  Config: Rate=44100 Bits=16 Mode=STEREO
  Selectable: Rate=44100 Bits=16 Mode=STEREO
  Local capability: Rate=44100 Bits=16 Mode=STEREO
  Packet counts (expected/dropped)                        : 580 / 0
  PCM read counts (expected/actual)                       : 2900 / 2900
  PCM read bytes (expected/actual)                        : 1484800 / 1484800
  Frames counts (expected/dropped)                        : 3724 / 0
---

Bug: 36567128
Test: Stream A2DP and "adb shell dumpsys bluetooth_manager"
Change-Id: Idd86005b842a4e569b7df91b8bbaf0632ed7f7c9
parent f026691b
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1024,8 +1024,10 @@ void btif_a2dp_source_debug_dump(int fd) {
  //
  // Codec-specific stats
  //
  if (btif_a2dp_source_cb.encoder_interface != NULL)
    btif_a2dp_source_cb.encoder_interface->debug_codec_dump(fd);
  A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs();
  if (a2dp_codecs != nullptr) {
    a2dp_codecs->debug_codec_dump(fd);
  }
}

void btif_a2dp_source_update_metrics(void) {
+2 −2
Original line number Diff line number Diff line
@@ -82,8 +82,8 @@ static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_aac = {
    a2dp_aac_feeding_flush,
    a2dp_aac_get_encoder_interval_ms,
    a2dp_aac_send_frames,
    nullptr,  // set_transmit_queue_length
    a2dp_aac_debug_codec_dump};
    nullptr  // set_transmit_queue_length
};

UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
    const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
+20 −14
Original line number Diff line number Diff line
@@ -34,12 +34,6 @@
// Encoder for AAC Source Codec
//

#define STATS_UPDATE_MAX(current_value_storage, new_value) \
  do {                                                     \
    if ((new_value) > (current_value_storage))             \
      (current_value_storage) = (new_value);               \
  } while (0)

// A2DP AAC encoder interval in milliseconds
#define A2DP_AAC_ENCODER_INTERVAL_MS 20

@@ -575,15 +569,16 @@ static void a2dp_aac_encode_frames(uint8_t nb_frame) {

  while (nb_frame) {
    BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);

    /* Init buffer */
    p_buf->offset = A2DP_AAC_OFFSET;
    p_buf->len = 0;
    p_buf->layer_specific = 0;
    a2dp_aac_encoder_cb.stats.media_read_total_expected_packets++;

    count = 0;
    do {
      /* Read PCM data */
      //
      // Read the PCM data and encode it
      //
      if (a2dp_aac_read_feeding(read_buffer)) {
        uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
        if (!a2dp_aac_encoder_cb.has_aac_handle) {
@@ -637,6 +632,7 @@ static void a2dp_aac_encode_frames(uint8_t nb_frame) {
      remain_nb_frame = nb_frame;
      if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
    } else {
      a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++;
      osi_free(p_buf);
    }
  }
@@ -647,9 +643,13 @@ static bool a2dp_aac_read_feeding(uint8_t* read_buffer) {
                       a2dp_aac_encoder_cb.feeding_params.channel_count *
                       a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8;

  a2dp_aac_encoder_cb.stats.media_read_total_expected_reads_count++;
  a2dp_aac_encoder_cb.stats.media_read_total_expected_read_bytes += read_size;

  /* Read Data from UIPC channel */
  uint32_t nb_byte_read =
      a2dp_aac_encoder_cb.read_callback(read_buffer, read_size);
  a2dp_aac_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;

  if (nb_byte_read < read_size) {
    if (nb_byte_read == 0) return false;
@@ -658,28 +658,34 @@ static bool a2dp_aac_read_feeding(uint8_t* read_buffer) {
    memset(((uint8_t*)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
    nb_byte_read = read_size;
  }
  a2dp_aac_encoder_cb.stats.media_read_total_actual_reads_count++;

  return true;
}

void a2dp_aac_debug_codec_dump(int fd) {
period_ms_t A2dpCodecConfigAac::encoderIntervalMs() const {
  return a2dp_aac_get_encoder_interval_ms();
}

void A2dpCodecConfigAac::debug_codec_dump(int fd) {
  a2dp_aac_encoder_stats_t* stats = &a2dp_aac_encoder_cb.stats;

  dprintf(fd, "\nA2DP AAC State:\n");
  A2dpCodecConfig::debug_codec_dump(fd);

  dprintf(fd,
          "  Packets expected/dropped                                : %zu / "
          "  Packet counts (expected/dropped)                        : %zu / "
          "%zu\n",
          stats->media_read_total_expected_packets,
          stats->media_read_total_dropped_packets);

  dprintf(fd,
          "  PCM reads count expected/actual                         : %zu / "
          "  PCM read counts (expected/actual)                       : %zu / "
          "%zu\n",
          stats->media_read_total_expected_reads_count,
          stats->media_read_total_actual_reads_count);

  dprintf(fd,
          "  PCM read bytes expected/actual                          : %zu / "
          "  PCM read bytes (expected/actual)                        : %zu / "
          "%zu\n",
          stats->media_read_total_expected_read_bytes,
          stats->media_read_total_actual_read_bytes);
+142 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include "a2dp_codec_api.h"

#include <base/logging.h>
#include <inttypes.h>

#include "a2dp_aac.h"
#include "a2dp_sbc.h"
@@ -282,6 +283,130 @@ bool A2dpCodecConfig::setCodecUserConfig(
  return true;
}

bool A2dpCodecConfig::codecConfigIsValid(
    const btav_a2dp_codec_config_t& codec_config) {
  return (codec_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) &&
         (codec_config.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) &&
         (codec_config.bits_per_sample !=
          BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) &&
         (codec_config.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE);
}

std::string A2dpCodecConfig::codecConfig2Str(
    const btav_a2dp_codec_config_t& codec_config) {
  std::string result;

  if (!codecConfigIsValid(codec_config)) return "Invalid";

  result.append("Rate=");
  result.append(codecSampleRate2Str(codec_config.sample_rate));
  result.append(" Bits=");
  result.append(codecBitsPerSample2Str(codec_config.bits_per_sample));
  result.append(" Mode=");
  result.append(codecChannelMode2Str(codec_config.channel_mode));

  return result;
}

std::string A2dpCodecConfig::codecSampleRate2Str(
    btav_a2dp_codec_sample_rate_t codec_sample_rate) {
  std::string result;

  if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_44100) {
    if (!result.empty()) result += "|";
    result += "44100";
  }
  if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_48000) {
    if (!result.empty()) result += "|";
    result += "48000";
  }
  if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_88200) {
    if (!result.empty()) result += "|";
    result += "88200";
  }
  if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_96000) {
    if (!result.empty()) result += "|";
    result += "96000";
  }
  if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_176400) {
    if (!result.empty()) result += "|";
    result += "176400";
  }
  if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_192000) {
    if (!result.empty()) result += "|";
    result += "192000";
  }
  if (result.empty()) {
    std::stringstream ss;
    ss << "UnknownSampleRate(0x" << std::hex << codec_sample_rate << ")";
    ss >> result;
  }

  return result;
}

std::string A2dpCodecConfig::codecBitsPerSample2Str(
    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) {
  std::string result;

  if (codec_bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
    if (!result.empty()) result += "|";
    result += "16";
  }
  if (codec_bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
    if (!result.empty()) result += "|";
    result += "24";
  }
  if (codec_bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
    if (!result.empty()) result += "|";
    result += "32";
  }
  if (result.empty()) {
    std::stringstream ss;
    ss << "UnknownBitsPerSample(0x" << std::hex << codec_bits_per_sample << ")";
    ss >> result;
  }

  return result;
}

std::string A2dpCodecConfig::codecChannelMode2Str(
    btav_a2dp_codec_channel_mode_t codec_channel_mode) {
  std::string result;

  if (codec_channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_MONO) {
    if (!result.empty()) result += "|";
    result += "MONO";
  }
  if (codec_channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO) {
    if (!result.empty()) result += "|";
    result += "STEREO";
  }
  if (result.empty()) {
    std::stringstream ss;
    ss << "UnknownChannelMode(0x" << std::hex << codec_channel_mode << ")";
    ss >> result;
  }

  return result;
}

void A2dpCodecConfig::debug_codec_dump(int fd) {
  std::string result;
  dprintf(fd, "\nA2DP %s State:\n", name().c_str());
  dprintf(fd, "  Priority: %d\n", codecPriority());
  dprintf(fd, "  Encoder interval (ms): %" PRIu64 "\n", encoderIntervalMs());

  result = codecConfig2Str(getCodecConfig());
  dprintf(fd, "  Config: %s\n", result.c_str());

  result = codecConfig2Str(getCodecSelectableCapability());
  dprintf(fd, "  Selectable: %s\n", result.c_str());

  result = codecConfig2Str(getCodecLocalCapability());
  dprintf(fd, "  Local capability: %s\n", result.c_str());
}

//
// Compares two codecs |lhs| and |rhs| based on their priority.
// Returns true if |lhs| has higher priority (larger priority value).
@@ -668,6 +793,23 @@ bool A2dpCodecs::getCodecConfigAndCapabilities(
  return true;
}

void A2dpCodecs::debug_codec_dump(int fd) {
  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
  dprintf(fd, "\nA2DP Codecs State:\n");

  // Print the current codec name
  if (current_codec_config_ != nullptr) {
    dprintf(fd, "  Current Codec: %s\n", current_codec_config_->name().c_str());
  } else {
    dprintf(fd, "  Current Codec: None\n");
  }

  // Print the codec-specific state
  for (auto codec_config : ordered_source_codecs_) {
    codec_config->debug_codec_dump(fd);
  }
}

tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info) {
  return (tA2DP_CODEC_TYPE)(p_codec_info[AVDT_CODEC_TYPE_INDEX]);
}
+7 −2
Original line number Diff line number Diff line
@@ -97,8 +97,8 @@ static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_sbc = {
    a2dp_sbc_feeding_flush,
    a2dp_sbc_get_encoder_interval_ms,
    a2dp_sbc_send_frames,
    nullptr,  // set_transmit_queue_length
    a2dp_sbc_debug_codec_dump};
    nullptr  // set_transmit_queue_length
};

static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
    const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
@@ -1638,3 +1638,8 @@ bool A2dpCodecConfigSbcSink::updateEncoderUserConfig(
  // TODO: This method applies only to Source codecs
  return false;
}

period_ms_t A2dpCodecConfigSbcSink::encoderIntervalMs() const {
  // TODO: This method applies only to Source codecs
  return 0;
}
Loading