| 33 |
|
|
| 34 |
#include "lwip/opt.h" |
#include "lwip/opt.h" |
| 35 |
|
|
| 36 |
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ |
#if LWIP_SOCKET && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ |
| 37 |
|
|
| 38 |
#include "lwip/sys.h" |
#include "lwip/sys.h" |
| 39 |
#include "lwip/sockets.h" |
#include "lwip/sockets.h" |
| 40 |
|
|
| 41 |
#include "rtpdata.h" |
#include "rtpdata.h" |
| 42 |
|
|
| 43 |
|
#include <string.h> |
| 44 |
|
|
| 45 |
/** This is an example of a "RTP" client/server based on a MPEG4 bitstream (with socket API). |
/** This is an example of a "RTP" client/server based on a MPEG4 bitstream (with socket API). |
| 46 |
*/ |
*/ |
| 47 |
|
|
| 99 |
#endif |
#endif |
| 100 |
PACK_STRUCT_BEGIN |
PACK_STRUCT_BEGIN |
| 101 |
struct rtp_hdr { |
struct rtp_hdr { |
| 102 |
u8_t version; |
PACK_STRUCT_FIELD(u8_t version); |
| 103 |
u8_t payloadtype; |
PACK_STRUCT_FIELD(u8_t payloadtype); |
| 104 |
u16_t seqNum; |
PACK_STRUCT_FIELD(u16_t seqNum); |
| 105 |
u32_t timestamp; |
PACK_STRUCT_FIELD(u32_t timestamp); |
| 106 |
u32_t ssrc; |
PACK_STRUCT_FIELD(u32_t ssrc); |
| 107 |
} PACK_STRUCT_STRUCT; |
} PACK_STRUCT_STRUCT; |
| 108 |
PACK_STRUCT_END |
PACK_STRUCT_END |
| 109 |
#ifdef PACK_STRUCT_USE_INCLUDES |
#ifdef PACK_STRUCT_USE_INCLUDES |
| 129 |
rtphdr = (struct rtp_hdr*)rtp_send_packet; |
rtphdr = (struct rtp_hdr*)rtp_send_packet; |
| 130 |
rtphdr->version = RTP_VERSION; |
rtphdr->version = RTP_VERSION; |
| 131 |
rtphdr->payloadtype = 0; |
rtphdr->payloadtype = 0; |
| 132 |
rtphdr->ssrc = htonl(RTP_SSRC); |
rtphdr->ssrc = PP_HTONL(RTP_SSRC); |
| 133 |
rtphdr->timestamp = htonl(ntohl(rtphdr->timestamp)+RTP_TIMESTAMP_INCREMENT); |
rtphdr->timestamp = htonl(ntohl(rtphdr->timestamp) + RTP_TIMESTAMP_INCREMENT); |
| 134 |
|
|
| 135 |
/* send RTP stream packets */ |
/* send RTP stream packets */ |
| 136 |
rtp_data_index = 0; |
rtp_data_index = 0; |
| 137 |
do { |
do { |
| 138 |
rtp_payload = rtp_send_packet+sizeof(struct rtp_hdr); |
rtp_payload = rtp_send_packet+sizeof(struct rtp_hdr); |
| 139 |
rtp_payload_size = min( RTP_PAYLOAD_SIZE, (sizeof(rtp_data)-rtp_data_index)); |
rtp_payload_size = min(RTP_PAYLOAD_SIZE, (sizeof(rtp_data) - rtp_data_index)); |
| 140 |
|
|
| 141 |
memcpy( rtp_payload, rtp_data+rtp_data_index, rtp_payload_size); |
memcpy(rtp_payload, rtp_data + rtp_data_index, rtp_payload_size); |
| 142 |
|
|
| 143 |
/* set MARKER bit in RTP header on the last packet of an image */ |
/* set MARKER bit in RTP header on the last packet of an image */ |
| 144 |
rtphdr->payloadtype = RTP_PAYLOADTYPE | (((rtp_data_index+rtp_payload_size)>=sizeof(rtp_data))?RTP_MARKER_MASK:0); |
rtphdr->payloadtype = RTP_PAYLOADTYPE | (((rtp_data_index + rtp_payload_size) |
| 145 |
|
>= sizeof(rtp_data)) ? RTP_MARKER_MASK : 0); |
| 146 |
|
|
| 147 |
/* send RTP stream packet */ |
/* send RTP stream packet */ |
| 148 |
if (sendto( sock, rtp_send_packet, sizeof(struct rtp_hdr)+rtp_payload_size, 0, (struct sockaddr *)to, sizeof(struct sockaddr))>=0) { |
if (sendto(sock, rtp_send_packet, sizeof(struct rtp_hdr) + rtp_payload_size, |
| 149 |
rtphdr->seqNum = htons(ntohs(rtphdr->seqNum)+1); |
0, (struct sockaddr *)to, sizeof(struct sockaddr)) >= 0) { |
| 150 |
|
rtphdr->seqNum = htons(ntohs(rtphdr->seqNum) + 1); |
| 151 |
rtp_data_index += rtp_payload_size; |
rtp_data_index += rtp_payload_size; |
| 152 |
} else { |
} else { |
| 153 |
LWIP_DEBUGF( RTP_DEBUG, ("rtp_sender: not sendto==%i\n", errno)); |
LWIP_DEBUGF(RTP_DEBUG, ("rtp_sender: not sendto==%i\n", errno)); |
| 154 |
} |
} |
| 155 |
}while (rtp_data_index<sizeof(rtp_data)); |
}while (rtp_data_index < sizeof(rtp_data)); |
| 156 |
} |
} |
| 157 |
|
|
| 158 |
/** |
/** |
| 172 |
rtp_stream_address = RTP_STREAM_ADDRESS; |
rtp_stream_address = RTP_STREAM_ADDRESS; |
| 173 |
|
|
| 174 |
/* if we got a valid RTP stream address... */ |
/* if we got a valid RTP stream address... */ |
| 175 |
if (rtp_stream_address!=0) { |
if (rtp_stream_address != 0) { |
| 176 |
/* create new socket */ |
/* create new socket */ |
| 177 |
sock = socket( AF_INET, SOCK_DGRAM, 0); |
sock = socket(AF_INET, SOCK_DGRAM, 0); |
| 178 |
if (sock>=0) { |
if (sock >= 0) { |
| 179 |
/* prepare local address */ |
/* prepare local address */ |
| 180 |
memset(&local, 0, sizeof(local)); |
memset(&local, 0, sizeof(local)); |
| 181 |
local.sin_family = AF_INET; |
local.sin_family = AF_INET; |
| 182 |
local.sin_port = htons(INADDR_ANY); |
local.sin_port = PP_HTONS(INADDR_ANY); |
| 183 |
local.sin_addr.s_addr = htonl(INADDR_ANY); |
local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); |
| 184 |
|
|
| 185 |
/* bind to local address */ |
/* bind to local address */ |
| 186 |
if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0) { |
if (bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { |
| 187 |
/* prepare RTP stream address */ |
/* prepare RTP stream address */ |
| 188 |
memset(&to, 0, sizeof(to)); |
memset(&to, 0, sizeof(to)); |
| 189 |
to.sin_family = AF_INET; |
to.sin_family = AF_INET; |
| 190 |
to.sin_port = htons(RTP_STREAM_PORT); |
to.sin_port = PP_HTONS(RTP_STREAM_PORT); |
| 191 |
to.sin_addr.s_addr = rtp_stream_address; |
to.sin_addr.s_addr = rtp_stream_address; |
| 192 |
|
|
| 193 |
/* send RTP packets */ |
/* send RTP packets */ |
| 194 |
memset( rtp_send_packet, 0, sizeof(rtp_send_packet)); |
memset(rtp_send_packet, 0, sizeof(rtp_send_packet)); |
| 195 |
while(1) { |
while (1) { |
| 196 |
rtp_send_packets( sock, &to); |
rtp_send_packets( sock, &to); |
| 197 |
sys_msleep(RTP_SEND_DELAY); |
sys_msleep(RTP_SEND_DELAY); |
| 198 |
} |
} |
| 229 |
rtp_stream_address = RTP_STREAM_ADDRESS; |
rtp_stream_address = RTP_STREAM_ADDRESS; |
| 230 |
|
|
| 231 |
/* if we got a valid RTP stream address... */ |
/* if we got a valid RTP stream address... */ |
| 232 |
if (rtp_stream_address!=0) { |
if (rtp_stream_address != 0) { |
| 233 |
/* create new socket */ |
/* create new socket */ |
| 234 |
sock = socket( AF_INET, SOCK_DGRAM, 0); |
sock = socket(AF_INET, SOCK_DGRAM, 0); |
| 235 |
if (sock>=0) { |
if (sock >= 0) { |
| 236 |
/* prepare local address */ |
/* prepare local address */ |
| 237 |
memset(&local, 0, sizeof(local)); |
memset(&local, 0, sizeof(local)); |
| 238 |
local.sin_family = AF_INET; |
local.sin_family = AF_INET; |
| 239 |
local.sin_port = htons(RTP_STREAM_PORT); |
local.sin_port = PP_HTONS(RTP_STREAM_PORT); |
| 240 |
local.sin_addr.s_addr = htonl(INADDR_ANY); |
local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); |
| 241 |
|
|
| 242 |
/* bind to local address */ |
/* bind to local address */ |
| 243 |
if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0) { |
if (bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { |
| 244 |
/* set recv timeout */ |
/* set recv timeout */ |
| 245 |
timeout = RTP_RECV_TIMEOUT; |
timeout = RTP_RECV_TIMEOUT; |
| 246 |
setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); |
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); |
| 247 |
|
|
| 248 |
/* prepare multicast "ip_mreq" struct */ |
/* prepare multicast "ip_mreq" struct */ |
| 249 |
ipmreq.imr_multiaddr.s_addr = rtp_stream_address; |
ipmreq.imr_multiaddr.s_addr = rtp_stream_address; |
| 250 |
ipmreq.imr_interface.s_addr = htonl(INADDR_ANY); |
ipmreq.imr_interface.s_addr = PP_HTONL(INADDR_ANY); |
| 251 |
|
|
| 252 |
/* join multicast group */ |
/* join multicast group */ |
| 253 |
if (setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq))==0) { |
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq)) == 0) { |
| 254 |
/* receive RTP packets */ |
/* receive RTP packets */ |
| 255 |
while(1) { |
while(1) { |
| 256 |
fromlen = sizeof(from); |
fromlen = sizeof(from); |
| 257 |
result = recvfrom( sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen); |
result = recvfrom(sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0, |
| 258 |
|
(struct sockaddr *)&from, (socklen_t *)&fromlen); |
| 259 |
if (result >= sizeof(struct rtp_hdr)) { |
if (result >= sizeof(struct rtp_hdr)) { |
| 260 |
rtphdr = (struct rtp_hdr *)rtp_recv_packet; |
rtphdr = (struct rtp_hdr *)rtp_recv_packet; |
| 261 |
recvrtppackets++; |
recvrtppackets++; |
| 262 |
if ((lastrtpseq == 0) || ((lastrtpseq+1) == ntohs(rtphdr->seqNum))) { |
if ((lastrtpseq == 0) || ((lastrtpseq + 1) == ntohs(rtphdr->seqNum))) { |
| 263 |
RTP_RECV_PROCESSING((rtp_recv_packet+sizeof(rtp_hdr)),(result-sizeof(rtp_hdr))); |
RTP_RECV_PROCESSING((rtp_recv_packet + sizeof(rtp_hdr)),(result-sizeof(rtp_hdr))); |
| 264 |
} else { |
} else { |
| 265 |
lostrtppackets++; |
lostrtppackets++; |
| 266 |
} |
} |
| 267 |
lastrtpseq = ntohs(rtphdr->seqNum); |
lastrtpseq = ntohs(rtphdr->seqNum); |
| 268 |
if ((recvrtppackets % RTP_RECV_STATS) == 0) { |
if ((recvrtppackets % RTP_RECV_STATS) == 0) { |
| 269 |
LWIP_DEBUGF( RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets)); |
LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets)); |
| 270 |
} |
} |
| 271 |
} else { |
} else { |
| 272 |
LWIP_DEBUGF( RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n")); |
LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n")); |
| 273 |
} |
} |
| 274 |
} |
} |
| 275 |
|
|
| 276 |
/* leave multicast group */ |
/* leave multicast group */ |
| 277 |
setsockopt( sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq)); |
setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq)); |
| 278 |
} |
} |
| 279 |
} |
} |
| 280 |
|
|
| 286 |
|
|
| 287 |
void |
void |
| 288 |
rtp_init(void) |
rtp_init(void) |
| 289 |
{ sys_thread_new("rtp_send_thread", rtp_send_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); |
{ |
| 290 |
|
sys_thread_new("rtp_send_thread", rtp_send_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); |
| 291 |
sys_thread_new("rtp_recv_thread", rtp_recv_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); |
sys_thread_new("rtp_recv_thread", rtp_recv_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); |
| 292 |
} |
} |
| 293 |
|
|
| 294 |
#endif /* LWIP_SOCKET */ |
#endif /* LWIP_SOCKET && LWIP_IGMP */ |