Add sound manager initial source code
[staging/soundmanager.git] / sample / radio_qml / binding / radio-binding.c
1 /*
2  * Copyright (C) 2017 Konsulko Group
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 #define _GNU_SOURCE
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdint.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24
25 #include <json-c/json.h>
26 #include <afb/afb-binding.h>
27 #include <afb/afb-service-itf.h>
28
29 #include "radio_impl.h"
30
31 static const struct afb_binding_interface *interface;
32
33 static struct afb_event freq_event;
34 static struct afb_event scan_event;
35
36 static void freq_callback(uint32_t frequency, void *data)
37 {
38         json_object *jresp = json_object_new_object();
39         json_object *value = json_object_new_int((int) frequency);
40
41         json_object_object_add(jresp, "value", value);
42         afb_event_push(freq_event, json_object_get(jresp));
43 }
44
45 static void scan_callback(uint32_t frequency, void *data)
46 {
47         json_object *jresp = json_object_new_object();
48         json_object *value = json_object_new_int((int) frequency);
49
50         json_object_object_add(jresp, "value", value);
51         afb_event_push(scan_event, json_object_get(jresp));
52 }
53
54 /*
55  * Binding verb handlers
56  */
57
58 /*
59  * @brief Get (and optionally set) frequency
60  *
61  * @param struct afb_req : an afb request structure
62  *
63  */
64 static void frequency(struct afb_req request)
65 {
66         json_object *ret_json;
67         const char *value = afb_req_value(request, "value");
68         uint32_t frequency;
69
70         if(value) {
71                 char *p;
72                 frequency = strtoul(value, &p, 10);
73                 if(frequency && *p == '\0') {
74                         radio_impl_set_frequency(frequency);
75                 } else {
76                         afb_req_fail(request, "failed", "Invalid scan direction");
77                         return;
78                 }
79         }
80         ret_json = json_object_new_object();
81         frequency = radio_impl_get_frequency();
82         json_object_object_add(ret_json, "frequency", json_object_new_int((int32_t) frequency));
83         afb_req_success(request, ret_json, NULL);
84 }
85
86 /*
87  * @brief Get (and optionally set) frequency band
88  *
89  * @param struct afb_req : an afb request structure
90  *
91  */
92 static void band(struct afb_req request)
93 {
94         json_object *ret_json;
95         const char *value = afb_req_value(request, "value");
96         int valid = 0;
97         radio_band_t band;
98         char band_name[4];
99
100         if(value) {
101                 if(!strcasecmp(value, "AM")) {
102                         band = BAND_AM;
103                         valid = 1;
104                 } else if(!strcasecmp(value, "FM")) {
105                         band = BAND_FM;
106                         valid = 1;
107                 } else {
108                         char *p;
109                         band = strtoul(value, &p, 10);
110                         if(p != value && *p == '\0') {
111                                 switch(band) {
112                                 case BAND_AM:
113                                 case BAND_FM:
114                                         valid = 1;
115                                         break;
116                                 default:
117                                         break;
118                                 }
119                         }
120                 }
121                 if(valid) {
122                         radio_impl_set_band(band);
123                 } else {
124                         afb_req_fail(request, "failed", "Invalid band");
125                         return;
126                 }
127         }
128         ret_json = json_object_new_object();
129         band = radio_impl_get_band();
130         sprintf(band_name, "%s", band == BAND_AM ? "AM" : "FM");
131         json_object_object_add(ret_json, "band", json_object_new_string(band_name));
132         afb_req_success(request, ret_json, NULL);
133 }
134
135 /*
136  * @brief Check if band is supported
137  *
138  * @param struct afb_req : an afb request structure
139  *
140  */
141 static void band_supported(struct afb_req request)
142 {
143         json_object *ret_json;
144         const char *value = afb_req_value(request, "band");
145         int valid = 0;
146         radio_band_t band;
147
148         if(value) {
149                 if(!strcasecmp(value, "AM")) {
150                         band = BAND_AM;
151                         valid = 1;
152                 } else if(!strcasecmp(value, "FM")) {
153                         band = BAND_FM;
154                         valid = 1;
155                 } else {
156                         char *p;
157                         band = strtoul(value, &p, 10);
158                         if(p != value && *p == '\0') {
159                                 switch(band) {
160                                 case BAND_AM:
161                                 case BAND_FM:
162                                         valid = 1;
163                                         break;
164                                 default:
165                                         break;
166                                 }
167                         }
168                 }
169         }
170         if(!valid) {
171                 afb_req_fail(request, "failed", "Invalid band");
172                 return;
173         }
174         ret_json = json_object_new_object();
175         json_object_object_add(ret_json,
176                                "supported",
177                                json_object_new_int(radio_impl_band_supported(band)));
178         afb_req_success(request, ret_json, NULL);
179 }
180
181 /*
182  * @brief Get frequency range for a band
183  *
184  * @param struct afb_req : an afb request structure
185  *
186  */
187 static void frequency_range(struct afb_req request)
188 {
189         json_object *ret_json;
190         const char *value = afb_req_value(request, "band");
191         int valid = 0;
192         radio_band_t band;
193         uint32_t min_frequency;
194         uint32_t max_frequency;
195
196         if(value) {
197                 if(!strcasecmp(value, "AM")) {
198                         band = BAND_AM;
199                         valid = 1;
200                 } else if(!strcasecmp(value, "FM")) {
201                         band = BAND_FM;
202                         valid = 1;
203                 } else {
204                         char *p;
205                         band = strtoul(value, &p, 10);
206                         if(p != value && *p == '\0') {
207                                 switch(band) {
208                                 case BAND_AM:
209                                 case BAND_FM:
210                                         valid = 1;
211                                         break;
212                                 default:
213                                         break;
214                                 }
215                         }
216                 }
217         }
218         if(!valid) {
219                 afb_req_fail(request, "failed", "Invalid band");
220                 return;
221         }
222         ret_json = json_object_new_object();
223         min_frequency = radio_impl_get_min_frequency(band);
224         max_frequency = radio_impl_get_max_frequency(band);
225         json_object_object_add(ret_json, "min", json_object_new_int((int32_t) min_frequency));
226         json_object_object_add(ret_json, "max", json_object_new_int((int32_t) max_frequency));
227         afb_req_success(request, ret_json, NULL);
228 }
229
230 /*
231  * @brief Get frequency step size (Hz) for a band
232  *
233  * @param struct afb_req : an afb request structure
234  *
235  */
236 static void frequency_step(struct afb_req request)
237 {
238         json_object *ret_json;
239         const char *value = afb_req_value(request, "band");
240         int valid = 0;
241         radio_band_t band;
242         uint32_t step;
243
244         if(value) {
245                 if(!strcasecmp(value, "AM")) {
246                         band = BAND_AM;
247                         valid = 1;
248                 } else if(!strcasecmp(value, "FM")) {
249                         band = BAND_FM;
250                         valid = 1;
251                 } else {
252                         char *p;
253                         band = strtoul(value, &p, 10);
254                         if(p != value && *p == '\0') {
255                                 switch(band) {
256                                 case BAND_AM:
257                                 case BAND_FM:
258                                         valid = 1;
259                                         break;
260                                 default:
261                                         break;
262                                 }
263                         }
264                 }
265         }
266         if(!valid) {
267                 afb_req_fail(request, "failed", "Invalid band");
268                 return;
269         }
270         ret_json = json_object_new_object();
271         step = radio_impl_get_frequency_step(band);
272         json_object_object_add(ret_json, "step", json_object_new_int((int32_t) step));
273         afb_req_success(request, ret_json, NULL);
274 }
275
276 /*
277  * @brief Start radio playback
278  *
279  * @param struct afb_req : an afb request structure
280  *
281  */
282 static void start(struct afb_req request)
283 {
284         radio_impl_start();
285         afb_req_success(request, NULL, NULL);
286 }
287
288 /*
289  * @brief Stop radio playback
290  *
291  * @param struct afb_req : an afb request structure
292  *
293  */
294 static void stop(struct afb_req request)
295 {
296         radio_impl_stop();
297         afb_req_success(request, NULL, NULL);
298 }
299
300 /*
301  * @brief Scan for a station in the specified direction
302  *
303  * @param struct afb_req : an afb request structure
304  *
305  */
306 static void scan_start(struct afb_req request)
307 {
308         json_object *ret_json;
309         const char *value = afb_req_value(request, "direction");
310         int valid = 0;
311         radio_scan_direction_t direction;
312
313         if(value) {
314                 if(!strcasecmp(value, "forward")) {
315                         direction = SCAN_FORWARD;
316                         valid = 1;
317                 } else if(!strcasecmp(value, "backward")) {
318                         direction = SCAN_BACKWARD;
319                         valid = 1;
320                 } else {
321                         char *p;
322                         direction = strtoul(value, &p, 10);
323                         if(p != value && *p == '\0') {
324                                 switch(direction) {
325                                 case SCAN_FORWARD:
326                                 case SCAN_BACKWARD:
327                                         valid = 1;
328                                         break;
329                                 default:
330                                         break;
331                                 }
332                         }
333                 }
334         }
335         if(!valid) {
336                 afb_req_fail(request, "failed", "Invalid direction");
337                 return;
338         }
339         radio_impl_scan_start(direction, scan_callback, NULL);
340         afb_req_success(request, ret_json, NULL);
341 }
342
343 /*
344  * @brief Stop station scan
345  *
346  * @param struct afb_req : an afb request structure
347  *
348  */
349 static void scan_stop(struct afb_req request)
350 {
351         radio_impl_scan_stop();
352         afb_req_success(request, NULL, NULL);
353 }
354
355 /*
356  * @brief Get (and optionally set) stereo mode
357  *
358  * @param struct afb_req : an afb request structure
359  *
360  */
361 static void stereo_mode(struct afb_req request)
362 {
363         json_object *ret_json;
364         const char *value = afb_req_value(request, "value");
365         int valid = 0;
366         radio_stereo_mode_t mode;
367         char mode_name[4];
368
369         if(value) {
370                 if(!strcasecmp(value, "mono")) {
371                         mode = MONO;
372                         valid = 1;
373                 } else if(!strcasecmp(value, "stereo")) {
374                         mode = STEREO;
375                         valid = 1;
376                 } else {
377                         char *p;
378                         mode = strtoul(value, &p, 10);
379                         if(p != value && *p == '\0') {
380                                 switch(mode) {
381                                 case MONO:
382                                 case STEREO:
383                                         valid = 1;
384                                         break;
385                                 default:
386                                         break;
387                                 }
388                         }
389                 }
390                 if(valid) {
391                         radio_impl_set_stereo_mode(mode);
392                 } else {
393                         afb_req_fail(request, "failed", "Invalid mode");
394                         return;
395                 }
396         }
397         ret_json = json_object_new_object();
398         mode = radio_impl_get_stereo_mode();
399         sprintf(mode_name, "%s", mode == MONO ? "mono" : "stereo");
400         json_object_object_add(ret_json, "mode", json_object_new_string(mode_name));
401         afb_req_success(request, ret_json, NULL);
402 }
403
404 /*
405  * @brief Subscribe for an event
406  *
407  * @param struct afb_req : an afb request structure
408  *
409  */
410 static void subscribe(struct afb_req request)
411 {
412         const char *value = afb_req_value(request, "value");
413         if(value) {
414                 if(!strcasecmp(value, "frequency")) {
415                         afb_req_subscribe(request, freq_event);
416                 } else if(!strcasecmp(value, "station_found")) {
417                         afb_req_subscribe(request, scan_event);
418                 } else {
419                         afb_req_fail(request, "failed", "Invalid event");
420                         return;
421                 }
422         }
423         afb_req_success(request, NULL, NULL);
424 }
425
426 /*
427  * @brief Unsubscribe for an event
428  *
429  * @param struct afb_req : an afb request structure
430  *
431  */
432 static void unsubscribe(struct afb_req request)
433 {
434         const char *value = afb_req_value(request, "value");
435         if(value) {
436                 if(!strcasecmp(value, "frequency")) {
437                         afb_req_unsubscribe(request, freq_event);
438                 } else if(!strcasecmp(value, "station_found")) {
439                         afb_req_unsubscribe(request, scan_event);
440                 } else {
441                         afb_req_fail(request, "failed", "Invalid event");
442                         return;
443                 }
444         }
445         afb_req_success(request, NULL, NULL);
446 }
447
448 static const struct afb_verb_desc_v1 verbs[]= {
449         { "frequency",          AFB_SESSION_CHECK, frequency,           "Get/Set frequency" },
450         { "band",               AFB_SESSION_CHECK, band,                "Get/Set band" },
451         { "band_supported",     AFB_SESSION_CHECK, band_supported,      "Check band support" },
452         { "frequency_range",    AFB_SESSION_CHECK, frequency_range,     "Get frequency range" },
453         { "frequency_step",     AFB_SESSION_CHECK, frequency_step,      "Get frequency step" },
454         { "start",              AFB_SESSION_CHECK, start,               "Start radio playback" },
455         { "stop",               AFB_SESSION_CHECK, stop,                "Stop radio playback" },
456         { "scan_start",         AFB_SESSION_CHECK, scan_start,          "Start station scan" },
457         { "scan_stop",          AFB_SESSION_CHECK, scan_stop,           "Stop station scan" },
458         { "stereo_mode",        AFB_SESSION_CHECK, stereo_mode,         "Get/Set stereo_mode" },
459         { "subscribe",          AFB_SESSION_CHECK, subscribe,           "Subscribe for an event" },
460         { "unsubscribe",        AFB_SESSION_CHECK, unsubscribe,         "Unsubscribe for an event" },
461         { NULL }
462 };
463
464 static const struct afb_binding binding_desc = {
465         .type = AFB_BINDING_VERSION_1,
466         .v1 = {
467                 .info = "radio service",
468                 .prefix = "radio",
469                 .verbs = verbs
470         }
471 };
472
473 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
474 {
475         interface = itf;
476
477         return &binding_desc;
478 }
479
480 int afbBindingV1ServiceInit(struct afb_service service)
481 {
482         int rc;
483
484         freq_event = afb_daemon_make_event(interface->daemon, "frequency");
485         scan_event = afb_daemon_make_event(interface->daemon, "station_found");
486
487         rc = radio_impl_init();
488         if(rc == 0) {
489                 radio_impl_set_frequency_callback(freq_callback, NULL);
490         }
491         
492         return rc;
493 }