/*
 * OpenMRCP - Open Source Media Resource Control Protocol Stack
 * Copyright (C) 2007, Cepstral LLC
 *
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Author(s):
 * Arsen Chaloyan <achaloyan@yahoo.com>
 *
 * Contributor(s):
 *
 */

#include <apr_general.h>
#include <sofia-sip/sdp.h>

#include "mrcp_server_signaling_agent.h"
#include "mrcp_server_proto_agent.h"
#include "apt_task.h"
#include "mrcp_parser.h"
#include "rtsp_engine.h"

typedef struct mrcp_server_rtsp_agent_t mrcp_server_rtsp_agent_t;

struct mrcp_server_rtsp_agent_t {
	mrcp_signaling_agent_t     *signaling_agent;
	mrcp_proto_agent_t          proto_agent;

	unsigned char               create_count;
	unsigned char               open_count;

	rtsp_engine_event_handler_t handler;
	rtsp_engine_t              *engine;

	apt_task_msg_pool_t        *msg_pool;
	apr_pool_t                 *pool;
};

typedef struct mrcp_server_rtsp_session_t mrcp_server_rtsp_session_t;

struct mrcp_server_rtsp_session_t {
	mrcp_signaling_channel_t *channel;
	mrcp_connection_t        *proto_connection;

	rtsp_session_t           *session;
	rtsp_message_t           *request;

	su_home_t                *home;
};


typedef enum {
	MRCP_RTSP_EVENT_AGENT_STARTED,
	MRCP_RTSP_EVENT_AGENT_TERMINATED,
	MRCP_RTSP_EVENT_SESSION_CREATED,
	MRCP_RTSP_EVENT_SESSION_TERMINATED,
	MRCP_RTSP_EVENT_REQUEST_RECEIVED,
	MRCP_RTSP_EVENT_RESPONSE_RECEIVED
} mrcp_rtsp_event_id;


typedef struct mrcp_rtsp_event_t mrcp_rtsp_event_t;

struct mrcp_rtsp_event_t {
	mrcp_rtsp_event_id        event_id;

	mrcp_server_rtsp_agent_t *rtsp_agent;
	rtsp_session_t           *session;
	rtsp_message_t           *request;
	rtsp_message_t           *response;
};


static mrcp_status_t mrcp_rtsp_agent_destroy(mrcp_module_t *module);
static mrcp_module_state_t mrcp_rtsp_agent_open(mrcp_module_t *module);
static mrcp_module_state_t mrcp_rtsp_agent_close(mrcp_module_t *module);
static mrcp_status_t mrcp_rtsp_agent_signal_handler(mrcp_module_t *module, apt_task_msg_t *msg);

static const mrcp_module_method_set_t module_method_set = {
	mrcp_rtsp_agent_destroy,
	mrcp_rtsp_agent_open,
	mrcp_rtsp_agent_close,
	mrcp_rtsp_agent_signal_handler
};

static mrcp_status_t mrcp_rtsp_session_answer(mrcp_signaling_channel_t *channel);
static mrcp_status_t mrcp_rtsp_session_destroy(mrcp_signaling_channel_t *channel);

static const mrcp_signaling_channel_method_set_t signaling_channel_method_set = {
	NULL, /*offer*/
	mrcp_rtsp_session_answer,
	NULL, /*terminate*/
	mrcp_rtsp_session_destroy
};


static mrcp_connection_t* mrcp_rtsp_proto_connection_add(mrcp_proto_agent_t *proto_agent, mrcp_signaling_channel_t *channel, const char *remote_ip);

static const mrcp_proto_agent_method_set_t proto_agent_method_set = {
	mrcp_rtsp_proto_connection_add,
};


static mrcp_status_t mrcp_rtsp_proto_connection_remove(mrcp_connection_t *proto_connection);
static mrcp_status_t mrcp_rtsp_message_send(mrcp_connection_t *proto_connection, mrcp_message_t *mrcp_message);

static const mrcp_connection_method_set_t connection_method_set = {
	mrcp_rtsp_proto_connection_remove,
	mrcp_rtsp_message_send
};

mrcp_status_t mrcp_descriptor_generate_by_rtsp_request(mrcp_descriptor_t *descriptor, rtsp_message_t *request, apr_pool_t *pool, su_home_t *home);
size_t rtsp_response_generate_by_mrcp_descriptor(rtsp_message_t *message, mrcp_descriptor_t *descriptor, const char *resource_name);
size_t rtsp_resource_discover_sdp_generate(rtsp_message_t *message, mrcp_descriptor_t *descriptor);


