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