apps/streamer/rtp.c

Go to the documentation of this file.
00001 /*
00002  * This code includes an implememtation of RFC1889 (RTP)
00003  *
00004  * (C)2004 Alexander Melichenko <alexlp@freemail.ru>
00005  * The code was optimized for use in Elphel 313 cameras
00006  *
00007  * This file consist a portin of code from the UCL Common Code Library (2.4.18)
00008  * Copyright (c) 1998-2001 University College London
00009  *
00010  *  This program is free software: you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation, either version 3 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00022  */
00023 
00024 #include <stdint.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <sys/time.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <sys/param.h>
00031 #include <sys/socket.h>
00032 #include <netinet/in.h>
00033 #include <netinet/ip.h>
00034 #include <netinet/udp.h>
00035 #include <linux/if_ether.h>
00036 //#include <linux/if_packet.h>
00037 #include <errno.h>
00038 
00039 #include "str.h"
00040 #include "net_udp.h"
00041 #include "rtp.h"
00042 
00043 #include <sys/types.h>
00044 #include <sys/uio.h>
00045 #include <unistd.h>
00046 
00047 #define SECS_BETWEEN_1900_1970 2208988800u
00048 void ntp64_time(uint32_t * ntp_sec, uint32_t * ntp_frac)
00049 {
00050     struct timeval now;
00051     gettimeofday(&now, NULL);
00052     /* NB ntp_frac is in units of 1 / (2^32 - 1) secs. */
00053     *ntp_sec = now.tv_sec + SECS_BETWEEN_1900_1970;
00054     *ntp_frac =
00055         (now.tv_usec << 12) + (now.tv_usec << 8) -
00056         ((now.tv_usec * 3650) >> 6);
00057 }
00058 
00059 static void init_rng(const int8_t  *s)
00060 {
00061     static uint32_t seed;
00062     if (s == NULL) {
00063         /* This should never happen, but just in case */
00064         s = "ARANDOMSTRINGSOWEDONTCOREDUMP";
00065     }
00066     if (seed == 0) {
00067         pid_t p = getpid();
00068         while (*s) {
00069             seed += (uint32_t) * s++;
00070             seed = seed * 31 + 1;
00071         }
00072         seed = 1 + seed * 31 + (uint32_t) p;
00073         srand48(seed);
00074     }
00075 }
00076 
00077 int32_t rtp_init(struct param *p)
00078 {
00079     static int8_t  hname[MAXHOSTNAMELEN];
00080     int32_t res;
00081 
00082     gethostname(hname, MAXHOSTNAMELEN);
00083     init_rng(hname);
00084     
00085     if (p->dport % 2) {
00086         return -1;
00087     }
00088 
00089     res = udp_init4(p);
00090 
00091 
00092     if (res != 0) {
00093         return -1;
00094     }
00095     
00096     p->ip_id = 0;
00097     p->my_ssrc = (uint32_t) lrand48();
00098     p->rtp_seq = (uint16_t) lrand48();
00099 
00100     return 0;
00101 }
00102 
00103 
00104 /*
00105  * compute an IP header checksum.
00106  * don't modify the packet.
00107  */
00108 uint16_t
00109 in_chksum(const uint16_t *addr, register uint32_t len)
00110 {
00111     int32_t nleft = len;
00112     const uint16_t *w = addr;
00113     uint16_t answer;
00114     int32_t sum = 0;
00115 
00116     while (nleft > 1)  {
00117         sum += *w++;
00118         nleft -= 2;
00119     }
00120 
00121     if (nleft == 1)
00122         sum += htons(*(uint8_t  *)w<<8);
00123 
00124     sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
00125     sum += (sum >> 16);                     /* add carry */
00126     answer = ~sum;                          /* truncate to 16 bits */
00127 
00128     return (answer);
00129 }
00130 
00131 
00132 #define SOURCE_UDP_PORT 20020
00133 int
00134 rtp_send_data(struct param *p, uint32_t rtp_ts, int8_t  pt, int32_t m, int8_t  *data, int32_t data_len, unsigned char *h_buf, int h_offset, int h_len) {
00135     int32_t buffer_len, rc;
00136     int8_t  *buffer = data;
00137     rtp_packet *packet;
00138 //    int32_t stack_offs=0;
00139     struct iphdr  *iph;
00140     struct udphdr *udph;
00141 //    struct sockaddr_in s_in;
00142 //    struct sockaddr_ll s_ll;
00143 //    uint32_t res;
00144 
00145     buffer_len = data_len + RTP_HEADER_SIZE;
00146 
00147         // header
00148         unsigned char *h_ptr = h_buf;
00149         h_ptr += h_offset;
00150 
00151         // add RTP header;
00152         h_ptr -= sizeof(rtp_packet);
00153         h_len += sizeof(rtp_packet);
00154         packet = (rtp_packet *)((void *)h_ptr);
00155 
00156         /* ...and the actual packet header... */
00157         /* RTP header */
00158         packet->v = 2;
00159         packet->p = 0;
00160         packet->x = 0;
00161         packet->cc = 0;
00162         packet->m = m;
00163         packet->pt = pt;
00164         packet->seq = htons(p->rtp_seq++);
00165         packet->ts = htonl(rtp_ts);
00166         packet->ssrc = htonl(p->my_ssrc);
00167 
00168         if(p->raw) {
00169                 buffer_len += 8;
00170                 h_ptr -= sizeof(struct udphdr);
00171                 h_len += sizeof(struct udphdr);
00172                 udph = (struct udphdr *)h_ptr;
00173                 udph->len       = htons(sizeof(struct udphdr) + buffer_len);
00174 //              udph->len       = htons(sizeof(struct udphdr) + data_len);
00175                 udph->check     = 0;
00176                 udph->dest      = htons(p->dport);
00177                 udph->source    = htons(SOURCE_UDP_PORT);
00178         
00179                 h_ptr -= sizeof(struct iphdr);
00180                 h_len += sizeof(struct iphdr);
00181                 iph = (struct iphdr *)h_ptr;
00182                 iph->version = 4;      // ipv4
00183                 iph->ihl        = 5;       // ip header len in words
00184                 iph->tos        = 0;
00185                 iph->tot_len    = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + buffer_len);
00186 //              iph->tot_len    = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + data_len);
00187                 iph->id         = htons((uint16_t) p->ip_id);
00188                 iph->frag_off   = htons(IP_DF);
00189                 iph->ttl        = (uint8_t) p->ttl;
00190                 iph->protocol   = IPPROTO_UDP;
00191                 iph->saddr      = p->src_addr4.s_addr;
00192                 iph->daddr      = (int)p->dst_addr4.s_addr;
00193                 iph->check      = 0;
00194                 iph->check      = in_chksum((uint16_t *) iph, iph->ihl << 2);
00195 
00196 /*
00197                 memset(&s_ll, 0, sizeof(s_ll));
00198         
00199                 s_ll.sll_family   = AF_PACKET;
00200                 s_ll.sll_protocol = htons(ETH_P_IP);
00201                 s_ll.sll_ifindex  = p->eth_index;
00202                 s_ll.sll_halen    = ETH_ALEN;   // MAC
00203 
00204                 if(ismulticast(p)){
00205                         // Generate multicast ethernet address
00206                         memcpy(s_ll.sll_addr, "\x01\x00\x5e", 3);
00207                         res = htonl(s_in.sin_addr.s_addr)  & 0x7fffff;
00208                         memcpy(s_ll.sll_addr + 3, (int8_t *)(&res), 3);
00209                 } else {
00210                         memcpy(s_ll.sll_addr, p->dst_mac, 6);
00211                 }
00212 
00213                 stack_offs += IP_UDP_SIZE;
00214 */
00215         }
00216 
00217         struct iovec iov[2];
00218         int iovcnt = sizeof(iov) / sizeof(struct iovec);
00219         // [NET]/RTP/MJPEG headers
00220         iov[0].iov_base = h_ptr;
00221         iov[0].iov_len = h_len;
00222         // frame
00223         iov[1].iov_base = buffer;
00224         iov[1].iov_len = data_len;
00225 
00226         if(!p->raw) {
00227                 rc = writev(p->fd_udp, iov, iovcnt);
00228         } else {
00229 //              iov[1].iov_len = 8;
00230                 p->msg.msg_iov = iov;
00231                 p->msg.msg_iovlen = iovcnt;
00232 //              p->msg.msg_control = 0;
00233 //              p->msg.msg_flags = 0;
00234 //              p->msg.msg_name = (void *)&s_ll;
00235 //              p->msg.msg_namelen = sizeof(s_ll);
00236                 rc = sendmsg(p->fd_raw, &p->msg, 0);
00237                 p->ip_id++;
00238         }
00239         return rc;
00240 }
00241 
00242 
00243 void rtp_done(struct param * p) {
00244     udp_exit4(p);
00245 }
00246 
00247 
00248 int32_t ismulticast(struct param *p) {
00249     if(IN_MULTICAST(ntohl(p->dst_addr4.s_addr)))
00250                 return 1;
00251     return 0;
00252 }
00253         

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1