| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // SPDX-License-Identifier: Apache-2.0
- /*
- * Copyright (C) 2014 Tieto Poland
- *
- */
- #define _GNU_SOURCE
- #include <stdint.h>
- #include <stdbool.h>
- #include <string.h>
- #include <malloc.h>
- #include <dlfcn.h>
- #include "audio-msg.h"
- #include "hal-audio.h"
- #include "hal-log.h"
- #include "profiles/audio/a2dp-codecs.h"
- #define APTX_SO_NAME "libbt-aptx.so"
- struct aptx_data {
- a2dp_aptx_t aptx;
- void *enc;
- };
- static const a2dp_aptx_t aptx_presets[] = {
- {
- .info =
- A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
- .frequency = APTX_SAMPLING_FREQ_44100 |
- APTX_SAMPLING_FREQ_48000,
- .channel_mode = APTX_CHANNEL_MODE_STEREO,
- },
- {
- .info =
- A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
- .frequency = APTX_SAMPLING_FREQ_48000,
- .channel_mode = APTX_CHANNEL_MODE_STEREO,
- },
- {
- .info =
- A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
- .frequency = APTX_SAMPLING_FREQ_44100,
- .channel_mode = APTX_CHANNEL_MODE_STEREO,
- },
- };
- static void *aptx_handle;
- static int aptx_btencsize;
- static int (*aptx_init)(void *, short);
- static int (*aptx_encode)(void *, void *, void *, void *);
- static bool aptx_load(void)
- {
- const char * (*aptx_version)(void);
- const char * (*aptx_build)(void);
- int (*aptx_sizeofenc)(void);
- aptx_handle = dlopen(APTX_SO_NAME, RTLD_LAZY);
- if (!aptx_handle) {
- error("APTX: failed to open library %s (%s)", APTX_SO_NAME,
- dlerror());
- return false;
- }
- aptx_version = dlsym(aptx_handle, "aptxbtenc_version");
- aptx_build = dlsym(aptx_handle, "aptxbtenc_build");
- if (aptx_version && aptx_build)
- info("APTX: using library version %s build %s", aptx_version(),
- aptx_build());
- else
- warn("APTX: cannot retrieve library version");
- aptx_sizeofenc = dlsym(aptx_handle, "SizeofAptxbtenc");
- aptx_init = dlsym(aptx_handle, "aptxbtenc_init");
- aptx_encode = dlsym(aptx_handle, "aptxbtenc_encodestereo");
- if (!aptx_sizeofenc || !aptx_init || !aptx_encode) {
- error("APTX: failed initialize library");
- dlclose(aptx_handle);
- aptx_handle = NULL;
- return false;
- }
- aptx_btencsize = aptx_sizeofenc();
- info("APTX: codec library initialized (size=%d)", aptx_btencsize);
- return true;
- }
- static void aptx_unload(void)
- {
- if (!aptx_handle)
- return;
- dlclose(aptx_handle);
- aptx_handle = NULL;
- }
- static int aptx_get_presets(struct audio_preset *preset, size_t *len)
- {
- int i;
- int count;
- size_t new_len = 0;
- uint8_t *ptr = (uint8_t *) preset;
- size_t preset_size = sizeof(*preset) + sizeof(a2dp_aptx_t);
- DBG("");
- count = sizeof(aptx_presets) / sizeof(aptx_presets[0]);
- for (i = 0; i < count; i++) {
- preset = (struct audio_preset *) ptr;
- if (new_len + preset_size > *len)
- break;
- preset->len = sizeof(a2dp_aptx_t);
- memcpy(preset->data, &aptx_presets[i], preset->len);
- new_len += preset_size;
- ptr += preset_size;
- }
- *len = new_len;
- return i;
- }
- static bool aptx_codec_init(struct audio_preset *preset, uint16_t payload_len,
- void **codec_data)
- {
- struct aptx_data *aptx_data;
- DBG("");
- if (preset->len != sizeof(a2dp_aptx_t)) {
- error("APTX: preset size mismatch");
- return false;
- }
- aptx_data = malloc(sizeof(*aptx_data));
- if (!aptx_data)
- return false;
- memset(aptx_data, 0, sizeof(*aptx_data));
- memcpy(&aptx_data->aptx, preset->data, preset->len);
- aptx_data->enc = calloc(1, aptx_btencsize);
- if (!aptx_data->enc) {
- error("APTX: failed to create encoder");
- free(aptx_data);
- return false;
- }
- /* 1 = big-endian, this is what devices are using */
- aptx_init(aptx_data->enc, 1);
- *codec_data = aptx_data;
- return true;
- }
- static bool aptx_cleanup(void *codec_data)
- {
- struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
- free(aptx_data->enc);
- free(codec_data);
- return true;
- }
- static bool aptx_get_config(void *codec_data, struct audio_input_config *config)
- {
- struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
- config->rate = aptx_data->aptx.frequency & APTX_SAMPLING_FREQ_48000 ?
- 48000 : 44100;
- config->channels = AUDIO_CHANNEL_OUT_STEREO;
- config->format = AUDIO_FORMAT_PCM_16_BIT;
- return true;
- }
- static size_t aptx_get_buffer_size(void *codec_data)
- {
- /* TODO: return actual value */
- return 0;
- }
- static size_t aptx_get_mediapacket_duration(void *codec_data)
- {
- /* TODO: return actual value */
- return 0;
- }
- static ssize_t aptx_encode_mediapacket(void *codec_data, const uint8_t *buffer,
- size_t len, struct media_packet *mp,
- size_t mp_data_len, size_t *written)
- {
- struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
- const int16_t *ptr = (const void *) buffer;
- size_t bytes_in = 0;
- size_t bytes_out = 0;
- while ((len - bytes_in) >= 16 && (mp_data_len - bytes_out) >= 4) {
- int pcm_l[4], pcm_r[4];
- int i;
- for (i = 0; i < 4; i++) {
- pcm_l[i] = ptr[0];
- pcm_r[i] = ptr[1];
- ptr += 2;
- }
- aptx_encode(aptx_data->enc, pcm_l, pcm_r, &mp->data[bytes_out]);
- bytes_in += 16;
- bytes_out += 4;
- }
- *written = bytes_out;
- return bytes_in;
- }
- static bool aptx_update_qos(void *codec_data, uint8_t op)
- {
- /*
- * aptX has constant bitrate of 352kbps (with constant 4:1 compression
- * ratio) thus QoS is not possible here.
- */
- return false;
- }
- static const struct audio_codec codec = {
- .type = A2DP_CODEC_VENDOR,
- .use_rtp = false,
- .load = aptx_load,
- .unload = aptx_unload,
- .get_presets = aptx_get_presets,
- .init = aptx_codec_init,
- .cleanup = aptx_cleanup,
- .get_config = aptx_get_config,
- .get_buffer_size = aptx_get_buffer_size,
- .get_mediapacket_duration = aptx_get_mediapacket_duration,
- .encode_mediapacket = aptx_encode_mediapacket,
- .update_qos = aptx_update_qos,
- };
- const struct audio_codec *codec_aptx(void)
- {
- return &codec;
- }
|