summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontend_svr.c150
-rw-r--r--frontend_svr.h5
-rw-r--r--tools/udp_pes_scheduler.c63
-rw-r--r--tools/udp_pes_scheduler.h12
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 */