📄 rtp.c
字号:
for(i = 0; i < RTP_DB_SIZE; i++) { start = &session->rr[ssrc_hash(ssrc)][i]; cur = start->next; while (cur != start) { if (cur->reporter_ssrc == ssrc) { tmp = cur; cur = cur->prev; tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; xfree(tmp->ts); xfree(tmp->rr); xfree(tmp); } cur = cur->next; } } /* Remove columns, i.e. ssrc == reporter_ssrc */ for(i = 0; i < RTP_DB_SIZE; i++) { start = &session->rr[i][ssrc_hash(ssrc)]; cur = start->next; while (cur != start) { if (cur->rr->ssrc == ssrc) { tmp = cur; cur = cur->prev; tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; xfree(tmp->ts); xfree(tmp->rr); xfree(tmp); } cur = cur->next; } }}static void timeout_rr(struct rtp *session, struct timeval *curr_ts){ /* Timeout any reception reports which have been in the database for more than 3 */ /* times the RTCP reporting interval without refresh. */ rtcp_rr_wrapper *start, *cur, *tmp; rtp_event event; int i, j; for(i = 0; i < RTP_DB_SIZE; i++) { for(j = 0; j < RTP_DB_SIZE; j++) { start = &session->rr[i][j]; cur = start->next; while (cur != start) { if (tv_diff(*curr_ts, *(cur->ts)) > (session->rtcp_interval * 3)) { /* Signal the application... */ if (!filter_event(session, cur->reporter_ssrc)) { event.ssrc = cur->reporter_ssrc; event.type = RR_TIMEOUT; event.data = cur->rr; event.ts = curr_ts; session->callback(session, &event); } /* Delete this reception report... */ tmp = cur; cur = cur->prev; tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; xfree(tmp->ts); xfree(tmp->rr); xfree(tmp); } cur = cur->next; } } }}static const rtcp_rr* get_rr(struct rtp *session, uint32_t reporter_ssrc, uint32_t reportee_ssrc){ rtcp_rr_wrapper *cur, *start; start = &session->rr[ssrc_hash(reporter_ssrc)][ssrc_hash(reportee_ssrc)]; cur = start->next; while (cur != start) { if (cur->reporter_ssrc == reporter_ssrc && cur->rr->ssrc == reportee_ssrc) { return cur->rr; } cur = cur->next; } return NULL;}static inline void check_source(source *s){#ifdef DEBUG assert(s != NULL); assert(s->magic == 0xc001feed);#else UNUSED(s);#endif}static inline void check_database(struct rtp *session){ /* This routine performs a sanity check on the database. */ /* This should not call any of the other routines which */ /* manipulate the database, to avoid common failures. */#ifdef DEBUG source *s; int source_count; int chain; assert(session != NULL); assert(session->magic == 0xfeedface); /* Check that we have a database entry for our ssrc... */ /* We only do this check if ssrc_count > 0 since it is */ /* performed during initialisation whilst creating the */ /* source entry for my_ssrc. */ if (session->ssrc_count > 0) { for (s = session->db[ssrc_hash(session->my_ssrc)]; s != NULL; s = s->next) { if (s->ssrc == session->my_ssrc) { break; } } assert(s != NULL); } source_count = 0; for (chain = 0; chain < RTP_DB_SIZE; chain++) { /* Check that the linked lists making up the chains in */ /* the hash table are correctly linked together... */ for (s = session->db[chain]; s != NULL; s = s->next) { check_source(s); source_count++; if (s->prev == NULL) { assert(s == session->db[chain]); } else { assert(s->prev->next == s); } if (s->next != NULL) { assert(s->next->prev == s); } /* Check that the SR is for this source... */ if (s->sr != NULL) { assert(s->sr->ssrc == s->ssrc); } } } /* Check that the number of entries in the hash table */ /* matches session->ssrc_count */ assert(source_count == session->ssrc_count);#else UNUSED(session);#endif}static inline source *get_source(struct rtp *session, uint32_t ssrc){ source *s; check_database(session); for (s = session->db[ssrc_hash(ssrc)]; s != NULL; s = s->next) { if (s->ssrc == ssrc) { check_source(s); return s; } } return NULL;}static source *create_source(struct rtp *session, uint32_t ssrc, int probation){ /* Create a new source entry, and add it to the database. */ /* The database is a hash table, using the separate chaining */ /* algorithm. */ rtp_event event; struct timeval event_ts; source *s = get_source(session, ssrc); int h; if (s != NULL) { /* Source is already in the database... Mark it as */ /* active and exit (this is the common case...) */ gettimeofday(&(s->last_active), NULL); return s; } check_database(session); /* This is a new source, we have to create it... */ h = ssrc_hash(ssrc); s = (source *) xmalloc(sizeof(source)); memset(s, 0, sizeof(source)); s->magic = 0xc001feed; s->next = session->db[h]; s->ssrc = ssrc; if (probation) { /* This is a probationary source, which only counts as */ /* valid once several consecutive packets are received */ s->probation = -1; } else { s->probation = 0; } gettimeofday(&(s->last_active), NULL); /* Now, add it to the database... */ if (session->db[h] != NULL) { session->db[h]->prev = s; } session->db[ssrc_hash(ssrc)] = s; session->ssrc_count++; check_database(session); debug_msg("Created database entry for ssrc 0x%08lx (%d valid sources)\n", ssrc, session->ssrc_count); if (ssrc != session->my_ssrc) { /* Do not send during rtp_init since application cannot map the address */ /* of the rtp session to anything since rtp_init has not returned yet. */ if (!filter_event(session, ssrc)) { gettimeofday(&event_ts, NULL); event.ssrc = ssrc; event.type = SOURCE_CREATED; event.data = NULL; event.ts = &event_ts; session->callback(session, &event); } } return s;}static void delete_source(struct rtp *session, uint32_t ssrc){ /* Remove a source from the RTP database... */ source *s = get_source(session, ssrc); int h = ssrc_hash(ssrc); rtp_event event; struct timeval event_ts; assert(s != NULL); /* Deleting a source which doesn't exist is an error... */ gettimeofday(&event_ts, NULL); check_source(s); check_database(session); if (session->db[h] == s) { /* It's the first entry in this chain... */ session->db[h] = s->next; if (s->next != NULL) { s->next->prev = NULL; } } else { assert(s->prev != NULL); /* Else it would be the first in the chain... */ s->prev->next = s->next; if (s->next != NULL) { s->next->prev = s->prev; } } /* Free the memory allocated to a source... */ if (s->cname != NULL) xfree(s->cname); if (s->name != NULL) xfree(s->name); if (s->email != NULL) xfree(s->email); if (s->phone != NULL) xfree(s->phone); if (s->loc != NULL) xfree(s->loc); if (s->tool != NULL) xfree(s->tool); if (s->note != NULL) xfree(s->note); if (s->priv != NULL) xfree(s->priv); if (s->sr != NULL) xfree(s->sr); remove_rr(session, ssrc); /* Reduce our SSRC count, and perform reverse reconsideration on the RTCP */ /* reporting interval (draft-ietf-avt-rtp-new-05.txt, section 6.3.4). To */ /* make the transmission rate of RTCP packets more adaptive to changes in */ /* group membership, the following "reverse reconsideration" algorithm */ /* SHOULD be executed when a BYE packet is received that reduces members */ /* to a value less than pmembers: */ /* o The value for tn is updated according to the following formula: */ /* tn = tc + (members/pmembers)(tn - tc) */ /* o The value for tp is updated according the following formula: */ /* tp = tc - (members/pmembers)(tc - tp). */ /* o The next RTCP packet is rescheduled for transmission at time tn, */ /* which is now earlier. */ /* o The value of pmembers is set equal to members. */ session->ssrc_count--; if (session->ssrc_count < session->ssrc_count_prev) { gettimeofday(&(session->next_rtcp_send_time), NULL); gettimeofday(&(session->last_rtcp_send_time), NULL); tv_add(&(session->next_rtcp_send_time), (session->ssrc_count / session->ssrc_count_prev) * tv_diff(session->next_rtcp_send_time, event_ts)); tv_add(&(session->last_rtcp_send_time), - ((session->ssrc_count / session->ssrc_count_prev) * tv_diff(event_ts, session->last_rtcp_send_time))); session->ssrc_count_prev = session->ssrc_count; } /* Reduce our csrc count... */ if (s->should_advertise_sdes == TRUE) { session->csrc_count--; } if (session->last_advertised_csrc == session->csrc_count) { session->last_advertised_csrc = 0; } /* Signal to the application that this source is dead... */ if (!filter_event(session, ssrc)) { event.ssrc = ssrc; event.type = SOURCE_DELETED; event.data = NULL; event.ts = &event_ts; session->callback(session, &event); } xfree(s); check_database(session);}static inline void init_seq(source *s, uint16_t seq){ /* Taken from draft-ietf-avt-rtp-new-01.txt */ check_source(s); s->base_seq = seq; s->max_seq = seq; s->bad_seq = RTP_SEQ_MOD + 1; s->cycles = 0; s->received = 0; s->received_prior = 0; s->expected_prior = 0;}static int update_seq(source *s, uint16_t seq){ /* Taken from draft-ietf-avt-rtp-new-01.txt */ uint16_t udelta = seq - s->max_seq; /* * Source is not valid until MIN_SEQUENTIAL packets with * sequential sequence numbers have been received. */ check_source(s); if (s->probation) { /* packet is in sequence */ if (seq == s->max_seq + 1) { s->probation--; s->max_seq = seq; if (s->probation == 0) { init_seq(s, seq); s->received++; return 1; } } else { s->probation = MIN_SEQUENTIAL - 1; s->max_seq = seq; } return 0; } else if (udelta < MAX_DROPOUT) { /* in order, with permissible gap */ if (seq < s->max_seq) { /* * Sequence number wrapped - count another 64K cycle. */ s->cycles += RTP_SEQ_MOD; } s->max_seq = seq; } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { /* the sequence number made a very large jump */ if (seq == s->bad_seq) { /* * Two sequential packets -- assume that the other side * restarted without telling us so just re-sync * (i.e., pretend this was the first packet). */ init_seq(s, seq); } else { s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); return 0; } } else { /* duplicate or reordered packet */ } s->received++; return 1;}static double rtcp_interval(struct rtp *session){ /* Minimum average time between RTCP packets from this site (in */ /* seconds). This time prevents the reports from `clumping' when */ /* sessions are small and the law of large numbers isn't helping */ /* to smooth out the traffic. It also keeps the report interval */ /* from becoming ridiculously small during transient outages like */ /* a network partition. */ double const RTCP_MIN_TIME = 5.0; /* Fraction of the RTCP bandwidth to be shared among active */ /* senders. (This fraction was chosen so that in a typical */ /* session with one or two active senders, the computed report */ /* time would be roughly equal to the minimum report time so that */ /* we don't unnecessarily slow down receiver reports.) The */ /* receiver fraction must be 1 - the sender fraction. */ double const RTCP_SENDER_BW_FRACTION = 0.25; double const RTCP_RCVR_BW_FRACTION = (1-RTCP_SENDER_BW_FRACTION); /* To compensate for "unconditional reconsideration" converging */ /* to a value below the intended average. */ double const COMPENSATION = 2.71828 - 1.5; double t; /* interval */ double rtcp_min_time = RTCP_MIN_TIME; int n; /* no. of members for computation */ double rtcp_bw = session->rtcp_bw; /* Very first call at application start-up uses half the min */ /* delay for quicker notification while still allowing some time */ /* before reporting for randomization and to learn about other */ /* sources so the report interval will converge to the correct */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -