OSDN Git Service

Add support for A2DP LDAC Sink function
authorChisato Kenmochi <Chisato.Kenmochi@sony.com>
Fri, 10 Aug 2018 11:44:05 +0000 (20:44 +0900)
committerPavlin Radoslavov <pavlin@google.com>
Wed, 12 Sep 2018 18:25:14 +0000 (18:25 +0000)
Note: The LDAC decoder source code is needed to run with this patch.

Bug: 112839060
Test: Manual
Change-Id: Idce0070dcce4d6b83cfd08213b846d957d694d26
Signed-off-by: Chisato Kenmochi <Chisato.Kenmochi@sony.com>
24 files changed:
btif/include/btif_a2dp_sink.h
btif/include/btif_avrcp_audio_track.h
btif/src/btif_a2dp_sink.cc
btif/src/btif_avrcp_audio_track.cc
include/hardware/bt_av.h
stack/Android.bp
stack/a2dp/a2dp_aac.cc
stack/a2dp/a2dp_codec_config.cc
stack/a2dp/a2dp_sbc.cc
stack/a2dp/a2dp_vendor.cc
stack/a2dp/a2dp_vendor_aptx.cc
stack/a2dp/a2dp_vendor_aptx_hd.cc
stack/a2dp/a2dp_vendor_ldac.cc
stack/a2dp/a2dp_vendor_ldac_decoder.cc [new file with mode: 0644]
stack/a2dp/a2dp_vendor_ldac_encoder.cc
stack/include/a2dp_aac.h
stack/include/a2dp_codec_api.h
stack/include/a2dp_sbc.h
stack/include/a2dp_vendor.h
stack/include/a2dp_vendor_aptx.h
stack/include/a2dp_vendor_aptx_hd.h
stack/include/a2dp_vendor_ldac.h
stack/include/a2dp_vendor_ldac_decoder.h [new file with mode: 0644]
stack/test/stack_a2dp_test.cc

index 25e65f4..efb3b26 100644 (file)
@@ -85,6 +85,9 @@ tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void);
 // Get the audio channel count for the A2DP Sink module.
 tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void);
 
+// Get the audio bits per sample for the A2DP Sink module.
+tA2DP_BITS_PER_SAMPLE btif_a2dp_sink_get_bits_per_sample(void);
+
 // Update the decoder for the A2DP Sink module.
 // |p_codec_info| contains the new codec information.
 void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info);
index 720fe60..20b21ff 100644 (file)
@@ -35,7 +35,8 @@
  * should eventually be
  * deleted using BtifAvrcpAudioTrackDelete (see below).
  */
-void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType);
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int bits_per_sample,
+                                int channelType);
 
 /**
  * Starts the audio track.
index 109b208..16d43e3 100644 (file)
@@ -113,6 +113,7 @@ class BtifA2dpSinkControlBlock {
   bool rx_flush; /* discards any incoming data when true */
   alarm_t* decode_alarm;
   tA2DP_SAMPLE_RATE sample_rate;
+  tA2DP_BITS_PER_SAMPLE bits_per_sample;
   tA2DP_CHANNEL_COUNT channel_count;
   btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
   void* audio_track;
@@ -320,6 +321,11 @@ tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate() {
   return btif_a2dp_sink_cb.sample_rate;
 }
 
