RDK Documentation (Open Sourced RDK Components)
audio_converter.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 #include <string.h>
20 #include "audio_converter.h"
21 #include <stdint.h>
22 const unsigned int TEMPORARY_BUFFER_SIZE = 100 * 1024; //100kB
23 
24 audio_converter::audio_converter(const audiocapturemgr::audio_properties_t &in_props, const audiocapturemgr::audio_properties_t &out_props, audio_converter_sink &sink) : m_in_props(in_props), m_out_props(out_props), m_sink(sink)
25 {
26  m_downsample = false; //CID:88634 - Intialize bool variables
27  m_downmix = false;
28  process_conversion_params();
29 }
30 
31 
32 int audio_converter::process_conversion_params()
33 {
34  int ret = -1;
35  bool format_ok = false;
36  bool sample_rate_ok = false;
37  bool downmix = false;
38  bool downsample = false;
39 
40  m_op = UNSUPPORTED_CONVERSION;
41 
42  do
43  {
44  if((racFormat_e16BitMono == m_out_props.format) && (racFormat_e16BitStereo == m_in_props.format))
45  {
46  INFO("Convert 16-bit stereo to mono.\n");
47  format_ok = true;
48  downmix = true;
49  break;
50  }
51 
52  if(m_out_props.format == m_in_props.format)
53  {
54  INFO("No format conversion.\n");
55  format_ok = true;
56  break;
57  }
58 
59  if((racFormat_e16BitMono == m_out_props.format) && (
60  (racFormat_e16BitMonoLeft == m_in_props.format) ||
61  (racFormat_e16BitMonoRight == m_in_props.format)))
62  {
63  INFO("Convert Mono/mono-left/mono-right to mono.\n");
64  format_ok = true;
65  break;
66  }
67  ERROR("Unsupported format conversion: 0x%x to 0x%x.\n", m_in_props.format, m_out_props.format);
68 
69  } while(false);
70 
71  if(format_ok)
72  {
73  unsigned int in_sampling_rate, in_bits_per_sample, in_num_channels;
74  unsigned int out_sampling_rate, out_bits_per_sample, out_num_channels;
75  audiocapturemgr::get_individual_audio_parameters(m_in_props, in_sampling_rate, in_bits_per_sample, in_num_channels);
76  audiocapturemgr::get_individual_audio_parameters(m_out_props, out_sampling_rate, out_bits_per_sample, out_num_channels);
77 
78  if(out_sampling_rate > in_sampling_rate)
79  {
80  ERROR("Cannot up-sample. %d to %d.\n", in_sampling_rate, out_sampling_rate);
81  }
82  else if(0 != (in_sampling_rate % out_sampling_rate))
83  {
84  ERROR("Incompatible sampling rates: %d to %d.\n", in_sampling_rate, out_sampling_rate);
85  }
86  else
87  {
88  sample_rate_ok = true;
89  if(out_sampling_rate < in_sampling_rate)
90  {
91  downsample = true;
92  INFO("Downsample from %d to %d\n", in_sampling_rate, out_sampling_rate);
93  }
94  }
95  }
96 
97  if(format_ok && sample_rate_ok)
98  {
99  if (downmix && downsample)
100  {
101  m_op = DOWNMIX_AND_DOWNSAMPLE;
102  }
103  else if(downmix && !downsample)
104  {
105  m_op = DOWNMIX;
106  }
107  else if (!downmix && downsample)
108  {
109  m_op = DOWNSAMPLE;
110  }
111  else
112  {
113  m_op = NO_CONVERSION;
114  }
115  ret = 0;
116  }
117  return ret;
118 }
119 
120 int audio_converter::downsample_and_downmix(const std::list<audio_buffer *> &queue, int size)
121 {
122  int ret = 0;
123 
124  unsigned int in_sampling_rate, in_bits_per_sample, in_num_channels;
125  audiocapturemgr::get_individual_audio_parameters(m_in_props, in_sampling_rate, in_bits_per_sample, in_num_channels);
126 
127  unsigned int out_sampling_rate, out_bits_per_sample, out_num_channels;
128  audiocapturemgr::get_individual_audio_parameters(m_out_props, out_sampling_rate, out_bits_per_sample, out_num_channels);
129 
130  unsigned int sample_size = in_bits_per_sample / 8;
131  unsigned int frame_size = in_num_channels * sample_size;
132  unsigned int leap_value = frame_size * in_sampling_rate / out_sampling_rate;
133  unsigned int write_length = (DOWNMIX_AND_DOWNSAMPLE == m_op ? sample_size : frame_size ); //Write only first sample of a frame if we're downmixing.
134 
135  int read_offset = 0;
136 
137  unsigned int temp_buffer_write_offset = 0;
138 
139  for(auto &entry: queue)
140  {
141  char * ptr = (char *)entry->m_start_ptr + read_offset;
142  if(0 != (entry->m_size % frame_size))
143  {
144  WARN("Audio buffer not aligned with frame boundary!\n");
145  }
146 
147  int buffer_size = entry->m_size;
148  while (buffer_size > 0)
149  {
150  m_sink.write_data(ptr, write_length);
151  buffer_size -= leap_value;
152  ptr += leap_value;
153  }
154 
155  /*If the value of buffer_size when exiting the above loop is a negative value (it can only be zero or negative), we need to skip that many bytes
156  * when processing the next buffer in the list. This is to maintain the continuity of 'frame-skipping' across buffer boundaries. read_offset will
157  * now be a positive value that we advance the read pointer of the next buffer by.
158  *
159  * Illustration:
160  * If we're skipping 3 samples for every 4 samples read (i. e. writing only one sample for every 4 samples read), and we ran out of data in the current
161  * buffer after skipping just one sample, the remaining 2 samples need to be skipped at the beginning of the next buffer.
162  * */
163  read_offset = -1 * buffer_size;
164 
165  size -= entry->m_size;
166  if(0 >= size)
167  {
168  break;
169  }
170  }
171  return ret;
172 }
173 
174 
175 int audio_converter::downmix(const std::list<audio_buffer *> &queue, int size)
176 {
177  int ret = 0;
178 
179  unsigned int in_sampling_rate, in_bits_per_sample, in_num_channels;
180  audiocapturemgr::get_individual_audio_parameters(m_in_props, in_sampling_rate, in_bits_per_sample, in_num_channels);
181 
182  unsigned int sample_size = in_bits_per_sample / 8;
183  unsigned int frame_size = in_num_channels * sample_size;
184 
185  audio_converter_memory_sink * memsink = dynamic_cast <audio_converter_memory_sink * > (&m_sink);
186 
187  /* Targeted optimizations to downmix 16-bit 2 chanel audio to 1-channel. */
188  if(memsink && (16 == in_bits_per_sample) && (2 == in_num_channels))
189  {
190  INFO("Running special optimizations for 16-bit stereo to mono conversion.\n");
191  int16_t * dptr = (int16_t *)memsink->get_buffer();
192  unsigned int write_offset = memsink->get_size();
193  for(auto &entry: queue)
194  {
195  int16_t * sptr = (int16_t *)entry->m_start_ptr;
196  unsigned int data_remaining = entry->m_size;
197  while(32 <= data_remaining)
198  {
199  dptr[0] = sptr[0];
200  dptr[1] = sptr[2];
201  dptr[2] = sptr[4];
202  dptr[3] = sptr[6];
203  dptr[4] = sptr[8];
204  dptr[5] = sptr[10];
205  dptr[6] = sptr[12];
206  dptr[7] = sptr[14];
207  dptr += 8;
208  sptr += 16;
209  data_remaining -= 16 * 2;
210  write_offset += 8 * 2;
211  }
212 
213  /* If there is any remaining data making up less than 32 bytes, process that as well*/
214  while(0 != data_remaining)
215  {
216  *dptr = *sptr;
217  dptr += 1;
218  sptr += 2;
219  data_remaining -= 2 * 2;
220  write_offset += 1 * 2;
221  }
222 
223  }
224  memsink->m_write_offset = write_offset;
225  INFO("Final write offset is %d. Final value of dptr: %p\n", write_offset, dptr); //CID:128015 - Type cast
226  }
227  else
228  {
229  for(auto &entry: queue)
230  {
231  char * ptr = (char *)entry->m_start_ptr;
232  if(0 != (entry->m_size % frame_size))
233  {
234  WARN("Audio buffer not aligned with frame boundary!\n");
235  }
236 
237  unsigned int buffer_size = entry->m_size;
238  while (buffer_size > 0)
239  {
240  m_sink.write_data(ptr, sample_size);
241  buffer_size -= frame_size;
242  ptr += frame_size;
243  }
244 
245  size -= entry->m_size;
246  if(0 >= size)
247  {
248  break;
249  }
250  }
251  }
252  return ret;
253 }
254 #if 0
255 int audio_converter::downsample(std::list<audio_buffer *> &queue, int size)
256 {
257  int ret = 0;
258 
259  unsigned int in_sampling_rate, in_bits_per_sample, in_num_channels;
260  audiocapturemgr::get_individual_audio_parameters(m_in_props, in_sampling_rate, in_bits_per_sample, in_num_channels);
261 
262  unsigned int out_sampling_rate, out_bits_per_sample, out_num_channels;
263  audiocapturemgr::get_individual_audio_parameters(m_out_props, out_sampling_rate, out_bits_per_sample, out_num_channels);
264 
265  unsigned int frame_size = in_num_channels * in_bits_per_sample * 8;
266  unsigned int leap_value = frame_size * in_sampling_rate / out_sampling_rate;
267  int read_offset = 0;
268 
269  for(auto &entry: queue)
270  {
271  char * ptr = (char *)entry->m_start_ptr + read_offset;
272  if(0 != (entry->m_size % frame_size))
273  {
274  WARN("Audio buffer not aligned with frame boundary!\n");
275  }
276 
277  int buffer_size = entry->m_size;
278  while (buffer_size > 0)
279  {
280  m_sink.write_data(ptr, frame_size); //TODO Check for errors
281  buffer_size -= leap_value;
282  ptr += leap_value;
283  }
284  read_offset = -1 * buffer_size;
285 
286  size -= entry->m_size;
287  if(0 >= size)
288  {
289  break;
290  }
291  }
292  return ret;
293 }
294 #endif
295 int audio_converter::passthrough(const std::list<audio_buffer *> &queue, int size)
296 {
297  int ret = -1;
298  for(auto &entry: queue)
299  {
300  ret = m_sink.write_data((char *)entry->m_start_ptr, entry->m_size);
301  if(0 > ret)
302  {
303  ERROR("Write error!\n");
304  break;
305  }
306  size -= entry->m_size;
307  if(0 > size)
308  {
309  break;
310  }
311  }
312  return ret;
313 }
314 
315 int audio_converter::convert(const std::list<audio_buffer *> &queue, unsigned int size)
316 {
317  int ret = -1;
318  INFO("Operation: 0x%x\n", m_op);
319  switch(m_op)
320  {
321  case DOWNMIX_AND_DOWNSAMPLE:
322  ret = downsample_and_downmix(queue, size);
323  break;
324 
325  case DOWNMIX:
326  ret = downmix(queue, size);
327  break;
328 
329  case DOWNSAMPLE:
330  ret = downsample_and_downmix(queue, size);
331  break;
332 
333  case NO_CONVERSION:
334  ret = passthrough(queue, size);
335  break;
336 
337  default:
338  ERROR("Unsupported conversion.\n");
339  ret = -1;
340  }
341 
342  return ret;
343 }
344 
345 int audio_converter_file_sink::write_data(const char * ptr, unsigned int size)
346 {
347  int ret = 0;
348  m_file.write(ptr, size); //TODO: Add error handling
349  return ret;
350 }
351 
352 
353 audio_converter_memory_sink::audio_converter_memory_sink(unsigned int max_size) : m_write_offset(0)
354 {
355  m_buffer = new char[max_size];
356  INFO("Created with size %d. ptr: %p, this: %p\n", max_size, m_buffer, this); //CID:127553 and CID:127680 - Type cast
357 }
358 
359 audio_converter_memory_sink::~audio_converter_memory_sink()
360 {
361  INFO("Destroying %p\n", this); //CID:127449- Type cast
362  delete [] m_buffer;
363 }
364 
365 int audio_converter_memory_sink::write_data(const char * ptr, unsigned int size)
366 {
367  int ret = 0;
368  memcpy(&m_buffer[m_write_offset], ptr, size);
369  m_write_offset += size;
370  return ret;
371 }
audio_converter_sink
Definition: audio_converter.h:26
audio_converter_memory_sink
Definition: audio_converter.h:81
audiocapturemgr::audio_properties_t
Definition: audio_capture_manager.h:56
racFormat_e16BitMonoRight
@ racFormat_e16BitMonoRight
Definition: rmfAudioCapture.h:73
racFormat_e16BitMono
@ racFormat_e16BitMono
Definition: rmfAudioCapture.h:74
racFormat_e16BitStereo
@ racFormat_e16BitStereo
Definition: rmfAudioCapture.h:68
racFormat_e16BitMonoLeft
@ racFormat_e16BitMonoLeft
Definition: rmfAudioCapture.h:72