153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright (C) 2020 Asymptotic <sanchayan@asymptotic.io>
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
853a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
953a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1753a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
2553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
2653a5a1b3Sopenharmony_ci#include <pulsecore/once.h>
2753a5a1b3Sopenharmony_ci#include <pulse/sample.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include <arpa/inet.h>
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#include "a2dp-codecs.h"
3253a5a1b3Sopenharmony_ci#include "a2dp-codec-api.h"
3353a5a1b3Sopenharmony_ci#include "a2dp-codec-gst.h"
3453a5a1b3Sopenharmony_ci#include "rtp.h"
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_cistatic bool can_be_supported(bool for_encoding) {
3753a5a1b3Sopenharmony_ci    GstElementFactory *element_factory;
3853a5a1b3Sopenharmony_ci
3953a5a1b3Sopenharmony_ci    if (!for_encoding)
4053a5a1b3Sopenharmony_ci        return false;
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci    element_factory = gst_element_factory_find("ldacenc");
4353a5a1b3Sopenharmony_ci    if (element_factory == NULL) {
4453a5a1b3Sopenharmony_ci        pa_log_info("LDAC encoder element `ldacenc` not found");
4553a5a1b3Sopenharmony_ci        return false;
4653a5a1b3Sopenharmony_ci    }
4753a5a1b3Sopenharmony_ci    gst_object_unref(element_factory);
4853a5a1b3Sopenharmony_ci
4953a5a1b3Sopenharmony_ci    return true;
5053a5a1b3Sopenharmony_ci}
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_cistatic bool can_accept_capabilities_common(const a2dp_ldac_t *capabilities, uint32_t vendor_id, uint16_t codec_id) {
5353a5a1b3Sopenharmony_ci    if (A2DP_GET_VENDOR_ID(capabilities->info) != vendor_id || A2DP_GET_CODEC_ID(capabilities->info) != codec_id)
5453a5a1b3Sopenharmony_ci        return false;
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_ci    if (!(capabilities->frequency & (LDAC_SAMPLING_FREQ_44100 | LDAC_SAMPLING_FREQ_48000 |
5753a5a1b3Sopenharmony_ci                                     LDAC_SAMPLING_FREQ_88200 | LDAC_SAMPLING_FREQ_96000)))
5853a5a1b3Sopenharmony_ci        return false;
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci    if (!(capabilities->channel_mode & LDAC_CHANNEL_MODE_STEREO))
6153a5a1b3Sopenharmony_ci        return false;
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci    return true;
6453a5a1b3Sopenharmony_ci}
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_cistatic bool can_accept_capabilities(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) {
6753a5a1b3Sopenharmony_ci    const a2dp_ldac_t *capabilities = (const a2dp_ldac_t *) capabilities_buffer;
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_ci    if (capabilities_size != sizeof(*capabilities))
7053a5a1b3Sopenharmony_ci        return false;
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_ci    return can_accept_capabilities_common(capabilities, LDAC_VENDOR_ID, LDAC_CODEC_ID);
7353a5a1b3Sopenharmony_ci}
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_cistatic const char *choose_remote_endpoint(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) {
7653a5a1b3Sopenharmony_ci    const pa_a2dp_codec_capabilities *a2dp_capabilities;
7753a5a1b3Sopenharmony_ci    const char *key;
7853a5a1b3Sopenharmony_ci    void *state;
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci    /* There is no preference, just choose random valid entry */
8153a5a1b3Sopenharmony_ci    PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) {
8253a5a1b3Sopenharmony_ci        if (can_accept_capabilities(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding))
8353a5a1b3Sopenharmony_ci            return key;
8453a5a1b3Sopenharmony_ci    }
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_ci    return NULL;
8753a5a1b3Sopenharmony_ci}
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_cistatic void fill_capabilities_common(a2dp_ldac_t *capabilities, uint32_t vendor_id, uint16_t codec_id) {
9053a5a1b3Sopenharmony_ci    capabilities->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id);
9153a5a1b3Sopenharmony_ci    capabilities->channel_mode = LDAC_CHANNEL_MODE_STEREO;
9253a5a1b3Sopenharmony_ci    capabilities->frequency = LDAC_SAMPLING_FREQ_44100 | LDAC_SAMPLING_FREQ_48000 |
9353a5a1b3Sopenharmony_ci                              LDAC_SAMPLING_FREQ_88200 | LDAC_SAMPLING_FREQ_96000;
9453a5a1b3Sopenharmony_ci}
9553a5a1b3Sopenharmony_ci
9653a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) {
9753a5a1b3Sopenharmony_ci    a2dp_ldac_t *capabilities = (a2dp_ldac_t *) capabilities_buffer;
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci    pa_zero(*capabilities);
10053a5a1b3Sopenharmony_ci    fill_capabilities_common(capabilities, LDAC_VENDOR_ID, LDAC_CODEC_ID);
10153a5a1b3Sopenharmony_ci    return sizeof(*capabilities);
10253a5a1b3Sopenharmony_ci}
10353a5a1b3Sopenharmony_ci
10453a5a1b3Sopenharmony_cistatic bool is_configuration_valid(const uint8_t *config_buffer, uint8_t config_size) {
10553a5a1b3Sopenharmony_ci    const a2dp_ldac_t *config = (const a2dp_ldac_t *) config_buffer;
10653a5a1b3Sopenharmony_ci
10753a5a1b3Sopenharmony_ci    if (config_size != sizeof(*config)) {
10853a5a1b3Sopenharmony_ci        pa_log_error("Invalid size of config buffer");
10953a5a1b3Sopenharmony_ci        return false;
11053a5a1b3Sopenharmony_ci    }
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    if (A2DP_GET_VENDOR_ID(config->info) != LDAC_VENDOR_ID || A2DP_GET_CODEC_ID(config->info) != LDAC_CODEC_ID) {
11353a5a1b3Sopenharmony_ci        pa_log_error("Invalid vendor codec information in configuration");
11453a5a1b3Sopenharmony_ci        return false;
11553a5a1b3Sopenharmony_ci    }
11653a5a1b3Sopenharmony_ci
11753a5a1b3Sopenharmony_ci    if (config->frequency != LDAC_SAMPLING_FREQ_44100 && config->frequency != LDAC_SAMPLING_FREQ_48000 &&
11853a5a1b3Sopenharmony_ci        config->frequency != LDAC_SAMPLING_FREQ_88200 && config->frequency != LDAC_SAMPLING_FREQ_96000) {
11953a5a1b3Sopenharmony_ci        pa_log_error("Invalid sampling frequency in configuration");
12053a5a1b3Sopenharmony_ci        return false;
12153a5a1b3Sopenharmony_ci    }
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    if (config->channel_mode != LDAC_CHANNEL_MODE_STEREO) {
12453a5a1b3Sopenharmony_ci        pa_log_error("Invalid channel mode in configuration");
12553a5a1b3Sopenharmony_ci        return false;
12653a5a1b3Sopenharmony_ci    }
12753a5a1b3Sopenharmony_ci
12853a5a1b3Sopenharmony_ci    return true;
12953a5a1b3Sopenharmony_ci}
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_cistatic int fill_preferred_configuration_common(const pa_sample_spec *default_sample_spec, const a2dp_ldac_t *capabilities, a2dp_ldac_t *config, uint32_t vendor_id, uint16_t codec_id) {
13253a5a1b3Sopenharmony_ci    int i;
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci    static const struct {
13553a5a1b3Sopenharmony_ci        uint32_t rate;
13653a5a1b3Sopenharmony_ci        uint8_t cap;
13753a5a1b3Sopenharmony_ci    } freq_table[] = {
13853a5a1b3Sopenharmony_ci        { 44100U, LDAC_SAMPLING_FREQ_44100 },
13953a5a1b3Sopenharmony_ci        { 48000U, LDAC_SAMPLING_FREQ_48000 },
14053a5a1b3Sopenharmony_ci        { 88200U, LDAC_SAMPLING_FREQ_88200 },
14153a5a1b3Sopenharmony_ci        { 96000U, LDAC_SAMPLING_FREQ_96000 }
14253a5a1b3Sopenharmony_ci    };
14353a5a1b3Sopenharmony_ci
14453a5a1b3Sopenharmony_ci    if (A2DP_GET_VENDOR_ID(capabilities->info) != LDAC_VENDOR_ID || A2DP_GET_CODEC_ID(capabilities->info) != LDAC_CODEC_ID) {
14553a5a1b3Sopenharmony_ci        pa_log_error("No supported vendor codec information");
14653a5a1b3Sopenharmony_ci        return -1;
14753a5a1b3Sopenharmony_ci    }
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci    config->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id);
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_ci    if (!(capabilities->channel_mode & LDAC_CHANNEL_MODE_STEREO)) {
15253a5a1b3Sopenharmony_ci        pa_log_error("No supported channel modes");
15353a5a1b3Sopenharmony_ci        return -1;
15453a5a1b3Sopenharmony_ci    }
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_ci    config->channel_mode = LDAC_CHANNEL_MODE_STEREO;
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_ci    /* Find the lowest freq that is at least as high as the requested sampling rate */
15953a5a1b3Sopenharmony_ci    for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++) {
16053a5a1b3Sopenharmony_ci        if (freq_table[i].rate >= default_sample_spec->rate && (capabilities->frequency & freq_table[i].cap)) {
16153a5a1b3Sopenharmony_ci            config->frequency = freq_table[i].cap;
16253a5a1b3Sopenharmony_ci            break;
16353a5a1b3Sopenharmony_ci        }
16453a5a1b3Sopenharmony_ci    }
16553a5a1b3Sopenharmony_ci
16653a5a1b3Sopenharmony_ci    if ((unsigned) i == PA_ELEMENTSOF(freq_table)) {
16753a5a1b3Sopenharmony_ci        for (--i; i >= 0; i--) {
16853a5a1b3Sopenharmony_ci            if (capabilities->frequency & freq_table[i].cap) {
16953a5a1b3Sopenharmony_ci                config->frequency = freq_table[i].cap;
17053a5a1b3Sopenharmony_ci                break;
17153a5a1b3Sopenharmony_ci            }
17253a5a1b3Sopenharmony_ci        }
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci        if (i < 0) {
17553a5a1b3Sopenharmony_ci            pa_log_error("Not suitable sample rate");
17653a5a1b3Sopenharmony_ci            return false;
17753a5a1b3Sopenharmony_ci        }
17853a5a1b3Sopenharmony_ci    }
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_ci    return 0;
18153a5a1b3Sopenharmony_ci}
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) {
18453a5a1b3Sopenharmony_ci    a2dp_ldac_t *config = (a2dp_ldac_t *) config_buffer;
18553a5a1b3Sopenharmony_ci    const a2dp_ldac_t *capabilities = (const a2dp_ldac_t *) capabilities_buffer;
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci    if (capabilities_size != sizeof(*capabilities)) {
18853a5a1b3Sopenharmony_ci        pa_log_error("Invalid size of capabilities buffer");
18953a5a1b3Sopenharmony_ci        return 0;
19053a5a1b3Sopenharmony_ci    }
19153a5a1b3Sopenharmony_ci
19253a5a1b3Sopenharmony_ci    pa_zero(*config);
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci    if (fill_preferred_configuration_common(default_sample_spec, capabilities, config, LDAC_VENDOR_ID, LDAC_CODEC_ID) < 0)
19553a5a1b3Sopenharmony_ci        return 0;
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_ci    return sizeof(*config);
19853a5a1b3Sopenharmony_ci}
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ciGstElement *gst_init_ldac(struct gst_info *info, pa_sample_spec *ss, bool for_encoding) {
20153a5a1b3Sopenharmony_ci    GstElement *bin;
20253a5a1b3Sopenharmony_ci    GstElement *enc;
20353a5a1b3Sopenharmony_ci    GstPad *pad;
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_ci    if (!for_encoding) {
20653a5a1b3Sopenharmony_ci        pa_log_error("LDAC does not support decoding");
20753a5a1b3Sopenharmony_ci        return NULL;
20853a5a1b3Sopenharmony_ci    }
20953a5a1b3Sopenharmony_ci
21053a5a1b3Sopenharmony_ci    ss->format = PA_SAMPLE_FLOAT32LE;
21153a5a1b3Sopenharmony_ci
21253a5a1b3Sopenharmony_ci    switch (info->a2dp_codec_t.ldac_config->frequency) {
21353a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_44100:
21453a5a1b3Sopenharmony_ci            ss->rate = 44100u;
21553a5a1b3Sopenharmony_ci            break;
21653a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_48000:
21753a5a1b3Sopenharmony_ci            ss->rate = 48000u;
21853a5a1b3Sopenharmony_ci            break;
21953a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_88200:
22053a5a1b3Sopenharmony_ci            ss->rate = 88200;
22153a5a1b3Sopenharmony_ci            break;
22253a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_96000:
22353a5a1b3Sopenharmony_ci            ss->rate = 96000;
22453a5a1b3Sopenharmony_ci            break;
22553a5a1b3Sopenharmony_ci        default:
22653a5a1b3Sopenharmony_ci            pa_log_error("LDAC invalid frequency %d", info->a2dp_codec_t.ldac_config->frequency);
22753a5a1b3Sopenharmony_ci            goto fail;
22853a5a1b3Sopenharmony_ci    }
22953a5a1b3Sopenharmony_ci
23053a5a1b3Sopenharmony_ci    switch (info->a2dp_codec_t.ldac_config->channel_mode) {
23153a5a1b3Sopenharmony_ci        case LDAC_CHANNEL_MODE_STEREO:
23253a5a1b3Sopenharmony_ci            ss->channels = 2;
23353a5a1b3Sopenharmony_ci            break;
23453a5a1b3Sopenharmony_ci        case LDAC_CHANNEL_MODE_MONO:
23553a5a1b3Sopenharmony_ci            ss->channels = 1;
23653a5a1b3Sopenharmony_ci            break;
23753a5a1b3Sopenharmony_ci        case LDAC_CHANNEL_MODE_DUAL:
23853a5a1b3Sopenharmony_ci            ss->channels = 1;
23953a5a1b3Sopenharmony_ci            break;
24053a5a1b3Sopenharmony_ci        default:
24153a5a1b3Sopenharmony_ci            pa_log_error("LDAC invalid channel mode %d", info->a2dp_codec_t.ldac_config->channel_mode);
24253a5a1b3Sopenharmony_ci            goto fail;
24353a5a1b3Sopenharmony_ci    }
24453a5a1b3Sopenharmony_ci
24553a5a1b3Sopenharmony_ci    enc = gst_element_factory_make("ldacenc", "ldac_enc");
24653a5a1b3Sopenharmony_ci    if (!enc) {
24753a5a1b3Sopenharmony_ci        pa_log_error("Could not create LDAC encoder element");
24853a5a1b3Sopenharmony_ci        goto fail;
24953a5a1b3Sopenharmony_ci    }
25053a5a1b3Sopenharmony_ci
25153a5a1b3Sopenharmony_ci    switch (info->codec_type) {
25253a5a1b3Sopenharmony_ci        case LDAC_EQMID_HQ:
25353a5a1b3Sopenharmony_ci            g_object_set(enc, "eqmid", 0, NULL);
25453a5a1b3Sopenharmony_ci            break;
25553a5a1b3Sopenharmony_ci        case LDAC_EQMID_SQ:
25653a5a1b3Sopenharmony_ci            g_object_set(enc, "eqmid", 1, NULL);
25753a5a1b3Sopenharmony_ci            break;
25853a5a1b3Sopenharmony_ci        case LDAC_EQMID_MQ:
25953a5a1b3Sopenharmony_ci            g_object_set(enc, "eqmid", 2, NULL);
26053a5a1b3Sopenharmony_ci            break;
26153a5a1b3Sopenharmony_ci        default:
26253a5a1b3Sopenharmony_ci            goto fail;
26353a5a1b3Sopenharmony_ci    }
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_ci    bin = gst_bin_new("ldac_enc_bin");
26653a5a1b3Sopenharmony_ci    pa_assert(bin);
26753a5a1b3Sopenharmony_ci
26853a5a1b3Sopenharmony_ci    gst_bin_add_many(GST_BIN(bin), enc, NULL);
26953a5a1b3Sopenharmony_ci
27053a5a1b3Sopenharmony_ci    pad = gst_element_get_static_pad(enc, "sink");
27153a5a1b3Sopenharmony_ci    pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad)));
27253a5a1b3Sopenharmony_ci    gst_object_unref(GST_OBJECT(pad));
27353a5a1b3Sopenharmony_ci
27453a5a1b3Sopenharmony_ci    pad = gst_element_get_static_pad(enc, "src");
27553a5a1b3Sopenharmony_ci    pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("src", pad)));
27653a5a1b3Sopenharmony_ci    gst_object_unref(GST_OBJECT(pad));
27753a5a1b3Sopenharmony_ci
27853a5a1b3Sopenharmony_ci    return bin;
27953a5a1b3Sopenharmony_ci
28053a5a1b3Sopenharmony_cifail:
28153a5a1b3Sopenharmony_ci    pa_log_error("LDAC encoder initialisation failed");
28253a5a1b3Sopenharmony_ci    return NULL;
28353a5a1b3Sopenharmony_ci}
28453a5a1b3Sopenharmony_ci
28553a5a1b3Sopenharmony_cistatic void *init_common(enum a2dp_codec_type codec_type, bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
28653a5a1b3Sopenharmony_ci    GstElement *bin;
28753a5a1b3Sopenharmony_ci    struct gst_info *info = NULL;
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci    if (!for_encoding) {
29053a5a1b3Sopenharmony_ci        pa_log_error("LDAC decoder not supported");
29153a5a1b3Sopenharmony_ci        return NULL;
29253a5a1b3Sopenharmony_ci    }
29353a5a1b3Sopenharmony_ci
29453a5a1b3Sopenharmony_ci    info = pa_xnew0(struct gst_info, 1);
29553a5a1b3Sopenharmony_ci    pa_assert(info);
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_ci    info->core = core;
29853a5a1b3Sopenharmony_ci    info->ss = sample_spec;
29953a5a1b3Sopenharmony_ci
30053a5a1b3Sopenharmony_ci    info->codec_type = codec_type;
30153a5a1b3Sopenharmony_ci    info->a2dp_codec_t.ldac_config = (const a2dp_ldac_t *) config_buffer;
30253a5a1b3Sopenharmony_ci    pa_assert(config_size == sizeof(*(info->a2dp_codec_t.ldac_config)));
30353a5a1b3Sopenharmony_ci
30453a5a1b3Sopenharmony_ci    if (!(bin = gst_init_ldac(info, sample_spec, for_encoding)))
30553a5a1b3Sopenharmony_ci        goto fail;
30653a5a1b3Sopenharmony_ci
30753a5a1b3Sopenharmony_ci    if (!gst_codec_init(info, for_encoding, bin))
30853a5a1b3Sopenharmony_ci        goto fail;
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci    return info;
31153a5a1b3Sopenharmony_ci
31253a5a1b3Sopenharmony_cifail:
31353a5a1b3Sopenharmony_ci    if (info)
31453a5a1b3Sopenharmony_ci        pa_xfree(info);
31553a5a1b3Sopenharmony_ci
31653a5a1b3Sopenharmony_ci    return NULL;
31753a5a1b3Sopenharmony_ci}
31853a5a1b3Sopenharmony_ci
31953a5a1b3Sopenharmony_cistatic void *init_hq(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
32053a5a1b3Sopenharmony_ci    return init_common(LDAC_EQMID_HQ, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core);
32153a5a1b3Sopenharmony_ci}
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_cistatic void *init_sq(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
32453a5a1b3Sopenharmony_ci    return init_common(LDAC_EQMID_SQ, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core);
32553a5a1b3Sopenharmony_ci}
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_cistatic void *init_mq(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
32853a5a1b3Sopenharmony_ci    return init_common(LDAC_EQMID_MQ, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core);
32953a5a1b3Sopenharmony_ci}
33053a5a1b3Sopenharmony_ci
33153a5a1b3Sopenharmony_cistatic void deinit(void *codec_info) {
33253a5a1b3Sopenharmony_ci    return gst_codec_deinit(codec_info);
33353a5a1b3Sopenharmony_ci}
33453a5a1b3Sopenharmony_ci
33553a5a1b3Sopenharmony_cistatic int reset(void *codec_info) {
33653a5a1b3Sopenharmony_ci    return 0;
33753a5a1b3Sopenharmony_ci}
33853a5a1b3Sopenharmony_ci
33953a5a1b3Sopenharmony_cistatic uint32_t get_ldac_num_samples(void *codec_info) {
34053a5a1b3Sopenharmony_ci    struct gst_info *info = (struct gst_info *) codec_info;
34153a5a1b3Sopenharmony_ci
34253a5a1b3Sopenharmony_ci    switch (info->a2dp_codec_t.ldac_config->frequency) {
34353a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_44100:
34453a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_48000:
34553a5a1b3Sopenharmony_ci            return 128;
34653a5a1b3Sopenharmony_ci            break;
34753a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_88200:
34853a5a1b3Sopenharmony_ci        case LDAC_SAMPLING_FREQ_96000:
34953a5a1b3Sopenharmony_ci            return 256;
35053a5a1b3Sopenharmony_ci            break;
35153a5a1b3Sopenharmony_ci        default:
35253a5a1b3Sopenharmony_ci            break;
35353a5a1b3Sopenharmony_ci    }
35453a5a1b3Sopenharmony_ci
35553a5a1b3Sopenharmony_ci    return 128;
35653a5a1b3Sopenharmony_ci}
35753a5a1b3Sopenharmony_ci
35853a5a1b3Sopenharmony_cistatic uint8_t get_ldac_num_frames(void *codec_info, enum a2dp_codec_type codec_type) {
35953a5a1b3Sopenharmony_ci    struct gst_info *info = (struct gst_info *) codec_info;
36053a5a1b3Sopenharmony_ci    uint8_t channels;
36153a5a1b3Sopenharmony_ci
36253a5a1b3Sopenharmony_ci    switch (info->a2dp_codec_t.ldac_config->channel_mode) {
36353a5a1b3Sopenharmony_ci        case LDAC_CHANNEL_MODE_STEREO:
36453a5a1b3Sopenharmony_ci            channels = 2;
36553a5a1b3Sopenharmony_ci            break;
36653a5a1b3Sopenharmony_ci        case LDAC_CHANNEL_MODE_MONO:
36753a5a1b3Sopenharmony_ci        case LDAC_CHANNEL_MODE_DUAL:
36853a5a1b3Sopenharmony_ci            channels = 1;
36953a5a1b3Sopenharmony_ci            break;
37053a5a1b3Sopenharmony_ci        default:
37153a5a1b3Sopenharmony_ci            break;
37253a5a1b3Sopenharmony_ci    }
37353a5a1b3Sopenharmony_ci
37453a5a1b3Sopenharmony_ci    switch (codec_type) {
37553a5a1b3Sopenharmony_ci        case LDAC_EQMID_HQ:
37653a5a1b3Sopenharmony_ci            return 4 / channels;
37753a5a1b3Sopenharmony_ci        case LDAC_EQMID_SQ:
37853a5a1b3Sopenharmony_ci            return 6 / channels;
37953a5a1b3Sopenharmony_ci        case LDAC_EQMID_MQ:
38053a5a1b3Sopenharmony_ci            return 12 / channels;
38153a5a1b3Sopenharmony_ci        default:
38253a5a1b3Sopenharmony_ci            break;
38353a5a1b3Sopenharmony_ci    }
38453a5a1b3Sopenharmony_ci
38553a5a1b3Sopenharmony_ci    return 6 / channels;
38653a5a1b3Sopenharmony_ci}
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_cistatic size_t get_block_size(void *codec_info, size_t link_mtu) {
38953a5a1b3Sopenharmony_ci    struct gst_info *info = (struct gst_info *) codec_info;
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    return get_ldac_num_samples(codec_info) * get_ldac_num_frames(codec_info, info->codec_type) * pa_frame_size(info->ss);
39253a5a1b3Sopenharmony_ci}
39353a5a1b3Sopenharmony_ci
39453a5a1b3Sopenharmony_cistatic size_t get_encoded_block_size(void *codec_info, size_t input_size) {
39553a5a1b3Sopenharmony_ci    /* encoded block size is not exactly known, report input_size */
39653a5a1b3Sopenharmony_ci    return input_size;
39753a5a1b3Sopenharmony_ci}
39853a5a1b3Sopenharmony_ci
39953a5a1b3Sopenharmony_cistatic size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) {
40053a5a1b3Sopenharmony_ci    return 0;
40153a5a1b3Sopenharmony_ci}
40253a5a1b3Sopenharmony_ci
40353a5a1b3Sopenharmony_cistatic size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
40453a5a1b3Sopenharmony_ci    struct gst_info *info = (struct gst_info *) codec_info;
40553a5a1b3Sopenharmony_ci    struct rtp_header *header;
40653a5a1b3Sopenharmony_ci    struct rtp_payload *payload;
40753a5a1b3Sopenharmony_ci    size_t written;
40853a5a1b3Sopenharmony_ci
40953a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(output_size < sizeof(*header) + sizeof(*payload))) {
41053a5a1b3Sopenharmony_ci        *processed = 0;
41153a5a1b3Sopenharmony_ci        return 0;
41253a5a1b3Sopenharmony_ci    }
41353a5a1b3Sopenharmony_ci
41453a5a1b3Sopenharmony_ci    written = gst_transcode_buffer(codec_info, timestamp, input_buffer, input_size, output_buffer + sizeof(*header) + sizeof(*payload), output_size - sizeof(*header) - sizeof(*payload), processed);
41553a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(*processed != input_size))
41653a5a1b3Sopenharmony_ci        pa_log_error("LDAC encoding error");
41753a5a1b3Sopenharmony_ci
41853a5a1b3Sopenharmony_ci    if (PA_LIKELY(written > 0)) {
41953a5a1b3Sopenharmony_ci        header = (struct rtp_header *) output_buffer;
42053a5a1b3Sopenharmony_ci        pa_zero(*header);
42153a5a1b3Sopenharmony_ci        header->v = 2;
42253a5a1b3Sopenharmony_ci        header->pt = 96;
42353a5a1b3Sopenharmony_ci        header->sequence_number = htons(info->seq_num++);
42453a5a1b3Sopenharmony_ci        header->timestamp = htonl(timestamp);
42553a5a1b3Sopenharmony_ci        header->ssrc = htonl(1);
42653a5a1b3Sopenharmony_ci        payload = (struct rtp_payload*) (output_buffer + sizeof(*header));
42753a5a1b3Sopenharmony_ci        payload->frame_count = get_ldac_num_frames(codec_info, info->codec_type);
42853a5a1b3Sopenharmony_ci        written += sizeof(*header) + sizeof(*payload);
42953a5a1b3Sopenharmony_ci    }
43053a5a1b3Sopenharmony_ci
43153a5a1b3Sopenharmony_ci    return written;
43253a5a1b3Sopenharmony_ci}
43353a5a1b3Sopenharmony_ci
43453a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_hq = {
43553a5a1b3Sopenharmony_ci    .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID },
43653a5a1b3Sopenharmony_ci    .support_backchannel = false,
43753a5a1b3Sopenharmony_ci    .can_be_supported = can_be_supported,
43853a5a1b3Sopenharmony_ci    .can_accept_capabilities = can_accept_capabilities,
43953a5a1b3Sopenharmony_ci    .choose_remote_endpoint = choose_remote_endpoint,
44053a5a1b3Sopenharmony_ci    .fill_capabilities = fill_capabilities,
44153a5a1b3Sopenharmony_ci    .is_configuration_valid = is_configuration_valid,
44253a5a1b3Sopenharmony_ci    .fill_preferred_configuration = fill_preferred_configuration,
44353a5a1b3Sopenharmony_ci    .bt_codec = {
44453a5a1b3Sopenharmony_ci        .name = "ldac_hq",
44553a5a1b3Sopenharmony_ci        .description = "LDAC (High Quality)",
44653a5a1b3Sopenharmony_ci        .init = init_hq,
44753a5a1b3Sopenharmony_ci        .deinit = deinit,
44853a5a1b3Sopenharmony_ci        .reset = reset,
44953a5a1b3Sopenharmony_ci        .get_read_block_size = get_block_size,
45053a5a1b3Sopenharmony_ci        .get_write_block_size = get_block_size,
45153a5a1b3Sopenharmony_ci        .get_encoded_block_size = get_encoded_block_size,
45253a5a1b3Sopenharmony_ci        .reduce_encoder_bitrate = reduce_encoder_bitrate,
45353a5a1b3Sopenharmony_ci        .encode_buffer = encode_buffer,
45453a5a1b3Sopenharmony_ci    },
45553a5a1b3Sopenharmony_ci};
45653a5a1b3Sopenharmony_ci
45753a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_sq = {
45853a5a1b3Sopenharmony_ci    .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID },
45953a5a1b3Sopenharmony_ci    .support_backchannel = false,
46053a5a1b3Sopenharmony_ci    .can_be_supported = can_be_supported,
46153a5a1b3Sopenharmony_ci    .can_accept_capabilities = can_accept_capabilities,
46253a5a1b3Sopenharmony_ci    .choose_remote_endpoint = choose_remote_endpoint,
46353a5a1b3Sopenharmony_ci    .fill_capabilities = fill_capabilities,
46453a5a1b3Sopenharmony_ci    .is_configuration_valid = is_configuration_valid,
46553a5a1b3Sopenharmony_ci    .fill_preferred_configuration = fill_preferred_configuration,
46653a5a1b3Sopenharmony_ci    .bt_codec = {
46753a5a1b3Sopenharmony_ci        .name = "ldac_sq",
46853a5a1b3Sopenharmony_ci        .description = "LDAC (Standard Quality)",
46953a5a1b3Sopenharmony_ci        .init = init_sq,
47053a5a1b3Sopenharmony_ci        .deinit = deinit,
47153a5a1b3Sopenharmony_ci        .reset = reset,
47253a5a1b3Sopenharmony_ci        .get_read_block_size = get_block_size,
47353a5a1b3Sopenharmony_ci        .get_write_block_size = get_block_size,
47453a5a1b3Sopenharmony_ci        .get_encoded_block_size = get_encoded_block_size,
47553a5a1b3Sopenharmony_ci        .reduce_encoder_bitrate = reduce_encoder_bitrate,
47653a5a1b3Sopenharmony_ci        .encode_buffer = encode_buffer,
47753a5a1b3Sopenharmony_ci    },
47853a5a1b3Sopenharmony_ci};
47953a5a1b3Sopenharmony_ci
48053a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_mq = {
48153a5a1b3Sopenharmony_ci    .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID },
48253a5a1b3Sopenharmony_ci    .support_backchannel = false,
48353a5a1b3Sopenharmony_ci    .can_be_supported = can_be_supported,
48453a5a1b3Sopenharmony_ci    .can_accept_capabilities = can_accept_capabilities,
48553a5a1b3Sopenharmony_ci    .choose_remote_endpoint = choose_remote_endpoint,
48653a5a1b3Sopenharmony_ci    .fill_capabilities = fill_capabilities,
48753a5a1b3Sopenharmony_ci    .is_configuration_valid = is_configuration_valid,
48853a5a1b3Sopenharmony_ci    .fill_preferred_configuration = fill_preferred_configuration,
48953a5a1b3Sopenharmony_ci    .bt_codec = {
49053a5a1b3Sopenharmony_ci        .name = "ldac_mq",
49153a5a1b3Sopenharmony_ci        .description = "LDAC (Mobile Quality)",
49253a5a1b3Sopenharmony_ci        .init = init_mq,
49353a5a1b3Sopenharmony_ci        .deinit = deinit,
49453a5a1b3Sopenharmony_ci        .reset = reset,
49553a5a1b3Sopenharmony_ci        .get_read_block_size = get_block_size,
49653a5a1b3Sopenharmony_ci        .get_write_block_size = get_block_size,
49753a5a1b3Sopenharmony_ci        .get_encoded_block_size = get_encoded_block_size,
49853a5a1b3Sopenharmony_ci        .reduce_encoder_bitrate = reduce_encoder_bitrate,
49953a5a1b3Sopenharmony_ci        .encode_buffer = encode_buffer,
50053a5a1b3Sopenharmony_ci    },
50153a5a1b3Sopenharmony_ci};
502