+tA2DP_BITS_PER_SAMPLE btif_a2dp_sink_get_bits_per_sample() {
+  LockGuard lock(g_mutex);
+  return btif_a2dp_sink_cb.bits_per_sample;
+}
+
 tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count() {
   LockGuard lock(g_mutex);
   return btif_a2dp_sink_cb.channel_count;
@@ -539,6 +545,11 @@ static void btif_a2dp_sink_decoder_update_event(
     LOG_ERROR(LOG_TAG, "%s: cannot get the track frequency", __func__);
     return;
   }
+  int bits_per_sample = A2DP_GetTrackBitsPerSample(p_buf->codec_info);
+  if (bits_per_sample == -1) {
+    LOG_ERROR(LOG_TAG, "%s: cannot get the bits per sample", __func__);
+    return;
+  }
   int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
   if (channel_count == -1) {
     LOG_ERROR(LOG_TAG, "%s: cannot get the channel count", __func__);
@@ -550,6 +561,7 @@ static void btif_a2dp_sink_decoder_update_event(
     return;
   }
   btif_a2dp_sink_cb.sample_rate = sample_rate;
+  btif_a2dp_sink_cb.bits_per_sample = bits_per_sample;
   btif_a2dp_sink_cb.channel_count = channel_count;
 
   btif_a2dp_sink_cb.rx_flush = false;
@@ -571,7 +583,7 @@ static void btif_a2dp_sink_decoder_update_event(
   APPL_TRACE_DEBUG("%s: create audio track", __func__);
   btif_a2dp_sink_cb.audio_track =
 #ifndef OS_GENERIC
-      BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
+      BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_type);
 #else
       NULL;
 #endif
index 76da406..4f3cd35 100644 (file)
@@ -35,11 +35,26 @@ FILE* outputPcmSampleFile;
 char outputFilename[50] = "/data/misc/bluedroid/output_sample.pcm";
 #endif
 
-void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType) {
-  LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d  channel %d ",
-              __func__, trackFreq, channelType);
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int bits_per_sample,
+                                int channelType) {
+  audio_format_t format;
+  switch (bits_per_sample) {
+    default:
+    case 16:
+      format = AUDIO_FORMAT_PCM_16_BIT;
+      break;
+    case 24:
+      format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+      break;
+    case 32:
+      format = AUDIO_FORMAT_PCM_32_BIT;
+      break;
+  }
+  LOG_VERBOSE(LOG_TAG,
+              "%s Track.cpp: btCreateTrack freq %d format 0x%x channel %d ",
+              __func__, trackFreq, format, channelType);
   sp<android::AudioTrack> track = new android::AudioTrack(
-      AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT, channelType,
+      AUDIO_STREAM_MUSIC, trackFreq, format, channelType,
       (size_t)0 /*frameCount*/, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST,
       NULL /*callback_t*/, NULL /*void* user*/, 0 /*notificationFrames*/,
       AUDIO_SESSION_ALLOCATE, android::AudioTrack::TRANSFER_SYNC);
index bdb1285..5cdf1c2 100644 (file)
@@ -62,6 +62,7 @@ typedef enum {
   // Add an entry for each sink codec here
   BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
   BTAV_A2DP_CODEC_INDEX_SINK_AAC,
+  BTAV_A2DP_CODEC_INDEX_SINK_LDAC,
 
   BTAV_A2DP_CODEC_INDEX_SINK_MAX,
 
@@ -154,6 +155,9 @@ typedef struct {
       case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
         codec_name_str = "AAC (Sink)";
         break;
+      case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+        codec_name_str = "LDAC (Sink)";
+        break;
       case BTAV_A2DP_CODEC_INDEX_MAX:
         codec_name_str = "Unknown(CODEC_INDEX_MAX)";
         break;
index 4baebe3..2752010 100644 (file)
@@ -63,6 +63,7 @@ cc_library_static {
         "a2dp/a2dp_vendor_aptx_hd_encoder.cc",
         "a2dp/a2dp_vendor_ldac.cc",
         "a2dp/a2dp_vendor_ldac_abr.cc",
+        "a2dp/a2dp_vendor_ldac_decoder.cc",
         "a2dp/a2dp_vendor_ldac_encoder.cc",
         "avct/avct_api.cc",
         "avct/avct_bcb_act.cc",
index 67a2430..df641be 100644 (file)
@@ -402,6 +402,21 @@ int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  // NOTE: The bits per sample never changes for AAC
+  return 16;
+}
+
 int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info) {
   tA2DP_AAC_CIE aac_cie;
 
@@ -1335,6 +1350,7 @@ fail:
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
 bool A2dpCodecConfigAacBase::setPeerCodecCapabilities(
     const uint8_t* p_peer_codec_capabilities) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
index fe6da47..8df2e96 100644 (file)
@@ -129,7 +129,10 @@ A2dpCodecConfig* A2dpCodecConfig::createCodec(
       codec_config = new A2dpCodecConfigAptxHd(codec_priority);
       break;
     case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
-      codec_config = new A2dpCodecConfigLdac(codec_priority);
+      codec_config = new A2dpCodecConfigLdacSource(codec_priority);
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+      codec_config = new A2dpCodecConfigLdacSink(codec_priority);
       break;
     case BTAV_A2DP_CODEC_INDEX_MAX:
       break;
@@ -1219,6 +1222,26 @@ int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetTrackBitsPerSampleAac(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetTrackBitsPerSample(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
 int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
 
index 53f1e1a..4c48993 100644 (file)
@@ -483,6 +483,20 @@ int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  // NOTE: The bits per sample never changes for SBC
+  return 16;
+}
+
 int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info) {
   tA2DP_SBC_CIE sbc_cie;
 
@@ -855,8 +869,8 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_SBC_CIE& config_cie,
 
 A2dpCodecConfigSbcSource::A2dpCodecConfigSbcSource(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC",
-                             codec_priority, true) {
+    : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC,
+                             A2DP_CodecIndexStrSbc(), codec_priority, true) {
   // Compute the local capability
   if (a2dp_sbc_source_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1540,8 +1554,9 @@ fail:
 
 A2dpCodecConfigSbcSink::A2dpCodecConfigSbcSink(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SINK_SBC, "SBC(Sink)",
-                             codec_priority, false) {}
+    : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SINK_SBC,
+                             A2DP_CodecIndexStrSbcSink(), codec_priority,
+                             false) {}
 
 A2dpCodecConfigSbcSink::~A2dpCodecConfigSbcSink() {}
 
index 1a6dcc2..bcea13d 100644 (file)
@@ -54,24 +54,33 @@ bool A2DP_IsVendorSourceCodecValid(const uint8_t* p_codec_info) {
   return false;
 }
 
-bool A2DP_IsVendorSinkCodecValid(UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorSinkCodecValid(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Add checks based on <vendor_id, codec_id>
   // NOTE: Should be done only for local Sink codecs.
 
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_IsVendorSinkCodecValidLdac(p_codec_info);
+  }
+
   return false;
 }
 
-bool A2DP_IsVendorPeerSourceCodecValid(
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorPeerSourceCodecValid(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Add checks based on <vendor_id, codec_id>
   // NOTE: Should be done only for local Sink codecs.
 
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_IsVendorPeerSourceCodecValidLdac(p_codec_info);
+  }
+
   return false;
 }
 
@@ -101,24 +110,33 @@ bool A2DP_IsVendorPeerSinkCodecValid(const uint8_t* p_codec_info) {
   return false;
 }
 
-bool A2DP_IsVendorSinkCodecSupported(UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorSinkCodecSupported(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Add checks based on <vendor_id, codec_id>
   // NOTE: Should be done only for local Sink codecs.
 
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_IsVendorSinkCodecSupportedLdac(p_codec_info);
+  }
+
   return false;
 }
 
-bool A2DP_IsVendorPeerSourceCodecSupported(
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorPeerSourceCodecSupported(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Add checks based on <vendor_id, codec_id> and peer codec capabilities
   // NOTE: Should be done only for local Sink codecs.
 
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_IsPeerSourceCodecSupportedLdac(p_codec_info);
+  }
+
   return false;
 }
 
@@ -170,7 +188,7 @@ bool A2DP_VendorUsesRtpHeader(bool content_protection_enabled,
   return true;
 }
 
-const char* A2DP_VendorCodecName(UNUSED_ATTR const uint8_t* p_codec_info) {
+const char* A2DP_VendorCodecName(const uint8_t* p_codec_info) {
   uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
   uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
@@ -328,6 +346,32 @@ int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Check for aptX
+  if (vendor_id == A2DP_APTX_VENDOR_ID &&
+      codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+    return A2DP_VendorGetTrackBitsPerSampleAptx(p_codec_info);
+  }
+
+  // Check for aptX-HD
+  if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+      codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+    return A2DP_VendorGetTrackBitsPerSampleAptxHd(p_codec_info);
+  }
+
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_VendorGetTrackBitsPerSampleLdac(p_codec_info);
+  }
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
 int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info) {
   uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
   uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -354,14 +398,18 @@ int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info) {
   return -1;
 }
 
-int A2DP_VendorGetSinkTrackChannelType(
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Add checks based on <vendor_id, codec_id>
   // NOTE: Should be done only for local Sink codecs.
 
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_VendorGetSinkTrackChannelTypeLdac(p_codec_info);
+  }
+
   return -1;
 }
 
@@ -453,7 +501,17 @@ const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
 
 const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
     const uint8_t* p_codec_info) {
-  // We do not support vendor codecs for decoding right now.
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+  // NOTE: Should be done only for local Sink codecs.
+
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_VendorGetDecoderInterfaceLdac(p_codec_info);
+  }
+
   return NULL;
 }
 
@@ -511,10 +569,16 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndex(
 }
 
 btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndex(const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Add checks based on <vendor_id, codec_id>
+  // NOTE: Should be done only for local Sink codecs.
+
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_VendorSinkCodecIndexLdac(p_codec_info);
+  }
 
   return BTAV_A2DP_CODEC_INDEX_MAX;
 }
@@ -533,6 +597,8 @@ const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index) {
       return A2DP_VendorCodecIndexStrAptxHd();
     case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
       return A2DP_VendorCodecIndexStrLdac();
+    case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+      return A2DP_VendorCodecIndexStrLdacSink();
     // Add a switch statement for each vendor-specific codec
     case BTAV_A2DP_CODEC_INDEX_MAX:
       break;
@@ -556,6 +622,8 @@ bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
       return A2DP_VendorInitCodecConfigAptxHd(p_cfg);
     case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
       return A2DP_VendorInitCodecConfigLdac(p_cfg);
+    case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+      return A2DP_VendorInitCodecConfigLdacSink(p_cfg);
     // Add a switch statement for each vendor-specific codec
     case BTAV_A2DP_CODEC_INDEX_MAX:
       break;
index cedc95b..e3e844d 100644 (file)
@@ -313,6 +313,21 @@ int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info) {
+  tA2DP_APTX_CIE aptx_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  // NOTE: The bits per sample never changes for aptX
+  return 16;
+}
+
 int A2DP_VendorGetTrackChannelCountAptx(const uint8_t* p_codec_info) {
   tA2DP_APTX_CIE aptx_cie;
 
@@ -428,8 +443,8 @@ bool A2DP_VendorInitCodecConfigAptx(AvdtpSepConfig* p_cfg) {
 
 A2dpCodecConfigAptx::A2dpCodecConfigAptx(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX",
-                      codec_priority) {
+    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX,
+                      A2DP_VendorCodecIndexStrAptx(), codec_priority) {
   // Compute the local capability
   if (a2dp_aptx_source_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
index 85ec398..9e19d5f 100644 (file)
@@ -328,6 +328,22 @@ int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info) {
+  tA2DP_APTX_HD_CIE aptx_hd_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  // NOTE: The bits per sample never changes for aptX-HD
+  return 24;
+}
+
 int A2DP_VendorGetTrackChannelCountAptxHd(const uint8_t* p_codec_info) {
   tA2DP_APTX_HD_CIE aptx_hd_cie;
 
@@ -445,8 +461,8 @@ bool A2DP_VendorInitCodecConfigAptxHd(AvdtpSepConfig* p_cfg) {
 
 A2dpCodecConfigAptxHd::A2dpCodecConfigAptxHd(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD",
-                      codec_priority) {
+    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
+                      A2DP_VendorCodecIndexStrAptxHd(), codec_priority) {
   // Compute the local capability
   if (a2dp_aptx_hd_source_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
index 2438be9..4949e74 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <base/logging.h>
 #include "a2dp_vendor.h"
+#include "a2dp_vendor_ldac_decoder.h"
 #include "a2dp_vendor_ldac_encoder.h"
 #include "bt_utils.h"
 #include "btif_av_co.h"
@@ -60,6 +61,19 @@ static const tA2DP_LDAC_CIE a2dp_ldac_source_caps = {
     (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 | BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
      BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32)};
 
+/* LDAC Sink codec capabilities */
+static const tA2DP_LDAC_CIE a2dp_ldac_sink_caps = {
+    A2DP_LDAC_VENDOR_ID,  // vendorId
+    A2DP_LDAC_CODEC_ID,   // codecId
+    // sampleRate
+    (A2DP_LDAC_SAMPLING_FREQ_44100 | A2DP_LDAC_SAMPLING_FREQ_48000 |
+     A2DP_LDAC_SAMPLING_FREQ_88200 | A2DP_LDAC_SAMPLING_FREQ_96000),
+    // channelMode
+    (A2DP_LDAC_CHANNEL_MODE_DUAL | A2DP_LDAC_CHANNEL_MODE_STEREO),
+    // bits_per_sample
+    (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 | BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+     BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32)};
+
 /* Default LDAC codec configuration */
 static const tA2DP_LDAC_CIE a2dp_ldac_default_config = {
     A2DP_LDAC_VENDOR_ID,                // vendorId
@@ -78,6 +92,12 @@ static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_ldac = {
     a2dp_vendor_ldac_send_frames,
     a2dp_vendor_ldac_set_transmit_queue_length};
 
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_ldac = {
+    a2dp_vendor_ldac_decoder_init,
+    a2dp_vendor_ldac_decoder_cleanup,
+    a2dp_vendor_ldac_decoder_decode_packet,
+};
+
 UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityLdac(
     const tA2DP_LDAC_CIE* p_cap, const uint8_t* p_codec_info,
     bool is_peer_codec_info);
@@ -208,6 +228,22 @@ bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info) {
          (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
 }
 
+bool A2DP_IsVendorSinkCodecValidLdac(const uint8_t* p_codec_info) {
+  tA2DP_LDAC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSourceCodecValidLdac(const uint8_t* p_codec_info) {
+  tA2DP_LDAC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
 bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info) {
   tA2DP_LDAC_CIE cfg_cie;
 
@@ -216,6 +252,15 @@ bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info) {
          (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
 }
 
+bool A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityLdac(&a2dp_ldac_sink_caps, p_codec_info,
+                                             false) == A2DP_SUCCESS;
+}
+bool A2DP_IsPeerSourceCodecSupportedLdac(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityLdac(&a2dp_ldac_sink_caps, p_codec_info,
+                                             true) == A2DP_SUCCESS;
+}
+
 // Checks whether A2DP LDAC codec configuration matches with a device's codec
 // capabilities. |p_cap| is the LDAC codec configuration. |p_codec_info| is
 // the device's codec capabilities.
@@ -370,6 +415,35 @@ int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) {
+  tA2DP_LDAC_CIE ldac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+#if 1
+  return 32;
+#else
+  // TODO : Implement proc to care about bit per sample in A2DP_ParseInfoLdac()
+
+  switch (ldac_cie.bits_per_sample) {
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+      return 16;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      return 24;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      return 32;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+      return -1;
+  }
+#endif
+}
+
 int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) {
   tA2DP_LDAC_CIE ldac_cie;
 
@@ -393,6 +467,29 @@ int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) {
   return -1;
 }
 
+int A2DP_VendorGetSinkTrackChannelTypeLdac(const uint8_t* p_codec_info) {
+  tA2DP_LDAC_CIE ldac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (ldac_cie.channelMode) {
+    case A2DP_LDAC_CHANNEL_MODE_MONO:
+      return 1;
+    case A2DP_LDAC_CHANNEL_MODE_DUAL:
+      return 3;
+    case A2DP_LDAC_CHANNEL_MODE_STEREO:
+      return 3;
+  }
+
+  return -1;
+}
+
 int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info) {
   tA2DP_LDAC_CIE ldac_cie;
 
@@ -492,6 +589,13 @@ const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
   return &a2dp_encoder_interface_ldac;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsVendorSinkCodecValidLdac(p_codec_info)) return NULL;
+
+  return &a2dp_decoder_interface_ldac;
+}
+
 bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info) {
   tA2DP_LDAC_CIE cfg_cie;
 
@@ -507,8 +611,15 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(
   return BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC;
 }
 
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return BTAV_A2DP_CODEC_INDEX_SINK_LDAC;
+}
+
 const char* A2DP_VendorCodecIndexStrLdac(void) { return "LDAC"; }
 
+const char* A2DP_VendorCodecIndexStrLdacSink(void) { return "LDAC SINK"; }
+
 bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) {
   if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_source_caps,
                          p_cfg->codec_info) != A2DP_SUCCESS) {
@@ -526,6 +637,11 @@ bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) {
   return true;
 }
 
+bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg) {
+  return A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_sink_caps,
+                            p_cfg->codec_info) == A2DP_SUCCESS;
+}
+
 UNUSED_ATTR static void build_codec_config(const tA2DP_LDAC_CIE& config_cie,
                                            btav_a2dp_codec_config_t* result) {
   if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100)
