153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
553a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
653a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
753a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
853a5a1b3Sopenharmony_ci
953a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1053a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1153a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1253a5a1b3Sopenharmony_ci  General Public License for more details.
1353a5a1b3Sopenharmony_ci
1453a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1553a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1653a5a1b3Sopenharmony_ci***/
1753a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
1853a5a1b3Sopenharmony_ci#include <config.h>
1953a5a1b3Sopenharmony_ci#endif
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#include <pulsecore/core.h>
2253a5a1b3Sopenharmony_ci#include "bt-codec-api.h"
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include "bt-codec-msbc.h"
2553a5a1b3Sopenharmony_ci#include <sbc/sbc.h>
2653a5a1b3Sopenharmony_ci
2753a5a1b3Sopenharmony_citypedef struct sbc_info {
2853a5a1b3Sopenharmony_ci    sbc_t sbc;                           /* Codec data */
2953a5a1b3Sopenharmony_ci    size_t codesize, frame_length;       /* SBC Codesize, frame_length. We simply cache those values here */
3053a5a1b3Sopenharmony_ci    uint8_t msbc_seq:2;                  /* mSBC packet sequence number, 2 bits only */
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_ci    uint16_t msbc_push_offset;
3353a5a1b3Sopenharmony_ci    uint8_t input_buffer[MSBC_PACKET_SIZE];                        /* Codec transfer buffer */
3453a5a1b3Sopenharmony_ci
3553a5a1b3Sopenharmony_ci    pa_sample_spec sample_spec;
3653a5a1b3Sopenharmony_ci} sbc_info_t;
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_cistatic void *init(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
3953a5a1b3Sopenharmony_ci    struct sbc_info *info;
4053a5a1b3Sopenharmony_ci    int ret;
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci    info = pa_xnew0(struct sbc_info, 1);
4353a5a1b3Sopenharmony_ci
4453a5a1b3Sopenharmony_ci    ret = sbc_init_msbc(&info->sbc, 0);
4553a5a1b3Sopenharmony_ci    if (ret != 0) {
4653a5a1b3Sopenharmony_ci        pa_xfree(info);
4753a5a1b3Sopenharmony_ci        pa_log_error("mSBC initialization failed: %d", ret);
4853a5a1b3Sopenharmony_ci        return NULL;
4953a5a1b3Sopenharmony_ci    }
5053a5a1b3Sopenharmony_ci
5153a5a1b3Sopenharmony_ci    info->sbc.endian = SBC_LE;
5253a5a1b3Sopenharmony_ci
5353a5a1b3Sopenharmony_ci    info->codesize = sbc_get_codesize(&info->sbc);
5453a5a1b3Sopenharmony_ci    info->frame_length = sbc_get_frame_length(&info->sbc);
5553a5a1b3Sopenharmony_ci    pa_log_info("mSBC codesize=%d, frame_length=%d",
5653a5a1b3Sopenharmony_ci                (int)info->codesize,
5753a5a1b3Sopenharmony_ci                (int)info->frame_length);
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_ci    info->sample_spec.format = PA_SAMPLE_S16LE;
6053a5a1b3Sopenharmony_ci    info->sample_spec.channels = 1;
6153a5a1b3Sopenharmony_ci    info->sample_spec.rate = 16000;
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci    pa_assert(pa_frame_aligned(info->codesize, &info->sample_spec));
6453a5a1b3Sopenharmony_ci
6553a5a1b3Sopenharmony_ci    *sample_spec = info->sample_spec;
6653a5a1b3Sopenharmony_ci
6753a5a1b3Sopenharmony_ci    return info;
6853a5a1b3Sopenharmony_ci}
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_cistatic void deinit(void *codec_info) {
7153a5a1b3Sopenharmony_ci    struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci    sbc_finish(&sbc_info->sbc);
7453a5a1b3Sopenharmony_ci    pa_xfree(sbc_info);
7553a5a1b3Sopenharmony_ci}
7653a5a1b3Sopenharmony_ci
7753a5a1b3Sopenharmony_cistatic int reset(void *codec_info) {
7853a5a1b3Sopenharmony_ci    struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
7953a5a1b3Sopenharmony_ci    int ret;
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_ci    /* SBC library release 1.5 has a bug in sbc_reinit_msbc:
8253a5a1b3Sopenharmony_ci     * it forgets to restore priv->msbc flag after clearing priv content.
8353a5a1b3Sopenharmony_ci     * This causes decoder assertion on first call since codesize would be
8453a5a1b3Sopenharmony_ci     * different from expected for mSBC configuration.
8553a5a1b3Sopenharmony_ci     *
8653a5a1b3Sopenharmony_ci     * Do not use sbc_reinit_msbc until it is fixed.
8753a5a1b3Sopenharmony_ci     */
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci    sbc_finish(&sbc_info->sbc);
9053a5a1b3Sopenharmony_ci    ret = sbc_init_msbc(&sbc_info->sbc, 0);
9153a5a1b3Sopenharmony_ci    if (ret != 0) {
9253a5a1b3Sopenharmony_ci        pa_xfree(sbc_info);
9353a5a1b3Sopenharmony_ci        pa_log_error("mSBC initialization failed: %d", ret);
9453a5a1b3Sopenharmony_ci        return -1;
9553a5a1b3Sopenharmony_ci    }
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_ci    sbc_info->sbc.endian = SBC_LE;
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci    sbc_info->msbc_seq = 0;
10053a5a1b3Sopenharmony_ci    sbc_info->msbc_push_offset = 0;
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_ci    return 0;
10353a5a1b3Sopenharmony_ci}
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_cistatic size_t get_read_block_size(void *codec_info, size_t link_mtu) {
10653a5a1b3Sopenharmony_ci    struct sbc_info *info = (struct sbc_info *) codec_info;
10753a5a1b3Sopenharmony_ci    size_t block_size = info->codesize;
10853a5a1b3Sopenharmony_ci
10953a5a1b3Sopenharmony_ci    /* this never happens as sbc_info->codesize is always frame-aligned */
11053a5a1b3Sopenharmony_ci    if (!pa_frame_aligned(block_size, &info->sample_spec)) {
11153a5a1b3Sopenharmony_ci        pa_log_debug("Got invalid block size: %lu, rounding down", block_size);
11253a5a1b3Sopenharmony_ci        block_size = pa_frame_align(block_size, &info->sample_spec);
11353a5a1b3Sopenharmony_ci    }
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci    /* If MTU exceeds mSBC frame size there could be up to 1 + MTU / (mSBC frame size)
11653a5a1b3Sopenharmony_ci     * frames decoded for single incoming packet.
11753a5a1b3Sopenharmony_ci     * See also pa_bluetooth_transport::last_read_size handling
11853a5a1b3Sopenharmony_ci     * and comment about MTU size in bt_prepare_encoder_buffer()
11953a5a1b3Sopenharmony_ci     */
12053a5a1b3Sopenharmony_ci    if (link_mtu <= MSBC_PACKET_SIZE)
12153a5a1b3Sopenharmony_ci        return block_size;
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    return block_size * (1 + link_mtu / MSBC_PACKET_SIZE);
12453a5a1b3Sopenharmony_ci}
12553a5a1b3Sopenharmony_ci
12653a5a1b3Sopenharmony_cistatic size_t get_write_block_size(void *codec_info, size_t link_mtu) {
12753a5a1b3Sopenharmony_ci    struct sbc_info *info = (struct sbc_info *) codec_info;
12853a5a1b3Sopenharmony_ci    return info->codesize;
12953a5a1b3Sopenharmony_ci}
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_cistatic size_t get_encoded_block_size(void *codec_info, size_t input_size) {
13253a5a1b3Sopenharmony_ci    struct sbc_info *info = (struct sbc_info *) codec_info;
13353a5a1b3Sopenharmony_ci    size_t encoded_size = MSBC_PACKET_SIZE;
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_ci    /* input size should be aligned to write block size */
13653a5a1b3Sopenharmony_ci    pa_assert_fp(input_size % info->codesize == 0);
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_ci    return encoded_size * (input_size / info->codesize);
13953a5a1b3Sopenharmony_ci}
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_cistatic size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) {
14253a5a1b3Sopenharmony_ci    return 0;
14353a5a1b3Sopenharmony_ci}
14453a5a1b3Sopenharmony_ci
14553a5a1b3Sopenharmony_cistatic size_t increase_encoder_bitrate(void *codec_info, size_t write_link_mtu) {
14653a5a1b3Sopenharmony_ci    return 0;
14753a5a1b3Sopenharmony_ci}
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_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) {
15053a5a1b3Sopenharmony_ci    struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
15153a5a1b3Sopenharmony_ci    struct msbc_frame *frame;
15253a5a1b3Sopenharmony_ci    uint8_t seq;
15353a5a1b3Sopenharmony_ci    ssize_t encoded;
15453a5a1b3Sopenharmony_ci    ssize_t written;
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_ci    pa_assert(input_size == sbc_info->codesize);
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_ci    /* must be room to render packet */
15953a5a1b3Sopenharmony_ci    pa_assert(output_size >= MSBC_PACKET_SIZE);
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_ci    frame = (struct msbc_frame *)output_buffer;
16253a5a1b3Sopenharmony_ci    seq = sbc_info->msbc_seq++;
16353a5a1b3Sopenharmony_ci    frame->hdr.id0 = MSBC_H2_ID0;
16453a5a1b3Sopenharmony_ci    frame->hdr.id1.s.id1 = MSBC_H2_ID1;
16553a5a1b3Sopenharmony_ci    if (seq & 0x02)
16653a5a1b3Sopenharmony_ci        frame->hdr.id1.s.sn1 = 3;
16753a5a1b3Sopenharmony_ci    else
16853a5a1b3Sopenharmony_ci        frame->hdr.id1.s.sn1 = 0;
16953a5a1b3Sopenharmony_ci    if (seq & 0x01)
17053a5a1b3Sopenharmony_ci        frame->hdr.id1.s.sn0 = 3;
17153a5a1b3Sopenharmony_ci    else
17253a5a1b3Sopenharmony_ci        frame->hdr.id1.s.sn0 = 0;
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci    encoded = sbc_encode(&sbc_info->sbc,
17553a5a1b3Sopenharmony_ci                         input_buffer, input_size,
17653a5a1b3Sopenharmony_ci                         frame->payload, MSBC_FRAME_SIZE,
17753a5a1b3Sopenharmony_ci                         &written);
17853a5a1b3Sopenharmony_ci
17953a5a1b3Sopenharmony_ci    frame->padding = 0x00;
18053a5a1b3Sopenharmony_ci
18153a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(encoded <= 0)) {
18253a5a1b3Sopenharmony_ci        pa_log_error("SBC encoding error (%li) for input size %lu, SBC codesize %lu",
18353a5a1b3Sopenharmony_ci                    (long) encoded, input_size, sbc_get_codesize(&sbc_info->sbc));
18453a5a1b3Sopenharmony_ci
18553a5a1b3Sopenharmony_ci        if (encoded < 0) {
18653a5a1b3Sopenharmony_ci            *processed = 0;
18753a5a1b3Sopenharmony_ci            return -1;
18853a5a1b3Sopenharmony_ci        } else {
18953a5a1b3Sopenharmony_ci            *processed = input_size;
19053a5a1b3Sopenharmony_ci            return 0;
19153a5a1b3Sopenharmony_ci        }
19253a5a1b3Sopenharmony_ci    }
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci    pa_assert_fp((size_t) encoded == sbc_info->codesize);
19553a5a1b3Sopenharmony_ci    pa_assert_fp((size_t) written == sbc_info->frame_length);
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_ci    *processed = encoded;
19853a5a1b3Sopenharmony_ci
19953a5a1b3Sopenharmony_ci    return MSBC_PACKET_SIZE;
20053a5a1b3Sopenharmony_ci}
20153a5a1b3Sopenharmony_ci
20253a5a1b3Sopenharmony_cistatic inline bool is_all_zero(const uint8_t *ptr, size_t len) {
20353a5a1b3Sopenharmony_ci    size_t i;
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_ci    for (i = 0; i < len; ++i)
20653a5a1b3Sopenharmony_ci        if (ptr[i] != 0)
20753a5a1b3Sopenharmony_ci            return false;
20853a5a1b3Sopenharmony_ci
20953a5a1b3Sopenharmony_ci    return true;
21053a5a1b3Sopenharmony_ci}
21153a5a1b3Sopenharmony_ci
21253a5a1b3Sopenharmony_ci/*
21353a5a1b3Sopenharmony_ci * We build a msbc frame up in the sbc_info buffer until we have a whole one
21453a5a1b3Sopenharmony_ci */
21553a5a1b3Sopenharmony_cistatic struct msbc_frame *msbc_find_frame(struct sbc_info *si, size_t *len,
21653a5a1b3Sopenharmony_ci                                          const uint8_t *buf, int *pseq)
21753a5a1b3Sopenharmony_ci{
21853a5a1b3Sopenharmony_ci    size_t i;
21953a5a1b3Sopenharmony_ci    uint8_t *p = si->input_buffer;
22053a5a1b3Sopenharmony_ci
22153a5a1b3Sopenharmony_ci    /* skip input if it has all zero bytes
22253a5a1b3Sopenharmony_ci     * this could happen with older kernels inserting all-zero blocks
22353a5a1b3Sopenharmony_ci     * inside otherwise valid mSBC stream */
22453a5a1b3Sopenharmony_ci    if (*len > 0 && is_all_zero(buf, *len))
22553a5a1b3Sopenharmony_ci        *len = 0;
22653a5a1b3Sopenharmony_ci
22753a5a1b3Sopenharmony_ci    for (i = 0; i < *len; i++) {
22853a5a1b3Sopenharmony_ci        union msbc_h2_id1 id1;
22953a5a1b3Sopenharmony_ci
23053a5a1b3Sopenharmony_ci        if (si->msbc_push_offset == 0) {
23153a5a1b3Sopenharmony_ci            if (buf[i] != MSBC_H2_ID0)
23253a5a1b3Sopenharmony_ci                continue;
23353a5a1b3Sopenharmony_ci        } else if (si->msbc_push_offset == 1) {
23453a5a1b3Sopenharmony_ci            id1.b = buf[i];
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci            if (id1.s.id1 != MSBC_H2_ID1)
23753a5a1b3Sopenharmony_ci                goto error;
23853a5a1b3Sopenharmony_ci            if (id1.s.sn0 != 3 && id1.s.sn0 != 0)
23953a5a1b3Sopenharmony_ci                goto error;
24053a5a1b3Sopenharmony_ci            if (id1.s.sn1 != 3 && id1.s.sn1 != 0)
24153a5a1b3Sopenharmony_ci                goto error;
24253a5a1b3Sopenharmony_ci        } else if (si->msbc_push_offset == 2) {
24353a5a1b3Sopenharmony_ci            if (buf[i] != MSBC_SYNC_BYTE)
24453a5a1b3Sopenharmony_ci                goto error;
24553a5a1b3Sopenharmony_ci        }
24653a5a1b3Sopenharmony_ci        p[si->msbc_push_offset++] = buf[i];
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_ci        if (si->msbc_push_offset == MSBC_PACKET_SIZE) {
24953a5a1b3Sopenharmony_ci            id1.b = p[1];
25053a5a1b3Sopenharmony_ci            *pseq = (id1.s.sn0 & 0x1) | (id1.s.sn1 & 0x2);
25153a5a1b3Sopenharmony_ci            si->msbc_push_offset = 0;
25253a5a1b3Sopenharmony_ci            *len -= i + 1;
25353a5a1b3Sopenharmony_ci            return (struct msbc_frame *)p;
25453a5a1b3Sopenharmony_ci        }
25553a5a1b3Sopenharmony_ci        continue;
25653a5a1b3Sopenharmony_ci
25753a5a1b3Sopenharmony_ci        error:
25853a5a1b3Sopenharmony_ci        si->msbc_push_offset = 0;
25953a5a1b3Sopenharmony_ci    }
26053a5a1b3Sopenharmony_ci    *len = 0;
26153a5a1b3Sopenharmony_ci    return NULL;
26253a5a1b3Sopenharmony_ci}
26353a5a1b3Sopenharmony_ci
26453a5a1b3Sopenharmony_cistatic size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
26553a5a1b3Sopenharmony_ci    struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
26653a5a1b3Sopenharmony_ci    size_t save_input_size;
26753a5a1b3Sopenharmony_ci    ssize_t decoded;
26853a5a1b3Sopenharmony_ci    size_t written = 0;
26953a5a1b3Sopenharmony_ci    size_t total_written = 0;
27053a5a1b3Sopenharmony_ci    size_t total_processed = 0;
27153a5a1b3Sopenharmony_ci    struct msbc_frame *frame;
27253a5a1b3Sopenharmony_ci    int seq;
27353a5a1b3Sopenharmony_ci
27453a5a1b3Sopenharmony_ci    while (input_size > 0) {
27553a5a1b3Sopenharmony_ci
27653a5a1b3Sopenharmony_ci        save_input_size = input_size;
27753a5a1b3Sopenharmony_ci        frame = msbc_find_frame(sbc_info, &input_size, input_buffer + total_processed, &seq);
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_ci        total_processed += save_input_size - input_size;
28053a5a1b3Sopenharmony_ci
28153a5a1b3Sopenharmony_ci        /* Only full mSBC frame should be decoded */
28253a5a1b3Sopenharmony_ci        if (!frame)
28353a5a1b3Sopenharmony_ci            break;
28453a5a1b3Sopenharmony_ci
28553a5a1b3Sopenharmony_ci        uint8_t lost_packets = (4 + seq - sbc_info->msbc_seq++) % 4;
28653a5a1b3Sopenharmony_ci
28753a5a1b3Sopenharmony_ci        if (lost_packets) {
28853a5a1b3Sopenharmony_ci            pa_log_debug("Lost %d input audio packet(s)", lost_packets);
28953a5a1b3Sopenharmony_ci            sbc_info->msbc_seq = seq + 1;
29053a5a1b3Sopenharmony_ci        }
29153a5a1b3Sopenharmony_ci
29253a5a1b3Sopenharmony_ci        /* pa_bt_codec::get_read_block_size must provide space for all decoded frames */
29353a5a1b3Sopenharmony_ci        pa_assert_fp(output_size >= sbc_info->codesize);
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci        decoded = sbc_decode(&sbc_info->sbc, frame->payload, MSBC_FRAME_SIZE, output_buffer, output_size, &written);
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_ci        if (PA_UNLIKELY(decoded <= 0)) {
29853a5a1b3Sopenharmony_ci            pa_log_error("mSBC decoding error (%li)", (long) decoded);
29953a5a1b3Sopenharmony_ci            pa_silence_memory(output_buffer, sbc_info->codesize, &sbc_info->sample_spec);
30053a5a1b3Sopenharmony_ci            decoded = sbc_info->frame_length;
30153a5a1b3Sopenharmony_ci            written = sbc_info->codesize;
30253a5a1b3Sopenharmony_ci        }
30353a5a1b3Sopenharmony_ci
30453a5a1b3Sopenharmony_ci        pa_assert_fp((size_t)decoded == sbc_info->frame_length);
30553a5a1b3Sopenharmony_ci        pa_assert_fp((size_t)written == sbc_info->codesize);
30653a5a1b3Sopenharmony_ci
30753a5a1b3Sopenharmony_ci        output_buffer += written;
30853a5a1b3Sopenharmony_ci        output_size -= written;
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci        total_written += written;
31153a5a1b3Sopenharmony_ci    }
31253a5a1b3Sopenharmony_ci
31353a5a1b3Sopenharmony_ci    *processed = total_processed;
31453a5a1b3Sopenharmony_ci    return total_written;
31553a5a1b3Sopenharmony_ci}
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci/* Modified SBC codec for HFP Wideband Speech*/
31853a5a1b3Sopenharmony_ciconst pa_bt_codec pa_bt_codec_msbc = {
31953a5a1b3Sopenharmony_ci    .name = "mSBC",
32053a5a1b3Sopenharmony_ci    .description = "mSBC",
32153a5a1b3Sopenharmony_ci    .init = init,
32253a5a1b3Sopenharmony_ci    .deinit = deinit,
32353a5a1b3Sopenharmony_ci    .reset = reset,
32453a5a1b3Sopenharmony_ci    .get_read_block_size = get_read_block_size,
32553a5a1b3Sopenharmony_ci    .get_write_block_size = get_write_block_size,
32653a5a1b3Sopenharmony_ci    .get_encoded_block_size = get_encoded_block_size,
32753a5a1b3Sopenharmony_ci    .reduce_encoder_bitrate = reduce_encoder_bitrate,
32853a5a1b3Sopenharmony_ci    .increase_encoder_bitrate = increase_encoder_bitrate,
32953a5a1b3Sopenharmony_ci    .encode_buffer = encode_buffer,
33053a5a1b3Sopenharmony_ci    .decode_buffer = decode_buffer,
33153a5a1b3Sopenharmony_ci};
332