summaryrefslogtreecommitdiffstats
path: root/stack/include/a2dp_codec_api.h
blob: 94871ce4b3c963ffec7af1819b2b9d1cccbbc88a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// A2DP Codecs API
//

#ifndef A2DP_CODEC_API_H
#define A2DP_CODEC_API_H

#include <stddef.h>
#include <string.h>
#include <functional>
#include <list>
#include <map>
#include <mutex>
#include <string>

#include <hardware/bt_av.h>

#include "a2dp_api.h"
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
#include "avdt_api.h"
#include "osi/include/time.h"

/**
 * Structure used to initialize the A2DP encoder with A2DP peer information
 */
typedef struct {
  bool is_peer_edr;          // True if the A2DP peer supports EDR
  bool peer_supports_3mbps;  // True if the A2DP peer supports 3 Mbps EDR
  uint16_t peer_mtu;         // MTU of the A2DP peer
} tA2DP_ENCODER_INIT_PEER_PARAMS;

class A2dpCodecConfig {
  friend class A2dpCodecs;

 public:
  // Creates a codec entry. The selected codec is defined by |codec_index|,
  // Returns the codec entry on success, otherwise nullptr.
  static A2dpCodecConfig* createCodec(
      btav_a2dp_codec_index_t codec_index,
      btav_a2dp_codec_priority_t codec_priority =
          BTAV_A2DP_CODEC_PRIORITY_DEFAULT);

  virtual ~A2dpCodecConfig() = 0;

  // Gets the pre-defined codec index.
  btav_a2dp_codec_index_t codecIndex() const { return codec_index_; }

  // Gets the codec name.
  const std::string& name() const { return name_; }

  // Gets the current priority of the codec.
  btav_a2dp_codec_priority_t codecPriority() const { return codec_priority_; }

  // Copies out the current OTA codec config to |p_codec_info|.
  // Returns true if the current codec config is valid and copied,
  // otherwise false.
  bool copyOutOtaCodecConfig(uint8_t* p_codec_info);

  // Gets the current codec configuration.
  // Returns a copy of the current codec configuration.
  btav_a2dp_codec_config_t getCodecConfig();

  // Gets the current codec capability.
  // The capability is computed by intersecting the local codec's capability
  // and the peer's codec capability. However, if there is an explicit user
  // configuration for some of the parameters, the result codec configuration
  // and capability is restricted to the user's configuration choice.
  // Returns a copy of the current codec capability.
  btav_a2dp_codec_config_t getCodecCapability();

  // Gets the codec local capability.
  // Returns a copy of the codec local capability.
  btav_a2dp_codec_config_t getCodecLocalCapability();

  // Gets the codec selectable capability.
  // The capability is computed by intersecting the local codec's capability
  // and the peer's codec capability. Any explicit user configuration is
  // not included in the result.
  // Returns a copy of the codec selectable capability.
  btav_a2dp_codec_config_t getCodecSelectableCapability();

  // Gets the current codec user configuration.
  // Returns a copy of the current codec user configuration.
  btav_a2dp_codec_config_t getCodecUserConfig();

  // Gets the current codec audio configuration.
  // Returns a copy of the current codec audio configuration.
  btav_a2dp_codec_config_t getCodecAudioConfig();

  // Gets the number of bits per sample of the current codec configuration,
  // or 0 if not configured.
  uint8_t getAudioBitsPerSample();

  // Checks whether the codec uses the RTP Header Marker bit (see RFC 6416).
  // NOTE: Even if the encoded data uses RTP headers, some codecs do not use
  // the Marker bit - that bit is expected to be set to 0.
  // Returns true if the encoded data packets have RTP headers, and
  // the Marker bit in the header is set according to RFC 6416.
  virtual bool useRtpHeaderMarkerBit() const = 0;

  // Checks whether |codec_config| is empty and contains no configuration.
  // Returns true if |codec_config| is empty, otherwise false.
  static bool isCodecConfigEmpty(const btav_a2dp_codec_config_t& codec_config);

 protected:
  // Sets the current priority of the codec to |codec_priority|.
  // If |codec_priority| is BTAV_A2DP_CODEC_PRIORITY_DEFAULT, the priority is
  // reset to its default value.
  void setCodecPriority(btav_a2dp_codec_priority_t codec_priority);

