Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ST2110-30 sender to the gstreamer and demo #13

Merged
merged 1 commit into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions cpp/demos/ossrf-nmos-api/config/nmos_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"label": "BISECT OSSRF Node",
"description": "BISECT OSSRF node",
"host_addresses": [
"192.168.1.79"
"192.168.1.15"
],
"interfaces": [
{
Expand All @@ -24,10 +24,10 @@
"locked": true
}
],
"registry_address": "192.168.1.79",
"registry_address": "192.168.1.15",
"registry_version": "v1.3",
"registration_port": 8010,
"system_address": "192.168.1.79",
"system_address": "192.168.1.15",
"system_version": "v1.0",
"system_port": 8010
}
Expand All @@ -44,7 +44,7 @@
"description": "BISECT OSSRF receiver video",
"network": {
"primary": {
"interface_address": "192.168.1.79",
"interface_address": "192.168.1.15",
"interface_name": "wlp1s0"
}
},
Expand All @@ -60,7 +60,7 @@
"description": "BISECT OSSRF sender video 1",
"network": {
"primary": {
"source_address": "192.168.1.79",
"source_address": "192.168.1.15",
"interface_name": "wlp1s0",
"destination_address": "239.10.10.10",
"destination_port": 5004
Expand All @@ -81,27 +81,22 @@
},
{
"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",
"source_address": "192.168.1.15",
"interface_name": "wlp1s0",
"destination_address": "239.10.10.11",
"destination_port": 5005
}
},
"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
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "bisect/expected/match.h"
#include "bisect/json.h"
#include "st2110_20_sender_plugin.h"
#include "st2110_30_sender_plugin.h"
#include <nlohmann/json.hpp>

using namespace bisect;
Expand Down Expand Up @@ -95,7 +96,7 @@ namespace
{
BST_CHECK_ASSIGN(s.format, video_sender_info_from_json(media));
}
else if(media_type == "audio/raw")
else if(media_type == "audio/L24")
{
BST_CHECK_ASSIGN(s.format, audio_l24_sender_info_from_json(media));
}
Expand All @@ -118,6 +119,12 @@ namespace
{
return create_gst_st2110_20_plugin(settings, format, pattern);
}

expected<gst_sender_plugin_uptr> do_create_plugin(const audio_info_t& format, const sender_settings& settings,
int pattern)
{
return create_gst_st2110_30_plugin(settings, format);
}
} // namespace

expected<gst_sender_plugin_uptr> plugins::create_gst_sender_plugin(const std::string& config, int pattern) noexcept
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// 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 <gst/gst.h>

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_ = {};
}
};

expected<gst_sender_plugin_uptr> ossrf::gst::plugins::create_gst_st2110_30_plugin(sender_settings settings,
audio_info_t format) noexcept
{
auto i = std::make_unique<gst_st2110_30_sender_impl>(settings, format);

BST_CHECK(i->create_gstreamer_pipeline());

return i;
}
Original file line number Diff line number Diff line change
@@ -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<gst_sender_plugin_uptr>
create_gst_st2110_30_plugin(ossrf::gst::sender::sender_settings settings,
ossrf::gst::sender::audio_info_t audio_info_t) noexcept;
}