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