source: azure_iot_hub_f767zi/trunk/asp_baseplatform/lwip/contrib-2.1.0/apps/rtp/rtp.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 9.7 KB
Line 
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
102PACK_STRUCT_BEGIN
103struct 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;
110PACK_STRUCT_END
111#ifdef PACK_STRUCT_USE_INCLUDES
112# include "arch/epstruct.h"
113#endif
114
115/** RTP packets */
116static u8_t rtp_send_packet[RTP_PACKET_SIZE];
117static u8_t rtp_recv_packet[RTP_PACKET_SIZE];
118
119/**
120 * RTP send packets
121 */
122static void
123rtp_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 */
166static void
167rtp_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 */
215static void
216rtp_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
301void
302rtp_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 */
Note: See TracBrowser for help on using the repository browser.