1 /******************************************************************************
2 *
3 * Copyright (c) 2023 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include "codec_interface.h"
20
21 #include <bluetooth/log.h>
22 #include <lc3.h>
23
24 #include <cstddef>
25 #include <cstdint>
26 #include <cstdlib>
27 #include <memory>
28 #include <optional>
29 #include <vector>
30
31 #include "audio_hal_client/audio_hal_client.h"
32 #include "le_audio/le_audio_types.h"
33
34 namespace bluetooth::le_audio {
35
36 struct CodecInterface::Impl {
Implbluetooth::le_audio::CodecInterface::Impl37 Impl(const types::LeAudioCodecId& codec_id) : codec_id_(codec_id) {}
~Implbluetooth::le_audio::CodecInterface::Impl38 ~Impl() { Cleanup(); }
39
IsReadybluetooth::le_audio::CodecInterface::Impl40 bool IsReady() { return pcm_config_.has_value(); }
41
InitEncoderbluetooth::le_audio::CodecInterface::Impl42 CodecInterface::Status InitEncoder(const LeAudioCodecConfiguration& pcm_config,
43 const LeAudioCodecConfiguration& codec_config) {
44 // Output codec configuration
45 bt_codec_config_ = codec_config;
46
47 // TODO: For now only blocks_per_sdu = 1 is supported
48 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
49 if (pcm_config_.has_value()) {
50 Cleanup();
51 }
52 pcm_config_ = pcm_config;
53
54 lc3_.pcm_format_ =
55 (pcm_config_->bits_per_sample == 24) ? LC3_PCM_FORMAT_S24 : LC3_PCM_FORMAT_S16;
56
57 // Prepare the encoder
58 const auto encoder_size =
59 lc3_encoder_size(bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
60 lc3_.codec_mem_.reset(malloc(encoder_size));
61 lc3_.encoder_ =
62 lc3_setup_encoder(bt_codec_config_.data_interval_us, bt_codec_config_.sample_rate,
63 pcm_config_->sample_rate, lc3_.codec_mem_.get());
64
65 return Status::STATUS_OK;
66 }
67
68 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format, codec_id_.vendor_company_id,
69 codec_id_.vendor_codec_id);
70 return Status::STATUS_ERR_INVALID_CODEC_ID;
71 }
72
InitDecoderbluetooth::le_audio::CodecInterface::Impl73 CodecInterface::Status InitDecoder(const LeAudioCodecConfiguration& codec_config,
74 const LeAudioCodecConfiguration& pcm_config) {
75 // Input codec configuration
76 bt_codec_config_ = codec_config;
77
78 // TODO: For now only blocks_per_sdu = 1 is supported
79 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
80 if (pcm_config_.has_value()) {
81 Cleanup();
82 }
83 pcm_config_ = pcm_config;
84
85 lc3_.pcm_format_ =
86 (pcm_config_->bits_per_sample == 24) ? LC3_PCM_FORMAT_S24 : LC3_PCM_FORMAT_S16;
87
88 // Prepare the decoded output buffer
89 auto num_samples =
90 lc3_frame_samples(bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
91 if (num_samples == -1) {
92 log::error("Could not determine the sample count for data_interval: {}, sample_rate: {}",
93 bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
94 return CodecInterface::Status::STATUS_ERR_CODEC_NOT_READY;
95 }
96 output_channel_samples_ = num_samples;
97 adjustOutputBufferSizeIfNeeded(&output_channel_data_);
98
99 // Prepare the decoder
100 const auto decoder_size =
101 lc3_decoder_size(bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
102 lc3_.codec_mem_.reset(malloc(decoder_size));
103 lc3_.decoder_ =
104 lc3_setup_decoder(bt_codec_config_.data_interval_us, bt_codec_config_.sample_rate,
105 pcm_config_->sample_rate, lc3_.codec_mem_.get());
106
107 return Status::STATUS_OK;
108 }
109
110 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format, codec_id_.vendor_company_id,
111 codec_id_.vendor_codec_id);
112 return Status::STATUS_ERR_INVALID_CODEC_ID;
113 }
114
GetDecodedSamplesbluetooth::le_audio::CodecInterface::Impl115 std::vector<int16_t>& GetDecodedSamples() { return output_channel_data_; }
Decodebluetooth::le_audio::CodecInterface::Impl116 CodecInterface::Status Decode(uint8_t* data, uint16_t size) {
117 if (!IsReady()) {
118 log::error("decoder not ready");
119 return Status::STATUS_ERR_CODEC_NOT_READY;
120 }
121
122 // For now only LC3 is supported
123 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
124 adjustOutputBufferSizeIfNeeded(&output_channel_data_);
125 auto err = lc3_decode(lc3_.decoder_, data, size, lc3_.pcm_format_,
126 output_channel_data_.data(), 1 /* stride */);
127 if (err < 0) {
128 log::error("bad decoding parameters: {}", static_cast<int>(err));
129 return Status::STATUS_ERR_CODING_ERROR;
130 }
131
132 return Status::STATUS_OK;
133 }
134
135 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format, codec_id_.vendor_company_id,
136 codec_id_.vendor_codec_id);
137 return Status::STATUS_ERR_INVALID_CODEC_ID;
138 }
139
Encodebluetooth::le_audio::CodecInterface::Impl140 CodecInterface::Status Encode(const uint8_t* data, int stride, uint16_t out_size,
141 std::vector<int16_t>* out_buffer = nullptr,
142 uint16_t out_offset = 0) {
143 if (!IsReady()) {
144 log::error("decoder not ready");
145 return Status::STATUS_ERR_CODEC_NOT_READY;
146 }
147
148 if (out_size == 0) {
149 log::error("out_size cannot be 0");
150 return Status::STATUS_ERR_CODING_ERROR;
151 }
152
153 // For now only LC3 is supported
154 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
155 // Prepare the encoded output buffer
156 if (out_buffer == nullptr) {
157 out_buffer = &output_channel_data_;
158 }
159
160 // We have two bytes per sample in the buffer, while out_size and
161 // out_offset are in bytes
162 size_t channel_samples = (out_offset + out_size) / 2;
163 if (output_channel_samples_ < channel_samples) {
164 output_channel_samples_ = channel_samples;
165 }
166 adjustOutputBufferSizeIfNeeded(out_buffer);
167
168 // Encode
169 auto err = lc3_encode(lc3_.encoder_, lc3_.pcm_format_, data, stride, out_size,
170 ((uint8_t*)out_buffer->data()) + out_offset);
171 if (err < 0) {
172 log::error("bad encoding parameters: {}", static_cast<int>(err));
173 return Status::STATUS_ERR_CODING_ERROR;
174 }
175
176 return Status::STATUS_OK;
177 }
178
179 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format, codec_id_.vendor_company_id,
180 codec_id_.vendor_codec_id);
181 return Status::STATUS_ERR_INVALID_CODEC_ID;
182 }
183
Cleanupbluetooth::le_audio::CodecInterface::Impl184 void Cleanup() {
185 pcm_config_ = std::nullopt;
186 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
187 lc3_.Cleanup();
188 }
189 output_channel_data_.clear();
190 output_channel_samples_ = 0;
191 }
192
GetNumOfSamplesPerChannelbluetooth::le_audio::CodecInterface::Impl193 uint16_t GetNumOfSamplesPerChannel() {
194 if (!IsReady()) {
195 log::error("decoder not ready");
196 return 0;
197 }
198
199 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
200 auto num_samples =
201 lc3_frame_samples(bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
202 if (num_samples == -1) {
203 log::error("Could not determine the sample count for data_interval: {}, sample_rate: {}",
204 bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
205 return 0;
206 }
207 return num_samples;
208 }
209
210 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format, codec_id_.vendor_company_id,
211 codec_id_.vendor_codec_id);
212 return 0;
213 }
214
GetNumOfBytesPerSamplebluetooth::le_audio::CodecInterface::Impl215 uint8_t GetNumOfBytesPerSample() {
216 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
217 return lc3_.bits_to_bytes_per_sample(bt_codec_config_.bits_per_sample);
218 }
219
220 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format, codec_id_.vendor_company_id,
221 codec_id_.vendor_codec_id);
222 return 0;
223 }
224
225 private:
adjustOutputBufferSizeIfNeededbluetooth::le_audio::CodecInterface::Impl226 inline void adjustOutputBufferSizeIfNeeded(std::vector<int16_t>* out_buffer) {
227 if (out_buffer->size() < output_channel_samples_) {
228 log::debug("Changing buffer size to {}", output_channel_samples_);
229 out_buffer->resize(output_channel_samples_);
230 }
231 }
232
233 // BT codec params set when codec is initialized
234 types::LeAudioCodecId codec_id_;
235 LeAudioCodecConfiguration bt_codec_config_;
236 std::optional<LeAudioCodecConfiguration> pcm_config_;
237
238 // Output buffer
239 std::vector<int16_t> output_channel_data_;
240 size_t output_channel_samples_ = 0;
241
242 // LC3
243 struct lc3_t {
bits_to_bytes_per_samplebluetooth::le_audio::CodecInterface::Impl::lc3_t244 static inline uint8_t bits_to_bytes_per_sample(uint8_t bits_per_sample) {
245 // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes.
246 if (bits_per_sample == 24) {
247 return 4;
248 }
249 return bits_per_sample / 8;
250 }
251
Cleanupbluetooth::le_audio::CodecInterface::Impl::lc3_t252 void Cleanup() {
253 decoder_ = nullptr;
254 encoder_ = nullptr;
255 codec_mem_.reset();
256 }
257
lc3_tbluetooth::le_audio::CodecInterface::Impl::lc3_t258 lc3_t() : codec_mem_(nullptr, &std::free) {}
259 lc3_pcm_format pcm_format_;
260 union {
261 lc3_decoder_t decoder_;
262 lc3_encoder_t encoder_;
263 };
264 std::unique_ptr<void, decltype(&std::free)> codec_mem_;
265 } lc3_;
266 };
267
CodecInterface(const types::LeAudioCodecId & codec_id)268 CodecInterface::CodecInterface(const types::LeAudioCodecId& codec_id) {
269 if (codec_id.coding_format == types::kLeAudioCodingFormatLC3) {
270 impl = new Impl(codec_id);
271 } else {
272 log::error("Invalid codec ID: [{}:{}:{}]", codec_id.coding_format, codec_id.vendor_company_id,
273 codec_id.vendor_codec_id);
274 }
275 }
276
~CodecInterface()277 CodecInterface::~CodecInterface() { delete impl; }
278
IsReady()279 bool CodecInterface::IsReady() { return impl->IsReady(); }
InitEncoder(const LeAudioCodecConfiguration & pcm_config,const LeAudioCodecConfiguration & codec_config)280 CodecInterface::Status CodecInterface::InitEncoder(const LeAudioCodecConfiguration& pcm_config,
281 const LeAudioCodecConfiguration& codec_config) {
282 return impl->InitEncoder(pcm_config, codec_config);
283 }
InitDecoder(const LeAudioCodecConfiguration & codec_config,const LeAudioCodecConfiguration & pcm_config)284 CodecInterface::Status CodecInterface::InitDecoder(const LeAudioCodecConfiguration& codec_config,
285 const LeAudioCodecConfiguration& pcm_config) {
286 return impl->InitDecoder(codec_config, pcm_config);
287 }
GetDecodedSamples()288 std::vector<int16_t>& CodecInterface::GetDecodedSamples() { return impl->GetDecodedSamples(); }
Decode(uint8_t * data,uint16_t size)289 CodecInterface::Status CodecInterface::Decode(uint8_t* data, uint16_t size) {
290 return impl->Decode(data, size);
291 }
Encode(const uint8_t * data,int stride,uint16_t out_size,std::vector<int16_t> * out_buffer,uint16_t out_offset)292 CodecInterface::Status CodecInterface::Encode(const uint8_t* data, int stride, uint16_t out_size,
293 std::vector<int16_t>* out_buffer,
294 uint16_t out_offset) {
295 return impl->Encode(data, stride, out_size, out_buffer, out_offset);
296 }
Cleanup()297 void CodecInterface::Cleanup() { return impl->Cleanup(); }
298
GetNumOfSamplesPerChannel()299 uint16_t CodecInterface::GetNumOfSamplesPerChannel() { return impl->GetNumOfSamplesPerChannel(); }
GetNumOfBytesPerSample()300 uint8_t CodecInterface::GetNumOfBytesPerSample() { return impl->GetNumOfBytesPerSample(); }
301
302 } // namespace bluetooth::le_audio
303