Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.

Secure Real-Time Media Flow Protocol Library

This is a C++ (11) implementation of the Secure Real-Time Media Flow Protocol (RTMFP) as described in RFC 7016.

The library includes sample Platform Adapters and other utilities, such as a simple select() based run loop, but these are not required to be used. The protocol implementation is intended to be adaptable to any host program environment.

The library is intended for clients, servers, and P2P applications. It includes the necessary helpers and callback hooks to support P2P introduction and load balancing.

The test directory includes unit tests and examples. Of special note are tcserver, a simple RTMFP and RTMP live media server; tcrelay, an RTMFP ↔︎ RTMP relay/proxy; and redirector, a simple load balancer.

How to Use

The most complete API documentation is currently in the rtmfp.hpp header file.

An application will instantiate an IPlatformAdapter and an ICryptoAdapter, then a com::zenomt::rtmfp::RTMFP (which requires these adapters). Typically the platform adapter will need to be told of the new RTMFP instance so it can invoke the instance’s platform methods (such as howLongToSleep() and onReceivePacket()).

The platform will add at least one interface by calling RTMFP::addInterface().

The application can open sending flows to new or current endpoints with RTMFP::openFlow() and Flow::openFlow, and can open associated return flows with RecvFlow::openReturnFlow().

The application can accept new flows by setting the onRecvFlow callbacks on the RTMFP (for bare incoming flows) or on SendFlows (for associated return flows).

The application can send messages to far peers with SendFlow::write(), and receive messages from far peers by setting the onMessage callback on RecvFlows. Messages can expire and be abandoned if not started or delivered by per-message deadlines, or by arbitrary application logic using the WriteReceipts returned by SendFlow::write(). The application can be notified by callback when a message is delivered or abandoned.

SendFlows set to priority PRI_PRIORITY (PRI_4) or higher (PRI_IMMEDIATE, PRI_FLASH, and PRI_FLASHOVERRIDE) are considered time critical. Sending messages on time critical flows affects congestion control.

When it’s done, the application can shut down the RTMFP in an orderly manner or abruptly.

Threading Model

The protocol implementation is single-threaded and has no locks/mutexes. All calls to its APIs must be externally synchronized, for example by all being in the same thread or run-loop-like construct. This was done to improve portability and performance, since locking can be very expensive on modern CPUs. Synchronization is abstracted by the Platform Adapter’s perform method to allow for offloading some expensive or time-consuming operations to other cores/threads, if desired.

Platform Adapter

The protocol implementation doesn’t directly interact with the operating system’s UDP sockets, clock, run loops, locks, or threads. These interactions are abstracted to a Platform Adapter provided by the host program.

The Platform Adapter will be a concrete implementation of com::zenomt::rtmfp::IPlatformAdapter, that calls the RTMFP public instance methods in its “Used by the Platform Adapter” section. The adapter provides the current time, reading and writing to sockets, timing, and synchronization.

The library provides two example platform adapters that run in RunLoops: PosixPlatformAdapter for pure single-threaded applications, and PerformerPosixPlatformAdapter to allow for offloading CPU-intensive public-key cryptography to a worker thread. These platform adapters should be suitable for many applications on Unix-like operating systems and should serve as examples of how to write single-threaded and multi-threaded platform adapters for your host application.

There is no requirement for Platform Adapter’s interfaces to be UDP sockets. For example, an interface could be a SOCKS or TURN proxy, tunnel, or network simulator.

RunLoop and Performer

For Unix-like operating systems, this library provides a simple select() based run loop suitable for many socket-based applications. It also includes a simple epoll based run loop for Linux that scales better than select() for handling many sockets. Use the PreferredRunLoop alias to automatically choose the best variant available at compile time for the target OS.

A Performer can be attached to a run loop to enable invoking a task inside/synchronized with the run loop from any thread. Performers are used with the PerformerPosixPlatformAdapter.


Microsoft Windows is not an officially supported platform. However, the core library (excluding the platform adapters, run loops, and Performer) should build on Windows, and maintenance of the core for that platform will be attempted as time and help from the community allow. Please open an issue if there is a problem with the core library on Windows.

To use this library on Windows, you will need to supply an appropriate platform adapter.

Please contact the maintainer or open an issue to request for a link to your Windows platform adapter to be added here in this document.

Cryptography Adapter

RFC 7016 describes a generalized framework for securing RTMFP communication according to the needs of the application, and leaves cryptographic specifics to a Cryptography Profile. This library doesn’t lock its application to any particular cryptography profile, and is written to support many potential profiles. The cryptography profile is implemented by a concrete ICryptoAdapter provided to the RTMFP on instantiation.

Most applications of RTMFP will use the Cryptography Profile for Flash Communication described in RFC 7425. This is provided by the FlashCryptoAdapter. Note that this adapter is abstract and must be subclassed to provide concrete implementations of the required cryptographic primitives. A concrete implementation using OpenSSL is provided by FlashCryptoAdapter_OpenSSL, which can also serve as an example for how to use other cryptography libraries. If you don’t have OpenSSL or you don’t want to use it, you can suppress building this module by defining make variable WITHOUT_OPENSSL. If your OpenSSL is installed outside of your compiler’s default include and linker search paths, you can define make variables OPENSSL_INCLUDEDIR and OPENSSL_LIBDIR with appropriate directives (see the Makefile for examples).

