/* rtp_api.c: RTP API types, structures, and functions that a user
of RTP might require
Copyright 1997, 1998 Lucent Technologies; all rights reserved
*/
#include "sysdep.h"
#include "rtp_api_internal.h"
#include "rtp_mlist.h"
#include "rtp_api.h"
#include "rtp_encrypt.h"
#include "rtp_collision.h"
#include "rtp_lowlevel.h"
rtperror RTPLowLevelCreate(context *the_context){
context i;
InitRandom();
if (_RTP_contexts_in_use < _RTP_context_above_used){
/* Not all contexts #'s that have been allocated in the ContextList
are in use, so grab one of those. */
for (i=0; i < _RTP_context_above_used; i++){
if (ContextList[i] == NULL){
break;
}
}
}
else if (ContextList==NULL){
i = _RTP_context_above_used;
_RTP_context_above_used = _RTP_INIT_CONTEXTS_AVAIL;
ContextList = (_RTP_CONTEXT**) calloc(_RTP_INIT_CONTEXTS_AVAIL,
sizeof(_RTP_CONTEXT*));
}
else {
/* Need to increase the size of the ContextList. */
i = _RTP_context_above_used;
_RTP_context_above_used += _RTP_CONTEXT_INC;
ContextList = realloc(ContextList,
sizeof(_RTP_CONTEXT*) * _RTP_context_above_used);
}
ContextList[i] = malloc(sizeof(_RTP_CONTEXT));
_RTP_contexts_in_use++;
if (ContextList[i]==NULL){
return errordebug(RTP_CANT_ALLOC_MEM, "RTPLowLevelCreate", "%ld contexts in use",
_RTP_contexts_in_use);
}
ContextList[i]->context_num = i;
/* We do not set any defaults for the following fields, because
they must be filled in by the user, or are filled in when
RTPOpenConnection() is called: IP_address, RTP_port,
RTCP_port, RTP_socket, RTCP_socket,
key, user_info */
ContextList[i]->CSRCList = NULL;
ContextList[i]->CSRClen = 0;
ContextList[i]->contriblist = NULL;
ContextList[i]->unique_id_counter = 0;
ContextList[i]->num_remaps = 0;
ContextList[i]->reconsideration = RTP_RECONSIDERATION_UNCONDITIONAL;
ContextList[i]->prev_group_size = 0;
ContextList[i]->session_bandwidth = _RTP_DEFAULT_BANDWIDTH;
ContextList[i]->rtcp_fraction = (float) _RTP_DEFAULT_RTCP_FRAC;
ContextList[i]->sender_bw_fraction = _RTP_DEFAULT_SENDER_BW_FRAC;
SetDefaultPayloadRates(ContextList[i]);
/* NOTE: Which of these should be done at the opening
of each connection? */
ContextList[i]->init_RTP_timestamp = random32(i);
ContextList[i]->time_elapsed = 0;
/* The sequence # should only use the first 16 bits.
The rest is the extension, so keep the extension
part initially at 0 */
ContextList[i]->seq_no = random32(i) % 65536;
ContextList[i]->init_seq_no = ContextList[i]->seq_no;
/* SSRC is not set until first packet is sent. However,
for now we set the SSRC to 0 so that we can establish a member.
We will move the member in the SSRC hash once we change
the SSRC */
ContextList[i]->static_ssrc = 0;
ContextList[i]->ssrc_mask = 0;
ContextList[i]->my_ssrc = 0;
ContextList[i]->hdr_extension = NULL;
/* Initially, nobody has sent me any packets. */
ContextList[i]->most_recent_rtp_sender = NULL;
ContextList[i]->most_recent_rtcp_sender = NULL;
ContextList[i]->most_recent_addr.sa_family = _RTP_ADDRESS_NOT_YET_KNOWN;
ContextList[i]->PreventEntryIntoFlaggingFunctions = FALSE;
ContextList[i]->UpdateMemberCallBack = NULL;
ContextList[i]->ChangedMemberInfoCallBack = NULL;
ContextList[i]->ChangedMemberSockaddrCallBack = NULL;
ContextList[i]->CollidedMemberCallBack = NULL;
ContextList[i]->RevertingIDCallBack = NULL;
RTP_Membership_Initialize(ContextList[i]);
/* Place myself on the memberlist */
ContextList[i]->my_memberinfo =
EstablishNewMember(ContextList[i], ContextList[i]->my_ssrc, NULL,
NULL, FALSE, RTP_MEMBER_PENDING);
/* I should always be confirmed */
ChangeMemberStatus(ContextList[i], ContextList[i]->my_memberinfo,
RTP_MEMBER_CONFIRMED);
ContextList[i]->my_memberinfo->my_addr[0].sa_family =
_RTP_ADDRESS_NOT_YET_KNOWN;
ContextList[i]->my_memberinfo->my_addr[1].sa_family =
_RTP_ADDRESS_NOT_YET_KNOWN;
gettimeofday(&ContextList[i]->last_rtcp_send, NULL);
*the_context = i;
return RTP_OK;
}
rtperror RTPLowLevelDestroy(context cid){
rtperror err;
contributor_t *con, *tempcon;
if ((err = ValidRTPContext(cid, "RTPDestroy")) != RTP_OK)
return err;
/* Destroy all members and links */
CleanMembershipList(ContextList[cid], &ContextList[cid]->RTP_MemberList);
CleanMembershipList(ContextList[cid], &ContextList[cid]->RTP_SenderList);
DeleteSSRCHashTable(ContextList[cid]);
DeleteUniqueIDHashTable(ContextList[cid]);
DeleteCNAMEHashTable(ContextList[cid]);
/* Remove the CSRC list (if it exists) */
if (ContextList[cid]->CSRCList != NULL){
free(ContextList[cid]->CSRCList);
}
/* Remove the contributor list (if it exists) */
con = ContextList[cid]->contriblist;
while(con != NULL) {
tempcon = con;
con = con->next;
free(tempcon);
}
/* Mark the context as unused */
free (ContextList[cid]);
ContextList[cid] = NULL;
_RTP_contexts_in_use--;
return RTP_OK;
}
rtperror RTPSessionSetRTPStampRate(context cid, int32 payload_type,
int32 usec){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionSetRTPStampRate")) != RTP_OK)
return err;
if (payload_type >= _RTP_MAX_PAYLOAD_TYPES){
return errordebug(RTP_BAD_PROFILE, "RTPSessionSetRTPStampRate",
"Payload type %ld not allowed", payload_type);
}
ContextList[cid]->profileRTPTimeRates[payload_type] = usec;
return RTP_OK;
}
rtperror RTPSessionGetRTPStampRate(context cid, int32 payload_type,
int32 *usec){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionGetRTPStampRate")) != RTP_OK)
return err;
if (payload_type >= _RTP_MAX_PAYLOAD_TYPES){
return errordebug(RTP_BAD_PROFILE, "RTPSessionGetRTPStampRate",
"Payload type %ld not allowed", payload_type);
}
*usec = ContextList[cid]->profileRTPTimeRates[payload_type];
return RTP_OK;
}
rtperror RTPSessionSetReconsideration(context cid, reconsideration_t value){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionSetReconsideration")) != RTP_OK)
return err;
ContextList[cid]->reconsideration = value;
return RTP_OK;
}
rtperror RTPSessionGetReconsideration(context cid, reconsideration_t *value){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionGetReconsideration")) != RTP_OK)
return err;
*value = ContextList[cid]->reconsideration;
return RTP_OK;
}
rtperror RTPSessionSetExtension(context cid, rtp_hdr_ext *the_ext){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionSetExtension")) != RTP_OK)
return err;
ContextList[cid]->hdr_extension = the_ext;
return RTP_OK;
}
rtperror RTPSessionGetExtension(context cid, rtp_hdr_ext **the_ext){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionSetExtension")) != RTP_OK)
return err;
*the_ext = ContextList[cid]->hdr_extension;
return RTP_OK;
}
rtperror RTPSessionSetBandwidth(context cid, float session_bwidth,
float rtcp_fraction){
rtperror err;
if ((err = ValidRTPContext(cid, "RTPSessionSetBandwidth")) != RTP_OK)
return err;
if ((session_bwidth > 0.0) && (rtcp_fraction > 0.0)) {
/* Disallow invalid or meaningless bandwidth values. */
/* Note: in a future version we will allow bandwidth or fraction 0,
which will mean "never send RTCP packets".*/
/* Note: we should check for NaN and Infinity here too, but I'm not sure
how to do that portably. */
ContextList[cid]->session_bandwidth = session_bwidth;
ContextList[cid]->rtcp_fraction = rtcp_fraction;
return RTP_OK;
} else {
return errordebug(RTP_BAD_VALUE, "RTPSessionSetBandwidth",
"context %d, invalid bandwidth and/or fraction %f / %f",
(int)cid, session_bwidth, rtcp_fraction);
}
}
rtperror RTPSessionGetBandwidth(context cid, float *session_bwidth,
float *rtcp_fraction){
rtperror err;
if ((err = ValidRTPCo