1 /****************************************************************************** 2 * 3 * Copyright 2022 Google LLC 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 /** 20 * Low Complexity Communication Codec (LC3) - C++ interface 21 */ 22 23 #ifndef __LC3_CPP_H 24 #define __LC3_CPP_H 25 26 #include <cassert> 27 #include <memory> 28 #include <vector> 29 #include <stdlib.h> 30 31 #include "lc3.h" 32 33 namespace lc3 { 34 35 // PCM Sample Format 36 // - Signed 16 bits, in 16 bits words (int16_t) 37 // - Signed 24 bits, using low three bytes of 32 bits words (int32_t) 38 // The high byte sign extends (bits 31..24 set to b23) 39 // - Signed 24 bits packed in 3 bytes little endian 40 // - Floating point 32 bits (float type), in range -1 to 1 41 42 enum class PcmFormat { 43 kS16 = LC3_PCM_FORMAT_S16, 44 kS24 = LC3_PCM_FORMAT_S24, 45 kS24In3Le = LC3_PCM_FORMAT_S24_3LE, 46 kF32 = LC3_PCM_FORMAT_FLOAT 47 }; 48 49 // Base Encoder/Decoder Class 50 template <typename T> 51 class Base { 52 protected: Base(int dt_us,int sr_hz,int sr_pcm_hz,size_t nchannels,bool hrmode)53 Base(int dt_us, int sr_hz, int sr_pcm_hz, size_t nchannels, bool hrmode) 54 : dt_us_(dt_us), 55 sr_hz_(sr_hz), 56 sr_pcm_hz_(sr_pcm_hz == 0 ? sr_hz : sr_pcm_hz), 57 nchannels_(nchannels), 58 hrmode_(hrmode) { 59 states.reserve(nchannels_); 60 } 61 62 virtual ~Base() = default; 63 64 int dt_us_, sr_hz_; 65 int sr_pcm_hz_; 66 size_t nchannels_; 67 bool hrmode_; 68 69 using state_ptr = std::unique_ptr<T, decltype(&free)>; 70 std::vector<state_ptr> states; 71 72 public: 73 // Return the number of PCM samples in a frame GetFrameSamples()74 int GetFrameSamples() { 75 return lc3_hr_frame_samples(hrmode_, dt_us_, sr_pcm_hz_); } 76 77 // Return the size of a frame block, from bitrate GetFrameBytes(int bitrate)78 int GetFrameBytes(int bitrate) { 79 return lc3_hr_frame_block_bytes( 80 hrmode_, dt_us_, sr_hz_, nchannels_, bitrate); } 81 82 // Resolve the bitrate, from the size of frame blocks ResolveBitrate(int nbytes)83 int ResolveBitrate(int nbytes) { 84 return lc3_hr_resolve_bitrate(hrmode_, dt_us_, sr_hz_, nbytes); } 85 86 // Return algorithmic delay, as a number of samples GetDelaySamples()87 int GetDelaySamples() { 88 return lc3_hr_delay_samples(hrmode_, dt_us_, sr_pcm_hz_); } 89 90 }; // class Base 91 92 // Encoder Class 93 class Encoder : public Base<struct lc3_encoder> { 94 template <typename T> EncodeImpl(PcmFormat fmt,const T * pcm,int block_size,uint8_t * out)95 int EncodeImpl(PcmFormat fmt, const T *pcm, int block_size, uint8_t *out) { 96 if (states.size() != nchannels_) return -1; 97 98 enum lc3_pcm_format cfmt = static_cast<lc3_pcm_format>(fmt); 99 int ret = 0; 100 101 uint8_t *out_ptr = out; 102 for (size_t ich = 0; ich < nchannels_; ich++) { 103 int frame_size = block_size / nchannels_ 104 + (ich < block_size % nchannels_); 105 106 ret |= lc3_encode(states[ich].get(), cfmt, pcm + ich, nchannels_, 107 frame_size, out_ptr); 108 109 out_ptr += frame_size; 110 } 111 112 return ret; 113 } 114 115 public: 116 // Encoder construction / destruction 117 // 118 // The frame duration `dt_us` is 2500, 5000, 7500 or 10000 us. 119 // The sample rate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. 120 // The `hrmode` flag enables the high-resolution mode, in which case 121 // the sample rate is 48000 or 96000 Hz. 122 // 123 // The `sr_pcm_hz` parameter is a downsampling option of PCM input, 124 // the value 0 fallback to the sample rate of the encoded stream `sr_hz`. 125 // When used, `sr_pcm_hz` is intended to be higher or equal to the encoder 126 // sample rate `sr_hz`. 127 128 Encoder(int dt_us, int sr_hz, int sr_pcm_hz = 0, 129 size_t nchannels = 1, bool hrmode = false) Base(dt_us,sr_hz,sr_pcm_hz,nchannels,hrmode)130 : Base(dt_us, sr_hz, sr_pcm_hz, nchannels, hrmode) { 131 for (size_t ich = 0; ich < nchannels_; ich++) { 132 auto s = state_ptr((lc3_encoder_t) 133 malloc(lc3_hr_encoder_size(hrmode_, dt_us_, sr_pcm_hz_)), free); 134 135 if (lc3_hr_setup_encoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get())) 136 states.push_back(std::move(s)); 137 } 138 } 139 140 ~Encoder() override = default; 141 142 // Reset encoder state 143 Reset()144 void Reset() { 145 for (auto &s : states) 146 lc3_hr_setup_encoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get()); 147 } 148 149 // Encode 150 // 151 // The input PCM samples are given in signed 16 bits, 24 bits, float, 152 // according the type of `pcm` input buffer, or by selecting a format. 153 // 154 // The PCM samples are read in interleaved way, and consecutive 155 // `nchannels` frames, are output in `out` buffer, of size `buffer_size`. 156 // 157 // The value returned is 0 on successs, -1 otherwise. 158 Encode(const int16_t * pcm,int block_size,uint8_t * out)159 int Encode(const int16_t *pcm, int block_size, uint8_t *out) { 160 return EncodeImpl(PcmFormat::kS16, pcm, block_size, out); 161 } 162 Encode(const int32_t * pcm,int block_size,uint8_t * out)163 int Encode(const int32_t *pcm, int block_size, uint8_t *out) { 164 return EncodeImpl(PcmFormat::kS24, pcm, block_size, out); 165 } 166 Encode(const float * pcm,int block_size,uint8_t * out)167 int Encode(const float *pcm, int block_size, uint8_t *out) { 168 return EncodeImpl(PcmFormat::kF32, pcm, block_size, out); 169 } 170 Encode(PcmFormat fmt,const void * pcm,int block_size,uint8_t * out)171 int Encode(PcmFormat fmt, const void *pcm, int block_size, uint8_t *out) { 172 uintptr_t pcm_ptr = reinterpret_cast<uintptr_t>(pcm); 173 174 switch (fmt) { 175 case PcmFormat::kS16: 176 assert(pcm_ptr % alignof(int16_t) == 0); 177 return EncodeImpl(fmt, reinterpret_cast<const int16_t *>(pcm), 178 block_size, out); 179 180 case PcmFormat::kS24: 181 assert(pcm_ptr % alignof(int32_t) == 0); 182 return EncodeImpl(fmt, reinterpret_cast<const int32_t *>(pcm), 183 block_size, out); 184 185 case PcmFormat::kS24In3Le: 186 return EncodeImpl(fmt, reinterpret_cast<const int8_t(*)[3]>(pcm), 187 block_size, out); 188 189 case PcmFormat::kF32: 190 assert(pcm_ptr % alignof(float) == 0); 191 return EncodeImpl(fmt, reinterpret_cast<const float *>(pcm), block_size, 192 out); 193 } 194 195 return -1; 196 } 197 198 }; // class Encoder 199 200 // Decoder Class 201 class Decoder : public Base<struct lc3_decoder> { 202 template <typename T> DecodeImpl(const uint8_t * in,int block_size,PcmFormat fmt,T * pcm)203 int DecodeImpl(const uint8_t *in, int block_size, PcmFormat fmt, T *pcm) { 204 if (states.size() != nchannels_) return -1; 205 206 enum lc3_pcm_format cfmt = static_cast<enum lc3_pcm_format>(fmt); 207 int ret = 0; 208 209 const uint8_t *in_ptr = in; 210 for (size_t ich = 0; ich < nchannels_; ich++) { 211 int frame_size = block_size / nchannels_ 212 + (ich < block_size % nchannels_); 213 214 ret |= lc3_decode(states[ich].get(), in_ptr, frame_size, 215 cfmt, pcm + ich, nchannels_); 216 217 in_ptr += frame_size; 218 } 219 220 return ret; 221 } 222 223 public: 224 // Decoder construction / destruction 225 // 226 // The frame duration `dt_us` is 2500, 5000, 7500 or 10000 us. 227 // The sample rate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. 228 // The `hrmode` flag enables the high-resolution mode, in which case 229 // the sample rate is 48000 or 96000 Hz. 230 // 231 // The `sr_pcm_hz` parameter is an downsampling option of PCM output, 232 // the value 0 fallback to the sample rate of the decoded stream `sr_hz`. 233 // When used, `sr_pcm_hz` is intended to be higher or equal to the decoder 234 // sample rate `sr_hz`. 235 236 Decoder(int dt_us, int sr_hz, int sr_pcm_hz = 0, 237 size_t nchannels = 1, bool hrmode = false) Base(dt_us,sr_hz,sr_pcm_hz,nchannels,hrmode)238 : Base(dt_us, sr_hz, sr_pcm_hz, nchannels, hrmode) { 239 for (size_t i = 0; i < nchannels_; i++) { 240 auto s = state_ptr((lc3_decoder_t) 241 malloc(lc3_hr_decoder_size(hrmode_, dt_us_, sr_pcm_hz_)), free); 242 243 if (lc3_hr_setup_decoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get())) 244 states.push_back(std::move(s)); 245 } 246 } 247 248 ~Decoder() override = default; 249 250 // Reset decoder state 251 Reset()252 void Reset() { 253 for (auto &s : states) 254 lc3_hr_setup_decoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get()); 255 } 256 257 // Decode 258 // 259 // Decode a frame block of size `block_size`, 260 // in the `pcm` buffer in interleaved way. 261 // 262 // The PCM samples are output in signed 16 bits, 24 bits, float, 263 // according the type of `pcm` output buffer, or by selecting a format. 264 // 265 // The value returned is 0 on successs, 1 when PLC has been performed, 266 // and -1 otherwise. 267 Decode(const uint8_t * in,int block_size,int16_t * pcm)268 int Decode(const uint8_t *in, int block_size, int16_t *pcm) { 269 return DecodeImpl(in, block_size, PcmFormat::kS16, pcm); 270 } 271 Decode(const uint8_t * in,int block_size,int32_t * pcm)272 int Decode(const uint8_t *in, int block_size, int32_t *pcm) { 273 return DecodeImpl(in, block_size, PcmFormat::kS24In3Le, pcm); 274 } 275 Decode(const uint8_t * in,int block_size,float * pcm)276 int Decode(const uint8_t *in, int block_size, float *pcm) { 277 return DecodeImpl(in, block_size, PcmFormat::kF32, pcm); 278 } 279 Decode(const uint8_t * in,int block_size,PcmFormat fmt,void * pcm)280 int Decode(const uint8_t *in, int block_size, PcmFormat fmt, void *pcm) { 281 uintptr_t pcm_ptr = reinterpret_cast<uintptr_t>(pcm); 282 283 switch (fmt) { 284 case PcmFormat::kS16: 285 assert(pcm_ptr % alignof(int16_t) == 0); 286 return DecodeImpl(in, block_size, fmt, 287 reinterpret_cast<int16_t *>(pcm)); 288 289 case PcmFormat::kS24: 290 assert(pcm_ptr % alignof(int32_t) == 0); 291 return DecodeImpl(in, block_size, fmt, 292 reinterpret_cast<int32_t *>(pcm)); 293 294 case PcmFormat::kS24In3Le: 295 return DecodeImpl(in, block_size, fmt, 296 reinterpret_cast<int8_t(*)[3]>(pcm)); 297 298 case PcmFormat::kF32: 299 assert(pcm_ptr % alignof(float) == 0); 300 return DecodeImpl(in, block_size, fmt, reinterpret_cast<float *>(pcm)); 301 } 302 303 return -1; 304 } 305 306 }; // class Decoder 307 308 } // namespace lc3 309 310 #endif /* __LC3_CPP_H */ 311