mirror of
https://github.com/ep00ch/lwip-contrib-mac.git
synced 2024-07-07 20:29:04 +00:00
contrib/apps/rtp: add a rtp sample to be able to test lwip's multicast features.
This commit is contained in:
parent
d0b500244b
commit
85c2c164cc
288
apps/rtp/rtp.c
Normal file
288
apps/rtp/rtp.c
Normal 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
6
apps/rtp/rtp.h
Normal 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
2040
apps/rtp/rtpdata.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -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. */
|
||||
|
@ -271,6 +271,10 @@
|
||||
RelativePath="..\..\..\apps\ping\ping.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\apps\rtp\rtp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\apps\sntp\sntp.c"
|
||||
>
|
||||
|
@ -201,7 +201,8 @@ low_level_input(struct netif *netif, void *packet, int packet_len)
|
||||
if (((memcmp(ðhdr->dest, &netif->hwaddr, ETHARP_HWADDR_LEN)) &&
|
||||
((ethhdr->dest.addr[0] & 0x01) == 0)) ||
|
||||
/* and don't let feedback packets through (limitation in winpcap?) */
|
||||
!memcmp(ðhdr->src, netif->hwaddr, ETHARP_HWADDR_LEN)) {
|
||||
((!memcmp(ðhdr->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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user