示例#1
0
/* Process incoming RTSP event (request) */
static apt_bool_t rtsp_client_session_event_process(rtsp_client_t *client, rtsp_client_connection_t *rtsp_connection, rtsp_message_t *message)
{
	rtsp_message_t *response = NULL;
	rtsp_client_session_t *session = NULL;
	if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) == TRUE) {
		/* find existing session */
		session = apr_hash_get(
					rtsp_connection->session_table,
					message->header.session_id.buf,
					message->header.session_id.length);
	}

	if(session) {
		response = rtsp_response_create(message,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,message->pool);
		if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) == TRUE) {
			response->header.session_id = message->header.session_id;
			rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
		}
		client->vtable->on_session_event(client,session,message);
	}
	else {
		response = rtsp_response_create(message,RTSP_STATUS_CODE_NOT_FOUND,RTSP_REASON_PHRASE_NOT_FOUND,message->pool);
	}

	return rtsp_client_message_send(client,rtsp_connection->base,response);
}
示例#2
0
static apt_bool_t rtsp_server_message_handler(rtsp_server_connection_t *rtsp_connection, rtsp_message_t *message, apt_message_status_e status)
{
	if(status == APT_MESSAGE_STATUS_COMPLETE) {
		/* message is completely parsed */
		apt_str_t *destination;
		destination = &message->header.transport.destination;
		if(!destination->buf && rtsp_connection->client_ip) {
			apt_string_assign(destination,rtsp_connection->client_ip,rtsp_connection->pool);
		}
		rtsp_server_session_request_process(rtsp_connection->server,rtsp_connection,message);
	}
	else if(status == APT_MESSAGE_STATUS_INVALID) {
		/* error case */
		rtsp_message_t *response;
		apt_log(RTSP_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse RTSP Data");
		if(message) {
			response = rtsp_response_create(message,RTSP_STATUS_CODE_BAD_REQUEST,
									RTSP_REASON_PHRASE_BAD_REQUEST,message->pool);
			if(rtsp_server_message_send(rtsp_connection->server,rtsp_connection,response) == FALSE) {
				apt_log(RTSP_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Response");
			}
		}
	}
	return TRUE;
}
示例#3
0
/* Finally terminate RTSP session */
static apt_bool_t rtsp_server_session_do_terminate(rtsp_server_t *server, rtsp_server_session_t *session)
{
	rtsp_server_connection_t *rtsp_connection = session->connection;

	if(session->active_request) {
		rtsp_message_t *response = rtsp_response_create(session->active_request,
			RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,session->active_request->pool);
		if(response) {
			if(session->id.buf) {
				response->header.session_id = session->id;
				rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_SESSION_ID,response->pool);
			}

			if(rtsp_connection) {
				rtsp_server_message_send(server,rtsp_connection,response);
			}
		}
	}

	apt_log(RTSP_LOG_MARK,APT_PRIO_INFO,"Remove RTSP Session " APT_SID_FMT,session->id.buf);
	if(rtsp_connection) {
		apr_hash_set(rtsp_connection->session_table,session->id.buf,session->id.length,NULL);
	}
	rtsp_server_session_destroy(session);

	if(rtsp_connection && !rtsp_connection->sock) {
		if(apr_hash_count(rtsp_connection->session_table) == 0) {
			rtsp_server_connection_destroy(rtsp_connection);
		}
	}
	return TRUE;
}
示例#4
0
/* Raise RTSP session terminate event */
static apt_bool_t rtsp_client_session_terminate_raise(rtsp_client_t *client, rtsp_client_session_t *session)
{
	rtsp_message_t *request;
	rtsp_message_t *response;

	/* cancel pending requests */
	do {
		request = apt_list_pop_front(session->pending_request_queue);
		if(request) {
			response = rtsp_response_create(
							session->active_request,
							RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
							RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
							session->pool);
			rtsp_client_session_response_process(client,session,request,response);
		}
	}
	while(request);

	
	if(session->term_state == TERMINATION_STATE_NONE) {
		client->vtable->on_session_terminate_event(client,session);
	}
	else {
		rtsp_client_session_terminate_respond(client,session);
	}
	return TRUE;
}
示例#5
0
/* Process pending RTSP requests */
static apt_bool_t rtsp_client_session_pending_requests_process(rtsp_client_t *client, rtsp_client_session_t *session)
{
	rtsp_message_t *request = apt_list_pop_front(session->pending_request_queue);
	if(!request) {
		/* pending queue is empty, no in-progress request */
		return FALSE;
	}

	/* process pending request; get the next one, if current is failed */
	do {
		rtsp_message_t *response;
		if(rtsp_client_session_request_process(client,session,request) == TRUE) {
			return TRUE;
		}
			
		/* respond with error */
		response = rtsp_response_create(
							request,
							RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
							RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
							session->pool);
		rtsp_client_session_response_process(client,session,request,response);
		
		/* process the next pending request / if any */
		request = apt_list_pop_front(session->pending_request_queue);
	}
	while(request);

	/* no in-progress request */
	return FALSE;
}
static apt_bool_t mrcp_unirtsp_on_session_answer(mrcp_session_t *mrcp_session, mrcp_session_descriptor_t *descriptor)
{
	mrcp_unirtsp_session_t *session = mrcp_session->obj;
	mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
	rtsp_message_t *response = NULL;
	const rtsp_message_t *request = rtsp_server_session_request_get(session->rtsp_session);
	if(!request) {
		return FALSE;
	}

	if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
		if(agent->config->origin) {
			apt_string_set(&descriptor->origin,agent->config->origin);
		}

		response = rtsp_response_generate_by_mrcp_descriptor(
						request,
						descriptor,
						agent->config->resource_map,
						mrcp_session->pool);
	}
	else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
		response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,mrcp_session->pool);
	}

	if(!response) {
		return FALSE;
	}
	rtsp_server_session_respond(agent->rtsp_server,session->rtsp_session,response);
	return TRUE;
}
static apt_bool_t mrcp_unirtsp_message_handle(rtsp_server_t *rtsp_server, rtsp_server_session_t *rtsp_session, rtsp_message_t *rtsp_message)
{
	apt_bool_t status = FALSE;
	mrcp_unirtsp_agent_t *agent = rtsp_server_object_get(rtsp_server);
	mrcp_unirtsp_session_t *session	= rtsp_server_session_object_get(rtsp_session);
	if(!session) {
		return FALSE;
	}

	switch(rtsp_message->start_line.common.request_line.method_id) {
		case RTSP_METHOD_SETUP:
		case RTSP_METHOD_TEARDOWN:
		{
			const char *force_destination_ip = NULL;
			mrcp_session_descriptor_t *descriptor;

			if(agent->config->force_destination == TRUE) {
				force_destination_ip = rtsp_server_session_destination_get(rtsp_session);
			}
			descriptor = mrcp_descriptor_generate_by_rtsp_request(
							rtsp_message,
							force_destination_ip,
							agent->config->resource_map,
							session->mrcp_session->pool,
							session->home);
			if(!descriptor) {
				rtsp_message_t *response = rtsp_response_create(rtsp_message,
										RTSP_STATUS_CODE_BAD_REQUEST,
										RTSP_REASON_PHRASE_BAD_REQUEST,
										rtsp_message->pool);
				status = rtsp_server_session_respond(rtsp_server,session->rtsp_session,response);
				break;
			}
			status = mrcp_session_offer(session->mrcp_session,descriptor);
			break;
		}
		case RTSP_METHOD_ANNOUNCE:
		{
			status = mrcp_unirtsp_session_announce(agent,session,rtsp_message);
			break;
		}
		case RTSP_METHOD_DESCRIBE:
		{
			rtsp_message_t *response = rtsp_resource_discovery_response_generate(
						rtsp_message,
						agent->config->local_ip,
						agent->config->origin,
						session->mrcp_session->pool);
			status = rtsp_server_session_respond(rtsp_server,session->rtsp_session,response);
			break;
		}
		default:
			break;
	}

	return status;
}
static apt_bool_t mrcp_unirtsp_on_session_control(mrcp_session_t *mrcp_session, mrcp_message_t *mrcp_message)
{
	mrcp_unirtsp_session_t *session = mrcp_session->obj;
	mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;

	char buffer[500];
	apt_text_stream_t stream;
	rtsp_message_t *rtsp_message = NULL;
	apt_str_t *body;

	apt_text_stream_init(&stream,buffer,sizeof(buffer));

	mrcp_message->start_line.version = MRCP_VERSION_1;
	if(mrcp_message_generate(agent->sig_agent->resource_factory,mrcp_message,&stream) != TRUE) {
		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv1 Message");
		return FALSE;
	}
	stream.text.length = stream.pos - stream.text.buf;

	if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
		/* send RTSP response (OK) */
		const rtsp_message_t *request = rtsp_server_session_request_get(session->rtsp_session);
		if(request) {
			rtsp_message = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,mrcp_session->pool);
		}
	}
	else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
		/* send RTSP announce */
		rtsp_message = rtsp_request_create(mrcp_session->pool);
		rtsp_message->start_line.common.request_line.resource_name = rtsp_name_get_by_mrcp_name(
									agent->config->resource_map,
									mrcp_message->channel_id.resource_name.buf);
		rtsp_message->start_line.common.request_line.method_id = RTSP_METHOD_ANNOUNCE;
	}

	if(!rtsp_message) {
		return FALSE;
	}

	body = &rtsp_message->body;
	body->length = mrcp_message->start_line.length;
	body->buf = apr_palloc(rtsp_message->pool,body->length+1);
	memcpy(body->buf,stream.text.buf,stream.text.length);
	if(mrcp_message->body.length) {
		memcpy(body->buf+stream.text.length,mrcp_message->body.buf,mrcp_message->body.length);
	}
	body->buf[body->length] = '\0';

	rtsp_message->header.content_type = RTSP_CONTENT_TYPE_MRCP;
	rtsp_header_property_add(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_TYPE,rtsp_message->pool);
	rtsp_message->header.content_length = body->length;
	rtsp_header_property_add(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_LENGTH,rtsp_message->pool);

	rtsp_server_session_respond(agent->rtsp_server,session->rtsp_session,rtsp_message);
	return TRUE;
}
示例#9
0
/* Receive RTSP message through RTSP connection */
static apt_bool_t rtsp_server_message_receive(apt_net_server_task_t *task, apt_net_server_connection_t *connection)
{
	rtsp_server_t *server = apt_net_server_task_object_get(task);
	char buffer[RTSP_MESSAGE_MAX_SIZE];
	apt_bool_t more_messages_on_buffer = FALSE;
	apr_status_t status;
	apt_text_stream_t text_stream;
	rtsp_message_t *message;

	if(!connection || !connection->sock) {
		return FALSE;
	}
	
	text_stream.text.buf = buffer;
	text_stream.text.length = sizeof(buffer)-1;
	status = apr_socket_recv(connection->sock, text_stream.text.buf, &text_stream.text.length);
	if(status == APR_EOF || text_stream.text.length == 0) {
		return apt_net_server_connection_close(task,connection);
	}
	text_stream.text.buf[text_stream.text.length] = '\0';
	text_stream.pos = text_stream.text.buf;

	apt_log(APT_PRIO_INFO,"Receive RTSP Message size=%lu\n%s",text_stream.text.length,text_stream.text.buf);
	do {
		message = rtsp_message_create(RTSP_MESSAGE_TYPE_UNKNOWN,connection->pool);
		if(rtsp_message_parse(message,&text_stream) == TRUE) {
			apt_str_t *destination = &message->header.transport.destination;
			if(!destination->buf && connection->client_ip) {
				apt_string_assign(destination,connection->client_ip,connection->pool);
			}
			rtsp_server_session_request_process(server,connection->obj,message);
		}
		else {
			rtsp_message_t *response;
			apt_log(APT_PRIO_WARNING,"Failed to Parse RTSP Message");
			response = rtsp_response_create(message,RTSP_STATUS_CODE_BAD_REQUEST,
									RTSP_REASON_PHRASE_BAD_REQUEST,message->pool);
			if(rtsp_server_message_send(server,connection,response) == FALSE) {
				apt_log(APT_PRIO_WARNING,"Failed to Send RTSP Response");
			}
		}

		more_messages_on_buffer = FALSE;
		if(text_stream.text.length > (apr_size_t)(text_stream.pos - text_stream.text.buf)) {
			/* there are more RTSP messages to signal */
			more_messages_on_buffer = TRUE;
			text_stream.text.length -= text_stream.pos - text_stream.text.buf;
			text_stream.text.buf = text_stream.pos;
			apt_log(APT_PRIO_DEBUG,"Saving Remaining Buffer for Next Message");
		}
	}
	while(more_messages_on_buffer);

	return TRUE;
}
示例#10
0
static apt_bool_t rtsp_server_error_respond(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection, rtsp_message_t *request, 
											rtsp_status_code_e status_code, rtsp_reason_phrase_e reason)
{
	/* send error response to client */
	rtsp_message_t *response = rtsp_response_create(request,status_code,reason,request->pool);
	if(rtsp_server_message_send(server,rtsp_connection,response) == FALSE) {
		apt_log(RTSP_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Response");
		return FALSE;
	}
	return TRUE;
}
示例#11
0
/* RTSP connection disconnected */
static apt_bool_t rtsp_client_on_disconnect(rtsp_client_t *client, rtsp_client_connection_t *rtsp_connection)
{
	rtsp_client_session_t *session;
	rtsp_message_t *request;
	rtsp_message_t *response;
	apr_size_t remaining_handles = 0;
	apr_size_t cancelled_requests = 0;

	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP Peer Disconnected %s", rtsp_connection->base->id);
	apt_net_client_connection_close(client->task,rtsp_connection->base);

	/* Cancel in-progreess requests */
	do {
		session = apt_list_pop_front(rtsp_connection->inprogress_request_queue);
		if(session && session->active_request) {
			request = session->active_request;
			session->active_request = NULL;
			cancelled_requests++;

			response = rtsp_response_create(
								request,
								RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
								RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
								session->pool);
			rtsp_client_session_response_process(client,session,request,response);
		}
	}
	while(session);

	/* Walk through RTSP handles and raise termination event for them */
	remaining_handles = apr_hash_count(rtsp_connection->handle_table);
	if(remaining_handles) {
		void *val;
		apr_hash_index_t *it;
		apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Terminate Remaining RTSP Handles [%d]",remaining_handles);
		it = apr_hash_first(rtsp_connection->base->pool,rtsp_connection->session_table);
		for(; it; it = apr_hash_next(it)) {
			apr_hash_this(it,NULL,NULL,&val);
			session = val;
			if(session) {
				rtsp_client_session_terminate_raise(client,session);
			}
		}
		remaining_handles = apr_hash_count(rtsp_connection->session_table);
	}

	if(!remaining_handles && !cancelled_requests) {
		rtsp_client_connection_destroy(client,rtsp_connection);
	}
	return TRUE;
}
示例#12
0
/** Generate RTSP resource discovery response */
MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_response_generate(
											const rtsp_message_t *request, 
											const char *ip,
											const char *origin,
											apr_pool_t *pool)
{
	rtsp_message_t *response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,pool);
	if(response) {
		apr_size_t offset = 0;
		char buffer[2048];
		apr_size_t size = sizeof(buffer);
		
		if(!ip) {
			ip = "0.0.0.0";
		}
		if(!origin) {
			origin = "-";
		}
		
		buffer[0] = '\0';
		offset += snprintf(buffer+offset,size-offset,
			"v=0\r\n"
			"o=%s 0 0 IN IP4 %s\r\n"
			"s=-\r\n"
			"c=IN IP4 %s\r\n"
			"t=0 0\r\n"
			"m=audio 0 RTP/AVP 0 8 96 101\r\n"
			"a=rtpmap:0 PCMU/8000\r\n"
			"a=rtpmap:8 PCMA/8000\r\n"
			"a=rtpmap:96 L16/8000\r\n"
			"a=rtpmap:101 telephone-event/8000\r\n",
			origin,
			ip,
			ip);
		
		if(offset) {
			apt_string_assign_n(&response->body,buffer,offset,pool);
			response->header.content_type = RTSP_CONTENT_TYPE_SDP;
			rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
			response->header.content_length = offset;
			rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
		}
	}

	return response;
}
示例#13
0
/* Process outgoing RTSP message */
static apt_bool_t rtsp_client_session_message_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message)
{
	if(session->active_request) {
		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push RTSP Request to Pending Queue "APT_PTR_FMT,session);
		apt_list_push_back(session->pending_request_queue,message,message->pool);
		return TRUE;
	}

	if(rtsp_client_session_request_process(client,session,message) == FALSE) {
		/* respond with error in case request cannot be processed */
		rtsp_message_t *response = rtsp_response_create(
							message,
							RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
							RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
							session->pool);
		rtsp_client_session_response_process(client,session,message,response);
	}
	return TRUE;
}
示例#14
0
/* Cancel RTSP request */
static apt_bool_t rtsp_client_request_cancel(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_status_code_e status_code, rtsp_reason_phrase_e reason)
{
	rtsp_message_t *request;
	rtsp_message_t *response;
	if(!session->active_request) {
		return FALSE;
	}

	request = session->active_request;
	response = rtsp_response_create(
						request,
						status_code,
						reason,
						session->pool);

	apt_log(RTSP_LOG_MARK,APT_PRIO_INFO,"Cancel RTSP Request " APT_PTRSID_FMT " CSeq:%" APR_SIZE_T_FMT " [%d]",
		session,
		request->header.session_id.buf ? request->header.session_id.buf : "new",
		request->header.cseq,
		status_code);
	
	return rtsp_client_message_handler(session->connection, response, APT_MESSAGE_STATUS_COMPLETE);
}
示例#15
0
/** Generate RTSP response by MRCP descriptor */
MRCP_DECLARE(rtsp_message_t*) rtsp_response_generate_by_mrcp_descriptor(const rtsp_message_t *request, const mrcp_session_descriptor_t *descriptor, const apr_table_t *resource_map, apr_pool_t *pool)
{
	rtsp_message_t *response = NULL;

	switch(descriptor->status) {
		case MRCP_SESSION_STATUS_OK:
			response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,pool);
			break;
		case MRCP_SESSION_STATUS_NO_SUCH_RESOURCE:
			response = rtsp_response_create(request,RTSP_STATUS_CODE_NOT_FOUND,RTSP_REASON_PHRASE_NOT_FOUND,pool);
			break;
		case MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE:
		case MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE:
			response = rtsp_response_create(request,RTSP_STATUS_CODE_NOT_ACCEPTABLE,RTSP_REASON_PHRASE_NOT_ACCEPTABLE,pool);
			break;
		case MRCP_SESSION_STATUS_ERROR:
			response = rtsp_response_create(request,RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,pool);
			break;
	}

	if(!response) {
		return NULL;
	}

	if(descriptor->status == MRCP_SESSION_STATUS_OK) {
		apr_size_t i;
		apr_size_t count;
		apr_size_t audio_index = 0;
		mpf_rtp_media_descriptor_t *audio_media;
		apr_size_t video_index = 0;
		mpf_rtp_media_descriptor_t *video_media;
		apr_size_t offset = 0;
		char buffer[2048];
		apr_size_t size = sizeof(buffer);
		const char *ip = descriptor->ext_ip.buf ? descriptor->ext_ip.buf : (descriptor->ip.buf ? descriptor->ip.buf : "0.0.0.0");

		buffer[0] = '\0';
		offset += snprintf(buffer+offset,size-offset,
				"v=0\r\n"
				"o=%s 0 0 IN IP4 %s\r\n"
				"s=-\r\n"
				"c=IN IP4 %s\r\n"
				"t=0 0\r\n",
				descriptor->origin.buf ? descriptor->origin.buf : "-",
				ip,
				ip);
		count = mrcp_session_media_count_get(descriptor);
		for(i=0; i<count; i++) {
			audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
			if(audio_media && audio_media->id == i) {
				/* generate audio media */
				rtsp_transport_t *transport;
				audio_index++;
				offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
				transport = &response->header.transport;
				transport->server_port_range.min = audio_media->port;
				transport->server_port_range.max = audio_media->port+1;
				transport->client_port_range = request->header.transport.client_port_range;
				continue;
			}
			video_media = mrcp_session_video_media_get(descriptor,video_index);
			if(video_media && video_media->id == i) {
				/* generate video media */
				video_index++;
				offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
				continue;
			}
		}

		/* ok */
		response->header.transport.protocol = RTSP_TRANSPORT_RTP;
		response->header.transport.profile = RTSP_PROFILE_AVP;
		response->header.transport.delivery = RTSP_DELIVERY_UNICAST;
		rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);

		if(offset) {
			apt_string_assign_n(&response->body,buffer,offset,pool);
			response->header.content_type = RTSP_CONTENT_TYPE_SDP;
			rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
			response->header.content_length = offset;
			rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
		}
	}
	return response;
}
示例#16
0
/** Generate RTSP response by MRCP descriptor */
MRCP_DECLARE(rtsp_message_t*) rtsp_response_generate_by_mrcp_descriptor(const rtsp_message_t *request, const mrcp_session_descriptor_t *descriptor, apr_pool_t *pool)
{
	apr_size_t i;
	apr_size_t count;
	apr_size_t audio_index = 0;
	mpf_rtp_media_descriptor_t *audio_media;
	apr_size_t video_index = 0;
	mpf_rtp_media_descriptor_t *video_media;
	apr_size_t offset = 0;
	char buffer[2048];
	apr_size_t size = sizeof(buffer);
	rtsp_message_t *response;

	if(descriptor->resource_state != TRUE) {
		response = rtsp_response_create(request,RTSP_STATUS_CODE_NOT_FOUND,RTSP_REASON_PHRASE_NOT_FOUND,pool);
		return response;
	}

	response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,pool);
	if(!response) {
		return NULL;
	}

	buffer[0] = '\0';
	offset += snprintf(buffer+offset,size-offset,
			"v=0\r\n"
			"o=%s 0 0 IN IP4 %s\r\n"
			"s=-\r\n"
			"c=IN IP4 %s\r\n"
			"t=0 0\r\n",
			descriptor->origin.buf ? descriptor->origin.buf : "-",
			descriptor->ip.buf ? descriptor->ip.buf : "0",
			descriptor->ip.buf ? descriptor->ip.buf : "0");
	count = mrcp_session_media_count_get(descriptor);
	for(i=0; i<count; i++) {
		audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
		if(audio_media && audio_media->base.id == i) {
			/* generate audio media */
			audio_index++;
			offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
			continue;
		}
		video_media = mrcp_session_video_media_get(descriptor,video_index);
		if(video_media && video_media->base.id == i) {
			/* generate video media */
			video_index++;
			offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
			continue;
		}
	}

	/* ok */
	response->header.transport.profile = RTSP_PROFILE_RTP_AVP;
	response->header.transport.delivery = RTSP_DELIVERY_UNICAST;
	rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);

	if(offset) {
		apt_string_assign_n(&response->body,buffer,offset,pool);
		response->header.content_type = RTSP_CONTENT_TYPE_SDP;
		rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
		response->header.content_length = offset;
		rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
	}
	return response;
}