static APR_INLINE mrcp_server_rtsp_agent_t* mrcp_rtsp_agent_get(mrcp_module_t *module)
{
	return ((mrcp_signaling_agent_t*)module)->object;
}

static mrcp_status_t mrcp_rtsp_session_answer(mrcp_signaling_channel_t *channel)
{
	mrcp_server_rtsp_session_t *rtsp_session = channel->object;
	rtsp_message_t *response;

	if(!rtsp_session || !rtsp_session->request) {
		return MRCP_STATUS_FAILURE;
	}

	response = rtsp_response_create(rtsp_session->request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,channel->pool);
	if(rtsp_session->request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
		if(rtsp_response_generate_by_mrcp_descriptor(response,&channel->local_descriptor,
			rtsp_session->request->start_line.common.request_line.resource_name) > 0) {
			apt_log(APT_PRIO_INFO,"Local SDP\n[%s]\n", response->body);
		}
	}

	rtsp_engine_message_send(rtsp_session->session,response);

	if(rtsp_session->request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN ||
		(rtsp_session->request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP && 
		response->start_line.common.status_line.status_code != RTSP_STATUS_CODE_OK) ) {
		if(!mrcp_enabled_control_media_get(&rtsp_session->channel->local_descriptor)) {
			rtsp_engine_session_terminate(rtsp_session->session);
		}
	}
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_session_destroy(mrcp_signaling_channel_t *channel)
{
	mrcp_server_rtsp_session_t *rtsp_session = channel->object;
	if(!rtsp_session || !rtsp_session->request) {
		return MRCP_STATUS_FAILURE;
	}

	if(rtsp_session->home) {
		su_home_unref(rtsp_session->home);
		rtsp_session->home = NULL;
	}

	channel->object = NULL;

	rtsp_engine_session_destroy(rtsp_session->session);
	rtsp_session->session = NULL;
	return MRCP_STATUS_SUCCESS;
}

static mrcp_connection_t* mrcp_rtsp_proto_connection_add(mrcp_proto_agent_t *proto_agent, mrcp_signaling_channel_t *channel, const char *remote_ip)
{
	mrcp_server_rtsp_session_t* rtsp_session = channel->object;
	if(!rtsp_session) {
		return NULL;
	}

	if(!rtsp_session->proto_connection) {
		rtsp_session->proto_connection = apr_palloc(rtsp_session->channel->pool,sizeof(mrcp_connection_t));
		rtsp_session->proto_connection->agent = proto_agent;
		rtsp_session->proto_connection->method_set = &connection_method_set;
		rtsp_session->proto_connection->event_set = proto_agent->connection_event_set;
		rtsp_session->proto_connection->object = rtsp_session;
	}
	return rtsp_session->proto_connection;
}

static mrcp_status_t mrcp_rtsp_proto_connection_remove(mrcp_connection_t *proto_connection)
{
	/* nothing to do, no actual connection exists */
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_message_send(mrcp_connection_t *proto_connection, mrcp_message_t *mrcp_message)
{
	char buffer[MRCP_MESSAGE_MAX_SIZE];
	apt_text_stream_t text_stream;
	size_t size = sizeof(buffer)-1;
	
	mrcp_server_rtsp_session_t *rtsp_session = proto_connection->object;
	mrcp_server_rtsp_agent_t *rtsp_agent = proto_connection->agent->object;
	rtsp_message_t *rtsp_message = NULL;

	if(!rtsp_agent || !rtsp_session || !rtsp_session->session) {
		return MRCP_STATUS_FAILURE;
	}

	text_stream.buffer = buffer;
	text_stream.size = size;
	text_stream.pos = text_stream.buffer;

	mrcp_message->start_line.version = MRCP_VERSION_1;
	if(mrcp_message_generate(proto_connection->agent->resource_container,mrcp_message,&text_stream) != MRCP_STATUS_SUCCESS) {
		apt_log(APT_PRIO_WARNING,"Failed to Generate MRCPv1 Message\n");
		return MRCP_STATUS_FAILURE;
	}
	*text_stream.pos = '\0';
	apt_log(APT_PRIO_DEBUG,"Send MRCPv1 Message size=%lu\n%s\n",text_stream.size,text_stream.buffer);

	if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
		/* send rtsp response (ok) */
		rtsp_message = rtsp_response_create(rtsp_session->request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,rtsp_session->channel->pool);
	}
	else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
		/* send rtsp announce */
		rtsp_message = rtsp_request_create(rtsp_session->channel->pool);
		rtsp_message->start_line.common.request_line.method_id = RTSP_METHOD_ANNOUNCE;

		if(rtsp_session->request) {
			rtsp_message->start_line.common.request_line.url = rtsp_session->request->start_line.common.request_line.url;
		}
	}

	if(!rtsp_message) {
		return MRCP_STATUS_FAILURE;
	}

	rtsp_message->body = apr_pstrdup(rtsp_message->pool,text_stream.buffer);
	rtsp_message->header.content_type = RTSP_CONTENT_TYPE_MRCP;
	rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
	rtsp_message->header.content_length = text_stream.size;
	rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
	return rtsp_engine_message_send(rtsp_session->session,rtsp_message);
}

