Add sound manager initial source code
[staging/soundmanager.git] / sample / radio_qml / binding / radio-binding.c
diff --git a/sample/radio_qml/binding/radio-binding.c b/sample/radio_qml/binding/radio-binding.c
new file mode 100644 (file)
index 0000000..12ed966
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2017 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <json-c/json.h>
+#include <afb/afb-binding.h>
+#include <afb/afb-service-itf.h>
+
+#include "radio_impl.h"
+
+static const struct afb_binding_interface *interface;
+
+static struct afb_event freq_event;
+static struct afb_event scan_event;
+
+static void freq_callback(uint32_t frequency, void *data)
+{
+       json_object *jresp = json_object_new_object();
+       json_object *value = json_object_new_int((int) frequency);
+
+       json_object_object_add(jresp, "value", value);
+       afb_event_push(freq_event, json_object_get(jresp));
+}
+
+static void scan_callback(uint32_t frequency, void *data)
+{
+       json_object *jresp = json_object_new_object();
+       json_object *value = json_object_new_int((int) frequency);
+
+       json_object_object_add(jresp, "value", value);
+       afb_event_push(scan_event, json_object_get(jresp));
+}
+
+/*
+ * Binding verb handlers
+ */
+
+/*
+ * @brief Get (and optionally set) frequency
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void frequency(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "value");
+       uint32_t frequency;
+
+       if(value) {
+               char *p;
+               frequency = strtoul(value, &p, 10);
+               if(frequency && *p == '\0') {
+                       radio_impl_set_frequency(frequency);
+               } else {
+                       afb_req_fail(request, "failed", "Invalid scan direction");
+                       return;
+               }
+       }
+       ret_json = json_object_new_object();
+       frequency = radio_impl_get_frequency();
+       json_object_object_add(ret_json, "frequency", json_object_new_int((int32_t) frequency));
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Get (and optionally set) frequency band
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void band(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "value");
+       int valid = 0;
+       radio_band_t band;
+       char band_name[4];
+
+       if(value) {
+               if(!strcasecmp(value, "AM")) {
+                       band = BAND_AM;
+                       valid = 1;
+               } else if(!strcasecmp(value, "FM")) {
+                       band = BAND_FM;
+                       valid = 1;
+               } else {
+                       char *p;
+                       band = strtoul(value, &p, 10);
+                       if(p != value && *p == '\0') {
+                               switch(band) {
+                               case BAND_AM:
+                               case BAND_FM:
+                                       valid = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+               if(valid) {
+                       radio_impl_set_band(band);
+               } else {
+                       afb_req_fail(request, "failed", "Invalid band");
+                       return;
+               }
+       }
+       ret_json = json_object_new_object();
+       band = radio_impl_get_band();
+       sprintf(band_name, "%s", band == BAND_AM ? "AM" : "FM");
+       json_object_object_add(ret_json, "band", json_object_new_string(band_name));
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Check if band is supported
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void band_supported(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "band");
+       int valid = 0;
+       radio_band_t band;
+
+       if(value) {
+               if(!strcasecmp(value, "AM")) {
+                       band = BAND_AM;
+                       valid = 1;
+               } else if(!strcasecmp(value, "FM")) {
+                       band = BAND_FM;
+                       valid = 1;
+               } else {
+                       char *p;
+                       band = strtoul(value, &p, 10);
+                       if(p != value && *p == '\0') {
+                               switch(band) {
+                               case BAND_AM:
+                               case BAND_FM:
+                                       valid = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+       if(!valid) {
+               afb_req_fail(request, "failed", "Invalid band");
+               return;
+       }
+       ret_json = json_object_new_object();
+       json_object_object_add(ret_json,
+                              "supported",
+                              json_object_new_int(radio_impl_band_supported(band)));
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Get frequency range for a band
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void frequency_range(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "band");
+       int valid = 0;
+       radio_band_t band;
+       uint32_t min_frequency;
+       uint32_t max_frequency;
+
+       if(value) {
+               if(!strcasecmp(value, "AM")) {
+                       band = BAND_AM;
+                       valid = 1;
+               } else if(!strcasecmp(value, "FM")) {
+                       band = BAND_FM;
+                       valid = 1;
+               } else {
+                       char *p;
+                       band = strtoul(value, &p, 10);
+                       if(p != value && *p == '\0') {
+                               switch(band) {
+                               case BAND_AM:
+                               case BAND_FM:
+                                       valid = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+       if(!valid) {
+               afb_req_fail(request, "failed", "Invalid band");
+               return;
+       }
+       ret_json = json_object_new_object();
+       min_frequency = radio_impl_get_min_frequency(band);
+       max_frequency = radio_impl_get_max_frequency(band);
+       json_object_object_add(ret_json, "min", json_object_new_int((int32_t) min_frequency));
+       json_object_object_add(ret_json, "max", json_object_new_int((int32_t) max_frequency));
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Get frequency step size (Hz) for a band
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void frequency_step(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "band");
+       int valid = 0;
+       radio_band_t band;
+       uint32_t step;
+
+       if(value) {
+               if(!strcasecmp(value, "AM")) {
+                       band = BAND_AM;
+                       valid = 1;
+               } else if(!strcasecmp(value, "FM")) {
+                       band = BAND_FM;
+                       valid = 1;
+               } else {
+                       char *p;
+                       band = strtoul(value, &p, 10);
+                       if(p != value && *p == '\0') {
+                               switch(band) {
+                               case BAND_AM:
+                               case BAND_FM:
+                                       valid = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+       if(!valid) {
+               afb_req_fail(request, "failed", "Invalid band");
+               return;
+       }
+       ret_json = json_object_new_object();
+       step = radio_impl_get_frequency_step(band);
+       json_object_object_add(ret_json, "step", json_object_new_int((int32_t) step));
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Start radio playback
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void start(struct afb_req request)
+{
+       radio_impl_start();
+       afb_req_success(request, NULL, NULL);
+}
+
+/*
+ * @brief Stop radio playback
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void stop(struct afb_req request)
+{
+       radio_impl_stop();
+       afb_req_success(request, NULL, NULL);
+}
+
+/*
+ * @brief Scan for a station in the specified direction
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void scan_start(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "direction");
+       int valid = 0;
+       radio_scan_direction_t direction;
+
+       if(value) {
+               if(!strcasecmp(value, "forward")) {
+                       direction = SCAN_FORWARD;
+                       valid = 1;
+               } else if(!strcasecmp(value, "backward")) {
+                       direction = SCAN_BACKWARD;
+                       valid = 1;
+               } else {
+                       char *p;
+                       direction = strtoul(value, &p, 10);
+                       if(p != value && *p == '\0') {
+                               switch(direction) {
+                               case SCAN_FORWARD:
+                               case SCAN_BACKWARD:
+                                       valid = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+       if(!valid) {
+               afb_req_fail(request, "failed", "Invalid direction");
+               return;
+       }
+       radio_impl_scan_start(direction, scan_callback, NULL);
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Stop station scan
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void scan_stop(struct afb_req request)
+{
+       radio_impl_scan_stop();
+       afb_req_success(request, NULL, NULL);
+}
+
+/*
+ * @brief Get (and optionally set) stereo mode
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void stereo_mode(struct afb_req request)
+{
+       json_object *ret_json;
+       const char *value = afb_req_value(request, "value");
+       int valid = 0;
+       radio_stereo_mode_t mode;
+       char mode_name[4];
+
+       if(value) {
+               if(!strcasecmp(value, "mono")) {
+                       mode = MONO;
+                       valid = 1;
+               } else if(!strcasecmp(value, "stereo")) {
+                       mode = STEREO;
+                       valid = 1;
+               } else {
+                       char *p;
+                       mode = strtoul(value, &p, 10);
+                       if(p != value && *p == '\0') {
+                               switch(mode) {
+                               case MONO:
+                               case STEREO:
+                                       valid = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+               if(valid) {
+                       radio_impl_set_stereo_mode(mode);
+               } else {
+                       afb_req_fail(request, "failed", "Invalid mode");
+                       return;
+               }
+       }
+       ret_json = json_object_new_object();
+       mode = radio_impl_get_stereo_mode();
+       sprintf(mode_name, "%s", mode == MONO ? "mono" : "stereo");
+       json_object_object_add(ret_json, "mode", json_object_new_string(mode_name));
+       afb_req_success(request, ret_json, NULL);
+}
+
+/*
+ * @brief Subscribe for an event
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void subscribe(struct afb_req request)
+{
+       const char *value = afb_req_value(request, "value");
+       if(value) {
+               if(!strcasecmp(value, "frequency")) {
+                       afb_req_subscribe(request, freq_event);
+               } else if(!strcasecmp(value, "station_found")) {
+                       afb_req_subscribe(request, scan_event);
+               } else {
+                       afb_req_fail(request, "failed", "Invalid event");
+                       return;
+               }
+       }
+       afb_req_success(request, NULL, NULL);
+}
+
+/*
+ * @brief Unsubscribe for an event
+ *
+ * @param struct afb_req : an afb request structure
+ *
+ */
+static void unsubscribe(struct afb_req request)
+{
+       const char *value = afb_req_value(request, "value");
+       if(value) {
+               if(!strcasecmp(value, "frequency")) {
+                       afb_req_unsubscribe(request, freq_event);
+               } else if(!strcasecmp(value, "station_found")) {
+                       afb_req_unsubscribe(request, scan_event);
+               } else {
+                       afb_req_fail(request, "failed", "Invalid event");
+                       return;
+               }
+       }
+       afb_req_success(request, NULL, NULL);
+}
+
+static const struct afb_verb_desc_v1 verbs[]= {
+       { "frequency",          AFB_SESSION_CHECK, frequency,           "Get/Set frequency" },
+       { "band",               AFB_SESSION_CHECK, band,                "Get/Set band" },
+       { "band_supported",     AFB_SESSION_CHECK, band_supported,      "Check band support" },
+       { "frequency_range",    AFB_SESSION_CHECK, frequency_range,     "Get frequency range" },
+       { "frequency_step",     AFB_SESSION_CHECK, frequency_step,      "Get frequency step" },
+       { "start",              AFB_SESSION_CHECK, start,               "Start radio playback" },
+       { "stop",               AFB_SESSION_CHECK, stop,                "Stop radio playback" },
+       { "scan_start",         AFB_SESSION_CHECK, scan_start,          "Start station scan" },
+       { "scan_stop",          AFB_SESSION_CHECK, scan_stop,           "Stop station scan" },
+       { "stereo_mode",        AFB_SESSION_CHECK, stereo_mode,         "Get/Set stereo_mode" },
+       { "subscribe",          AFB_SESSION_CHECK, subscribe,           "Subscribe for an event" },
+       { "unsubscribe",        AFB_SESSION_CHECK, unsubscribe,         "Unsubscribe for an event" },
+       { NULL }
+};
+
+static const struct afb_binding binding_desc = {
+       .type = AFB_BINDING_VERSION_1,
+       .v1 = {
+               .info = "radio service",
+               .prefix = "radio",
+               .verbs = verbs
+       }
+};
+
+const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
+{
+       interface = itf;
+
+       return &binding_desc;
+}
+
+int afbBindingV1ServiceInit(struct afb_service service)
+{
+       int rc;
+
+       freq_event = afb_daemon_make_event(interface->daemon, "frequency");
+       scan_event = afb_daemon_make_event(interface->daemon, "station_found");
+
+       rc = radio_impl_init();
+       if(rc == 0) {
+               radio_impl_set_frequency_callback(freq_callback, NULL);
+       }
+       
+       return rc;
+}