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, &param[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, &param[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