@@ -551,10 +667,11 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_LDAC_CIE& config_cie,
   }
 }
 
-A2dpCodecConfigLdac::A2dpCodecConfigLdac(
+A2dpCodecConfigLdacSource::A2dpCodecConfigLdacSource(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC",
-                      codec_priority) {
+    : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC,
+                              A2DP_VendorCodecIndexStrLdac(), codec_priority,
+                              true) {
   // Compute the local capability
   if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -587,9 +704,9 @@ A2dpCodecConfigLdac::A2dpCodecConfigLdac(
   }
 }
 
-A2dpCodecConfigLdac::~A2dpCodecConfigLdac() {}
+A2dpCodecConfigLdacSource::~A2dpCodecConfigLdacSource() {}
 
-bool A2dpCodecConfigLdac::init() {
+bool A2dpCodecConfigLdacSource::init() {
   if (!isValid()) return false;
 
   // Load the encoder
@@ -601,7 +718,7 @@ bool A2dpCodecConfigLdac::init() {
   return true;
 }
 
-bool A2dpCodecConfigLdac::useRtpHeaderMarkerBit() const { return false; }
+bool A2dpCodecConfigLdacSource::useRtpHeaderMarkerBit() const { return false; }
 
 //
 // Selects the best sample rate from |sampleRate|.
@@ -831,15 +948,17 @@ static bool select_audio_channel_mode(
   return false;
 }
 
-bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
-                                         bool is_capability,
-                                         uint8_t* p_result_codec_config) {
+bool A2dpCodecConfigLdacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
+                                             bool is_capability,
+                                             uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
   tA2DP_LDAC_CIE peer_info_cie;
   tA2DP_LDAC_CIE result_config_cie;
   uint8_t channelMode;
   uint8_t sampleRate;
   btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+  const tA2DP_LDAC_CIE* p_a2dp_ldac_caps =
+      (is_source_) ? &a2dp_ldac_source_caps : &a2dp_ldac_sink_caps;
 
   // Save the internal state
   btav_a2dp_codec_config_t saved_codec_config = codec_config_;
@@ -869,13 +988,13 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_ldac_source_caps.vendorId;
-  result_config_cie.codecId = a2dp_ldac_source_caps.codecId;
+  result_config_cie.vendorId = p_a2dp_ldac_caps->vendorId;
+  result_config_cie.codecId = p_a2dp_ldac_caps->codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
+  sampleRate = p_a2dp_ldac_caps->sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -995,8 +1114,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
     LOG_ERROR(LOG_TAG,
               "%s: cannot match sample frequency: local caps = 0x%x "
               "peer info = 0x%x",
-              __func__, a2dp_ldac_source_caps.sampleRate,
-              peer_info_cie.sampleRate);
+              __func__, p_a2dp_ldac_caps->sampleRate, peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -1005,7 +1123,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   //
   // NOTE: this information is NOT included in the LDAC A2DP codec description
   // that is sent OTA.
-  bits_per_sample = a2dp_ldac_source_caps.bits_per_sample;
+  bits_per_sample = p_a2dp_ldac_caps->bits_per_sample;
   codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
   switch (codec_user_config_.bits_per_sample) {
     case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
@@ -1040,7 +1158,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_ldac_source_caps.bits_per_sample;
+        p_a2dp_ldac_caps->bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -1050,7 +1168,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - the the codec audio config
     if (select_audio_bits_per_sample(&codec_audio_config_,
-                                     a2dp_ldac_source_caps.bits_per_sample,
+                                     p_a2dp_ldac_caps->bits_per_sample,
                                      &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1062,7 +1180,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
     }
 
     // No user preference - use the best match
-    if (select_best_bits_per_sample(a2dp_ldac_source_caps.bits_per_sample,
+    if (select_best_bits_per_sample(p_a2dp_ldac_caps->bits_per_sample,
                                     &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1079,7 +1197,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   //
   // Select the channel mode
   //
-  channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
+  channelMode = p_a2dp_ldac_caps->channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -1158,7 +1276,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
     LOG_ERROR(LOG_TAG,
               "%s: cannot match channel mode: local caps = 0x%x "
               "peer info = 0x%x",
-              __func__, a2dp_ldac_source_caps.channelMode,
+              __func__, p_a2dp_ldac_caps->channelMode,
               peer_info_cie.channelMode);
     goto fail;
   }
@@ -1210,12 +1328,14 @@ fail:
   return false;
 }
 
-bool A2dpCodecConfigLdac::setPeerCodecCapabilities(
+bool A2dpCodecConfigLdacBase::setPeerCodecCapabilities(
     const uint8_t* p_peer_codec_capabilities) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
   tA2DP_LDAC_CIE peer_info_cie;
   uint8_t channelMode;
   uint8_t sampleRate;
+  const tA2DP_LDAC_CIE* p_a2dp_ldac_caps =
+      (is_source_) ? &a2dp_ldac_source_caps : &a2dp_ldac_sink_caps;
 
   // Save the internal state
   btav_a2dp_codec_config_t saved_codec_selectable_capability =
@@ -1233,7 +1353,7 @@ bool A2dpCodecConfigLdac::setPeerCodecCapabilities(
   }
 
   // Compute the selectable capability - sample rate
-  sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
+  sampleRate = p_a2dp_ldac_caps->sampleRate & peer_info_cie.sampleRate;
   if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
     codec_selectable_capability_.sample_rate |=
         BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1261,10 +1381,10 @@ bool A2dpCodecConfigLdac::setPeerCodecCapabilities(
 
   // Compute the selectable capability - bits per sample
   codec_selectable_capability_.bits_per_sample =
-      a2dp_ldac_source_caps.bits_per_sample;
+      p_a2dp_ldac_caps->bits_per_sample;
 
   // Compute the selectable capability - channel mode
-  channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
+  channelMode = p_a2dp_ldac_caps->channelMode & peer_info_cie.channelMode;
   if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
     codec_selectable_capability_.channel_mode |=
         BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
@@ -1290,3 +1410,46 @@ fail:
          sizeof(ota_codec_peer_capability_));
   return false;
 }
+
+A2dpCodecConfigLdacSink::A2dpCodecConfigLdacSink(
+    btav_a2dp_codec_priority_t codec_priority)
+    : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SINK_LDAC,
+                              A2DP_VendorCodecIndexStrLdacSink(),
+                              codec_priority, false) {}
+
+A2dpCodecConfigLdacSink::~A2dpCodecConfigLdacSink() {}
+
+bool A2dpCodecConfigLdacSink::init() {
+  if (!isValid()) return false;
+
+  // Load the decoder
+  if (!A2DP_VendorLoadDecoderLdac()) {
+    LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+    return false;
+  }
+
+  return true;
+}
+
+uint64_t A2dpCodecConfigLdacSink::encoderIntervalMs() const {
+  // TODO: This method applies only to Source codecs
+  return 0;
+}
+
+int A2dpCodecConfigLdacSink::getEffectiveMtu() const {
+  // TODO: This method applies only to Source codecs
+  return 0;
+}
+
+bool A2dpCodecConfigLdacSink::useRtpHeaderMarkerBit() const {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
+
+bool A2dpCodecConfigLdacSink::updateEncoderUserConfig(
+    UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+    UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+    UNUSED_ATTR bool* p_config_updated) {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
diff --git a/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/stack/a2dp/a2dp_vendor_ldac_decoder.cc
new file mode 100644 (file)
index 0000000..444af34
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "a2dp_vendor_ldac_decoder"
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include "a2dp_vendor_ldac_decoder.h"
+
+#ifndef OS_GENERIC
+#include <cutils/trace.h>
+#endif
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ldacBT.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_ldac.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Decoder for LDAC Source Codec
+//
+
+//
+// The LDAC decoder shared library, and the functions to use
+//
+static const char* LDAC_DECODER_LIB_NAME = "libldacBT_dec.so";
+static void* ldac_decoder_lib_handle = NULL;
+
+static const char* LDAC_GET_HANDLE_NAME = "ldacBT_get_handle";
+typedef HANDLE_LDAC_BT (*tLDAC_GET_HANDLE)(void);
+
+static const char* LDAC_FREE_HANDLE_NAME = "ldacBT_free_handle";
+typedef void (*tLDAC_FREE_HANDLE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_CLOSE_HANDLE_NAME = "ldacBT_close_handle";
+typedef void (*tLDAC_CLOSE_HANDLE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_VERSION_NAME = "ldacBT_get_version";
+typedef int (*tLDAC_GET_VERSION)(void);
+
+static const char* LDAC_GET_BITRATE_NAME = "ldacBT_get_bitrate";
+typedef int (*tLDAC_GET_BITRATE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_SAMPLING_FREQ_NAME = "ldacBT_get_sampling_freq";
+typedef int (*tLDAC_GET_SAMPLING_FREQ)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_INIT_HANDLE_DECODE_NAME = "ldacBT_init_handle_decode";
+typedef int (*tLDAC_INIT_HANDLE_DECODE)(HANDLE_LDAC_BT hLdacParam, int cm,
+                                        int sf, int var0, int var1, int var2);
+
+static const char* LDAC_DECODE_NAME = "ldacBT_decode";
+typedef int (*tLDAC_DECODE)(HANDLE_LDAC_BT hLdacBt, unsigned char* p_bs,
+                            unsigned char* p_pcm, LDACBT_SMPL_FMT_T fmt,
+                            int bs_bytes, int* used_bytes, int* wrote_bytes);
+
+static const char* LDAC_GET_ERROR_CODE_NAME = "ldacBT_get_error_code";
+typedef int (*tLDAC_GET_ERROR_CODE)(HANDLE_LDAC_BT hLdacParam);
+
+static tLDAC_GET_HANDLE ldac_get_handle_func;
+static tLDAC_FREE_HANDLE ldac_free_handle_func;
+static tLDAC_CLOSE_HANDLE ldac_close_handle_func;
+static tLDAC_GET_VERSION ldac_get_version_func;
+static tLDAC_GET_BITRATE ldac_get_bitrate_func;
+static tLDAC_GET_SAMPLING_FREQ ldac_get_sampling_freq_func;
+static tLDAC_INIT_HANDLE_DECODE ldac_init_handle_decode_func;
+static tLDAC_DECODE ldac_decode_func;
+static tLDAC_GET_ERROR_CODE ldac_get_error_code_func;
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN + 1)
+#else
+#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN)
+#endif
+
+typedef struct {
+  uint32_t sample_rate;
+  uint8_t channel_mode;
+  uint8_t bits_per_sample;
+  int pcm_wlength;
+  LDACBT_SMPL_FMT_T pcm_fmt;
+} tA2DP_LDAC_DECODER_PARAMS;
+
+typedef struct {
+  bool use_SCMS_T;
+  bool is_peer_edr;          // True if the peer device supports EDR
+  bool peer_supports_3mbps;  // True if the peer device supports 3Mbps EDR
+  uint16_t peer_mtu;         // MTU of the A2DP peer
+  uint32_t timestamp;        // Timestamp for the A2DP frames
+
+  HANDLE_LDAC_BT ldac_handle;
+  bool has_ldac_handle;  // True if ldac_handle is valid
+  unsigned char* decode_buf;
+  decoded_data_callback_t decode_callback;
+} tA2DP_LDAC_DECODER_CB;
+
+static tA2DP_LDAC_DECODER_CB a2dp_ldac_decoder_cb;
+
+static void* load_func(const char* func_name) {
+  void* func_ptr = dlsym(ldac_decoder_lib_handle, func_name);
+  if (func_ptr == NULL) {
+    LOG_ERROR(LOG_TAG,
+              "%s: cannot find function '%s' in the decoder library: %s",
+              __func__, func_name, dlerror());
+    A2DP_VendorUnloadDecoderLdac();
+    return NULL;
+  }
+  return func_ptr;
+}
+
+bool A2DP_VendorLoadDecoderLdac(void) {
+  if (ldac_decoder_lib_handle != NULL) return true;  // Already loaded
+
+  // Initialize the control block
+  memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+
+  // Open the decoder library
+  ldac_decoder_lib_handle = dlopen(LDAC_DECODER_LIB_NAME, RTLD_NOW);
+  if (ldac_decoder_lib_handle == NULL) {
+    LOG_ERROR(LOG_TAG, "%s: cannot open LDAC decoder library %s: %s", __func__,
+              LDAC_DECODER_LIB_NAME, dlerror());
+    return false;
+  }
+
+  // Load all functions
+  ldac_get_handle_func = (tLDAC_GET_HANDLE)load_func(LDAC_GET_HANDLE_NAME);
+  if (ldac_get_handle_func == NULL) return false;
+  ldac_free_handle_func = (tLDAC_FREE_HANDLE)load_func(LDAC_FREE_HANDLE_NAME);
+  if (ldac_free_handle_func == NULL) return false;
+  ldac_close_handle_func =
+      (tLDAC_CLOSE_HANDLE)load_func(LDAC_CLOSE_HANDLE_NAME);
+  if (ldac_close_handle_func == NULL) return false;
+  ldac_get_version_func = (tLDAC_GET_VERSION)load_func(LDAC_GET_VERSION_NAME);
+  if (ldac_get_version_func == NULL) return false;
+  ldac_get_bitrate_func = (tLDAC_GET_BITRATE)load_func(LDAC_GET_BITRATE_NAME);
+  if (ldac_get_bitrate_func == NULL) return false;
+  ldac_get_sampling_freq_func =
+      (tLDAC_GET_SAMPLING_FREQ)load_func(LDAC_GET_SAMPLING_FREQ_NAME);
+  if (ldac_get_sampling_freq_func == NULL) return false;
+  ldac_init_handle_decode_func =
+      (tLDAC_INIT_HANDLE_DECODE)load_func(LDAC_INIT_HANDLE_DECODE_NAME);
+  if (ldac_init_handle_decode_func == NULL) return false;
+  ldac_decode_func = (tLDAC_DECODE)load_func(LDAC_DECODE_NAME);
+  if (ldac_decode_func == NULL) return false;
+  ldac_get_error_code_func =
+      (tLDAC_GET_ERROR_CODE)load_func(LDAC_GET_ERROR_CODE_NAME);
+  if (ldac_get_error_code_func == NULL) return false;
+
+  return true;
+}
+
+void A2DP_VendorUnloadDecoderLdac(void) {
+  // Cleanup any LDAC-related state
+  if (a2dp_ldac_decoder_cb.has_ldac_handle && ldac_free_handle_func != NULL)
+    ldac_free_handle_func(a2dp_ldac_decoder_cb.ldac_handle);
+  memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+
+  ldac_get_handle_func = NULL;
+  ldac_free_handle_func = NULL;
+  ldac_close_handle_func = NULL;
+  ldac_get_version_func = NULL;
+  ldac_get_bitrate_func = NULL;
+  ldac_get_sampling_freq_func = NULL;
+  ldac_init_handle_decode_func = NULL;
+  ldac_decode_func = NULL;
+  ldac_get_error_code_func = NULL;
+
+  if (ldac_decoder_lib_handle != NULL) {
+    dlclose(ldac_decoder_lib_handle);
+    ldac_decoder_lib_handle = NULL;
+  }
+}
+
+bool a2dp_vendor_ldac_decoder_init(decoded_data_callback_t decode_callback) {
+  if (a2dp_ldac_decoder_cb.has_ldac_handle)
+    ldac_free_handle_func(a2dp_ldac_decoder_cb.ldac_handle);
+  memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+
+  a2dp_vendor_ldac_decoder_cleanup();
+
+  a2dp_ldac_decoder_cb.ldac_handle = ldac_get_handle_func();
+  a2dp_ldac_decoder_cb.has_ldac_handle = true;
+  a2dp_ldac_decoder_cb.decode_buf = static_cast<unsigned char*>(
+      osi_malloc(sizeof(a2dp_ldac_decoder_cb.decode_buf[0]) * LDACBT_MAX_LSU *
+                 LDAC_PRCNCH * sizeof(int)));
+  a2dp_ldac_decoder_cb.decode_callback = decode_callback;
+
+  // initialize
+  ldac_init_handle_decode_func(a2dp_ldac_decoder_cb.ldac_handle,
+                               LDACBT_CHANNEL_MODE_STEREO, 96000, 0, 0, 0);
+  return true;
+}
+
+void a2dp_vendor_ldac_decoder_cleanup(void) {
+  if (a2dp_ldac_decoder_cb.has_ldac_handle)
+    ldac_free_handle_func(a2dp_ldac_decoder_cb.ldac_handle);
+  memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+}
+
+bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf) {
+  unsigned char* pBuffer =
+      reinterpret_cast<unsigned char*>(p_buf->data + p_buf->offset);
+  //  unsigned int bufferSize = p_buf->len;
+  unsigned int bytesValid = p_buf->len;
+  int err;
+  LDACBT_SMPL_FMT_T fmt;
+  int bs_bytes, used_bytes, wrote_bytes, frame_number;
+
+  fmt = LDACBT_SMPL_FMT_S32;
+  frame_number = (int)pBuffer[0];
+  pBuffer++;
+  bs_bytes = (int)bytesValid - 1;
+  bytesValid -= 1;
+  LOG_VERBOSE(LOG_TAG, "%s:INPUT size : %d, frame : %d", __func__, bs_bytes,
+              frame_number);
+
+  while (bytesValid > 0) {
+#if 0
+    err = ldacDecoder_Fill(a2dp_ldac_decoder_cb.ldac_handle,
+                               &pBuffer, &bufferSize, &bytesValid);
+    if (err != LDACBT_ERR_NONE) {
+      LOG_ERROR(LOG_TAG, "%s: ldacDecoder_Fill failed: 0x%x", __func__,
+                static_cast<unsigned>(err));
+      return false;
+    }
+#endif
+    while (true) {
+      // Todo : implement LDAC Buffer Control Operation instead of
+      // ldac_decode_func().
+      err = ldac_decode_func(a2dp_ldac_decoder_cb.ldac_handle, pBuffer,
+                             a2dp_ldac_decoder_cb.decode_buf, fmt, bs_bytes,
+                             &used_bytes, &wrote_bytes);
+      //      if (err == LDAC_DEC_NOT_ENOUGH_FRAMES) {
+      //        break;
+      //      }
+      if (LDACBT_ERROR(err)) {
+        err = ldac_get_error_code_func(a2dp_ldac_decoder_cb.ldac_handle);
+        LOG_ERROR(LOG_TAG, "%s: ldacDecoder_DecodeFrame failed: %d:%d:%d",
+                  __func__, LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err),
+                  LDACBT_BLOCK_ERR(err));
+        if (LDACBT_FATAL(err)) {
+          break;
+        }
+      }
+
+      if (wrote_bytes > 0) {
+        size_t frame_len = (size_t)wrote_bytes;
+        a2dp_ldac_decoder_cb.decode_callback(
+            reinterpret_cast<uint8_t*>(a2dp_ldac_decoder_cb.decode_buf),
+            frame_len);
+      }
+      pBuffer += used_bytes;
+      bs_bytes -= used_bytes;
+      if (bs_bytes <= 1) {
+        bytesValid = 0;
+        break;
+      }
+    }
+  }
+
+  return true;
+}
index bd1653b..ca6c2fc 100644 (file)
@@ -315,7 +315,7 @@ void a2dp_vendor_ldac_encoder_init(
                                   &restart_output, &config_updated);
 }
 
-bool A2dpCodecConfigLdac::updateEncoderUserConfig(
+bool A2dpCodecConfigLdacSource::updateEncoderUserConfig(
     const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
     bool* p_restart_output, bool* p_config_updated) {
   a2dp_ldac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
@@ -761,15 +761,15 @@ void a2dp_vendor_ldac_set_transmit_queue_length(size_t transmit_queue_length) {
   a2dp_ldac_encoder_cb.TxQueueLength = transmit_queue_length;
 }
 
-uint64_t A2dpCodecConfigLdac::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigLdacSource::encoderIntervalMs() const {
   return a2dp_vendor_ldac_get_encoder_interval_ms();
 }
 
-int A2dpCodecConfigLdac::getEffectiveMtu() const {
+int A2dpCodecConfigLdacSource::getEffectiveMtu() const {
   return a2dp_ldac_encoder_cb.TxAaMtuSize;
 }
 
-void A2dpCodecConfigLdac::debug_codec_dump(int fd) {
+void A2dpCodecConfigLdacSource::debug_codec_dump(int fd) {
   a2dp_ldac_encoder_stats_t* stats = &a2dp_ldac_encoder_cb.stats;
   tA2DP_LDAC_ENCODER_PARAMS* p_encoder_params =
       &a2dp_ldac_encoder_cb.ldac_encoder_params;
index 49b1495..94ba730 100644 (file)
@@ -147,6 +147,12 @@ bool A2DP_CodecEqualsAac(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info);
+
 // Gets the channel count for the A2DP AAC codec.
 // |p_codec_info| is a pointer to the AAC codec_info to decode.
 // Returns the channel count on success, or -1 if |p_codec_info|
index 6a34776..45cbf9c 100644 (file)
@@ -642,6 +642,12 @@ bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSample(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|
index 3a03a55..5f7b0aa 100644 (file)
@@ -143,6 +143,12 @@ bool A2DP_CodecEqualsSbc(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info);
+
 // Gets the channel count for the A2DP SBC codec.
 // |p_codec_info| is a pointer to the SBC codec_info to decode.
 // Returns the channel count on success, or -1 if |p_codec_info|
index 0b5ba7c..117e25c 100644 (file)
@@ -117,6 +117,12 @@ bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info);
+
 // Gets the channel count for the A2DP vendor-specific codec.
 // |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
 // Returns the channel count on success, or -1 if |p_codec_info|
index a2b154a..bf4ebf0 100644 (file)
@@ -91,6 +91,12 @@ bool A2DP_VendorCodecEqualsAptx(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP aptX codec.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info);
+
 // Gets the track bitrate value for the A2DP aptX codec.
 // |p_codec_info| is a pointer to the aptX codec_info to decode.
 // Returns the track sample rate on success, or -1 if |p_codec_info|
index c537330..8efe8c6 100644 (file)
@@ -91,6 +91,12 @@ bool A2DP_VendorCodecEqualsAptxHd(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP aptX-HD codec.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info);
+
 // Gets the track bitrate value for the A2DP aptX-HD codec.
 // |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
 // Returns the track sample rate on success, or -1 if |p_codec_info|
index d3e206c..9b1958f 100644 (file)
 #include "a2dp_vendor_ldac_constants.h"
 #include "avdt_api.h"
 
-class A2dpCodecConfigLdac : public A2dpCodecConfig {
+class A2dpCodecConfigLdacBase : public A2dpCodecConfig {
+ protected:
+  A2dpCodecConfigLdacBase(btav_a2dp_codec_index_t codec_index,
+                          const std::string& name,
+                          btav_a2dp_codec_priority_t codec_priority,
+                          bool is_source)
+      : A2dpCodecConfig(codec_index, name, codec_priority),
+        is_source_(is_source) {}
+  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+                      uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
+
+ private:
+  bool is_source_;  // True if local is Source
+};
+
+class A2dpCodecConfigLdacSource : public A2dpCodecConfigLdacBase {
  public:
-  A2dpCodecConfigLdac(btav_a2dp_codec_priority_t codec_priority);
-  virtual ~A2dpCodecConfigLdac();
+  A2dpCodecConfigLdacSource(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigLdacSource();
 
   bool init() override;
   uint64_t encoderIntervalMs() const override;
   int getEffectiveMtu() const override;
-  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
-                      uint8_t* p_result_codec_config) override;
-  bool setPeerCodecCapabilities(
-      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -47,6 +60,23 @@ class A2dpCodecConfigLdac : public A2dpCodecConfig {
   void debug_codec_dump(int fd) override;
 };
 
+class A2dpCodecConfigLdacSink : public A2dpCodecConfigLdacBase {
+ public:
+  A2dpCodecConfigLdacSink(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigLdacSink();
+
+  bool init() override;
+  uint64_t encoderIntervalMs() const override;
+  int getEffectiveMtu() const override;
+
+ private:
+  bool useRtpHeaderMarkerBit() const override;
+  bool updateEncoderUserConfig(
+      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+      bool* p_restart_input, bool* p_restart_output,
+      bool* p_config_updated) override;
+};
+
 // Checks whether the codec capabilities contain a valid A2DP LDAC Source
 // codec.
 // NOTE: only codecs that are implemented are considered valid.
@@ -54,6 +84,13 @@ class A2dpCodecConfigLdac : public A2dpCodecConfig {
 // codec, otherwise false.
 bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info);
 
+// Checks whether the codec capabilities contain a valid A2DP LDAC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid LDAC
+// codec, otherwise false.
+bool A2DP_IsVendorSinkCodecValidLdac(const uint8_t* p_codec_info);
+
 // Checks whether the codec capabilities contain a valid peer A2DP LDAC Sink
 // codec.
 // NOTE: only codecs that are implemented are considered valid.
@@ -61,6 +98,26 @@ bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info);
 // codec, otherwise false.
 bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info);
 
+// Checks whether the codec capabilities contain a valid peer A2DP LDAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid LDAC
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecValidLdac(const uint8_t* p_codec_info);
+
+// Checks whether A2DP LDAC Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP LDAC Sink codec is supported, otherwise false.
+bool A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP LDAC 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 LDAC Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedLdac(const uint8_t* p_codec_info);
+
 // 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.
@@ -91,6 +148,12 @@ bool A2DP_VendorCodecEqualsLdac(const uint8_t* p_codec_info_a,
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info);
 
+// Gets the track bits per sample value for the A2DP LDAC codec.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info);
+
 // Gets the track bitrate value for the A2DP LDAC codec.
 // |p_codec_info| is a pointer to the LDAC codec_info to decode.
 // Returns the track sample rate on success, or -1 if |p_codec_info|
@@ -103,6 +166,13 @@ int A2DP_VendorGetBitRateLdac(const uint8_t* p_codec_info);
 // contains invalid codec information.
 int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info);
 
+// Gets the channel type for the A2DP LDAC codec.
+// 1 for mono, or 3 for dual channel/stereo.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkTrackChannelTypeLdac(const uint8_t* p_codec_info);
+
 // Gets the channel mode code for the A2DP LDAC codec.
 // The actual value is codec-specific - see |A2DP_LDAC_CHANNEL_MODE_*|.
 // |p_codec_info| is a pointer to the LDAC codec_info to decode.
@@ -140,6 +210,14 @@ std::string A2DP_VendorCodecInfoStringLdac(const uint8_t* p_codec_info);
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
     const uint8_t* p_codec_info);
 
+// Gets the current A2DP LDAC decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP LDAC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP LDAC codec, based on local support and Bluetooth
 // specification.
 // |p_codec_info| contains the codec information to adjust.
@@ -152,11 +230,24 @@ bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info);
 btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(
     const uint8_t* p_codec_info);
 
+// Gets the A2DP LDAC Sink 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_VendorSinkCodecIndexLdac(
+    const uint8_t* p_codec_info);
+
 // Gets the A2DP LDAC Source codec name.
 const char* A2DP_VendorCodecIndexStrLdac(void);
 
+// Gets the A2DP LDAC Sink codec name.
+const char* A2DP_VendorCodecIndexStrLdacSink(void);
+
 // Initializes A2DP LDAC Source codec information into |AvdtpSepConfig|
 // configuration entry pointed by |p_cfg|.
 bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg);
 
+// Initializes A2DP LDAC Sink codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg);
+
 #endif  // A2DP_VENDOR_LDAC_H
diff --git a/stack/include/a2dp_vendor_ldac_decoder.h b/stack/include/a2dp_vendor_ldac_decoder.h
new file mode 100644 (file)
index 0000000..2a05baa
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.
+ */
+
+//
+// Interface to the A2DP LDAC Decoder
+//
+
+#ifndef A2DP_VENDOR_LDAC_DECODER_H
+#define A2DP_VENDOR_LDAC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP LDAC decoder.
+// Return true on success, otherwise false.
+bool A2DP_VendorLoadDecoderLdac(void);
+
+// Unloads the A2DP LDAC decoder.
+void A2DP_VendorUnloadDecoderLdac(void);
+
+// Initialize the A2DP LDAC decoder.
+bool a2dp_vendor_ldac_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP LDAC decoder.
+void a2dp_vendor_ldac_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into
+// |a2dp_vendor_ldac_decoder_init| if decoded frames are available.
+bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif  // A2DP_VENDOR_LDAC_DECODER_H
index 63dfb28..fecb3ca 100644 (file)
@@ -173,6 +173,7 @@ const uint8_t codec_info_non_a2dp_dummy[AVDT_CODEC_SIZE] = {
 static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
 static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so";
 static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so";
+static const char* LDAC_DECODER_LIB_NAME = "libldacBT_dec.so";
 
 static bool has_shared_library(const char* name) {
   void* lib_handle = dlopen(name, RTLD_NOW);
@@ -223,6 +224,11 @@ class StackA2dpTest : public ::testing::Test {
         case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
           supported = true;
           break;
+        case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+          // Codec LDAC is supported only if the device has the corresponding
+          // shared library installed.
+          supported = has_shared_library(LDAC_DECODER_LIB_NAME);
+          break;
         case BTAV_A2DP_CODEC_INDEX_MAX:
           // Needed to avoid using "default:" case so we can capture when
           // a new codec is added, and it can be included here.