Haivision / srt

Secure, Reliable, Transport
https://www.srtalliance.org
Mozilla Public License 2.0
3.13k stars 856 forks source link

[FR] Send user data out-of-band over an existing SRT connection #2397

Open maxsharabayko opened 2 years ago

maxsharabayko commented 2 years ago

Allow sending some OOB user data bi-directionally over an existing SRT connection.

  1. Unreliable delivery. If a packet is lost, neither the receiver nor the sender would ever know. An application's responsibility is to track losses and retransmissions of those packets if required.
  2. These packets are sent just like other control packets: bypassing the data packet sending queue, and ignoring MAXBW limit and any kind of pacing from the SRT side.
  3. Incoming packets are not buffered by the receiver, and outgoing packets are not buffered by the sender, thus it is not possible to send a message not fitting into a single packet.
  4. If SRT connection has defined an encryption method, the same encryption method must be applied to this user data packet.
  5. Group connections ❓ In case of a group connection sending should follow the selected group type (broadcast/backup). The receiver must avoid duplications. It means that it has to track the last received user data packet, or it should be the responsibility of an application.

SRT API

// A control structure with additional fields.
struct SRT_UDCTRL {
    uint32_t timestamp;
};

/// @param u SRT scoket with an established connection.
/// @param buf data to send (must fit in one MTU!).
/// @param len length of the data to send.
/// @param udctrl control structure with additional fields, mainly for possible future extenstions.
int srt_senduserdata(SRTSOCKET u,  const char* buf, int len, SRT_UDCTRL *udctrl);

typedef int srt_userdata_callback_fn   (void* opaq, SRTSOCKET u, const char* buf, int len, const SRT_UDCTRL* ctrl);
SRT_API       int srt_userdata_callback(SRTSOCKET u, srt_userdata_callback_fn* cb_fn, void* opaque);

SRT Protocol

Extend the User Data Control type packet:

+===================+==============+=========+===============+
| Packet Type       | Control Type | Subtype | Section       |
+===================+==============+=========+===============+
| (...)                  | (...)  | (..) |
+-------------------+--------------+---------+---------------+
| User-Defined Type |    0x7FFF    |    -    | N/A           |
+-------------------+--------------+---------+---------------+
              Table 1: SRT Control Packet Types

Control Type = 0x7FFF (User Defined Data, UDTMessageType::UMSG_EXT). Subtype:

The user-data packet itself has the following structure. Some means to identify sequential packet number might be needed unless handled by the application.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+- SRT Header +-+-+-+-+-+-+-+-+-+-+-+-+-+
|1|   Control Type = 0x7FFF     |            Subtype = 5?          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   Type-specific Information                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Destination Socket ID                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- CIF -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                      Free form text content                   +
                               ...
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ethouris commented 2 years ago

This should use the UMSG_EXT and a newly defined subtype, this is ok. The "specific data" in the SRT header I'd reuse for:

The data identifier is to state the purpose - some standard values for this may be in use in the future so that independent applications can get fed by the data. Assignment for these values could be like with PID in TS - some are fixed, some ranges are for free dynamic allocation.

The journal is for the case when a request-response cycle is required on this data, if this mechanism is used for querying. The journal value should be placed identical in the response as with the request. For journal the values from 1 and increasing should be used to handle the "deaf telephone" problem.

The API functions should have an extra parameter for setting these data, although both the identifier and the journal should be set freely by the application.

jlsantiago0 commented 2 years ago

Being able to send bi-directional user/application data over an existing SRT connection that can be easily distinguished from the stream data would be very useful for a number of reasons.

Perhaps QoS/retransmission requirements could be a configuration type option. But even bi-direciton user/application data without restrans possibilities would still be very useful. Especially for application layer usage where we currently need to use another network connection/protocol to convey this type of information.

Possible Usage: 1) Implementing authentication/access control at the application layer. 2) Exchanging Public keys to use for data encryption. 3) Sending Stream Control requests from the Stream Receiver side: e.g: Start, Stop, Change Channel, etc. 4) Sending Channel Guide information to the receiver. 5) I can think of many more.

Please consider implementing this functionality soon.

ethouris commented 2 years ago

One of the methods to do a similar thing today is to establish a new connection over the same UDP link and use the message mode to send some application data. But this would be something that could not be anyhow standardized - it's simply an application-to-application solution.

jlsantiago0 commented 2 years ago

@ethouris Is there some documentation or example code that demonstrates how to do that?

jlsantiago0 commented 2 years ago

@maxsharabayko This looks very useful. The limitations in the PR seem fine for my use cases, except for possibly the Group connections one. So does this mean we cannot use this in bonding mode?

maxsharabayko commented 2 years ago

@jlsantiago0 I would say bonded connections should be supported eventually, just not yet supported in this PoC. The question is whether SRT or an application must handle the redundancy of user data messages. I bend towards SRT.

jlsantiago0 commented 2 years ago

@maxsharabayko That is Great news. Perhaps redundancy at the SRT level could be configurable? So that the application can decide to do it or not or to do a hybrid approach. But I am OK either way.

maxsharabayko commented 2 years ago

@maxsharabayko That is Great news. Perhaps redundancy at the SRT level could be configurable? So that the application can decide to do it or not or to do a hybrid approach. But I am OK either way.

Not sure. If it would be implemented in SRT already, then there is no point to disable it. If only to confuse the user.

jlsantiago0 commented 2 years ago

Perfect. That is fine.

jlsantiago0 commented 2 years ago

Oh. One thing that may be useful. Would be for a way to query the max user data size we can send. If it wont change during the lifetime of the connection, perhaps as an out parameter to srt_userdata_callback()? Or if the message we try to send via srt_senduserdata() is too big, maybe there is a way to query at that point. Or if SRT_USERDATACTRL is in in/out parameter maybe there.