diff --git a/server/Makefile b/server/Makefile index 37cd4bb..d339116 100644 --- a/server/Makefile +++ b/server/Makefile @@ -25,6 +25,7 @@ SERVEROBJS = $(PLUGIN).o \ server.o component.o connection.o \ componentVTP.o connectionVTP.o \ componentHTTP.o connectionHTTP.o menuHTTP.o \ + componentRTSP.o connectionRTSP.o \ componentIGMP.o connectionIGMP.o \ streamer.o livestreamer.o livefilter.o recstreamer.o recplayer.o \ menu.o suspend.o setup.o diff --git a/server/server.c b/server/server.c index 8dd122e..fbb575b 100644 --- a/server/server.c +++ b/server/server.c @@ -5,6 +5,7 @@ #include "server/server.h" #include "server/componentVTP.h" #include "server/componentHTTP.h" +#include "server/componentRTSP.h" #include "server/componentIGMP.h" #include "server/setup.h" @@ -27,16 +28,17 @@ cStreamdevServer::cStreamdevServer(void): Start(); } -cStreamdevServer::~cStreamdevServer() +cStreamdevServer::~cStreamdevServer() { Stop(); } -void cStreamdevServer::Initialize(void) +void cStreamdevServer::Initialize(void) { if (m_Instance == NULL) { if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP); if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP); + if (StreamdevServerSetup.StartRTSPServer) Register(new cComponentRTSP); if (StreamdevServerSetup.StartIGMPServer) { if (strcmp(StreamdevServerSetup.IGMPBindIP, "0.0.0.0") == 0) esyslog("streamdev-server: Not starting IGMP. IGMP must be bound to a local IP"); diff --git a/server/setup.c b/server/setup.c index 37d1b45..c9a4847 100644 --- a/server/setup.c +++ b/server/setup.c @@ -22,6 +22,9 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) { HTTPServerPort = 3000; HTTPPriority = 0; HTTPStreamType = stTS; + StartRTSPServer = true; + RTSPServerPort = 554; + RTSPPriority = 0; StartIGMPServer = false; IGMPClientPort = 1234; IGMPPriority = 0; @@ -29,6 +32,7 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) { AllowSuspend = false; strcpy(VTPBindIP, "0.0.0.0"); strcpy(HTTPBindIP, "0.0.0.0"); + strcpy(RTSPBindIP, "0.0.0.0"); strcpy(IGMPBindIP, "0.0.0.0"); } @@ -47,6 +51,10 @@ bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) { else if (strcmp(Name, "HTTPPriority") == 0) HTTPPriority = atoi(Value); else if (strcmp(Name, "HTTPStreamType") == 0) HTTPStreamType = atoi(Value); else if (strcmp(Name, "HTTPBindIP") == 0) strcpy(HTTPBindIP, Value); + else if (strcmp(Name, "StartRTSPServer") == 0) StartRTSPServer = atoi(Value); + else if (strcmp(Name, "RTSPServerPort") == 0) RTSPServerPort = atoi(Value); + else if (strcmp(Name, "RTSPPriority") == 0) RTSPPriority = atoi(Value); + else if (strcmp(Name, "RTSPBindIP") == 0) strcpy(RTSPBindIP, Value); else if (strcmp(Name, "StartIGMPServer") == 0) StartIGMPServer = atoi(Value); else if (strcmp(Name, "IGMPClientPort") == 0) IGMPClientPort = atoi(Value); else if (strcmp(Name, "IGMPPriority") == 0) IGMPPriority = atoi(Value); @@ -107,6 +115,12 @@ void cStreamdevServerMenuSetupPage::Set(void) { Add(new cMenuEditIntItem (tr("Priority"), &m_NewSetup.HTTPPriority, MINPRIORITY, MAXPRIORITY)); Add(new cMenuEditStraItem(tr("HTTP Streamtype"), &m_NewSetup.HTTPStreamType, st_Count - 1, StreamTypes)); + AddCategory (tr("RTSP Server")); + Add(new cMenuEditBoolItem(tr("Start RTSP Server"), &m_NewSetup.StartRTSPServer)); + Add(new cMenuEditIntItem (tr("RTSP Server Port"), &m_NewSetup.RTSPServerPort, 0, 65535)); + Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.RTSPBindIP)); + Add(new cMenuEditIntItem (tr("Priority"), &m_NewSetup.RTSPPriority, MINPRIORITY, MAXPRIORITY)); + AddCategory (tr("Multicast Streaming Server")); Add(new cMenuEditBoolItem(tr("Start IGMP Server"), &m_NewSetup.StartIGMPServer)); Add(new cMenuEditIntItem (tr("Multicast Client Port"), &m_NewSetup.IGMPClientPort, 0, 65535)); @@ -135,13 +149,16 @@ void cStreamdevServerMenuSetupPage::Store(void) { || m_NewSetup.StartHTTPServer != StreamdevServerSetup.StartHTTPServer || m_NewSetup.HTTPServerPort != StreamdevServerSetup.HTTPServerPort || strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0 + || m_NewSetup.StartRTSPServer != StreamdevServerSetup.StartRTSPServer + || m_NewSetup.RTSPServerPort != StreamdevServerSetup.RTSPServerPort + || strcmp(m_NewSetup.RTSPBindIP, StreamdevServerSetup.RTSPBindIP) != 0 || m_NewSetup.StartIGMPServer != StreamdevServerSetup.StartIGMPServer || m_NewSetup.IGMPClientPort != StreamdevServerSetup.IGMPClientPort || strcmp(m_NewSetup.IGMPBindIP, StreamdevServerSetup.IGMPBindIP) != 0) { restart = true; cStreamdevServer::Destruct(); } - + SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry); SetupStore("MaxClients", m_NewSetup.MaxClients); SetupStore("StartSuspended", m_NewSetup.StartSuspended); @@ -156,6 +173,9 @@ void cStreamdevServerMenuSetupPage::Store(void) { SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP); SetupStore("HTTPPriority", m_NewSetup.HTTPPriority); SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType); + SetupStore("RTSPServerPort", m_NewSetup.RTSPServerPort); + SetupStore("RTSPBindIP", m_NewSetup.RTSPBindIP); + SetupStore("RTSPPriority", m_NewSetup.RTSPPriority); SetupStore("StartIGMPServer", m_NewSetup.StartIGMPServer); SetupStore("IGMPClientPort", m_NewSetup.IGMPClientPort); SetupStore("IGMPBindIP", m_NewSetup.IGMPBindIP); diff --git a/server/setup.h b/server/setup.h index f464137..d171c33 100644 --- a/server/setup.h +++ b/server/setup.h @@ -34,6 +34,10 @@ struct cStreamdevServerSetup { int HTTPPriority; int HTTPStreamType; char HTTPBindIP[20]; + int StartRTSPServer; + int RTSPServerPort; + int RTSPPriority; + char RTSPBindIP[20]; int StartIGMPServer; int IGMPClientPort; int IGMPPriority; diff --git a/server/streamer.c b/server/streamer.c index d1a9b3e..afc1bae 100644 --- a/server/streamer.c +++ b/server/streamer.c @@ -21,11 +21,12 @@ cStreamdevBuffer::cStreamdevBuffer(int Size, int Margin, bool Statistics, const // --- cStreamdevWriter ------------------------------------------------------- -cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket, +cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer): cThread("streamdev-writer"), m_Streamer(Streamer), - m_Socket(Socket) + m_Socket(Socket), + m_StreamEncapsulation(seRAW) { } @@ -42,6 +43,10 @@ void cStreamdevWriter::Action(void) Dprintf("Writer start\n"); int max = 0; uchar *block = NULL; + uchar rtpbuf[(7*TS_SIZE)+12]; // 7 TS packets + RTP header size (12 bytes) + ushort sequence_number = 0; + ulong tstamp = 0; + ulong ssrc = 0; int count, offset = 0; int timeout = 0; @@ -71,7 +76,7 @@ void cStreamdevWriter::Action(void) if (sel.CanWrite(*m_Socket)) { int written; int pkgsize = count; - // SOCK_DGRAM indicates multicast + // SOCK_DGRAM indicates unicast/multicast RTP or TS-in-UDP if (m_Socket->Type() == SOCK_DGRAM) { // don't fragment multicast packets // max. payload on standard local ethernet is 1416 to 1456 bytes @@ -81,10 +86,42 @@ void cStreamdevWriter::Action(void) pkgsize = 7 * TS_SIZE; else pkgsize -= pkgsize % TS_SIZE; + + // Check if this should be an RTP stream and not a raw TS-in-UDP stream + if (m_StreamEncapsulation == seRTP) { + // Set RTP header + rtpbuf[0] = 0x02; //RTP version 2, no padding, no extension header, CSRC Count = 0 + rtpbuf[1] = 0x20; // RTP payload type 32, no marker + rtpbuf[2] = sequence_number & 0x00FF; + rtpbuf[3] = (sequence_number & 0xFF00) >>8; + rtpbuf[4] = tstamp & 0x000000FF; + rtpbuf[5] = (tstamp & 0x0000FF00) >>8; + rtpbuf[6] = (tstamp & 0x00FF0000) >>16; + rtpbuf[7] = (tstamp & 0xFF000000) >>24; + rtpbuf[8] = ssrc & 0x000000FF; + rtpbuf[9] = (ssrc & 0x0000FF00) >>8; + rtpbuf[10] = (ssrc & 0x00FF0000) >>16; + rtpbuf[11] = (ssrc & 0xFF000000) >>24; + memcpy(&rtpbuf[12], block + offset, pkgsize); + if ((written = m_Socket->Write(&rtpbuf[0], pkgsize+12)) == -1) { + esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize); + break; + } + // Remove size of RTP header again + if (written > 12 ) + written -= 12; + } + else + if ((written = m_Socket->Write(block + offset, pkgsize)) == -1) { + esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize); + break; + } } - if ((written = m_Socket->Write(block + offset, pkgsize)) == -1) { - esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize); - break; + else { + if ((written = m_Socket->Write(block + offset, pkgsize)) == -1) { + esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize); + break; + } } // statistics @@ -107,6 +144,11 @@ void cStreamdevWriter::Action(void) Dprintf("Max. Transmit Blocksize was: %d\n", max); } +void cStreamdevWriter::SetStreamEncapsulationType(eStreamEncapsulation StreamEncapsulation) +{ + m_StreamEncapsulation = StreamEncapsulation; +} + // --- cRemuxDummy ------------------------------------------------------------ class cRemuxDummy: public Streamdev::cTSRemux { diff --git a/server/streamer.h b/server/streamer.h index af69cbe..79ad7f8 100644 --- a/server/streamer.h +++ b/server/streamer.h @@ -21,6 +21,11 @@ class cServerConnection; #define WRITERBUFSIZE (20000 * TS_SIZE) +enum eStreamEncapsulation{ + seRAW, + seRTP +}; + // --- cStreamdevBuffer ------------------------------------------------------- class cStreamdevBuffer: public cRingBufferLinear { @@ -53,6 +58,7 @@ class cStreamdevWriter: public cThread { private: cStreamdevStreamer *m_Streamer; cTBSocket *m_Socket; + eStreamEncapsulation m_StreamEncapsulation; protected: virtual void Action(void); @@ -60,6 +66,8 @@ protected: public: cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer); virtual ~cStreamdevWriter(); + + void SetStreamEncapsulationType(eStreamEncapsulation StreamEncapsulation); }; // --- cStreamdevStreamer -----------------------------------------------------