diff --git a/Connector_RTSP/Makefile b/Connector_RTSP/Makefile index f628e588..f1db6322 100644 --- a/Connector_RTSP/Makefile +++ b/Connector_RTSP/Makefile @@ -1,7 +1,7 @@ -SRC = main.cpp ../sockets/sw_base.cpp ../sockets/sw_inet.cpp ../sockets/sw_unix.cpp +SRC = main.cpp ../util/socket.cpp ../util/http_parser.cpp ../util/flv_tag.cpp ../util/amf.cpp OBJ = $(SRC:.cpp=.o) OUT = Connector_RTSP -INCLUDES = -I/usr/local/include/jthread/ +INCLUDES = DEBUG = 4 OPTIMIZE = -g CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) diff --git a/Connector_RTSP/compile_remarks.txt b/Connector_RTSP/compile_remarks.txt index 3985360b..9eb10db9 100644 --- a/Connector_RTSP/compile_remarks.txt +++ b/Connector_RTSP/compile_remarks.txt @@ -11,9 +11,11 @@ anders geen compiles... Vervolgens: bij het runnen van ./Connector_RTSP: -./Connector_RTSP: error while loading shared libraries: libjrtp-3.7.1.so: cannot open shared object file: No such file or directory +./Connector_RTSP: error while loading shared libraries: libjrtp-3.7.1.so: cannot open shared object +file: No such file or directory -dus: ik kan op het moment genoeg coden, en zorgen dat het compiled, maar ook daadwerkelijk draaien wordt lastig... Enige ideeen? \ No newline at end of file +dus: ik kan op het moment genoeg coden, en zorgen dat het compiled, maar ook daadwerkelijk draaien +wordt lastig... Enige ideeen? diff --git a/Connector_RTSP/main.cpp b/Connector_RTSP/main.cpp index f0b6c41f..7cae8b8f 100644 --- a/Connector_RTSP/main.cpp +++ b/Connector_RTSP/main.cpp @@ -1,214 +1,130 @@ -#define DEBUG(args...) //debugging disabled -//#define DEBUG(args...) fprintf(stderr, args) //debugging enabled +/// \file Connector_RTSP/main.cpp +/// Contains the main code for the RTSP Connector -#include -#include -#include +#include #include -#include - -//needed for select -#include -#include -#include -#include +#include +#include +#include +#include +#include #include - +#include +#include #include -#include - -unsigned int getNowMS(){ - timeval t; - gettimeofday(&t, 0); - return t.tv_sec + t.tv_usec/1000; -} -void hexdump(void *pAddressIn, long lSize) -{ - char szBuf[100]; - long lIndent = 1; - long lOutLen, lIndex, lIndex2, lOutLen2; - long lRelPos; - struct { char *pData; unsigned long lSize; } buf; - unsigned char *pTmp,ucTmp; - unsigned char *pAddress = (unsigned char *)pAddressIn; - - buf.pData = (char *)pAddress; - buf.lSize = lSize; - - while (buf.lSize > 0) - { - pTmp = (unsigned char *)buf.pData; - lOutLen = (int)buf.lSize; - if (lOutLen > 16) - lOutLen = 16; - - // create a 64-character formatted output line: - sprintf(szBuf, " > " - " " - " %08lX", pTmp-pAddress); - lOutLen2 = lOutLen; - - for(lIndex = 1+lIndent, lIndex2 = 53-15+lIndent, lRelPos = 0; - lOutLen2; - lOutLen2--, lIndex += 2, lIndex2++ - ) - { - ucTmp = *pTmp++; - - sprintf(szBuf + lIndex, "%02X ", (unsigned short)ucTmp); - if(!isprint(ucTmp)) ucTmp = '.'; // nonprintable char - szBuf[lIndex2] = ucTmp; - - if (!(++lRelPos & 3)) // extra blank after 4 bytes - { lIndex++; szBuf[lIndex+2] = ' '; } - } - - if (!(lRelPos & 3)) lIndex--; - - szBuf[lIndex ] = '<'; - szBuf[lIndex+1] = ' '; - - DEBUG("%s\n", szBuf); - - buf.pData += lOutLen; - buf.lSize -= lOutLen; - } -} - -//for connection to server -#include "../sockets/SocketW.h" -bool ready4data = false;//set to true when streaming starts -bool inited = false; -bool stopparsing = false; -timeval lastrec; - -#include "../util/flv_sock.cpp" //FLV parsing with SocketW -#include "rtsp.cpp" +#include +#include +#include +#include "../util/socket.h" +#include "../util/flv_tag.h" +#include "../util/http_parser.h" +//JRTPLIB #include "rtp.h" -void parse_ip(char* ip_addr, uint8_t * uitvoer) { - int i = 0; - int j = 0; - int tempint = 0; - while( ip_addr[i] != '\0' ) { - if( ip_addr[i] != '.' ) { - tempint = tempint * 10; - tempint += ip_addr[i] - '0'; - } else { - uitvoer[j] = tempint; - tempint = 0; - j++; +/// The main function of the connector +/// \param conn A connection with the client +int RTSP_Handler( Socket::Connection conn ) { + bool ready4data = false; + FLV::Tag tag;///< Temporary tag buffer for incoming video data. + bool inited = false; + bool firstvideo = true; + std::string PreviousRequest = ""; + Socket::Connection ss(-1); + HTTP::Parser HTTP_R, HTTP_S; + bool PerRequest = false; + while(conn.connected() && !FLV::Parse_Error) { + if( HTTP_R.Read(conn, ready4data) ) { + fprintf( stderr, "REQUEST:\n%s\n", HTTP_R.BuildRequest().c_str() ); + if( HTTP_R.GetHeader( "User-Agent" ).find( "RealMedia Player Version" ) != std::string::npos) { + PerRequest = true; + } + HTTP_S.protocol = "RTSP/1.0"; + if( HTTP_R.method == "OPTIONS" ) { + HTTP_S.SetHeader( "CSeq", HTTP_R.GetHeader( "CSeq" ).c_str() ); + HTTP_S.SetHeader( "Public", "DESCRIBE, SETUP, TEARDOWN, PLAY" ); + HTTP_S.SetBody( "\r\n" ); + fprintf( stderr, "RESPONSE:\n%s\n", HTTP_S.BuildResponse( "200", "OK" ).c_str() ); + conn.write( HTTP_S.BuildResponse( "200", "OK" ) ); + } else if ( HTTP_R.method == "DESCRIBE" ) { + if( HTTP_R.GetHeader( "Accept" ).find( "application/sdp" ) == std::string::npos ) { + fprintf( stderr, "RESPONSE:\n%s\n", HTTP_S.BuildResponse( "501", "Not Implemented" ).c_str() ); + conn.write( HTTP_S.BuildResponse( "501", "Not Implemented" ) ); + } else { + HTTP_S.SetHeader( "CSeq", HTTP_R.GetHeader( "CSeq" ).c_str() ); + HTTP_S.SetHeader( "Content-Type", "application/sdp" ); + HTTP_S.SetBody( "v=0\r\no=- 0 0 IN IP4 ddvtech.com\r\ns=Fifa Test\r\nc=IN IP4 127.0.0.1\r\nt=0 0\r\na=recvonly\r\nm=video 0 RTP/AVP 98\r\na=rtpmap:98 H264/90000\na=fmtp:98 packetization-mode=1\r\n\r\n" ); + fprintf( stderr, "RESPONSE:\n%s\n", HTTP_S.BuildResponse( "200", "OK" ).c_str() ); + conn.write( HTTP_S.BuildResponse( "200", "OK" ) ); + } + } else if ( HTTP_R. method == "SETUP" ) { + std::string temp = HTTP_R.GetHeader("Transport"); + int ClientRTPLoc = temp.find( "client_port=" ) + 12; + int PortSpacer = temp.find( "-", ClientRTPLoc ); + int PortEnd = ( temp.find( ";", PortSpacer ) ); + int RTPClientPort = atoi( temp.substr( ClientRTPLoc, ( PortSpacer - ClientRTPLoc ) ).c_str() ); + int RTCPClientPort = atoi( temp.substr( PortSpacer + 1 , ( PortEnd - ( PortSpacer + 1 ) ) ).c_str() ); + if( HTTP_S.GetHeader( "Session" ) != "" ) { + fprintf( stderr, "RESPONSE:\n%s\n", HTTP_S.BuildResponse( "459", "Aggregate Operation Not Allowed" ).c_str() ); + conn.write( HTTP_S.BuildResponse( "459", "Aggregate Operation Not Allowed" ) ); + } else { + HTTP_S.SetHeader( "CSeq", HTTP_R.GetHeader( "CSeq" ).c_str() ); + HTTP_S.SetHeader( "Session", time(NULL) ); + fprintf( stderr, "RESPONSE:\n%s\n", HTTP_S.BuildResponse( "200", "OK" ).c_str() ); + conn.write( HTTP_S.BuildResponse( "200", "OK" ) ); + } + } else { + fprintf( stderr, "RESPONSE:\n%s\n", HTTP_S.BuildResponse( "501", "Not Implemented" ).c_str() ); + conn.write( HTTP_S.BuildResponse( "501", "Not Implemented" ) ); + } + HTTP_R.Clean(); + HTTP_S.Clean(); + if( PerRequest ) { + conn.close(); + } } - i++; +/* if( !inited ) { + ss = Socket::Connection("/tmp/shared_socket_fifa"); + if (!ss.connected()){ + #if DEBUG >= 1 + fprintf(stderr, "Could not connect to server!\n"); + #endif + conn.close(); + break; + } + #if DEBUG >= 3 + fprintf(stderr, "Everything connected, starting to send video data...\n"); + #endif + inited = true; + } + + switch (ss.ready()){ + case -1: + conn.close(); + #if DEBUG >= 1 + fprintf(stderr, "Source socket is disconnected.\n"); + #endif + break; + case 0: break;//not ready yet + default: + if (tag.SockLoader(ss)){//able to read a full packet? + if( tag.data[ 0 ] == 0x09 ) { + if( ( ( tag.data[ 11 ] & 0x0F ) == 7 ) ) { //&& ( tag.data[ 12 ] == 1 ) ) { + fprintf(stderr, "Video contains NALU\n" ); + } + } + if( tag.data[ 0 ] == 0x08 ) { + if( ( tag.data[ 11 ] == 0xAF ) && ( tag.data[ 12 ] == 0x01 ) ) { + fprintf(stderr, "Audio Contains Raw AAC\n"); + } + } + } + break; + }*/ } - uitvoer[j] = tempint; + return 0; } -int main(){ - unsigned int ts; - unsigned int fts = 0; - unsigned int ftst; - SWUnixSocket ss; - fd_set pollset; - struct timeval timeout; - RTPSession rtp_connection; - RTPSessionParams sessionparams; - RTPUDPv4TransmissionParams transparams; - - //0 timeout - return immediately after select call - timeout.tv_sec = 1; timeout.tv_usec = 0; - FD_ZERO(&pollset);//clear the polling set - FD_SET(0, &pollset);//add stdin to polling set - - - DEBUG("Starting processing...\n"); - while (!feof(stdin) && !stopparsing){ - //select(1, &pollset, 0, 0, &timeout); - //only parse input from stdin if available or not yet init'ed - //FD_ISSET(0, &pollset) || //NOTE: Polling does not work? WHY?!? WHY DAMN IT?!? - if (!ready4data && !stopparsing){ParseRTSPPacket();} - if (ready4data && !stopparsing){ - if (!inited){ - //we are ready, connect the socket! - if (!ss.connect("/tmp/shared_socket")){ - DEBUG("Could not connect to server!\n"); - return 0; - } - FLV_Readheader(ss);//read the header, we don't want it - DEBUG("Header read, starting to send video data...\n"); - - sessionparams.SetOwnTimestampUnit(1.0);//1sample/second, dummydata, wordt toch elke keer per packet ingesteld. - transparams.SetPortbase(serverport); - rtp_connection.Create(sessionparams,&transparams); - - struct sockaddr_in i; - int len; - char * addr1; - len = sizeof(i); - if (getpeername( fileno(stdin), (sockaddr*)&i, (socklen_t*)&len ) == 0) { - addr1 = (char *) inet_ntoa(i.sin_addr); - DEBUG("%s\n", addr1 ); - } else { - DEBUG("Blaah\n"); - } - - uint8_t clientip[4]; - parse_ip(addr1,clientip); - - //TODO: clientip ophalen uit stdin-socket: zie http://www.mail-archive.com/plug@lists.q-linux.com/msg16482.html - RTPIPv4Address addr(clientip,clientport); - DEBUG("RTP Connected\n"); - - inited = true; - } - if (FLV_GetPacket(ss)){//able to read a full packet? - //gooi de time uit de flv codec naar de juiste offsets voor deze kijker - ts = FLVbuffer[7] * 256*256*256; - ts += FLVbuffer[4] * 256*256; - ts += FLVbuffer[5] * 256; - ts += FLVbuffer[6]; - if (ts != 0){ - if (fts == 0){fts = ts;ftst = getNowMS();} - ts -= fts; - FLVbuffer[7] = ts / (256*256*256); - FLVbuffer[4] = ts / (256*256); - FLVbuffer[5] = ts / 256; - FLVbuffer[6] = ts % 256; - ts += ftst; - }else{ - ftst = getNowMS(); - FLVbuffer[7] = ftst / (256*256*256); - FLVbuffer[4] = ftst / (256*256); - FLVbuffer[5] = ftst / 256; - FLVbuffer[6] = ftst % 256; - } - - if( FLVbuffer[0] != 0x12 ) {//Metadata direct filteren. - if( FLVbuffer[0] == 0x08 ) { //Audio Packet -// DEBUG("Audio Packet\n"); - rtp_connection.SetTimestampUnit(1.0/11025);//11025 samples/second - //Audiodata heeft na de flv-tag nog 2 UI8 aan beschrijvingen die NIET bij de AAC-data horen - //NOTE:Same als hieronder, wat moeten we doen met init-data van aac? die info wordt nu omitted. - rtp_connection.SendPacket( &FLVbuffer[13], FLV_len - 17, 99, false, 1); - } else if ( FLVbuffer[0] == 0x09 ) { //Video Packet -// DEBUG("Video Packet: %i\n", (FLVbuffer[16] & 0x1F) ); - rtp_connection.SetTimestampUnit(1.0/90000);//90000 samples/second - //Videodata heeft na de flv-tag nog 2 UI8 en een SI24 aan beschrijvingen die niet bij de NALU horen - //NOTE:Moeten we eigenlijk wat adobe genereert als sequence headers/endings ook gwoon doorsturen? gebeurt nu wel - rtp_connection.SendPacket( &FLVbuffer[16], FLV_len - 19, 98, false, 1); -// hexdump(&FLVbuffer[16], FLV_len-19 ); - } - } else {//Datatype 0x12 = metadata, zouden we voor nu weggooien - DEBUG("Metadata, throwing away\n"); - } - FLV_Dump();//dump packet and get ready for next - } - if ((SWBerr != SWBaseSocket::ok) && (SWBerr != SWBaseSocket::notReady)){ - DEBUG("No more data! :-( (%s)\n", SWBerr.get_error().c_str()); - return 0;//no more input possible! Fail immediately. - } - } - } - DEBUG("User disconnected.\n"); - return 0; -}//main +#define DEFAULT_PORT 554 +#define MAINHANDLER RTSP_Handler +#define CONFIGSECT RTSP +#include "../util/server_setup.cpp" diff --git a/Connector_RTSP/rtsp.cpp b/Connector_RTSP/rtsp.cpp deleted file mode 100644 index a8b07812..00000000 --- a/Connector_RTSP/rtsp.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include -#include - -int clientport = 0; -int serverport = 6256; - - -class RTSPPack{ - public: - std::map params; - std::string data; -};//RTSPPack - - -RTSPPack GetRTSPPacket(){ - std::string tmp, a, b; - RTSPPack ret; - bool first = true; - std::size_t f; - do { - std::getline(std::cin, tmp); - if (first){ - f = tmp.find_first_of(' '); - if (f != std::string::npos){ - a = tmp.substr(0, f); - tmp = tmp.substr(f+1); - f = tmp.find('\r'); - if (f != std::string::npos){tmp.erase(f);} - ret.params["request"] = a; - DEBUG("Request type %s\n", a.c_str()); - f = tmp.find_first_of(' '); - if (f != std::string::npos){ - a = tmp.substr(0, f); - ret.params["url"] = a; - DEBUG("URL=%s\n", a.c_str()); - } - } - first = false; - }else{ - f = tmp.find_first_of(':'); - if (f != std::string::npos){ - a = tmp.substr(0, f); - b = tmp.substr(f+2); - f = b.find('\r'); - if (f != std::string::npos){b.erase(f);} - ret.params[a] = b; - DEBUG("Adding '%s' as '%s'\n", a.c_str(), b.c_str()); - } - } - }while(tmp.length() > 2); - DEBUG("End of request headers\n"); - int len = 0; - if (ret.params["Content-Length"] != ""){ - len = atoi(ret.params["Content-Length"].c_str()); - } - - if (len > 0){ - DEBUG("There is a length %i request body:\n", len); - char * data = (char*)malloc(len); - fread(&data, 1, len, stdin); - ret.data = data; - free(data); - DEBUG("%s\nEnd of body data.\n", ret.data.c_str()); - }else{ - DEBUG("No request body.\n"); - } - return ret; -}//GetRTSPPacket - -void RTSPReply(RTSPPack & q, RTSPPack & a, std::string retval){ - if (q.params["CSeq"] != ""){a.params["CSeq"] = q.params["CSeq"];} - if (q.params["Require"] != ""){a.params["Unsupported"] = q.params["Require"];} - if (a.data != ""){ - char * len = (char*)malloc(10); - sprintf(len, "%i", (int)a.data.length()); - a.params["Content-Length"] = len; - free(len); - } - - std::cout << "RTSP/1.0 " << retval << "\r\n"; - - std::map::iterator it; - for (it = a.params.begin(); it != a.params.end(); it++){ - std::cout << (*it).first << ": " << (*it).second << "\r\n"; - } - std::cout << "\r\n" << a.data; - std::cout.flush(); -}//RTSPReply - -void ParseRTSPPacket(){ - RTSPPack q = GetRTSPPacket(); - RTSPPack a; - - //parse OPTIONS request - if (q.params["request"] == "OPTIONS"){ - a.params["Public"] = "SETUP, TEARDOWN, OPTIONS, DESCRIBE, PLAY"; - RTSPReply(q, a, "200 OK"); - DEBUG("Sent OPTIONS reply\n"); - } - - //parse DESCRIBE request - if (q.params["request"] == "DESCRIBE"){ - a.params["Content-Type"] = "application/sdp"; - a.data = "v=0\r\no=- 0 0 IN IP4 ddvtech.com\r\ns=PLSServer\r\nc=IN IP4 0.0.0.0\r\na=recvonly\r\nt=0 0\r\nm=video 0 RTP/AVP 98\r\na=rtpmap:98 H264/90000\r\na=fmtp:98 packetization-mode=1\r\nm=audio 0 RTP/AVP 99\r\na=rtpmap:99 MPEG4-GENERIC/11025/1\r\na=ftmp:99 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexltalength=3; config=1210\r\n"; - RTSPReply(q, a, "200 OK"); - DEBUG("Sent DESCRIBE reply\n"); - } - - //parse SETUP request - if (q.params["request"] == "SETUP"){ - size_t f, g; - std::string s; - f = q.params["Transport"].rfind('=')+1; - g = q.params["Transport"].rfind('-'); - clientport = atoi(q.params["Transport"].substr(f, g-f).c_str()); - DEBUG("Requested client base port: %i\n", clientport); - char * len = (char*)malloc(30); - sprintf(len, ";server_port=%i-%i", serverport, serverport+1); - a.params["Transport"] = len; - a.params["Transport"] = q.params["Transport"] + a.params["Transport"]; - free(len); - a.params["Session"] = "puddingbroodjes"; - RTSPReply(q, a, "200 OK"); - DEBUG("Sent SETUP reply\n"); - } - - //parse PLAY request - if (q.params["request"] == "PLAY"){ - RTSPReply(q, a, "200 OK"); - ready4data = true; - } - - //parse TEARDOWN request - if (q.params["request"] == "TEARDOWN"){ - RTSPReply(q, a, "200 OK"); - stopparsing = true; - } - - -}//ParseRTSPPacket