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

RTCP support #14

Closed
gavv opened this issue Dec 15, 2015 · 3 comments
Closed

RTCP support #14

gavv opened this issue Dec 15, 2015 · 3 comments
Assignees
Milestone

Comments

@gavv
Copy link
Member

gavv commented Dec 15, 2015

RFC 3550 requires conforming implementations to provide RTCP support. In fact, roc can function without it, though RTCP provides some benefits:

  • without RTCP, sender has no feedback from receiver; it even doesn't know, if receiver was able to receive traffic, if receiver was able to process the traffic and didn't reject it for some reason, and if quality of service is acceptable;
  • RTCP allows receiver to detect associated streams from single sender in a standard-conforming way, e.g. audio stream and FEC stream (we're now using an ad-hoc implementation that conforms to no standard);
  • RTCP provides timing synchronisation for sender and receiver and for several streams of single sender (e.g. audio and video);
  • RTCP can be used to implement dynamic adjustment of latency and FEC code rate (using RFC 5725);
  • RTCP can be used to implement retransmission using RFC 4588 and RFC 4585;
  • RTCP allows multiple senders to share the same source transport address (e.g. in case of RTP translator);
  • RTCP allows seamless sender restart or address change (this also allows sender roaming);
  • RTCP allows receiver to terminate sender's session immediately without waiting for timeout;
  • RTCP is used in RTSP, which we may want to support in future;
  • with RTCP, receiver sends to sender various statistics that may be useful for troubleshooting, especially when receiver is some embedded device which is harder to debug;
  • some senders may reject connection if there is no RTCP feedback from receiver (I'm not aware of such senders however);
  • finally, RTCP also allows to exchange arbitrary application-specific data.

RTCP consists of the following message types:

  • SR (sender report): statistics sent from sender to receiver;
  • RR (receiver report): statistics and feedback send from receiver to sender;
  • SDES (source description items): sender identification sent from sender to receiver;
  • BYE: session termination, initiated by sender or receiver;
  • APP: arbitrary application-specific data.
@gavv gavv added this to the 0.2 milestone Dec 26, 2015
@gavv gavv mentioned this issue Jan 4, 2016
9 tasks
@gavv gavv added this to Frontlog in kanban board Apr 23, 2019
@gavv gavv moved this from Frontlog to In progress in kanban board Apr 23, 2019
@gavv gavv removed this from In progress in kanban board Apr 23, 2019
@gavv gavv added this to In progress in kanban board Apr 23, 2019
@gavv gavv moved this from In progress to Frontlog in kanban board Apr 23, 2019
@gavv gavv moved this from Frontlog to In progress in kanban board May 30, 2019
@gavv gavv changed the title Minimal RTCP support RTCP support May 30, 2019
@gavv gavv moved this from In progress to Frontlog in kanban board May 30, 2019
@gavv gavv removed this from the 0.2.0 milestone Jul 8, 2020
@gavv
Copy link
Member Author

gavv commented Sep 4, 2023

Steps

Implement components

  • rtcp::Parser
  • rtcp::Composer
  • rtcp::Builder
  • rtcp::Traverser
  • rtcp::XrTraverser
  • rtcp::SdesTraverser
  • rtcp::ByeTraverser
  • rtcp::IStreamController
  • rtcp::Reporter
  • rtcp::Communicator (process and generates packets)
  • rtcp::RttEstimator (estimates RTT based on XR)

Refine error handling

  • instead of INVALID state, keep only END state and add bool error() getter to check if there were errors; this will make user code less bug prone - the last state is always END
  • if we skip some packet/chunk/block, we should set error flag so that the user can check it with bool error() getter; this should be done in all traverser
  • when we skip something, we should allow to continue to next item, don't fail instantly, so that the user could parse everything that is parsable

Support padding

  • RTCP traverser: remove padding
  • RTCP builder: pad last packet in compound

Refine test coverage

  • unknown RTCP packet type
  • unknown XR blocks
  • zero blocks (RR, SR, XR)
  • zero sub-blocks (XR DLRR)
  • zero chunks, zero items (SDES)
  • zero sources (BYE)
  • empty strings (SDES item, BYE reason)
  • multiple SDES chunks
  • test for various invalid packets
  • tests for padding

Integration into pipeline

  • teach receiver to send packets
  • teach sender to receive packets
  • teach netio to share port for receiving and sending
  • receiver: implement rtcp::IStreamController
  • receiver: query reports from sessions (multiple streams per each session)
  • receiver: pass reports to sessions
  • receiver: session routing based on RTCP
  • receiver: associate streams based on SDES CNAME messages
  • receiver: terminate sessions based on BYE messages
  • sender: implement rtcp::IStreamController
  • sender: query report from pipeline
  • sender: pass report to pipeline

Reports checklist

  • receiver: fully fill RR/XR
  • receiver: fully handle SR/XR
  • sender: fully fill SR/XR
  • sender: fully handle RR/XR

Packet handling checklist

  • SDES: generate (on sender and receiver)
  • SDES: process (on sender and receiver)
  • BYE: generate (on sender and receiver)
  • BYE: process (on sender and receiver)
  • SR, DLRR: generate (on sender)
  • SR, DLRR: process (on receiver)
  • RR, RRTR: generate (on receiver)
  • RR, RRTR: process (on sender)

API and CLI

  • Extend the public API. Add control port type and RTCP protocol. Allow to bind and connect receiver and sender to control ports. Allow to bind sender to different source and repair ports.
  • Add RTCP port to command-line tools.
  • Support two-way control packet exchange in roc_sender_encoder & roc_receiver_decoder

High-level tests

  • rtcp communicator
  • pipeline
  • public_api

@gavv gavv moved this from Frontlog to In work in kanban board Nov 7, 2023
@gavv gavv added this to the next milestone Nov 24, 2023
gavv added a commit that referenced this issue Nov 25, 2023
- unify code in iterators
- use index instead of pointer to benefit from slice
  bounds checking
- more careful checks for various corner cases
- add iterator error() method that reports if parsing error
  occurred
- when possible, skip malformed sub-packets/blocks instead of
  terminating the whole iteration (and raise error flag)
- fix frac_loss/cum_loss fields setters
- add traverser tests and cover various invalid packets and
  corner cases
gavv added a commit that referenced this issue Nov 28, 2023
gavv added a commit that referenced this issue Nov 28, 2023
gavv added a commit that referenced this issue Dec 29, 2023
rtcp::Communicator is top-level roc_rtcp class. It holds a reference
to IStreamController, generates & processes RTCP packets, and invokes
stream controller methods to gather local reports and handle received
remote reports.

IStreamController is implemented by sender and receiver pipelines.

Internally rtcp::Communicator uses rtcp::Reporter, which maintains
a hash table of all discovered participants and collects local/remote
reports to/from them.

List of changes:

- rtcp::Session is renamed to rtcp::Communicator

- rtcp::IReceiverHooks and rtcp::ISenderHooks are
  replaced with rtcp::IStreamController

- rtcp::SendingMetrics/ReceptionMetrics/LinkMetrics are
  replaced with 2 structs: SendReport and RecvReport

- new class rtcp::Reporter

- new struct rtcp::Config

- rtcp::Communicator now can parse & generate all necessary blocks
  as defined by RFC 3550 (SR, RR, XR, SDES, BYE)

- rtcp::Communicator can split big reports into multiple packets
  when number of participants is high

- rtcp::Reporter collects data from all blocks, handles timeouts,
  BYE messages, and SSRC collisions, as defined by RFC 3550

- RTCP exchange is covered by tests
gavv added a commit that referenced this issue Dec 29, 2023
gavv added a commit that referenced this issue Dec 29, 2023
gavv added a commit that referenced this issue Dec 29, 2023
- Introduce rtp::Identity which handles generation of
  SSRC and CNAME

- Introduce packet::ISequencer which hides filling of
  protocol-specific packet fields during packetization

- Add rtp::Sequencer which implements packet::ISequencer
  and internally used rtp::Identity

- Use ISequencer in Packetizer

- Add Packet getters for STS/CTS

- Make Packetizer and Depacketizer independent of specific
  packet protocol (RTP)

- Add validation to all classes in roc_pipeline

- Integrate rtp::Identity and rtp::Sequencer into
  sender and receiver pipelines

- Cosmetic renames
gavv added a commit that referenced this issue Dec 29, 2023
gavv added a commit that referenced this issue Dec 29, 2023
ReceiverSessionRouter maintains mapping of SSRC, source address,
CNAME, and sessions, and routes packets to sessions.

Some pipeline tests mistakenly didn't set SSRC or source addresses
of packets, which is now fixed.
gavv added a commit that referenced this issue Jan 3, 2024
gavv added a commit that referenced this issue Jan 3, 2024
@gavv gavv mentioned this issue Jan 20, 2024
13 tasks
gavv added a commit that referenced this issue Jan 26, 2024
Extract starting sending and receiving on UDP port into separate
tasks, which can be executed later. This is needed when we don't know
if we will be sending or receiving at the time when we construct port.
gavv added a commit that referenced this issue Jan 26, 2024
- Pipeline endpoints (SenderEndpoint, ReceiverEndpoint) are
  now bidirectional. Each one may have inbound_writer() for
  packets received from network and outbound_writer() for
  packets to be sent to network.

- On sender endpoints, inbound_writer() is optional. It is used
  for RTCP endpoints to get feedback from receiver.

- On receiver endpoints, outbound_writer() is optional. It is used
  for RTCP endpoints to produce feedback for sender.

- Both receiver and sender pipelines now both generate and process
  RTCP reports.

- Receiver now tracks what streams it has and collects reports
  from all streams of each session.

- For RTCP endpoints, roc_node now configures roc_netio to create
  bidirectional UDP ports, and properly connects them with
  bidirectional pipeline endpoints.
gavv added a commit that referenced this issue Jan 26, 2024
- Allow to configure rtcp::Communicator in one of the 2 modes:

  - either set report_address, which defines destination
    address for all generated reports

  - or set report_back flag, which tells communicator to collect
    addresses of remote participants and send reports to each

- In roc_pipeline, use report_address on sender and
  report_back on receiver

- Rename rtcp::IStreamController to rtcp::IParticipant and
  simplify its interface

- In rtcp::Reporter, keep track of destination addresses and
  streams associated with them

- In rtcp::Reporter, rebuild index of addresses and streams
  only when something changed, instead of every packet generation
gavv added a commit that referenced this issue Jan 26, 2024
- Add rtcp::RttEstimator, which computes RTT and clock offset
  based on data from RTCP reports

- In rtcp::Reporter, create RttEstimator for each stream and
  pass data from reports to it

- Add clock_offset and rtt fields to SendReport and RecvReport,
  fill it with estimated values, and pass to pipeline
gavv added a commit that referenced this issue Jan 26, 2024
- Unify types of report fields: use nanoseconds and unsized
  types where possible

- Query streams before processing reports, not only before
  generating reports.

- Fill ext_first_seqnum from reports.

- Adjust tests to the above changes.

- Cleanup headers helpers.

- Simplify RTT estimator metrics.
gavv added a commit that referenced this issue Feb 5, 2024
gavv added a commit that referenced this issue Feb 5, 2024
After adding new pipeline metrics it now became possible to test
RTCP support in pipeline tests:

  - in test_receiver_source, we deliver fake RTCP reports
    to receiver and check that it properly populated metrics
    from it, which means that RTCP was correctly parsed, routed,
    and processed by pipeline

  - in test_loopback_sink_2_source, we enable bi-directional exchange
    of RTCP reports between sender and receiver and check that
    metrics on both side are always close to each other
gavv added a commit that referenced this issue Feb 7, 2024
- Add test::ControlReader that allows to inspect RTCP reports

- Add tests to receiver_source and sender_sink for different
  configurations (one session, two sessions, unicast, multicast)
  that inspect generated reports

- Fix high CPU usage in rtcp::Communicator

- Fix missing reports in rtcp::Reporter when DLRR/DLSR is zero
gavv added a commit that referenced this issue Feb 7, 2024
SenderEncoder and ReceiverDecoder now both have write_packet()
and read_packet() methods.
@gavv
Copy link
Member Author

gavv commented Feb 10, 2024

Done.

@gavv gavv closed this as completed Feb 10, 2024
kanban board automation moved this from In work to Done Feb 10, 2024
gavv added a commit that referenced this issue Feb 10, 2024
gavv added a commit that referenced this issue Feb 18, 2024
FEC packets were routed incorrectly when using roc_sender_encoder
and roc_receiver_decoder API, which resulted to dropping all FEC
packets and not being able to repair losses. This patch disables
normal multi-session routing logic when pipeline is created via
that API, because this API anyway uses only a single session per
receiver or sender.

Changes:

- Add per-slot configs for sender and receiver
- Add enable_routing flag to receiver slot config
- If this flag is disabled, allow only single session per
  slot, and always route packets to that session
- By default, the routing is enabled
- In node::ReceiverDecoder (roc_receiver_decoder), routing
  is disabled

Tests:

- Cover FEC in loopback_encoder_2_decoder tests
- Rework roc_receiver_decoder test that implicitly relied on
  (incorrect) routing

API:

- Add comment that roc_sender_encoder/roc_receiver_decoder
  are single-session

Sponsored-by: waspd
gavv added a commit that referenced this issue Feb 18, 2024
Since roc_sender_encoder / roc_receiver_decoder now support only
a single connection (session), roc_sender_encoder_query() and
roc_receiver_decoder_query() are reworked to return a single
roc_connection_metrics struct instead of array of structs.

Comments are updated accordingly.

Sponsored-by: waspd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

2 participants