diff options
-rw-r--r-- | frontend.h | 4 | ||||
-rw-r--r-- | frontend_svr.c | 33 | ||||
-rw-r--r-- | frontend_svr.h | 7 | ||||
-rw-r--r-- | tools/udp_pes_scheduler.c | 86 | ||||
-rw-r--r-- | tools/udp_pes_scheduler.h | 15 |
5 files changed, 102 insertions, 43 deletions
@@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: frontend.h,v 1.4 2006-07-02 17:11:06 phintuka Exp $ + * $Id: frontend.h,v 1.5 2006-07-07 05:32:14 phintuka Exp $ * */ @@ -48,7 +48,7 @@ class cXinelibThread : public cThread, public cListObject public: void PauseOutput(void) { TrickSpeed(0); } void ResumeOutput(void) { TrickSpeed(1); } - void TrickSpeed(int Speed); + virtual void TrickSpeed(int Speed); void SetVolume(int NewVolume); void SetLiveMode(bool); void SetStillMode(bool); diff --git a/frontend_svr.c b/frontend_svr.c index 017a033d..18f9fb1b 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.8 2006-07-06 02:57:59 phintuka Exp $ + * $Id: frontend_svr.c,v 1.9 2006-07-07 05:32:14 phintuka Exp $ * */ @@ -457,6 +457,16 @@ int cXinelibServer::Xine_Control(const char *cmd) return 1; } +void cXinelibServer::TrickSpeed(int Speed) +{ + if(Speed == 0) + m_Scheduler->Pause(true); + else + m_Scheduler->Pause(false); + + cXinelibThread::TrickSpeed(Speed); +} + bool cXinelibServer::EndOfStreamReached(void) { LOCK_THREAD; @@ -577,7 +587,7 @@ bool cXinelibServer::Listen(int listen_port) // set listen for discovery messages CLOSESOCKET(fd_discovery); - if(xc.remote_usebcast && fd_discovery<0) { + if(xc.remote_usebcast) { struct sockaddr_in sin; if ((fd_discovery = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_TCP*/)) < 0) { LOGERR("socket() failed (UDP discovery)"); @@ -608,7 +618,7 @@ bool cXinelibServer::Listen(int listen_port) CLOSESOCKET(fd_multicast); CLOSESOCKET(fd_rtcp); - if(xc.remote_usertp && fd_multicast < 0) { + if(xc.remote_usertp) { // // RTP // @@ -671,7 +681,7 @@ bool cXinelibServer::Listen(int listen_port) 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); + m_Scheduler->AddHandle(fd_multicast, fd_rtcp); } } @@ -688,7 +698,6 @@ uchar *cXinelibServer::GrabImage(int &Size, bool Jpeg, return NULL; } - // // (Client) Control message handling // @@ -826,7 +835,7 @@ void cXinelibServer::Handle_Control_RTP(int cli, const char *arg) } if(!m_iMulticastMask) - m_Scheduler->AddHandle(fd_multicast); + m_Scheduler->AddHandle(fd_multicast, fd_rtcp); m_bMulticast[cli] = true; m_iMulticastMask |= (1<<cli); @@ -1170,16 +1179,6 @@ 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) { @@ -1308,8 +1307,6 @@ void cXinelibServer::Action(void) } /* for(fds) */ - Handle_RTCP(); - Unlock(); } /* Check poll result */ diff --git a/frontend_svr.h b/frontend_svr.h index fbb28d07..a4414753 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.3 2006-07-04 02:06:16 phintuka Exp $ + * $Id: frontend_svr.h,v 1.4 2006-07-07 05:32:14 phintuka Exp $ * */ @@ -36,9 +36,10 @@ class cXinelibServer : public cXinelibThread protected: virtual void Action(void); - void Handle_RTCP(void); - public: + // Playback control + virtual void TrickSpeed(int Speed); + // Data transfer virtual bool Poll(cPoller &Poller, int TimeoutMs); virtual bool Flush(int TimeoutMs); diff --git a/tools/udp_pes_scheduler.c b/tools/udp_pes_scheduler.c index caa69485..ad98c035 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.7 2006-07-04 02:34:07 phintuka Exp $ + * $Id: udp_pes_scheduler.c,v 1.8 2006-07-07 05:32:14 phintuka Exp $ * */ @@ -42,11 +42,15 @@ _syscall0(pid_t, gettid) cTimePts::cTimePts(void) { + m_Paused = false; Set(); } int64_t cTimePts::Now(void) { + if(m_Paused) + return begin; + struct timeval t; if (gettimeofday(&t, NULL) == 0) { @@ -71,6 +75,17 @@ void cTimePts::Set(int64_t Pts) begin = Pts; } +void cTimePts::Pause(void) +{ + Set(Now()); + m_Paused = true; +} + +void cTimePts::Resume(void) +{ + m_Paused = false; +} + //----------------------- cUdpScheduler ------------------------------------- //#define LOG_RESEND @@ -86,7 +101,7 @@ 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 +const int RTCP_MIN_INTERVAL = 45000; // max. twice in second typedef enum { eScrDetect, @@ -116,12 +131,15 @@ cUdpScheduler::cUdpScheduler() m_ssrc = random(); LOGDBG("RTP SSRC: 0x%08x", m_ssrc); m_LastRtcpTime = 0; + m_Frames = 0; + m_Octets = 0; // queuing int i; for(i=0; i<MAX_UDP_HANDLES; i++) m_Handles[i] = -1; + m_fd_rtp = m_fd_rtcp = -1; m_BackLog = new cUdpBackLog; @@ -147,7 +165,7 @@ cUdpScheduler::~cUdpScheduler() delete m_BackLog; } -bool cUdpScheduler::AddHandle(int fd) +bool cUdpScheduler::AddHandle(int fd, int fd_rtcp) { cMutexLock ml(&m_Lock); @@ -159,6 +177,11 @@ bool cUdpScheduler::AddHandle(int fd) return true; } + if(fd_rtcp >=0 ) { + m_fd_rtp = fd; + m_fd_rtcp = fd_rtcp; + } + return false; } @@ -176,6 +199,9 @@ void cUdpScheduler::RemoveHandle(int fd) m_Handles[MAX_UDP_HANDLES-1] = -1; + if(fd == m_fd_rtp) + m_fd_rtp = m_fd_rtcp = -1; + if(m_Handles[0] < 0) { // No clients left ... @@ -184,6 +210,9 @@ void cUdpScheduler::RemoveHandle(int fd) m_QueuePending = 0; delete m_BackLog; m_BackLog = new cUdpBackLog; + + m_Frames = 0; + m_Octets = 0; } } @@ -240,6 +269,16 @@ void cUdpScheduler::Clear(void) m_Cond.Broadcast(); } +void cUdpScheduler::Pause(bool On) +{ + cMutexLock ml(&m_Lock); + + if(On) + MasterClock.Pause(); + else + MasterClock.Resume(); +} + bool cUdpScheduler::Queue(uint64_t StreamPos, const uchar *Data, int Length) { cMutexLock ml(&m_Lock); @@ -313,15 +352,20 @@ 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) +void cUdpScheduler::Send_RTCP(void) { + if(m_fd_rtcp < 0) + return; + uint64_t scr = RtpScr.Now(); if(scr > (m_LastRtcpTime + RTCP_MIN_INTERVAL)) { uint8_t frame[2048], *content = frame; + char hostname[64] = ""; rtcp_packet_t *msg = (rtcp_packet_t *)content; struct timeval tv; - gettimeofday(&tv,NULL); + gettimeofday(&tv, NULL); + gethostname(hostname, 63); // SR (Sender report) msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ @@ -332,8 +376,8 @@ void cUdpScheduler::Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets) 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)); + msg->sr.psent = htonl((uint32_t)(m_Frames & 0xffffffff)); + msg->sr.osent = htonl((uint32_t)(m_Octets & 0xffffffff)); content += sizeof(rtcp_common_t) + sizeof(rtcp_sr_t); msg = (rtcp_packet_t *)content; @@ -345,7 +389,9 @@ void cUdpScheduler::Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets) 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); + sprintf(msg->sdes.item[0].data, "VDR@%s:%d%c%c%c", + hostname[0] ? hostname : 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 + 1 + ((msg->sdes.item[0].length - 2) + 3) / 4); @@ -354,7 +400,7 @@ void cUdpScheduler::Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets) msg = (rtcp_packet_t *)content; // Send - int err = send(fd_rtcp, frame, content - frame, 0); + (void) send(m_fd_rtcp, frame, content - frame, 0); #ifdef LOG_RTCP LOGMSG("RTCP send (%d)", err); for(int i=0; i<content-frame; i+=16) @@ -370,6 +416,8 @@ void cUdpScheduler::Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets) frame[i+8],frame[i+9],frame[i+10],frame[i+11], frame[i+12],frame[i+13],frame[i+14],frame[i+15]); #endif + + m_LastRtcpTime = scr; } } @@ -462,17 +510,14 @@ void cUdpScheduler::Action(void) sched_get_priority_min(SCHED_RR), sched_get_priority_max(SCHED_RR)); } - - /* UDP Scheduler needs high priority */ - SetPriority(0); - SetPriority(-1); - SetPriority(-2); - SetPriority(-3); - SetPriority(-4); - SetPriority(-5); } #endif + /* UDP Scheduler needs high priority */ + SetPriority(-5); + (void)nice(-5); + errno = 0; + m_Lock.Lock(); while(m_Running) { @@ -486,6 +531,9 @@ void cUdpScheduler::Action(void) if(m_QueuePending <= 0) { m_Cond.TimedWait(m_Lock, 100); if(m_QueuePending <= 0) { + // Still nothing... + // Send padding frame once in 100ms so clients can detect + // possible missing frames and server shutdown static unsigned char padding[] = {0x00,0x00,0x01,0xBE,0x00,0x02,0xff,0xff}; int prevseq = (m_QueueNextSeq + UDP_BUFFER_SIZE - 1) & UDP_BUFFER_MASK; stream_udp_header_t *frame = m_BackLog->Get(prevseq); @@ -605,6 +653,10 @@ void cUdpScheduler::Action(void) } m_Lock.Lock(); + m_Frames ++; + m_Octets += PayloadSize; + if((m_Frames & 0xff) == 1) // every 256th frame + Send_RTCP(); } m_Lock.Unlock(); diff --git a/tools/udp_pes_scheduler.h b/tools/udp_pes_scheduler.h index 4fa81a1b..4fe72141 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.2 2006-07-04 02:08:27 phintuka Exp $ + * $Id: udp_pes_scheduler.h,v 1.3 2006-07-07 05:32:14 phintuka Exp $ * */ @@ -23,12 +23,16 @@ class cTimePts private: int64_t begin; struct timeval tbegin; + bool m_Paused; public: cTimePts(void); int64_t Now(void); void Set(int64_t Pts = 0LL); + + void Pause(void); + void Resume(void); }; //----------------------- cUdpPesScheduler ---------------------------------- @@ -45,7 +49,7 @@ class cUdpScheduler : public cThread virtual ~cUdpScheduler(); // fd should be binded & connected to IP:PORT (local+remote) pair ! - bool AddHandle(int fd); + bool AddHandle(int fd, int fd_rtcp=-1); void RemoveHandle(int fd); bool Poll(int TimeoutMs, bool Master); @@ -55,7 +59,7 @@ class cUdpScheduler : public cThread void Clear(void); bool Flush(int TimeoutMs); - void Send_RTCP(int fd_rtcp, uint32_t Frames, uint64_t Octets); + void Pause(bool On); protected: @@ -67,6 +71,7 @@ class cUdpScheduler : public cThread // Clients int m_Handles[MAX_UDP_HANDLES]; + int m_fd_rtp, m_fd_rtcp; // Queue int m_QueueNextSeq; /* next outgoing */ @@ -85,6 +90,8 @@ class cUdpScheduler : public cThread uint32_t m_ssrc; // RTP synchronization source id cTimePts RtpScr; // 90 kHz monotonic time source for RTP timestamps uint64_t m_LastRtcpTime; + uint32_t m_Frames; + uint32_t m_Octets; #if 0 int data_sent; /* in current time interval, bytes */ @@ -104,6 +111,8 @@ class cUdpScheduler : public cThread bool m_Running; virtual void Action(void); + + void Send_RTCP(void); }; #endif |