📄 rtp.c
字号:
/* rtp.c - Real Time Protocol *//* *//* This program is free software; you can redistribute it and/or modify *//* it under the terms of the GNU General Public License as published by *//* the Free Software Foundation; either version 2, or (at your option) *//* any later version. *//* *//* This program is distributed in the hope that it will be useful, *//* but WITHOUT ANY WARRANTY; without even the implied warranty of *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *//* GNU General Public License for more details. *//* *//* You should have received a copy of the GNU General Public License *//* along with this program; if not, write to the Free Software *//* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA *//* 02111-1307, USA. */#include "rtp.h"/* used in NTP time calculation */#define SECS_BETWEEN_1900_1970 2208988800u/* tool identification */char ecomm_id[] = "e-Comm (C) ComunIP";/* Functions for double hashing */unsigned int _rtp_members_h1 (const void *key) { return (((rtp_source_t *) key) -> ssrc % RTP_HASH_SIZE);}unsigned int _rtp_members_h2 (const void *key) { return (1 + ((rtp_source_t *) key) -> ssrc % (RTP_HASH_SIZE - 2));}/* Match function */int _rtp_members_match (const void *key1, const void *key2) { return (((rtp_source_t *) key1) -> ssrc == ((rtp_source_t *) key2) -> ssrc);}/* Initializes a RTP session */void rtp_init (rtp_t *s, int flags) { uint8_t *username = getenv("LOGNAME"); uint8_t *hostname = getenv("HOSTNAME"); pthread_mutex_init (&s -> guard, NULL); /* set RTP build flags */ s -> flags = flags; s -> seq = (uint16_t) rand32(); /* initialize sequencing */ s -> cycles = 0; s -> ssrc = (uint32_t) rand32(); /* get random SSRC id */ s -> pcount = 0; s -> ocount = 0; s -> cc = 0; memset (s -> cname, '\0', RTP_SDES_MAX); memset (s -> name, '\0', RTP_SDES_MAX); memset (s -> email, '\0', RTP_SDES_MAX); memset (s -> phone, '\0', RTP_SDES_MAX); memset (s -> loc, '\0', RTP_SDES_MAX); memset (s -> tool, '\0', RTP_SDES_MAX); memset (s -> note, '\0', RTP_SDES_MAX); sprintf(s -> cname, "%s@%s", username, hostname); sprintf(s -> tool, "%s", ecomm_id); ohtbl_init (&s -> members, RTP_HASH_SIZE, _rtp_members_h1, _rtp_members_h2, _rtp_members_match, NULL, RTP_HASH_TOLERANCE / 2); return;}/* Destroy RTP session */void rtp_destroy (rtp_t *s) { rtp_source_t *member; pthread_mutex_lock (&s -> guard); ohtbl_flush (&s -> members); while ((member = (rtp_source_t *) ohtbl_traverse(&s -> members)) != NULL) { phtbl_destroy (&member -> pqueue); pthread_mutex_destroy (&member -> guard); } ohtbl_destroy (&s -> members); pthread_mutex_destroy (&s -> guard); return;}/* Add new csrc to RTP parameters, returns 0 on fail, 1 on success */int rtp_add_csrc (rtp_t *s, uint32_t csrc) { int idx; /* index */ /* put csrc in network byte order */ csrc = htonl (csrc); pthread_mutex_lock (&s -> guard); /* checks for maximal csrc number */ if (s -> cc >= 15) { pthread_mutex_unlock (&s -> guard); return (0); } /* check if new csrc doesn't exist in csrc list */ for (idx = 0; idx < s -> cc; idx++) { if (s -> csrc[idx] == csrc) { pthread_mutex_unlock (&s -> guard); return (0); } } /* just append new csrc to list */ s -> csrc[s -> cc++] = csrc; pthread_mutex_unlock (&s -> guard); return (1);}/* Remove a csrc from list, returns 0 on fail, 1 on success */int rtp_del_csrc (rtp_t *s, uint32_t csrc) { int cur, prev; /* current and previous index */ /* put csrc in network byte order */ csrc = htonl (csrc); pthread_mutex_lock (&s -> guard); /* tries to remove element */ for (cur = 0, prev = 0; prev < s -> cc; cur++, prev++) { if (s -> csrc[cur] == csrc) cur++; s -> csrc[prev] = s -> csrc[cur]; } /* checks for empty csrc list */ if (s -> cc > 0 && prev != cur) { s -> cc--; pthread_mutex_unlock (&s -> guard); return (1); } pthread_mutex_unlock (&s -> guard); return (0);}int rtp_update_sr (rtp_source_t *member, vstr_t *p) { rtcp_sr_t *sr = (rtcp_sr_t *) p -> head; member -> lsr = sr -> rtp_ts; return (0);}int rtp_update_rr (rtp_source_t *member, vstr_t *p) { rtcp_report_t *rr = (rtcp_report_t *) p -> head; struct timeval ts; gettimeofday (&ts, NULL); member -> rtt = (ts.tv_usec + ts.tv_sec * 1000000) - (rr -> lsr + rr -> dlsr); member -> jitter = rr -> jitter; return (0);}void rtp_update_sdes_item (char *data, int size, vstr_t *p, int *flag, int item) { if (!(*flag & item)) { *flag |= item; vstr_get_head (p, data, size); } else vstr_adv_head (p, size); return;}int rtp_update_sdes (rtp_source_t *member, vstr_t *p) { int flag = 0; rtcp_sdes_item_t *item = (rtcp_sdes_item_t *) p -> head; char *c; int i = 0; while (item -> type != RTCP_SDES_END) { vstr_adv_head (p, sizeof(uint16_t)); switch (item -> type) { case RTCP_SDES_CNAME: rtp_update_sdes_item (member -> cname, item -> length, p, &flag, SDES_CNAME); break; case RTCP_SDES_NAME: rtp_update_sdes_item (member -> name, item -> length, p, &flag, SDES_NAME); break; case RTCP_SDES_EMAIL: rtp_update_sdes_item (member -> email, item -> length, p, &flag, SDES_EMAIL); break; case RTCP_SDES_PHONE: rtp_update_sdes_item (member -> phone, item -> length, p, &flag, SDES_PHONE); break; case RTCP_SDES_LOC: rtp_update_sdes_item (member -> loc, item -> length, p, &flag, SDES_LOC); break; case RTCP_SDES_TOOL: rtp_update_sdes_item (member -> tool, item -> length, p, &flag, SDES_TOOL); break; case RTCP_SDES_NOTE: rtp_update_sdes_item (member -> note, item -> length, p, &flag, SDES_NOTE); break; } item = (rtcp_sdes_item_t *) p -> head; } /* discard trailling null bytes */ c = (char *) p -> head; while (i++ < sizeof(uint32_t) && *c == '\0') { vstr_adv_head (p, sizeof(uint8_t)); c = (char *) p -> head; } return (0);}void rtp_discard_sdes (vstr_t *p) { rtcp_sdes_item_t *item = (rtcp_sdes_item_t *) p -> head; char *c; int i = 0; while (item -> type != RTCP_SDES_END) { vstr_adv_head (p, sizeof(uint16_t) + item -> length); item = (rtcp_sdes_item_t *) p -> head; } /* discard trailling null bytes */ c = (char *) p -> head; while (i++ < sizeof(uint32_t) && *c == '\0') { vstr_adv_head (p, sizeof(uint8_t)); c = (char *) p -> head; } return;}/* Create a new RTP packet */void rtp_send (rtp_t *s, rtp_param_t *param, vstr_t *p) { struct timeval ts; rtp_packet_t *rtp_packet = (rtp_packet_t *) p -> data; /* initialize RTP packet */ vstr_set (p, RTP_PACKET_IDX, RTP_PACKET_IDX); /* get timestamp */ gettimeofday (&ts, NULL); /* build the header in network byte order */ rtp_packet -> ver = RTP_VERSION; rtp_packet -> p = (param -> flags & FLAG_PADDING) ? 1 : 0; rtp_packet -> x = (param -> flags & FLAG_EXTENSION) ? 1 : 0; rtp_packet -> m = (param -> flags & FLAG_MARKER) ? 1 : 0; rtp_packet -> pt = param -> pt; rtp_packet -> ssrc = htonl(s -> ssrc); rtp_packet -> ts = htonl(ts.tv_usec + ts.tv_sec * 1000000); vstr_adv_tail (p, RTP_HEADER_SIZE); pthread_mutex_lock (&s -> guard); rtp_packet -> seq = htons(s -> seq); rtp_packet -> cc = s -> cc; /* update sequence number and check new cycle */ if (++s -> seq == 0) s -> cycles++; /* update packet and octet counters */ s -> pcount++; s -> ocount += p -> size; /* checks for optional CSRC list */ if (s -> cc > 0) vstr_put_tail (p, s -> csrc, s -> cc * sizeof(uint32_t)); pthread_mutex_unlock (&s -> guard); /* checks for optional header extension */ if (rtp_packet -> x != 0) { /* add optional header extension */ rtp_packet -> xdef = htons (param -> xdef); rtp_packet -> xlen = htons (param -> xlen); vstr_put_tail (p, &(rtp_packet -> xdef), 2 * sizeof(uint16_t)); if (rtp_packet -> xlen != 0) { rtp_packet -> xhdr = (uint32_t *) p -> tail; vstr_put_tail (p, param -> xhdr, param -> xlen * sizeof(uint32_t)); } } /* appends payload to packet */ rtp_packet -> payload = p -> tail; vstr_put_tail (p, param -> payload, param -> len); return;}/* Free a received RTP packet */void rtp_packet_free (rtp_packet_t *rtp_packet) { free (rtp_packet); return;}/* Updates jitter based on received packet */void rtp_update_jitter (rtp_source_t *r, uint32_t pkt_ts) { long d; long transit; unsigned long arrival; struct timeval ts; /* interarrival jitter statistics */ gettimeofday (&ts, NULL); arrival = ts.tv_usec + ts.tv_sec * 1000000; transit = arrival - pkt_ts; if (r -> transit == 0) r -> transit = transit; else { d = transit - r -> transit; r -> transit = transit; /* absolute value */ if (d < 0) d = -d; r -> jitter += (1.0 / 16.0) * ((double) d - r -> jitter); } return;}/* Functions for packet queue */unsigned int _rtp_pqueue_hash (const void *key) { return ((unsigned int)((rtp_packet_t *) key) -> seq);}int _rtp_pqueue_match (const void *key1, const void *key2) { return (((rtp_packet_t *) key1) -> seq == ((rtp_packet_t *) key2) -> seq);}int _rtp_pqueue_solve (const void *key1, const void *key2) { uint32_t current = ((rtp_packet_t *) key1) -> ts; uint32_t next = ((rtp_packet_t *) key2) -> ts; if (current < (uint32_t) -RTP_SOLVE_TIME) return (next > current); else return (next + (uint32_t) RTP_SOLVE_TIME > current + (uint32_t) RTP_SOLVE_TIME);}/* New member */rtp_source_t *rtp_new_member (uint32_t ssrc) { rtp_source_t *member; member = (rtp_source_t *) alloc (sizeof(rtp_source_t)); member -> ssrc = ssrc; pthread_mutex_init (&member -> guard, NULL); member -> max_seq = 0; member -> cycles = 0; member -> received = 0; member -> lost = 0; member -> frac = 0; member -> last_seq = 0; member -> transit = 0; member -> jitter = 0; member -> lsr = 0; member -> dlsr = 0; member -> min_seq = 0; member -> fail_count = 0; member -> cname[0] = '\0'; member -> name[0] = '\0'; member -> email[0] = '\0'; member -> phone[0] = '\0'; member -> loc[0] = '\0'; member -> tool[0] = '\0'; member -> note[0] = '\0'; phtbl_init (&member -> pqueue, RTP_MAX_QUEUE, _rtp_pqueue_hash, _rtp_pqueue_match, free, _rtp_pqueue_solve); return (member);}/* Free member */void rtp_free_member (rtp_source_t *ptr) { free (ptr); return;}/* Find member in table */rtp_source_t *rtp_find_member (ohtbl_t *htbl, uint32_t ssrc) { rtp_source_t get; get.ssrc = ssrc; return ((rtp_source_t *) ohtbl_lookup(htbl, &get));}/* Add member to table */int rtp_add_member (ohtbl_t *htbl, rtp_source_t *member) { return (ohtbl_insert (htbl, member));}/* Remove member from table */rtp_source_t *rtp_remove_member (ohtbl_t *htbl, uint32_t ssrc) { rtp_source_t remove;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -