fixup! Fix hanging on pthread_cond_destroy during cancellation of thread by broadcast...
[platform/core/api/sound-pool.git] / test / proxy / src / proxy.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
17 #include "proxy.h"
18 #include "logger.h"
19
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #define DEFAULT_MAX_STREAMS_PER_POOL_CNT 25U
26 #define DEFAULT_STREAM_PRIORITY_RANK 255U
27 #define MICROSECS_PER_MILLISEC 1000
28
29 #define MAX_POOL_CNT 100
30 static sound_pool_h pools[MAX_POOL_CNT] = { NULL };
31
32 /* Messages to be used for callbacks output (for pool state changing) */
33 static char *messages[MAX_POOL_CNT] = { NULL };
34 /* Scripts will be launched from callbacks (for stream state changing) */
35 static char *scripts[MAX_POOL_CNT] = { NULL };
36
37 #define MAX_STREAM_CNT 1000
38
39 static const char *__stringify_sound_pool_error(sound_pool_error_e error);
40 static int __proxy_sound_pool_execute_script(const char *pars);
41
42 static const char *__stringify_sound_pool_error(sound_pool_error_e error)
43 {
44         switch (error) {
45         case SOUND_POOL_ERROR_NONE:
46                 return "SOUND_POOL_ERROR_NONE";
47                 break;
48         case SOUND_POOL_ERROR_KEY_NOT_AVAILABLE:
49                 return "SOUND_POOL_ERROR_KEY_NOT_AVAILABLE";
50                 break;
51         case SOUND_POOL_ERROR_OUT_OF_MEMORY:
52                 return "SOUND_POOL_ERROR_OUT_OF_MEMORY";
53                 break;
54         case SOUND_POOL_ERROR_INVALID_PARAMETER:
55                 return "SOUND_POOL_ERROR_INVALID_PARAMETER";
56                 break;
57         case SOUND_POOL_ERROR_INVALID_OPERATION:
58                 return "SOUND_POOL_ERROR_INVALID_OPERATION";
59                 break;
60         case SOUND_POOL_ERROR_NOT_PERMITTED:
61                 return "SOUND_POOL_ERROR_NOT_PERMITTED";
62                 break;
63         case SOUND_POOL_ERROR_NO_SUCH_FILE:
64                 return "SOUND_POOL_ERROR_NO_SUCH_FILE";
65                 break;
66         default:
67                 return "";
68                 break;
69         }
70
71         return NULL;
72 }
73
74 const char *__stringify_stream_state(sound_pool_stream_state_e state)
75 {
76         switch (state) {
77         case SOUND_POOL_STREAM_STATE_NONE:
78                 return "SOUND_POOL_STREAM_STATE_NONE";
79                 break;
80         case SOUND_POOL_STREAM_STATE_PLAYING:
81                 return "SOUND_POOL_STREAM_STATE_PLAYING";
82                 break;
83         case SOUND_POOL_STREAM_STATE_PAUSED:
84                 return "SOUND_POOL_STREAM_STATE_PAUSED";
85                 break;
86         case SOUND_POOL_STREAM_STATE_SUSPENDED:
87                 return "SOUND_POOL_STREAM_STATE_SUSPENDED";
88                 break;
89         case SOUND_POOL_STREAM_STATE_STOPPED:
90                 return "SOUND_POOL_STREAM_STATE_STOPPED";
91                 break;
92         case SOUND_POOL_STREAM_STATE_FINISHED:
93                 return "SOUND_POOL_STREAM_STATE_FINISHED";
94                 break;
95         default:
96                 return "";
97                 break;
98         }
99
100         return NULL;
101 }
102
103 static void __sp_cb_msg(sound_pool_h pool, sound_pool_state_e prev_state,
104                 sound_pool_state_e cur_state, void *data)
105 {
106         const char *msg = (const char *)data;
107         _logger_log_info("Sound pool state was changing from %s to %s: %s",
108                         prev_state == SOUND_POOL_STATE_ACTIVE ?
109                                         "SOUND_POOL_STATE_ACTIVE" : "SOUND_POOL_STATE_INACTIVE",
110                         cur_state == SOUND_POOL_STATE_ACTIVE ?
111                                         "SOUND_POOL_STATE_ACTIVE" : "SOUND_POOL_STATE_INACTIVE",
112                         msg ? msg : "No message");
113 }
114
115 static void __sp_cb_scr(sound_pool_h pool, sound_pool_state_e prev_state,
116                 sound_pool_state_e cur_state, void *data)
117 {
118         const char *scr = (const char *)data;
119         _logger_log_info("Sound pool state was changing from %s to %s; "
120                         "Executing: %s...",
121                         prev_state == SOUND_POOL_STATE_ACTIVE ? "SOUND_POOL_STATE_ACTIVE" :
122                                         "SOUND_POOL_STATE_INACTIVE",
123                         cur_state == SOUND_POOL_STATE_ACTIVE ? "SOUND_POOL_STATE_ACTIVE" :
124                                         "SOUND_POOL_STATE_INACTIVE",
125                         scr ? scr : "No script");
126         __proxy_sound_pool_execute_script(scr);
127 }
128
129 static void __s_cb_msg(sound_pool_h pool, unsigned id,
130                 sound_pool_stream_state_e prev_state,
131                 sound_pool_stream_state_e cur_state, void *data)
132 {
133         const char *msg = (const char *)data;
134         _logger_log_info("Stream state was changing from %s to %s: %s",
135                         __stringify_stream_state(prev_state),
136                         __stringify_stream_state(cur_state),
137                         msg ? msg : "No message");
138 }
139
140 /* CMD_EXIT */
141 static int __exit()
142 {
143         return EXIT;
144 }
145
146 /* CMD_HELP */
147 static int __print_cmd_help_msg()
148 {
149         printf("\nTest suite usage help:\n");
150
151         printf(CMD_HELP "\n");
152         printf("\t- Shows this help.\n");
153
154         printf(CMD_CREATE_POOL "\n");
155         printf("\t- creates pool with specific identifier.\n");
156
157         printf(CMD_DESTROY_POOL "\n");
158         printf("\t- destroys pool with specific identifier.\n");
159
160         printf(CMD_ACTIVATE_POOL "\n");
161         printf("\t- activates pool with specific identifier.\n");
162
163         printf(CMD_DEACTIVATE_POOL "\n");
164         printf("\t- deactivates pool with specific identifier.\n");
165
166         printf(CMD_GET_POOL_STATE "\n");
167         printf("\t- shows state of the pool with specific identifier.\n");
168
169         printf(CMD_SET_POOL_VOLUME "\n");
170         printf("\t- use this command to set volume for the specific sound pool.\n");
171
172         printf(CMD_GET_POOL_VOLUME "\n");
173         printf("\t- shows volume of the sound pool with specific identifier.\n");
174
175         printf(CMD_SET_POOL_CB_MSG "\n");
176         printf("\t- sets callback which will show the message when sound pool "
177                         "state is changed.\n");
178
179         printf(CMD_UNSET_POOL_CB "\n");
180         printf("\t- unsets the callback for the sound pool.\n");
181
182         printf(CMD_LIST_POOL "\n");
183         printf("\t- shows ids of all pools had been created and their states.\n");
184
185         printf(CMD_LOAD_SOURCE "\n");
186         printf("\t- loads the source with specific source tag.\n");
187
188         printf(CMD_UNLOAD_SOURCE "\n");
189         printf("\t- unloads the source with specific source tag.\n");
190
191         printf(CMD_PLAY_STREAM "\n");
192         printf("\t- creates the stream with unique identifier and starts playback.\n"
193                         "\t  Source tag to be used for stream creation should be specified.\n");
194
195         printf(CMD_STOP_STREAM "\n");
196         printf("\t- stops the stream playback. Stream unique identifier should be\n"
197                         "\t  specified after command. After stopping the stream became invalid.\n");
198
199         printf(CMD_PAUSE_STREAM "\n");
200         printf("\t- pauses the stream playback. Stream unique identifier should be\n"
201                         "\t  specified after command.\n");
202
203         printf(CMD_RESUME_STREAM "\n");
204         printf("\t- resumes the stream was paused before. Stream unique identifier\n"
205                         "\t  should be specified after command.\n");
206
207         printf(CMD_SET_STREAM_VOLUME "\n");
208         printf("\t- use this command to set volume parameter of the stream.\n");
209
210         printf(CMD_GET_STREAM_VOLUME "\n");
211         printf("\t- shows volume of the stream in the pool with specified "
212                         "identifiers.\n");
213
214         printf(CMD_SET_STREAM_PRIORITY "\n");
215         printf("\t- use this command to set priority parameter of the stream. "
216                         "0 is the lowest priority.\n");
217
218         printf(CMD_GET_STREAM_PRIORITY "\n");
219         printf("\t- shows priority rank of the stream in the pool with specified "
220                         "identifiers. 0 is the lowest priority.\n");
221
222         printf(CMD_GET_STREAM_STATE "\n");
223         printf("\t- shows state of the stream in the pool with specified "
224                         "identifiers.\n");
225
226         printf(CMD_EXECUTE_SCRIPT "\n");
227         printf("\t- executes the script from the file in filesystem. Script has to\n"
228                         "\t  be compiled with commands supported by testsuite, one command\n"
229                         "\t  per single line.\n");
230
231         printf(CMD_SLEEP "\n");
232         printf("\t- suspends execution of the main thread for the specific amount "
233                         "of milleseconds.\n");
234
235         printf(CMD_EXIT "\n");
236         printf("\t- exits from the test suite.\n");
237
238         printf("\n");
239
240         return OK;
241 }
242
243 /* CMD_CREATE_POOL */
244 static int __proxy_sound_pool_create()
245 {
246         _logger_log_info(CMD_CREATE_POOL " command was called");
247         _logger_log_info("Creating the pool...");
248
249         sound_pool_h pool = NULL;
250         int ret = sound_pool_create(&pool);
251
252         if (ret == SOUND_POOL_ERROR_NONE) {
253                 _logger_log_info("sound_pool_create(pool) returned %s value",
254                                 __stringify_sound_pool_error(ret));
255
256                 size_t idx = 0;
257                 while (idx < MAX_POOL_CNT) {
258                         if (pools[idx++] == NULL) {
259                                 pools[--idx] = pool;
260                                 break;
261                         }
262                 }
263
264                 if (idx == MAX_POOL_CNT) {
265                         _printf(CMD_COLOR_RED, "Limit of possible pools is exceeded. Destroy "
266                                         "some pools before creating of new ones.\n");
267
268                         _logger_log_warn("Pool can't be created due to test suite "
269                                         "restrictions. Destroying the pool...");
270
271                         ret = sound_pool_destroy(pool);
272
273                         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
274                                         "sound_pool_destroy(pool) returned %s value",
275                                         __stringify_sound_pool_error(ret));
276
277                         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
278                 }
279
280                 if (!pool)
281                         _logger_log_warn("Created pool is NULL");
282                 else
283                         _logger_log_info("Identifier of the pool has been created is %zu", idx);
284         } else {
285                 _logger_log_err("sound_pool_create(pool) returned %s value",
286                                 __stringify_sound_pool_error(ret));
287         }
288
289         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
290 }
291
292 /* CMD_DESTROY_POOL */
293 static int __proxy_sound_pool_destroy(const char *pars)
294 {
295         int ret = SOUND_POOL_ERROR_NONE;
296         size_t idx = 0;
297         if ((pars == NULL) || (sscanf(pars, " %zu", &idx) < 1)) {
298                 _printf(CMD_COLOR_RED, "You have to specify identifier of the pool to be "
299                                 "destroyed after command! Format: " CMD_DESTROY_POOL " <id>\n");
300                 return FAIL;
301         }
302
303         if (idx > (MAX_POOL_CNT - 1)) {
304                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
305                                 MAX_POOL_CNT - 1);
306                 return FAIL;
307         }
308
309         _logger_log_info(CMD_DESTROY_POOL " command was called");
310         _logger_log_info("Destroying the pool by %zu identifier...", idx);
311
312         if (pools[idx] == NULL)
313                 _logger_log_warn("Pool to be destroyed is NULL");
314
315         ret = sound_pool_destroy(pools[idx]);
316
317         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
318                         "sound_pool_destroy(pool) returned %s value",
319                         __stringify_sound_pool_error(ret));
320
321         pools[idx] = NULL;
322
323         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
324 }
325
326 /* CMD_ACTIVATE_POOL */
327 static int __proxy_sound_pool_activate(const char *pars)
328 {
329         int ret = SOUND_POOL_ERROR_NONE;
330         size_t idx = 0;
331         if ((pars == NULL) || (sscanf(pars, " %zu", &idx) < 1)) {
332                 _printf(CMD_COLOR_RED, "You have to specify identifier of the pool "
333                                 "to be activated after command name! Format: "
334                                 CMD_ACTIVATE_POOL " <id>\n");
335                 return FAIL;
336         }
337
338         if (idx > (MAX_POOL_CNT - 1)) {
339                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
340                                 MAX_POOL_CNT - 1);
341                 return FAIL;
342         }
343
344         _logger_log_info(CMD_ACTIVATE_POOL " command was called");
345         _logger_log_info("Activating the pool by %zu identifier...", idx);
346
347         if (pools[idx] == NULL)
348                 _logger_log_warn("Pool to be activated is NULL");
349
350         ret = sound_pool_activate(pools[idx]);
351
352         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
353                         "sound_pool_set_state(pool, SOUND_POOL_STATE_ACTIVE) returned "
354                         "%s value", __stringify_sound_pool_error(ret));
355
356         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
357 }
358
359 /* CMD_DEACTIVATE_POOL */
360 static int __proxy_sound_pool_deactivate(const char *pars)
361 {
362         size_t idx = 0;
363         if ((pars == NULL) || (sscanf(pars, " %zu", &idx) < 1)) {
364                 _printf(CMD_COLOR_RED, "You have to specify identifier of the pool "
365                                 "to be deactivated after command name! Format: "
366                                 CMD_DEACTIVATE_POOL " <id>\n");
367                 return FAIL;
368         }
369
370         if (idx > (MAX_POOL_CNT - 1)) {
371                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
372                                 MAX_POOL_CNT - 1);
373                 return FAIL;
374         }
375
376         _logger_log_info(CMD_DEACTIVATE_POOL " command was called");
377         _logger_log_info("Deactivating the pool by %zu identifier...", idx);
378
379         if (pools[idx] == NULL)
380                 _logger_log_warn("Pool to be deactivated is NULL");
381
382         int ret = sound_pool_deactivate(pools[idx]);
383
384         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
385                         "sound_pool_set_state(pool, SOUND_POOL_STATE_INACTIVE) returned "
386                         "%s value", __stringify_sound_pool_error(ret));
387
388         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
389 }
390
391 /* CMD_GET_POOL_STATE */
392 static int __proxy_sound_pool_get_state(const char *pars)
393 {
394         size_t idx = 0;
395         if ((pars == NULL) || (sscanf(pars, " %zu", &idx) < 1)) {
396                 _printf(CMD_COLOR_RED, "You have to specify identifier of the pool "
397                                 "to get state for, after command name! Format: "
398                                 CMD_GET_POOL_STATE " <id>\n");
399                 return FAIL;
400         }
401
402         if (idx > (MAX_POOL_CNT - 1)) {
403                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
404                                 MAX_POOL_CNT - 1);
405                 return FAIL;
406         }
407
408         _logger_log_info(CMD_GET_POOL_STATE " command was called");
409         _logger_log_info("Getting the pool state by %zu identifier...", idx);
410
411         if (pools[idx] == NULL)
412                 _logger_log_warn("Pool to get state for is NULL");
413
414         sound_pool_state_e state = SOUND_POOL_STATE_INACTIVE;
415         int ret = sound_pool_get_state(pools[idx], &state);
416
417         const char *str_state = (state == SOUND_POOL_STATE_ACTIVE ?
418                         "SOUND_POOL_STATE_ACTIVE" : "SOUND_POOL_STATE_INACTIVE");
419
420         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
421                         "sound_pool_get_state(pool, state) returned %s value,"
422                         " state is %s", __stringify_sound_pool_error(ret), str_state);
423
424         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
425 }
426
427 /* CMD_SET_POOL_VOLUME */
428 static int __proxy_sound_pool_set_volume(const char *pars)
429 {
430         size_t idx = 0;
431         float volume = .0f;
432         if ((pars == NULL) || (sscanf(pars, " %zu %f", &idx, &volume) < 2)) {
433                 _printf(CMD_COLOR_RED, "You have to specify both identifier of the "
434                                 "pool and new volume float value to set volume for whole pool! "
435                                 "Format: " CMD_SET_POOL_VOLUME " <id> <volume>\n");
436                 return FAIL;
437         }
438
439         if (idx > (MAX_POOL_CNT - 1)) {
440                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
441                                 MAX_POOL_CNT - 1);
442                 return FAIL;
443         }
444
445         _logger_log_info(CMD_SET_POOL_VOLUME " command was called");
446         _logger_log_info("Set %f volume value for pool with %zu identifier...",
447                         volume, idx);
448
449         if (pools[idx] == NULL)
450                 _logger_log_warn("Pool to get state for is NULL");
451
452         if (volume < .0f || volume > 1.0f)
453                 _logger_log_warn("Volume is set as %f, not in [0, 1.0] range", volume);
454
455         int ret = sound_pool_set_volume(pools[idx], volume);
456
457         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
458                         "sound_pool_set_global_volume(pool, %f) returned %s value",
459                         volume, __stringify_sound_pool_error(ret));
460
461         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
462 }
463
464 /* CMD_GET_POOL_VOLUME */
465 static int __proxy_sound_pool_get_volume(const char *pars)
466 {
467         size_t idx = 0;
468         if ((pars == NULL) || (sscanf(pars, " %zu", &idx) < 1)) {
469                 _printf(CMD_COLOR_RED, "You have to specify identifier of the pool "
470                                 "to get volume for, after command name! Format: "
471                                 CMD_GET_POOL_VOLUME " <id>\n");
472                 return FAIL;
473         }
474
475         if (idx > (MAX_POOL_CNT - 1)) {
476                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
477                                 MAX_POOL_CNT - 1);
478                 return FAIL;
479         }
480
481         _logger_log_info(CMD_GET_POOL_VOLUME " command was called");
482         _logger_log_info("Getting the pool global volume for pool with %zu "
483                         "identifier...", idx);
484
485         if (pools[idx] == NULL)
486                 _logger_log_warn("Pool to get state for is NULL");
487
488         float volume = .0f;
489         int ret = sound_pool_get_volume(pools[idx], &volume);
490
491         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
492                         "sound_pool_get_global_volume(pool, volume) returned %s value, "
493                         "volume is %f", __stringify_sound_pool_error(ret), volume);
494
495         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
496 }
497
498 /* CMD_SET_POOL_CB_MSG */
499 static int __proxy_sound_pool_set_state_changed_cb_message(const char *pars)
500 {
501         size_t idx = 0;
502
503         char msg[MAX_MSG_LEN] = { '\0' };
504
505         if ((pars == NULL) || (sscanf(pars, " %zu %"MAX_MSG_LEN_STR"[^ ]", &idx, msg) < 2)) {
506                 _printf(CMD_COLOR_RED, "You have to specify both identifier of the "
507                                 "pool and message to be shown each time when state of the pool "
508                                 " is changed! Message should be a single word. Format: "
509                                 CMD_SET_POOL_CB_MSG " <id> <message>\n");
510                 return FAIL;
511         }
512
513         if (idx > (MAX_POOL_CNT - 1)) {
514                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
515                                 MAX_POOL_CNT - 1);
516                 return FAIL;
517         }
518
519         _logger_log_info(CMD_SET_POOL_CB_MSG " command was called");
520         _logger_log_info("Set state changing callback (%s message) for pool with "
521                         "%zu identifier...", msg, idx);
522
523         if (pools[idx] == NULL)
524                 _logger_log_warn("Pool to set callback for is NULL");
525
526         if (messages[idx])
527                 free(messages[idx]);
528         messages[idx] = strndup(msg, MAX_MSG_LEN);
529
530         int ret = sound_pool_set_state_changed_cb(pools[idx], __sp_cb_msg,
531                         messages[idx]);
532
533         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
534                         "sound_pool_set_state_change_callback(pool, cb, \"%s\") "
535                         "returned %s value", msg, __stringify_sound_pool_error(ret));
536
537         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
538 }
539
540 /* CMD_SET_POOL_CB_SCRIPT */
541 static int __proxy_sound_pool_set_state_changed_cb_script(const char *pars)
542 {
543         size_t idx = 0;
544
545         char scr[MAX_MSG_LEN] = { '\0' };
546
547         if ((pars == NULL) || (sscanf(pars, " %zu %"MAX_MSG_LEN_STR"[^ ]", &idx, scr) < 2)) {
548                 _printf(CMD_COLOR_RED, "You have to specify both identifier of the "
549                                 "pool and script file name to be executed each time when state "
550                                 "of the pool will be changed! Format: "
551                                 CMD_SET_POOL_CB_SCRIPT " <id> <script file>\n");
552                 return FAIL;
553         }
554
555         if (idx > (MAX_POOL_CNT - 1)) {
556                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
557                                 MAX_POOL_CNT - 1);
558                 return FAIL;
559         }
560
561         _logger_log_info(CMD_SET_POOL_CB_SCRIPT " command was called");
562         _logger_log_info("Set state changing callback (%s script) for pool with "
563                         "%zu identifier...", scr, idx);
564
565         if (pools[idx] == NULL)
566                 _logger_log_warn("Pool to set callback for is NULL");
567
568         if (scripts[idx])
569                 free(scripts[idx]);
570         scripts[idx] = strndup(scr, MAX_MSG_LEN);
571
572         int ret = sound_pool_set_state_changed_cb(pools[idx], __sp_cb_scr,
573                         scripts[idx]);
574
575         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
576                         "sound_pool_set_state_change_callback(pool, cb, \"%s\") "
577                         "returned %s value", scr, __stringify_sound_pool_error(ret));
578
579         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
580 }
581
582 /* CMD_UNSET_POOL_CB */
583 static int __proxy_sound_pool_unset_state_changed_cb(const char *pars)
584 {
585         size_t idx = 0;
586         if ((pars == NULL) || (sscanf(pars, " %zu", &idx) < 1)) {
587                 _printf(CMD_COLOR_RED, "You have to specify identifier of the pool! "
588                                 "Format: " CMD_UNSET_POOL_CB " <id>\n");
589                 return FAIL;
590         }
591
592         if (idx > (MAX_POOL_CNT - 1)) {
593                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
594                                 MAX_POOL_CNT - 1);
595                 return FAIL;
596         }
597
598         _logger_log_info(CMD_UNSET_POOL_CB " command was called");
599         _logger_log_info("Unset state changing callback for pool with "
600                         "%zu identifier...", idx);
601
602         if (pools[idx] == NULL)
603                 _logger_log_warn("Pool to unset callback for is NULL");
604
605         int ret = sound_pool_unset_state_changed_cb(pools[idx]);
606
607         if (messages[idx] != NULL)
608                 free(messages[idx]);
609         messages[idx] = NULL;
610
611         if (scripts[idx] != NULL)
612                 free(scripts[idx]);
613         scripts[idx] = NULL;
614
615         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
616                         "sound_pool_unset_state_change_callback(pool) "
617                         "returned %s value", __stringify_sound_pool_error(ret));
618
619         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
620 }
621
622 /* CMD_LIST_POOL */
623 static int __proxy_sound_pool_list()
624 {
625         _logger_log_info("Getting the pool identifiers...");
626
627         const size_t buffer_size = 1024;
628         char buffer[buffer_size];
629         buffer[0] = '\0';
630
631         size_t idx = 0;
632         size_t len = 0;
633         while (idx < MAX_POOL_CNT) {
634                 len = strnlen(buffer, buffer_size);
635                 if (pools[idx++] != NULL) {
636                         size_t add_len = 1;
637                         size_t id = idx - 1;
638                         do
639                                 add_len++;
640                         while ((id = id / 10) > 0);
641                         id = idx - 1;
642                         if (len + add_len + 1 > buffer_size)
643                                 break;
644                         snprintf(buffer + len, buffer_size, "%zu ", id);
645                 }
646         }
647
648         _printf(CMD_COLOR_GREEN, "Pools identifiers: %s\n", buffer);
649         _logger_log_info("Pools identifiers: %s", buffer);
650
651         _logger_log_info("Pool identifiers were retrieved...");
652
653         return OK;
654 }
655
656 /* CMD_LOAD_SOURCE */
657 static int __proxy_sound_pool_load_source_from_file(const char *pars)
658 {
659         size_t idx = 0;
660
661         char fname[MAX_PATH_LEN] = {'\0'};
662         char tag[MAX_PATH_LEN] = {'\0'};
663
664         if ((pars == NULL) || sscanf(pars, " %zu %"MAX_PATH_LEN_STR"[^ ] "
665                         "%"MAX_PATH_LEN_STR"[^ ]", &idx, fname, tag) < 2) {
666                 _printf(CMD_COLOR_RED, "You have to specify at least pool identifier and "
667                                 "file name to be loaded! Format: " CMD_LOAD_SOURCE " <pool id> "
668                                 "<file name> <source tag>\n");
669                 return FAIL;
670         }
671
672         if (idx > (MAX_POOL_CNT - 1)) {
673                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
674                                 MAX_POOL_CNT - 1);
675                 return FAIL;
676         }
677
678         if (pools[idx] == NULL)
679                 _logger_log_warn("Pool with specified identifier is NULL");
680
681         /* If tag wasn't specified by the user, we will use file path as a tag */
682         if (tag[0] == '\0') {
683                 strncpy(tag, fname, MAX_PATH_LEN - 1);
684                 tag[MAX_PATH_LEN - 1] = '\0';
685         }
686
687
688         _logger_log_info(CMD_LOAD_SOURCE " command was called");
689         _logger_log_info("Loading source to the pool with %zu identifier from %s file. "
690                         "Tag '%s' will be assigned for the loaded source...", idx, fname, tag);
691
692         int ret = sound_pool_load_source_from_file(pools[idx], fname, tag);
693
694         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
695                         "sound_pool_load_source_from_file(pool, \"%s\", \"%s\") returned "
696                         "%s value", fname, tag, __stringify_sound_pool_error(ret));
697
698         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
699 }
700
701 /* CMD_UNLOAD_SOURCE */
702 static int __proxy_sound_pool_unload_source(const char *pars)
703 {
704         size_t idx = 0;
705
706         char tag[MAX_PATH_LEN] = {'\0'};
707
708         if ((pars == NULL) || sscanf(pars, " %zu %"MAX_PATH_LEN_STR"[^ ]", &idx, tag) < 2) {
709                 _printf(CMD_COLOR_RED, "You have to specify both pool identifier and "
710                                 "source tag to be unloaded! Format: " CMD_UNLOAD_SOURCE
711                                 " <pool id> <source tag>\n");
712                 return FAIL;
713         }
714
715         if (idx > (MAX_POOL_CNT - 1)) {
716                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
717                                 MAX_POOL_CNT - 1);
718                 return FAIL;
719         }
720
721         if (pools[idx] == NULL)
722                 _logger_log_warn("Pool with specified identifier is NULL");
723
724         _logger_log_info(CMD_UNLOAD_SOURCE " command was called");
725         _logger_log_info("Unloading source by '%s' tag from the pool with %zu "
726                         "identifier...", tag, idx);
727
728         int ret = sound_pool_unload_source(pools[idx], tag);
729
730         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
731                         "sound_pool_unload_source(pool, \"%s\") returned "
732                         "%s value", tag, __stringify_sound_pool_error(ret));
733
734         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
735 }
736
737 /* CMD_PLAY_STREAM */
738 static int __proxy_sound_pool_play_stream(const char *pars)
739 {
740         size_t idx = 0;
741         int loop = 0;
742         float volume = 1.0f;
743         unsigned rank = DEFAULT_STREAM_PRIORITY_RANK;
744         sound_pool_stream_priority_policy_e priority_policy = SOUND_POOL_STREAM_PRIORITY_POLICY_MUTE;
745
746         char tag[MAX_PATH_LEN] = {'\0'};
747
748         if ((pars == NULL) || sscanf(pars, " %zu %"MAX_PATH_LEN_STR"[^ ] %i %f %u %u",
749                                                                 &idx, tag, &loop, &volume, &rank, &priority_policy) < 2) {
750                 _printf(CMD_COLOR_RED, "You have to specify at least pool identifier and "
751                                 "source tag to be played in stream! Format: " CMD_PLAY_STREAM
752                                 " <pool id> <source tag> <loop> <volume> <priority rank> <priority_policy>... "
753                                 "0 'priority rank' value corresponds to the lowest priority.\n");
754                 return FAIL;
755         }
756
757         if (idx > (MAX_POOL_CNT - 1)) {
758                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
759                                 MAX_POOL_CNT - 1);
760                 return FAIL;
761         }
762
763         if (pools[idx] == NULL)
764                 _logger_log_warn("Pool with specified identifier is NULL");
765
766         _logger_log_info(CMD_PLAY_STREAM " command was called");
767         _logger_log_info("Playing stream based on source with '%s' tag from the pool "
768                         "with %zu identifier...", tag, idx);
769
770         unsigned stream_idx = 0;
771         int ret = sound_pool_stream_play(pools[idx], tag, loop, volume, rank, priority_policy, __s_cb_msg,
772                         NULL, &stream_idx);
773
774         if (ret == SOUND_POOL_ERROR_NONE) {
775                 _logger_log_info("sound_pool_play_stream(pool, \"%s\", %i, %f, %u,"
776                                 " %u, %p, NULL, &stream_idx) returned %s value. "
777                                 "Generated identifier is %i", tag, loop, volume, rank, priority_policy, __s_cb_msg,
778                                 __stringify_sound_pool_error(ret), stream_idx);
779                 _printf(CMD_COLOR_GREEN, "Generated stream identifier is %i\n", stream_idx);
780         } else {
781                 _logger_log_err("sound_pool_play_stream(pool, \"%s\", %i, %f, %u,"
782                                 " %u, %p, NULL, &stream_idx) returned %s value",
783                                 tag, loop, volume, rank, priority_policy, __s_cb_msg, __stringify_sound_pool_error(ret));
784         }
785
786         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
787 }
788
789 /* CMD_PAUSE_STREAM */
790 static int __proxy_sound_pool_pause_stream(const char *pars)
791 {
792         size_t idx = 0;
793         size_t stream_idx = 0;
794
795         if ((pars == NULL) || (sscanf(pars, " %zu %i", &idx, &stream_idx) < 2)) {
796                 _printf(CMD_COLOR_RED, "You have to specify both pool identifier and "
797                                 "stream to be paused identifier! Format: " CMD_PAUSE_STREAM
798                                 " <pool id> <stream id>\n");
799                 return FAIL;
800         }
801
802         if (idx > (MAX_POOL_CNT - 1)) {
803                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
804                                 MAX_POOL_CNT - 1);
805                 return FAIL;
806         }
807
808         if (pools[idx] == NULL)
809                 _logger_log_warn("Pool with specified identifier is NULL");
810
811         _logger_log_info(CMD_PAUSE_STREAM " command was called");
812
813         int ret = sound_pool_stream_pause(pools[idx], stream_idx);
814
815         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
816                         "sound_pool_pause_stream(pool, %i) returned %s value",
817                         stream_idx, __stringify_sound_pool_error(ret));
818
819         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
820 }
821
822 /* CMD_RESUME_STREAM */
823 static int __proxy_sound_pool_resume_stream(const char *pars)
824 {
825         size_t idx = 0;
826         size_t stream_idx = 0;
827
828         if ((pars == NULL) || (sscanf(pars, " %zu %i", &idx, &stream_idx) < 2)) {
829                 _printf(CMD_COLOR_RED, "You have to specify both pool identifier and "
830                                 "stream to be resumed identifier! Format: " CMD_RESUME_STREAM
831                                 " <pool id> <stream id>\n");
832                 return FAIL;
833         }
834
835         if (idx > (MAX_POOL_CNT - 1)) {
836                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
837                                 MAX_POOL_CNT - 1);
838                 return FAIL;
839         }
840
841         if (pools[idx] == NULL)
842                 _logger_log_warn("Pool with specified identifier is NULL");
843
844         _logger_log_info(CMD_RESUME_STREAM " command was called");
845
846         int ret = sound_pool_stream_resume(pools[idx], stream_idx);
847
848         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
849                         "sound_pool_resume_stream(pool, %i) returned %s value",
850                         stream_idx, __stringify_sound_pool_error(ret));
851
852         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
853 }
854
855 /* CMD_STOP_STREAM */
856 static int __proxy_sound_pool_stop_stream(const char *pars)
857 {
858         size_t idx = 0;
859         size_t stream_idx = 0;
860
861         if ((pars == NULL) || (sscanf(pars, " %zu %zu", &idx, &stream_idx) < 2)) {
862                 _printf(CMD_COLOR_RED, "You have to specify both pool identifier and "
863                                 "stream to be stopped identifier! Format: " CMD_STOP_STREAM
864                                 " <pool id> <stream id>\n");
865                 return FAIL;
866         }
867
868         if (idx > (MAX_POOL_CNT - 1)) {
869                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
870                                 MAX_POOL_CNT - 1);
871                 return FAIL;
872         }
873
874         if (pools[idx] == NULL)
875                 _logger_log_warn("Pool with specified identifier is NULL");
876
877         _logger_log_info(CMD_STOP_STREAM " command was called");
878
879         int ret = sound_pool_stream_stop(pools[idx], stream_idx);
880
881         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
882                         "sound_pool_stop_stream(pool, %i) returned %s value",
883                         stream_idx, __stringify_sound_pool_error(ret));
884
885         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
886 }
887
888 /* CMD_SET_STREAM_VOLUME */
889 static int __proxy_sound_pool_stream_set_volume(const char *pars)
890 {
891         size_t idx = 0;
892         size_t stream_idx = 0;
893         float volume_val = 1.0f;
894
895         if ((pars == NULL)
896                         || (sscanf(pars, " %zu %zu %f", &idx, &stream_idx, &volume_val) < 3)) {
897                 _printf(CMD_COLOR_RED, "You have to specify all following parameters: "
898                                 "pool identifier, stream identifier! Format: "
899                                 CMD_SET_STREAM_VOLUME " <pool id> <stream id> <volume>\n");
900                 return FAIL;
901         }
902
903         if (idx > (MAX_POOL_CNT - 1)) {
904                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
905                                 MAX_POOL_CNT - 1);
906                 return FAIL;
907         }
908
909         if (pools[idx] == NULL)
910                 _logger_log_warn("Pool with specified identifier is NULL");
911
912         if (volume_val < .0f || volume_val > 1.0f)
913                 _logger_log_warn("Volume has to be specified in 0.0~1.0 range");
914
915         _logger_log_info(CMD_SET_STREAM_VOLUME " command was called");
916
917         int ret = sound_pool_stream_set_volume(pools[idx], stream_idx, volume_val);
918
919         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
920                         "sound_pool_stream_set_volume(pool, %i, %f) returned %s value",
921                         stream_idx, volume_val, __stringify_sound_pool_error(ret));
922
923         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
924 }
925
926 /* CMD_GET_STREAM_VOLUME */
927 static int __proxy_sound_pool_stream_get_volume(const char *pars)
928 {
929         size_t idx = 0;
930         size_t stream_idx = 0;
931         if ((pars == NULL) || (sscanf(pars, " %zu %zu", &idx, &stream_idx) < 2)) {
932                 _printf(CMD_COLOR_RED, "You have to specify both pool and stream "
933                                 "identifiers after command name! Format: "
934                                 CMD_GET_STREAM_VOLUME " <pool id> <stream id>\n");
935                 return FAIL;
936         }
937
938         if (idx > (MAX_POOL_CNT - 1)) {
939                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
940                                 MAX_POOL_CNT - 1);
941                 return FAIL;
942         }
943
944         _logger_log_info(CMD_GET_STREAM_VOLUME " command was called");
945         _logger_log_info("Getting the %zu stream from %zu pool volume value...",
946                         stream_idx, idx);
947
948         if (pools[idx] == NULL)
949                 _logger_log_warn("Pool to get state for is NULL");
950
951         float volume = .0f;
952         int ret = sound_pool_stream_get_volume(pools[idx], stream_idx, &volume);
953
954         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
955                         "sound_pool_stream_get_volume(pool, %zu, volume) returned %s value, "
956                         "volume is %f", stream_idx, __stringify_sound_pool_error(ret), volume);
957
958         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
959 }
960
961 /* CMD_SET_STREAM_PRIORITY */
962 static int __proxy_sound_pool_stream_set_priority(const char *pars)
963 {
964         size_t idx = 0;
965         size_t stream_idx = 0;
966         unsigned rank = 0;
967
968         if ((pars == NULL)
969                         || (sscanf(pars, " %zu %zu %u", &idx, &stream_idx, &rank) < 3)) {
970                 _printf(CMD_COLOR_RED, "You have to specify all following parameters: "
971                                 "pool identifier, stream identifier, and priority rank! Format: "
972                                 CMD_SET_STREAM_PRIORITY " <pool id> <stream id> <rank>\n");
973                 return FAIL;
974         }
975
976         if (idx > (MAX_POOL_CNT - 1)) {
977                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
978                                 MAX_POOL_CNT - 1);
979                 return FAIL;
980         }
981
982         if (pools[idx] == NULL)
983                 _logger_log_warn("Pool with specified identifier is NULL");
984
985         _logger_log_info(CMD_SET_STREAM_PRIORITY " command was called");
986
987         int ret = sound_pool_stream_set_priority(pools[idx], stream_idx, rank);
988
989         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
990                         "sound_pool_stream_set_priority(pool, %zu, %u) returned %s value",
991                         stream_idx, rank, __stringify_sound_pool_error(ret));
992
993         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
994 }
995
996 /* CMD_GET_STREAM_PRIORITY */
997 static int __proxy_sound_pool_stream_get_priority(const char *pars)
998 {
999         size_t idx = 0;
1000         size_t stream_idx = 0;
1001         if ((pars == NULL) || (sscanf(pars, " %zu %zu", &idx, &stream_idx) < 2)) {
1002                 _printf(CMD_COLOR_RED, "You have to specify both pool and stream "
1003                                 "identifiers after command name! Format: "
1004                                 CMD_GET_STREAM_PRIORITY " <pool id> <stream id>\n");
1005                 return FAIL;
1006         }
1007
1008         if (idx > (MAX_POOL_CNT - 1)) {
1009                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
1010                                 MAX_POOL_CNT - 1);
1011                 return FAIL;
1012         }
1013
1014         _logger_log_info(CMD_GET_STREAM_PRIORITY " command was called");
1015         _logger_log_info("Getting the stream priority rank by %zu identifier in "
1016                         "%zu pool...", stream_idx, idx);
1017
1018         if (pools[idx] == NULL)
1019                 _logger_log_warn("Pool where stream should be located is NULL");
1020
1021         unsigned rank = 0;
1022         int ret = sound_pool_stream_get_priority(pools[idx], stream_idx, &rank);
1023
1024         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
1025                         "sound_pool_stream_get_priority(pool, %u, rank) returned %s value, "
1026                         "rank value is %u", stream_idx, __stringify_sound_pool_error(ret), rank);
1027
1028         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
1029 }
1030
1031 /* CMD_GET_STREAM_STATE */
1032 static int __proxy_sound_pool_get_stream_state(const char *pars)
1033 {
1034         size_t idx = 0;
1035         size_t stream_idx = 0;
1036         if ((pars == NULL) || (sscanf(pars, " %zu %zu", &idx, &stream_idx) < 2)) {
1037                 _printf(CMD_COLOR_RED, "You have to specify both pool and stream "
1038                                 "identifiers after command name! Format: "
1039                                 CMD_GET_STREAM_STATE " <pool id> <stream id>\n");
1040                 return FAIL;
1041         }
1042
1043         if (idx > (MAX_POOL_CNT - 1)) {
1044                 _printf(CMD_COLOR_RED, "Pool identifier value can't be greater than %d\n",
1045                                 MAX_POOL_CNT - 1);
1046                 return FAIL;
1047         }
1048
1049         _logger_log_info(CMD_GET_STREAM_STATE " command was called");
1050         _logger_log_info("Getting the stream state by %zu identifier in %zu "
1051                         "pool...", stream_idx, idx);
1052
1053         if (pools[idx] == NULL)
1054                 _logger_log_warn("Pool where stream should be located is NULL");
1055
1056         sound_pool_stream_state_e state = SOUND_POOL_STREAM_STATE_NONE;
1057         int ret = sound_pool_stream_get_state(pools[idx], stream_idx,  &state);
1058
1059         PRINT_INFO_OR_ERROR_INFO(ret == SOUND_POOL_ERROR_NONE,
1060                         "sound_pool_get_stream_state(pool, %zu, state) returned %s value, "
1061                         "state is %s", stream_idx, __stringify_sound_pool_error(ret),
1062                         __stringify_stream_state(state));
1063
1064         return (ret == SOUND_POOL_ERROR_NONE ? OK : FAIL);
1065 }
1066
1067 /* CMD_SLEEP */
1068 static int __proxy_sleep(const char *pars)
1069 {
1070         useconds_t stime = 0;
1071
1072         if ((pars == NULL) || (sscanf(pars, " %u", &stime) < 1)) {
1073                 _printf(CMD_COLOR_RED, "You have to specify number of milliseconds "
1074                                 "for the pause duration! Format: " CMD_SLEEP " <millisecs>\n");
1075                 return FAIL;
1076         }
1077
1078         _logger_log_info(CMD_SLEEP " command was called");
1079         _logger_log_info("Start main thread sleep for %u milliseconds...", stime);
1080         stime *= MICROSECS_PER_MILLISEC;
1081         usleep(stime);
1082         _logger_log_info("Main thread sleep has been finished...", stime);
1083
1084         return OK;
1085 }
1086
1087 /* CMD_EXECUTE_SCRIPT */
1088 static int __proxy_sound_pool_execute_script(const char *pars)
1089 {
1090         char script_file[MAX_PATH_LEN] = {'\0'};
1091
1092         if ((pars == NULL) || (sscanf(pars, " %"MAX_PATH_LEN_STR"[^ ]", script_file) < 1)) {
1093                 _printf(CMD_COLOR_RED, "You have to specify script file name to be "
1094                                 "executed after command name! Format: " CMD_EXECUTE_SCRIPT " "
1095                                 "<script file>\n");
1096                 return FAIL;
1097         }
1098
1099         _logger_log_info(CMD_EXECUTE_SCRIPT " command was called");
1100         _logger_log_info("Loading script from file...");
1101         FILE *fd = fopen(script_file, "r");
1102
1103         if (fd) {
1104                 _logger_log_info("File has been loaded...");
1105                 _logger_log_info("Reading lines...");
1106                 size_t line_len = 0;
1107                 char *line = NULL;
1108                 while ((line_len = getline(&line, &line_len, fd)) != -1) {
1109                         line[strnlen(line, MAX_COMMAND_LINE_LEN) - 1] = '\0';
1110                         _logger_log_info("Executing line: %s", line);
1111                         if (_exec_cmd(line) != OK)
1112                                 _logger_log_warn("Unknown or unsupported command! "
1113                                                 "Line was skipped.");
1114                 }
1115                 _logger_log_info("Lines were read...");
1116                 if (line)
1117                     free(line);
1118         } else {
1119                 _logger_log_err("File wasn't loaded...");
1120                 return FAIL;
1121         }
1122
1123         _logger_log_info("Close file...");
1124
1125         if (fd)
1126                 fclose(fd);
1127
1128         return OK;
1129 }
1130
1131 /* Number of parameters supported by each command */
1132 static int cmd_pars[MAX_COMMAND_LINE_LEN] = { /* CMD_EXIT */ 0,
1133                 /* CMD_HELP */ 0, /* CMD_CREATE_POOL */ 0, /* CMD_DESTROY_POOL */ 1,
1134                 /* CMD_ACTIVATE_POOL */ 1, /* CMD_DEACTIVATE_POOL */ 1,
1135                 /* CMD_GET_POOL_STATE */ 1, /* CMD_SET_POOL_VOLUME */ 2,
1136                 /* CMD_GET_POOL_VOLUME */ 2, /* CMD_SET_POOL_CB_MSG */ 2,
1137                 /* CMD_SET_POOL_CB_SCRIPT */ 2, /* CMD_UNSET_POOL_CB */ 1,
1138                 /* CMD_LIST_POOL */ 0, /* CMD_LOAD_SOURCE */ 3,
1139                 /* CMD_LOAD_MEDIA_PACKAGE */ 3, /* CMD_UNLOAD_SOURCE */ 2,
1140                 /* CMD_PLAY_STREAM */ 5, /* CMD_STOP_STREAM */ 2,
1141                 /* CMD_PAUSE_STREAM */ 2, /* CMD_RESUME_STREAM */ 2,
1142                 /* CMD_SET_STREAM_VOLUME */ 3, /* CMD_GET_STREAM_VOLUME */ 2,
1143                 /* CMD_SET_STREAM_PRIORITY */ 3, /* CMD_GET_STREAM_PRIORITY */ 2,
1144                 /* CMD_GET_STREAM_STATE */ 2, /* CMD_SET_STREAM_CB_MSG */ 3,
1145                 /* CMD_SET_STREAM_CB_SCRIPT */ 3, /* CMD_UNSET_STREAM_CB */ 2,
1146                 /* CMD_EXECUTE_SCRIPT */ 1, /* CMD_SLEEP */ 1 };
1147
1148 /* Command -> Function mapping */
1149 static int (*cmd_fcns[MAX_COMMAND_LINE_LEN])() = {
1150                 /* CMD_EXIT */ __exit,
1151                 /* CMD_HELP */ __print_cmd_help_msg,
1152                 /* CMD_CREATE_POOL */ __proxy_sound_pool_create,
1153                 /* CMD_DESTROY_POOL */ __proxy_sound_pool_destroy,
1154                 /* CMD_ACTIVATE_POOL */ __proxy_sound_pool_activate,
1155                 /* CMD_DEACTIVATE_POOL */ __proxy_sound_pool_deactivate,
1156                 /* CMD_GET_POOL_STATE */ __proxy_sound_pool_get_state,
1157                 /* CMD_SET_POOL_VOLUME */ __proxy_sound_pool_set_volume,
1158                 /* CMD_GET_POOL_VOLUME */ __proxy_sound_pool_get_volume,
1159                 /* CMD_SET_POOL_CB_MSG */ __proxy_sound_pool_set_state_changed_cb_message,
1160                 /* CMD_SET_POOL_CB_SCRIPT */ __proxy_sound_pool_set_state_changed_cb_script,
1161                 /* CMD_UNSET_POOL_CB */ __proxy_sound_pool_unset_state_changed_cb,
1162                 /* CMD_LIST_POOL */ __proxy_sound_pool_list,
1163                 /* CMD_LOAD_SOURCE */ __proxy_sound_pool_load_source_from_file,
1164                 /* CMD_LOAD_MEDIA_PACKAGE */ NULL,
1165                 /* CMD_UNLOAD_SOURCE */ __proxy_sound_pool_unload_source,
1166                 /* CMD_PLAY_STREAM */ __proxy_sound_pool_play_stream,
1167                 /* CMD_STOP_STREAM */ __proxy_sound_pool_stop_stream,
1168                 /* CMD_PAUSE_STREAM */ __proxy_sound_pool_pause_stream,
1169                 /* CMD_RESUME_STREAM */ __proxy_sound_pool_resume_stream,
1170                 /* CMD_SET_STREAM_VOLUME */ __proxy_sound_pool_stream_set_volume,
1171                 /* CMD_GET_STREAM_VOLUME */ __proxy_sound_pool_stream_get_volume,
1172                 /* CMD_SET_STREAM_PRIORITY */ __proxy_sound_pool_stream_set_priority,
1173                 /* CMD_GET_STREAM_PRIORITY */ __proxy_sound_pool_stream_get_priority,
1174                 /* CMD_GET_STREAM_STATE */ __proxy_sound_pool_get_stream_state,
1175                 /* CMD_EXECUTE_SCRIPT */ __proxy_sound_pool_execute_script,
1176                 /* CMD_SLEEP */ __proxy_sleep };
1177
1178 int _exec_cmd(const char *cmd_line)
1179 {
1180         /* User just pressed enter: */
1181         if (strlen(cmd_line) == 0) return OK;
1182
1183         size_t trim_len = 0;
1184         while ((cmd_line + trim_len)[0] == ' ')
1185                 trim_len++;
1186
1187         const char *cmd = cmd_line + trim_len;
1188
1189         /* Macro for checking command correctness */
1190 #   define CHECK_CMD(ccmd, line) \
1191                         (strncmp(ccmd, line, strnlen(ccmd, MAX_COMMAND_LINE_LEN)) == 0)
1192
1193         int idx = 0;
1194         for (; idx < CMD_COUNT; ++idx) {
1195                 if (CHECK_CMD(cmd_list[idx], cmd)) {
1196                         if (cmd_pars[idx] > 0) {
1197                                 if (cmd_fcns[idx])
1198                                         return cmd_fcns[idx](cmd + strlen(cmd_list[idx]));
1199                         } else {
1200                                 return cmd_fcns[idx]();
1201                         }
1202                 }
1203         }
1204
1205         return UCMD;
1206 }