Skip to content

Commit

Permalink
Add ST2110-30 sender to the gstreamer and demo
Browse files Browse the repository at this point in the history
  • Loading branch information
joaofigueiredobisect committed Sep 24, 2024
1 parent 6a069a4 commit 3cface9
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 11 deletions.
17 changes: 6 additions & 11 deletions cpp/demos/ossrf-nmos-api/config/nmos_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
}
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <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_ = {};
}
};

// TODO this function will need to receive an SDP and use the information in it to build the GST 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;
}

0 comments on commit 3cface9

Please sign in to comment.