diff options
Diffstat (limited to 'binding/radio_output_gstreamer.c')
-rw-r--r-- | binding/radio_output_gstreamer.c | 231 |
1 files changed, 0 insertions, 231 deletions
diff --git a/binding/radio_output_gstreamer.c b/binding/radio_output_gstreamer.c deleted file mode 100644 index e098d2d..0000000 --- a/binding/radio_output_gstreamer.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2018, 2019 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 <stdbool.h> -#include <string.h> -#include <errno.h> -#include <gst/gst.h> - -#include "radio_output.h" -#include "rtl_fm.h" - -// Flag to enable using GST_STATE_READY instead of GST_STATE_PAUSED to trigger -// Wireplumber policy mechanism. Hopefully temporary. -#define WIREPLUMBER_WORKAROUND - -// Output buffer -static unsigned int extra; -static int16_t extra_buf[1]; -static unsigned char *output_buf; - -// GStreamer state -static GstElement *pipeline, *appsrc; -static bool running; - -int radio_output_open() -{ - unsigned int rate = 24000; - GstElement *queue, *convert, *sink, *resample; - char *p; - - if(pipeline) - return 0; - - // Initialize GStreamer -#ifdef DEBUG - unsigned int argc = 2; - char **argv = malloc(2 * sizeof(char*)); - argv[0] = strdup("test"); - argv[1] = strdup("--gst-debug-level=5"); - gst_init(&argc, &argv); -#else - gst_init(NULL, NULL); -#endif - - // Setup pipeline - // NOTE: With our use of the simple buffer pushing mode, there seems to - // be no need for a mainloop, so currently not instantiating one. - pipeline = gst_pipeline_new("pipeline"); - appsrc = gst_element_factory_make("appsrc", "source"); - queue = gst_element_factory_make("queue", "queue"); - convert = gst_element_factory_make("audioconvert", "convert"); - resample = gst_element_factory_make("audioresample", "resample"); - sink = gst_element_factory_make("pipewiresink", "sink"); - if(!(pipeline && appsrc && queue && convert && resample && sink)) { - fprintf(stderr, "pipeline element construction failed!\n"); - } - g_object_set(G_OBJECT(appsrc), "caps", - gst_caps_new_simple("audio/x-raw", - "format", G_TYPE_STRING, "S16LE", - "rate", G_TYPE_INT, rate, - "channels", G_TYPE_INT, 2, - "layout", G_TYPE_STRING, "interleaved", - "channel-mask", G_TYPE_UINT64, 3, - NULL), NULL); - gst_util_set_object_arg(sink, "stream-properties", "p,media.role=Multimedia"); - - if((p = getenv("RADIO_OUTPUT"))) { - fprintf(stderr, "Using output device %s\n", p); - g_object_set(sink, "device", p, NULL); - } - gst_bin_add_many(GST_BIN(pipeline), appsrc, queue, convert, resample, sink, NULL); - gst_element_link_many(appsrc, queue, convert, resample, sink, NULL); - //gst_bin_add_many(GST_BIN(pipeline), appsrc, convert, resample, sink, NULL); - //gst_element_link_many(appsrc, convert, resample, sink, NULL); - - // Set up appsrc - // NOTE: Radio seems like it matches the use case the "is-live" property - // is for, but setting it seems to require a lot more work with - // respect to latency settings to make the pipeline work smoothly. - // For now, leave it unset since the result seems to work - // reasonably well. - g_object_set(G_OBJECT(appsrc), - "stream-type", 0, - "format", GST_FORMAT_TIME, - NULL); - - // Start pipeline in paused state -#ifdef WIREPLUMBER_WORKAROUND - gst_element_set_state(pipeline, GST_STATE_READY); -#else - gst_element_set_state(pipeline, GST_STATE_PAUSED); -#endif - - // Set up output buffer - extra = 0; - output_buf = malloc(sizeof(unsigned char) * RTL_FM_MAXIMUM_BUF_LENGTH); - - return 0; -} - -int radio_output_start(void) -{ - int rc = 0; - - if(!pipeline) { - rc = radio_output_open(); - if(rc) - return rc; - } - - // Start pipeline - running = true; - gst_element_set_state(pipeline, GST_STATE_PLAYING); - - return rc; -} - -void radio_output_stop(void) -{ - GstEvent *event; - - if(pipeline && running) { - // Stop pipeline - running = false; -#ifdef WIREPLUMBER_WORKAROUND - gst_element_set_state(pipeline, GST_STATE_READY); -#else - gst_element_set_state(pipeline, GST_STATE_PAUSED); -#endif - - // Flush pipeline - // This seems required to avoid stutters on starts after a stop - event = gst_event_new_flush_start(); - gst_element_send_event(GST_ELEMENT(pipeline), event); - event = gst_event_new_flush_stop(TRUE); - gst_element_send_event(GST_ELEMENT(pipeline), event); - } -} - -void radio_output_suspend(int state) -{ - // Placeholder -} - -void radio_output_close(void) -{ - radio_output_stop(); - - if(pipeline) { - // Tear down pipeline - gst_element_set_state(pipeline, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(pipeline)); - pipeline = NULL; - running = false; - } - - free(output_buf); - output_buf = NULL; -} - -ssize_t radio_output_write(void *buf, int len) -{ - ssize_t rc = -EINVAL; - size_t n = len; - int samples = len / 2; - unsigned char *p; - GstBuffer *buffer; - GstFlowReturn ret; - - if(!(pipeline && buf)) { - return rc; - } - - // Don't bother pushing samples if output hasn't started - if(!running) - return 0; - - /* - * Handle the rtl_fm code giving us an odd number of samples. - * 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; - } - - // Push buffer into pipeline - buffer = gst_buffer_new_allocate(NULL, n, NULL); - gst_buffer_fill(buffer, 0, p, n); - g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret); - gst_buffer_unref(buffer); - rc = n; - - return rc; -} |