  // Sets the current priority of the codec to its default value.
  void setDefaultCodecPriority();

  // Sets the A2DP Source-to-Sink codec configuration to be used
  // with a peer Sink device.
  // |p_peer_codec_info| is the peer's A2DP Sink codec information
  // to use. If |is_capability| is true, then |p_peer_codec_info| contains the
  // peer's A2DP Sink codec capability, otherwise it contains the peer's
  // preferred A2DP codec configuration to use.
  // The result codec configuration is stored in |p_result_codec_config|.
  // See |A2dpCodecs.setCodecConfig| for detailed description of
  // the actual mechanism used to compute the configuration.
  // Returns true on success, othewise false.
  virtual bool setCodecConfig(const uint8_t* p_peer_codec_info,
                              bool is_capability,
                              uint8_t* p_result_codec_config) = 0;

  // Sets the user prefered codec configuration.
  // |codec_user_config| contains the preferred codec user configuration.
  // |codec_audio_config| contains the selected audio feeding configuration.
  // |p_peer_params| contains the A2DP peer information.
  // |p_peer_codec_info| is the peer's A2DP Sink codec information
  // to use. If |is_capability| is true, then |p_peer_codec_info| contains the
  // peer's A2DP Sink codec capability, otherwise it contains the peer's
  // preferred A2DP codec configuration to use.
  // If there is a change in the codec configuration that requires restarting
  // if the audio input stream, flag |p_restart_input| is set to true.
  // If there is a change in the encoder configuration that requires restarting
  // of the A2DP connection, the new codec configuration is stored in
  // |p_result_codec_config|, and flag |p_restart_output| is set to true.
  // If there is any change in the codec configuration, flag |p_config_updated|
  // is set to true.
  // Returns true on success, otherwise false.
  virtual bool setCodecUserConfig(
      const btav_a2dp_codec_config_t& codec_user_config,
      const btav_a2dp_codec_config_t& codec_audio_config,
      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
      const uint8_t* p_peer_codec_info, bool is_capability,
      uint8_t* p_result_codec_config, bool* p_restart_input,
      bool* p_restart_output, bool* p_config_updated);

  // Updates the encoder with the user prefered codec configuration.
  // |p_peer_params| contains the A2DP peer information.
  // If there is a change in the encoder configuration that requires restarting
  // the audio input stream, flag |p_restart_input| is set to true.
  // If there is a change in the encoder configuration that requires restarting
  // of the A2DP connection, flag |p_restart_output| is set to true.
  // If there is any change in the codec configuration, flag |p_config_updated|
  // is set to true.
  // Returns true on success, otherwise false.
  virtual bool updateEncoderUserConfig(
      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
      bool* p_restart_input, bool* p_restart_output,
      bool* p_config_updated) = 0;

  // Constructor where |codec_index| is the unique index that identifies the
  // codec. The user-friendly name is |name|.
  // The default codec priority is |codec_priority|. If the value is
  // |BTAV_A2DP_CODEC_PRIORITY_DEFAULT|, the codec priority is computed
  // internally.
  A2dpCodecConfig(btav_a2dp_codec_index_t codec_index, const std::string& name,
                  btav_a2dp_codec_priority_t codec_priority);

  // Initializes the codec entry.
  // Returns true on success, otherwise false.
  virtual bool init() = 0;

  // Checks whether the internal state is valid
  virtual bool isValid() const;

  // Returns the encoder's periodic interval (in milliseconds).
  virtual period_ms_t encoderIntervalMs() const = 0;

  // Checks whether the A2DP Codec Configuration is valid.
  // Returns true if A2DP Codec Configuration stored in |codec_config|
  // is valid, otherwise false.
  static bool codecConfigIsValid(const btav_a2dp_codec_config_t& codec_config);

  // Gets the string representation of A2DP Codec Configuration.
  // Returns the string representation of A2DP Codec Configuration stored
  // in |codec_config|. The format is:
  // "Rate=44100|48000 Bits=16|24 Mode=MONO|STEREO"
  static std::string codecConfig2Str(
      const btav_a2dp_codec_config_t& codec_config);

