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

Commit 98fae15a authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Jakub Pawłowski
Browse files

LE Audio stereo recording

With this patch, we can receive ISO data for two channels. If audio
framework expect to receive mono signal, we would mix it into mono stream.
If audio framework expects stereo signal, we will pass it through.

Test: make a mono phone call, make stereo phone call, drop connection
during phone call, ensure no crashes and good audio quality
Bug: 209004829
Bug: 150670922
Change-Id: Ie8c347d15b08006360597c8493711a283eaef18c
parent 1e33487f
Loading
Loading
Loading
Loading
+186 −29
Original line number Original line Diff line number Diff line
@@ -174,8 +174,10 @@ class LeAudioClientImpl : public LeAudioClient {
        current_sink_codec_config({0, 0, 0, 0}),
        current_sink_codec_config({0, 0, 0, 0}),
        lc3_encoder_left_mem(nullptr),
        lc3_encoder_left_mem(nullptr),
        lc3_encoder_right_mem(nullptr),
        lc3_encoder_right_mem(nullptr),
        lc3_decoder_mem(nullptr),
        lc3_decoder_left_mem(nullptr),
        lc3_decoder(nullptr),
        lc3_decoder_right_mem(nullptr),
        lc3_decoder_left(nullptr),
        lc3_decoder_right(nullptr),
        audio_source_instance_(nullptr),
        audio_source_instance_(nullptr),
        audio_sink_instance_(nullptr),
        audio_sink_instance_(nullptr),
        suspend_timeout_(alarm_new("LeAudioSuspendTimeout")) {
        suspend_timeout_(alarm_new("LeAudioSuspendTimeout")) {
@@ -2120,7 +2122,6 @@ class LeAudioClientImpl : public LeAudioClient {
                     uint32_t timestamp) {
                     uint32_t timestamp) {
    /* Get only one channel for MONO microphone */
    /* Get only one channel for MONO microphone */
    /* Gather data for channel */
    /* Gather data for channel */

    if ((active_group_id_ == bluetooth::groups::kGroupUnknown) ||
    if ((active_group_id_ == bluetooth::groups::kGroupUnknown) ||
        (audio_sender_state_ != AudioState::STARTED))
        (audio_sender_state_ != AudioState::STARTED))
      return;
      return;
@@ -2133,17 +2134,31 @@ class LeAudioClientImpl : public LeAudioClient {


    auto stream_conf = group->stream_conf;
    auto stream_conf = group->stream_conf;


    uint16_t required_for_channel_byte_count =
    uint16_t left_cis_handle = 0;
        stream_conf.source_octets_per_codec_frame;
    uint16_t right_cis_handle = 0;
    size_t required_byte_count = current_sink_codec_config.num_channels *
    for (auto [cis_handle, audio_location] : stream_conf.source_streams) {
                                 required_for_channel_byte_count;
      if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyLeft) {
        left_cis_handle = cis_handle;
      }
      if (audio_location &
          le_audio::codec_spec_conf::kLeAudioLocationAnyRight) {
        right_cis_handle = cis_handle;
      }
    }


    if (required_byte_count != size) {
    bool is_left = true;
      LOG(ERROR) << "Insufficient data for decoding and send, required: "
    if (cis_conn_hdl == left_cis_handle) {
                 << int(required_byte_count) << ", received: " << int(size);
      is_left = true;
    } else if (cis_conn_hdl == right_cis_handle) {
      is_left = false;
    } else {
      LOG_ERROR("Received data for unknown handle: %04x", cis_conn_hdl);
      return;
      return;
    }
    }


    uint16_t required_for_channel_byte_count =
        stream_conf.source_octets_per_codec_frame;

    int dt_us = current_sink_codec_config.data_interval_us;
    int dt_us = current_sink_codec_config.data_interval_us;
    int af_hz = audio_framework_sink_config.sample_rate;
    int af_hz = audio_framework_sink_config.sample_rate;


@@ -2165,19 +2180,146 @@ class LeAudioClientImpl : public LeAudioClient {


    std::vector<int16_t> pcm_data_decoded(pcm_size, 0);
    std::vector<int16_t> pcm_data_decoded(pcm_size, 0);


    auto err = lc3_decode(lc3_decoder, data, size, pcm_data_decoded.data(),
    int err = 0;

    if (required_for_channel_byte_count != size) {
      LOG(INFO) << "Insufficient data for decoding and send, required: "
                << int(required_for_channel_byte_count)
                << ", received: " << int(size) << ", will do PLC";
      size = 0;
      data = nullptr;
    }

    lc3_decoder_t decoder_to_use =
        is_left ? lc3_decoder_left : lc3_decoder_right;

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


    /* TODO: How handle failing decoding ? */
    if (err < 0) {
    if (err < 0) {
      LOG(ERROR) << " error while decoding error code: "
      LOG(ERROR) << " bad decoding parameters: " << static_cast<int>(err);
                 << static_cast<int>(err);
      return;
    }

    /* AF == Audio Framework */
    bool af_is_stereo = (audio_framework_sink_config.num_channels == 2);

    if (!left_cis_handle || !right_cis_handle) {
      /* mono or just one device connected */
      SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo,
                        &pcm_data_decoded, nullptr);
      return;
      return;
    }
    }


    uint16_t to_write = sizeof(int16_t) * pcm_data_decoded.size();
    /* both devices are connected */
    uint16_t written = LeAudioClientAudioSink::SendData(
    if (cached_channel_timestamp_ == 0) {
        (uint8_t*)pcm_data_decoded.data(), to_write);
      /* First packet received, cache it. We need both channel data to send it
       * to AF. */
      cached_channel_data_ = pcm_data_decoded;
      cached_channel_timestamp_ = timestamp;
      cached_channel_is_left_ = is_left;
      return;
    }

    /* We received either data for the other audio channel, or another
     * packet for same channel */

    if (cached_channel_is_left_ != is_left) {
      /* It's data for the 2nd channel */
      if (timestamp == cached_channel_timestamp_) {
        /* Ready to mix data and send out to AF */
        if (is_left) {
          SendAudioDataToAF(true /* bt_got_stereo */, af_is_stereo,
                            &cached_channel_data_, &pcm_data_decoded);
        } else {
          SendAudioDataToAF(true /* bt_got_stereo */, af_is_stereo,
                            &pcm_data_decoded, &cached_channel_data_);
        }

        cached_channel_timestamp_ = 0;
        return;
      }

      /* 2nd Channel is in the future compared to the cached data.
       Send the cached data to AF, and keep the new channel data in cache.
       This should happen only during stream setup */

      if (cached_channel_is_left_) {
        SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo,
                          &cached_channel_data_, nullptr);
      } else {
        SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, nullptr,
                          &cached_channel_data_);
      }

      cached_channel_data_ = pcm_data_decoded;
      cached_channel_timestamp_ = timestamp;
      cached_channel_is_left_ = is_left;
      return;
    }

    /* Data for same channel received. 2nd channel is down/not sending
     * data */

    /* Send the cached data out */
    if (cached_channel_is_left_) {
      SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo,
                        &cached_channel_data_, nullptr);
    } else {
      SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, nullptr,
                        &cached_channel_data_);
    }

    /* Cache the data in case 2nd channel connects */
    cached_channel_data_ = pcm_data_decoded;
    cached_channel_timestamp_ = timestamp;
    cached_channel_is_left_ = is_left;
  }

  void SendAudioDataToAF(bool bt_got_stereo, bool af_is_stereo,
                         std::vector<int16_t>* left,
                         std::vector<int16_t>* right) {
    uint16_t to_write = 0;
    uint16_t written = 0;
    if (!bt_got_stereo && !af_is_stereo) {
      std::vector<int16_t>* mono = left ? left : right;
      /* mono audio over bluetooth, audio framework expects mono */
      to_write = sizeof(int16_t) * mono->size();
      written =
          LeAudioClientAudioSink::SendData((uint8_t*)mono->data(), to_write);
    } else if (bt_got_stereo && af_is_stereo) {
      /* stero audio over bluetooth, audio framework expects stereo */
      std::vector<uint16_t> mixed(left->size() * 2);

      for (size_t i = 0; i < left->size(); i++) {
        mixed[2 * i] = (*left)[i];
        mixed[2 * i + 1] = (*right)[i];
      }
      to_write = sizeof(int16_t) * mixed.size();
      written =
          LeAudioClientAudioSink::SendData((uint8_t*)mixed.data(), to_write);
    } else if (bt_got_stereo && !af_is_stereo) {
      /* stero audio over bluetooth, audio framework expects mono */
      std::vector<uint16_t> mixed(left->size() * 2);

      for (size_t i = 0; i < left->size(); i++) {
        (*left)[i] = ((*left)[i] + (*right)[i]) / 2;
      }
      to_write = sizeof(int16_t) * left->size();
      written =
          LeAudioClientAudioSink::SendData((uint8_t*)left->data(), to_write);
    } else if (!bt_got_stereo && af_is_stereo) {
      /* mono audio over bluetooth, audio framework expects stereo */
      std::vector<uint16_t> mixed(left ? left->size() * 2 : right->size() * 2);

      for (size_t i = 0; i < left->size(); i++) {
        mixed[2 * i] = left ? (*left)[i] : 0;
        mixed[2 * i + 1] = right ? (*right)[i] : 0;
      }
      to_write = sizeof(int16_t) * mixed.size();
      written =
          LeAudioClientAudioSink::SendData((uint8_t*)mixed.data(), to_write);
    }


    /* TODO: What to do if not all data sinked ? */
    /* TODO: What to do if not all data sinked ? */
    if (written != to_write) LOG(ERROR) << __func__ << ", not all data sinked";
    if (written != to_write) LOG(ERROR) << __func__ << ", not all data sinked";
@@ -2257,22 +2399,29 @@ class LeAudioClientImpl : public LeAudioClient {
    uint16_t remote_delay_ms =
    uint16_t remote_delay_ms =
        group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource);
        group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource);


    cached_channel_timestamp_ = 0;
    if (CodecManager::GetInstance()->GetCodecLocation() ==
    if (CodecManager::GetInstance()->GetCodecLocation() ==
        le_audio::types::CodecLocation::HOST) {
        le_audio::types::CodecLocation::HOST) {
      if (lc3_decoder_mem) {
      if (lc3_decoder_left_mem) {
        LOG(WARNING)
        LOG(WARNING)
            << " The decoder instance should have been already released.";
            << " The decoder instance should have been already released.";
        free(lc3_decoder_mem);
        free(lc3_decoder_left_mem);
        lc3_decoder_mem = nullptr;
        lc3_decoder_left_mem = nullptr;
        free(lc3_decoder_right_mem);
        lc3_decoder_right_mem = nullptr;
      }
      }


      int dt_us = current_sink_codec_config.data_interval_us;
      int dt_us = current_sink_codec_config.data_interval_us;
      int sr_hz = current_sink_codec_config.sample_rate;
      int sr_hz = current_sink_codec_config.sample_rate;
      int af_hz = audio_framework_sink_config.sample_rate;
      int af_hz = audio_framework_sink_config.sample_rate;
      unsigned dec_size = lc3_decoder_size(dt_us, af_hz);
      unsigned dec_size = lc3_decoder_size(dt_us, af_hz);
      lc3_decoder_mem = malloc(dec_size);
      lc3_decoder_left_mem = malloc(dec_size);
      lc3_decoder_right_mem = malloc(dec_size);


      lc3_decoder = lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_mem);
      lc3_decoder_left =
          lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_left_mem);
      lc3_decoder_right =
          lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_right_mem);
    } else if (CodecManager::GetInstance()->GetCodecLocation() ==
    } else if (CodecManager::GetInstance()->GetCodecLocation() ==
               le_audio::types::CodecLocation::ADSP) {
               le_audio::types::CodecLocation::ADSP) {
      CodecManager::GetInstance()->UpdateActiveSinkAudioConfig(*stream_conf,
      CodecManager::GetInstance()->UpdateActiveSinkAudioConfig(*stream_conf,
@@ -2295,10 +2444,11 @@ class LeAudioClientImpl : public LeAudioClient {
      lc3_encoder_right_mem = nullptr;
      lc3_encoder_right_mem = nullptr;
    }
    }


    if (lc3_decoder_mem) {
    if (lc3_decoder_left_mem) {
      LOG(INFO) << __func__ << " stopping sink";
      free(lc3_decoder_left_mem);
      free(lc3_decoder_mem);
      lc3_decoder_left_mem = nullptr;
      lc3_decoder_mem = nullptr;
      free(lc3_decoder_left_mem);
      lc3_decoder_right_mem = nullptr;
    }
    }
  }
  }


