GF_EXPORT GF_Err gf_rtsp_send_response(GF_RTSPSession *sess, GF_RTSPResponse *rsp) { u32 size; char *buffer; GF_Err e; if (!sess || !rsp || !rsp->CSeq) return GF_BAD_PARAM; //check we're not sending something greater than the current CSeq if (rsp->CSeq > sess->CSeq) return GF_BAD_PARAM; e = RTSP_WriteResponse(sess, rsp, (unsigned char **) &buffer, &size); if (e) goto exit; //send buffer e = gf_rtsp_send_data(sess, buffer, size); if (e) return e; // fprintf(stderr, "RTSP Send Response\n\n%s\n\n", buffer); exit: if (buffer) gf_free(buffer); return e; }
//format a DESCRIBE, SETUP, PLAY or PAUSE on a session //YOUR COMMAND MUST BE FORMATTED ACCORDINGLY //sCtrl contains a control string if needed, formating the REQUEST as server_url/service_name/sCtrl GF_EXPORT GF_Err gf_rtsp_send_command(GF_RTSPSession *sess, GF_RTSPCommand *com) { GF_Err e; char *sCtrl; const char *rad; u32 size; char buffer[1024], *result, *body; if (!com || !com->method) return GF_BAD_PARAM; sCtrl = com->ControlString; //NB: OPTIONS is not sent this way if (strcmp(com->method, GF_RTSP_DESCRIBE) && strcmp(com->method, GF_RTSP_ANNOUNCE) && strcmp(com->method, GF_RTSP_GET_PARAMETER) && strcmp(com->method, GF_RTSP_SET_PARAMETER) && strcmp(com->method, GF_RTSP_SETUP) && strcmp(com->method, GF_RTSP_PLAY) && strcmp(com->method, GF_RTSP_PAUSE) && strcmp(com->method, GF_RTSP_RECORD) && strcmp(com->method, GF_RTSP_REDIRECTE) && 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) gf_free(result); return e; }