  // Gets the string representation of A2DP Codec Sample Rate.
  // Returns the string representation of A2DP Codec Sample Rate stored
  // in |codec_sample_rate|. If there are multiple values stored in
  // |codec_sample_rate|, the return string format is "rate1|rate2|rate3".
  static std::string codecSampleRate2Str(
      btav_a2dp_codec_sample_rate_t codec_sample_rate);

  // Gets the string representation of A2DP Codec Bits Per Sample.
  // Returns the string representation of A2DP Codec Bits Per Sample stored
  // in |codec_bits_per_sample|. If there are multiple values stored in
  // |codec_bits_per_sample|, the return string format is "bits1|bits2|bits3".
  static std::string codecBitsPerSample2Str(
      btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample);

  // Gets the string representation of A2DP Codec Channel Mode.
  // Returns the string representation of A2DP Channel Mode stored
  // in |codec_channel_mode|. If there are multiple values stored in
  // |codec_channel_mode|, the return string format is "mode1|mode2|mode3".
  static std::string codecChannelMode2Str(
      btav_a2dp_codec_channel_mode_t codec_channel_mode);

  // Dumps codec-related information.
  // The information is written in user-friendly form to file descriptor |fd|.
  virtual void debug_codec_dump(int fd);

  std::recursive_mutex codec_mutex_;
  const btav_a2dp_codec_index_t codec_index_;  // The unique codec index
  const std::string name_;                     // The codec name
  btav_a2dp_codec_priority_t codec_priority_;  // Codec priority: must be unique
  btav_a2dp_codec_priority_t default_codec_priority_;

  btav_a2dp_codec_config_t codec_config_;
  btav_a2dp_codec_config_t codec_capability_;
  btav_a2dp_codec_config_t codec_local_capability_;
  btav_a2dp_codec_config_t codec_selectable_capability_;

  // The optional user configuration. The values (if set) are used
  // as a preference when there is a choice. If a particular value
  // is not supported by the local or remote device, it is ignored.
  btav_a2dp_codec_config_t codec_user_config_;

  // The selected audio feeding configuration.
  btav_a2dp_codec_config_t codec_audio_config_;

  uint8_t ota_codec_config_[AVDT_CODEC_SIZE];
  uint8_t ota_codec_peer_capability_[AVDT_CODEC_SIZE];
  uint8_t ota_codec_peer_config_[AVDT_CODEC_SIZE];
};

class A2dpCodecs {
 public:
  // Constructor for class |A2dpCodecs|.
  // |codec_priorities| contains the codec priorities to use.
  A2dpCodecs(const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
  ~A2dpCodecs();

  // Initializes all supported codecs.
  // Returns true if at least one Source codec and one Sink codec were
  // initialized, otherwise false.
  bool init();

  // Finds the Source codec that corresponds to the A2DP over-the-air
  // |p_codec_info| information.
  // Returns the Source codec if found, otherwise nullptr.
  A2dpCodecConfig* findSourceCodecConfig(const uint8_t* p_codec_info);

  // Gets the codec config that is currently selected.
  // Returns the codec config that is currently selected, or nullptr if
  // no codec is selected.
  A2dpCodecConfig* getCurrentCodecConfig() const {
    return current_codec_config_;
  }

  // Gets the list of Source codecs ordered by priority: higher priority first.
  const std::list<A2dpCodecConfig*> orderedSourceCodecs() const {
    return ordered_source_codecs_;
  }

  // Gets the list of Sink codecs ordered by priority: higher priority first.
  const std::list<A2dpCodecConfig*> orderedSinkCodecs() const {
    return ordered_sink_codecs_;
  }

  // Sets the A2DP Source-to-Sink codec configuration to be used
  // with a peer Sink device.
  // |p_peer_codec_info| is the peer's A2DP Sink codec information
  // to use. If |is_capability| is true, then |p_peer_codec_info| contains the
  // peer's A2DP Sink codec capability, otherwise it contains the peer's
  // preferred A2DP codec configuration to use.
  // If the codec can be used and |select_current_codec| is true, then
  // this codec is selected as the current one.
  //
  // The codec configuration is built by considering the optional user
  // configuration, the local codec capabilities, the peer's codec
  // capabilities, and the codec's locally-defined default values.
  // For each codec parameter:
  //
  // 1. If it is user-configurable parameter (sample rate, bits per sample,
  //    channel mode, and some codec-specific parameters),
  //    if the user has an explicit preference, and that preference
  //    is supported by both the local and remote device, this is the
  //    parameter value that is used.
  // 2. Otherwise, if the explicit internal default value is supported
  //    by both the local and remote device, this is the parameter value
  //    that is used.
  // 3. Otherwise, the best match is chosen among all values supported by
  //    the local and remote device.
  //
  // In addition, the codec's internal state is updated to reflect
  // the capabilities that are advertised to the upstream audio source
  // (Media Framework) to make run-time audio parameter choices:
  // 4. If the user-configurable parameter was selected, this is the
  //    only parameter value that is advertised to the Media Framework.
  // 5. Otherwise, all values supported by both the local and remote
  //    devices are advertised to the Media Framework.
  //
  // The result codec configuration is stored in |p_result_codec_config|.
  // Returns true on success, othewise false.
  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                      uint8_t* p_result_codec_config,
                      bool select_current_codec);