The OpenSSL implementation of the FlashCryptoAdapter implements 4096-bit Internet Key Exchange (IKE) Group 16, 2048-bit IKE Group 14, and 1024-bit IKE Group 2 for Diffie-Hellman key agreement. All implementations of the Flash Communication cryptography profile MUST implement at least Group 2; some also implement Group 14. This implementation prefers the strongest common group.

Note that RTMFP is not limited to Flash platform communication. This library provides a PlainCryptoAdapter suitable for testing and evaluation. As it provides no actual cryptography (and its cryptoHash256() and pseudoRandomBytes() methods are especially weak), it is not suitable for production use in the open Internet. Don’t.

Delay-Based Congestion Detection

Bufferbloat (excessive buffering and queuing in the network) can cause high end-to-end delays resulting in unacceptable performance for real-time applications. Unfortunately, the best solution to this problem (Active Queue Management with Explicit Congestion Notification) is not universally deployed in the Internet at this time.

In addition to the normal congestion signals (loss and Explicit Congestion Notification), this library can optionally infer likely congestion on a session from increases in Round-Trip Time (RTT). To enable this capability, use Flow::setSessionCongestionDelay() to set an amount of additional delay above the baseline RTT to be interpreted as an indication of congestion. The default value is INFINITY. A value of 0.1 seconds of additional delay is suggested for this feature.

The baseline RTT is the minimum RTT observed over at most the past three minutes. The baseline RTT observation window is cleared and reset in the following circumstances:

  • On a timeout (either from total loss or no data to send);
  • If the congestion window falls to the minimum value, which might happen after persistent inferred congestion that isn't actually our fault (such as from a change to the path or from competing traffic);
  • If the far end’s address changes;
  • If our address might have changed (inferred from receipt of a non-empty Ping that might be an address change validation probe from the far end).

From time-to-time, if a significant portion of the congestion window is being used, the congestion window will be temporarily reduced in order to probe the path for a new baseline RTT (in case our own sending is masking the baseline). Note that this can cause jitter.

If the Smoothed RTT is observed to be above the baseline plus the configured CongestionDelay (and is also at least 30ms), this is assumed to be an indication of congestion. The congestion controller responds to this as though it was loss.

This congestion detection scheme, like all end-to-end delay-based ones, is imperfect, and is subject to false positive signals caused by cases including:

  • Additional delay caused by data from the other end of this session;
  • Additional delay caused by delay-insensitive queue-filling transmissions competing through the bottleneck in either direction;
  • Changes to the return direction of the path that delay RTT measurements.

As such, this feature may not be indicated for all use cases. Care should be taken to enable this feature only when false positive congestion signals are unlikely, such as for substantially unidirectional media transmission through a dedicated bottleneck. False positives can cause transmission starvation.

This feature is inspired by Low Extra Delay Background Transport (LEDBAT), Self-Clocked Rate Adaptation for Multimedia (SCReAM), and Google’s BBR congestion control algorithm.

Explicit Congestion Notification

This implementation of RTMFP adds support for Explicit Congestion Notification (ECN). It adds a new experimental chunk “ECN Report” (type 0xec) for the receiver to send counts of received ECN codepoints back to the ECN sender. An RTMFP MUST NOT send an ECN Report to its peer unless it has received at least one valid packet in its S_OPEN session with that peer that is marked with an ECN Capable Transport code point (ECT(0), ECT(1), or ECN-CE).

An RTMFP receiver that is ECN-capable sends ECN Reports to its ECN-capable peer. ECN Reports SHOULD be assembled before the first Acknowledgement chunk in any packet containing an Acknowledgement (to avoid truncation of the report). In order that the ECN sender can detect whether the near and far interfaces, path, and receiver support ECN, an ECN-capable receiver SHOULD send an ECN Report in any packet that contains an Acknowledgement, if any packet marked with an ECN Capable Transport code point has been received either since the last time an ECN Report was sent or if a report has not yet been sent.

An RTMFP sender MUST stop marking packets with ECN Capable Transport code points if it determines that the receiver is not ECN-capable (for example, if the sender has not received at least one ECN Report along with an Acknowledgement for User Data that was sent in a marked packet during the open session with the peer).

An ECN-capable RTMFP receiver keeps at least a count of the number of packets received marked with ECN-CE. The endpoint sends the low 8 bits of the current counter to its peer in ECN Report chunks.

This implementation sends ECT(0). The congestion controller responds to increases of the ECN-CE-count as though it was loss. ECT(0) is only sent on packets containing User Data.

Explicit Congestion Notification Report Chunk (ECN Report)

 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
|      0xec     |               1               | ECN-CE-count  |

struct ecnReportChunkPayload_t
    uint8_t congestionExperiencedCountMod256; // ECN-CE-count
} :8;
  • congestionExperiencedCountMod256: The low 8 bits of the count of packets received from the peer marked with ECN-CE (ECN Congestion Experienced).

To Do

  • SendFlow unsent low water mark
  • More documentation
  • More unit tests
  • Performance counters
  • Persistent no-acks on buffer probes should be a timeout (eventually kill session)