summaryrefslogtreecommitdiffstats
path: root/binding/radio_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'binding/radio_output.c')
-rw-r--r--binding/radio_output.c294
1 files changed, 0 insertions, 294 deletions
diff --git a/binding/radio_output.c b/binding/radio_output.c
deleted file mode 100644
index a49687b..0000000
--- a/binding/radio_output.c
+++ /dev/null
@@ -1,294 +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) {
- pa_operation *o;
-
- 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;
-}
-
-int radio_output_write(void *buf, int len)
-{
- int rc = -EINVAL;
- int error;
- 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 %d bytes to PulseAudio : %s\n",
- n, pa_strerror(pa_context_errno(context)));
- }
-exit:
- pa_threaded_mainloop_unlock(mainloop);
-
- return rc;
-}