• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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