inital checkin of unimrcp svn revision 985 from http://unimrcp.googlecode.com/svn/trunk/

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@13790 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris committed 2009-06-16 22:31:19 +00:00
1 parent ec90221783
commit da925bddf8
349 files changed
+47866

No files matched your search

@@ -0,0 +1,395 @@
/*
* Copyright 2008 Arsen Chaloyan
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <apr_general.h>
#include <sofia-sip/sdp.h>
#include "mrcp_sdp.h"
#include "mrcp_session_descriptor.h"
#include "mrcp_control_descriptor.h"
#include "mpf_rtp_attribs.h"
#include "apt_text_stream.h"
#include "apt_log.h"
static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mpf_rtp_media_descriptor_t *audio_descriptor);
static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mrcp_control_descriptor_t *control_media, apt_bool_t offer);
static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool);
static apt_bool_t mrcp_control_media_generate(mrcp_control_descriptor_t *mrcp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool);
/** Generate SDP string by MRCP descriptor */
MRCP_DECLARE(apr_size_t) sdp_string_generate_by_mrcp_descriptor(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, apt_bool_t offer)
{
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 control_index = 0;
mrcp_control_descriptor_t *control_media;
apr_size_t offset = 0;
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->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;
}
control_media = mrcp_session_control_media_get(descriptor,control_index);
if(control_media && control_media->id == i) {
/** generate mrcp control media */
control_index++;
offset += sdp_control_media_generate(buffer+offset,size-offset,descriptor,control_media,offer);
continue;
}
}
return offset;
}
/** Generate MRCP descriptor by SDP session */
MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_sdp_session(const sdp_session_t *sdp, const char *force_destination_ip, apr_pool_t *pool)
{
sdp_media_t *sdp_media;
mrcp_session_descriptor_t *descriptor;
if(!sdp) {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid SDP Message");
return NULL;
}
descriptor = mrcp_session_descriptor_create(pool);
if(force_destination_ip) {
apt_string_assign(&descriptor->ip,force_destination_ip,pool);
}
else if(sdp->sdp_connection) {
apt_string_assign(&descriptor->ip,sdp->sdp_connection->c_address,pool);
}
for(sdp_media=sdp->sdp_media; sdp_media; sdp_media=sdp_media->m_next) {
switch(sdp_media->m_type) {
case sdp_media_audio:
{
mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
mpf_rtp_media_descriptor_init(media);
media->base.id = mrcp_session_audio_media_add(descriptor,media);
mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
break;
}
case sdp_media_video:
{
mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
mpf_rtp_media_descriptor_init(media);
media->base.id = mrcp_session_video_media_add(descriptor,media);
mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
break;
}
case sdp_media_application:
{
mrcp_control_descriptor_t *control_media = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
mrcp_control_descriptor_init(control_media);
control_media->id = mrcp_session_control_media_add(descriptor,control_media);
mrcp_control_media_generate(control_media,sdp_media,&descriptor->ip,pool);
break;
}
default:
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Not Supported SDP Media [%s]", sdp_media->m_type_name);
break;
}
}
return descriptor;
}
/** Generate SDP media by RTP media descriptor */
static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mpf_rtp_media_descriptor_t *audio_media)
{
apr_size_t offset = 0;
int i;
mpf_codec_descriptor_t *codec_descriptor;
apr_array_header_t *descriptor_arr = audio_media->codec_list.descriptor_arr;
if(!descriptor_arr) {
return 0;
}
offset += snprintf(buffer+offset,size-offset,
"m=audio %d RTP/AVP",
audio_media->base.state == MPF_MEDIA_ENABLED ? audio_media->base.port : 0);
for(i=0; i<descriptor_arr->nelts; i++) {
codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
if(codec_descriptor->enabled == TRUE) {
offset += snprintf(buffer+offset,size-offset," %d", codec_descriptor->payload_type);
}
}
offset += snprintf(buffer+offset,size-offset,"\r\n");
if(descriptor->ip.length && audio_media->base.ip.length &&
apt_string_compare(&descriptor->ip,&audio_media->base.ip) != TRUE) {
const char *media_ip = audio_media->base.ext_ip.buf ? audio_media->base.ext_ip.buf : audio_media->base.ip.buf;
offset += sprintf(buffer+offset,"c=IN IP4 %s\r\n",media_ip);
}
if(audio_media->base.state == MPF_MEDIA_ENABLED) {
const apt_str_t *mode_str = mpf_stream_mode_str_get(audio_media->mode);
for(i=0; i<descriptor_arr->nelts; i++) {
codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
if(codec_descriptor->enabled == TRUE && codec_descriptor->name.buf) {
offset += snprintf(buffer+offset,size-offset,"a=rtpmap:%d %s/%d\r\n",
codec_descriptor->payload_type,
codec_descriptor->name.buf,
codec_descriptor->sampling_rate);
}
}
offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",mode_str ? mode_str->buf : "");
if(audio_media->ptime) {
offset += snprintf(buffer+offset,size-offset,"a=ptime:%hu\r\n",audio_media->ptime);
}
}
offset += snprintf(buffer+offset,size-offset,"a=mid:%d\r\n",audio_media->mid);
return offset;
}
/** Generate SDP media by MRCP control media descriptor */
static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mrcp_control_descriptor_t *control_media, apt_bool_t offer)
{
apr_size_t offset = 0;
const apt_str_t *proto;
const apt_str_t *setup_type;
const apt_str_t *connection_type;
proto = mrcp_proto_get(control_media->proto);
setup_type = mrcp_setup_type_get(control_media->setup_type);
connection_type = mrcp_connection_type_get(control_media->connection_type);
if(offer == TRUE) { /* offer */
if(control_media->port) {
offset += snprintf(buffer+offset,size-offset,
"m=application %d %s 1\r\n"
"a=setup:%s\r\n"
"a=connection:%s\r\n"
"a=resource:%s\r\n"
"a=cmid:%d\r\n",
control_media->port,
proto ? proto->buf : "",
setup_type ? setup_type->buf : "",
connection_type ? connection_type->buf : "",
control_media->resource_name.buf,
control_media->cmid);
}
else {
offset += snprintf(buffer+offset,size-offset,
"m=application %d %s 1\r\n"
"a=resource:%s\r\n"
"a=cmid:%d\r\n",
control_media->port,
proto ? proto->buf : "",
control_media->resource_name.buf,
control_media->cmid);
}
}
else { /* answer */
if(control_media->port) {
offset += sprintf(buffer+offset,
"m=application %d %s 1\r\n"
"a=setup:%s\r\n"
"a=connection:%s\r\n"
"a=channel:%s@%s\r\n"
"a=cmid:%d\r\n",
control_media->port,
proto ? proto->buf : "",
setup_type ? setup_type->buf : "",
connection_type ? connection_type->buf : "",
control_media->session_id.buf,
control_media->resource_name.buf,
control_media->cmid);
}
else {
offset += sprintf(buffer+offset,
"m=application %d %s 1\r\n"
"a=channel:%s@%s\r\n"
"a=cmid:%d\r\n",
control_media->port,
proto ? proto->buf : "",
control_media->session_id.buf,
control_media->resource_name.buf,
control_media->cmid);
}
}
return offset;
}
/** Generate RTP media descriptor by SDP media */
static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool)
{
mpf_rtp_attrib_e id;
apt_str_t name;
sdp_attribute_t *attrib = NULL;
sdp_rtpmap_t *map;
mpf_codec_descriptor_t *codec;
for(attrib = sdp_media->m_attributes; attrib; attrib=attrib->a_next) {
apt_string_set(&name,attrib->a_name);
id = mpf_rtp_attrib_id_find(&name);
switch(id) {
case RTP_ATTRIB_MID:
rtp_media->mid = atoi(attrib->a_value);
break;
case RTP_ATTRIB_PTIME:
rtp_media->ptime = (apr_uint16_t)atoi(attrib->a_value);
break;
default:
break;
}
}
mpf_codec_list_init(&rtp_media->codec_list,5,pool);
for(map = sdp_media->m_rtpmaps; map; map = map->rm_next) {
codec = mpf_codec_list_add(&rtp_media->codec_list);
if(codec) {
codec->payload_type = (apr_byte_t)map->rm_pt;
apt_string_assign(&codec->name,map->rm_encoding,pool);
codec->sampling_rate = (apr_uint16_t)map->rm_rate;
codec->channel_count = 1;
}
}
switch(sdp_media->m_mode) {
case sdp_inactive:
rtp_media->mode = STREAM_MODE_NONE;
break;
case sdp_sendonly:
rtp_media->mode = STREAM_MODE_SEND;
break;
case sdp_recvonly:
rtp_media->mode = STREAM_MODE_RECEIVE;
break;
case sdp_sendrecv:
rtp_media->mode = STREAM_MODE_SEND_RECEIVE;
break;
}
if(sdp_media->m_connections) {
apt_string_assign(&rtp_media->base.ip,sdp_media->m_connections->c_address,pool);
}
else {
rtp_media->base.ip = *ip;
}
if(sdp_media->m_port) {
rtp_media->base.port = (apr_port_t)sdp_media->m_port;
rtp_media->base.state = MPF_MEDIA_ENABLED;
}
else {
rtp_media->base.state = MPF_MEDIA_DISABLED;
}
return TRUE;
}
/** Generate MRCP control media by SDP media */
static apt_bool_t mrcp_control_media_generate(mrcp_control_descriptor_t *control_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool)
{
mrcp_attrib_e id;
apt_str_t name;
apt_str_t value;
sdp_attribute_t *attrib = NULL;
apt_string_set(&name,sdp_media->m_proto_name);
control_media->proto = mrcp_proto_find(&name);
if(control_media->proto != MRCP_PROTO_TCP) {
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Not supported SDP Proto [%s], expected [%s]",sdp_media->m_proto_name,mrcp_proto_get(MRCP_PROTO_TCP));
return FALSE;
}
for(attrib = sdp_media->m_attributes; attrib; attrib=attrib->a_next) {
apt_string_set(&name,attrib->a_name);
id = mrcp_attrib_id_find(&name);
switch(id) {
case MRCP_ATTRIB_SETUP:
apt_string_set(&value,attrib->a_value);
control_media->setup_type = mrcp_setup_type_find(&value);
break;
case MRCP_ATTRIB_CONNECTION:
apt_string_set(&value,attrib->a_value);
control_media->connection_type = mrcp_connection_type_find(&value);
break;
case MRCP_ATTRIB_RESOURCE:
apt_string_assign(&control_media->resource_name,attrib->a_value,pool);
break;
case MRCP_ATTRIB_CHANNEL:
apt_string_set(&value,attrib->a_value);
apt_id_resource_parse(&value,'@',&control_media->session_id,&control_media->resource_name,pool);
break;
case MRCP_ATTRIB_CMID:
control_media->cmid = atoi(attrib->a_value);
break;
default:
break;
}
}
if(sdp_media->m_connections) {
apt_string_assign(&control_media->ip,sdp_media->m_connections->c_address,pool);
}
else {
control_media->ip = *ip;
}
control_media->port = (apr_port_t)sdp_media->m_port;
return TRUE;
}
/** Generate SDP resource discovery string */
MRCP_DECLARE(apr_size_t) sdp_resource_discovery_string_generate(const char *ip, const char *origin, char *buffer, apr_size_t size)
{
apr_size_t offset = 0;
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=application 0 TCP/MRCPv2 1\r\n"
"a=resource:speechsynth\r\n"
"a=resource:speechrecog\r\n"
"m=audio 0 RTP/AVP 0 8\r\n"
"a=rtpmap:0 PCMU/8000\r\n"
"a=rtpmap:8 PCMA/8000\r\n",
origin,
ip,
ip);
return offset;
}
@@ -0,0 +1,528 @@
/*
* Copyright 2008 Arsen Chaloyan
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
typedef struct mrcp_sofia_agent_t mrcp_sofia_agent_t;
#define NUA_MAGIC_T mrcp_sofia_agent_t
typedef struct mrcp_sofia_session_t mrcp_sofia_session_t;
#define NUA_HMAGIC_T mrcp_sofia_session_t
#include <apr_general.h>
#include <sofia-sip/su.h>
#include <sofia-sip/nua.h>
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sdp.h>
#include <sofia-sip/sofia_features.h>
#include "mrcp_sofiasip_client_agent.h"
#include "mrcp_session.h"
#include "mrcp_session_descriptor.h"
#include "mrcp_sdp.h"
#include "apt_log.h"
#define SOFIA_TASK_NAME "SofiaSIP Agent"
struct mrcp_sofia_agent_t {
mrcp_sig_agent_t *sig_agent;
mrcp_sofia_client_config_t *config;
char *sip_contact_str;
char *sip_to_str;
char *sip_from_str;
char *sip_bind_str;
su_root_t *root;
nua_t *nua;
};
struct mrcp_sofia_session_t {
mrcp_session_t *session;
su_home_t *home;
nua_handle_t *nh;
apt_bool_t terminate_requested;
apr_thread_mutex_t *mutex;
};
/* Task Interface */
static void mrcp_sofia_task_initialize(apt_task_t *task);
static apt_bool_t mrcp_sofia_task_run(apt_task_t *task);
static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task);
/* MRCP Signaling Interface */
static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
static apt_bool_t mrcp_sofia_session_terminate_request(mrcp_session_t *session);
static apt_bool_t mrcp_sofia_session_discover_request(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
static const mrcp_session_request_vtable_t session_request_vtable = {
mrcp_sofia_session_offer,
mrcp_sofia_session_terminate_request,
NULL,
mrcp_sofia_session_discover_request
};
static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_client_config_t *config, apr_pool_t *pool);
static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session);
static void mrcp_sofia_event_callback( nua_event_t nua_event,
int status,
char const *phrase,
nua_t *nua,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[]);
/** Create Sofia-SIP Signaling Agent */
MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(mrcp_sofia_client_config_t *config, apr_pool_t *pool)
{
apt_task_t *task;
apt_task_vtable_t *vtable;
mrcp_sofia_agent_t *sofia_agent;
sofia_agent = apr_palloc(pool,sizeof(mrcp_sofia_agent_t));
sofia_agent->sig_agent = mrcp_signaling_agent_create(sofia_agent,MRCP_VERSION_2,pool);
sofia_agent->sig_agent->create_client_session = mrcp_sofia_session_create;
sofia_agent->root = NULL;
sofia_agent->nua = NULL;
if(mrcp_sofia_config_validate(sofia_agent,config,pool) == FALSE) {
return NULL;
}
task = apt_task_create(sofia_agent,NULL,pool);
if(!task) {
return NULL;
}
apt_task_name_set(task,SOFIA_TASK_NAME);
vtable = apt_task_vtable_get(task);
if(vtable) {
vtable->on_pre_run = mrcp_sofia_task_initialize;
vtable->run = mrcp_sofia_task_run;
vtable->terminate = mrcp_sofia_task_terminate;
}
sofia_agent->sig_agent->task = task;
apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "SOFIA_TASK_NAME" ["SOFIA_SIP_VERSION"] %s:%hu -> %s:%hu %s",
config->local_ip,config->local_port,
config->remote_ip,config->remote_port,
config->transport ? config->transport : "");
return sofia_agent->sig_agent;
}
/** Allocate Sofia-SIP config */
MRCP_DECLARE(mrcp_sofia_client_config_t*) mrcp_sofiasip_client_config_alloc(apr_pool_t *pool)
{
mrcp_sofia_client_config_t *config = apr_palloc(pool,sizeof(mrcp_sofia_client_config_t));
config->local_ip = NULL;
config->ext_ip = NULL;
config->local_port = 0;
config->local_user_name = NULL;
config->remote_ip = NULL;
config->remote_port = 0;
config->remote_user_name = NULL;
config->force_destination = FALSE;
config->user_agent_name = NULL;
config->origin = NULL;
config->transport = NULL;
return config;
}
static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_client_config_t *config, apr_pool_t *pool)
{
const char *local_ip = config->ext_ip ? config->ext_ip : config->local_ip;
if(!config->local_ip || !config->remote_ip) {
return FALSE;
}
sofia_agent->config = config;
sofia_agent->sip_contact_str = apr_psprintf(pool,"sip:%s:%d", local_ip, config->local_port);
sofia_agent->sip_from_str = apr_psprintf(pool,"sip:%s:%d", local_ip, config->local_port);
if(config->remote_user_name && config->remote_user_name != '\0') {
sofia_agent->sip_to_str = apr_psprintf(pool,"sip:%s@%s:%d",
config->remote_user_name,
config->remote_ip,
config->remote_port);
}
else {
sofia_agent->sip_to_str = apr_psprintf(pool,"sip:%s:%d",
config->remote_ip,
config->remote_port);
}
if(config->transport) {
sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d;transport=%s",
config->local_ip,
config->local_port,
config->transport);
}
else {
sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d",
config->local_ip,
config->local_port);
}
return TRUE;
}
static void mrcp_sofia_task_initialize(apt_task_t *task)
{
mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
/* Initialize Sofia-SIP library and create event loop */
su_init();
sofia_agent->root = su_root_create(NULL);
/* Create a user agent instance. The stack will call the 'event_callback()'
* callback when events such as succesful registration to network,
* an incoming call, etc, occur.
*/
sofia_agent->nua = nua_create(
sofia_agent->root, /* Event loop */
mrcp_sofia_event_callback, /* Callback for processing events */
sofia_agent, /* Additional data to pass to callback */
NUTAG_URL(sofia_agent->sip_bind_str), /* Address to bind to */
TAG_END()); /* Last tag should always finish the sequence */
if(sofia_agent->nua) {
nua_set_params(
sofia_agent->nua,
NUTAG_AUTOANSWER(0),
NUTAG_APPL_METHOD("OPTIONS"),
SIPTAG_USER_AGENT_STR(sofia_agent->config->user_agent_name),
TAG_END());
}
}
static apt_bool_t mrcp_sofia_task_run(apt_task_t *task)
{
mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
if(sofia_agent->nua) {
/* Run event loop */
su_root_run(sofia_agent->root);
/* Destroy allocated resources */
nua_destroy(sofia_agent->nua);
sofia_agent->nua = NULL;
}
su_root_destroy(sofia_agent->root);
sofia_agent->root = NULL;
su_deinit();
apt_task_child_terminate(task);
return TRUE;
}
static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task)
{
mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
if(sofia_agent->nua) {
apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Send Shutdown Signal to NUA");
nua_shutdown(sofia_agent->nua);
}
return TRUE;
}
static APR_INLINE mrcp_sofia_agent_t* mrcp_sofia_agent_get(mrcp_session_t *session)
{
return session->signaling_agent->obj;
}
static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session)
{
mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session);
mrcp_sofia_session_t *sofia_session;
session->request_vtable = &session_request_vtable;
sofia_session = apr_palloc(session->pool,sizeof(mrcp_sofia_session_t));
sofia_session->mutex = NULL;
sofia_session->home = su_home_new(sizeof(*sofia_session->home));
sofia_session->session = session;
sofia_session->terminate_requested = FALSE;
session->obj = sofia_session;
sofia_session->nh = nua_handle(
sofia_agent->nua,
sofia_session,
SIPTAG_TO_STR(sofia_agent->sip_to_str),
SIPTAG_FROM_STR(sofia_agent->sip_from_str),
SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
TAG_END());
apr_thread_mutex_create(&sofia_session->mutex,APR_THREAD_MUTEX_DEFAULT,session->pool);
return TRUE;
}
static apt_bool_t mrcp_sofia_session_destroy(mrcp_sofia_session_t *sofia_session)
{
if(sofia_session->mutex) {
apr_thread_mutex_destroy(sofia_session->mutex);
sofia_session->mutex = NULL;
}
if(sofia_session->home) {
su_home_unref(sofia_session->home);
sofia_session->home = NULL;
}
return TRUE;
}
static apt_bool_t mrcp_sofia_session_unref(mrcp_sofia_session_t *sofia_session)
{
if(sofia_session->nh) {
nua_handle_bind(sofia_session->nh, NULL);
nua_handle_destroy(sofia_session->nh);
sofia_session->nh = NULL;
}
sofia_session->session = NULL;
return TRUE;
}
static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
{
char sdp_str[2048];
char *local_sdp_str = NULL;
apt_bool_t res = FALSE;
mrcp_sofia_session_t *sofia_session = session->obj;
if(!sofia_session) {
return FALSE;
}
if(session->signaling_agent) {
mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session);
if(sofia_agent) {
if(sofia_agent->config->origin) {
apt_string_set(&descriptor->origin,sofia_agent->config->origin);
}
}
}
if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,TRUE) > 0) {
local_sdp_str = sdp_str;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP "APT_PTRSID_FMT"\n%s",
MRCP_SESSION_PTRSID(session),
local_sdp_str);
}
apr_thread_mutex_lock(sofia_session->mutex);
if(sofia_session->nh) {
res = TRUE;
nua_invite(sofia_session->nh,
TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
TAG_END());
}
apr_thread_mutex_unlock(sofia_session->mutex);
return res;
}
static apt_bool_t mrcp_sofia_session_terminate_request(mrcp_session_t *session)
{
mrcp_sofia_session_t *sofia_session = session->obj;
if(!sofia_session) {
return FALSE;
}
sofia_session->terminate_requested = FALSE;
apr_thread_mutex_lock(sofia_session->mutex);
if(sofia_session->nh) {
sofia_session->terminate_requested = TRUE;
nua_bye(sofia_session->nh,TAG_END());
}
apr_thread_mutex_unlock(sofia_session->mutex);
if(sofia_session->terminate_requested == FALSE) {
mrcp_sofia_session_destroy(sofia_session);
mrcp_session_terminate_response(session);
}
return TRUE;
}
static apt_bool_t mrcp_sofia_session_discover_request(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
{
apt_bool_t res = FALSE;
mrcp_sofia_session_t *sofia_session = session->obj;
if(!sofia_session) {
return FALSE;
}
apr_thread_mutex_lock(sofia_session->mutex);
if(sofia_session->nh) {
res = TRUE;
nua_options(sofia_session->nh,TAG_END());
}
apr_thread_mutex_unlock(sofia_session->mutex);
return res;
}
static void mrcp_sofia_on_session_ready(
int status,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
mrcp_session_t *session = sofia_session->session;
if(session) {
const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
mrcp_session_descriptor_t *descriptor = NULL;
tl_gets(tags,
SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
TAG_END());
if(remote_sdp_str) {
sdp_parser_t *parser = NULL;
sdp_session_t *sdp = NULL;
const char *force_destination_ip = NULL;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP "APT_PTRSID_FMT"\n%s",
MRCP_SESSION_PTRSID(session),
remote_sdp_str);
parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
sdp = sdp_session(parser);
if(sofia_agent && sofia_agent->config->force_destination == TRUE) {
force_destination_ip = sofia_agent->config->remote_ip;
}
descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,force_destination_ip,session->pool);
sdp_parser_free(parser);
}
mrcp_session_answer(session,descriptor);
}
}
static void mrcp_sofia_on_session_terminate(
int status,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
mrcp_session_t *session = sofia_session->session;
if(session) {
apt_bool_t terminate_requested;
apr_thread_mutex_lock(sofia_session->mutex);
terminate_requested = sofia_session->terminate_requested;
session = sofia_session->session;
mrcp_sofia_session_unref(sofia_session);
apr_thread_mutex_unlock(sofia_session->mutex);
if(terminate_requested == TRUE) {
mrcp_sofia_session_destroy(sofia_session);
mrcp_session_terminate_response(session);
}
else {
mrcp_session_terminate_event(session);
}
}
}
static void mrcp_sofia_on_state_change(
int status,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
int ss_state = nua_callstate_init;
tl_gets(tags,
NUTAG_CALLSTATE_REF(ss_state),
TAG_END());
apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State "APT_PTR_FMT" [%s]",
sofia_session ? MRCP_SESSION_PTR(sofia_session->session) : NULL,
nua_callstate_name(ss_state));
switch(ss_state) {
case nua_callstate_ready:
mrcp_sofia_on_session_ready(status,sofia_agent,nh,sofia_session,sip,tags);
break;
case nua_callstate_terminated:
mrcp_sofia_on_session_terminate(status,sofia_agent,nh,sofia_session,sip,tags);
break;
}
}
static void mrcp_sofia_on_resource_discover(
int status,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
mrcp_session_t *session = sofia_session->session;
if(session) {
const char *remote_sdp_str = NULL;
mrcp_session_descriptor_t *descriptor = NULL;
tl_gets(tags,
SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
TAG_END());
if(remote_sdp_str) {
sdp_parser_t *parser = NULL;
sdp_session_t *sdp = NULL;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP "APT_PTR_FMT"\n%s",
MRCP_SESSION_PTR(session),
remote_sdp_str);
parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
sdp = sdp_session(parser);
descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,session->pool);
sdp_parser_free(parser);
}
mrcp_session_discover_response(session,descriptor);
}
}
/** This callback will be called by SIP stack to process incoming events */
static void mrcp_sofia_event_callback(
nua_event_t nua_event,
int status,
char const *phrase,
nua_t *nua,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive SIP Event [%s] Status %d %s",
nua_event_name(nua_event),status,phrase);
switch(nua_event) {
case nua_i_state:
mrcp_sofia_on_state_change(status,sofia_agent,nh,sofia_session,sip,tags);
break;
case nua_r_options:
mrcp_sofia_on_resource_discover(status,sofia_agent,nh,sofia_session,sip,tags);
break;
case nua_r_shutdown:
/* break main loop of sofia thread */
su_root_break(sofia_agent->root);
break;
default:
break;
}
}
@@ -0,0 +1,434 @@
/*
* Copyright 2008 Arsen Chaloyan
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
typedef struct mrcp_sofia_agent_t mrcp_sofia_agent_t;
#define NUA_MAGIC_T mrcp_sofia_agent_t
typedef struct mrcp_sofia_session_t mrcp_sofia_session_t;
#define NUA_HMAGIC_T mrcp_sofia_session_t
#include <apr_general.h>
#include <sofia-sip/su.h>
#include <sofia-sip/nua.h>
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sdp.h>
#include <sofia-sip/sofia_features.h>
#include "mrcp_sofiasip_server_agent.h"
#include "mrcp_session.h"
#include "mrcp_session_descriptor.h"
#include "mrcp_sdp.h"
#include "apt_log.h"
#define SOFIA_TASK_NAME "SofiaSIP Agent"
struct mrcp_sofia_agent_t {
mrcp_sig_agent_t *sig_agent;
mrcp_sofia_server_config_t *config;
char *sip_contact_str;
char *sip_bind_str;
su_root_t *root;
nua_t *nua;
};
struct mrcp_sofia_session_t {
mrcp_session_t *session;
su_home_t *home;
nua_handle_t *nh;
};
/* Task Interface */
static void mrcp_sofia_task_initialize(apt_task_t *task);
static apt_bool_t mrcp_sofia_task_run(apt_task_t *task);
static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task);
/* MRCP Signaling Interface */
static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
static apt_bool_t mrcp_sofia_on_session_terminate(mrcp_session_t *session);
static const mrcp_session_response_vtable_t session_response_vtable = {
mrcp_sofia_on_session_answer,
mrcp_sofia_on_session_terminate
};
static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_server_config_t *config, apr_pool_t *pool);
static void mrcp_sofia_event_callback( nua_event_t nua_event,
int status,
char const *phrase,
nua_t *nua,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[]);
/** Create Sofia-SIP Signaling Agent */
MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(mrcp_sofia_server_config_t *config, apr_pool_t *pool)
{
apt_task_t *task;
apt_task_vtable_t *vtable;
mrcp_sofia_agent_t *sofia_agent;
sofia_agent = apr_palloc(pool,sizeof(mrcp_sofia_agent_t));
sofia_agent->sig_agent = mrcp_signaling_agent_create(sofia_agent,MRCP_VERSION_2,pool);
sofia_agent->config = config;
sofia_agent->root = NULL;
sofia_agent->nua = NULL;
if(mrcp_sofia_config_validate(sofia_agent,config,pool) == FALSE) {
return NULL;
}
task = apt_task_create(sofia_agent,NULL,pool);
if(!task) {
return NULL;
}
apt_task_name_set(task,SOFIA_TASK_NAME);
vtable = apt_task_vtable_get(task);
if(vtable) {
vtable->on_pre_run = mrcp_sofia_task_initialize;
vtable->run = mrcp_sofia_task_run;
vtable->terminate = mrcp_sofia_task_terminate;
}
sofia_agent->sig_agent->task = task;
apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "SOFIA_TASK_NAME" ["SOFIA_SIP_VERSION"] %s:%hu %s",
config->local_ip,
config->local_port,
config->transport ? config->transport : "");
return sofia_agent->sig_agent;
}
/** Allocate Sofia-SIP config */
MRCP_DECLARE(mrcp_sofia_server_config_t*) mrcp_sofiasip_server_config_alloc(apr_pool_t *pool)
{
mrcp_sofia_server_config_t *config = apr_palloc(pool,sizeof(mrcp_sofia_server_config_t));
config->local_ip = NULL;
config->ext_ip = NULL;
config->local_port = 0;
config->user_name = NULL;
config->user_agent_name = NULL;
config->origin = NULL;
config->transport = NULL;
config->force_destination = FALSE;
return config;
}
static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_server_config_t *config, apr_pool_t *pool)
{
const char *local_ip = config->ext_ip ? config->ext_ip : config->local_ip;
sofia_agent->config = config;
sofia_agent->sip_contact_str = apr_psprintf(pool,"sip:%s:%d",local_ip,config->local_port);
if(config->transport) {
sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d;transport=%s",
config->local_ip,
config->local_port,
config->transport);
}
else {
sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d",
config->local_ip,
config->local_port);
}
return TRUE;
}
static void mrcp_sofia_task_initialize(apt_task_t *task)
{
mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
/* Initialize Sofia-SIP library and create event loop */
su_init();
sofia_agent->root = su_root_create(NULL);
/* Create a user agent instance. The stack will call the 'event_callback()'
* callback when events such as succesful registration to network,
* an incoming call, etc, occur.
*/
sofia_agent->nua = nua_create(
sofia_agent->root, /* Event loop */
mrcp_sofia_event_callback, /* Callback for processing events */
sofia_agent, /* Additional data to pass to callback */
NUTAG_URL(sofia_agent->sip_bind_str), /* Address to bind to */
TAG_END()); /* Last tag should always finish the sequence */
if(sofia_agent->nua) {
nua_set_params(
sofia_agent->nua,
NUTAG_AUTOANSWER(0),
NUTAG_APPL_METHOD("OPTIONS"),
SIPTAG_USER_AGENT_STR(sofia_agent->config->user_agent_name),
TAG_END());
}
}
static apt_bool_t mrcp_sofia_task_run(apt_task_t *task)
{
mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
if(sofia_agent->nua) {
/* Run event loop */
su_root_run(sofia_agent->root);
/* Destroy allocated resources */
nua_destroy(sofia_agent->nua);
sofia_agent->nua = NULL;
}
su_root_destroy(sofia_agent->root);
sofia_agent->root = NULL;
su_deinit();
apt_task_child_terminate(task);
return TRUE;
}
static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task)
{
mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
if(sofia_agent->nua) {
apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Send Shutdown Signal to NUA");
nua_shutdown(sofia_agent->nua);
}
return TRUE;
}
static mrcp_sofia_session_t* mrcp_sofia_session_create(mrcp_sofia_agent_t *sofia_agent, nua_handle_t *nh)
{
mrcp_sofia_session_t *sofia_session;
mrcp_session_t* session = sofia_agent->sig_agent->create_server_session(sofia_agent->sig_agent);
if(!session) {
return NULL;
}
session->response_vtable = &session_response_vtable;
session->event_vtable = NULL;
sofia_session = apr_palloc(session->pool,sizeof(mrcp_sofia_session_t));
sofia_session->home = su_home_new(sizeof(*sofia_session->home));
sofia_session->session = session;
session->obj = sofia_session;
nua_handle_bind(nh, sofia_session);
sofia_session->nh = nh;
return sofia_session;
}
static int sip_status_get(mrcp_session_status_e status)
{
switch (status) {
case MRCP_SESSION_STATUS_OK:
return 200;
case MRCP_SESSION_STATUS_NO_SUCH_RESOURCE:
return 404;
case MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE:
return 406;
case MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE:
return 480;
case MRCP_SESSION_STATUS_ERROR:
return 500;
}
return 200;
}
static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
{
mrcp_sofia_session_t *sofia_session = session->obj;
mrcp_sofia_agent_t *sofia_agent = session->signaling_agent->obj;
const char *local_sdp_str = NULL;
char sdp_str[2048];
if(!sofia_agent || !sofia_session || !sofia_session->nh) {
return FALSE;
}
if(descriptor->status != MRCP_SESSION_STATUS_OK) {
int status = sip_status_get(descriptor->status);
nua_respond(sofia_session->nh, status, sip_status_phrase(status),
SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
TAG_END());
return TRUE;
}
if(sofia_agent->config->origin) {
apt_string_set(&descriptor->origin,sofia_agent->config->origin);
}
if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,FALSE) > 0) {
local_sdp_str = sdp_str;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP\n%s", local_sdp_str);
}
nua_respond(sofia_session->nh, SIP_200_OK,
SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
NUTAG_AUTOANSWER(0),
TAG_END());
return TRUE;
}
static apt_bool_t mrcp_sofia_on_session_terminate(mrcp_session_t *session)
{
mrcp_sofia_session_t *sofia_session = session->obj;
if(sofia_session) {
if(sofia_session->nh) {
nua_handle_bind(sofia_session->nh, NULL);
nua_handle_destroy(sofia_session->nh);
}
if(sofia_session->home) {
su_home_unref(sofia_session->home);
sofia_session->home = NULL;
}
sofia_session->session = NULL;
}
apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Session "APT_SID_FMT, MRCP_SESSION_SID(session));
mrcp_session_destroy(session);
return TRUE;
}
static void mrcp_sofia_on_call_receive(mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
mrcp_session_descriptor_t *descriptor = NULL;
tl_gets(tags,
NUTAG_OFFER_RECV_REF(offer_recv),
NUTAG_ANSWER_RECV_REF(answer_recv),
NUTAG_OFFER_SENT_REF(offer_sent),
NUTAG_ANSWER_SENT_REF(answer_sent),
SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
TAG_END());
if(!sofia_session) {
sofia_session = mrcp_sofia_session_create(sofia_agent,nh);
if(!sofia_session) {
nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
return;
}
}
if(remote_sdp_str) {
sdp_parser_t *parser = NULL;
sdp_session_t *sdp = NULL;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP\n%s", remote_sdp_str);
parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
sdp = sdp_session(parser);
descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,sofia_session->session->pool);
sdp_parser_free(parser);
}
if(!descriptor) {
nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
return;
}
mrcp_session_offer(sofia_session->session,descriptor);
}
static void mrcp_sofia_on_call_terminate(mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
if(sofia_session) {
mrcp_session_terminate_request(sofia_session->session);
}
}
static void mrcp_sofia_on_state_change(mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
int ss_state = nua_callstate_init;
tl_gets(tags,
NUTAG_CALLSTATE_REF(ss_state),
TAG_END());
apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State [%s]", nua_callstate_name(ss_state));
switch(ss_state) {
case nua_callstate_received:
mrcp_sofia_on_call_receive(sofia_agent,nh,sofia_session,sip,tags);
break;
case nua_callstate_terminated:
mrcp_sofia_on_call_terminate(sofia_agent,nh,sofia_session,sip,tags);
break;
}
}
static void mrcp_sofia_on_resource_discover(mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
char sdp_str[2048];
char *local_sdp_str = NULL;
const char *ip = sofia_agent->config->ext_ip ?
sofia_agent->config->ext_ip : sofia_agent->config->local_ip;
if(sdp_resource_discovery_string_generate(ip,sofia_agent->config->origin,sdp_str,sizeof(sdp_str)) > 0) {
local_sdp_str = sdp_str;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP\n[%s]\n", local_sdp_str);
}
nua_respond(nh, SIP_200_OK,
NUTAG_WITH_CURRENT(sofia_agent->nua),
SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
TAG_END());
}
/** This callback will be called by SIP stack to process incoming events */
static void mrcp_sofia_event_callback( nua_event_t nua_event,
int status,
char const *phrase,
nua_t *nua,
mrcp_sofia_agent_t *sofia_agent,
nua_handle_t *nh,
mrcp_sofia_session_t *sofia_session,
sip_t const *sip,
tagi_t tags[])
{
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive SIP Event [%s] Status %d %s",nua_event_name(nua_event),status,phrase);
switch(nua_event) {
case nua_i_state:
mrcp_sofia_on_state_change(sofia_agent,nh,sofia_session,sip,tags);
break;
case nua_i_options:
mrcp_sofia_on_resource_discover(sofia_agent,nh,sofia_session,sip,tags);
break;
case nua_r_shutdown:
/* break main loop of sofia thread */
su_root_break(sofia_agent->root);
break;
default:
break;
}
}