Пример #1
0
//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;
}
Пример #2
0
//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
M4Err RTSP_SendRequest(RTSPSession *sess, RTSPCommand *com)
{
	M4Err e;
	char *rad, *sCtrl;
	u32 size;
	char buffer[1024], *result, *body;

	if (!com || !com->method) return M4BadParam;

	sCtrl = com->ControlString;

	//NB: OPTIONS is not sent this way
	if (strcmp(com->method, RTSP_DESCRIBE)
		&& strcmp(com->method, RTSP_ANNOUNCE)
		&& strcmp(com->method, RTSP_GET_PARAMETER)
		&& strcmp(com->method, RTSP_SET_PARAMETER)
		&& strcmp(com->method, RTSP_SETUP)
		&& strcmp(com->method, RTSP_PLAY)
		&& strcmp(com->method, RTSP_PAUSE)
		&& strcmp(com->method, RTSP_RECORD)
		&& strcmp(com->method, RTSP_REDIRECT)
		&& strcmp(com->method, RTSP_TEARDOWN)
		&& strcmp(com->method, RTSP_OPTIONS)

		) return M4BadParam;

	//check the state machine
	if (strcmp(com->method, RTSP_PLAY) 
		&& strcmp(com->method, RTSP_PAUSE) 
		&& strcmp(com->method, RTSP_RECORD)
		&& sess->RTSP_State != RSM_Init) 
		return M4ServiceError;

	//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 == RSM_WaitForControl 
		&& strcmp(com->method, sess->RTSPLastRequest))
		&& strcmp(com->method, RTSP_OPTIONS))

		return M4BadParam;
*/

	//OPTIONS must have a parameter string 
	if (!strcmp(com->method, RTSP_OPTIONS) && !sCtrl) return M4BadParam;


	//update sequence number
	sess->CSeq += 1;
	sess->NbPending += 1;

	if (!strcmp(com->method, RTSP_OPTIONS)) {
		sprintf(buffer, "OPTIONS %s %s\r\n", sCtrl, RTSP_VERSION);
	} else {
		rad = (sess->ConnectionType == SK_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, 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, 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, RTSP_VERSION);
//				sprintf(buffer, "%s %s://%s:%d/%s/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sess->Service, sCtrl, RTSP_VERSION);
			}
		} else {
			sprintf(buffer, "%s %s://%s:%d/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sess->Service, RTSP_VERSION);
		}
	}

	//Body on ANNOUNCE, GET_PARAMETER, SET_PARAMETER ONLY
	body = NULL;
	if (strcmp(com->method, RTSP_ANNOUNCE) 
		&& strcmp(com->method, RTSP_GET_PARAMETER) 
		&& strcmp(com->method, 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, buffer, (unsigned char **) &result, &size);
	//restore body if needed
	if (body) com->body = body;
	if (e) goto exit;


	//send buffer
	e = RTSP_Send(sess, result, size);
	if (e) goto exit;


	if (sess->rtsp_log) fprintf(sess->rtsp_log, "\n/*RTSP Send Command*/\n\n%s\n", result);

	//update our state
	if (!strcmp(com->method, RTSP_RECORD)) sess->RTSP_State = RSM_WaitForControl;
	else if (!strcmp(com->method, RTSP_PLAY)) sess->RTSP_State = RSM_WaitForControl;
	else if (!strcmp(com->method, RTSP_PAUSE)) sess->RTSP_State = RSM_WaitForControl;
	else sess->RTSP_State = RSM_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;
}