Prosody application note: Using RTCP

Introduction

In addition to defining RTP, RFC3550 also defines RTCP, a control protocol that allows endpoints to emit and receive statistical information relating to RTP traffic flows (for example providing packet loss and jitter statistics).

Prosody provides an API to control generation and reception of such RTCP packets. An application may choose just to generate RTCP packets for the benefit of a peer entity, or may, in addition, request the data in such received and/or transmitted packets to be supplied to the application. In the latter case, the data supplied is in the same format/byte-encoding as it occurs in the RTCP packets, a parsing library is supplied to help the application disect these packets and retrieve relevant statistical information.

RTCP Packet Transmission and Reception

An application must create one or more RTCP Handlers in order to permit RTCP packets to be transmitted and received and these need to be configured with a source description. Typically one RTCP handler will be created per VMPTx/VMPRx pair. The interval at which RTCP packets should be transmitted can be indicated by specifying RTCP bandwidth settings. A typical use of bandwith would be to set rtcp_bw field to 3200 (this being 5% 0f 64000).

Some older equipment may have interoperability problems with RTCP packets that include XR elements. It is possible to suppress these elements in RTCP packets generated by Prosody-S/Prosody-X by invoking sm_rtcphand_config_options with appropriate settings prior to invoking sm_rtcphand_config_sdes.

When a VMPRx is created, it will report the port on which it expects to receive RTCP packets seen by peer RTP entities. This will typically be one plus the RTP port number.

When a VMPTx target address is configured, the target address and port for generated RTCP packets must be specified at the same time. The usual convention is for the RTCP port to be odd numbered and one plus the RTP port number.

In order to make a VMPTx that transmits RTP also to transmit RTCP, it is necessary to associate that VMPTx with an RTCP handler. Similarly, in order for a VMPRx to processing incoming RTCP, the VMPRx must be associated with an RTCP handler. Normally a given RTCP handler would be associated with a single pair of VMPTx and VMPRx objects, and will send statistics relating to jitter etc. experienced on that VMPRx to RTCP address/port specified in VMPTx associated with the RTCP handler. For special types of application it may be necessary to associate a single VMPTx and multiple VMPRxs with an RTCP handler in order that transmitted RTCP packets will contain multiple source report blocks, one for each VMPRx (SSRC) associated with that handler . If multiple VMPTxs are associated with an RTCP handler, reports will only be transmitted to the VMPTx RTCP address of the first associated VMPTx, and this VMPTx SSRC will be indicated as sender in the report.

Application Processing of RTCP Data

In order to receive data from RTCP packets into the application, it is necessary to configure the set of report types that the RTCP handler should pass up to the application. The set of report types is specified as a bitmask with bits numbered as follows:

  • bit 2 should be set to obtain data from RTCP packets transmitted by Prosody
  • bit 3 should be set to obtain data from RTCP packets received by Prosody
  • both bits 2 & 3 should be set to receive both types of packet
  • For example:
      SM_RTCPHAND_CONFIG_REPORTS_PARMS cfg;
      memset(&cfg,0,sizeof(cfg));
      cfg.reports = (1<<2) | (1<<3)
      ...
    

    An application might then launch an event driven thread to process RTCP data as it becomes available.

    	RTCP_BUFFER	buffer;
    
    	rtcp_buffer_init(&buffer);
    
    	for (;;)
    	{
    		int	rc;
    		SM_RTCPHAND_GET_DATA_PARMS rtcpGetData;
    		SM_RTCPHAND_STATUS_PARMS rtcpStatus;
    
    		smd_ev_wait(gRTCPEvent);
    
    		memset(&rtcpGetData,0,sizeof(rtcpGetData));
    		rtcpGetData.rtcphand   = gRTCPHandle;
    		rtcpGetData.max_length = rtcp_buffer_space(&buffer);
    		rtcpGetData.data       = rtcp_buffer_end(&buffer);
    
    		rc = sm_rtcphand_get_data(&rtcpGetData); 
    
    		if (rc != 0)
    		{
    			// handle error
    		}
    
    		if (rtcpGetData.done_length == 0)
    		{
    			// this must be called when no more data
    			rtcpStatus.rtcphand = rtcpSet->fRTCPHandle;
    
    			rc = sm_rtcphand_status(&rtcpStatus);
    
    			if (rc != 0)
    			{
    				// handle error
    			}
    		}
    		else
    		{
    			rtcp_buffer_append(&buffer,rtcpGetData.done_length);
    
    			if (rtcp_buffer_needed(&buffer) == 0)
    			{
    				int             rtcpType   = rtcp_buffer_type(&buffer);
    				unsigned char*  rtcpData   = rtcp_buffer_data(&buffer);
    				int             rtcpLength = rtcp_buffer_length(&buffer)-4;
    
    				// customer specific processing of RTCP using parsing library
    				processRTCPPacket(verbose,rtcpType,rtcpData,rtcpLength,rtcpStats);
    
    				rtcp_buffer_discard(&buffer);
    			}
    		}
    	}
    }
    

    RTCP Summary Reports

    In addition to transmitted and received RTCP packets, an application can request or configure local generation of sumnmary reports. The data associated with a summary report is passed up through the API in the same way as for transmitted and received RTCP packets and may also be parsed using RTCP parsing library.

    Notes on Prosody Generated RTCP XR Reports

    Prosody RTCP XR reports do not include following optional elements:

    In the VOIP Stats Block: