1 /******************************************************************************
2  *
3  *  Copyright 2004-2012 Broadcom Corporation
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  *
21  *  This module contains utility functions for dealing with SBC data frames
22  *  and codec capabilities.
23  *
24  ******************************************************************************/
25 
26 #include "a2dp_sbc_up_sample.h"
27 
28 #include <cstdint>
29 
30 typedef int(tA2DP_SBC_ACT)(void* p_src, void* p_dst, uint32_t src_samples, uint32_t dst_samples,
31                            uint32_t* p_ret);
32 
33 typedef struct {
34   int32_t cur_pos;      /* current position */
35   uint32_t src_sps;     /* samples per second (source audio data) */
36   uint32_t dst_sps;     /* samples per second (converted audio data) */
37   tA2DP_SBC_ACT* p_act; /* the action function to do the conversion */
38   uint8_t bits;         /* number of bits per pcm sample */
39   uint8_t n_channels;   /* number of channels (i.e. mono(1), stereo(2)...) */
40   int16_t worker1;
41   int16_t worker2;
42   uint8_t div;
43 } tA2DP_SBC_UPS_CB;
44 
45 tA2DP_SBC_UPS_CB a2dp_sbc_ups_cb;
46 
47 /*******************************************************************************
48  *
49  * Function         a2dp_sbc_init_up_sample
50  *
51  * Description      initialize the up sample
52  *
53  *                  src_sps: samples per second (source audio data)
54  *                  dst_sps: samples per second (converted audio data)
55  *                  bits: number of bits per pcm sample
56  *                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
57  *
58  * Returns          none
59  *
60  ******************************************************************************/
a2dp_sbc_init_up_sample(uint32_t src_sps,uint32_t dst_sps,uint8_t bits,uint8_t n_channels)61 void a2dp_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits, uint8_t n_channels) {
62   a2dp_sbc_ups_cb.cur_pos = -1;
63   a2dp_sbc_ups_cb.src_sps = src_sps;
64   a2dp_sbc_ups_cb.dst_sps = dst_sps;
65   a2dp_sbc_ups_cb.bits = bits;
66   a2dp_sbc_ups_cb.n_channels = n_channels;
67 
68   if (n_channels == 1) {
69     /* mono */
70     if (bits == 8) {
71       a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_8m;
72       a2dp_sbc_ups_cb.div = 1;
73     } else {
74       a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_16m;
75       a2dp_sbc_ups_cb.div = 2;
76     }
77   } else {
78     /* stereo */
79     if (bits == 8) {
80       a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_8s;
81       a2dp_sbc_ups_cb.div = 2;
82     } else {
83       a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_16s;
84       a2dp_sbc_ups_cb.div = 4;
85     }
86   }
87 }
88 
89 /*******************************************************************************
90  *
91  * Function         a2dp_sbc_up_sample
92  *
93  * Description      Given the source (p_src) audio data and
94  *                  source speed (src_sps, samples per second),
95  *                  This function converts it to audio data in the desired
96  *                  format
97  *
98  *                  p_src: the data buffer that holds the source audio data
99  *                  p_dst: the data buffer to hold the converted audio data
100  *                  src_samples: The number of source samples (number of bytes)
101  *                  dst_samples: The size of p_dst (number of bytes)
102  *
103  * Note:            An AE reported an issue with this function.
104  *                  When called with a2dp_sbc_up_sample(src, uint8_array_dst..)
105  *                  the byte before uint8_array_dst may get overwritten.
106  *                  Using uint16_array_dst avoids the problem.
107  *                  This issue is related to endian-ness and is hard to resolve
108  *                  in a generic manner.
109  * **************** Please use uint16 array as dst.
110  *
111  * Returns          The number of bytes used in p_dst
112  *                  The number of bytes used in p_src (in *p_ret)
113  *
114  ******************************************************************************/
a2dp_sbc_up_sample(void * p_src,void * p_dst,uint32_t src_samples,uint32_t dst_samples,uint32_t * p_ret)115 int a2dp_sbc_up_sample(void* p_src, void* p_dst, uint32_t src_samples, uint32_t dst_samples,
116                        uint32_t* p_ret) {
117   uint32_t src;
118   uint32_t dst;
119 
120   if (a2dp_sbc_ups_cb.p_act) {
121     src = src_samples / a2dp_sbc_ups_cb.div;
122     dst = dst_samples / a2dp_sbc_ups_cb.div;
123     return (*a2dp_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret);
124   } else {
125     *p_ret = 0;
126     return 0;
127   }
128 }
129 
130 /*******************************************************************************
131  *
132  * Function         a2dp_sbc_up_sample_16s (16bits-stereo)
133  *
134  * Description      Given the source (p_src) audio data and
135  *                  source speed (src_sps, samples per second),
136  *                  This function converts it to audio data in the desired
137  *                  format
138  *
139  *                  p_src: the data buffer that holds the source audio data
140  *                  p_dst: the data buffer to hold the converted audio data
141  *                  src_samples: The number of source samples (in uint of 4
142  *                               bytes)
143  *                  dst_samples: The size of p_dst (in uint of 4 bytes)
144  *
145  * Returns          The number of bytes used in p_dst
146  *                  The number of bytes used in p_src (in *p_ret)
147  *
148  ******************************************************************************/
a2dp_sbc_up_sample_16s(void * p_src,void * p_dst,uint32_t src_samples,uint32_t dst_samples,uint32_t * p_ret)149 int a2dp_sbc_up_sample_16s(void* p_src, void* p_dst, uint32_t src_samples, uint32_t dst_samples,
150                            uint32_t* p_ret) {
151   int16_t* p_src_tmp = (int16_t*)p_src;
152   int16_t* p_dst_tmp = (int16_t*)p_dst;
153   int16_t* p_worker1 = &a2dp_sbc_ups_cb.worker1;
154   int16_t* p_worker2 = &a2dp_sbc_ups_cb.worker2;
155   uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
156   uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
157 
158   while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
159     *p_dst_tmp++ = *p_worker1;
160     *p_dst_tmp++ = *p_worker2;
161 
162     a2dp_sbc_ups_cb.cur_pos -= src_sps;
163     dst_samples--;
164   }
165 
166   a2dp_sbc_ups_cb.cur_pos = dst_sps;
167 
168   while (src_samples-- && dst_samples) {
169     *p_worker1 = *p_src_tmp++;
170     *p_worker2 = *p_src_tmp++;
171 
172     do {
173       *p_dst_tmp++ = *p_worker1;
174       *p_dst_tmp++ = *p_worker2;
175 
176       a2dp_sbc_ups_cb.cur_pos -= src_sps;
177       dst_samples--;
178     } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
179 
180     a2dp_sbc_ups_cb.cur_pos += dst_sps;
181   }
182 
183   if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) {
184     a2dp_sbc_ups_cb.cur_pos = 0;
185   }
186 
187   *p_ret = ((char*)p_src_tmp - (char*)p_src);
188   return (char*)p_dst_tmp - (char*)p_dst;
189 }
190 
191 /*******************************************************************************
192  *
193  * Function         a2dp_sbc_up_sample_16m (16bits-mono)
194  *
195  * Description      Given the source (p_src) audio data and
196  *                  source speed (src_sps, samples per second),
197  *                  This function converts it to audio data in the desired
198  *                  format
199  *
200  *                  p_src: the data buffer that holds the source audio data
201  *                  p_dst: the data buffer to hold the converted audio data
202  *                  src_samples: The number of source samples (in uint of 2
203  *                               bytes)
204  *                  dst_samples: The size of p_dst (in uint of 2 bytes)
205  *
206  * Returns          The number of bytes used in p_dst
207  *                  The number of bytes used in p_src (in *p_ret)
208  *
209  ******************************************************************************/
a2dp_sbc_up_sample_16m(void * p_src,void * p_dst,uint32_t src_samples,uint32_t dst_samples,uint32_t * p_ret)210 int a2dp_sbc_up_sample_16m(void* p_src, void* p_dst, uint32_t src_samples, uint32_t dst_samples,
211                            uint32_t* p_ret) {
212   int16_t* p_src_tmp = (int16_t*)p_src;
213   int16_t* p_dst_tmp = (int16_t*)p_dst;
214   int16_t* p_worker = &a2dp_sbc_ups_cb.worker1;
215   uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
216   uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
217 
218   while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
219     *p_dst_tmp++ = *p_worker;
220     *p_dst_tmp++ = *p_worker;
221 
222     a2dp_sbc_ups_cb.cur_pos -= src_sps;
223     dst_samples--;
224     dst_samples--;
225   }
226 
227   a2dp_sbc_ups_cb.cur_pos = dst_sps;
228 
229   while (src_samples-- && dst_samples) {
230     *p_worker = *p_src_tmp++;
231 
232     do {
233       *p_dst_tmp++ = *p_worker;
234       *p_dst_tmp++ = *p_worker;
235 
236       a2dp_sbc_ups_cb.cur_pos -= src_sps;
237       dst_samples--;
238       dst_samples--;
239     } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
240 
241     a2dp_sbc_ups_cb.cur_pos += dst_sps;
242   }
243 
244   if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) {
245     a2dp_sbc_ups_cb.cur_pos = 0;
246   }
247 
248   *p_ret = ((char*)p_src_tmp - (char*)p_src);
249   return (char*)p_dst_tmp - (char*)p_dst;
250 }
251 
252 /*******************************************************************************
253  *
254  * Function         a2dp_sbc_up_sample_8s (8bits-stereo)
255  *
256  * Description      Given the source (p_src) audio data and
257  *                  source speed (src_sps, samples per second),
258  *                  This function converts it to audio data in the desired
259  *                  format
260  *
261  *                  p_src: the data buffer that holds the source audio data
262  *                  p_dst: the data buffer to hold the converted audio data
263  *                  src_samples: The number of source samples (in uint of 2
264  *                               bytes)
265  *                  dst_samples: The size of p_dst (in uint of 2 bytes)
266  *
267  * Returns          The number of bytes used in p_dst
268  *                  The number of bytes used in p_src (in *p_ret)
269  *
270  ******************************************************************************/
a2dp_sbc_up_sample_8s(void * p_src,void * p_dst,uint32_t src_samples,uint32_t dst_samples,uint32_t * p_ret)271 int a2dp_sbc_up_sample_8s(void* p_src, void* p_dst, uint32_t src_samples, uint32_t dst_samples,
272                           uint32_t* p_ret) {
273   uint8_t* p_src_tmp = (uint8_t*)p_src;
274   int16_t* p_dst_tmp = (int16_t*)p_dst;
275   int16_t* p_worker1 = &a2dp_sbc_ups_cb.worker1;
276   int16_t* p_worker2 = &a2dp_sbc_ups_cb.worker2;
277   uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
278   uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
279 
280   while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
281     *p_dst_tmp++ = *p_worker1;
282     *p_dst_tmp++ = *p_worker2;
283 
284     a2dp_sbc_ups_cb.cur_pos -= src_sps;
285     dst_samples--;
286     dst_samples--;
287   }
288 
289   a2dp_sbc_ups_cb.cur_pos = dst_sps;
290 
291   while (src_samples-- && dst_samples) {
292     *p_worker1 = *(uint8_t*)p_src_tmp++;
293     *p_worker1 -= 0x80;
294     *p_worker1 <<= 8;
295     *p_worker2 = *(uint8_t*)p_src_tmp++;
296     *p_worker2 -= 0x80;
297     *p_worker2 <<= 8;
298 
299     do {
300       *p_dst_tmp++ = *p_worker1;
301       *p_dst_tmp++ = *p_worker2;
302 
303       a2dp_sbc_ups_cb.cur_pos -= src_sps;
304       dst_samples--;
305       dst_samples--;
306     } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
307 
308     a2dp_sbc_ups_cb.cur_pos += dst_sps;
309   }
310 
311   if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) {
312     a2dp_sbc_ups_cb.cur_pos = 0;
313   }
314 
315   *p_ret = ((char*)p_src_tmp - (char*)p_src);
316   return (char*)p_dst_tmp - (char*)p_dst;
317 }
318 
319 /*******************************************************************************
320  *
321  * Function         a2dp_sbc_up_sample_8m (8bits-mono)
322  *
323  * Description      Given the source (p_src) audio data and
324  *                  source speed (src_sps, samples per second),
325  *                  This function converts it to audio data in the desired
326  *                  format
327  *
328  *                  p_src: the data buffer that holds the source audio data
329  *                  p_dst: the data buffer to hold the converted audio data
330  *                  src_samples: The number of source samples (number of bytes)
331  *                  dst_samples: The size of p_dst (number of bytes)
332  *
333  * Returns          The number of bytes used in p_dst
334  *                  The number of bytes used in p_src (in *p_ret)
335  *
336  ******************************************************************************/
a2dp_sbc_up_sample_8m(void * p_src,void * p_dst,uint32_t src_samples,uint32_t dst_samples,uint32_t * p_ret)337 int a2dp_sbc_up_sample_8m(void* p_src, void* p_dst, uint32_t src_samples, uint32_t dst_samples,
338                           uint32_t* p_ret) {
339   uint8_t* p_src_tmp = (uint8_t*)p_src;
340   int16_t* p_dst_tmp = (int16_t*)p_dst;
341   int16_t* p_worker = &a2dp_sbc_ups_cb.worker1;
342   uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
343   uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
344 
345   while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
346     *p_dst_tmp++ = *p_worker;
347     *p_dst_tmp++ = *p_worker;
348 
349     a2dp_sbc_ups_cb.cur_pos -= src_sps;
350     dst_samples -= 4;
351   }
352 
353   a2dp_sbc_ups_cb.cur_pos = dst_sps;
354 
355   while (src_samples-- && dst_samples) {
356     *p_worker = *(uint8_t*)p_src_tmp++;
357     *p_worker -= 0x80;
358     *p_worker <<= 8;
359 
360     do {
361       *p_dst_tmp++ = *p_worker;
362       *p_dst_tmp++ = *p_worker;
363 
364       a2dp_sbc_ups_cb.cur_pos -= src_sps;
365       dst_samples -= 4;
366     } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
367 
368     a2dp_sbc_ups_cb.cur_pos += dst_sps;
369   }
370 
371   if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) {
372     a2dp_sbc_ups_cb.cur_pos = 0;
373   }
374 
375   *p_ret = ((char*)p_src_tmp - (char*)p_src);
376   return (char*)p_dst_tmp - (char*)p_dst;
377 }
378