contrib/apps/rtp: add a rtp sample to be able to test lwip's multicast features.

This commit is contained in:
fbernon 2008-04-26 10:53:32 +00:00
parent d0b500244b
commit 85c2c164cc
8 changed files with 2366 additions and 19 deletions

288
apps/rtp/rtp.c Normal file
View File

@ -0,0 +1,288 @@
/**
* @file
* RTP client/server module
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "rtpdata.h"
/** This is an example of a "RTP" client/server based on a MPEG4 bitstream (with socket API).
*/
/**
* RTP_DEBUG: Enable debugging for RTP.
*/
#ifndef RTP_DEBUG
#define RTP_DEBUG LWIP_DBG_ON
#endif
/** RTP stream port */
#ifndef RTP_STREAM_PORT
#define RTP_STREAM_PORT 4000
#endif
/** RTP stream multicast address as IPv4 address in "u32_t" format */
#ifndef RTP_STREAM_ADDRESS
#define RTP_STREAM_ADDRESS inet_addr("232.0.0.0")
#endif
/** RTP send delay - in milliseconds */
#ifndef RTP_SEND_DELAY
#define RTP_SEND_DELAY 40
#endif
/** RTP receive timeout - in milliseconds */
#ifndef RTP_RECV_TIMEOUT
#define RTP_RECV_TIMEOUT 2000
#endif
/** RTP stats display period - in received packets */
#ifndef RTP_RECV_STATS
#define RTP_RECV_STATS 50
#endif
/** RTP macro to let the application process the data */
#ifndef RTP_RECV_PROCESSING
#define RTP_RECV_PROCESSING(p,s)
#endif
/** RTP packet/payload size */
#define RTP_PACKET_SIZE 1500
#define RTP_PAYLOAD_SIZE 1024
/** RTP header constants */
#define RTP_VERSION 0x80
#define RTP_TIMESTAMP_INCREMENT 3600
#define RTP_SSRC 0
#define RTP_PAYLOADTYPE 96
#define RTP_MARKER_MASK 0x80
/** RTP message header */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct rtp_hdr {
u8_t version;
u8_t payloadtype;
u16_t seqNum;
u32_t timestamp;
u32_t ssrc;
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** RTP packets */
static u8_t rtp_send_packet[RTP_PACKET_SIZE];
static u8_t rtp_recv_packet[RTP_PACKET_SIZE];
/**
* RTP send packets
*/
static void
rtp_send_packets( int sock, struct sockaddr_in* to)
{
struct rtp_hdr* rtphdr;
u8_t* rtp_payload;
int rtp_payload_size;
int rtp_data_index;
/* prepare RTP packet */
rtphdr = (struct rtp_hdr*)rtp_send_packet;
rtphdr->version = RTP_VERSION;
rtphdr->payloadtype = 0;
rtphdr->ssrc = htonl(RTP_SSRC);
rtphdr->timestamp = htonl(ntohl(rtphdr->timestamp)+RTP_TIMESTAMP_INCREMENT);
/* send RTP stream packets */
rtp_data_index = 0;
do {
rtp_payload = rtp_send_packet+sizeof(struct rtp_hdr);
rtp_payload_size = min( RTP_PAYLOAD_SIZE, (sizeof(rtp_data)-rtp_data_index));
memcpy( rtp_payload, rtp_data+rtp_data_index, rtp_payload_size);
/* set MARKER bit in RTP header on the last packet of an image */
rtphdr->payloadtype = RTP_PAYLOADTYPE | (((rtp_data_index+rtp_payload_size)>=sizeof(rtp_data))?RTP_MARKER_MASK:0);
/* send RTP stream packet */
if (sendto( sock, rtp_send_packet, sizeof(struct rtp_hdr)+rtp_payload_size, 0, (struct sockaddr *)to, sizeof(struct sockaddr))>=0) {
rtphdr->seqNum = htons(ntohs(rtphdr->seqNum)+1);
rtp_data_index += rtp_payload_size;
} else {
LWIP_DEBUGF( RTP_DEBUG, ("rtp_sender: not sendto==%i\n", errno));
}
}while (rtp_data_index<sizeof(rtp_data));
}
/**
* RTP send thread
*/
static void
rtp_send_thread(void *arg)
{
int sock;
struct sockaddr_in local;
struct sockaddr_in to;
u32_t rtp_stream_address;
LWIP_UNUSED_ARG(arg);
/* initialize RTP stream address */
rtp_stream_address = RTP_STREAM_ADDRESS;
/* if we got a valid RTP stream address... */
if (rtp_stream_address!=0) {
/* create new socket */
sock = socket( AF_INET, SOCK_DGRAM, 0);
if (sock>=0) {
/* prepare local address */
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(INADDR_ANY);
local.sin_addr.s_addr = htonl(INADDR_ANY);
/* bind to local address */
if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0) {
/* prepare RTP stream address */
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = htons(RTP_STREAM_PORT);
to.sin_addr.s_addr = rtp_stream_address;
/* send RTP packets */
memset( rtp_send_packet, 0, sizeof(rtp_send_packet));
while(1) {
rtp_send_packets( sock, &to);
sys_msleep(RTP_SEND_DELAY);
}
}
/* close the socket */
closesocket(sock);
}
}
}
/**
* RTP recv thread
*/
static void
rtp_recv_thread(void *arg)
{
int sock;
struct sockaddr_in local;
struct sockaddr_in from;
int fromlen;
struct ip_mreq ipmreq;
struct rtp_hdr* rtphdr;
u32_t rtp_stream_address;
int timeout;
int result;
int recvrtppackets = 0;
int lostrtppackets = 0;
u16_t lastrtpseq = 0;
LWIP_UNUSED_ARG(arg);
/* initialize RTP stream address */
rtp_stream_address = RTP_STREAM_ADDRESS;
/* if we got a valid RTP stream address... */
if (rtp_stream_address!=0) {
/* create new socket */
sock = socket( AF_INET, SOCK_DGRAM, 0);
if (sock>=0) {
/* prepare local address */
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(RTP_STREAM_PORT);
local.sin_addr.s_addr = htonl(INADDR_ANY);
/* bind to local address */
if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0) {
/* set recv timeout */
timeout = RTP_RECV_TIMEOUT;
setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
/* prepare multicast "ip_mreq" struct */
ipmreq.imr_multiaddr.s_addr = rtp_stream_address;
ipmreq.imr_interface.s_addr = htonl(INADDR_ANY);
/* join multicast group */
if (setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq))==0) {
/* receive RTP packets */
while(1) {
fromlen = sizeof(from);
result = recvfrom( sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
if (result >= sizeof(struct rtp_hdr)) {
rtphdr = (struct rtp_hdr *)rtp_recv_packet;
recvrtppackets++;
if ((lastrtpseq == 0) || ((lastrtpseq+1) == ntohs(rtphdr->seqNum))) {
RTP_RECV_PROCESSING((rtp_recv_packet+sizeof(rtp_hdr)),(result-sizeof(rtp_hdr)));
} else {
lostrtppackets++;
}
lastrtpseq = ntohs(rtphdr->seqNum);
if ((recvrtppackets % RTP_RECV_STATS) == 0) {
LWIP_DEBUGF( RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets));
}
} else {
LWIP_DEBUGF( RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n"));
}
}
/* leave multicast group */
setsockopt( sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq));
}
}
/* close the socket */
closesocket(sock);
}
}
}
void
rtp_init(void)
{ sys_thread_new("rtp_send_thread", rtp_send_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
sys_thread_new("rtp_recv_thread", rtp_recv_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}
#endif /* LWIP_SOCKET */

6
apps/rtp/rtp.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __RTP_H__
#define __RTP_H__
void rtp_init(void);
#endif /* __RTP_H__ */

2040
apps/rtp/rtpdata.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -104,13 +104,13 @@ a lot of data that needs to be copied, this should be set high. */
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#define MEMP_NUM_PBUF 16
#define MEMP_NUM_PBUF 64//FB 16
/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One
per active RAW "connection". */
#define MEMP_NUM_RAW_PCB 3
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#define MEMP_NUM_UDP_PCB 4
#define MEMP_NUM_UDP_PCB 64//FB 4
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#define MEMP_NUM_TCP_PCB 5
@ -127,9 +127,9 @@ a lot of data that needs to be copied, this should be set high. */
/* The following four are used only with the sequential API and can be
set to 0 if the application only will use the raw API. */
/* MEMP_NUM_NETBUF: the number of struct netbufs. */
#define MEMP_NUM_NETBUF 2
#define MEMP_NUM_NETBUF 64//FB 2
/* MEMP_NUM_NETCONN: the number of struct netconns. */
#define MEMP_NUM_NETCONN 10
#define MEMP_NUM_NETCONN 64//FB 10
/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used
for sequential API communication and incoming packets. Used in
src/api/tcpip.c. */

View File

@ -271,6 +271,10 @@
RelativePath="..\..\..\apps\ping\ping.c"
>
</File>
<File
RelativePath="..\..\..\apps\rtp\rtp.c"
>
</File>
<File
RelativePath="..\..\..\apps\sntp\sntp.c"
>

View File

@ -91,7 +91,7 @@ struct packet_adapter {
UINT bs_drop;
NDIS_MEDIA_STATE fNdisMediaState;
/* buffer to hold the data coming from the driver */
char buffer[PACKET_INPUT_BUFSIZE];
char buffer[PACKET_INPUT_BUFSIZE];
};
/**

View File

@ -201,7 +201,8 @@ low_level_input(struct netif *netif, void *packet, int packet_len)
if (((memcmp(&ethhdr->dest, &netif->hwaddr, ETHARP_HWADDR_LEN)) &&
((ethhdr->dest.addr[0] & 0x01) == 0)) ||
/* and don't let feedback packets through (limitation in winpcap?) */
!memcmp(&ethhdr->src, netif->hwaddr, ETHARP_HWADDR_LEN)) {
((!memcmp(&ethhdr->src, netif->hwaddr, ETHARP_HWADDR_LEN)) &&
((ethhdr->dest.addr[0] & 0x01) == 0))) {
return NULL;
}
@ -259,9 +260,9 @@ ethernetif_input(struct netif *netif, void *packet, int packet_len)
if (p == NULL) {
return;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
@ -313,7 +314,7 @@ ethernetif_init(struct netif *netif)
netif->output = etharp_output;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_LINK_UP;
netif->hwaddr_len = ETHARP_HWADDR_LEN;
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);

View File

@ -61,6 +61,7 @@
#include "apps/netio/netio.h"
#include "apps/netbios/netbios.h"
#include "apps/ping/ping.h"
#include "apps/rtp/rtp.h"
#include "apps/sntp/sntp.h"
#if NO_SYS
@ -337,30 +338,37 @@ void dns_found(const char *name, struct ip_addr *addr, void *arg)
static void
apps_init()
{
#if LWIP_DNS
#if LWIP_DNS_APP && LWIP_DNS
char* dnsname="3com.com";
struct ip_addr dnsresp;
if (dns_gethostbyname(dnsname, &dnsresp, dns_found, 0) == ERR_OK) {
dns_found(dnsname, &dnsresp, 0);
}
#endif /* LWIP_DNS */
#endif /* LWIP_DNS_APP && LWIP_DNS */
#if LWIP_RAW && LWIP_ICMP
#if LWIP_PING_APP && LWIP_RAW && LWIP_ICMP
ping_init();
#endif /* LWIP_RAW */
#endif /* LWIP_PING_APP && LWIP_RAW && LWIP_ICMP */
#if LWIP_UDP
#if LWIP_NETBIOS_APP && LWIP_UDP
netbios_init();
#endif /* LWIP_UDP */
#endif /* LWIP_NETBIOS_APP && LWIP_UDP */
#if LWIP_TCP
#if LWIP_HTTPD_APP && LWIP_TCP
httpd_init();
netio_init();
#endif /* LWIP_TCP */
#endif /* LWIP_HTTPD_APP && LWIP_TCP */
#if LWIP_SOCKET
#if LWIP_NETIO_APP && LWIP_TCP
netio_init();
#endif /* LWIP_NETIO_APP && LWIP_TCP */
#if LWIP_RTP_APP && LWIP_SOCKET
rtp_init();
#endif /* LWIP_RTP_APP && LWIP_SOCKET */
#if LWIP_SNTP_APP && LWIP_SOCKET
sntp_init();
#endif /* LWIP_SOCKET */
#endif /* LWIP_SNTP_APP && LWIP_SOCKET */
}
/* This function initializes this lwIP test. When NO_SYS=1, this is done in