📄 rtsp_command.c
字号:
&& strcmp(com->method, GF_RTSP_TEARDOWN) && strcmp(com->method, GF_RTSP_OPTIONS) ) return GF_BAD_PARAM; //check the state machine if (strcmp(com->method, GF_RTSP_PLAY) && strcmp(com->method, GF_RTSP_PAUSE) && strcmp(com->method, GF_RTSP_RECORD) && sess->RTSP_State != GF_RTSP_STATE_INIT) return GF_SERVICE_ERROR; //aggregation is ONLY for the same request - unclear in RFC2326 ... //it is often mentioned "queued requests" at the server, like 3 PLAYS //and a PAUSE .... /* else if (sess->RTSP_State == GF_RTSP_STATE_WAIT_FOR_CONTROL && strcmp(com->method, sess->RTSPLastRequest)) && strcmp(com->method, GF_RTSP_OPTIONS)) return GF_BAD_PARAM;*/ //OPTIONS must have a parameter string if (!strcmp(com->method, GF_RTSP_OPTIONS) && !sCtrl) return GF_BAD_PARAM; //update sequence number sess->CSeq += 1; sess->NbPending += 1; if (!strcmp(com->method, GF_RTSP_OPTIONS)) { sprintf(buffer, "OPTIONS %s %s\r\n", sCtrl, GF_RTSP_VERSION); } else { rad = (sess->ConnectionType == GF_SOCK_TYPE_TCP) ? "rtsp" : "rtspu"; if (sCtrl) { //if both server and service names are included in the control, just //use the control if (strstr(sCtrl, sess->Server) && strstr(sCtrl, sess->Service)) { sprintf(buffer, "%s %s %s\r\n", com->method, sCtrl, GF_RTSP_VERSION); } //if service is specified in ctrl, do not rewrite it else if (strstr(sCtrl, sess->Service)) { sprintf(buffer, "%s %s://%s:%d/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sCtrl, GF_RTSP_VERSION); } else if (!strnicmp(sCtrl, "rtsp", 4)) { sprintf(buffer, "%s %s %s\r\n", com->method, sCtrl, GF_RTSP_VERSION); } //otherwise rewrite full URL else { sprintf(buffer, "%s %s://%s/%s/%s %s\r\n", com->method, rad, sess->Server, sess->Service, sCtrl, GF_RTSP_VERSION);// sprintf(buffer, "%s %s://%s:%d/%s/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sess->Service, sCtrl, GF_RTSP_VERSION); } } else { sprintf(buffer, "%s %s://%s:%d/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sess->Service, GF_RTSP_VERSION); } } //Body on ANNOUNCE, GET_PARAMETER, SET_PARAMETER ONLY body = NULL; if (strcmp(com->method, GF_RTSP_ANNOUNCE) && strcmp(com->method, GF_RTSP_GET_PARAMETER) && strcmp(com->method, GF_RTSP_SET_PARAMETER) ) { //this is an error, but don't say anything if (com->body) { body = com->body; com->body = NULL; } } result = NULL; e = RTSP_WriteCommand(sess, com, (unsigned char *)buffer, (unsigned char **) &result, &size); //restore body if needed if (body) com->body = body; if (e) goto exit; GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSP] Sending Command:\n%s\n", result)); //send buffer e = gf_rtsp_send_data(sess, result, size); if (e) goto exit; //update our state if (!strcmp(com->method, GF_RTSP_RECORD)) sess->RTSP_State = GF_RTSP_STATE_WAIT_FOR_CONTROL; else if (!strcmp(com->method, GF_RTSP_PLAY)) sess->RTSP_State = GF_RTSP_STATE_WAIT_FOR_CONTROL; else if (!strcmp(com->method, GF_RTSP_PAUSE)) sess->RTSP_State = GF_RTSP_STATE_WAIT_FOR_CONTROL; else sess->RTSP_State = GF_RTSP_STATE_WAITING; //teardown invalidates the session most of the time, so we force the user to wait for the reply //as the reply may indicate a connection-closed strcpy(sess->RTSPLastRequest, com->method);exit: if (result) free(result); return e;}void gf_rtsp_set_command_value(GF_RTSPCommand *com, char *Header, char *Value){ char LineBuffer[400]; s32 LinePos; GF_RTSPTransport *trans; GF_X_Attribute *x_Att; if (!stricmp(Header, "Accept")) com->Accept = strdup(Value); else if (!stricmp(Header, "Accept-Encoding")) com->Accept_Encoding = strdup(Value); else if (!stricmp(Header, "Accept-Language")) com->Accept_Language = strdup(Value); else if (!stricmp(Header, "Authorization")) com->Authorization = strdup(Value); else if (!stricmp(Header, "Bandwidth")) sscanf(Value, "%d", &com->Bandwidth); else if (!stricmp(Header, "Blocksize")) sscanf(Value, "%d", &com->Blocksize); else if (!stricmp(Header, "Cache-Control")) com->Cache_Control = strdup(Value); else if (!stricmp(Header, "Conference")) com->Conference = strdup(Value); else if (!stricmp(Header, "Connection")) com->Connection = strdup(Value); else if (!stricmp(Header, "Content-Length")) sscanf(Value, "%d", &com->Content_Length); else if (!stricmp(Header, "CSeq")) sscanf(Value, "%d", &com->CSeq); else if (!stricmp(Header, "From")) com->From = strdup(Value); else if (!stricmp(Header, "Proxy_Authorization")) com->Proxy_Authorization = strdup(Value); else if (!stricmp(Header, "Proxy_Require")) com->Proxy_Require = strdup(Value); else if (!stricmp(Header, "Range")) com->Range = gf_rtsp_range_parse(Value); else if (!stricmp(Header, "Referer")) com->Referer = strdup(Value); else if (!stricmp(Header, "Scale")) sscanf(Value, "%lf", &com->Scale); else if (!stricmp(Header, "Session")) com->Session = strdup(Value); else if (!stricmp(Header, "Speed")) sscanf(Value, "%lf", &com->Speed); else if (!stricmp(Header, "User_Agent")) com->User_Agent = strdup(Value); //Transports else if (!stricmp(Header, "Transport")) { LinePos = 0; while (1) { LinePos = gf_token_get(Value, LinePos, "\r\n", LineBuffer, 400); if (LinePos <= 0) return; trans = gf_rtsp_transport_parse(Value); if (trans) gf_list_add(com->Transports, trans); } } //eXtensions attributes else if (!strnicmp(Header, "x-", 2)) { x_Att = (GF_X_Attribute*)malloc(sizeof(GF_X_Attribute)); x_Att->Name = strdup(Header+2); x_Att->Value = NULL; if (Value && strlen(Value)) x_Att->Value = strdup(Value); gf_list_add(com->Xtensions, x_Att); } //the rest is ignored}GF_Err RTSP_ParseCommandHeader(GF_RTSPSession *sess, GF_RTSPCommand *com, u32 BodyStart){ char LineBuffer[1024]; char ValBuf[1024]; char *buffer; s32 Pos, ret; u32 Size; Size = sess->CurrentSize - sess->CurrentPos; buffer = sess->TCPBuffer + sess->CurrentPos; //by default the command is wrong ;) com->StatusCode = NC_RTSP_Bad_Request; //parse first line ret = gf_token_get_line(buffer, 0, Size, LineBuffer, 1024); if (ret < 0) return GF_REMOTE_SERVICE_ERROR; //method Pos = gf_token_get(LineBuffer, 0, " \t\r\n", ValBuf, 1024); if (Pos <= 0) return GF_OK; com->method = strdup((const char *) ValBuf); //URL Pos = gf_token_get(LineBuffer, Pos, " \t\r\n", ValBuf, 1024); if (Pos <= 0) return GF_OK; com->service_name = strdup(ValBuf); //RTSP version Pos = gf_token_get(LineBuffer, Pos, "\t\r\n", ValBuf, 1024); if (Pos <= 0) return GF_OK; if (strcmp(ValBuf, GF_RTSP_VERSION)) { com->StatusCode = NC_RTSP_RTSP_Version_Not_Supported; return GF_OK; } com->StatusCode = NC_RTSP_OK; return gf_rtsp_parse_header(buffer + ret, Size - ret, BodyStart, com, NULL);}GF_EXPORTGF_Err gf_rtsp_get_command(GF_RTSPSession *sess, GF_RTSPCommand *com){ GF_Err e; u32 BodyStart, size; if (!sess || !com) return GF_BAD_PARAM; //reset the command gf_rtsp_command_reset(com); //if no connection, we have sent a "Connection: Close" if (!sess->connection) return GF_IP_CONNECTION_CLOSED; //lock gf_mx_p(sess->mx); //fill TCP buffer e = gf_rtsp_fill_buffer(sess); if (e) goto exit; //this is upcoming, interleaved data if (strncmp(sess->TCPBuffer+sess->CurrentPos, "RTSP", 4)) { e = GF_IP_NETWORK_EMPTY; goto exit; } e = gf_rtsp_read_reply(sess); if (e) goto exit; gf_rtsp_get_body_info(sess, &BodyStart, &size); e = RTSP_ParseCommandHeader(sess, com, BodyStart); //before returning an error we MUST reset the TCP buffer //copy the body if any if (!e && com->Content_Length) { com->body = (char *) malloc(sizeof(char) * (com->Content_Length)); memcpy(com->body, sess->TCPBuffer+sess->CurrentPos + BodyStart, com->Content_Length); } //reset TCP buffer sess->CurrentPos += BodyStart + com->Content_Length; if (!com->CSeq) com->StatusCode = NC_RTSP_Bad_Request; if (e || (com->StatusCode != NC_RTSP_OK)) goto exit; //NB: there is no "session state" in our lib when acting at the server side, as it depends //on the server implementation. We cannot block responses / announcement to be sent //dynamically, nor reset the session ourselves as we don't know the details of the session //(eg TEARDOWN may keep resources up or not, ...) //we also have the same pb for CSeq, as nothing forbids a server to buffer commands (and it //happens during aggregation of PLAY/PAUSE with overlapping ranges) //however store the last CSeq in case for client checking if (!sess->CSeq) { sess->CSeq = com->CSeq; } //check we're in the right range else { if (sess->CSeq >= com->CSeq) com->StatusCode = NC_RTSP_Header_Field_Not_Valid; else sess->CSeq = com->CSeq; } // //if a connection closed is signal, check this is the good session // and reset it (the client is no longer connected) if (sess->last_session_id && com->Session && !strcmp(com->Session, sess->last_session_id) && com->Connection && !stricmp(com->Connection, "Close")) { gf_rtsp_session_reset(sess, 0); //destroy the socket if (sess->connection) gf_sk_del(sess->connection); sess->connection = NULL; //destroy the http tunnel if any if (sess->HasTunnel && sess->http) { gf_sk_del(sess->http); sess->http = NULL; } } exit: gf_mx_v(sess->mx); return e;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -