diff options
-rw-r--r-- | frontend_svr.c | 150 | ||||
-rw-r--r-- | frontend_svr.h | 5 | ||||
-rw-r--r-- | tools/udp_pes_scheduler.c | 63 | ||||
-rw-r--r-- | tools/udp_pes_scheduler.h | 12 |
4 files changed, 158 insertions, 72 deletions
diff --git a/frontend_svr.c b/frontend_svr.c index 9b9a6929..15eb43ce 100644 --- a/frontend_svr.c +++ b/frontend_svr.c @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: frontend_svr.c,v 1.6 2006-06-11 21:02:54 phintuka Exp $ + * $Id: frontend_svr.c,v 1.7 2006-07-04 02:06:31 phintuka Exp $ * */ @@ -69,6 +69,7 @@ cXinelibServer::cXinelibServer(int listen_port) : fd_listen = -1; fd_multicast = -1; + fd_rtcp = -1; fd_discovery = -1; m_iMulticastMask = 0; @@ -88,6 +89,7 @@ cXinelibServer::~cXinelibServer() CLOSESOCKET(fd_listen); CLOSESOCKET(fd_discovery); CLOSESOCKET(fd_multicast); + CLOSESOCKET(fd_rtcp); for(i=0; i<MAXCLIENTS; i++) CloseConnection(i); @@ -110,6 +112,7 @@ void cXinelibServer::Stop(void) CLOSESOCKET(fd_listen); CLOSESOCKET(fd_discovery); CLOSESOCKET(fd_multicast); + CLOSESOCKET(fd_rtcp); for(i=0; i<MAXCLIENTS; i++) CloseConnection(i); @@ -411,7 +414,7 @@ bool cXinelibServer::Flush(int TimeoutMs) if(result) { char tmp[64]; - sprintf(tmp, "FLUSH %d %" PRIu64, TimeoutMs, m_StreamPos); + sprintf(tmp, "FLUSH %d %" PRIu64 " %d", TimeoutMs, m_StreamPos, m_Frames); result = (PlayFileCtrl(tmp)) <= 0 && result; } @@ -426,10 +429,11 @@ int cXinelibServer::Xine_Control(const char *cmd) sprintf(buf, "%s\r\n", cmd); int len = strlen(buf); LOCK_THREAD; + for(int i=0; i<MAXCLIENTS; i++) if(fd_control[i]>=0 && (fd_data[i]>=0 || m_bMulticast[i]) && m_bConfigOk[i]) if(len != timed_write(fd_control[i], buf, len, 100)) { - LOGMSG("Control send failed, dropping client"); + LOGMSG("Control send failed (%s), dropping client", cmd); CloseConnection(i); } @@ -521,6 +525,7 @@ bool cXinelibServer::Listen(int listen_port) if(fd_multicast >= 0 && m_Scheduler) m_Scheduler->RemoveHandle(fd_multicast); CLOSESOCKET(fd_multicast); + CLOSESOCKET(fd_rtcp); LOGMSG("Not listening for remote connections"); return false; } @@ -579,79 +584,77 @@ bool cXinelibServer::Listen(int listen_port) } } - // set up multicast socket + // set up multicast sockets - //if(!xc.remote_usertp) if(fd_multicast >= 0 && m_Scheduler) m_Scheduler->RemoveHandle(fd_multicast); CLOSESOCKET(fd_multicast); + CLOSESOCKET(fd_rtcp); if(xc.remote_usertp && fd_multicast < 0) { - int iReuse = 1, iLoop = 1, iTtl = xc.remote_rtp_ttl; + // + // RTP + // + if((fd_multicast = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + LOGERR("socket() failed (UDP/RTP multicast)"); - if(xc.remote_rtp_always_on) - LOGMSG("WARNING: RTP Configuration: transmission is always on !"); + // Set buffer sizes + set_socket_buffers(fd_multicast, KILOBYTE(256), 2048); - fd_multicast = socket(AF_INET, SOCK_DGRAM, 0); - if(fd_multicast < 0) { - LOGERR("socket() failed (UDP/RTP multicast)"); - } else { + // Set multicast socket options + if(set_multicast_options(fd_multicast, xc.remote_rtp_ttl)) + CLOSESOCKET(fd_multicast); - // Set buffer sizes - int max_buf = KILOBYTE(128); - if(setsockopt(fd_multicast, SOL_SOCKET, SO_SNDBUF, - &max_buf, sizeof(int))) { - LOGERR("setsockopt(fd_multicast, SO_SNDBUF,%d) failed", max_buf); - } else { - int tmp = 0; - int len = sizeof(int); - if(getsockopt(fd_multicast, SOL_SOCKET, SO_SNDBUF, - &tmp, (socklen_t*)&len)) { - LOGERR("getsockopt(fd_multicast, SO_SNDBUF,%d) failed", max_buf); - } else if(tmp != max_buf) { - LOGDBG("setsockopt(fd_multicast, SO_SNDBUF): got %d bytes", tmp); - } - } - max_buf = 1024; - setsockopt(fd_multicast, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)); + // Connect to multicast address + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = htons(xc.remote_rtp_port); + sin.sin_addr.s_addr = inet_addr(xc.remote_rtp_addr); - // Set multicast socket options - if(setsockopt(fd_multicast, SOL_SOCKET, SO_REUSEADDR, - &iReuse, sizeof(int)) < 0) - LOGERR("setsockopt(SO_REUSEADDR) failed"); - - if(setsockopt(fd_multicast, IPPROTO_IP, IP_MULTICAST_TTL, - &iTtl, sizeof(int))) { - LOGERR("setsockopt(IP_MULTICAST_TTL) failed"); - CLOSESOCKET(fd_multicast); - } - - if(setsockopt(fd_multicast, IPPROTO_IP, IP_MULTICAST_LOOP, - &iLoop, sizeof(int))) { - LOGERR("setsockopt(IP_MULTICAST_LOOP) failed"); - CLOSESOCKET(fd_multicast); - } + if(connect(fd_multicast, (struct sockaddr *)&sin, sizeof(sin))==-1 && + errno != EINPROGRESS) + LOGERR("connect(fd_multicast) failed. Address=%s, port=%d", + xc.remote_rtp_addr, xc.remote_rtp_port); + + // Set to non-blocking mode + if(fcntl (fd_multicast, F_SETFL, + fcntl (fd_multicast, F_GETFL) | O_NONBLOCK) == -1) + LOGERR("can't put multicast socket in non-blocking mode"); + + // + // RTCP + // + if((fd_rtcp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + LOGERR("socket() failed (RTCP multicast)"); - // Connect to multicast address - struct sockaddr_in sin; - sin.sin_family = sin.sin_family = AF_INET; - sin.sin_port = sin.sin_port = htons(xc.remote_rtp_port); - sin.sin_addr.s_addr = inet_addr(xc.remote_rtp_addr); + /* RTCP port (RFC 1889) */ + if(xc.remote_rtp_port & 1) + sin.sin_port = htons(xc.remote_rtp_port - 1); + else + sin.sin_port = htons(xc.remote_rtp_port + 1); + + set_socket_buffers(fd_rtcp, 16384, 16384); + if(set_multicast_options(fd_rtcp, xc.remote_rtp_ttl)) + CLOSESOCKET(fd_rtcp); + + if(connect(fd_rtcp, (struct sockaddr *)&sin, sizeof(sin))==-1 && + errno != EINPROGRESS) + LOGERR("connect(fd_rtcp) failed. Address=%s, port=%d", + xc.remote_rtp_addr, xc.remote_rtp_port + + (xc.remote_rtp_port&1)?-1:1); + + // Set to non-blocking mode + if(fcntl (fd_rtcp, F_SETFL, + fcntl (fd_rtcp, F_GETFL) | O_NONBLOCK) == -1) + LOGERR("can't put multicast socket in non-blocking mode"); + + // Finished - if(connect(fd_multicast, (struct sockaddr *)&sin, sizeof(sin))==-1 && - errno != EINPROGRESS) - LOGERR("connect(fd_multicast) failed. Address=%s, port=%d", - xc.remote_rtp_addr, xc.remote_rtp_port); - - // Set to non-blocking mode - if(fcntl (fd_multicast, F_SETFL, - fcntl (fd_multicast, F_GETFL) | O_NONBLOCK) == -1) - LOGERR("can't put multicast socket in non-blocking mode"); - - if(fd_multicast >= 0 && xc.remote_rtp_always_on) + if(fd_multicast >= 0) { + if(xc.remote_rtp_always_on) + LOGMSG("WARNING: RTP Configuration: transmission is always on !"); + if(xc.remote_rtp_always_on || m_iMulticastMask) m_Scheduler->AddHandle(fd_multicast); - - // Finished } } @@ -1014,6 +1017,8 @@ void cXinelibServer::Handle_Control(int cli, const char *cmd) } else if(!strncasecmp(cmd, "CLOSE", 5)) { CloseConnection(cli); + } else if(!strncasecmp(cmd, "GET ", 4)) { + // HTTP ? } } @@ -1092,7 +1097,7 @@ void cXinelibServer::Handle_ClientConnected(int fd) m_CtrlBufPos[cli] = 0; m_CtrlBuf[cli][0] = 0; - sprintf(str, + sprintf(str, "VDR-" VDRVERSION " " "xineliboutput-" XINELIBOUTPUT_VERSION " " "READY\r\nCLIENT-ID %d\r\n", cli); @@ -1148,6 +1153,16 @@ void cXinelibServer::Handle_Discovery_Broadcast() } } +void cXinelibServer::Handle_RTCP(void) +{ + // Called locked ! + if(fd_rtcp >= 0 && (xc.remote_rtp_always_on || m_iMulticastMask)) { + if(m_Scheduler) { + m_Scheduler->Send_RTCP(fd_rtcp, m_Frames, m_StreamPos); + } + } +} + void cXinelibServer::Action(void) { @@ -1202,7 +1217,7 @@ void cXinelibServer::Action(void) } if(fd_data[i]>=0) { pfd[fds].fd = fd_data[i]; - pfd[fds++].events = 0; + pfd[fds++].events = 0; /* check for errors only */ } } Unlock(); @@ -1218,7 +1233,6 @@ void cXinelibServer::Action(void) // poll timeout } else { - TRACE("cXinelibServer::Action --> select READY " << err); Lock(); for(int f=0; f<fds; f++) { @@ -1276,7 +1290,9 @@ void cXinelibServer::Action(void) } /* Check ready for reading */ } /* for(fds) */ - + + Handle_RTCP(); + Unlock(); } /* Check poll result */ diff --git a/frontend_svr.h b/frontend_svr.h index 642ecbd8..fbb28d07 100644 --- a/frontend_svr.h +++ b/frontend_svr.h @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: frontend_svr.h,v 1.2 2006-06-04 11:00:04 phintuka Exp $ + * $Id: frontend_svr.h,v 1.3 2006-07-04 02:06:16 phintuka Exp $ * */ @@ -36,6 +36,8 @@ class cXinelibServer : public cXinelibThread protected: virtual void Action(void); + void Handle_RTCP(void); + public: // Data transfer virtual bool Poll(cPoller &Poller, int TimeoutMs); @@ -88,6 +90,7 @@ protected: int fd_listen; int fd_multicast; + int fd_rtcp; int fd_discovery; int fd_control[MAXCLIENTS]; int fd_data[MAXCLIENTS]; diff --git a/tools/udp_pes_scheduler.c b/tools/udp_pes_scheduler.c index d44d3c38..e80f0226 100644 --- a/tools/udp_pes_scheduler.c +++ b/tools/udp_pes_scheduler.c @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: udp_pes_scheduler.c,v 1.5 2006-06-11 21:02:54 phintuka Exp $ + * $Id: udp_pes_scheduler.c,v 1.6 2006-07-04 02:09:39 phintuka Exp $ * */ @@ -12,6 +12,7 @@ #include <inttypes.h> #include <stdint.h> +#include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -28,6 +29,13 @@ #include "udp_pes_scheduler.h" #include "../xine_input_vdr_net.h" // frame headers +#include "../config.h" // rtp address & port + + +#include <sys/types.h> +#include <linux/unistd.h> +#include <errno.h> +_syscall0(pid_t, gettid) //----------------------- cTimePts ------------------------------------------ @@ -78,6 +86,8 @@ const int64_t INITIAL_BURST_TIME = (int64_t)(45000); // pts units (90kHz) // assume seek when when pts difference between two frames exceeds this (1.5 seconds) const int64_t JUMP_LIMIT_TIME = (int64_t)(3*90000/2); // pts units (90kHz) +const int RTCP_MIN_INTERVAL = 90000; // max. once in second + typedef enum { eScrDetect, eScrFromAudio, @@ -102,6 +112,11 @@ cUdpScheduler::cUdpScheduler() last_delay_time = 0; + srandom(time(NULL) ^ gettid()); + m_ssrc = random(); + LOGDBG("RTP SSRC: 0x%08x", m_ssrc); + m_LastRtcpTime = 0; + // queuing int i; @@ -298,6 +313,52 @@ int cUdpScheduler::calc_elapsed_vtime(int64_t pts, bool Audio) return (int) diff; } +void cUdpScheduler::Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets) +{ + uint64_t scr = RtpScr.Now(); + + if(scr > (m_LastRtcpTime + RTCP_MIN_INTERVAL)) { + uint8_t frame[2048], *content = frame; + rtcp_packet_t *msg = (rtcp_packet_t *)content; + struct timeval tv; + gettimeofday(&tv,NULL); + + // SR (Sender report) + msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ + msg->hdr.ptype = RTCP_SR; + msg->hdr.length = htons(6); // length 6 dwords + + msg->sr.ssrc = htonl(m_ssrc); + msg->sr.ntp_sec = htonl(tv.tv_sec + 0x83AA7E80); + msg->sr.ntp_frac = htonl((uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6)); + msg->sr.rtp_ts = htonl((uint32_t)(scr & 0xffffffff)); + msg->sr.psent = htonl((uint32_t)(Frames & 0xffffffff)); + msg->sr.osent = htonl((uint32_t)(Octets & 0xffffffff)); + + content += sizeof(rtcp_common_t) + sizeof(rtcp_sr_t); + msg = (rtcp_packet_t *)content; + + // SDES + msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ + msg->hdr.ptype = RTCP_SDES; + msg->hdr.count = 1; + + msg->sdes.ssrc = m_ssrc; + msg->sdes.item[0].type = RTCP_SDES_CNAME; + sprintf(msg->sdes.item[0].data, "VDR@%s:%d%c%c%c", xc.remote_rtp_addr, xc.remote_rtp_port, 0, 0, 0); + msg->sdes.item[0].length = strlen(msg->sdes.item[0].data); + + msg->hdr.length = htons(1 + ((msg->sdes.item[0].length - 2) + 3) / 4); + + content += sizeof(rtcp_common_t) + 4*ntohs(msg->hdr.length); + msg = (rtcp_packet_t *)content; + + // Send + int err = send(fd_rtcp, frame, content - frame, 0); + //LOGMSG("RTCP send (%d)", err); + } +} + void cUdpScheduler::Schedule(const uchar *Data, int Length) { bool Audio=false, Video=false; diff --git a/tools/udp_pes_scheduler.h b/tools/udp_pes_scheduler.h index 57fce688..4fa81a1b 100644 --- a/tools/udp_pes_scheduler.h +++ b/tools/udp_pes_scheduler.h @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: udp_pes_scheduler.h,v 1.1 2006-06-03 10:04:28 phintuka Exp $ + * $Id: udp_pes_scheduler.h,v 1.2 2006-07-04 02:08:27 phintuka Exp $ * */ @@ -55,6 +55,8 @@ class cUdpScheduler : public cThread void Clear(void); bool Flush(int TimeoutMs); + void Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets); + protected: // Data for payload handling & buffering @@ -73,13 +75,17 @@ class cUdpScheduler : public cThread // Data for scheduling algorithm - cTimePts RtpScr; // 90 kHz monotonic time source for RTP packets cTimePts MasterClock; // Current MPEG PTS (synchronized with current stream) cCondWait CondWait; int64_t current_audio_vtime; int64_t current_video_vtime; - + + // RTP + uint32_t m_ssrc; // RTP synchronization source id + cTimePts RtpScr; // 90 kHz monotonic time source for RTP timestamps + uint64_t m_LastRtcpTime; + #if 0 int data_sent; /* in current time interval, bytes */ int frames_sent; /* in current time interval */ |