From 3cface96122af108234413c425c393c173192302 Mon Sep 17 00:00:00 2001 From: Joao Figueiredo Date: Tue, 24 Sep 2024 11:04:32 +0000 Subject: [PATCH] Add ST2110-30 sender to the gstreamer and demo --- .../ossrf-nmos-api/config/nmos_config.json | 17 +-- .../src/sender/st2110_30_sender_plugin.cpp | 137 ++++++++++++++++++ .../lib/src/sender/st2110_30_sender_plugin.h | 24 +++ 3 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.cpp create mode 100644 cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.h diff --git a/cpp/demos/ossrf-nmos-api/config/nmos_config.json b/cpp/demos/ossrf-nmos-api/config/nmos_config.json index cae96fd..4c18c1c 100644 --- a/cpp/demos/ossrf-nmos-api/config/nmos_config.json +++ b/cpp/demos/ossrf-nmos-api/config/nmos_config.json @@ -81,8 +81,8 @@ }, { "id": "f2aa5651-c673-448c-bd02-5e8475898c7f", - "label": "BISECT OSSRF sender video 2", - "description": "BISECT OSSRF sender video 2", + "label": "BISECT OSSRF sender audio", + "description": "BISECT OSSRF sender audio", "network": { "primary": { "source_address": "192.168.1.79", @@ -92,16 +92,11 @@ } }, "payload_type": 97, - "media_type": "video/raw", + "media_type": "audio/L24", "media": { - "width": 640, - "height": 480, - "frame_rate": { - "num": 50, - "den": 1 - }, - "sampling": "RGB_444", - "structure": "progressive" + "number_of_channels": 2, + "sampling_rate": 48000, + "packet_time": 1.000 } } ] diff --git a/cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.cpp b/cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.cpp new file mode 100644 index 0000000..0416af1 --- /dev/null +++ b/cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.cpp @@ -0,0 +1,137 @@ +// Copyright (C) 2024 Advanced Media Workflow Association +// +// 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 "st2110_30_sender_plugin.h" +#include "bisect/expected/macros.h" +#include "bisect/pipeline.h" +#include + +using namespace bisect; +using namespace ossrf::gst::sender; +using namespace ossrf::gst::plugins; + +namespace +{ + constexpr auto queue_max_size_time = 200000; + constexpr auto queue_max_size_buffers = 0; + constexpr auto queue_max_size_bytes = 0; +}; // namespace + +struct gst_st2110_30_sender_impl : gst_sender_plugin_t +{ + sender_settings s_; + audio_info_t f_; + gst::pipeline pipeline_; + + gst_st2110_30_sender_impl(sender_settings settings, audio_info_t format) : s_(settings), f_(format) {} + + ~gst_st2110_30_sender_impl() { stop(); } + + maybe_ok create_gstreamer_pipeline() + { + // Create pipeline and check if all elements are created successfully + BST_CHECK_ASSIGN(pipeline_, bisect::gst::pipeline::create(NULL)); + auto* pipeline = pipeline_.get(); + + // Add pipeline pulsesrc (audio source) + auto* source = gst_element_factory_make("pulsesrc", NULL); + BST_ENFORCE(source != nullptr, "Failed creating GStreamer element pulsesrc"); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), source), "Failed adding pulsesrc to the pipeline"); + + // Add pipeline queue1 + auto* queue1 = gst_element_factory_make("queue", NULL); + BST_ENFORCE(queue1 != nullptr, "Failed creating GStreamer element queue"); + g_object_set(G_OBJECT(queue1), "max-size-time", queue_max_size_time, "max-size-buffers", queue_max_size_buffers, + "max-size-bytes", queue_max_size_bytes, NULL); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), queue1), "Failed adding queue to the pipeline"); + + // Add pipeline audioconvert + auto* audioconvert = gst_element_factory_make("audioconvert", NULL); + BST_ENFORCE(audioconvert != nullptr, "Failed creating GStreamer element audioconvert"); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), audioconvert), "Failed adding audioconvert to the pipeline"); + + // Add pipeline queue2 + auto* queue2 = gst_element_factory_make("queue", NULL); + BST_ENFORCE(queue2 != nullptr, "Failed creating GStreamer element queue"); + g_object_set(G_OBJECT(queue1), "max-size-time", queue_max_size_time, "max-size-buffers", queue_max_size_buffers, + "max-size-bytes", queue_max_size_bytes, NULL); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), queue2), "Failed adding queue to the pipeline"); + + // Add pipeline audioresample + auto* audioresample = gst_element_factory_make("audioresample", NULL); + BST_ENFORCE(audioresample != nullptr, "Failed creating GStreamer element audioresample"); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), audioresample), "Failed adding audioresample to the pipeline"); + + // Add pipeline capsfilter + auto* capsfilter = gst_element_factory_make("capsfilter", NULL); + BST_ENFORCE(capsfilter != nullptr, "Failed creating capsfilter"); + + // Create caps for capsfilter + auto* caps = gst_caps_new_simple("audio/x-raw", "channels", G_TYPE_INT, f_.number_of_channels, "rate", + G_TYPE_INT, f_.sampling_rate, NULL); + BST_ENFORCE(caps != nullptr, "Failed creating GStreamer audio caps"); + g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), capsfilter), "Failed adding capsfilter to the pipeline"); + gst_caps_unref(caps); + + // Add pipeline queue1 + auto* queue3 = gst_element_factory_make("queue", NULL); + BST_ENFORCE(queue3 != nullptr, "Failed creating GStreamer element queue"); + g_object_set(G_OBJECT(queue1), "max-size-time", queue_max_size_time, "max-size-buffers", queue_max_size_buffers, + "max-size-bytes", queue_max_size_bytes, NULL); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), queue3), "Failed adding queue to the pipeline"); + + // Add pipeline rtpL24pay (audio payload) + auto* rtpL24pay = gst_element_factory_make("rtpL24pay", NULL); + BST_ENFORCE(rtpL24pay != nullptr, "Failed creating GStreamer element rtpL24pay"); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), rtpL24pay), "Failed adding rtpL24pay to the pipeline"); + + // Add pipeline udpsink + auto* udpsink = gst_element_factory_make("udpsink", NULL); + BST_ENFORCE(udpsink != nullptr, "Failed creating GStreamer element udpsink"); + // Set properties + g_object_set(G_OBJECT(udpsink), "host", s_.primary.destination_ip_address.c_str(), NULL); + g_object_set(G_OBJECT(udpsink), "port", s_.primary.destination_port, NULL); + g_object_set(G_OBJECT(udpsink), "auto-multicast", TRUE, NULL); + g_object_set(G_OBJECT(udpsink), "multicast-iface", s_.primary.interface_name.c_str(), NULL); + BST_ENFORCE(gst_bin_add(GST_BIN(pipeline), udpsink), "Failed adding udpsink to the pipeline"); + + // Link elements + BST_ENFORCE(gst_element_link_many(source, queue1, audioconvert, queue2, audioresample, capsfilter, queue3, + rtpL24pay, udpsink, NULL), + "Failed linking GStreamer audio pipeline"); + + // Setup runner + pipeline_.run_loop(); + + return {}; + } + + void stop() noexcept override + { + pipeline_.stop(); + pipeline_ = {}; + } +}; + +// TODO this function will need to receive an SDP and use the information in it to build the GST pipeline +expected ossrf::gst::plugins::create_gst_st2110_30_plugin(sender_settings settings, + audio_info_t format) noexcept +{ + auto i = std::make_unique(settings, format); + + BST_CHECK(i->create_gstreamer_pipeline()); + + return i; +} diff --git a/cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.h b/cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.h new file mode 100644 index 0000000..a5d3e57 --- /dev/null +++ b/cpp/libs/ossrf_gstreamer_api/lib/src/sender/st2110_30_sender_plugin.h @@ -0,0 +1,24 @@ +// Copyright (C) 2024 Advanced Media Workflow Association +// +// 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. + +#pragma once +#include "ossrf/gstreamer/api/sender/sender_plugin.h" +#include "ossrf/gstreamer/api/sender/sender_configuration.h" + +namespace ossrf::gst::plugins +{ + bisect::expected + create_gst_st2110_30_plugin(ossrf::gst::sender::sender_settings settings, + ossrf::gst::sender::audio_info_t audio_info_t) noexcept; +} \ No newline at end of file