hal-audio-aptx.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // SPDX-License-Identifier: Apache-2.0
  2. /*
  3. * Copyright (C) 2014 Tieto Poland
  4. *
  5. */
  6. #define _GNU_SOURCE
  7. #include <stdint.h>
  8. #include <stdbool.h>
  9. #include <string.h>
  10. #include <malloc.h>
  11. #include <dlfcn.h>
  12. #include "audio-msg.h"
  13. #include "hal-audio.h"
  14. #include "hal-log.h"
  15. #include "profiles/audio/a2dp-codecs.h"
  16. #define APTX_SO_NAME "libbt-aptx.so"
  17. struct aptx_data {
  18. a2dp_aptx_t aptx;
  19. void *enc;
  20. };
  21. static const a2dp_aptx_t aptx_presets[] = {
  22. {
  23. .info =
  24. A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
  25. .frequency = APTX_SAMPLING_FREQ_44100 |
  26. APTX_SAMPLING_FREQ_48000,
  27. .channel_mode = APTX_CHANNEL_MODE_STEREO,
  28. },
  29. {
  30. .info =
  31. A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
  32. .frequency = APTX_SAMPLING_FREQ_48000,
  33. .channel_mode = APTX_CHANNEL_MODE_STEREO,
  34. },
  35. {
  36. .info =
  37. A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
  38. .frequency = APTX_SAMPLING_FREQ_44100,
  39. .channel_mode = APTX_CHANNEL_MODE_STEREO,
  40. },
  41. };
  42. static void *aptx_handle;
  43. static int aptx_btencsize;
  44. static int (*aptx_init)(void *, short);
  45. static int (*aptx_encode)(void *, void *, void *, void *);
  46. static bool aptx_load(void)
  47. {
  48. const char * (*aptx_version)(void);
  49. const char * (*aptx_build)(void);
  50. int (*aptx_sizeofenc)(void);
  51. aptx_handle = dlopen(APTX_SO_NAME, RTLD_LAZY);
  52. if (!aptx_handle) {
  53. error("APTX: failed to open library %s (%s)", APTX_SO_NAME,
  54. dlerror());
  55. return false;
  56. }
  57. aptx_version = dlsym(aptx_handle, "aptxbtenc_version");
  58. aptx_build = dlsym(aptx_handle, "aptxbtenc_build");
  59. if (aptx_version && aptx_build)
  60. info("APTX: using library version %s build %s", aptx_version(),
  61. aptx_build());
  62. else
  63. warn("APTX: cannot retrieve library version");
  64. aptx_sizeofenc = dlsym(aptx_handle, "SizeofAptxbtenc");
  65. aptx_init = dlsym(aptx_handle, "aptxbtenc_init");
  66. aptx_encode = dlsym(aptx_handle, "aptxbtenc_encodestereo");
  67. if (!aptx_sizeofenc || !aptx_init || !aptx_encode) {
  68. error("APTX: failed initialize library");
  69. dlclose(aptx_handle);
  70. aptx_handle = NULL;
  71. return false;
  72. }
  73. aptx_btencsize = aptx_sizeofenc();
  74. info("APTX: codec library initialized (size=%d)", aptx_btencsize);
  75. return true;
  76. }
  77. static void aptx_unload(void)
  78. {
  79. if (!aptx_handle)
  80. return;
  81. dlclose(aptx_handle);
  82. aptx_handle = NULL;
  83. }
  84. static int aptx_get_presets(struct audio_preset *preset, size_t *len)
  85. {
  86. int i;
  87. int count;
  88. size_t new_len = 0;
  89. uint8_t *ptr = (uint8_t *) preset;
  90. size_t preset_size = sizeof(*preset) + sizeof(a2dp_aptx_t);
  91. DBG("");
  92. count = sizeof(aptx_presets) / sizeof(aptx_presets[0]);
  93. for (i = 0; i < count; i++) {
  94. preset = (struct audio_preset *) ptr;
  95. if (new_len + preset_size > *len)
  96. break;
  97. preset->len = sizeof(a2dp_aptx_t);
  98. memcpy(preset->data, &aptx_presets[i], preset->len);
  99. new_len += preset_size;
  100. ptr += preset_size;
  101. }
  102. *len = new_len;
  103. return i;
  104. }
  105. static bool aptx_codec_init(struct audio_preset *preset, uint16_t payload_len,
  106. void **codec_data)
  107. {
  108. struct aptx_data *aptx_data;
  109. DBG("");
  110. if (preset->len != sizeof(a2dp_aptx_t)) {
  111. error("APTX: preset size mismatch");
  112. return false;
  113. }
  114. aptx_data = malloc(sizeof(*aptx_data));
  115. if (!aptx_data)
  116. return false;
  117. memset(aptx_data, 0, sizeof(*aptx_data));
  118. memcpy(&aptx_data->aptx, preset->data, preset->len);
  119. aptx_data->enc = calloc(1, aptx_btencsize);
  120. if (!aptx_data->enc) {
  121. error("APTX: failed to create encoder");
  122. free(aptx_data);
  123. return false;
  124. }
  125. /* 1 = big-endian, this is what devices are using */
  126. aptx_init(aptx_data->enc, 1);
  127. *codec_data = aptx_data;
  128. return true;
  129. }
  130. static bool aptx_cleanup(void *codec_data)
  131. {
  132. struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
  133. free(aptx_data->enc);
  134. free(codec_data);
  135. return true;
  136. }
  137. static bool aptx_get_config(void *codec_data, struct audio_input_config *config)
  138. {
  139. struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
  140. config->rate = aptx_data->aptx.frequency & APTX_SAMPLING_FREQ_48000 ?
  141. 48000 : 44100;
  142. config->channels = AUDIO_CHANNEL_OUT_STEREO;
  143. config->format = AUDIO_FORMAT_PCM_16_BIT;
  144. return true;
  145. }
  146. static size_t aptx_get_buffer_size(void *codec_data)
  147. {
  148. /* TODO: return actual value */
  149. return 0;
  150. }
  151. static size_t aptx_get_mediapacket_duration(void *codec_data)
  152. {
  153. /* TODO: return actual value */
  154. return 0;
  155. }
  156. static ssize_t aptx_encode_mediapacket(void *codec_data, const uint8_t *buffer,
  157. size_t len, struct media_packet *mp,
  158. size_t mp_data_len, size_t *written)
  159. {
  160. struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
  161. const int16_t *ptr = (const void *) buffer;
  162. size_t bytes_in = 0;
  163. size_t bytes_out = 0;
  164. while ((len - bytes_in) >= 16 && (mp_data_len - bytes_out) >= 4) {
  165. int pcm_l[4], pcm_r[4];
  166. int i;
  167. for (i = 0; i < 4; i++) {
  168. pcm_l[i] = ptr[0];
  169. pcm_r[i] = ptr[1];
  170. ptr += 2;
  171. }
  172. aptx_encode(aptx_data->enc, pcm_l, pcm_r, &mp->data[bytes_out]);
  173. bytes_in += 16;
  174. bytes_out += 4;
  175. }
  176. *written = bytes_out;
  177. return bytes_in;
  178. }
  179. static bool aptx_update_qos(void *codec_data, uint8_t op)
  180. {
  181. /*
  182. * aptX has constant bitrate of 352kbps (with constant 4:1 compression
  183. * ratio) thus QoS is not possible here.
  184. */
  185. return false;
  186. }
  187. static const struct audio_codec codec = {
  188. .type = A2DP_CODEC_VENDOR,
  189. .use_rtp = false,
  190. .load = aptx_load,
  191. .unload = aptx_unload,
  192. .get_presets = aptx_get_presets,
  193. .init = aptx_codec_init,
  194. .cleanup = aptx_cleanup,
  195. .get_config = aptx_get_config,
  196. .get_buffer_size = aptx_get_buffer_size,
  197. .get_mediapacket_duration = aptx_get_mediapacket_duration,
  198. .encode_mediapacket = aptx_encode_mediapacket,
  199. .update_qos = aptx_update_qos,
  200. };
  201. const struct audio_codec *codec_aptx(void)
  202. {
  203. return &codec;
  204. }