• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * RTP client/server module
4  *
5  */
6 
7 /*
8  * Redistribution and use in source and binary forms, with or without modification,
9  * are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28  * OF SUCH DAMAGE.
29  *
30  * This file is part of the lwIP TCP/IP stack.
31  *
32  */
33 
34 #include "lwip/opt.h"
35 
36 #if LWIP_SOCKET && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
37 
38 #include "lwip/sys.h"
39 #include "lwip/sockets.h"
40 
41 #include "rtp.h"
42 
43 #include "rtpdata.h"
44 
45 #include <string.h>
46 
47 /** This is an example of a "RTP" client/server based on a MPEG4 bitstream (with socket API).
48  */
49 
50 /**
51  * RTP_DEBUG: Enable debugging for RTP.
52  */
53 #ifndef RTP_DEBUG
54 #define RTP_DEBUG                   LWIP_DBG_ON
55 #endif
56 
57 /** RTP stream port */
58 #ifndef RTP_STREAM_PORT
59 #define RTP_STREAM_PORT             4000
60 #endif
61 
62 /** RTP stream multicast address as IPv4 address in "u32_t" format */
63 #ifndef RTP_STREAM_ADDRESS
64 #define RTP_STREAM_ADDRESS          inet_addr("232.0.0.0")
65 #endif
66 
67 /** RTP send delay - in milliseconds */
68 #ifndef RTP_SEND_DELAY
69 #define RTP_SEND_DELAY              40
70 #endif
71 
72 /** RTP receive timeout - in milliseconds */
73 #ifndef RTP_RECV_TIMEOUT
74 #define RTP_RECV_TIMEOUT            2000
75 #endif
76 
77 /** RTP stats display period - in received packets */
78 #ifndef RTP_RECV_STATS
79 #define RTP_RECV_STATS              50
80 #endif
81 
82 /** RTP macro to let the application process the data */
83 #ifndef RTP_RECV_PROCESSING
84 #define RTP_RECV_PROCESSING(p,s)
85 #endif
86 
87 /** RTP packet/payload size */
88 #define RTP_PACKET_SIZE             1500
89 #define RTP_PAYLOAD_SIZE            1024
90 
91 /** RTP header constants */
92 #define RTP_VERSION                 0x80
93 #define RTP_TIMESTAMP_INCREMENT     3600
94 #define RTP_SSRC                    0
95 #define RTP_PAYLOADTYPE             96
96 #define RTP_MARKER_MASK             0x80
97 
98 /** RTP message header */
99 #ifdef PACK_STRUCT_USE_INCLUDES
100 #  include "arch/bpstruct.h"
101 #endif
102 PACK_STRUCT_BEGIN
103 struct rtp_hdr {
104   PACK_STRUCT_FLD_8(u8_t  version);
105   PACK_STRUCT_FLD_8(u8_t  payloadtype);
106   PACK_STRUCT_FIELD(u16_t seqNum);
107   PACK_STRUCT_FIELD(u32_t timestamp);
108   PACK_STRUCT_FIELD(u32_t ssrc);
109 } PACK_STRUCT_STRUCT;
110 PACK_STRUCT_END
111 #ifdef PACK_STRUCT_USE_INCLUDES
112 #  include "arch/epstruct.h"
113 #endif
114 
115 /** RTP packets */
116 static u8_t rtp_send_packet[RTP_PACKET_SIZE];
117 static u8_t rtp_recv_packet[RTP_PACKET_SIZE];
118 
119 /**
120  * RTP send packets
121  */
122 static void
rtp_send_packets(int sock,struct sockaddr_in * to)123 rtp_send_packets( int sock, struct sockaddr_in* to)
124 {
125   struct rtp_hdr* rtphdr;
126   u8_t*           rtp_payload;
127   size_t          rtp_payload_size;
128   size_t          rtp_data_index;
129 
130   /* prepare RTP packet */
131   rtphdr = (struct rtp_hdr*)rtp_send_packet;
132   rtphdr->version     = RTP_VERSION;
133   rtphdr->payloadtype = 0;
134   rtphdr->ssrc        = PP_HTONL(RTP_SSRC);
135   rtphdr->timestamp   = lwip_htonl(lwip_ntohl(rtphdr->timestamp) + RTP_TIMESTAMP_INCREMENT);
136 
137   /* send RTP stream packets */
138   rtp_data_index = 0;
139   do {
140     rtp_payload      = rtp_send_packet+sizeof(struct rtp_hdr);
141     rtp_payload_size = LWIP_MIN(RTP_PAYLOAD_SIZE, sizeof(rtp_data) - rtp_data_index);
142 
143     MEMCPY(rtp_payload, rtp_data + rtp_data_index, rtp_payload_size);
144 
145     /* set MARKER bit in RTP header on the last packet of an image */
146     if ((rtp_data_index + rtp_payload_size) >= sizeof(rtp_data)) {
147       rtphdr->payloadtype = RTP_PAYLOADTYPE | RTP_MARKER_MASK;
148     } else {
149       rtphdr->payloadtype = RTP_PAYLOADTYPE;
150     }
151 
152     /* send RTP stream packet */
153     if (lwip_sendto(sock, rtp_send_packet, sizeof(struct rtp_hdr) + rtp_payload_size,
154         0, (struct sockaddr *)to, sizeof(struct sockaddr)) >= 0) {
155       rtphdr->seqNum  = lwip_htons((u16_t)(lwip_ntohs(rtphdr->seqNum) + 1));
156       rtp_data_index += rtp_payload_size;
157     } else {
158       LWIP_DEBUGF(RTP_DEBUG, ("rtp_sender: not sendto==%i\n", errno));
159     }
160   }while (rtp_data_index < sizeof(rtp_data));
161 }
162 
163 /**
164  * RTP send thread
165  */
166 static void
rtp_send_thread(void * arg)167 rtp_send_thread(void *arg)
168 {
169   int                sock;
170   struct sockaddr_in local;
171   struct sockaddr_in to;
172   u32_t              rtp_stream_address;
173 
174   LWIP_UNUSED_ARG(arg);
175 
176   /* initialize RTP stream address */
177   rtp_stream_address = RTP_STREAM_ADDRESS;
178 
179   /* if we got a valid RTP stream address... */
180   if (rtp_stream_address != 0) {
181     /* create new socket */
182     sock = lwip_socket(AF_INET, SOCK_DGRAM, 0);
183     if (sock >= 0) {
184       /* prepare local address */
185       memset(&local, 0, sizeof(local));
186       local.sin_family      = AF_INET;
187       local.sin_port        = PP_HTONS(INADDR_ANY);
188       local.sin_addr.s_addr = PP_HTONL(INADDR_ANY);
189 
190       /* bind to local address */
191       if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) {
192         /* prepare RTP stream address */
193         memset(&to, 0, sizeof(to));
194         to.sin_family      = AF_INET;
195         to.sin_port        = PP_HTONS(RTP_STREAM_PORT);
196         to.sin_addr.s_addr = rtp_stream_address;
197 
198         /* send RTP packets */
199         memset(rtp_send_packet, 0, sizeof(rtp_send_packet));
200         while (1) {
201           rtp_send_packets( sock, &to);
202           sys_msleep(RTP_SEND_DELAY);
203         }
204       }
205 
206       /* close the socket */
207       lwip_close(sock);
208     }
209   }
210 }
211 
212 /**
213  * RTP recv thread
214  */
215 static void
rtp_recv_thread(void * arg)216 rtp_recv_thread(void *arg)
217 {
218   int                sock;
219   struct sockaddr_in local;
220   struct sockaddr_in from;
221   int                fromlen;
222   struct ip_mreq     ipmreq;
223   struct rtp_hdr*    rtphdr;
224   u32_t              rtp_stream_address;
225   int                timeout;
226   int                result;
227   int                recvrtppackets  = 0;
228   int                lostrtppackets  = 0;
229   u16_t              lastrtpseq = 0;
230 
231   LWIP_UNUSED_ARG(arg);
232 
233   /* initialize RTP stream address */
234   rtp_stream_address = RTP_STREAM_ADDRESS;
235 
236   /* if we got a valid RTP stream address... */
237   if (rtp_stream_address != 0) {
238     /* create new socket */
239     sock = lwip_socket(AF_INET, SOCK_DGRAM, 0);
240     if (sock >= 0) {
241       /* prepare local address */
242       memset(&local, 0, sizeof(local));
243       local.sin_family      = AF_INET;
244       local.sin_port        = PP_HTONS(RTP_STREAM_PORT);
245       local.sin_addr.s_addr = PP_HTONL(INADDR_ANY);
246 
247       /* bind to local address */
248       if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) {
249         /* set recv timeout */
250         timeout = RTP_RECV_TIMEOUT;
251         result = lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
252         if (result) {
253           LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: setsockopt(SO_RCVTIMEO) failed: errno=%d\n", errno));
254         }
255 
256         /* prepare multicast "ip_mreq" struct */
257         ipmreq.imr_multiaddr.s_addr = rtp_stream_address;
258         ipmreq.imr_interface.s_addr = PP_HTONL(INADDR_ANY);
259 
260         /* join multicast group */
261         if (lwip_setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq)) == 0) {
262           /* receive RTP packets */
263           while(1) {
264             fromlen = sizeof(from);
265             result  = lwip_recvfrom(sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0,
266               (struct sockaddr *)&from, (socklen_t *)&fromlen);
267             if ((result > 0) && ((size_t)result >= sizeof(struct rtp_hdr))) {
268               size_t recved = (size_t)result;
269               rtphdr = (struct rtp_hdr *)rtp_recv_packet;
270               recvrtppackets++;
271               if ((lastrtpseq == 0) || ((lastrtpseq + 1) == lwip_ntohs(rtphdr->seqNum))) {
272                 RTP_RECV_PROCESSING((rtp_recv_packet + sizeof(rtp_hdr)), (recved-sizeof(rtp_hdr)));
273                 LWIP_UNUSED_ARG(recved); /* just in case... */
274               } else {
275                 lostrtppackets++;
276               }
277               lastrtpseq = lwip_ntohs(rtphdr->seqNum);
278               if ((recvrtppackets % RTP_RECV_STATS) == 0) {
279                 LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets));
280               }
281             } else {
282               LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n"));
283             }
284           }
285 
286           /* leave multicast group */
287           /* TODO: this code is never reached
288           result = lwip_setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq));
289           if (result) {
290             LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: setsockopt(IP_DROP_MEMBERSHIP) failed: errno=%d\n", errno));
291           }*/
292         }
293       }
294 
295       /* close the socket */
296       lwip_close(sock);
297     }
298   }
299 }
300 
301 void
rtp_init(void)302 rtp_init(void)
303 {
304   sys_thread_new("rtp_send_thread", rtp_send_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
305   sys_thread_new("rtp_recv_thread", rtp_recv_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
306 }
307 
308 #endif /* LWIP_SOCKET && LWIP_IGMP */
309