1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <inttypes.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <vector>
20
21 #include <audio_effects/effect_downmix.h>
22 #include <audio_utils/channels.h>
23 #include <audio_utils/primitives.h>
24 #include <log/log.h>
25 #include <system/audio.h>
26
27 #include "EffectDownmix.h"
28 #define FRAME_LENGTH 256
29 #define MAX_NUM_CHANNELS 8
30
31 struct downmix_cntxt_s {
32 effect_descriptor_t desc;
33 effect_handle_t handle;
34 effect_config_t config;
35
36 int numFileChannels;
37 int numProcessChannels;
38 };
39
40 extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
41
printUsage()42 void printUsage() {
43 printf("\nUsage:");
44 printf("\n downmixtest <input_file> <out_file> [options]\n");
45 printf("\nwhere,");
46 printf("\n <input_file> is the input file name");
47 printf("\n on which LVM effects are applied");
48 printf("\n <output_file> processed output file");
49 printf("\n and options are mentioned below");
50 printf("\n");
51 printf("\n -h");
52 printf("\n Prints this usage information");
53 printf("\n");
54 printf("\n -ch_fmt:<format_of_input_audio>");
55 printf("\n 0:AUDIO_CHANNEL_OUT_7POINT1(default)");
56 printf("\n 1:AUDIO_CHANNEL_OUT_5POINT1_SIDE");
57 printf("\n 2:AUDIO_CHANNEL_OUT_5POINT1_BACK");
58 printf("\n 3:AUDIO_CHANNEL_OUT_QUAD_SIDE");
59 printf("\n 4:AUDIO_CHANNEL_OUT_QUAD_BACK");
60 printf("\n");
61 printf("\n -fch:<file_channels> (1 through 8)");
62 printf("\n");
63 }
64
DownmixDefaultConfig(effect_config_t * pConfig)65 int32_t DownmixDefaultConfig(effect_config_t *pConfig) {
66 pConfig->inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
67 pConfig->inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
68 pConfig->inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
69 pConfig->inputCfg.bufferProvider.getBuffer = nullptr;
70 pConfig->inputCfg.bufferProvider.releaseBuffer = nullptr;
71 pConfig->inputCfg.bufferProvider.cookie = nullptr;
72 pConfig->inputCfg.mask = EFFECT_CONFIG_ALL;
73
74 pConfig->inputCfg.samplingRate = 44100;
75 pConfig->outputCfg.samplingRate = pConfig->inputCfg.samplingRate;
76
77 // set a default value for the access mode, but should be overwritten by caller
78 pConfig->outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
79 pConfig->outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
80 pConfig->outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
81 pConfig->outputCfg.bufferProvider.getBuffer = nullptr;
82 pConfig->outputCfg.bufferProvider.releaseBuffer = nullptr;
83 pConfig->outputCfg.bufferProvider.cookie = nullptr;
84 pConfig->outputCfg.mask = EFFECT_CONFIG_ALL;
85
86 return 0;
87 }
88
DownmixConfiureAndEnable(downmix_cntxt_s * pDescriptor)89 int32_t DownmixConfiureAndEnable(downmix_cntxt_s *pDescriptor) {
90 effect_handle_t *effectHandle = &pDescriptor->handle;
91 downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
92 const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
93 int32_t err = 0;
94 uint32_t replySize = (uint32_t)sizeof(err);
95
96 err = (Downmix_api->command)(*effectHandle, EFFECT_CMD_SET_CONFIG,
97 sizeof(effect_config_t), &(pDescriptor->config),
98 &replySize, &err);
99 if (err != 0) {
100 ALOGE("Downmix command to configure returned an error %d", err);
101 return err;
102 }
103
104 err = ((Downmix_api->command))(*effectHandle, EFFECT_CMD_ENABLE, 0, nullptr,
105 &replySize, &err);
106 if (err != 0) {
107 ALOGE("Downmix command to enable effect returned an error %d", err);
108 return err;
109 }
110 return 0;
111 }
112
DownmixExecute(downmix_cntxt_s * pDescriptor,FILE * finp,FILE * fout)113 int32_t DownmixExecute(downmix_cntxt_s *pDescriptor, FILE *finp,
114 FILE *fout) {
115 effect_handle_t *effectHandle = &pDescriptor->handle;
116 downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
117 const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
118
119 const int numFileChannels = pDescriptor->numFileChannels;
120 const int numProcessChannels = pDescriptor->numProcessChannels;
121 const int fileFrameSize = numFileChannels * sizeof(short);
122 const unsigned int outputChannels =
123 audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
124
125 std::vector<float> outFloat(FRAME_LENGTH * MAX_NUM_CHANNELS);
126 std::vector<float> inFloat(FRAME_LENGTH * MAX_NUM_CHANNELS);
127
128 audio_buffer_t inbuffer, outbuffer;
129 inbuffer.f32 = inFloat.data();
130 outbuffer.f32 = outFloat.data();
131 inbuffer.frameCount = FRAME_LENGTH;
132 outbuffer.frameCount = FRAME_LENGTH;
133
134 audio_buffer_t *pinbuf, *poutbuf;
135 pinbuf = &inbuffer;
136 poutbuf = &outbuffer;
137
138 int frameCounter = 0;
139 std::vector<short> inS16(FRAME_LENGTH * MAX_NUM_CHANNELS);
140 std::vector<short> outS16(FRAME_LENGTH * MAX_NUM_CHANNELS);
141
142 while (fread(inS16.data(), fileFrameSize, FRAME_LENGTH, finp) ==
143 FRAME_LENGTH) {
144 if (numFileChannels != numProcessChannels) {
145 adjust_channels(inS16.data(), numFileChannels, inS16.data(),
146 numProcessChannels, sizeof(short),
147 FRAME_LENGTH * fileFrameSize);
148 }
149
150 memcpy_to_float_from_i16(inFloat.data(), inS16.data(),
151 FRAME_LENGTH * numProcessChannels);
152
153 const int32_t err = (Downmix_api->process)(*effectHandle, pinbuf, poutbuf);
154 if (err != 0) {
155 ALOGE("DownmixProcess returned an error %d", err);
156 return -1;
157 }
158
159 memcpy_to_i16_from_float(outS16.data(), outFloat.data(),
160 FRAME_LENGTH * outputChannels);
161 fwrite(outS16.data(), sizeof(short), (FRAME_LENGTH * outputChannels),
162 fout);
163 frameCounter++;
164 }
165 printf("frameCounter: [%d]\n", frameCounter);
166 return 0;
167 }
168
DowmixMainProcess(downmix_cntxt_s * pDescriptor,FILE * finp,FILE * fout)169 int32_t DowmixMainProcess(downmix_cntxt_s *pDescriptor, FILE *finp,
170 FILE *fout) {
171 effect_handle_t *effectHandle = &pDescriptor->handle;
172 int32_t sessionId = 0, ioId = 0;
173 const effect_uuid_t downmix_uuid = {
174 0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
175
176 int32_t err = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
177 &downmix_uuid, sessionId, ioId,
178 effectHandle);
179 if (err != 0) {
180 ALOGE("DownmixLib_Create returned an error %d", err);
181 return -1;
182 }
183
184 // Passing the init config for time being.
185 err = DownmixConfiureAndEnable(pDescriptor);
186 if (err != 0) {
187 ALOGE("DownmixConfigureAndEnable returned an error %d", err);
188 return -1;
189 }
190 // execute call for downmix.
191 err = DownmixExecute(pDescriptor, finp, fout);
192 if (err != 0) {
193 ALOGE("DownmixExecute returned an error %d", err);
194 return -1;
195 }
196 // Release the library function.
197 err = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(*effectHandle);
198 if (err != 0) {
199 ALOGE("DownmixRelease returned an error %d", err);
200 return -1;
201 }
202 return 0;
203 }
204
main(int argc,const char * argv[])205 int main(int argc, const char *argv[]) {
206 int numFileChannels = 1, numProcessChannels = 8;
207 downmix_cntxt_s descriptor = {};
208 DownmixDefaultConfig(&(descriptor.config));
209
210 const char *infile = nullptr;
211 const char *outfile = nullptr;
212 for (int i = 1; i < argc; i++) {
213 printf("%s ", argv[i]);
214 if (argv[i][0] != '-') {
215 if (infile == nullptr) {
216 infile = argv[i];
217 } else if (outfile == nullptr) {
218 outfile = argv[i];
219 } else {
220 printUsage();
221 return -1;
222 }
223 } else if (!strncmp(argv[i], "-fs:", 4)) {
224 // Add a check for all the supported streams.
225 const int samplingFreq = atoi(argv[i] + 4);
226 if (samplingFreq != 8000 && samplingFreq != 11025 &&
227 samplingFreq != 12000 && samplingFreq != 16000 &&
228 samplingFreq != 22050 && samplingFreq != 24000 &&
229 samplingFreq != 32000 && samplingFreq != 44100 &&
230 samplingFreq != 48000 && samplingFreq != 88200 &&
231 samplingFreq != 96000 && samplingFreq != 176400 &&
232 samplingFreq != 192000) {
233 printf("Unsupported Sampling Frequency : %d", samplingFreq);
234 printUsage();
235 return -1;
236 }
237
238 descriptor.config.inputCfg.samplingRate = samplingFreq;
239 descriptor.config.outputCfg.samplingRate = samplingFreq;
240 } else if (!strncmp(argv[i], "-ch_fmt:", 8)) {
241 const int format = atoi(argv[i] + 8);
242 uint32_t *audioType = &descriptor.config.inputCfg.channels;
243 switch (format) {
244 case 0:
245 *audioType = AUDIO_CHANNEL_OUT_7POINT1;
246 break;
247 case 1:
248 *audioType = AUDIO_CHANNEL_OUT_5POINT1_SIDE;
249 break;
250 case 2:
251 *audioType = AUDIO_CHANNEL_OUT_5POINT1_BACK;
252 break;
253 case 3:
254 *audioType = AUDIO_CHANNEL_OUT_QUAD_SIDE;
255 break;
256 case 4:
257 *audioType = AUDIO_CHANNEL_OUT_QUAD_BACK;
258 break;
259 default:
260 *audioType = AUDIO_CHANNEL_OUT_7POINT1;
261 break;
262 }
263 descriptor.numProcessChannels =
264 audio_channel_count_from_out_mask(*audioType);
265 } else if (!strncmp(argv[i], "-fch:", 5)) {
266 const int fChannels = atoi(argv[i] + 5);
267 if (fChannels > 8 || fChannels < 1) {
268 printf("Unsupported number of file channels : %d", fChannels);
269 printUsage();
270 return -1;
271 }
272 descriptor.numFileChannels = fChannels;
273
274 } else if (!strncmp(argv[i], "-h", 2)) {
275 printUsage();
276 return 0;
277 }
278 }
279
280 if (/*infile == nullptr || */ outfile == nullptr) {
281 printUsage();
282 return -1;
283 }
284
285 FILE *finp = fopen(infile, "rb");
286 if (finp == nullptr) {
287 printf("Cannot open input file %s", infile);
288 return -1;
289 }
290 FILE *fout = fopen(outfile, "wb");
291 if (fout == nullptr) {
292 printf("Cannot open output file %s", outfile);
293 fclose(finp);
294 return -1;
295 }
296
297 const int err = DowmixMainProcess(&descriptor, finp, fout);
298 // close input and output files.
299 fclose(finp);
300 fclose(fout);
301 if (err != 0) {
302 printf("Error: %d\n", err);
303 }
304 return err;
305 }
306