@@ -3189,8 +3339,11 @@ class LeAudioClientImpl : public LeAudioClient {
  lc3_encoder_t lc3_encoder_left;
  lc3_encoder_t lc3_encoder_left;
  lc3_encoder_t lc3_encoder_right;
  lc3_encoder_t lc3_encoder_right;


  void* lc3_decoder_mem;
  void* lc3_decoder_left_mem;
  lc3_decoder_t lc3_decoder;
  void* lc3_decoder_right_mem;

  lc3_decoder_t lc3_decoder_left;
  lc3_decoder_t lc3_decoder_right;


  std::vector<uint8_t> encoded_data;
  std::vector<uint8_t> encoded_data;
  const void* audio_source_instance_;
  const void* audio_source_instance_;
@@ -3200,6 +3353,10 @@ class LeAudioClientImpl : public LeAudioClient {
      "persist.bluetooth.leaudio.audio.suspend.timeoutms";
      "persist.bluetooth.leaudio.audio.suspend.timeoutms";
  alarm_t* suspend_timeout_;
  alarm_t* suspend_timeout_;


  std::vector<int16_t> cached_channel_data_;
  uint32_t cached_channel_timestamp_ = 0;
  uint32_t cached_channel_is_left_;

  void ClientAudioIntefraceRelease() {
  void ClientAudioIntefraceRelease() {
    if (audio_source_instance_) {
    if (audio_source_instance_) {
      LeAudioClientAudioSource::Stop();
      LeAudioClientAudioSource::Stop();