  // Sets the user prefered codec configuration.
  // |codec_user_config| contains the preferred codec configuration.
  // |p_peer_params| contains the A2DP peer information.
  // |p_peer_sink_capabilities| is the peer's A2DP Sink codec capabilities
  // to use.
  // If there is a change in the encoder configuration that requires restarting
  // the audio input stream, flag |p_restart_input| is set to true.
  // If there is a change in the encoder configuration that requires restarting
  // of the A2DP connection, flag |p_restart_output| is set to true, and the
  // new codec is stored in |p_result_codec_config|.
  // If there is any change in the codec configuration, flag |p_config_updated|
  // is set to true.
  // Returns true on success, otherwise false.
  bool setCodecUserConfig(const btav_a2dp_codec_config_t& codec_user_config,
                          const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
                          const uint8_t* p_peer_sink_capabilities,
                          uint8_t* p_result_codec_config, bool* p_restart_input,
                          bool* p_restart_output, bool* p_config_updated);

  // Sets the Audio HAL selected audio feeding parameters.
  // Those parameters are applied only to the currently selected codec.
  // |codec_audio_config| contains the selected audio feeding configuration.
  // |p_peer_params| contains the A2DP peer information.
  // |p_peer_sink_capabilities| is the peer's A2DP Sink codec capabilities
  // to use.
  // If there is a change in the encoder configuration that requires restarting
  // of the A2DP connection, flag |p_restart_output| is set to true, and the
  // new codec is stored in |p_result_codec_config|.
  // If there is any change in the codec configuration, flag |p_config_updated|
  // is set to true.
  // Returns true on success, otherwise false.
  bool setCodecAudioConfig(const btav_a2dp_codec_config_t& codec_audio_config,
                           const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
                           const uint8_t* p_peer_sink_capabilities,
                           uint8_t* p_result_codec_config,
                           bool* p_restart_output, bool* p_config_updated);

  // Sets the Over-The-Air preferred codec configuration.
  // The OTA prefered codec configuration is ignored if the current
  // codec configuration contains explicit user configuration, or if the
  // codec configuration for the same codec contains explicit user
  // configuration.
  // |p_ota_codec_config| contains the received OTA A2DP codec configuration
  // from the remote peer. Note: this is not the peer codec capability,
  // but the codec configuration that the peer would like to use.
  // |p_peer_params| contains the A2DP peer information.
  // If there is a change in the encoder configuration that requires restarting
  // the audio input stream, flag |p_restart_input| is set to true.
  // If there is a change in the encoder configuration that requires restarting
  // of the A2DP connection, flag |p_restart_output| is set to true, and the
  // new codec is stored in |p_result_codec_config|.
  // If there is any change in the codec configuration, flag |p_config_updated|
  // is set to true.
  // Returns true on success, otherwise false.
  bool setCodecOtaConfig(const uint8_t* p_ota_codec_config,
                         const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
                         uint8_t* p_result_codec_config, bool* p_restart_input,
                         bool* p_restart_output, bool* p_config_updated);

