• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "a2dp_vendor_aptx_encoder"
18 
19 #include "a2dp_vendor_aptx_encoder.h"
20 
21 #include <dlfcn.h>
22 #include <inttypes.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "a2dp_vendor.h"
27 #include "a2dp_vendor_aptx.h"
28 #include "bt_common.h"
29 #include "common/time_util.h"
30 #include "osi/include/log.h"
31 #include "osi/include/osi.h"
32 
33 //
34 // Encoder for aptX Source Codec
35 //
36 
37 //
38 // The aptX encoder shared library, and the functions to use
39 //
40 static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
41 static void* aptx_encoder_lib_handle = NULL;
42 
43 static const char* APTX_ENCODER_INIT_NAME = "aptxbtenc_init";
44 typedef int (*tAPTX_ENCODER_INIT)(void* state, short endian);
45 
46 static const char* APTX_ENCODER_ENCODE_STEREO_NAME = "aptxbtenc_encodestereo";
47 typedef int (*tAPTX_ENCODER_ENCODE_STEREO)(void* state, void* pcmL, void* pcmR,
48                                            void* buffer);
49 
50 static const char* APTX_ENCODER_SIZEOF_PARAMS_NAME = "SizeofAptxbtenc";
51 typedef int (*tAPTX_ENCODER_SIZEOF_PARAMS)(void);
52 
53 static tAPTX_ENCODER_INIT aptx_encoder_init_func;
54 static tAPTX_ENCODER_ENCODE_STEREO aptx_encoder_encode_stereo_func;
55 static tAPTX_ENCODER_SIZEOF_PARAMS aptx_encoder_sizeof_params_func;
56 
57 // offset
58 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
59 #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1)
60 #else
61 // no RTP header for aptX classic
62 #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET - AVDT_MEDIA_HDR_SIZE)
63 #endif
64 
65 #define A2DP_APTX_MAX_PCM_BYTES_PER_READ 4096
66 
67 typedef struct {
68   uint64_t sleep_time_ns;
69   uint32_t pcm_reads;
70   uint32_t pcm_bytes_per_read;
71   uint32_t aptx_bytes;
72   uint32_t frame_size_counter;
73 } tAPTX_FRAMING_PARAMS;
74 
75 typedef struct {
76   uint64_t session_start_us;
77 
78   size_t media_read_total_expected_packets;
79   size_t media_read_total_expected_reads_count;
80   size_t media_read_total_expected_read_bytes;
81 
82   size_t media_read_total_dropped_packets;
83   size_t media_read_total_actual_reads_count;
84   size_t media_read_total_actual_read_bytes;
85 } a2dp_aptx_encoder_stats_t;
86 
87 typedef struct {
88   a2dp_source_read_callback_t read_callback;
89   a2dp_source_enqueue_callback_t enqueue_callback;
90 
91   bool use_SCMS_T;
92   bool is_peer_edr;          // True if the peer device supports EDR
93   bool peer_supports_3mbps;  // True if the peer device supports 3Mbps EDR
94   uint16_t peer_mtu;         // MTU of the A2DP peer
95   uint32_t timestamp;        // Timestamp for the A2DP frames
96 
97   tA2DP_FEEDING_PARAMS feeding_params;
98   tAPTX_FRAMING_PARAMS framing_params;
99   void* aptx_encoder_state;
100   a2dp_aptx_encoder_stats_t stats;
101 } tA2DP_APTX_ENCODER_CB;
102 
103 static tA2DP_APTX_ENCODER_CB a2dp_aptx_encoder_cb;
104 
105 static void a2dp_vendor_aptx_encoder_update(uint16_t peer_mtu,
106                                             A2dpCodecConfig* a2dp_codec_config,
107                                             bool* p_restart_input,
108                                             bool* p_restart_output,
109                                             bool* p_config_updated);
110 static void aptx_init_framing_params(tAPTX_FRAMING_PARAMS* framing_params);
111 static void aptx_update_framing_params(tAPTX_FRAMING_PARAMS* framing_params);
112 static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params,
113                                 size_t* data_out_index, uint16_t* data16_in,
114                                 uint8_t* data_out);
115 
A2DP_VendorLoadEncoderAptx(void)116 bool A2DP_VendorLoadEncoderAptx(void) {
117   if (aptx_encoder_lib_handle != NULL) return true;  // Already loaded
118 
119   // Open the encoder library
120   aptx_encoder_lib_handle = dlopen(APTX_ENCODER_LIB_NAME, RTLD_NOW);
121   if (aptx_encoder_lib_handle == NULL) {
122     LOG_ERROR(LOG_TAG, "%s: cannot open aptX encoder library %s: %s", __func__,
123               APTX_ENCODER_LIB_NAME, dlerror());
124     return false;
125   }
126 
127   aptx_encoder_init_func = (tAPTX_ENCODER_INIT)dlsym(aptx_encoder_lib_handle,
128                                                      APTX_ENCODER_INIT_NAME);
129   if (aptx_encoder_init_func == NULL) {
130     LOG_ERROR(LOG_TAG,
131               "%s: cannot find function '%s' in the encoder library: %s",
132               __func__, APTX_ENCODER_INIT_NAME, dlerror());
133     A2DP_VendorUnloadEncoderAptx();
134     return false;
135   }
136 
137   aptx_encoder_encode_stereo_func = (tAPTX_ENCODER_ENCODE_STEREO)dlsym(
138       aptx_encoder_lib_handle, APTX_ENCODER_ENCODE_STEREO_NAME);
139   if (aptx_encoder_encode_stereo_func == NULL) {
140     LOG_ERROR(LOG_TAG,
141               "%s: cannot find function '%s' in the encoder library: %s",
142               __func__, APTX_ENCODER_ENCODE_STEREO_NAME, dlerror());
143     A2DP_VendorUnloadEncoderAptx();
144     return false;
145   }
146 
147   aptx_encoder_sizeof_params_func = (tAPTX_ENCODER_SIZEOF_PARAMS)dlsym(
148       aptx_encoder_lib_handle, APTX_ENCODER_SIZEOF_PARAMS_NAME);
149   if (aptx_encoder_sizeof_params_func == NULL) {
150     LOG_ERROR(LOG_TAG,
151               "%s: cannot find function '%s' in the encoder library: %s",
152               __func__, APTX_ENCODER_SIZEOF_PARAMS_NAME, dlerror());
153     A2DP_VendorUnloadEncoderAptx();
154     return false;
155   }
156 
157   return true;
158 }
159 
A2DP_VendorUnloadEncoderAptx(void)160 void A2DP_VendorUnloadEncoderAptx(void) {
161   aptx_encoder_init_func = NULL;
162   aptx_encoder_encode_stereo_func = NULL;
163   aptx_encoder_sizeof_params_func = NULL;
164 
165   if (aptx_encoder_lib_handle != NULL) {
166     dlclose(aptx_encoder_lib_handle);
167     aptx_encoder_lib_handle = NULL;
168   }
169 }
170 
a2dp_vendor_aptx_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS * p_peer_params,A2dpCodecConfig * a2dp_codec_config,a2dp_source_read_callback_t read_callback,a2dp_source_enqueue_callback_t enqueue_callback)171 void a2dp_vendor_aptx_encoder_init(
172     const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
173     A2dpCodecConfig* a2dp_codec_config,
174     a2dp_source_read_callback_t read_callback,
175     a2dp_source_enqueue_callback_t enqueue_callback) {
176   memset(&a2dp_aptx_encoder_cb, 0, sizeof(a2dp_aptx_encoder_cb));
177 
178   a2dp_aptx_encoder_cb.stats.session_start_us =
179       bluetooth::common::time_get_os_boottime_us();
180 
181   a2dp_aptx_encoder_cb.read_callback = read_callback;
182   a2dp_aptx_encoder_cb.enqueue_callback = enqueue_callback;
183   a2dp_aptx_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
184   a2dp_aptx_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
185   a2dp_aptx_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
186   a2dp_aptx_encoder_cb.timestamp = 0;
187 
188   /* aptX encoder config */
189   a2dp_aptx_encoder_cb.use_SCMS_T = false;  // TODO: should be a parameter
190 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
191   a2dp_aptx_encoder_cb.use_SCMS_T = true;
192 #endif
193 
194   a2dp_aptx_encoder_cb.aptx_encoder_state =
195       osi_malloc(aptx_encoder_sizeof_params_func());
196   if (a2dp_aptx_encoder_cb.aptx_encoder_state != NULL) {
197     aptx_encoder_init_func(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
198   } else {
199     LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX encoder state", __func__);
200     // TODO: Return an error?
201   }
202 
203   // NOTE: Ignore the restart_input / restart_output flags - this initization
204   // happens when the connection is (re)started.
205   bool restart_input = false;
206   bool restart_output = false;
207   bool config_updated = false;
208   a2dp_vendor_aptx_encoder_update(a2dp_aptx_encoder_cb.peer_mtu,
209                                   a2dp_codec_config, &restart_input,
210                                   &restart_output, &config_updated);
211 }
212 
updateEncoderUserConfig(const tA2DP_ENCODER_INIT_PEER_PARAMS * p_peer_params,bool * p_restart_input,bool * p_restart_output,bool * p_config_updated)213 bool A2dpCodecConfigAptx::updateEncoderUserConfig(
214     const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
215     bool* p_restart_output, bool* p_config_updated) {
216   a2dp_aptx_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
217   a2dp_aptx_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
218   a2dp_aptx_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
219   a2dp_aptx_encoder_cb.timestamp = 0;
220 
221   if (a2dp_aptx_encoder_cb.peer_mtu == 0) {
222     LOG_ERROR(LOG_TAG,
223               "%s: Cannot update the codec encoder for %s: "
224               "invalid peer MTU",
225               __func__, name().c_str());
226     return false;
227   }
228 
229   a2dp_vendor_aptx_encoder_update(a2dp_aptx_encoder_cb.peer_mtu, this,
230                                   p_restart_input, p_restart_output,
231                                   p_config_updated);
232   return true;
233 }
234 
235 // Update the A2DP aptX encoder.
236 // |peer_mtu| is the peer MTU.
237 // |a2dp_codec_config| is the A2DP codec to use for the update.
a2dp_vendor_aptx_encoder_update(uint16_t peer_mtu,A2dpCodecConfig * a2dp_codec_config,bool * p_restart_input,bool * p_restart_output,bool * p_config_updated)238 static void a2dp_vendor_aptx_encoder_update(uint16_t peer_mtu,
239                                             A2dpCodecConfig* a2dp_codec_config,
240                                             bool* p_restart_input,
241                                             bool* p_restart_output,
242                                             bool* p_config_updated) {
243   uint8_t codec_info[AVDT_CODEC_SIZE];
244 
245   *p_restart_input = false;
246   *p_restart_output = false;
247   *p_config_updated = false;
248   if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
249     LOG_ERROR(LOG_TAG,
250               "%s: Cannot update the codec encoder for %s: "
251               "invalid codec config",
252               __func__, a2dp_codec_config->name().c_str());
253     return;
254   }
255   const uint8_t* p_codec_info = codec_info;
256 
257   // The feeding parameters
258   tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_aptx_encoder_cb.feeding_params;
259   p_feeding_params->sample_rate =
260       A2DP_VendorGetTrackSampleRateAptx(p_codec_info);
261   p_feeding_params->bits_per_sample =
262       a2dp_codec_config->getAudioBitsPerSample();
263   p_feeding_params->channel_count =
264       A2DP_VendorGetTrackChannelCountAptx(p_codec_info);
265   LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
266             __func__, p_feeding_params->sample_rate,
267             p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
268   a2dp_vendor_aptx_feeding_reset();
269 }
270 
a2dp_vendor_aptx_encoder_cleanup(void)271 void a2dp_vendor_aptx_encoder_cleanup(void) {
272   osi_free(a2dp_aptx_encoder_cb.aptx_encoder_state);
273   memset(&a2dp_aptx_encoder_cb, 0, sizeof(a2dp_aptx_encoder_cb));
274 }
275 
276 //
277 // Initialize the framing parameters, and set those that don't change
278 // while streaming (e.g., 'sleep_time_ns').
279 //
aptx_init_framing_params(tAPTX_FRAMING_PARAMS * framing_params)280 static void aptx_init_framing_params(tAPTX_FRAMING_PARAMS* framing_params) {
281   framing_params->sleep_time_ns = 0;
282   framing_params->pcm_reads = 0;
283   framing_params->pcm_bytes_per_read = 0;
284   framing_params->aptx_bytes = 0;
285   framing_params->frame_size_counter = 0;
286 
287   if (a2dp_aptx_encoder_cb.feeding_params.sample_rate == 48000) {
288     if (a2dp_aptx_encoder_cb.use_SCMS_T) {
289       framing_params->sleep_time_ns = 13000000;
290     } else {
291       framing_params->sleep_time_ns = 14000000;
292     }
293   } else {
294     // Assume the sample rate is 44100
295     if (a2dp_aptx_encoder_cb.use_SCMS_T) {
296       framing_params->sleep_time_ns = 14000000;
297     } else {
298       framing_params->sleep_time_ns = 15000000;
299     }
300   }
301 
302   LOG_DEBUG(LOG_TAG, "%s: sleep_time_ns = %" PRIu64, __func__,
303             framing_params->sleep_time_ns);
304 }
305 
306 //
307 // Set frame size and transmission interval needed to stream the required
308 // sample rate using 2-DH5 packets for aptX and 2-DH3 packets for aptX-LL.
309 // With SCMS-T enabled we need to reserve room for extra headers added later.
310 // Packets are always sent at equals time intervals but to achieve the
311 // required sample rate, the frame size needs to change on occasion.
312 //
313 // Also need to specify how many of the required PCM samples are read at a
314 // time:
315 //     aptx_bytes = pcm_reads * pcm_bytes_per_read / 4
316 // and
317 //     number of aptX samples produced = pcm_bytes_per_read / 16
318 //
aptx_update_framing_params(tAPTX_FRAMING_PARAMS * framing_params)319 static void aptx_update_framing_params(tAPTX_FRAMING_PARAMS* framing_params) {
320   if (a2dp_aptx_encoder_cb.feeding_params.sample_rate == 48000) {
321     if (a2dp_aptx_encoder_cb.use_SCMS_T) {
322       framing_params->aptx_bytes = 624;
323       framing_params->pcm_bytes_per_read = 208;
324       framing_params->pcm_reads = 12;
325     } else {
326       framing_params->aptx_bytes = 672;
327       framing_params->pcm_bytes_per_read = 224;
328       framing_params->pcm_reads = 12;
329     }
330   } else {
331     // Assume the sample rate is 44100
332     if (a2dp_aptx_encoder_cb.use_SCMS_T) {
333       if (++framing_params->frame_size_counter < 20) {
334         framing_params->aptx_bytes = 616;
335         framing_params->pcm_bytes_per_read = 224;
336         framing_params->pcm_reads = 11;
337       } else {
338         framing_params->aptx_bytes = 644;
339         framing_params->pcm_bytes_per_read = 368;
340         framing_params->pcm_reads = 7;
341         framing_params->frame_size_counter = 0;
342       }
343     } else {
344       if (++framing_params->frame_size_counter < 8) {
345         framing_params->aptx_bytes = 660;
346         framing_params->pcm_bytes_per_read = 240;
347         framing_params->pcm_reads = 11;
348       } else {
349         framing_params->aptx_bytes = 672;
350         framing_params->pcm_bytes_per_read = 224;
351         framing_params->pcm_reads = 12;
352         framing_params->frame_size_counter = 0;
353       }
354     }
355   }
356 
357   LOG_VERBOSE(LOG_TAG,
358               "%s: sleep_time_ns = %" PRIu64
359               " aptx_bytes = %u "
360               "pcm_bytes_per_read = %u pcm_reads = %u frame_size_counter = %u",
361               __func__, framing_params->sleep_time_ns,
362               framing_params->aptx_bytes, framing_params->pcm_bytes_per_read,
363               framing_params->pcm_reads, framing_params->frame_size_counter);
364 }
365 
a2dp_vendor_aptx_feeding_reset(void)366 void a2dp_vendor_aptx_feeding_reset(void) {
367   aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
368 }
369 
a2dp_vendor_aptx_feeding_flush(void)370 void a2dp_vendor_aptx_feeding_flush(void) {
371   aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
372 }
373 
a2dp_vendor_aptx_get_encoder_interval_ms(void)374 uint64_t a2dp_vendor_aptx_get_encoder_interval_ms(void) {
375   return a2dp_aptx_encoder_cb.framing_params.sleep_time_ns / (1000 * 1000);
376 }
377 
a2dp_vendor_aptx_send_frames(uint64_t timestamp_us)378 void a2dp_vendor_aptx_send_frames(uint64_t timestamp_us) {
379   tAPTX_FRAMING_PARAMS* framing_params = &a2dp_aptx_encoder_cb.framing_params;
380 
381   // Prepare the packet to send
382   BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
383   p_buf->offset = A2DP_APTX_OFFSET;
384   p_buf->len = 0;
385   p_buf->layer_specific = 0;
386 
387   uint8_t* encoded_ptr = (uint8_t*)(p_buf + 1);
388   encoded_ptr += p_buf->offset;
389 
390   aptx_update_framing_params(framing_params);
391 
392   //
393   // Read the PCM data and encode it
394   //
395   uint16_t read_buffer16[A2DP_APTX_MAX_PCM_BYTES_PER_READ / sizeof(uint16_t)];
396   uint32_t expected_read_bytes =
397       framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
398   size_t encoded_ptr_index = 0;
399   size_t pcm_bytes_encoded = 0;
400   uint32_t bytes_read = 0;
401 
402   a2dp_aptx_encoder_cb.stats.media_read_total_expected_packets++;
403   a2dp_aptx_encoder_cb.stats.media_read_total_expected_reads_count++;
404   a2dp_aptx_encoder_cb.stats.media_read_total_expected_read_bytes +=
405       expected_read_bytes;
406 
407   LOG_VERBOSE(LOG_TAG, "%s: PCM read of size %u", __func__,
408               expected_read_bytes);
409   bytes_read = a2dp_aptx_encoder_cb.read_callback((uint8_t*)read_buffer16,
410                                                   expected_read_bytes);
411   a2dp_aptx_encoder_cb.stats.media_read_total_actual_read_bytes += bytes_read;
412   if (bytes_read < expected_read_bytes) {
413     LOG_WARN(LOG_TAG,
414              "%s: underflow at PCM reading: read %u bytes instead of %u",
415              __func__, bytes_read, expected_read_bytes);
416     a2dp_aptx_encoder_cb.stats.media_read_total_dropped_packets++;
417     osi_free(p_buf);
418     return;
419   }
420   a2dp_aptx_encoder_cb.stats.media_read_total_actual_reads_count++;
421 
422   for (uint32_t reads = 0, offset = 0; reads < framing_params->pcm_reads;
423        reads++, offset +=
424                 (framing_params->pcm_bytes_per_read / sizeof(uint16_t))) {
425     pcm_bytes_encoded += aptx_encode_16bit(framing_params, &encoded_ptr_index,
426                                            read_buffer16 + offset, encoded_ptr);
427   }
428 
429   // Compute the number of encoded bytes
430   const int COMPRESSION_RATIO = 4;
431   size_t encoded_bytes = pcm_bytes_encoded / COMPRESSION_RATIO;
432   p_buf->len += encoded_bytes;
433   LOG_VERBOSE(LOG_TAG, "%s: encoded %zu PCM bytes to %zu", __func__,
434               pcm_bytes_encoded, encoded_bytes);
435 
436   // Update the RTP timestamp
437   *((uint32_t*)(p_buf + 1)) = a2dp_aptx_encoder_cb.timestamp;
438   const uint8_t BYTES_PER_FRAME = 2;
439   uint32_t rtp_timestamp =
440       (pcm_bytes_encoded / a2dp_aptx_encoder_cb.feeding_params.channel_count) /
441       BYTES_PER_FRAME;
442   a2dp_aptx_encoder_cb.timestamp += rtp_timestamp;
443 
444   if (p_buf->len > 0) {
445     a2dp_aptx_encoder_cb.enqueue_callback(p_buf, 1, bytes_read);
446   } else {
447     a2dp_aptx_encoder_cb.stats.media_read_total_dropped_packets++;
448     osi_free(p_buf);
449   }
450 }
451 
aptx_encode_16bit(tAPTX_FRAMING_PARAMS * framing_params,size_t * data_out_index,uint16_t * data16_in,uint8_t * data_out)452 static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params,
453                                 size_t* data_out_index, uint16_t* data16_in,
454                                 uint8_t* data_out) {
455   size_t pcm_bytes_encoded = 0;
456   size_t frame = 0;
457 
458   for (size_t aptx_samples = 0;
459        aptx_samples < framing_params->pcm_bytes_per_read / 16; aptx_samples++) {
460     uint32_t pcmL[4];
461     uint32_t pcmR[4];
462     uint16_t encoded_sample[2];
463 
464     for (size_t i = 0, j = frame; i < 4; i++, j++) {
465       pcmL[i] = (uint16_t) * (data16_in + (2 * j));
466       pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1));
467     }
468 
469     aptx_encoder_encode_stereo_func(a2dp_aptx_encoder_cb.aptx_encoder_state,
470                                     &pcmL, &pcmR, &encoded_sample);
471 
472     data_out[*data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff);
473     data_out[*data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff);
474     data_out[*data_out_index + 2] = (uint8_t)((encoded_sample[1] >> 8) & 0xff);
475     data_out[*data_out_index + 3] = (uint8_t)((encoded_sample[1] >> 0) & 0xff);
476 
477     frame += 4;
478     pcm_bytes_encoded += 16;
479     *data_out_index += 4;
480   }
481 
482   return pcm_bytes_encoded;
483 }
484 
encoderIntervalMs() const485 uint64_t A2dpCodecConfigAptx::encoderIntervalMs() const {
486   return a2dp_vendor_aptx_get_encoder_interval_ms();
487 }
488 
getEffectiveMtu() const489 int A2dpCodecConfigAptx::getEffectiveMtu() const {
490   return a2dp_aptx_encoder_cb.peer_mtu;
491 }
492 
debug_codec_dump(int fd)493 void A2dpCodecConfigAptx::debug_codec_dump(int fd) {
494   a2dp_aptx_encoder_stats_t* stats = &a2dp_aptx_encoder_cb.stats;
495 
496   A2dpCodecConfig::debug_codec_dump(fd);
497 
498   dprintf(fd,
499           "  Packet counts (expected/dropped)                        : %zu / "
500           "%zu\n",
501           stats->media_read_total_expected_packets,
502           stats->media_read_total_dropped_packets);
503 
504   dprintf(fd,
505           "  PCM read counts (expected/actual)                       : %zu / "
506           "%zu\n",
507           stats->media_read_total_expected_reads_count,
508           stats->media_read_total_actual_reads_count);
509 
510   dprintf(fd,
511           "  PCM read bytes (expected/actual)                        : %zu / "
512           "%zu\n",
513           stats->media_read_total_expected_read_bytes,
514           stats->media_read_total_actual_read_bytes);
515 }
516