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 <memory>
25 #include <optional>
26 #include <vector>
27
28 #include "os/log.h"
29
30 namespace bluetooth::le_audio {
31
32 struct CodecInterface::Impl {
Implbluetooth::le_audio::CodecInterface::Impl33 Impl(const types::LeAudioCodecId& codec_id) : codec_id_(codec_id) {}
~Implbluetooth::le_audio::CodecInterface::Impl34 ~Impl() { Cleanup(); }
35
IsReadybluetooth::le_audio::CodecInterface::Impl36 bool IsReady() { return pcm_config_.has_value(); };
37
InitEncoderbluetooth::le_audio::CodecInterface::Impl38 CodecInterface::Status InitEncoder(
39 const LeAudioCodecConfiguration& pcm_config,
40 const LeAudioCodecConfiguration& codec_config) {
41 // Output codec configuration
42 bt_codec_config_ = codec_config;
43
44 // TODO: For now only blocks_per_sdu = 1 is supported
45 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
46 if (pcm_config_.has_value()) {
47 Cleanup();
48 }
49 pcm_config_ = pcm_config;
50
51 lc3_.pcm_format_ = (pcm_config_->bits_per_sample == 24)
52 ? LC3_PCM_FORMAT_S24
53 : LC3_PCM_FORMAT_S16;
54
55 // Prepare the encoder
56 const auto encoder_size = lc3_encoder_size(
57 bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
58 lc3_.codec_mem_.reset(malloc(encoder_size));
59 lc3_.encoder_ = lc3_setup_encoder(
60 bt_codec_config_.data_interval_us, bt_codec_config_.sample_rate,
61 pcm_config_->sample_rate, lc3_.codec_mem_.get());
62
63 return Status::STATUS_OK;
64 }
65
66 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format,
67 codec_id_.vendor_company_id, codec_id_.vendor_codec_id);
68 return Status::STATUS_ERR_INVALID_CODEC_ID;
69 }
70
InitDecoderbluetooth::le_audio::CodecInterface::Impl71 CodecInterface::Status InitDecoder(
72 const LeAudioCodecConfiguration& codec_config,
73 const LeAudioCodecConfiguration& pcm_config) {
74 // Input codec configuration
75 bt_codec_config_ = codec_config;
76
77 // TODO: For now only blocks_per_sdu = 1 is supported
78 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
79 if (pcm_config_.has_value()) {
80 Cleanup();
81 }
82 pcm_config_ = pcm_config;
83
84 lc3_.pcm_format_ = (pcm_config_->bits_per_sample == 24)
85 ? LC3_PCM_FORMAT_S24
86 : LC3_PCM_FORMAT_S16;
87
88 // Prepare the decoded output buffer
89 output_channel_samples_ = lc3_frame_samples(
90 bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
91 adjustOutputBufferSizeIfNeeded(&output_channel_data_);
92
93 // Prepare the decoder
94 const auto decoder_size = lc3_decoder_size(
95 bt_codec_config_.data_interval_us, pcm_config_->sample_rate);
96 lc3_.codec_mem_.reset(malloc(decoder_size));
97 lc3_.decoder_ = lc3_setup_decoder(
98 bt_codec_config_.data_interval_us, bt_codec_config_.sample_rate,
99 pcm_config_->sample_rate, lc3_.codec_mem_.get());
100
101 return Status::STATUS_OK;
102 }
103
104 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format,
105 codec_id_.vendor_company_id, codec_id_.vendor_codec_id);
106 return Status::STATUS_ERR_INVALID_CODEC_ID;
107 }
108
GetDecodedSamplesbluetooth::le_audio::CodecInterface::Impl109 std::vector<int16_t>& GetDecodedSamples() { return output_channel_data_; }
Decodebluetooth::le_audio::CodecInterface::Impl110 CodecInterface::Status Decode(uint8_t* data, uint16_t size) {
111 if (!IsReady()) {
112 log::error("decoder not ready");
113 return Status::STATUS_ERR_CODEC_NOT_READY;
114 }
115
116 // For now only LC3 is supported
117 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
118 adjustOutputBufferSizeIfNeeded(&output_channel_data_);
119 auto err = lc3_decode(lc3_.decoder_, data, size, lc3_.pcm_format_,
120 output_channel_data_.data(), 1 /* stride */);
121 if (err < 0) {
122 log::error("bad decoding parameters: {}", static_cast<int>(err));
123 return Status::STATUS_ERR_CODING_ERROR;
124 }
125
126 return Status::STATUS_OK;
127 }
128
129 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format,
130 codec_id_.vendor_company_id, codec_id_.vendor_codec_id);
131 return Status::STATUS_ERR_INVALID_CODEC_ID;
132 }
133
Encodebluetooth::le_audio::CodecInterface::Impl134 CodecInterface::Status Encode(const uint8_t* data, int stride,
135 uint16_t out_size,
136 std::vector<int16_t>* out_buffer = nullptr,
137 uint16_t out_offset = 0) {
138 if (!IsReady()) {
139 log::error("decoder not ready");
140 return Status::STATUS_ERR_CODEC_NOT_READY;
141 }
142
143 if (out_size == 0) {
144 log::error("out_size cannot be 0");
145 return Status::STATUS_ERR_CODING_ERROR;
146 }
147
148 // For now only LC3 is supported
149 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
150 // Prepare the encoded output buffer
151 if (out_buffer == nullptr) {
152 out_buffer = &output_channel_data_;
153 }
154
155 // We have two bytes per sample in the buffer, while out_size and
156 // out_offset are in bytes
157 size_t channel_samples = (out_offset + out_size) / 2;
158 if (output_channel_samples_ < channel_samples) {
159 output_channel_samples_ = channel_samples;
160 }
161 adjustOutputBufferSizeIfNeeded(out_buffer);
162
163 // Encode
164 auto err =
165 lc3_encode(lc3_.encoder_, lc3_.pcm_format_, data, stride, out_size,
166 ((uint8_t*)out_buffer->data()) + out_offset);
167 if (err < 0) {
168 log::error("bad encoding parameters: {}", static_cast<int>(err));
169 return Status::STATUS_ERR_CODING_ERROR;
170 }
171
172 return Status::STATUS_OK;
173 }
174
175 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format,
176 codec_id_.vendor_company_id, codec_id_.vendor_codec_id);
177 return Status::STATUS_ERR_INVALID_CODEC_ID;
178 }
179
Cleanupbluetooth::le_audio::CodecInterface::Impl180 void Cleanup() {
181 pcm_config_ = std::nullopt;
182 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
183 lc3_.Cleanup();
184 }
185 output_channel_data_.clear();
186 output_channel_samples_ = 0;
187 }
188
GetNumOfSamplesPerChannelbluetooth::le_audio::CodecInterface::Impl189 uint16_t GetNumOfSamplesPerChannel() {
190 if (!IsReady()) {
191 log::error("decoder not ready");
192 return 0;
193 }
194
195 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
196 return lc3_frame_samples(bt_codec_config_.data_interval_us,
197 pcm_config_->sample_rate);
198 }
199
200 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format,
201 codec_id_.vendor_company_id, codec_id_.vendor_codec_id);
202 return 0;
203 }
204
GetNumOfBytesPerSamplebluetooth::le_audio::CodecInterface::Impl205 uint8_t GetNumOfBytesPerSample() {
206 if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) {
207 return lc3_.bits_to_bytes_per_sample(bt_codec_config_.bits_per_sample);
208 }
209
210 log::error("Invalid codec ID: [{}:{}:{}]", codec_id_.coding_format,
211 codec_id_.vendor_company_id, codec_id_.vendor_codec_id);
212 return 0;
213 }
214
215 private:
adjustOutputBufferSizeIfNeededbluetooth::le_audio::CodecInterface::Impl216 inline void adjustOutputBufferSizeIfNeeded(std::vector<int16_t>* out_buffer) {
217 if (out_buffer->size() < output_channel_samples_) {
218 out_buffer->resize(output_channel_samples_);
219 }
220 }
221
222 // BT codec params set when codec is initialized
223 types::LeAudioCodecId codec_id_;
224 LeAudioCodecConfiguration bt_codec_config_;
225 std::optional<LeAudioCodecConfiguration> pcm_config_;
226
227 // Output buffer
228 std::vector<int16_t> output_channel_data_;
229 size_t output_channel_samples_ = 0;
230
231 // LC3
232 struct lc3_t {
bits_to_bytes_per_samplebluetooth::le_audio::CodecInterface::Impl::lc3_t233 static inline uint8_t bits_to_bytes_per_sample(uint8_t bits_per_sample) {
234 // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes.
235 if (bits_per_sample == 24) return 4;
236 return bits_per_sample / 8;
237 }
238
Cleanupbluetooth::le_audio::CodecInterface::Impl::lc3_t239 void Cleanup() {
240 decoder_ = nullptr;
241 encoder_ = nullptr;
242 codec_mem_.reset();
243 }
244
lc3_tbluetooth::le_audio::CodecInterface::Impl::lc3_t245 lc3_t() : codec_mem_(nullptr, &std::free) {}
246 lc3_pcm_format pcm_format_;
247 union {
248 lc3_decoder_t decoder_;
249 lc3_encoder_t encoder_;
250 };
251 std::unique_ptr<void, decltype(&std::free)> codec_mem_;
252 } lc3_;
253 };
254
CodecInterface(const types::LeAudioCodecId & codec_id)255 CodecInterface::CodecInterface(const types::LeAudioCodecId& codec_id) {
256 if (codec_id.coding_format == types::kLeAudioCodingFormatLC3) {
257 impl = new Impl(codec_id);
258 } else {
259 log::error("Invalid codec ID: [{}:{}:{}]", codec_id.coding_format,
260 codec_id.vendor_company_id, codec_id.vendor_codec_id);
261 }
262 }
263
~CodecInterface()264 CodecInterface::~CodecInterface() { delete impl; }
265
IsReady()266 bool CodecInterface::IsReady() { return impl->IsReady(); };
InitEncoder(const LeAudioCodecConfiguration & pcm_config,const LeAudioCodecConfiguration & codec_config)267 CodecInterface::Status CodecInterface::InitEncoder(
268 const LeAudioCodecConfiguration& pcm_config,
269 const LeAudioCodecConfiguration& codec_config) {
270 return impl->InitEncoder(pcm_config, codec_config);
271 }
InitDecoder(const LeAudioCodecConfiguration & codec_config,const LeAudioCodecConfiguration & pcm_config)272 CodecInterface::Status CodecInterface::InitDecoder(
273 const LeAudioCodecConfiguration& codec_config,
274 const LeAudioCodecConfiguration& pcm_config) {
275 return impl->InitDecoder(codec_config, pcm_config);
276 }
GetDecodedSamples()277 std::vector<int16_t>& CodecInterface::GetDecodedSamples() {
278 return impl->GetDecodedSamples();
279 }
Decode(uint8_t * data,uint16_t size)280 CodecInterface::Status CodecInterface::Decode(uint8_t* data, uint16_t size) {
281 return impl->Decode(data, size);
282 }
Encode(const uint8_t * data,int stride,uint16_t out_size,std::vector<int16_t> * out_buffer,uint16_t out_offset)283 CodecInterface::Status CodecInterface::Encode(const uint8_t* data, int stride,
284 uint16_t out_size,
285 std::vector<int16_t>* out_buffer,
286 uint16_t out_offset) {
287 return impl->Encode(data, stride, out_size, out_buffer, out_offset);
288 }
Cleanup()289 void CodecInterface::Cleanup() { return impl->Cleanup(); }
290
GetNumOfSamplesPerChannel()291 uint16_t CodecInterface::GetNumOfSamplesPerChannel() {
292 return impl->GetNumOfSamplesPerChannel();
293 };
GetNumOfBytesPerSample()294 uint8_t CodecInterface::GetNumOfBytesPerSample() {
295 return impl->GetNumOfBytesPerSample();
296 };
297
298 } // namespace bluetooth::le_audio
299