  // Gets the current codec configuration and the capabilities of
  // all configured codecs.
  // The current codec configuration is stored in |p_codec_config|.
  // Local device's codecs capabilities are stored in
  // |p_codecs_local_capabilities|.
  // The codecs capabilities that can be used between the local device
  // and the remote device are stored in |p_codecs_selectable_capabilities|.
  // Returns true on success, otherwise false.
  bool getCodecConfigAndCapabilities(
      btav_a2dp_codec_config_t* p_codec_config,
      std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,
      std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities);

  // Dumps codec-related information.
  // The information is written in user-friendly form to file descriptor |fd|.
  void debug_codec_dump(int fd);

 private:
  struct CompareBtBdaddr
      : public std::binary_function<bt_bdaddr_t, bt_bdaddr_t, bool> {
    bool operator()(const bt_bdaddr_t& lhs, const bt_bdaddr_t& rhs) const {
      return (memcmp(&lhs, &rhs, sizeof(lhs)) < 0);
    }
  };
  typedef std::map<btav_a2dp_codec_index_t, A2dpCodecConfig*> IndexedCodecs;

  std::recursive_mutex codec_mutex_;
  A2dpCodecConfig* current_codec_config_;  // Currently selected codec
  std::map<btav_a2dp_codec_index_t, btav_a2dp_codec_priority_t>
      codec_priorities_;

  IndexedCodecs indexed_codecs_;           // The codecs indexed by codec index
  IndexedCodecs disabled_codecs_;          // The disabled codecs

  // A2DP Source codecs ordered by priority
  std::list<A2dpCodecConfig*> ordered_source_codecs_;

  // A2DP Sink codecs ordered by priority
  std::list<A2dpCodecConfig*> ordered_sink_codecs_;

  std::map<bt_bdaddr_t, IndexedCodecs*, CompareBtBdaddr> peer_codecs_;
};

/**
 * Structure used to configure the A2DP feeding.
 */
typedef struct {
  tA2DP_SAMPLE_RATE sample_rate;          // 44100, 48000, etc
  tA2DP_BITS_PER_SAMPLE bits_per_sample;  // 8, 16, 24, 32
  tA2DP_CHANNEL_COUNT channel_count;      // 1 for mono or 2 for stereo
} tA2DP_FEEDING_PARAMS;

// Prototype for a callback to read audio data for encoding.
// |p_buf| is the buffer to store the data. |len| is the number of octets to
// read.
// Returns the number of octets read.
typedef uint32_t (*a2dp_source_read_callback_t)(uint8_t* p_buf, uint32_t len);

// Prototype for a callback to enqueue A2DP Source packets for transmission.
// |p_buf| is the buffer with the audio data to enqueue. The callback is
// responsible for freeing |p_buf|.
// |frames_n| is the number of audio frames in |p_buf| - it is used for
// statistics purpose.
// Returns true if the packet was enqueued, otherwise false.
typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n);

//
// A2DP encoder callbacks interface.
//
typedef struct {
  // Initialize the A2DP encoder.
  // |p_peer_params| contains the A2DP peer information
  // The current A2DP codec config is in |a2dp_codec_config|.
  // |read_callback| is the callback for reading the input audio data.
  // |enqueue_callback| is the callback for enqueueing the encoded audio data.
  void (*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);

  // Cleanup the A2DP encoder.
  void (*encoder_cleanup)(void);

  // Reset the feeding for the A2DP encoder.
  void (*feeding_reset)(void);

  // Flush the feeding for the A2DP encoder.
  void (*feeding_flush)(void);

  // Get the A2DP encoder interval (in milliseconds).
  period_ms_t (*get_encoder_interval_ms)(void);

  // Prepare and send A2DP encoded frames.
  // |timestamp_us| is the current timestamp (in microseconds).
  void (*send_frames)(uint64_t timestamp_us);

  // Set transmit queue length for the A2DP encoder.
  void (*set_transmit_queue_length)(size_t transmit_queue_length);
} tA2DP_ENCODER_INTERFACE;

// Gets the A2DP codec type.
// |p_codec_info| contains information about the codec capabilities.
tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info);

