Skip to content

Commit a386723

Browse files
authored
Merge pull request #19 from AMWA-TV/nmos-gstreamer-master-enable
Nmos gstreamer master enable
2 parents 30a6d38 + 724fba3 commit a386723

File tree

15 files changed

+702
-279
lines changed

15 files changed

+702
-279
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,8 @@ Open `cpp/demos/ossrf-nmos-api/config/nmos_config.json` and adjust the following
128128

129129
./scripts/build-inside-container.sh
130130

131-
## Notes
132-
At the moment, the gstreamer plugins with NMOS (nmossender and nmosreceiver) aren't 100% functional, being more of a proof of concept that will be refined in the near future.
131+
## GStreamer Plugins
132+
133+
We have also developed GStreamer plugins (nmossender, nmosvideoreceiver, and nmosaudioreceiver) that integrate NMOS registration and control with the sending and receiving of raw ST2110 audio/video streams.
134+
135+
For detailed instructions on building, installing, and using these plugins (including examples of gst-launch-1.0 pipelines), please see the [Plugins Guide](/cpp/libs/gst_nmos_plugins/).

cpp/demos/config/nmos_plugin_node_config_receiver.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"label": "BISECT OSSRF Node Receiver",
66
"description": "BISECT OSSRF node receiver",
77
"host_addresses": [
8-
"192.168.1.36"
8+
"192.168.1.1"
99
],
1010
"interfaces": [
1111
{
@@ -24,16 +24,13 @@
2424
"locked": true
2525
}
2626
],
27-
"registry_address": "192.168.1.36",
27+
"registry_address": "192.168.1.1",
2828
"registry_version": "v1.3",
2929
"registration_port": 8010,
30-
"system_address": "192.168.1.36",
30+
"system_address": "192.168.1.1",
3131
"system_version": "v1.0",
3232
"system_port": 8010,
3333
"http_port": 5114
3434
}
35-
},
36-
"device": {},
37-
"receivers": [],
38-
"senders": []
35+
}
3936
}

cpp/demos/config/nmos_plugin_node_config_sender.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"label": "BISECT OSSRF Node Sender",
66
"description": "BISECT OSSRF node sender",
77
"host_addresses": [
8-
"192.168.1.36"
8+
"192.168.1.1"
99
],
1010
"interfaces": [
1111
{
@@ -24,16 +24,13 @@
2424
"locked": true
2525
}
2626
],
27-
"registry_address": "192.168.1.36",
27+
"registry_address": "192.168.1.1",
2828
"registry_version": "v1.3",
2929
"registration_port": 8010,
30-
"system_address": "192.168.1.36",
30+
"system_address": "192.168.1.1",
3131
"system_version": "v1.0",
3232
"system_port": 8010,
3333
"http_port": 6114
3434
}
35-
},
36-
"device": {},
37-
"receivers": [],
38-
"senders": []
35+
}
3936
}

