diff options
-rw-r--r-- | binding/radio-binding.c | 147 | ||||
-rw-r--r-- | binding/radio_impl.h | 4 | ||||
-rw-r--r-- | binding/radio_impl_kingfisher.c | 47 | ||||
-rw-r--r-- | binding/radio_impl_rtlsdr.c | 76 |
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, |