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

Commit 7e423cb5 authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Jakub Pawłowski
Browse files

LE Audio: accept 24 bit audio from audio framework properly

LC3 encoder expects the 24 bit audio packet in uint32_t.
Audio Frameworks provide 24bit audio in packed format currently.
In LE Audio code, we must accout for potential 24bit inputs.

Bug: 230578655
Test: Switch configuration to 24bit mode, play music
Merged-In: I4bc7aebb7437023114f732866322c026b71bcf56
Change-Id: I4bc7aebb7437023114f732866322c026b71bcf56
parent 7f5c7c66
Loading
Loading
Loading
Loading
+78 −46
Original line number Diff line number Diff line
@@ -116,6 +116,23 @@ std::ostream& operator<<(std::ostream& os, const AudioState& audio_state) {
namespace {
void le_audio_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);

inline uint8_t bits_to_bytes_per_sample(uint8_t bits_per_sample) {
  // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes.
  if (bits_per_sample == 24) return 4;

  return bits_per_sample / 8;
}

inline lc3_pcm_format bits_to_lc3_bits(uint8_t bits_per_sample) {
  if (bits_per_sample == 16) return LC3_PCM_FORMAT_S16;

  if (bits_per_sample == 24) return LC3_PCM_FORMAT_S24;

  LOG_ALWAYS_FATAL("Encoder/decoder don't know how to handle %d",
                   bits_per_sample);
  return LC3_PCM_FORMAT_S16;
}

class LeAudioClientImpl;
LeAudioClientImpl* instance;
LeAudioClientAudioSinkReceiver* audioSinkReceiver;
@@ -1923,27 +1940,36 @@ class LeAudioClientImpl : public LeAudioClient {
    return true;
  }

  void get_mono_stream(const std::vector<uint8_t>& data,
                       std::vector<int16_t>& chan_mono, int pitch = 1) {
    uint16_t num_of_frames_per_ch;

    int dt_us = current_source_codec_config.data_interval_us;
    int af_hz = audio_framework_source_config.sample_rate;
    num_of_frames_per_ch = lc3_frame_samples(dt_us, af_hz);

    chan_mono.reserve(num_of_frames_per_ch);
    for (int i = 0; i < pitch * num_of_frames_per_ch; i += pitch) {
      const uint8_t* sample = data.data() + i * 4;

      int16_t left = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;

      sample += 2;
      int16_t right = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;

      uint16_t mono_data = (int16_t)(((uint32_t)left + (uint32_t)right) >> 1);

      chan_mono.push_back(mono_data);
  // mix stero signal into mono
  std::vector<uint8_t> mono_blend(const std::vector<uint8_t>& buf,
                                  int bytes_per_sample, size_t frames) {
    std::vector<uint8_t> mono_out;
    mono_out.resize(frames * bytes_per_sample);

    if (bytes_per_sample == 2) {
      int16_t* out = (int16_t*)mono_out.data();
      for (size_t i = 0; i < frames; ++i) {
        const int16_t* in = (int16_t*)(buf.data());
        int accum = 0;
        accum += *in++;
        accum += *in++;
        accum /= 2;  // round to 0
        *out++ = accum;
      }
    } else if (bytes_per_sample == 4) {
      int32_t* out = (int32_t*)mono_out.data();
      for (size_t i = 0; i < frames; ++i) {
        const int32_t* in = (int32_t*)(buf.data());
        int accum = 0;
        accum += *in++;
        accum += *in++;
        accum /= 2;  // round to 0
        *out++ = accum;
      }
    } else {
      LOG_ERROR("Don't know how to mono blend that %d!", bytes_per_sample);
    }
    return mono_out;
  }

  void PrepareAndSendToTwoDevices(
@@ -1958,6 +1984,11 @@ class LeAudioClientImpl : public LeAudioClient {
    int af_hz = audio_framework_source_config.sample_rate;
    number_of_required_samples_per_channel = lc3_frame_samples(dt_us, af_hz);

    lc3_pcm_format bits_per_sample =
        bits_to_lc3_bits(audio_framework_source_config.bits_per_sample);
    uint8_t bytes_per_sample =
        bits_to_bytes_per_sample(audio_framework_source_config.bits_per_sample);

    for (auto [cis_handle, audio_location] : stream_conf->sink_streams) {
      if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyLeft)
        left_cis_handle = cis_handle;
@@ -1965,11 +1996,12 @@ class LeAudioClientImpl : public LeAudioClient {
        right_cis_handle = cis_handle;
    }

    if (data.size() < 2 /* bytes per sample */ * 2 /* channels */ *
    if (data.size() < bytes_per_sample * 2 /* channels */ *
                          number_of_required_samples_per_channel) {
      LOG(ERROR) << __func__ << " Missing samples. Data size: " << +data.size()
                 << " expected: "
                 << 2 * 2 * number_of_required_samples_per_channel;
                 << bytes_per_sample * 2 *
                        number_of_required_samples_per_channel;
      return;
    }

@@ -1979,26 +2011,22 @@ class LeAudioClientImpl : public LeAudioClient {
    bool mono = (left_cis_handle == 0) || (right_cis_handle == 0);

    if (!mono) {
      lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16,
                 (const int16_t*)data.data(), 2, chan_left_enc.size(),
                 chan_left_enc.data());
      lc3_encode(lc3_encoder_right, LC3_PCM_FORMAT_S16,
                 ((const int16_t*)data.data()) + 1, 2, chan_right_enc.size(),
      lc3_encode(lc3_encoder_left, bits_per_sample, data.data(), 2,
                 chan_left_enc.size(), chan_left_enc.data());
      lc3_encode(lc3_encoder_right, bits_per_sample,
                 data.data() + bytes_per_sample, 2, chan_right_enc.size(),
                 chan_right_enc.data());
    } else {
      std::vector<int16_t> chan_mono;
      get_mono_stream(data, chan_mono);

      std::vector<uint8_t> mono = mono_blend(
          data, bytes_per_sample, number_of_required_samples_per_channel);
      if (left_cis_handle) {
        lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16,
                   (const int16_t*)chan_mono.data(), 1, chan_left_enc.size(),
                   chan_left_enc.data());
        lc3_encode(lc3_encoder_left, bits_per_sample, mono.data(), 1,
                   chan_left_enc.size(), chan_left_enc.data());
      }

      if (right_cis_handle) {
        lc3_encode(lc3_encoder_right, LC3_PCM_FORMAT_S16,
                   (const int16_t*)chan_mono.data(), 1, chan_right_enc.size(),
                   chan_right_enc.data());
        lc3_encode(lc3_encoder_right, bits_per_sample, mono.data(), 1,
                   chan_right_enc.size(), chan_right_enc.data());
      }
    }

@@ -2025,6 +2053,10 @@ class LeAudioClientImpl : public LeAudioClient {
    int dt_us = current_source_codec_config.data_interval_us;
    int af_hz = audio_framework_source_config.sample_rate;
    number_of_required_samples_per_channel = lc3_frame_samples(dt_us, af_hz);
    lc3_pcm_format bits_per_sample =
        bits_to_lc3_bits(audio_framework_source_config.bits_per_sample);
    uint8_t bytes_per_sample =
        bits_to_bytes_per_sample(audio_framework_source_config.bits_per_sample);

    if ((int)data.size() < (2 /* bytes per sample */ * num_channels *
                            number_of_required_samples_per_channel)) {
@@ -2036,21 +2068,19 @@ class LeAudioClientImpl : public LeAudioClient {
    if (num_channels == 1) {
      /* Since we always get two channels from framework, lets make it mono here
       */
      std::vector<int16_t> chan_mono;
      get_mono_stream(data, chan_mono);
      std::vector<uint8_t> mono = mono_blend(
          data, bytes_per_sample, number_of_required_samples_per_channel);

      auto err = lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16,
                            (const int16_t*)chan_mono.data(), 1, byte_count,
                            chan_encoded.data());
      auto err = lc3_encode(lc3_encoder_left, bits_per_sample, mono.data(), 1,
                            byte_count, chan_encoded.data());

      if (err < 0) {
        LOG(ERROR) << " error while encoding, error code: " << +err;
      }
    } else {
      lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16,
                 (const int16_t*)data.data(), 2, byte_count,
                 chan_encoded.data());
      lc3_encode(lc3_encoder_right, LC3_PCM_FORMAT_S16,
      lc3_encode(lc3_encoder_left, bits_per_sample, (const int16_t*)data.data(),
                 2, byte_count, chan_encoded.data());
      lc3_encode(lc3_encoder_right, bits_per_sample,
                 (const int16_t*)data.data() + 1, 2, byte_count,
                 chan_encoded.data() + byte_count);
    }
@@ -2250,6 +2280,8 @@ class LeAudioClientImpl : public LeAudioClient {

    int dt_us = current_sink_codec_config.data_interval_us;
    int af_hz = audio_framework_sink_config.sample_rate;
    lc3_pcm_format bits_per_sample =
        bits_to_lc3_bits(audio_framework_sink_config.bits_per_sample);

    int pcm_size;
    if (dt_us == 10000) {
@@ -2282,7 +2314,7 @@ class LeAudioClientImpl : public LeAudioClient {
    lc3_decoder_t decoder_to_use =
        is_left ? lc3_decoder_left : lc3_decoder_right;

    err = lc3_decode(decoder_to_use, data, size, LC3_PCM_FORMAT_S16,
    err = lc3_decode(decoder_to_use, data, size, bits_per_sample,
                     pcm_data_decoded.data(), 1 /* pitch */);

    if (err < 0) {