diff options
Diffstat (limited to 'binding')
-rw-r--r-- | binding/CMakeLists.txt | 12 | ||||
-rw-r--r-- | binding/radio-binding.c | 75 | ||||
-rw-r--r-- | binding/radio_impl_kingfisher.c | 39 | ||||
-rw-r--r-- | binding/radio_output_pulse.c | 293 |
4 files changed, 8 insertions, 411 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; -} |