// Checks whether the codec capabilities contain a valid A2DP Source codec.
// NOTE: only codecs that are implemented are considered valid.
// Returns true if |p_codec_info| contains information about a valid codec,
// otherwise false.
bool A2DP_IsSourceCodecValid(const uint8_t* p_codec_info);

// Checks whether the codec capabilities contain a valid A2DP Sink codec.
// NOTE: only codecs that are implemented are considered valid.
// Returns true if |p_codec_info| contains information about a valid codec,
// otherwise false.
bool A2DP_IsSinkCodecValid(const uint8_t* p_codec_info);

// Checks whether the codec capabilities contain a valid peer A2DP Source
// codec.
// NOTE: only codecs that are implemented are considered valid.
// Returns true if |p_codec_info| contains information about a valid codec,
// otherwise false.
bool A2DP_IsPeerSourceCodecValid(const uint8_t* p_codec_info);

// Checks whether the codec capabilities contain a valid peer A2DP Sink codec.
// NOTE: only codecs that are implemented are considered valid.
// Returns true if |p_codec_info| contains information about a valid codec,
// otherwise false.
bool A2DP_IsPeerSinkCodecValid(const uint8_t* p_codec_info);

// Checks whether an A2DP Sink codec is supported.
// |p_codec_info| contains information about the codec capabilities.
// Returns true if the A2DP Sink codec is supported, otherwise false.
bool A2DP_IsSinkCodecSupported(const uint8_t* p_codec_info);

// Checks whether an A2DP Source codec for a peer Source device is supported.
// |p_codec_info| contains information about the codec capabilities of the
// peer device.
// Returns true if the A2DP Source codec for a peer Source device is supported,
// otherwise false.
bool A2DP_IsPeerSourceCodecSupported(const uint8_t* p_codec_info);

// Initialize state with the default A2DP codec.
// The initialized state with the codec capabilities is stored in
// |p_codec_info|.
void A2DP_InitDefaultCodec(uint8_t* p_codec_info);

// Builds A2DP preferred Sink capability from Source capability.
// |p_src_cap| is the Source capability to use.
// |p_pref_cfg| is the result Sink capability to store.
// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
// status code.
tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
                                      uint8_t* p_pref_cfg);

// Checks whether the A2DP data packets should contain RTP header.
// |content_protection_enabled| is true if Content Protection is
// enabled. |p_codec_info| contains information about the codec capabilities.
// Returns true if the A2DP data packets should contain RTP header, otherwise
// false.
bool A2DP_UsesRtpHeader(bool content_protection_enabled,
                        const uint8_t* p_codec_info);

// Gets the |AVDT_MEDIA_TYPE_*| media type from the codec capability
// in |p_codec_info|.
uint8_t A2DP_GetMediaType(const uint8_t* p_codec_info);

// Gets the A2DP codec name for a given |p_codec_info|.
const char* A2DP_CodecName(const uint8_t* p_codec_info);

// Checks whether two A2DP codecs |p_codec_info_a| and |p_codec_info_b| have
// the same type.
// Returns true if the two codecs have the same type, otherwise false.
// If the codec type is not recognized, the return value is false.
bool A2DP_CodecTypeEquals(const uint8_t* p_codec_info_a,
                          const uint8_t* p_codec_info_b);

// Checks whether two A2DP codecs p_codec_info_a| and |p_codec_info_b| are
// exactly the same.
// Returns true if the two codecs are exactly the same, otherwise false.
// If the codec type is not recognized, the return value is false.
bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
                      const uint8_t* p_codec_info_b);

// Gets the track sample rate value for the A2DP codec.
// |p_codec_info| is a pointer to the codec_info to decode.
// Returns the track sample rate on success, or -1 if |p_codec_info|
// contains invalid codec information.
int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info);

// Gets the channel count for the A2DP codec.
// |p_codec_info| is a pointer to the codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
// contains invalid codec information.
int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info);

// Gets the channel type for the A2DP Sink codec:
// 1 for mono, or 3 for dual/stereo/joint.
// |p_codec_info| is a pointer to the codec_info to decode.
// Returns the channel type on success, or -1 if |p_codec_info|
// contains invalid codec information.
int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info);

