aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--binding/CMakeLists.txt12
-rw-r--r--binding/radio-binding.c75
-rw-r--r--binding/radio_impl_kingfisher.c39
-rw-r--r--binding/radio_output_pulse.c293
-rw-r--r--conf.d/cmake/config.cmake6
-rw-r--r--conf.d/wgt/config-4a.xml.in32
6 files changed, 9 insertions, 448 deletions
diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt
index 949bb4b..97bc2a6 100644
--- a/binding/CMakeLists.txt
+++ b/binding/CMakeLists.txt
@@ -28,9 +28,6 @@ PROJECT_TARGET_ADD(radio-binding)
radio-binding.c
radio_impl_kingfisher.c
radio_impl_rtlsdr.c)
- if(HAVE_4A_FRAMEWORK)
- add_definitions(-DHAVE_4A_FRAMEWORK)
- endif()
PKG_CHECK_MODULES(SOUND REQUIRED gstreamer-1.0)
@@ -54,16 +51,11 @@ PROJECT_TARGET_ADD(rtl_fm_helper)
# Define project targets
set(helper_SOURCES
${TARGET_NAME}.c
+ radio_output_gstreamer.c
rtl_fm.c
convenience/convenience.c)
- if(HAVE_4A_FRAMEWORK OR HAVE_PIPEWIRE)
- set(helper_SOURCES ${helper_SOURCES} radio_output_gstreamer.c)
- PKG_CHECK_MODULES(helper_SOUND REQUIRED gstreamer-1.0)
- else()
- set(helper_SOURCES ${helper_SOURCES} radio_output_pulse.c)
- PKG_CHECK_MODULES(helper_SOUND REQUIRED libpulse-simple)
- endif()
+ PKG_CHECK_MODULES(helper_SOUND REQUIRED gstreamer-1.0)
PKG_CHECK_MODULES(helper_RTLSDR REQUIRED librtlsdr)
PKG_CHECK_MODULES(helper_LIBUSB REQUIRED libusb-1.0)
diff --git a/binding/radio-binding.c b/binding/radio-binding.c
index 19cea20..847e822 100644
--- a/binding/radio-binding.c
+++ b/binding/radio-binding.c
@@ -55,71 +55,6 @@ 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)
-{
-#ifdef HAVE_4A_FRAMEWORK
- 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;
-#else
- return 0;
-#endif
-}
-
/*
* Binding verb handlers
*/
@@ -373,13 +308,8 @@ static void frequency_step(struct afb_req request)
*/
static void start(struct afb_req request)
{
- char *output = NULL;
-
- if(set_role_state(true, &output) == 0) {
- radio_impl_ops->set_output(output);
- radio_impl_ops->start();
- free(output);
- }
+ radio_impl_ops->set_output(NULL);
+ radio_impl_ops->start();
afb_req_success(request, NULL, NULL);
json_object *jresp = json_object_new_object();
@@ -397,7 +327,6 @@ 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);
json_object *jresp = json_object_new_object();
diff --git a/binding/radio_impl_kingfisher.c b/binding/radio_impl_kingfisher.c
index 9388762..dcd3077 100644
--- a/binding/radio_impl_kingfisher.c
+++ b/binding/radio_impl_kingfisher.c
@@ -76,11 +76,6 @@ static int kf_init(void)
char cmd[SI_CTL_CMDLINE_MAXLEN];
int rc;
-#ifndef HAVE_4A_FRAMEWORK
- /* this code will only work with 4A */
- return -1;
-#endif
-
if(present)
return 0;
@@ -308,21 +303,8 @@ static void kf_start(void)
if (running)
return;
-#ifdef HAVE_4A_FRAMEWORK
- int rc;
- json_object *response;
-
- json_object *jsonData = json_object_new_object();
- json_object_object_add(jsonData, "action", json_object_new_string("unmute"));
- rc = afb_service_call_sync("ahl-4a", "radio", jsonData, &response);
- if (rc == 0) {
- AFB_INFO("Muted\n");
- json_object_put(response);
- }
- else {
- AFB_ERROR("afb_service_call_sync failed\n");
- }
-#endif /* HAVE_4A_FRAMEWORK */
+ /* TODO: start the stream in pipewire */
+
running = true;
}
@@ -334,21 +316,8 @@ static void kf_stop(void)
if (!running)
return;
-#ifdef HAVE_4A_FRAMEWORK
- int rc;
- json_object *response;
-
- json_object *jsonData = json_object_new_object();
- json_object_object_add(jsonData, "action", json_object_new_string("mute"));
- rc = afb_service_call_sync("ahl-4a", "radio", jsonData, &response);
- if (rc == 0) {
- AFB_INFO("UnMuted\n");
- json_object_put(response);
- }
- else {
- AFB_ERROR("afb_service_call_sync failed\n");
- }
-#endif /* HAVE_4A_FRAMEWORK */
+ /* TODO: stop the stream in pipewire */
+
running = false;
}
diff --git a/binding/radio_output_pulse.c b/binding/radio_output_pulse.c
deleted file mode 100644
index 8b2957e..0000000
--- a/binding/radio_output_pulse.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <pulse/pulseaudio.h>
-
-#include "radio_output.h"
-#include "rtl_fm.h"
-
-static pa_threaded_mainloop *mainloop;
-static pa_context *context;
-static pa_stream *stream;
-
-static unsigned int extra;
-static int16_t extra_buf[1];
-static unsigned char *output_buf;
-
-static void pa_context_state_cb(pa_context *c, void *data) {
-
- assert(c);
- switch (pa_context_get_state(c)) {
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- case PA_CONTEXT_READY:
- break;
- case PA_CONTEXT_TERMINATED:
- pa_threaded_mainloop_stop(mainloop);
- break;
- case PA_CONTEXT_FAILED:
- default:
- fprintf(stderr, "PA connection failed: %s\n",
- pa_strerror(pa_context_errno(c)));
- pa_threaded_mainloop_stop(mainloop);
- break;
- }
- pa_threaded_mainloop_signal(mainloop, 0);
-}
-
-int radio_output_open(void)
-{
- pa_context *c;
- pa_mainloop_api *mapi;
- char *client;
-
- if(context)
- return 0;
-
- if (!(mainloop = pa_threaded_mainloop_new())) {
- fprintf(stderr, "pa_mainloop_new() failed.\n");
- return -1;
- }
-
- pa_threaded_mainloop_set_name(mainloop, "pa_mainloop");
- mapi = pa_threaded_mainloop_get_api(mainloop);
-
- client = pa_xstrdup("radio");
- if (!(c = pa_context_new(mapi, client))) {
- fprintf(stderr, "pa_context_new() failed.\n");
- goto exit;
- }
-
- pa_context_set_state_callback(c, pa_context_state_cb, NULL);
- if (pa_context_connect(c, NULL, 0, NULL) < 0) {
- fprintf(stderr, "pa_context_connect(): %s", pa_strerror(pa_context_errno(c)));
- goto exit;
- }
-
- if (pa_threaded_mainloop_start(mainloop) < 0) {
- fprintf(stderr, "pa_mainloop_run() failed.\n");
- goto exit;
- }
-
- context = c;
-
- extra = 0;
- output_buf = malloc(sizeof(unsigned char) * RTL_FM_MAXIMUM_BUF_LENGTH);
-
- return 0;
-
-exit:
- if (c)
- pa_context_unref(c);
-
- if (mainloop)
- pa_threaded_mainloop_free(mainloop);
-
- pa_xfree(client);
- return -1;
-}
-
-int radio_output_start(void)
-{
- int error = 0;
- pa_sample_spec *spec;
-
- if(stream)
- return 0;
-
- if(!context) {
- error = radio_output_open();
- if(error != 0)
- return error;
- }
-
- while(pa_context_get_state(context) != PA_CONTEXT_READY)
- pa_threaded_mainloop_wait(mainloop);
-
- spec = (pa_sample_spec*) calloc(1, sizeof(pa_sample_spec));
- spec->format = PA_SAMPLE_S16LE;
- spec->rate = 24000;
- spec->channels = 2;
- if (!pa_sample_spec_valid(spec)) {
- fprintf(stderr, "%s\n",
- pa_strerror(pa_context_errno(context)));
- return -1;
- }
-
- pa_threaded_mainloop_lock(mainloop);
- pa_proplist *props = pa_proplist_new();
- pa_proplist_sets(props, PA_PROP_MEDIA_ROLE, "radio");
- stream = pa_stream_new_with_proplist(context, "radio-output", spec, 0, props);
- if(!stream) {
- fprintf(stderr, "Error creating stream %s\n",
- pa_strerror(pa_context_errno(context)));
- pa_proplist_free(props);
- free(spec);
- pa_threaded_mainloop_unlock(mainloop);
- return -1;
- }
- pa_proplist_free(props);
- free(spec);
-
- if(pa_stream_connect_playback(stream,
- NULL,
- NULL,
- (pa_stream_flags_t) 0,
- NULL,
- NULL) < 0) {
- fprintf(stderr, "Error connecting to PulseAudio : %s\n",
- pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- stream = NULL;
- pa_threaded_mainloop_unlock(mainloop);
- return -1;
- }
-
- pa_threaded_mainloop_unlock(mainloop);
-
- while(pa_stream_get_state(stream) != PA_STREAM_READY)
- pa_threaded_mainloop_wait(mainloop);
-
- return error;
-}
-
-void radio_output_stop(void)
-{
- if(stream) {
- pa_threaded_mainloop_lock(mainloop);
-
- pa_stream_set_state_callback(stream, 0, 0);
- pa_stream_set_write_callback(stream, 0, 0);
- pa_stream_set_underflow_callback(stream, 0, 0);
- pa_stream_set_overflow_callback(stream, 0, 0);
- pa_stream_set_latency_update_callback(stream, 0, 0);
-
- pa_operation *o = pa_stream_flush(stream, NULL, NULL);
- if(o)
- pa_operation_unref(o);
-
- pa_stream_disconnect(stream);
- pa_stream_unref(stream);
- stream = NULL;
-
- pa_threaded_mainloop_unlock(mainloop);
- }
-}
-
-void radio_output_suspend(int state)
-{
- if(stream) {
- pa_stream_cork(stream, state, NULL, NULL);
- }
-}
-
-void radio_output_close(void)
-{
- radio_output_stop();
-
- if(context) {
- pa_context_disconnect(context);
- pa_context_unref(context);
- context = NULL;
- }
-
- if(mainloop) {
- pa_threaded_mainloop_stop(mainloop);
- pa_threaded_mainloop_free(mainloop);
- mainloop = NULL;
- }
-
- free(output_buf);
- output_buf = NULL;
-}
-
-ssize_t radio_output_write(void *buf, int len)
-{
- ssize_t rc = -EINVAL;
-
- size_t n = len;
- size_t avail;
- int samples = len / 2;
- void *p;
-
- if(!stream) {
- return -1;
- }
-
- if(!buf) {
- fprintf(stderr, "Error: buf == null!\n");
- return rc;
- }
-
- pa_threaded_mainloop_lock(mainloop);
-
- avail = pa_stream_writable_size(stream);
- if(avail < n) {
- /*
- * NOTE: Definitely room for improvement here,but for now just
- * check for the no space case that happens when the
- * stream is corked.
- */
- if(!avail) {
- rc = 0;
- goto exit;
- }
- }
-
- /*
- * Handle the rtl_fm code giving us an odd number of samples, which
- * PA does not like. This extra buffer copying approach is not
- * particularly efficient, but works for now. It looks feasible to
- * hack in something in the demod and output thread routines in
- * rtl_fm.c to handle it there if more performance is required.
- */
- p = output_buf;
- if(extra) {
- memcpy(output_buf, extra_buf, sizeof(int16_t));
- if((extra + samples) % 2) {
- // We still have an extra sample, n remains the same, store the extra
- memcpy(output_buf + sizeof(int16_t), buf, n - 2);
- memcpy(extra_buf, ((unsigned char*) buf) + n - 2, sizeof(int16_t));
- } else {
- // We have an even number of samples, no extra
- memcpy(output_buf + sizeof(int16_t), buf, n);
- n += 2;
- extra = 0;
- }
- } else if(samples % 2) {
- // We have an extra sample, store it, and decrease n
- n -= 2;
- memcpy(output_buf + sizeof(int16_t), buf, n);
- memcpy(extra_buf, ((unsigned char*) buf) + n, sizeof(int16_t));
- extra = 1;
- } else {
- p = buf;
- }
-
- if ((rc = pa_stream_write(stream, p, n, NULL, 0, PA_SEEK_RELATIVE)) < 0) {
- fprintf(stderr, "Error writing %zu bytes to PulseAudio : %s\n",
- n, pa_strerror(pa_context_errno(context)));
- }
-exit:
- pa_threaded_mainloop_unlock(mainloop);
-
- return rc;
-}
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
index 3e09ee2..b18c8f1 100644
--- a/conf.d/cmake/config.cmake
+++ b/conf.d/cmake/config.cmake
@@ -88,11 +88,7 @@ set(INSTALL_PREFIX $ENV{HOME}/opt)
# Optional location for config.xml.in
# -----------------------------------
-if(HAVE_4A_FRAMEWORK)
- set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config-4a.xml.in)
-else()
- set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in)
-endif()
+set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in)
# Mandatory widget Mimetype specification of the main unit
# --------------------------------------------------------------------------
diff --git a/conf.d/wgt/config-4a.xml.in b/conf.d/wgt/config-4a.xml.in
deleted file mode 100644
index 11a36a1..0000000
--- a/conf.d/wgt/config-4a.xml.in
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="@PROJECT_VERSION@">
- <name>@PROJECT_NAME@</name>
- <icon src="@PROJECT_ICON@"/>
- <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/>
- <description>@PROJECT_DESCRIPTION@</description>
- <author>@PROJECT_AUTHOR@ &lt;@PROJECT_AUTHOR_MAIL@&gt;</author>
- <license>@PROJECT_LICENSE@</license>
-
- <feature name="urn:AGL:widget:required-permission">
- <param name="urn:AGL:permission::public:hidden" value="required" />
- <param name="urn:AGL:permission::public:no-htdocs" value="required" />
- <param name="urn:AGL:permission:audio:public:audiostream" value="required" />
- </feature>
-
- <feature name="urn:AGL:widget:file-properties">
- <param name="bin/rtl_fm_helper" value="executable" />
- </feature>
-
- <feature name="urn:AGL:widget:provided-api">
- <param name="radio" value="ws" />
- </feature>
-
- <feature name="urn:AGL:widget:required-api">
- <param name="ahl-4a" value="ws" />
- </feature>
-
- <feature name="urn:AGL:widget:required-binding">
- <param name="@WIDGET_ENTRY_POINT@" value="local" />
- </feature>
-
-</widget>