apps/astreamer/rtsp.cpp

Go to the documentation of this file.
00001 #include "rtsp.h"
00002 #include "helpers.h"
00003 
00004 #include <string.h>
00005 #include <vector>
00006 
00007 using namespace std;
00008 
00009 #undef RTSP_DEBUG
00010 //#define RTSP_DEBUG
00011 
00012 #ifdef RTSP_DEBUG
00013         #define D(a) a
00014 #else
00015         #define D(a)
00016 #endif
00017 
00018 #define RTSP_PORT       "554"
00019 #define RTSP_SIGN       "rtsp://"
00020 
00021 // TODO
00022 _Request::_Request(const string &request) {
00023         string s;
00024         int prev = 0;
00025         int i = 0;
00026         int l = request.length();
00027         const char *c = request.c_str();
00028         bool first = true;
00029         string name, value;
00030 
00031         while(i < l) {
00032                 s = "";
00033                 for(; c[i] != '\n' && c[i] != '\r' && c[i] != '\0'; i++);
00034                 if(c[i] == '\n' || c[i] == '\r') {
00035                         if(i == prev) {
00036                                 i++;
00037                                 prev = i;
00038                                 continue;
00039                         }
00040                         s.insert(0, request, prev, i - prev);
00041 //                      cerr << "prev == " << prev << "; i == " << i << ";--> " << "\trequest string: \"" << s << "\"" << endl;
00042                         if(first) {
00043                                 int x = s.find(" ");
00044                                 method.insert(0, s, 0, x);
00045                                 int y = s.find(" ", x + 1);
00046                                 uri.insert(0, s, x + 1, y - x - 1);
00047 //                              cerr  << "method == |" << method << "|; uri == |" << uri << "|" << endl;
00048                                 first = false;
00049                         } else {
00050                                 name = "";
00051                                 value = "";
00052                                 int x = s.find(": ");
00053                                 name.insert(0, s, 0, x);
00054                                 value.insert(0, s, x + 2, s.length() - x - 1);
00055                                 fields[name] = value;
00056 //                              cerr << "pair: name == |" << name << "|; value == |" << value << "|" << endl;
00057                         }
00058                 }
00059                 if(c[i] == '\0')
00060                         break;
00061                 i++;
00062                 prev = i;
00063         }
00064 }
00065 
00066 void _Responce::add_field(const string &name, const string &value) {
00067         fields[name] = value;
00068 }
00069 
00070 void _Responce::add_include(const string &_include) {
00071         include = _include;
00072 }
00073 
00074 string _Responce::serialize() {
00075         string rez;
00076         switch(_status) {
00077         case STATUS_OK:
00078                 rez = "RTSP/1.0 200 OK\r\n";
00079                 break;
00080         case STATUS_BUSY:
00081                 rez = "RTSP/1.0 455 Server is busy\r\n";
00082                 break;
00083         case STATUS_EMPTY:
00084                 rez = "";
00085                 return rez;
00086         }
00087         for(map<string, string>::iterator it = fields.begin(); it != fields.end(); it++) {
00088                 rez += (*it).first + ": " + (*it).second + "\r\n";
00089         }
00090         rez += "\r\n";
00091         if(include.length() != 0) {
00092                 rez += include;
00093         }
00094         return rez;
00095 }
00096 
00097 RTSP_Server::RTSP_Server(void (*h)(void *, RTSP_Server *, RTSP_Server::event), void *handler_data, Session *_session) {
00098         handler_f = h;
00099         this->handler_data = handler_data;
00100         session = _session;
00101         _busy = NULL;
00102 }
00103 
00104 void RTSP_Server::main(void) {
00105         list <Socket *> s;
00106         // create listen socket...
00107 
00108         Socket *socket_main = new Socket("", 554);
00109 //      Socket *socket_1 = new Socket("", 554);
00110 //      Socket *socket_2 = new Socket("", 8554);
00111 //      Socket *socket_3 = new Socket("", 7070);
00112         s.push_back(socket_main);
00113         socket_main->listen(2);
00114 
00115         while(1) {
00116 //              int p = Socket::poll(s);
00117                 Socket::poll(s);
00118 D(cerr << "incoming..." << endl;)
00119 refresh:
00120 D(cerr << "refresh..." << endl;)
00121                 for(list<Socket *>::iterator it = s.begin(); it != s.end(); it++) {
00122                         Socket::state state = (*it)->state_refresh();
00123                         if(state == Socket::STATE_IN) {
00124                                 if(*it == socket_main) {
00125                                         Socket *in = socket_main->accept();
00126                                         if(in)
00127                                                 s.push_back(in);
00128                                 } else {
00129                                         // check for remove closed socket !
00130                                         if(!process(*it)) {
00131                                                 s.remove(*it);
00132                                                 goto refresh;
00133                                         }
00134                                 }
00135                         }
00136                 }
00137         }
00138 }
00139 
00140 bool RTSP_Server::process(Socket *s) {
00141         string req;
00142         _Request *request;
00143         _Responce *responce = NULL;
00144         bool r = true;
00145         _Responce::status status = _Responce::STATUS_EMPTY;
00146 
00147 //      cerr << "process()..." << endl;
00148 //      int err = s->recv(req);
00149         if(!s->recv(req))
00150                 return false;
00151         if(req == "") {
00152 D(cerr << "request is empty, close client..." << endl;)
00153                 return false;
00154         }
00155         if(!session->rtp_out.multicast) {
00156                 if(req == "") { // socket has closed - close stream.
00157                         if(_busy == s) {
00158                                 handler(TEARDOWN);
00159                                 _busy = NULL;
00160                         }
00161                         return false;
00162 D( cerr << "--==-->> reset _busy !!! <<--==--" << endl;)
00163                 }
00164         }
00165 D(cerr << "part_REQUEST: " << endl << "\"" << req << "\"" << endl;)
00166         // check for partial request...
00167         part_of_request += req;
00168         req = part_of_request;
00169         const char *c = req.c_str();
00170         string end;
00171         int e = req.length();
00172         e -= 4;
00173         if(e <= 0)
00174                 e = 0;
00175         for(int i = req.length() - 1; i >= e; i--) {
00176                 end += c[i];
00177 //cerr << "..." << (int)c[i] << endl;
00178         }
00179         if(end.find("\n\n") != 0 && end.find("\n\r\n\r") != 0) {
00180 //cerr << "____________________" << endl << "|" << part_of_request << "|" << endl;
00181                 return true;
00182         } else
00183                 part_of_request = "";
00184         // process...
00185 //cerr << "process request !!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
00186 D(      cerr << "\tREQUEST: " << endl << "\"" << req << "\"" << endl;)
00187         request = new _Request(req);
00188 
00189         responce = new _Responce();
00190         responce->add_field("CSeq", (*request->get_fields().find("CSeq")).second);
00191 //      responce->add_field("CSeq", (*request->get_fields().find("CSeq")).second);
00192         if(request->get_method() == "OPTIONS") {
00193                 status = _Responce::STATUS_OK;
00194                 responce->add_field("Public", "DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
00195                 // check transport...
00196                 if(!session->rtp_out.multicast)
00197                         session->rtp_out.ip = s->source_ip();
00198         }
00199         if(request->get_method() == "DESCRIBE") {
00200                 if(session->rtp_out.multicast || !_busy) {
00201                         status = _Responce::STATUS_OK;
00202                         char buf[8];
00203                         string sdp = make_sdp(request->get_uri());
00204                         responce->add_field("Content-Type", "application/sdp");
00205                         sprintf(buf, "%d", (int)sdp.length());
00206                         responce->add_field("Content-Length", buf);
00207                         responce->add_include(sdp);
00208                 } else {
00209                         status = _Responce::STATUS_BUSY;
00210                 }
00211         }
00212         if(request->get_method() == "SETUP") {
00213                 if(session->rtp_out.multicast || !_busy) {
00214                         status = _Responce::STATUS_OK;
00215                         responce->add_field("Session", "47112344");
00216                         responce->add_field("Transport", make_transport((*request->get_fields().find("Transport")).second));
00217                 } else
00218                         status = _Responce::STATUS_BUSY;
00219         }
00220         if(request->get_method() == "TEARDOWN") {
00221                 status = _Responce::STATUS_OK;
00222                 handler(TEARDOWN);
00223                 _busy = NULL;
00224         }
00225         if(request->get_method() == "PLAY") {
00226 D(cerr << "--==-->> transport: " << session->rtp_out.multicast << "; _busy == " << (unsigned long)_busy << endl;)
00227                 if(session->rtp_out.multicast || !_busy) {
00228                         status = _Responce::STATUS_OK;
00229                         handler(PLAY);
00230                         if(!session->rtp_out.multicast)
00231                                 _busy = s;
00232                 } else
00233                         status = _Responce::STATUS_BUSY;
00234 D(cerr << "--==-->> transport: " << session->rtp_out.multicast << "; _busy == " << (unsigned long)_busy << endl;)
00235         }
00236         if(request->get_method() == "PAUSE") {
00237                 status = _Responce::STATUS_OK;
00238                 handler(PAUSE);
00239         }
00240         delete request;
00241         responce->set_status(status);
00242 D(              cerr << "\tRESPONCE: " << endl << "\"" << responce->serialize() << "\"" << endl;)
00243         r = s->send(responce->serialize());
00244         delete responce;
00245         return r;
00246 }
00247 
00248 string RTSP_Server::make_sdp(string uri) {
00249         char buf[256];
00250 
00251 D(cerr << "make SDP" << endl;)
00252         // make video description
00253         // m = - port + PAYLOAD
00254         string rez = "m=video ";
00255 D(cerr << "_____________________" << endl;)
00256 D(cerr << "_____________________" << endl;)
00257 D(cerr << "_____________________" << endl;)
00258         sprintf(buf, "%d", session->rtp_out.port_video);
00259         if(session->process_audio == false) {
00260 D(cerr << "+++++++++++++++++++++" << endl;)
00261                 if(session->rtp_out.multicast) {
00262                         rez += buf;
00263                 } else {
00264                         rez += "0";
00265                 }
00266         } else {
00267                 rez += buf;
00268         }
00269         rez += " RTP/AVP ";
00270         sprintf(buf, "%d", session->video.type);
00271         rez += buf;
00272         rez += "\r\n";  // port
00273         if(session->rtp_out.multicast) {
00274                 rez += "a=type:multicast\r\n";
00275                 rez += "c=IN IP4 " + session->rtp_out.ip + "/" + session->rtp_out.ttl + "\r\n"; // IP + TTL
00276         } else {
00277                 rez += "a=type:unicast\r\n";
00278                 rez += "c=IN IP4 0.0.0.0\r\n";  // IP + TTL
00279         }
00280         sprintf(buf, "%.4f", session->video.fps);
00281         rez += "a=framerate:";
00282         rez += buf;
00283         rez += "\r\na=x-framerate:";
00284         rez += buf;
00285         if(session->video.width > 0) {
00286                 sprintf(buf, "%d", session->video.width);
00287                 rez += "\r\na=width:";
00288                 rez += buf;
00289                 rez += "\r\na=x-width:";
00290                 rez += buf;
00291         }
00292         if(session->video.height > 0) {
00293                 sprintf(buf, "%d", session->video.height);
00294                 rez += "\r\na=height:";
00295                 rez += buf;
00296                 rez += "\r\na=x-height:";
00297                 rez += buf;
00298         }
00299         if(session->video.width > 0 && session->video.height > 0) {
00300                 sprintf(buf, "%d,%d", session->video.width, session->video.height);
00301                 rez += "\r\na=x-dimensions:";
00302                 rez += buf;
00303         }
00304 
00305         rez += "\r\n";
00306         // make audio description, if present
00307         if(session->process_audio) {
00308 //              sprintf(buf, "m=audio %d RTP/AVP %d\r\n", atoi(session->rtp_out.port.c_str()) + 2, session->audio.type);
00309                 sprintf(buf, "m=audio %d RTP/AVP %d\r\n", session->rtp_out.port_audio, session->audio.type);
00310                 rez += buf;
00311                 sprintf(buf, "a=rtpmap:%d L16/%d/%d\r\n", session->audio.type, session->audio.sample_rate, session->audio.channels);
00312                 rez += buf;
00313         }
00314         rez += "a=control:" + uri + "\r\n";
00315 D(cerr << "make SDP - ok!" << endl;)
00316         return rez;
00317 }
00318 
00319 string RTSP_Server::make_transport(string req) {
00320         map<string, string> m = String::split_list_to_map(String::split_to_list(req, ';'), '=');
00321         string client_port = m["client_port"];
00322         int port_req = session->rtp_out.port_video;
00323 //D(cerr << "client_port == " << client_port << endl;)
00324         if(client_port != "") {
00325                 string first, second;
00326                 String::split(client_port, '-', first, second);
00327                 port_req = atol(first.c_str());
00328 //D(cerr << "client_port == |" << client_port << "|; first == |" << first << "|; second == |" << "|" << endl;)
00329 //              session->rtp_out.port = first;
00330         }
00331 
00332         if(!session->rtp_out.multicast) {
00333                 if(!session->process_audio) {
00334                         session->rtp_out.port_video = port_req;
00335                 }
00336         }
00337 
00338         string rez = "RTP/AVP;";
00339         if(session->rtp_out.multicast)
00340                 rez += "multicast;";
00341         else
00342                 rez += "unicast;";
00343         char buf[128];
00344         sprintf(buf, "%d", port_req);
00345         rez += "destination=" + session->rtp_out.ip + ";port=" + buf;
00346         if(session->process_audio) {
00347                 sprintf(buf, "-%d", port_req + 1);
00348 //              rez += "-";
00349 //              long p = atol(session->rtp_out.port.c_str());
00350 //              p++;
00351 //              sprintf(buf, "%d", p);
00352                 rez += buf;
00353         }
00354         if(session->rtp_out.multicast)
00355                 rez += ";ttl=" + session->rtp_out.ttl;
00356 //      rez += "destination=" + transport.ip + ";port=" + transport.port;
00357 //      if(transport.multicast)
00358 //              rez += ";ttl=" + transport.ttl;
00359         return rez;
00360 
00361 /*
00362         if(!session->rtp_out.multicast) {
00363                 if(!session->process_audio) {
00364                         if(session->rtp_out)
00365                 }
00366         }
00367 */
00368 /*
00369 D(      cerr << "transport request: |" << req << "|" << endl;)
00370         if(!session->rtp_out.multicast) {
00371                 // unicast
00372                 map<string, string> m = String::split_list_to_map(String::split_to_list(req, ';'), '=');
00373                 string client_port = m["client_port"];
00374 D(cerr << "client_port == " << client_port << endl;)
00375                 if(client_port != "") {
00376                         string first, second;
00377                         String::split(client_port, '-', first, second);
00378 D(cerr << "client_port == |" << client_port << "|; first == |" << first << "|; second == |" << "|" << endl;)
00379                         session->rtp_out.port = first;
00380                 }
00381         }
00382 
00383         string rez = "RTP/AVP;";
00384         if(session->rtp_out.multicast)
00385                 rez += "multicast;";
00386         else
00387                 rez += "unicast;";
00388         rez += "destination=" + session->rtp_out.ip + ";port=" + session->rtp_out.port;
00389         if(session->process_audio) {
00390                 rez += "-";
00391                 long p = atol(session->rtp_out.port.c_str());
00392                 p++;
00393                 char buf[128];
00394                 sprintf(buf, "%d", p);
00395                 rez += buf;
00396         }
00397         if(session->rtp_out.multicast)
00398                 rez += ";ttl=" + session->rtp_out.ttl;
00399 //      rez += "destination=" + transport.ip + ";port=" + transport.port;
00400 //      if(transport.multicast)
00401 //              rez += ";ttl=" + transport.ttl;
00402         return rez;
00403 */
00404 }
00405 
00406 RTSP_Server::~RTSP_Server() {
00407 //      cerr << "destroy RTSP_Server object" << endl;
00408 //      delete socket;
00409 }
00410 

Generated on Thu Aug 7 16:18:58 2008 for elphel by  doxygen 1.5.1