// Computes the number of frames to process in a time window for the A2DP
// Sink codec. |time_interval_ms| is the time interval (in milliseconds).
// |p_codec_info| is a pointer to the codec_info to decode.
// Returns the number of frames to process on success, or -1 if |p_codec_info|
// contains invalid codec information.
int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
                                     const uint8_t* p_codec_info);

// Gets the A2DP audio data timestamp from an audio packet.
// |p_codec_info| contains the codec information.
// |p_data| contains the audio data.
// The timestamp is stored in |p_timestamp|.
// Returns true on success, otherwise false.
bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
                             uint32_t* p_timestamp);

// Builds A2DP codec header for audio data.
// |p_codec_info| contains the codec information.
// |p_buf| contains the audio data.
// |frames_per_packet| is the number of frames in this packet.
// Returns true on success, otherwise false.
bool A2DP_BuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
                           uint16_t frames_per_packet);

// Gets the A2DP encoder interface that can be used to encode and prepare
// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
// |p_codec_info| contains the codec information.
// Returns the A2DP encoder interface if the |p_codec_info| is valid and
// supported, otherwise NULL.
const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
    const uint8_t* p_codec_info);

// Adjusts the A2DP codec, based on local support and Bluetooth specification.
// |p_codec_info| contains the codec information to adjust.
// Returns true if |p_codec_info| is valid and supported, otherwise false.
bool A2DP_AdjustCodec(uint8_t* p_codec_info);

// Gets the A2DP Source codec index for a given |p_codec_info|.
// Returns the corresponding |btav_a2dp_codec_index_t| on success,
// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
btav_a2dp_codec_index_t A2DP_SourceCodecIndex(const uint8_t* p_codec_info);

// Gets the A2DP codec name for a given |codec_index|.
const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index);

// Initializes A2DP codec-specific information into |tAVDT_CFG| configuration
// entry pointed by |p_cfg|. The selected codec is defined by |codec_index|.
// Returns true on success, otherwise false.
bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
                          tAVDT_CFG* p_cfg);

// Decodes and displays A2DP codec info when using |LOG_DEBUG|.
// |p_codec_info| is a pointer to the codec_info to decode and display.
// Returns true if the codec information is valid, otherwise false.
bool A2DP_DumpCodecInfo(const uint8_t* p_codec_info);

// Add enum-based flag operators to the btav_a2dp_codec_config_t fields
#ifndef DEFINE_ENUM_FLAG_OPERATORS
#define DEFINE_ENUM_FLAG_OPERATORS(bitmask)                                 \
  extern "C++" {                                                            \
  inline constexpr bitmask operator&(bitmask X, bitmask Y) {                \
    return static_cast<bitmask>(static_cast<int>(X) & static_cast<int>(Y)); \
  }                                                                         \
  inline constexpr bitmask operator|(bitmask X, bitmask Y) {                \
    return static_cast<bitmask>(static_cast<int>(X) | static_cast<int>(Y)); \
  }                                                                         \
  inline constexpr bitmask operator^(bitmask X, bitmask Y) {                \
    return static_cast<bitmask>(static_cast<int>(X) ^ static_cast<int>(Y)); \
  }                                                                         \
  inline constexpr bitmask operator~(bitmask X) {                           \
    return static_cast<bitmask>(~static_cast<int>(X));                      \
  }                                                                         \
  inline bitmask& operator&=(bitmask& X, bitmask Y) {                       \
    X = X & Y;                                                              \
    return X;                                                               \
  }                                                                         \
  inline bitmask& operator|=(bitmask& X, bitmask Y) {                       \
    X = X | Y;                                                              \
    return X;                                                               \
  }                                                                         \
  inline bitmask& operator^=(bitmask& X, bitmask Y) {                       \
    X = X ^ Y;                                                              \
    return X;                                                               \
  }                                                                         \
  }
#endif  // DEFINE_ENUM_FLAG_OPERATORS
DEFINE_ENUM_FLAG_OPERATORS(btav_a2dp_codec_sample_rate_t);
DEFINE_ENUM_FLAG_OPERATORS(btav_a2dp_codec_bits_per_sample_t);
DEFINE_ENUM_FLAG_OPERATORS(btav_a2dp_codec_channel_mode_t);

#endif  // A2DP_CODEC_API_H