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 RTSP_Server::RTSP_Server(int (*h)(void *, RTSP_Server *, RTSP_Server::event), void *handler_data, Session *_session) {
00099         handler_f = h;
00100         this->handler_data = handler_data;
00101         session = _session;
00102         _busy = NULL;
00103 }
00104 
00105 void RTSP_Server::main(void) {
00106         list <Socket *> s;
00107         // create listen socket...
00108 
00109         Socket *socket_main = new Socket("", 554);
00110 //      Socket *socket_1 = new Socket("", 554);
00111 //      Socket *socket_2 = new Socket("", 8554);
00112 //      Socket *socket_3 = new Socket("", 7070);
00113         s.push_back(socket_main);
00114         socket_main->listen(2);
00115 
00116         while(1) {
00117 //              int p = Socket::poll(s);
00118                 Socket::poll(s);
00119 D(cerr << "incoming..." << endl;)
00120 refresh:
00121 D(cerr << "refresh..." << endl;)
00122                 for(list<Socket *>::iterator it = s.begin(); it != s.end(); it++) {
00123                         Socket::state state = (*it)->state_refresh();
00124                         if(state == Socket::STATE_IN) {
00125                                 if(*it == socket_main) {
00126                                         Socket *in = socket_main->accept();
00127                                         if(in)
00128                                                 s.push_back(in);
00129                                 } else {
00130                                         // check for remove closed socket !
00131                                         if(!process(*it)) {
00132                                                 s.remove(*it);
00133                                                 goto refresh;
00134                                         }
00135                                 }
00136                         }
00137                 }
00138         }
00139 }
00140 
00141 bool RTSP_Server::process(Socket *s) {
00142 
00143         string req;
00144         _Request *request;
00145         _Responce *responce = NULL;
00146         bool r = true;
00147         _Responce::status status = _Responce::STATUS_EMPTY;
00148 
00149 //      cerr << "process()..." << endl;
00150 //      int err = s->recv(req);
00151         if(!s->recv(req))
00152                 return false;
00153         if(req == "") {
00154 D(cerr << "request is empty, close client..." << endl;)
00155                 return false;
00156         }
00157         if(!session->rtp_out.multicast) {
00158                 if(req == "") { // socket has closed - close stream.
00159                         if(_busy == s) {
00160                                 handler(TEARDOWN);
00161                                 _busy = NULL;
00162                         }
00163                         return false;
00164 D( cerr << "--==-->> reset _busy !!! <<--==--" << endl;)
00165                 }
00166         }
00167 D(cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " part_REQUEST: " << endl << "\"" << req << "\"" << endl;)
00168         // check for partial request...
00169         part_of_request += req;
00170         req = part_of_request;
00171         const char *c = req.c_str();
00172         string end;
00173         int e = req.length();
00174         e -= 4;
00175         if(e <= 0)
00176                 e = 0;
00177         for(int i = req.length() - 1; i >= e; i--) {
00178                 end += c[i];
00179 //cerr << "..." << (int)c[i] << endl;
00180         }
00181         if(end.find("\n\n") != 0 && end.find("\n\r\n\r") != 0) {
00182 //cerr << "____________________" << endl << "|" << part_of_request << "|" << endl;
00183                 return true;
00184         } else
00185                 part_of_request = "";
00186         // process...
00187 //cerr << "process request !!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
00188 D(      cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << "\tREQUEST: " << endl << "\"" << req << "\"" << endl;)
00189         request = new _Request(req);
00190 
00191         responce = new _Responce();
00192         responce->add_field("CSeq", (*request->get_fields().find("CSeq")).second);
00193 //      responce->add_field("CSeq", (*request->get_fields().find("CSeq")).second);
00194         if(request->get_method() == "OPTIONS") {
00195                if (handler(IS_DAEMON_ENABLED)) {
00196                     status = _Responce::STATUS_OK;
00197                     responce->add_field("Public", "DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
00198                 // check transport...
00199                     if(!session->rtp_out.multicast)
00200                         session->rtp_out.ip = s->source_ip();
00201                } else {
00202                         status = _Responce::STATUS_BUSY;
00203                }
00204         }
00205         if(request->get_method() == "DESCRIBE") {
00206                 if(handler(IS_DAEMON_ENABLED)  && (session->rtp_out.multicast || !_busy)) {
00207                         handler(DESCRIBE); 
00208                         status = _Responce::STATUS_OK;
00209                         char buf[8];
00210                         string sdp = make_sdp(request->get_uri());
00211                         responce->add_field("Content-Type", "application/sdp");
00212                         sprintf(buf, "%d", (int)sdp.length());
00213                         responce->add_field("Content-Length", buf);
00214                         responce->add_include(sdp);
00215                 } else {
00216                         status = _Responce::STATUS_BUSY;
00217                 }
00218         }
00219         if(request->get_method() == "SETUP") {
00220                 if (handler(IS_DAEMON_ENABLED)  && (session->rtp_out.multicast || !_busy)) {
00221                         status = _Responce::STATUS_OK;
00222                         responce->add_field("Session", "47112344");
00223                         responce->add_field("Transport", make_transport((*request->get_fields().find("Transport")).second));
00224                 } else
00225                         status = _Responce::STATUS_BUSY;
00226         }
00227         if(request->get_method() == "TEARDOWN") {
00228                 status = _Responce::STATUS_OK;
00229                 handler(TEARDOWN);
00230                 _busy = NULL;
00231         }
00232         if(request->get_method() == "PLAY") {
00233 D(cerr << "--==-->> transport: " << session->rtp_out.multicast << "; _busy == " << (unsigned long)_busy << endl;)
00234 //              if(session->rtp_out.multicast || !_busy) {
00235                 if (handler(IS_DAEMON_ENABLED) && (session->rtp_out.multicast || !_busy)) {
00236                         status = _Responce::STATUS_OK;
00237                         handler(PLAY);
00238                         if(!session->rtp_out.multicast)
00239                                 _busy = s;
00240                 } else
00241                         status = _Responce::STATUS_BUSY;
00242 D(cerr << "--==-->> transport: " << session->rtp_out.multicast << "; _busy == " << (unsigned long)_busy << " status=" << status << endl;)
00243         }
00244         if(request->get_method() == "PAUSE") {
00245                 status = _Responce::STATUS_OK;
00246                 handler(PAUSE);
00247         }
00248         delete request;
00249         responce->set_status(status);
00250 D(              cerr << "\tRESPONSE: " << endl << "\"" << responce->serialize() << "\"" << endl;)
00251         r = s->send(responce->serialize());
00252         delete responce;
00253         return r;
00254 }
00255 
00256 string RTSP_Server::make_sdp(string uri) {
00257         char buf[256];
00258 
00259 D(cerr << "make SDP" << endl;)
00260         // make video description
00261         // m = - port + PAYLOAD
00262         string rez = "m=video ";
00263 D(cerr << "_____________________" << endl;)
00264 D(cerr << "_____________________" << endl;)
00265 D(cerr << "_____________________" << endl;)
00266         sprintf(buf, "%d", session->rtp_out.port_video);
00267         if(session->process_audio == false) {
00268 D(cerr << "+++++++++++++++++++++" << endl;)
00269                 if(session->rtp_out.multicast) {
00270                         rez += buf;
00271                 } else {
00272                         rez += "0";
00273                 }
00274         } else {
00275                 rez += buf;
00276         }
00277         rez += " RTP/AVP ";
00278         sprintf(buf, "%d", session->video.type);
00279         rez += buf;
00280         rez += "\r\n";  // port
00281         if(session->rtp_out.multicast) {
00282                 rez += "a=type:multicast\r\n";
00283                 rez += "c=IN IP4 " + session->rtp_out.ip + "/" + session->rtp_out.ttl + "\r\n"; // IP + TTL
00284         } else {
00285                 rez += "a=type:unicast\r\n";
00286                 rez += "c=IN IP4 0.0.0.0\r\n";  // IP + TTL
00287         }
00288         sprintf(buf, "%.4f", session->video.fps);
00289         rez += "a=framerate:";
00290         rez += buf;
00291         rez += "\r\na=x-framerate:";
00292         rez += buf;
00293         if(session->video.width > 0) {
00294                 sprintf(buf, "%d", session->video.width);
00295                 rez += "\r\na=width:";
00296                 rez += buf;
00297                 rez += "\r\na=x-width:";
00298                 rez += buf;
00299         }
00300         if(session->video.height > 0) {
00301                 sprintf(buf, "%d", session->video.height);
00302                 rez += "\r\na=height:";
00303                 rez += buf;
00304                 rez += "\r\na=x-height:";
00305                 rez += buf;
00306         }
00307         if(session->video.width > 0 && session->video.height > 0) {
00308                 sprintf(buf, "%d,%d", session->video.width, session->video.height);
00309                 rez += "\r\na=x-dimensions:";
00310                 rez += buf;
00311         }
00312 
00313         rez += "\r\n";
00314         // make audio description, if present
00315         if(session->process_audio) {
00316 //              sprintf(buf, "m=audio %d RTP/AVP %d\r\n", atoi(session->rtp_out.port.c_str()) + 2, session->audio.type);
00317                 sprintf(buf, "m=audio %d RTP/AVP %d\r\n", session->rtp_out.port_audio, session->audio.type);
00318                 rez += buf;
00319                 sprintf(buf, "a=rtpmap:%d L16/%d/%d\r\n", session->audio.type, session->audio.sample_rate, session->audio.channels);
00320                 rez += buf;
00321         }
00322         rez += "a=control:" + uri + "\r\n";
00323 D(cerr << "make SDP - ok!" << endl;)
00324         return rez;
00325 }
00326 
00327 string RTSP_Server::make_transport(string req) {
00328         map<string, string> m = String::split_list_to_map(String::split_to_list(req, ';'), '=');
00329         string client_port = m["client_port"];
00330         int port_req = session->rtp_out.port_video;
00331 //D(cerr << "client_port == " << client_port << endl;)
00332         if(client_port != "") {
00333                 string first, second;
00334                 String::split(client_port, '-', first, second);
00335                 port_req = atol(first.c_str());
00336 //D(cerr << "client_port == |" << client_port << "|; first == |" << first << "|; second == |" << "|" << endl;)
00337 //              session->rtp_out.port = first;
00338         }
00339 
00340         if(!session->rtp_out.multicast) {
00341                 if(!session->process_audio) {
00342                         session->rtp_out.port_video = port_req;
00343                 }
00344         }
00345 
00346         string rez = "RTP/AVP;";
00347         if(session->rtp_out.multicast)
00348                 rez += "multicast;";
00349         else
00350                 rez += "unicast;";
00351         char buf[128];
00352         sprintf(buf, "%d", port_req);
00353         rez += "destination=" + session->rtp_out.ip + ";port=" + buf;
00354         if(session->process_audio) {
00355                 sprintf(buf, "-%d", port_req + 1);
00356 //              rez += "-";
00357 //              long p = atol(session->rtp_out.port.c_str());
00358 //              p++;
00359 //              sprintf(buf, "%d", p);
00360                 rez += buf;
00361         }
00362         if(session->rtp_out.multicast)
00363                 rez += ";ttl=" + session->rtp_out.ttl;
00364 //      rez += "destination=" + transport.ip + ";port=" + transport.port;
00365 //      if(transport.multicast)
00366 //              rez += ";ttl=" + transport.ttl;
00367         return rez;
00368 
00369 /*
00370         if(!session->rtp_out.multicast) {
00371                 if(!session->process_audio) {
00372                         if(session->rtp_out)
00373                 }
00374         }
00375 */
00376 /*
00377 D(      cerr << "transport request: |" << req << "|" << endl;)
00378         if(!session->rtp_out.multicast) {
00379                 // unicast
00380                 map<string, string> m = String::split_list_to_map(String::split_to_list(req, ';'), '=');
00381                 string client_port = m["client_port"];
00382 D(cerr << "client_port == " << client_port << endl;)
00383                 if(client_port != "") {
00384                         string first, second;
00385                         String::split(client_port, '-', first, second);
00386 D(cerr << "client_port == |" << client_port << "|; first == |" << first << "|; second == |" << "|" << endl;)
00387                         session->rtp_out.port = first;
00388                 }
00389         }
00390 
00391         string rez = "RTP/AVP;";
00392         if(session->rtp_out.multicast)
00393                 rez += "multicast;";
00394         else
00395                 rez += "unicast;";
00396         rez += "destination=" + session->rtp_out.ip + ";port=" + session->rtp_out.port;
00397         if(session->process_audio) {
00398                 rez += "-";
00399                 long p = atol(session->rtp_out.port.c_str());
00400                 p++;
00401                 char buf[128];
00402                 sprintf(buf, "%d", p);
00403                 rez += buf;
00404         }
00405         if(session->rtp_out.multicast)
00406                 rez += ";ttl=" + session->rtp_out.ttl;
00407 //      rez += "destination=" + transport.ip + ";port=" + transport.port;
00408 //      if(transport.multicast)
00409 //              rez += ";ttl=" + transport.ttl;
00410         return rez;
00411 */
00412 }
00413 
00414 RTSP_Server::~RTSP_Server() {
00415         cerr << "destroy RTSP_Server object" << endl;
00416 //      delete socket_main;
00417 //      if (request)  delete request;
00418 //      if (responce) delete responce;
00419 }
00420 

Generated on Fri Nov 28 00:06:21 2008 for elphel by  doxygen 1.5.1