diff options
Diffstat (limited to 'libmpdemux/rtp.c')
-rw-r--r-- | libmpdemux/rtp.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/libmpdemux/rtp.c b/libmpdemux/rtp.c index 8f4b59ec23..e06709855c 100644 --- a/libmpdemux/rtp.c +++ b/libmpdemux/rtp.c @@ -11,21 +11,180 @@ #include <stdlib.h> #include <stdio.h> #include <sys/types.h> +#include <ctype.h> #include "config.h" #ifndef HAVE_WINSOCK2 #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> +#define closesocket close #else #include <winsock2.h> #include <ws2tcpip.h> #endif +#include <errno.h> +#include "stream.h" /* MPEG-2 TS RTP stack */ #define DEBUG 1 #include "rtp.h" +extern int network_bandwidth; + +int read_rtp_from_server(int fd, char *buffer, int length) { + struct rtpheader rh; + char *data; + int len; + static int got_first = 0; + static unsigned short sequence; + + if( buffer==NULL || length<0 ) return -1; + + getrtp2(fd, &rh, &data, &len); + if( got_first && rh.b.sequence != (unsigned short)(sequence+1) ) + mp_msg(MSGT_NETWORK,MSGL_ERR,"RTP packet sequence error! Expected: %d, received: %d\n", + sequence+1, rh.b.sequence); + got_first = 1; + sequence = rh.b.sequence; + memcpy(buffer, data, len); + return(len); +} + + +// Start listening on a UDP port. If multicast, join the group. +static int rtp_open_socket( URL_t *url ) { + int socket_server_fd, rxsockbufsz; + int err, err_len; + fd_set set; + struct sockaddr_in server_address; + struct ip_mreq mcast; + struct timeval tv; + struct hostent *hp; + + mp_msg(MSGT_NETWORK,MSGL_V,"Listening for traffic on %s:%d ...\n", url->hostname, url->port ); + + socket_server_fd = socket(AF_INET, SOCK_DGRAM, 0); +// fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK ); + if( socket_server_fd==-1 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create socket\n"); + return -1; + } + + if( isalpha(url->hostname[0]) ) { +#ifndef HAVE_WINSOCK2 + hp =(struct hostent*)gethostbyname( url->hostname ); + if( hp==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Counldn't resolve name: %s\n", url->hostname); + return -1; + } + memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr, hp->h_length ); +#else + server_address.sin_addr.s_addr = htonl(INADDR_ANY); +#endif + } else { +#ifndef HAVE_WINSOCK2 +#ifdef USE_ATON + inet_aton(url->hostname, &server_address.sin_addr); +#else + inet_pton(AF_INET, url->hostname, &server_address.sin_addr); +#endif +#else + server_address.sin_addr.s_addr = htonl(INADDR_ANY); +#endif + } + server_address.sin_family=AF_INET; + server_address.sin_port=htons(url->port); + + if( bind( socket_server_fd, (struct sockaddr*)&server_address, sizeof(server_address) )==-1 ) { +#ifndef HAVE_WINSOCK2 + if( errno!=EINPROGRESS ) { +#else + if( WSAGetLastError() != WSAEINPROGRESS ) { +#endif + mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server\n"); + closesocket(socket_server_fd); + return -1; + } + } + +#ifdef HAVE_WINSOCK2 + if (isalpha(url->hostname[0])) { + hp =(struct hostent*)gethostbyname( url->hostname ); + if( hp==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Counldn't resolve name: %s\n", url->hostname); + return -1; + } + memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr, hp->h_length ); + } else { + unsigned int addr = inet_addr(url->hostname); + memcpy( (void*)&server_address.sin_addr, (void*)&addr, sizeof(addr) ); + } +#endif + + // Increase the socket rx buffer size to maximum -- this is UDP + rxsockbufsz = 240 * 1024; + if( setsockopt( socket_server_fd, SOL_SOCKET, SO_RCVBUF, &rxsockbufsz, sizeof(rxsockbufsz))) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Couldn't set receive socket buffer size\n"); + } + + if((ntohl(server_address.sin_addr.s_addr) >> 28) == 0xe) { + mcast.imr_multiaddr.s_addr = server_address.sin_addr.s_addr; + //mcast.imr_interface.s_addr = inet_addr("10.1.1.2"); + mcast.imr_interface.s_addr = 0; + if( setsockopt( socket_server_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof(mcast))) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"IP_ADD_MEMBERSHIP failed (do you have multicasting enabled in your kernel?)\n"); + return -1; + } + } + + tv.tv_sec = 0; + tv.tv_usec = (1 * 1000000); // 1 second timeout + FD_ZERO( &set ); + FD_SET( socket_server_fd, &set ); + if( select(socket_server_fd+1, &set, NULL, NULL, &tv)>0 ) { + //if( select(socket_server_fd+1, &set, NULL, NULL, NULL)>0 ) { + err_len = sizeof( err ); + getsockopt( socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len ); + if( err ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Timeout! No data from host %s\n", url->hostname ); + mp_msg(MSGT_NETWORK,MSGL_DBG2,"Socket error: %d\n", err ); + closesocket(socket_server_fd); + return -1; + } + } + return socket_server_fd; +} + +static int rtp_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) { + return read_rtp_from_server( fd, buffer, size ); +} + +static int rtp_streaming_start( stream_t *stream, int raw_udp ) { + streaming_ctrl_t *streaming_ctrl; + int fd; + + if( stream==NULL ) return -1; + streaming_ctrl = stream->streaming_ctrl; + fd = stream->fd; + + if( fd<0 ) { + fd = rtp_open_socket( (streaming_ctrl->url) ); + if( fd<0 ) return -1; + stream->fd = fd; + } + + if(raw_udp) + streaming_ctrl->streaming_read = nop_streaming_read; + else + streaming_ctrl->streaming_read = rtp_streaming_read; + streaming_ctrl->streaming_seek = nop_streaming_seek; + streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes + streaming_ctrl->buffering = 0; + streaming_ctrl->status = streaming_playing_e; + return 0; +} + int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData) { static char buf[1600]; @@ -68,3 +227,51 @@ int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData) { } +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + URL_t *url; + int udp = 0; + + mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_RTP, URL: %s\n", stream->url); + stream->streaming_ctrl = streaming_ctrl_new(); + if( stream->streaming_ctrl==NULL ) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + + if( url->port==0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"You must enter a port number for RTP and UDP streams!\n"); + goto fail; + } + if(!strncmp(stream->url, "udp", 3)) + udp = 1; + + if(rtp_streaming_start(stream, udp) < 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp_streaming_start(rtp) failed\n"); + goto fail; + } + + stream->type = STREAMTYPE_STREAM; + fixup_network_stream_cache(stream); + return STREAM_OK; + +fail: + streaming_ctrl_free( stream->streaming_ctrl ); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; +} + + +stream_info_t stream_info_rtp_udp = { + "mpeg rtp and upd streaming", + "rtp and udp", + "Dave Chapman", + "native rtp support", + open_s, + {"rtp", "udp", NULL}, + NULL, + 0 // Urls are an option string +}; + + |