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