aboutsummaryrefslogtreecommitdiffstats
path: root/binding
diff options
context:
space:
mode:
Diffstat (limited to 'binding')
-rw-r--r--binding/radio-binding.c147
-rw-r--r--binding/radio_impl.h4
-rw-r--r--binding/radio_impl_kingfisher.c47
-rw-r--r--binding/radio_impl_rtlsdr.c76
4 files changed, 143 insertions, 131 deletions
diff --git a/binding/radio-binding.c b/binding/radio-binding.c
index 5f67567..490af5b 100644
--- a/binding/radio-binding.c
+++ b/binding/radio-binding.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
+#include <stdbool.h>
#include <unistd.h>
#include <sys/types.h>
#include <json-c/json.h>
@@ -53,6 +54,67 @@ static void scan_callback(uint32_t frequency, void *data)
afb_event_push(scan_event, json_object_get(jresp));
}
+static int set_role_state(bool state, char **output)
+{
+ int rc;
+ json_object *response = NULL;
+ json_object *jsonData = json_object_new_object();
+
+ json_object_object_add(jsonData, "action", json_object_new_string(state ? "open" : "close"));
+ rc = afb_service_call_sync("ahl-4a", "radio", jsonData, &response);
+ if (rc < 0) {
+ AFB_ERROR("Failed to %s 4A 'radio' role", state ? "open" : "close");
+ goto failed;
+ }
+
+ if(!state) {
+ // No need to look at the response on close
+ goto done;
+ }
+
+ // Handle response on open
+ json_object *valJson = NULL;
+ json_object *val = NULL;
+ rc = json_object_object_get_ex(response, "response", &valJson);
+ if (rc == 0) {
+ AFB_ERROR("Reply from 4A is missing a 'response' field");
+ rc = -1;
+ goto failed_malformed;
+ }
+
+ rc = json_object_object_get_ex(valJson, "device_uri", &val);
+ if (rc == 0) {
+ AFB_ERROR("Reply from 4A is missing a 'device_uri' field");
+ rc = -1;
+ goto failed_malformed;
+ }
+
+ const char *jres_pcm = json_object_get_string(val);
+ char * p = strchr(jres_pcm, ':');
+
+ if (p == NULL) {
+ AFB_ERROR("Unable to parse 'device_uri' value field");
+ rc = -1;
+ goto failed_malformed;
+ }
+
+ if (output) {
+ if (asprintf(output, "hw:%s", p + 1) < 0) {
+ AFB_ERROR("Insufficient memory");
+ rc = -1;
+ goto failed_malformed;
+ }
+ }
+done:
+ rc = 0;
+
+failed_malformed:
+ json_object_put(response);
+
+failed:
+ return rc;
+}
+
/*
* Binding verb handlers
*/
@@ -306,7 +368,13 @@ static void frequency_step(struct afb_req request)
*/
static void start(struct afb_req request)
{
- radio_impl_ops->start();
+ char *output = NULL;
+
+ if(set_role_state(true, &output) == 0) {
+ radio_impl_ops->set_output(output);
+ radio_impl_ops->start();
+ free(output);
+ }
afb_req_success(request, NULL, NULL);
}
@@ -319,6 +387,7 @@ static void start(struct afb_req request)
static void stop(struct afb_req request)
{
radio_impl_ops->stop();
+ set_role_state(false, NULL);
afb_req_success(request, NULL, NULL);
}
@@ -487,89 +556,29 @@ static const struct afb_verb_v2 verbs[]= {
static int init()
{
- int rc;
- char *output = NULL;
-
-#ifdef HAVE_4A_FRAMEWORK
- json_object *response = NULL;
- json_object *jsonData = json_object_new_object();
-
- json_object_object_add(jsonData, "action", json_object_new_string("open"));
- rc = afb_service_call_sync("ahl-4a", "get_roles", NULL, &response);
- if (rc < 0) {
- AFB_ERROR("Failed to query 4A about roles");
- goto failed;
- }
- AFB_NOTICE("4A: available roles are '%s'", json_object_get_string(response));
- json_object_put(response);
-
- rc = afb_service_call_sync("ahl-4a", "radio", jsonData, &response);
- if (rc < 0) {
- AFB_ERROR("Failed to query 'radio' role to 4A");
- goto failed;
- }
-
- json_object *valJson = NULL;
- json_object *val = NULL;
-
- rc = json_object_object_get_ex(response, "response", &valJson);
- if (rc == 0) {
- AFB_ERROR("Reply from 4A is missing a 'response' field");
- goto failed_malformed;
- }
-
- rc = json_object_object_get_ex(valJson, "device_uri", &val);
- if (rc == 0) {
- AFB_ERROR("Reply from 4A is missing a 'device_uri' field");
- goto failed_malformed;
- }
-
- const char *jres_pcm = json_object_get_string(val);
- char * p = strchr(jres_pcm, ':');
-
- if (p == NULL) {
- AFB_ERROR("Unable to parse 'device_uri' value field");
- rc = -1;
- goto failed_malformed;
- }
-
- if (asprintf(&output, "hw:%s", p + 1) < 0) {
- AFB_ERROR("Insufficient memory");
- rc = -1;
- goto failed_malformed;
- }
-#endif /* HAVE_4A_FRAMEWORK */
-
- // Initialize event structures
- freq_event = afb_daemon_make_event("frequency");
- scan_event = afb_daemon_make_event("station_found");
-
// Look for RTL-SDR USB adapter
radio_impl_ops = &rtlsdr_impl_ops;
- rc = radio_impl_ops->init(output);
+ int rc = radio_impl_ops->init();
if(rc != 0) {
// Look for Kingfisher Si4689
radio_impl_ops = &kf_impl_ops;
- rc = radio_impl_ops->init(output);
+ rc = radio_impl_ops->init();
}
if (rc != 0) {
AFB_ERROR("No radio device found, exiting");
- goto failed;
}
-
if(rc == 0) {
AFB_NOTICE("%s found\n", radio_impl_ops->name);
radio_impl_ops->set_frequency_callback(freq_callback, NULL);
+ } else {
+ return rc;
}
- free(output);
-#ifdef HAVE_4A_FRAMEWORK
-failed_malformed:
- json_object_put(response);
-#endif /* HAVE_4A_FRAMEWORK */
+ // Initialize event structures
+ freq_event = afb_daemon_make_event("frequency");
+ scan_event = afb_daemon_make_event("station_found");
-failed:
- return rc;
+ return 0;
}
const struct afb_binding_v2 afbBindingV2 = {
diff --git a/binding/radio_impl.h b/binding/radio_impl.h
index 49efe24..0216f69 100644
--- a/binding/radio_impl.h
+++ b/binding/radio_impl.h
@@ -41,7 +41,9 @@ typedef enum {
typedef struct {
char *name;
- int (*init)(const char *output);
+ int (*init)(void);
+
+ void (*set_output)(const char *output);
uint32_t (*get_frequency)(void);
diff --git a/binding/radio_impl_kingfisher.c b/binding/radio_impl_kingfisher.c
index 7775d5b..8bfc6ff 100644
--- a/binding/radio_impl_kingfisher.c
+++ b/binding/radio_impl_kingfisher.c
@@ -77,7 +77,7 @@ static void *freq_callback_data;
static uint32_t kf_get_min_frequency(radio_band_t band);
static void kf_scan_stop(void);
-static int kf_init(const char *output)
+static int kf_init(void)
{
GKeyFile* conf_file;
int conf_file_present = 0;
@@ -85,10 +85,6 @@ static int kf_init(const char *output)
char *value_str;
char cmd[SI_CTL_CMDLINE_MAXLEN];
int rc;
-#ifndef HAVE_4A_FRAMEWORK
- char output_sink_opt[GST_SINK_OPT_LEN];
- char gst_pipeline_str[GST_PIPELINE_LEN];
-#endif /* !HAVE_4A_FRAMEWORK */
if(present)
return 0;
@@ -182,46 +178,14 @@ static int kf_init(const char *output)
return -1;
}
-#ifndef HAVE_4A_FRAMEWORK
- // Initialize GStreamer
- gst_init(NULL, NULL);
-
- if(output) {
- AFB_INFO("Using output device %s", output);
- rc = snprintf(output_sink_opt, GST_SINK_OPT_LEN, " device=%s", output);
- if(rc >= GST_SINK_OPT_LEN) {
- AFB_ERROR("output device string too long");
- return -1;
- }
- } else {
- output_sink_opt[0] = '\0';
- }
- // NOTE: If muting without pausing is desired, it can likely be done
- // by adding a "volume" element to the pipeline before the sink,
- // and setting the volume to 0 to mute.
- // Use PulseAudio output for compatibility with audiomanager / module_router
- rc = snprintf(gst_pipeline_str,
- sizeof(gst_pipeline_str),
- "alsasrc device=hw:radio ! queue ! audioconvert ! audioresample ! pulsesink stream-properties=\"props,media.role=radio\"");
-
- if(rc >= GST_PIPELINE_LEN) {
- AFB_ERROR("pipeline string too long");
- return -1;
- }
- pipeline = gst_parse_launch(gst_pipeline_str, NULL);
- if(!pipeline) {
- AFB_ERROR("pipeline construction failed!");
- return -1;
- }
-
- // Start pipeline in paused state
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
-#endif /* !HAVE_4A_FRAMEWORK */
-
present = true;
return 0;
}
+static void kf_set_output(const char *output)
+{
+}
+
static uint32_t kf_get_frequency(void)
{
return current_frequency;
@@ -488,6 +452,7 @@ static void kf_set_stereo_mode(radio_stereo_mode_t mode)
radio_impl_ops_t kf_impl_ops = {
.name = "Kingfisher Si4689",
.init = kf_init,
+ .set_output = kf_set_output,
.get_frequency = kf_get_frequency,
.set_frequency = kf_set_frequency,
.set_frequency_callback = kf_set_frequency_callback,
diff --git a/binding/radio_impl_rtlsdr.c b/binding/radio_impl_rtlsdr.c
index c6b0ea9..109d3f3 100644
--- a/binding/radio_impl_rtlsdr.c
+++ b/binding/radio_impl_rtlsdr.c
@@ -51,6 +51,7 @@ static fm_band_plan_t known_fm_band_plans[5] = {
};
static unsigned int bandplan;
+static char *helper_output;
static pid_t helper_pid;
static int helper_in;
static int helper_out;
@@ -127,7 +128,7 @@ static pid_t popen2(char *command, int *in_fd, int *out_fd)
return pid;
}
-static int rtlsdr_init(const char *output)
+static int rtlsdr_init(void)
{
GKeyFile *conf_file;
char *value_str;
@@ -185,31 +186,20 @@ static int rtlsdr_init(const char *output)
return -1;
}
- if(output) {
- // Indicate desired output to helper
- AFB_INFO("Setting RADIO_OUTPUT=%s", output);
- setenv("RADIO_OUTPUT", output, 1);
- }
-
- // Run helper
- if(snprintf(helper_path, PATH_MAX, "%s/bin/%s", rootdir, HELPER_NAME) == PATH_MAX) {
- AFB_ERROR("Could not create path to %s", HELPER_NAME);
- return -EINVAL;
- }
- helper_pid = popen2(helper_path, &helper_out, &helper_in);
- if(helper_pid < 0) {
- AFB_ERROR("Could not run %s!", HELPER_NAME);
- return -1;
- }
- AFB_DEBUG("%s started", HELPER_NAME);
- free(helper_path);
-
present = true;
rtlsdr_set_frequency(current_frequency);
return 0;
}
+static void rtlsdr_set_output(const char *output)
+{
+ // Save output for later use
+ if(helper_output)
+ free(helper_output);
+ helper_output = strdup(output);
+}
+
static uint32_t rtlsdr_get_frequency(void)
{
return current_frequency;
@@ -309,6 +299,48 @@ static uint32_t rtlsdr_get_frequency_step(radio_band_t band)
return ret;
}
+static int rtlsdr_start_helper(void)
+{
+ char *rootdir;
+ char *helper_path;
+ static bool helper_started = false;
+
+ if(!present)
+ return -1;
+
+ if(helper_started)
+ return 0;
+
+ rootdir = getenv("AFM_APP_INSTALL_DIR");
+ if(!rootdir)
+ return -1;
+
+ if(helper_output) {
+ // Indicate desired output to helper
+ AFB_INFO("Setting RADIO_OUTPUT=%s", helper_output);
+ setenv("RADIO_OUTPUT", helper_output, 1);
+ }
+
+ // Run helper
+ helper_path = malloc(HELPER_MAX);
+ if(!helper_path)
+ return -ENOMEM;
+ if(snprintf(helper_path, PATH_MAX, "%s/bin/%s", rootdir, HELPER_NAME) == PATH_MAX) {
+ AFB_ERROR("Could not create path to %s", HELPER_NAME);
+ return -EINVAL;
+ }
+ helper_pid = popen2(helper_path, &helper_out, &helper_in);
+ if(helper_pid < 0) {
+ AFB_ERROR("Could not run %s!", HELPER_NAME);
+ return -1;
+ }
+ AFB_DEBUG("%s started", HELPER_NAME);
+ helper_started = true;
+ free(helper_path);
+
+ return 0;
+}
+
static void rtlsdr_start(void)
{
if(!present)
@@ -317,6 +349,9 @@ static void rtlsdr_start(void)
if(active)
return;
+ if(rtlsdr_start_helper() < 0)
+ return;
+
ssize_t rc;
char cmd[HELPER_CMD_MAXLEN];
@@ -437,6 +472,7 @@ static void rtlsdr_set_stereo_mode(radio_stereo_mode_t mode)
radio_impl_ops_t rtlsdr_impl_ops = {
.name = "RTL-SDR USB adapter",
.init = rtlsdr_init,
+ .set_output = rtlsdr_set_output,
.get_frequency = rtlsdr_get_frequency,
.set_frequency = rtlsdr_set_frequency,
.set_frequency_callback = rtlsdr_set_frequency_callback,