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