/*************************************************************************** * Copyright (c) 2012, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * ***************************************************************************/ #if defined(NEXUS_LINUXUSER) #include #include #include #include #include #include #include #include #include #elif defined(CONFIG_LWIP) #include "lwip/ip4.h" #endif /* MPEG-2 TS RTP stack */ #include "rtp.h" #ifdef BRCM_DBG #define RTP_DBGMSG(x) { printf("%s:%d-",__FUNCTION__,__LINE__); printf x ; } #else #define RTP_DBGMSG(x) ((void)0) #endif #if defined(NEXUS_LINUXUSER) #define RTP_SOCKET(a,b,c) socket(a,b,c) #define RTP_SETSOCKOPT(a,b,c,d,e) setsockopt(a,b,c,d,e) #define RTP_SENDTO(a,b,c,d,e,f) sendto(a,b,c,d,e,f) #define RTP_RECV(a,b,c,d) recv(a,b,c,d) #elif defined(CONFIG_LWIP) #define RTP_SOCKET(a,b,c) lwip_socket(a,b,c) #define RTP_SETSOCKOPT(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) #define RTP_SENDTO(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) #define RTP_RECV(a,b,c,d) lwip_recv(a,b,c,d) #else #define RTP_SOCKET(a,b,c) 0 #define RTP_SETSOCKOP(a,b,c,d,e) 0 #define RTP_SENDTO(a,b,c,d,e,f) 0 #define RTP_RECV(a,b,c,d) 0 #endif /* Payload types (from RFC 1890): PT encoding audio/video clock rate channels name (A/V) (Hz) (audio) _______________________________________________________________ 0 PCMU A 8000 1 1 1016 A 8000 1 2 G721 A 8000 1 3 GSM A 8000 1 4 unassigned A 8000 1 5 DVI4 A 8000 1 6 DVI4 A 16000 1 7 LPC A 8000 1 8 PCMA A 8000 1 9 G722 A 8000 1 10 L16 A 44100 2 11 L16 A 44100 1 12 unassigned A 13 unassigned A 14 MPA A 90000 (see text) 15 G728 A 8000 1 16--23 unassigned A 24 unassigned V 25 CelB V 90000 26 JPEG V 90000 27 unassigned V 28 nv V 90000 29 unassigned V 30 unassigned V 31 H261 V 90000 32 MPV V 90000 33 MP2T AV 90000 34--71 unassigned ? 72--76 reserved N/A N/A N/A 77--95 unassigned ? 96--127 dynamic ? */ /****************************************************************************** * INPUTS: p_rtp - uninitialized RTP structure * buf_len - length to allocate for buffer in bytes * payload_type - RTP payload type * OUTPUTS: None. * RETURNS: Non-zero on failure. * FUNCTION: Initialize rtp structure and header for payload type. ******************************************************************************/ int init_rtp( rtp_t *p_rtp, /* uninitialized RTP structure */ unsigned int buf_len, /* buffer length in bytes */ int payload_type /* payload type of default RTP header (to use for sending) */ ) { p_rtp->s_fd = -1; p_rtp->rtph.b.v = 2; p_rtp->rtph.b.p = 0; p_rtp->rtph.b.x = 0; p_rtp->rtph.b.cc = 0; p_rtp->rtph.b.m = 0; p_rtp->rtph.b.pt = payload_type; p_rtp->rtph.b.seq = rand() & 65535; p_rtp->rtph.timestamp = rand(); p_rtp->buf_len = buf_len; p_rtp->h_len = 12 + (4 * p_rtp->rtph.b.cc); p_rtp->buf = malloc(p_rtp->h_len); if (p_rtp->buf == NULL) { return RTP_MEM_ERR; } p_rtp->data_buf = &p_rtp->buf[p_rtp->h_len]; return RTP_OK; } /****************************************************************************** * INPUTS: p_rtp - initialized RTP structure * OUTPUTS: None. * RETURNS: None. * FUNCTION: Release rtp structure resources. ******************************************************************************/ void free_rtp( rtp_t *p_rtp /* initialized RTP structure */ ) { if (p_rtp->buf) { free(p_rtp->buf); } } /****************************************************************************** * INPUTS: p_rtp - initialized RTP structure * OUTPUTS: len - number of payload bytes. * RETURNS: non-zero on error. * FUNCTION: receive RTP packet on client socket. ******************************************************************************/ #if 0 static void DBG_HEXDUMP(unsigned char* ptr, unsigned long len) { unsigned long i; for (i=0; is_fd,p_rtp->buf,p_rtp->buf_len,0); if (*len <= 12) { RTP_DBGMSG(("recv packet length = %d, errno = %d\n",*len,errno)); return RTP_RECV_ERR; } memcpy(&p_rtp->rtph,p_rtp->buf,sizeof(rtp_header_t)); p_rtp->rtph.b.seq = ((p_rtp->rtph.b.seq & 0xFF) << 8) | ((p_rtp->rtph.b.seq >> 8) & 0xFF) ; p_rtp->rtph.timestamp = ((p_rtp->rtph.timestamp & 0xFF) << 24) | ((p_rtp->rtph.timestamp & 0xFF00) << 8) | ((p_rtp->rtph.timestamp & 0xFF0000) >> 8) | ((p_rtp->rtph.timestamp & 0xFF000000) >> 24); p_rtp->h_len = 12 ; // Not working + (4 * p_rtp->rtph.b.cc); p_rtp->data_buf = &(p_rtp->buf[p_rtp->h_len]); *len -= p_rtp->h_len; return RTP_OK; } /****************************************************************************** * INPUTS: p_rtp - initialized RTP structure * len - number of bytes in payload * OUTPUTS: None. * RETURNS: non-zero on error. * FUNCTION: sent RTP packet on server socket. Assumes data is loaded at * data_buf which is offset h_len from the beginning of buf so * if the cc field is changed make sure h_len is recalculated and * data_buf is set to the proper offset. ******************************************************************************/ int send_rtp( rtp_t *p_rtp, /* initialized RTP structure */ unsigned char *buf, unsigned int len /* number of bytes in payload */ ) { rtp_header_t *p_rh = buf; memcpy(p_rh,&p_rtp->rtph,p_rtp->h_len); p_rh->b.seq = ((p_rh->b.seq & 0xFF) << 8) | ((p_rh->b.seq >> 8) & 0xFF) ; p_rh->timestamp = ((p_rh->timestamp & 0xFF) << 24) | ((p_rh->timestamp & 0xFF00) << 8) | ((p_rh->timestamp & 0xFF0000) >> 8) | ((p_rh->timestamp & 0xFF000000) >> 24); p_rtp->rtph.b.seq++; return RTP_SENDTO(p_rtp->s_fd, buf, len + p_rtp->h_len, 0,(struct sockaddr *)&(p_rtp->saddr),sizeof(p_rtp->saddr)); } /****************************************************************************** * INPUTS: p_rtp - initialized RTP structure * addr_str - ip address in string format * port - ip port * ttl - time to live setting. * OUTPUTS: None. * RETURNS: non-zero on error. * FUNCTION: Open a socket and configure for sending RTP packets. ******************************************************************************/ int makesocket_rtp( rtp_t *p_rtp, /* initialized RTP structure */ char *addr_str, /* address string */ unsigned short port, /* create socket for port */ int ttl /* TTL */ ) { int val = 1; char c_val = (char)ttl; p_rtp->s_fd = RTP_SOCKET( AF_INET, SOCK_DGRAM, 0 ); if (p_rtp->s_fd < 0) { RTP_DBGMSG(("socket create failed errno = %d\n",errno)); return RTP_SOCKET_ERR; } #if defined(CONFIG_LWIP) p_rtp->saddr.sin_len = sizeof(p_rtp->saddr); #endif p_rtp->saddr.sin_family = AF_INET; p_rtp->saddr.sin_port = htons(port); p_rtp->saddr.sin_addr.s_addr = inet_addr(addr_str); if (RTP_SETSOCKOPT(p_rtp->s_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) < 0) { RTP_DBGMSG(("setsockopt SO_REUSEADDR failed errno = %d\n",errno)); return RTP_SOCKET_ERR; } #ifdef NEXUS_LINUXUSER if (RTP_SETSOCKOPT(p_rtp->s_fd, IPPROTO_IP, IP_MULTICAST_TTL, &c_val, sizeof(char)) < 0) { RTP_DBGMSG(("setsockopt IP_MULTICAST_TTL failed errno = %d\n",errno)); return RTP_SOCKET_ERR; } c_val = 1; if (RTP_SETSOCKOPT(p_rtp->s_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &c_val, sizeof(char)) < 0) { RTP_DBGMSG(("setsockopt IP_MULTICAST_LOOP failed errno = %d\n",errno)); return RTP_SOCKET_ERR; } #endif return RTP_OK; } /****************************************************************************** * INPUTS: p_rtp - initialized RTP structure * addr_str - ip address in string format * port - ip port * ttl - time to live setting. * OUTPUTS: None. * RETURNS: non-zero on error. * FUNCTION: Open a socket and configure for sending RTP packets. ******************************************************************************/ int makeclientsocket_rtp( rtp_t *p_rtp, /* initialized RTP structure */ char *addr_str, /* address string */ unsigned short port, /* create socket for port */ int ttl /* TTL */ ) { #ifdef NEXUS_LINUXUSER struct ip_mreq mreq; struct sockaddr_in sin; if (makesocket_rtp(p_rtp,addr_str,port,ttl) != RTP_OK) { RTP_DBGMSG(("makesocket_rtp failed\n")); return RTP_SOCKET_ERR; } sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = inet_addr(addr_str); if (bind(p_rtp->s_fd,(struct sockaddr *)&sin,sizeof(sin))) { RTP_DBGMSG(("bind failed errno = %d\n",errno)); return RTP_SOCKET_ERR; } if ((ntohl(sin.sin_addr.s_addr) >> 28) == 0xe) { mreq.imr_multiaddr.s_addr = sin.sin_addr.s_addr; mreq.imr_interface.s_addr = 0; if (setsockopt(p_rtp->s_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))) { RTP_DBGMSG(("setsockopt IP_ADD_MEMBERSHIP failed errno = %d\n",errno)); return RTP_SOCKET_ERR; } } #endif return RTP_OK; }