OSDN Git Service

A2DP: SBC encoding counter errata
authorCheney Ni <cheneyni@google.com>
Fri, 14 Feb 2020 12:29:54 +0000 (20:29 +0800)
committerCheney Ni <cheneyni@google.com>
Wed, 11 Mar 2020 06:54:16 +0000 (14:54 +0800)
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)

stack/a2dp/a2dp_sbc_encoder.cc

index aac7e6d..5773462 100644 (file)
@@ -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 =