1 /*******************************************************************************
2 * Copyright (C) 2018 Cadence Design Systems, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to use this Software with Cadence processor cores only and
7 * not with any other processors and platforms, subject to
8 * the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 ******************************************************************************/
22
23 #define MODULE_TAG UTEST
24
25 #include "xaf-utils-test.h"
26
27 #include "audio/xa_vorbis_dec_api.h"
28 #include "audio/xa-audio-decoder-api.h"
29
30 #include "xa_playback.h"
31
32 #define PRINT_USAGE do { fprintf(stderr, "\nUsage: %s <input-file>\n", argv[0]); \
33 fprintf(stderr, " Only .ogg and .pcm files are supported. \n"); \
34 fprintf(stderr, " Playback is configured @ 48kHz, 2 ch, 16 bits pcm. \n"); \
35 fprintf(stderr, " pcm output is written to dec-out.pcm, by default. \n\n"); \
36 } while(0)
37
38
39 #define NUM_COMP_IN_GRAPH 1
40
41 void *p_input, *p_output;
42 pthread_t dec_thread;
43
44 FILE *fp, *ofp=NULL;
45 xaf_info_t comp_info;
46 void *pb_handle = NULL;
47 unsigned int card = 0;
48 unsigned int device = 0;
49 unsigned int period_size = 1024;
50 unsigned int period_count = 4;
51
52 /* ...playback format */
53 xaf_format_t pb_format;
54
55 int g_pthread_exit_code=0x12345678;
56
thread_exit_handler(int sig)57 void thread_exit_handler(int sig)
58 {
59 /* ...unused arg */
60 (void) sig;
61
62 pthread_exit(0);
63 }
64
vorbis_setup(void * p_decoder)65 static int vorbis_setup(void *p_decoder)
66 {
67 int param[2];
68
69 /* 1: Raw decode, 0: Ogg decode */
70 param[0] = XA_VORBISDEC_CONFIG_PARAM_RAW_VORBIS_FILE_MODE;
71 param[1] = 0;
72
73 XF_CHK_API(xaf_comp_set_config(p_decoder, 1, ¶m[0]));
74
75 return 0;
76 }
77
pcm_setup(void * p_pcm)78 static int pcm_setup(void *p_pcm)
79 {
80 int param[6];
81
82 param[0] = XA_CODEC_CONFIG_PARAM_SAMPLE_RATE;
83 param[1] = pb_format.sample_rate;
84 param[2] = XA_CODEC_CONFIG_PARAM_CHANNELS;
85 param[3] = pb_format.channels;
86 param[4] = XA_CODEC_CONFIG_PARAM_PCM_WIDTH;
87 param[5] = pb_format.pcm_width;
88
89 XF_CHK_API(xaf_comp_set_config(p_pcm, 3, ¶m[0]));
90
91 return 0;
92 }
93
consume_output(void * p_buf,int buf_length,void * p_output)94 static int consume_output(void *p_buf, int buf_length, void *p_output)
95 {
96 XAF_CHK_PTR(p_buf);
97 XAF_CHK_PTR(p_output);
98
99 #if !defined BOARD
100 FILE *fp = p_output;
101 fwrite(p_buf, 1, buf_length, fp);
102
103 if (xa_playback_buf(pb_handle, p_buf, buf_length)) {
104 TRACE(ERROR, _b("Playback Failed \n"));
105 return -1;
106 }
107 #else
108 #endif
109 return 0;
110 }
111
read_input(void * p_buf,int buf_length,int * read_length,void * p_input)112 static int read_input(void *p_buf, int buf_length, int *read_length, void *p_input)
113 {
114 XAF_CHK_PTR(p_buf);
115 XAF_CHK_PTR(read_length);
116 XAF_CHK_PTR(p_input);
117
118 #if !defined BOARD
119 FILE *fp = p_input;
120 *read_length = fread(p_buf, 1, buf_length, fp);
121 #else
122 #endif
123 return 0;
124 }
125
comp_process_entry(void * arg)126 static int comp_process_entry(void *arg)
127 {
128 void *p_comp;
129 xaf_comp_status comp_status;
130 int input_over, read_length;
131 void *pg_pthread_exit_code = (void*)&g_pthread_exit_code;
132
133 XAF_CHK_PTR(arg);
134 XAF_CHK_PTR(p_input);
135 XAF_CHK_PTR(p_output);
136
137 p_comp = arg;
138 input_over = 0;
139
140 XF_CHK_API(xaf_comp_process(NULL, p_comp, NULL, 0, XAF_EXEC_FLAG));
141
142 while (1)
143 {
144
145 XF_CHK_API(xaf_comp_get_status(NULL, p_comp, &comp_status, &comp_info));
146
147 if (comp_status == XAF_EXEC_DONE) break;
148
149 if (comp_status == XAF_NEED_INPUT && !input_over)
150 {
151 void *p_buf = (void *)comp_info.buf;
152 int size = comp_info.length;
153
154 XF_CHK_API(read_input(p_buf, size, &read_length, p_input));
155
156 if (read_length)
157 XF_CHK_API(xaf_comp_process(NULL, p_comp, (void *)comp_info.buf, read_length, XAF_INPUT_READY_FLAG));
158 else
159 {
160 XF_CHK_API(xaf_comp_process(NULL, p_comp, NULL, 0, XAF_INPUT_OVER_FLAG));
161 input_over = 1;
162 }
163 }
164
165 if (comp_status == XAF_OUTPUT_READY)
166 {
167 void *p_buf = (void *)comp_info.buf;
168 int size = comp_info.length;
169
170 XF_CHK_API(consume_output(p_buf, size, p_output));
171 XF_CHK_API(xaf_comp_process(NULL, p_comp, (void *)comp_info.buf, comp_info.length, XAF_NEED_OUTPUT_FLAG));
172 }
173 }
174 pthread_exit(pg_pthread_exit_code);
175
176 return 0;
177 }
178
179
main(int argc,const char ** argv)180 int main(int argc, const char **argv)
181 {
182 void *p_adev = NULL;
183 void *p_decoder;
184 mem_obj_t* mem_handle;
185 int num_comp = NUM_COMP_IN_GRAPH;
186
187 xaf_comp_status dec_status;
188 void *dec_inbuf[2];
189 int buf_length = XAF_INBUF_SIZE;
190 int read_length;
191 int i;
192
193 xf_id_t dec_id;
194 int (*dec_setup)(void *p_comp);
195 const char *ext;
196 int pthread_error;
197 void *pthread_exit_code;
198
199 struct sigaction actions;
200 memset(&actions, 0, sizeof(actions));
201 sigemptyset(&actions.sa_mask);
202 actions.sa_flags = 0;
203 actions.sa_handler = thread_exit_handler;
204 sigaction(SIGUSR1,&actions,NULL);
205
206 /* ...initialize playback format */
207 pb_format.sample_rate = 48000;
208 pb_format.channels = 2;
209 pb_format.pcm_width = 16;
210
211 audio_frmwk_buf_size = 0; //unused
212 audio_comp_buf_size = 0; //unused
213
214 print_banner("\'Audio decoder(PCM/Ogg-Vorbis)\'");
215
216 /* ...initialize tracing facility */
217 TRACE_INIT("Xtensa Audio Framework - Sample Application");
218
219 #if !defined BOARD
220 /* ...check input arguments */
221 if (argc != 2)
222 {
223 TRACE(ERROR, _b("Usage: ./xaf-test <input-file-.ogg/.pcm>\n"));
224 PRINT_USAGE;
225 return 0;
226 }
227
228
229 ext = strrchr(argv[1], '.');
230 if (!ext)
231 {
232 PRINT_USAGE;
233 return 0;
234 }
235 ext++;
236 if (!strcmp(ext, "pcm")) {
237 dec_id = "audio-decoder/pcm";
238 dec_setup = pcm_setup;
239 }
240 else if (!strcmp(ext, "ogg")) {
241 dec_id = "audio-decoder/vorbis";
242 dec_setup = vorbis_setup;
243 }
244 else {
245 TRACE(ERROR, _x("Unknown Decoder Extension '%s'"), ext);
246 PRINT_USAGE;
247 exit(-1);
248 }
249
250 /* ...open file */
251 if ((fp = fopen(argv[1], "rb")) == NULL)
252 {
253 TRACE(ERROR, _x("Failed to open '%s': %d"), argv[1], errno);
254 exit(-1);
255 }
256 if ((ofp = fopen("/data/dec-out.pcm", "wb")) == NULL)
257 {
258 TRACE(ERROR, _x("Failed to open '%s': %d"), "/data/dec-out.pcm", errno);
259 exit(-1);
260 }
261 p_input = fp;
262 p_output = ofp;
263 #endif
264
265 mem_handle = mem_init(); //initialize memory handler
266
267 XF_CHK_API(xaf_adev_open(&p_adev, audio_frmwk_buf_size, audio_comp_buf_size, mem_malloc, mem_free));
268
269 /* ...create decoder component */
270 XF_CHK_API(xaf_comp_create(p_adev, &p_decoder, dec_id, 2, 1, &dec_inbuf[0], XAF_DECODER));
271 XF_CHK_API(dec_setup(p_decoder));
272
273 /* ...start decoder component */
274 XF_CHK_API(xaf_comp_process(p_adev, p_decoder, NULL, 0, XAF_START_FLAG));
275
276 /* ...feed input to decoder component */
277 for (i=0; i<2; i++)
278 {
279 XF_CHK_API(read_input(dec_inbuf[i], buf_length, &read_length, p_input));
280
281 if (read_length)
282 XF_CHK_API(xaf_comp_process(p_adev, p_decoder, dec_inbuf[i], read_length, XAF_INPUT_READY_FLAG));
283 else
284 break;
285 }
286
287 /* ...initialization loop */
288 while (1)
289 {
290 XF_CHK_API(xaf_comp_get_status(p_adev, p_decoder, &dec_status, &comp_info));
291
292 if (dec_status == XAF_INIT_DONE || dec_status == XAF_EXEC_DONE)
293 {
294 pb_handle = xa_playback_open(card, device, pb_format.channels, pb_format.sample_rate,
295 pb_format.pcm_width, period_size, period_count);
296 if (!pb_handle) {
297 TRACE(ERROR, _x("Playback open error\n"));
298 return -1;
299 }
300
301 break;
302 }
303
304 if (dec_status == XAF_NEED_INPUT)
305 {
306 void *p_buf = (void *) comp_info.buf;
307 int size = comp_info.length;
308
309 XF_CHK_API(read_input(p_buf, size, &read_length, p_input));
310
311 if (read_length)
312 XF_CHK_API(xaf_comp_process(p_adev, p_decoder, p_buf, read_length, XAF_INPUT_READY_FLAG));
313 else
314 break;
315 }
316 }
317
318 if (dec_status != XAF_INIT_DONE)
319 {
320 TRACE(ERROR, _x("Failed to init"));
321 exit(-1);
322 }
323
324 pthread_create(&dec_thread, 0, (void *(*)(void *))&comp_process_entry, p_decoder);
325
326 pthread_error = pthread_join(dec_thread, (void **) &pthread_exit_code);
327 if(pthread_error)
328 {
329 TRACE(ERROR, _b("decode thread join error:%x\n"), pthread_error);
330 }
331
332 /* ...exec done, clean-up */
333 XF_CHK_API(xaf_comp_delete(p_decoder));
334 xa_playback_close(pb_handle);
335 XF_CHK_API(xaf_adev_close(p_adev, 0 /*unused*/));
336 if (fp) fclose(fp);
337 if (ofp) fclose(ofp);
338
339 mem_exit();
340 XF_CHK_API(print_mem_mcps_info(mem_handle, num_comp));
341
342 return 0;
343 }
344
345