cpp/demos/ossrf-nmos-api/main.cpp

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -61,43 +61,45 @@ namespace
6161
{
6262
if(i == 1)
6363
{
64-
auto receiver_activation_callback = [r = (*it).dump(), &gst_receiver_uptr](
65-
const std::optional<std::string>& sdp, bool master_enable) {
66-
if(sdp.has_value())
67-
{
68-
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
69-
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
70-
if(plugin.has_value())
64+
auto receiver_activation_callback =
65+
[r = (*it).dump(), &gst_receiver_uptr](const std::optional<std::string>& sdp,
66+
bool master_enable, const nlohmann::json&) {
67+
if(sdp.has_value())
7168
{
72-
gst_receiver_uptr.reset(plugin.value().release());
69+
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
70+
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
71+
if(plugin.has_value())
72+
{
73+
gst_receiver_uptr.reset(plugin.value().release());
74+
return;
75+
}
76+
fmt::print("failed creating receiver\n");
7377
return;
7478
}
75-
fmt::print("failed creating receiver\n");
76-
return;
77-
}
78-
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
79-
};
79+
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
80+
};
8081
BST_CHECK(nmos_client->add_receiver(device_id, (*it).dump(), receiver_activation_callback));
8182
receiver_info_config = (*it).dump();
8283
}
8384
else if(i == 2)
8485
{
85-
auto receiver_activation_callback = [r = (*it).dump(), &gst_receiver_uptr_2](
86-
const std::optional<std::string>& sdp, bool master_enable) {
87-
if(sdp.has_value())
88-
{
89-
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
90-
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
91-
if(plugin.has_value())
86+
auto receiver_activation_callback =
87+
[r = (*it).dump(), &gst_receiver_uptr_2](const std::optional<std::string>& sdp,
88+
bool master_enable, const nlohmann::json&) {
89+
if(sdp.has_value())
9290
{
93-
gst_receiver_uptr_2.reset(plugin.value().release());
91+
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
92+
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
93+
if(plugin.has_value())
94+
{
95+
gst_receiver_uptr_2.reset(plugin.value().release());
96+
return;
97+
}
98+
fmt::print("failed creating receiver\n");
9499
return;
95100
}
96-
fmt::print("failed creating receiver\n");
97-
return;
98-
}
99-
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
100-
};
101+
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
102+
};
101103
BST_CHECK(nmos_client->add_receiver(device_id, (*it).dump(), receiver_activation_callback));
102104
}
103105
i++;

cpp/libs/bisect_nmoscpp/lib/include/bisect/nmoscpp/configuration.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,5 @@ namespace bisect::nmoscpp
157157
std::function<void(bool master_enable, const nlohmann::json& transport_params)>;
158158

159159
using receiver_activation_callback_t =
160-
std::function<void(const std::optional<std::string>& sdp, const bool master_enable)>;
160+
std::function<void(const std::optional<std::string>& sdp, const bool master_enable, const nlohmann::json& transport_params)>;
161161
} // namespace bisect::nmoscpp
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# NMOS GStreamer Plugins
2+
3+
This repository contains GStreamer plugins that integrate AMWA NMOS functionality into your pipelines.
4+
Specifically, it provides an **NMOS Audio Receiver** (`nmosaudioreceiver`), **NMOS Video Receiver** (`nmosvideoreceiver`), and **NMOS Sender** (`nmossender`) that can dynamically that can receive and send ST2110 audio/video streams configured by the NMOS control panel.
5+
6+
## Table of Contents
7+
8+
## Table of Contents
9+
10+
1. [Overview](#overview)
11+
2. [Building from Source](#building-from-source)
12+
3. [Installing the Plugin](#installing-the-plugin)
13+
- [Installing via Script](#option-1-installing-via-script)
14+
- [Installing Manually](#option-2-installing-manually)
15+
- [Environment Variable](#option-3-environment-variable)
16+
- [Verifying Installation](#verifying-the-installation)
17+
4. [Using the Plugin](#using-the-plugin)
18+
- [Inspecting the Plugin](#inspecting-the-plugin)
19+
- [Example Pipelines](#example-pipelines)
20+
- [NMOS Interface](#nmos-interface)
21+
5. [Notes and Troubleshooting](#notes-and-troubleshooting)
22+
6. [License](#license)
23+
24+
25+
---
26+
27+
## Overview
28+
29+
The **NMOS plugins** communicate with an NMOS registry (using the AMWA [IS-04](https://specs.amwa.tv/is-04/) and [IS-05](https://specs.amwa.tv/is-05/) APIs) to automatically register and control the NMOS resources that send/receive raw ST2110 video/audio streams.
30+
31+
## Building from Source
32+
33+
To build the plugin, follow the build steps in the [**README**](/) inside the root directory of this project. The binary files for the plugin will then be created in `/build/Release/plugins/`.
34+
35+
## Installing the Plugin
36+
37+
Once you've built the plugin, you need to install it so that GStreamer can detect and use it.
38+
39+
### Option 1: Installing via Script
40+
41+
To simplify installation, you can use the provided installation script. This script installs the NMOS GStreamer plugins system-wide.
42+
43+
Run the following command:
44+
```bash
45+
./scripts/install_custom_gstreamer_plugins.sh
46+
```
47+
48+
If the script is in a different directory, provide the path to your compiled plugins:
49+
```bash
50+
./scripts/install_custom_gstreamer_plugins.sh /path/to/your/plugins
51+
```
52+
By default, the script assumes that the compiled plugins are located in:
53+
```bash
54+
../build/Release/plugins/
55+
```
56+
**Removing the NMOS Plugins**
57+
58+
If you want to remove the NMOS plugins, run:
59+
```bash
60+
./scripts/install_custom_gstreamer_plugins.sh -r
61+
```
62+
or
63+
```bash
64+
./scripts/install_custom_gstreamer_plugins.sh --remove
65+
```
66+
This will delete nmossender, nmosvideoreceiver, and nmosaudioreceiver from the system.
67+
68+
### Option 2: Installing Manually
69+
70+
If you prefer a manual installation, follow these steps:
71+
1. **Locate Your Compiled Plugins**
72+
73+
After building the project, the compiled .so (Linux), .dylib (macOS), or .dll (Windows) files will be in:
74+
```
75+
/build/Release/plugins/
76+
```
77+
78+
2. **Copy the Plugins to a GStreamer Plugin Directory**
79+
80+
Copy the plugins to the GStreamer plugins folder.
81+
By default it should be ``/usr/lib/x86_64-linux-gnu/gstreamer-1.0`` for Linux.
82+
83+
### Option 3: Environment Variable
84+
85+
The last option for the plugin usage envolves setting environment variable `GST_PLUGIN_PATH` to the directory where the binary files are saved. This way for the current shell session GStreamer will also look for plugins in the specified path. Choosing this option will require the setting of the variable everytime a new session is created.
86+
87+
i.e.
88+
89+
```bash
90+
export GST_PLUGIN_PATH=/home/gst-plugins/
91+
```
92+
93+
### Verifying the installation
94+
95+
Check if GStreamer recognizes the plugins:
96+
```bash
97+
gst-inspect-1.0 | grep "nmos"
98+
```
99+
If the installation was successful, you should see output similar to:
100+
```
101+
nmossender: nmossender: NMOS Sender
102+
nmosvideoreceiver: nmosvideoreceiver: NMOS Video Receiver
103+
nmosaudioreceiver: nmosaudioreceiver: NMOS Audio Receiver
104+
```
105+
106+
## Using the Plugin
107+
108+
### Inspecting the Plugin
109+
110+
When using these plugins, you can inspect them along with all the properties you can change, capabilities, and info with the following command:
111+
112+
```bash
113+
gst-inspect-1.0 nmos(sender/videoreceiver/audioreceiver)
114+
```
115+
116+
Some of the more important properties to change are as follows:
117+
118+
| Property | Description |
119+
|------------------------------|-----------------------------------------------------------|
120+
| `node-id` | NMOS Node ID (UUID) |
121+
| `node-config-file-location` | Path to the node configuration JSON file (String) |
122+
| `device-id` | NMOS Device ID (UUID) |
123+
| `device-label` | A label for the NMOS Device (String) |
124+
| `device-description` | A description of the NMOS Device (String) |
125+
| `receiver-id` | NMOS Receiver ID (UUID) |
126+
| `receiver-label` | A label for the NMOS Receiver (String) |
127+
| `receiver-description` | A description of the NMOS Receiver (String) |
128+
| `destination-address` | IP address for the outgoing/incoming RTP stream (String) |
129+
130+
**Important Note:** Currently, the node fields for the NMOS interface connection aren't configurable by properties but instead by a JSON file. An example can be found at `/cpp/demos/config/`.
131+
132+
### Example Pipelines
133+
-----
134+
#### Sender (Audio):
135+
```bash
136+
gst-launch-1.0 audiotestsrc is-live=true wave=square ! audio/x-raw, format=S24BE, rate=48000, channels=2, layout=interleaved ! nmossender destination-address="192.168.1.1" destination-port=5004
137+
```
138+
139+
#### Audio Receiver:
140+
```bash
141+
gst-launch-1.0 -v nmosaudioreceiver destination-address="192.168.1.1" receiver-id="9dd4cb3e-7d28-411d-9939-b8e439bd8c2a" ! queue ! audioconvert ! wavescope ! ximagesink sync=false
142+
```
143+
-----
144+
145+
#### Sender (Video):
146+
```bash
147+
gst-launch-1.0 videotestsrc is-live=true timestamp-offset=1 pattern=ball ! videoconvert ! "video/x-raw, format=UYVP, sampling=YCbCr-4:2:2, width=460, height=240, clock-rate=9000, framerate=50/1" ! nmossender destination-address="192.168.1.1" source-address="192.168.1.1" destination-port=9999
148+
```
149+
#### Video Receiver:
150+
```bash
151+
gst-launch-1.0 -v nmosvideoreceiver destination-address="192.168.1.1" receiver-id="9dd4cb3e-7d28-411d-9939-b8e439bd8c2a" ! queue ! videoconvert ! autovideosink sync=false
152+
```
153+
-----
154+
### NMOS Interface
155+
156+
The NMOS Interface allows users to manage senders and receivers through a graphical user interface. It provides an overview of active streams, transport methods, and detailed configurations.
157+
158+
The NMOS page can be accessed through the following link ```http://localhost:8010/admin/```
159+
160+
- **Senders Management**: Displays active senders, transport type (e.g., RTP Multicast), and allows toggling activation.
161+
- **Receivers Management**: Lists available receivers, their bindings, supported media formats, and current connections.
162+
- **Detailed View**: Clicking on a node, device, sender or receiver provides detailed configuration options, including transport settings and associated flows.
163+
- **Connection Setup**: Users can establish connections between senders and receivers through a simple UI inside the receiver page, where they can freely connect and disconnect them.
164+
165+
Note: When changing the parameters inside the connect tab, be sure to activate the activation mode ```activate_immediate``` if you want to change the connection dynamically.
166+
167+
## Notes and Troubleshooting
168+
169+
- **State Management:** The plugin automatically transitions to PLAYING when valid SDP data is received. If the receiver is disabled from the NMOS registry side, the pipeline tears down its internal elements.
170+
- **Flush and Dynamic Reconfiguration:** If you dynamically change streams at runtime (e.g., the NMOS registry activates a new source), the plugin will remove old elements and construct new ones on the fly without restarting the entire pipeline.
171+
- **Verbose Debug:** If you need to see more logs, you can enable GStreamer debug categories:
172+
173+
```bash
174+
GST_DEBUG=nmosaudioreceiver:5 gst-launch-1.0 nmosaudioreceiver ...
175+
```
176+
177+
### Dependencies
178+
179+
- GStreamer (1.18+ recommended)
180+
181+
## License
182+
183+
This project is licensed under the Apache 2.0 License.
184+
Please see the LICENSE file on the root directory for more details.

cpp/libs/gst_nmos_plugins/include/element_class.h renamed to cpp/libs/gst_nmos_plugins/include/element_class.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,7 @@ template <typename T = GstElement> class GstElementHandle
5757
}
5858

5959
/// Destruction of this object will no longer unref the owned element.
60-
void forget(T* new_ptr = nullptr)
61-
{
62-
handle_ = new_ptr;
63-
}
60+
void forget(T* new_ptr = nullptr) { handle_ = new_ptr; }
6461

6562
T* get() const { return handle_; }
6663

0 commit comments

Comments
 (0)