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

Commit 06793fb2 authored by Cheney Ni's avatar Cheney Ni
Browse files

A2DP: SBC encoding counter errata

When the encoder interval is 20 milliseconds per tick for {44.1 kHz /
16 bits per sample / Stereo}, there were around three microseconds shift
every tick, but would cause one SBC frame mismatched after 20 seconds.
Here try to adjust the timeline to increase the accuracy by following
methods:

1. add the remainder back to the timeline when converting the time
   period to data size.
2. change the timestamp to be presented by values in 1/10 microseconds.

Bug: 149546181
Test: manually
Change-Id: Ic42b2f331628c44aa927c7b9e35562be1fa750c7
Merged-In: Ic42b2f331628c44aa927c7b9e35562be1fa750c7
(cherry picked from commit c8537f844d1c052e5c9d93981e270dd45d73a709)
parent 0c54edb6
Loading
Loading
Loading
Loading
+27 −11
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include "a2dp_sbc_encoder.h"

#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

@@ -71,8 +72,8 @@ typedef struct {
  int32_t aa_feed_counter;
  int32_t aa_feed_residue;
  uint32_t counter;
  uint32_t bytes_per_tick; /* pcm bytes read each media task tick */
  uint64_t last_frame_us;
  uint32_t bytes_per_tick;              // pcm bytes read each media task tick
  uint64_t last_frame_timestamp_100ns;  // values in 1/10 microseconds
} tA2DP_SBC_FEEDING_STATE;

typedef struct {
@@ -433,15 +434,30 @@ static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
  LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__,
              pcm_bytes_per_frame);

  uint32_t us_this_tick = A2DP_SBC_ENCODER_INTERVAL_MS * 1000;
  uint64_t now_us = timestamp_us;
  if (a2dp_sbc_encoder_cb.feeding_state.last_frame_us != 0)
    us_this_tick = (now_us - a2dp_sbc_encoder_cb.feeding_state.last_frame_us);
  a2dp_sbc_encoder_cb.feeding_state.last_frame_us = now_us;

  a2dp_sbc_encoder_cb.feeding_state.counter +=
      a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick * us_this_tick /
      (A2DP_SBC_ENCODER_INTERVAL_MS * 1000);
  uint32_t hecto_ns_this_tick = A2DP_SBC_ENCODER_INTERVAL_MS * 10000;
  uint64_t* last_100ns =
      &a2dp_sbc_encoder_cb.feeding_state.last_frame_timestamp_100ns;
  uint64_t now_100ns = timestamp_us * 10;
  if (*last_100ns != 0) {
    hecto_ns_this_tick = (now_100ns - *last_100ns);
  }
  *last_100ns = now_100ns;

  uint32_t bytes_this_tick = a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick *
                             hecto_ns_this_tick /
                             (A2DP_SBC_ENCODER_INTERVAL_MS * 10000);
  a2dp_sbc_encoder_cb.feeding_state.counter += bytes_this_tick;
  // Without this erratum, there was a three microseocnd shift per tick which
  // would cause one SBC frame mismatched after every 20 seconds
  uint32_t erratum_100ns =
      ceil(1.0f * A2DP_SBC_ENCODER_INTERVAL_MS * 10000 * bytes_this_tick /
           a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick);
  if (erratum_100ns < hecto_ns_this_tick) {
    LOG_VERBOSE(LOG_TAG,
                "%s: hecto_ns_this_tick=%d, bytes=%d, erratum_100ns=%d",
                __func__, hecto_ns_this_tick, bytes_this_tick, erratum_100ns);
    *last_100ns -= hecto_ns_this_tick - erratum_100ns;
  }

  /* Calculate the number of frames pending for this media tick */
  projected_nof =