static mrcp_status_t mrcp_rtsp_process_session_create(mrcp_server_rtsp_agent_t *rtsp_agent, rtsp_session_t *session)
{
	mrcp_server_rtsp_session_t *rtsp_session;
	apr_pool_t *pool;
	const mrcp_signaling_agent_event_set_t *event_set = rtsp_agent->signaling_agent->agent_event_set;
	mrcp_session_id *session_id = rtsp_engine_session_id_get(session);
	mrcp_session_t *mrcp_session = event_set->on_session_create(rtsp_agent->signaling_agent,session_id,&pool);
	if(!mrcp_session || !pool) {
		return MRCP_STATUS_FAILURE;
	}
	rtsp_session = apr_palloc(pool,sizeof(*rtsp_session));
	rtsp_session->home = su_home_new(sizeof(*rtsp_session->home));
	rtsp_session->proto_connection = NULL;
	rtsp_session->session = session;
	rtsp_engine_session_object_set(session,rtsp_session);
	rtsp_session->request = NULL;
	rtsp_session->channel = mrcp_server_signaling_channel_create(
		rtsp_agent->signaling_agent,
		&signaling_channel_method_set,
		rtsp_session,
		pool);
	event_set->on_channel_attach(mrcp_session,rtsp_session->channel);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_process_session_terminate(mrcp_server_rtsp_agent_t *rtsp_agent, rtsp_session_t *session)
{
	mrcp_server_rtsp_session_t *rtsp_session = rtsp_engine_session_object_get(session);
	if(rtsp_session) {
		rtsp_session->channel->event_set->on_terminate(rtsp_session->channel);
	}
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_process_setup(mrcp_server_rtsp_agent_t *agent, rtsp_session_t *session, rtsp_message_t *message)
{
	mrcp_server_rtsp_session_t *rtsp_session = rtsp_engine_session_object_get(session);

	apt_log(APT_PRIO_NOTICE,"RTSP Setup\n");
	if(!rtsp_session || !rtsp_session->channel) {
		return MRCP_STATUS_FAILURE;
	}

	rtsp_session->request = message;

	if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == MRCP_STATUS_SUCCESS) {
		if(message->header.content_type == RTSP_CONTENT_TYPE_SDP && message->body) {
			apt_log(APT_PRIO_INFO,"Remote SDP\n[%s]\n", message->body);

			mrcp_descriptor_generate_by_rtsp_request(
								&rtsp_session->channel->remote_descriptor,
								message,
								rtsp_session->channel->pool,
								rtsp_session->home);
		}
	}

	return rtsp_session->channel->event_set->on_offer(rtsp_session->channel);
}

static mrcp_status_t mrcp_rtsp_process_teardown(mrcp_server_rtsp_agent_t *agent, rtsp_session_t *session, rtsp_message_t *message)
{
	mrcp_server_rtsp_session_t *rtsp_session = rtsp_engine_session_object_get(session);
	mrcp_media_control_t *control_media;
	
	apt_log(APT_PRIO_NOTICE,"RTSP Teardown <%s>\n",message->header.session_id);

	if(!rtsp_session) {
		apt_log(APT_PRIO_NOTICE,"RTSP Teardown <%s>: no such session\n",message->header.session_id);
		return MRCP_STATUS_FAILURE;
	}
	rtsp_session->request = message;

	control_media = mrcp_control_media_get(&rtsp_session->channel->remote_descriptor,message->start_line.common.request_line.resource_name);
	if(!control_media) {
		apt_log(APT_PRIO_NOTICE,"RTSP Teardown <%s@%s>: no such resource\n",message->header.session_id,message->start_line.common.request_line.resource_name);
		return MRCP_STATUS_FAILURE;
	}

	control_media->base.state = MRCP_MEDIA_DISABLED;
	return rtsp_session->channel->event_set->on_offer(rtsp_session->channel);
}

static mrcp_status_t mrcp_rtsp_process_announce(mrcp_server_rtsp_agent_t *agent, rtsp_session_t *session, rtsp_message_t *message)
{
	mrcp_server_rtsp_session_t *rtsp_session = rtsp_engine_session_object_get(session);
	const char *resource_name = message->start_line.common.request_line.resource_name;
	mrcp_status_t status = MRCP_STATUS_SUCCESS;

	apt_log(APT_PRIO_NOTICE,"RTSP Announce\n");

	if(rtsp_session && resource_name && rtsp_session->proto_connection &&
		rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == MRCP_STATUS_SUCCESS &&
		message->header.content_type == RTSP_CONTENT_TYPE_MRCP &&
		rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == MRCP_STATUS_SUCCESS &&
		message->header.content_length > 0) {

		apt_text_stream_t text_stream;
		mrcp_message_t *mrcp_message;

		rtsp_session->request = message;

		text_stream.buffer = message->body;
		text_stream.size = message->header.content_length;
		text_stream.pos = text_stream.buffer;

		apt_log(APT_PRIO_DEBUG,"Receive MRCPv1 Message size=%lu\n%s\n",text_stream.size,text_stream.buffer);

		mrcp_message = mrcp_message_create(rtsp_session->channel->pool);
		mrcp_message->channel_id.session_id.hex_str = message->header.session_id;
		mrcp_message->channel_id.session_id.length = strlen(message->header.session_id);
		mrcp_message->channel_id.resource_name = resource_name;
		if(mrcp_message_parse(agent->proto_agent.resource_container,mrcp_message,&text_stream) == MRCP_STATUS_SUCCESS) {
			rtsp_session->proto_connection->event_set->on_receive(rtsp_session->proto_connection,mrcp_message);
		}
		else {
			/* error response */
			apt_log(APT_PRIO_WARNING,"Failed to Parse MRCPv1 Message\n");
			status = MRCP_STATUS_FAILURE;
		}
	}
	else {
		/* error response */
		status = MRCP_STATUS_FAILURE;
	}
	return status;
}


static mrcp_status_t mrcp_rtsp_process_describe(mrcp_server_rtsp_agent_t *agent, rtsp_session_t *session, rtsp_message_t *message)
{
	rtsp_message_t *response;
	apt_log(APT_PRIO_NOTICE,"RTSP Describe\n");

	response = rtsp_response_create(message,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,message->pool);
	if(rtsp_resource_discover_sdp_generate(response,&agent->signaling_agent->capabilities) > 0) {
		apt_log(APT_PRIO_INFO,"Local SDP\n[%s]\n", message->body);
	}
	return rtsp_engine_message_send(session,response);
}

static mrcp_status_t mrcp_rtsp_process_request(mrcp_server_rtsp_agent_t *rtsp_agent, rtsp_session_t *session, rtsp_message_t *message)
{
	if(!rtsp_agent) {
		return MRCP_STATUS_FAILURE;
	}

	if(message->start_line.message_type == RTSP_MESSAGE_TYPE_REQUEST) {
		mrcp_status_t status = MRCP_STATUS_SUCCESS;
		apt_log(APT_PRIO_DEBUG,"Process RTSP Request [%s]\n",message->start_line.common.request_line.method_name);
		switch(message->start_line.common.request_line.method_id) {
			case RTSP_METHOD_SETUP:
				status = mrcp_rtsp_process_setup(rtsp_agent,session,message);
				break;
			case RTSP_METHOD_ANNOUNCE:
				status = mrcp_rtsp_process_announce(rtsp_agent,session,message);
				break;
			case RTSP_METHOD_TEARDOWN:
				status = mrcp_rtsp_process_teardown(rtsp_agent,session,message);
				break;
			case RTSP_METHOD_DESCRIBE:
				status = mrcp_rtsp_process_describe(rtsp_agent,session,message);
				break;
			default:
			{
				/* not supported message */
				rtsp_message_t *response = rtsp_response_create(message,
					RTSP_STATUS_CODE_METHOD_NOT_ALLOWED,RTSP_REASON_PHRASE_METHOD_NOT_ALLOWED,message->pool);
				rtsp_engine_message_send(session,response);
			}
		}

		if(status == MRCP_STATUS_FAILURE) {
			rtsp_message_t *response = rtsp_response_create(message,
				RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,message->pool);
			rtsp_engine_message_send(session,response);
		}
	}
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_process_response(mrcp_server_rtsp_agent_t *rtsp_agent, rtsp_session_t *session, rtsp_message_t *response, rtsp_message_t *request)
{
	if(response->start_line.message_type == RTSP_MESSAGE_TYPE_RESPONSE) {
		apt_log(APT_PRIO_DEBUG,"Process RTSP Response\n");
	}
	
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_agent_signal_handler(mrcp_module_t *module, apt_task_msg_t *msg)
{
	mrcp_server_rtsp_agent_t *rtsp_agent = mrcp_rtsp_agent_get(module);
	mrcp_rtsp_event_t *rtsp_event = (mrcp_rtsp_event_t*)msg->data;
	if(!rtsp_event) {
		return MRCP_STATUS_FAILURE;
	}

	switch(rtsp_event->event_id) {
		case MRCP_RTSP_EVENT_AGENT_STARTED:
			break;
		case MRCP_RTSP_EVENT_AGENT_TERMINATED:
			if(module->event_set->on_close) {
				module->event_set->on_close(module);
			}
			break;
		case MRCP_RTSP_EVENT_SESSION_CREATED:
			mrcp_rtsp_process_session_create(rtsp_agent,rtsp_event->session);
			break;
		case MRCP_RTSP_EVENT_SESSION_TERMINATED:
			mrcp_rtsp_process_session_terminate(rtsp_agent,rtsp_event->session);
			break;
		case MRCP_RTSP_EVENT_REQUEST_RECEIVED:
			mrcp_rtsp_process_request(rtsp_agent,rtsp_event->session,rtsp_event->request);
			break;
		case MRCP_RTSP_EVENT_RESPONSE_RECEIVED:
			mrcp_rtsp_process_response(rtsp_agent,rtsp_event->session,rtsp_event->response,rtsp_event->request);
			break;
	}

	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t mrcp_rtsp_task_msg_signal(mrcp_server_rtsp_agent_t *rtsp_agent, mrcp_rtsp_event_id event_id, rtsp_session_t *session, rtsp_message_t *request, rtsp_message_t *response)
{
	apt_task_msg_t *task_msg;
	if(!rtsp_agent || !session) {
		return MRCP_STATUS_FAILURE;
	}

	task_msg = apt_task_msg_acquire(rtsp_agent->msg_pool);
	if(task_msg) {
		mrcp_rtsp_event_t *rtsp_event = (mrcp_rtsp_event_t*)task_msg->data;
		rtsp_event->event_id = event_id;
		rtsp_event->rtsp_agent = rtsp_agent;
		rtsp_event->session = session;
		rtsp_event->request = request;
		rtsp_event->response = response;
		task_msg->msg_pool = rtsp_agent->msg_pool;
		rtsp_agent->signaling_agent->module.signal(
								&rtsp_agent->signaling_agent->module,
								task_msg);
	}

	return MRCP_STATUS_SUCCESS;
}

static apt_bool_t mrcp_rtsp_on_session_create(rtsp_engine_event_handler_t *handler, rtsp_session_t *session)
{
	return mrcp_rtsp_task_msg_signal(handler->object,MRCP_RTSP_EVENT_SESSION_CREATED,session,NULL,NULL);
}

static apt_bool_t mrcp_rtsp_on_session_terminate(rtsp_engine_event_handler_t *handler, rtsp_session_t *session)
{
	return mrcp_rtsp_task_msg_signal(handler->object,MRCP_RTSP_EVENT_SESSION_TERMINATED,session,NULL,NULL);
}

static apt_bool_t mrcp_rtsp_on_request_receive(rtsp_engine_event_handler_t *handler, rtsp_session_t *session, rtsp_message_t *request)
{
	return mrcp_rtsp_task_msg_signal(handler->object,MRCP_RTSP_EVENT_REQUEST_RECEIVED,session,request,NULL);
}

static apt_bool_t mrcp_rtsp_on_response_receive(rtsp_engine_event_handler_t *handler, rtsp_session_t *session, rtsp_message_t *response, rtsp_message_t *request)
{
	return mrcp_rtsp_task_msg_signal(handler->object,MRCP_RTSP_EVENT_RESPONSE_RECEIVED,session,request,response);
}

static mrcp_module_state_t mrcp_rtsp_agent_open(mrcp_module_t *module)
{
	mrcp_server_rtsp_agent_t *rtsp_agent = mrcp_rtsp_agent_get(module);
	if(rtsp_agent->open_count++ != 0) {
		return MODULE_STATE_OPENED;
	}
	
	apt_log(APT_PRIO_INFO,"Open RTSP Agent\n");

	rtsp_agent->handler.object = rtsp_agent;
	rtsp_agent->handler.on_session_create = mrcp_rtsp_on_session_create;
	rtsp_agent->handler.on_session_terminate = mrcp_rtsp_on_session_terminate;
	rtsp_agent->handler.on_request_receive = mrcp_rtsp_on_request_receive;
	rtsp_agent->handler.on_response_receive = mrcp_rtsp_on_response_receive;

	rtsp_agent->engine = rtsp_server_engine_start(&rtsp_agent->handler,
		rtsp_agent->signaling_agent->capabilities.ip,
		rtsp_agent->signaling_agent->sip_port,
		rtsp_agent->signaling_agent->resource_location);
	return MODULE_STATE_OPEN_INPROGRESS;
}

static mrcp_module_state_t mrcp_rtsp_agent_close(mrcp_module_t *module)
{
	mrcp_server_rtsp_agent_t *rtsp_agent = mrcp_rtsp_agent_get(module);
	if(--rtsp_agent->open_count > 0) {
		return MODULE_STATE_CLOSED;
	}

	apt_log(APT_PRIO_INFO,"Close RTSP Agent\n");

	rtsp_engine_shutdown(rtsp_agent->engine);
	return MODULE_STATE_CLOSED;
}

static void mrcp_rtsp_agent_config(mrcp_server_rtsp_agent_t *rtsp_agent, 
								   const char *ip, unsigned short rtsp_port, 
								   const char *resource_location)
{
	if(ip) {
		rtsp_agent->signaling_agent->capabilities.ip = apr_pstrdup(rtsp_agent->pool,ip);
	}
	rtsp_agent->signaling_agent->mrcp_port = 0;
	rtsp_agent->signaling_agent->sip_port = rtsp_port;

	if(resource_location) {
		rtsp_agent->signaling_agent->resource_location = apr_pstrdup(rtsp_agent->pool,resource_location);
	}
}

static mrcp_status_t mrcp_rtsp_agent_destroy(mrcp_module_t *module)
{
	mrcp_server_rtsp_agent_t *rtsp_agent = mrcp_rtsp_agent_get(module);

	if(--rtsp_agent->create_count > 0) {
		return MRCP_STATUS_SUCCESS;
	}

	apt_log(APT_PRIO_NOTICE,"Destroy RTSP Agent\n");
	apt_task_msg_pool_destroy(rtsp_agent->msg_pool);

	rtsp_agent->pool = NULL;
	return MRCP_STATUS_SUCCESS;
}

mrcp_signaling_agent_t* mrcp_server_rtsp_agent_create(const char *ip, unsigned short rtsp_port, 
													  const char *resource_location, apr_pool_t *pool)
{
	mrcp_server_rtsp_agent_t *rtsp_agent = apr_palloc(pool,sizeof(mrcp_server_rtsp_agent_t));
	mrcp_signaling_agent_t *agent = mrcp_server_signaling_agent_create(&module_method_set,rtsp_agent,pool);
	apt_log(APT_PRIO_NOTICE,"Create RTSP Agent %s:%hu\n",ip,rtsp_port);
	rtsp_agent->pool = pool;
	rtsp_agent->signaling_agent = agent;
	rtsp_agent->engine = NULL;
	mrcp_rtsp_agent_config(rtsp_agent,ip,rtsp_port,resource_location);

	rtsp_agent->create_count = 1;
	rtsp_agent->open_count = 0;

	rtsp_agent->msg_pool = apt_task_msg_pool_create_waitable_static(sizeof(mrcp_rtsp_event_t),pool);
	return agent;
}

mrcp_proto_agent_t* mrcp_server_rtsp_proto_agent_create(mrcp_signaling_agent_t *signaling_agent)
{
	mrcp_server_rtsp_agent_t *rtsp_agent;
	if(!signaling_agent || !signaling_agent->object) {
		return NULL;
	}
	rtsp_agent = signaling_agent->object;
	
	rtsp_agent->proto_agent.object = rtsp_agent;
	rtsp_agent->proto_agent.agent_method_set = &proto_agent_method_set;

	mrcp_module_init(&rtsp_agent->proto_agent.module,&module_method_set);

	rtsp_agent->create_count++;

	return &rtsp_agent->proto_agent;
}
