spring cleaning 2

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4796 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2007-03-29 22:34:40 +00:00
parent 3a54126261
commit e6a60a20bc
25 changed files with 9878 additions and 0 deletions

View File

@ -0,0 +1,149 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* switch_core.h -- Core Library Private Data (not to be installed into the system)
* If the last line didn't make sense, stop reading this file, go away!,
* this file does not exist!!!!
*
*/
#ifndef WIN32
#include <switch_private.h>
#endif
/* for apr_pool_create and apr_pool_destroy */
/* functions only used in this file so not exposed */
#include <apr_pools.h>
/* for apr_hash_make, apr_hash_pool_get, apr_hash_set */
/* functions only used in this file so not exposed */
#include <apr_hash.h>
/* for apr_pvsprintf */
/* function only used in this file so not exposed */
#include <apr_strings.h>
/* for apr_initialize and apr_terminate */
/* function only used in this file so not exposed */
#include <apr_general.h>
#include <apr_portable.h>
typedef apr_os_thread_t switch_thread_id_t;
#define switch_thread_self apr_os_thread_current
#ifdef HAVE_MLOCKALL
#include <sys/mman.h>
#endif
/* #define DEBUG_ALLOC */
#define DO_EVENTS
#ifdef CRASH_PROT
#define __CP "ENABLED"
#else
#define __CP "DISABLED"
#endif
#define SWITCH_EVENT_QUEUE_LEN 256
#define SWITCH_MESSAGE_QUEUE_LEN 256
#define SWITCH_SQL_QUEUE_LEN 2000
#define SWITCH_BUFFER_BLOCK_FRAMES 25
#define SWITCH_BUFFER_START_FRAMES 50
typedef enum {
SSF_NONE = 0,
SSF_DESTROYED = (1 << 0)
} switch_session_flag_t;
struct switch_core_session {
uint32_t id;
char name[80];
switch_session_flag_t flags;
int thread_running;
switch_memory_pool_t *pool;
switch_channel_t *channel;
switch_thread_t *thread;
const switch_endpoint_interface_t *endpoint_interface;
switch_io_event_hooks_t event_hooks;
switch_codec_t *read_codec;
switch_codec_t *write_codec;
switch_buffer_t *raw_write_buffer;
switch_frame_t raw_write_frame;
switch_frame_t enc_write_frame;
uint8_t raw_write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
uint8_t enc_write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_buffer_t *raw_read_buffer;
switch_frame_t raw_read_frame;
switch_frame_t enc_read_frame;
uint8_t raw_read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
uint8_t enc_read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_audio_resampler_t *read_resampler;
switch_audio_resampler_t *write_resampler;
switch_mutex_t *mutex;
switch_thread_cond_t *cond;
switch_thread_rwlock_t *rwlock;
void *streams[SWITCH_MAX_STREAMS];
int stream_count;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
void *private_info;
switch_queue_t *event_queue;
switch_queue_t *message_queue;
switch_queue_t *private_event_queue;
switch_thread_rwlock_t *bug_rwlock;
switch_media_bug_t *bugs;
};
struct switch_media_bug {
switch_buffer_t *raw_write_buffer;
switch_buffer_t *raw_read_buffer;
switch_frame_t *replace_frame_in;
switch_frame_t *replace_frame_out;
switch_media_bug_callback_t callback;
switch_mutex_t *read_mutex;
switch_mutex_t *write_mutex;
switch_core_session_t *session;
void *user_data;
uint32_t flags;
uint8_t ready;
struct switch_media_bug *next;
};
SWITCH_DECLARE(void) switch_core_sqldb_start(switch_memory_pool_t *pool);
SWITCH_DECLARE(void) switch_core_sqldb_stop(void);
SWITCH_DECLARE(void) switch_core_session_init(switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_memory_pool_t *) switch_core_memory_init(void);

View File

@ -0,0 +1,281 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
* switch_core_event_hook.h Core Event Hooks
*
*/
#ifndef SWITCH_EVENT_HOOKS_H
#define SWITCH_EVENT_HOOKS_H
#include <switch.h>
SWITCH_BEGIN_EXTERN_C typedef struct switch_io_event_hooks switch_io_event_hooks_t;
typedef struct switch_io_event_hook_outgoing_channel switch_io_event_hook_outgoing_channel_t;
typedef struct switch_io_event_hook_answer_channel switch_io_event_hook_answer_channel_t;
typedef struct switch_io_event_hook_receive_message switch_io_event_hook_receive_message_t;
typedef struct switch_io_event_hook_receive_event switch_io_event_hook_receive_event_t;
typedef struct switch_io_event_hook_read_frame switch_io_event_hook_read_frame_t;
typedef struct switch_io_event_hook_write_frame switch_io_event_hook_write_frame_t;
typedef struct switch_io_event_hook_kill_channel switch_io_event_hook_kill_channel_t;
typedef struct switch_io_event_hook_waitfor_read switch_io_event_hook_waitfor_read_t;
typedef struct switch_io_event_hook_waitfor_write switch_io_event_hook_waitfor_write_t;
typedef struct switch_io_event_hook_send_dtmf switch_io_event_hook_send_dtmf_t;
typedef struct switch_io_event_hook_state_change switch_io_event_hook_state_change_t;
typedef switch_status_t (*switch_outgoing_channel_hook_t) (switch_core_session_t *, switch_caller_profile_t *,
switch_core_session_t *);
typedef switch_status_t (*switch_answer_channel_hook_t) (switch_core_session_t *);
typedef switch_status_t (*switch_receive_message_hook_t) (switch_core_session_t *, switch_core_session_message_t *);
typedef switch_status_t (*switch_receive_event_hook_t) (switch_core_session_t *, switch_event_t *);
typedef switch_status_t (*switch_read_frame_hook_t) (switch_core_session_t *, switch_frame_t **, int, switch_io_flag_t,
int);
typedef switch_status_t (*switch_write_frame_hook_t) (switch_core_session_t *, switch_frame_t *, int, switch_io_flag_t,
int);
typedef switch_status_t (*switch_kill_channel_hook_t) (switch_core_session_t *, int);
typedef switch_status_t (*switch_waitfor_read_hook_t) (switch_core_session_t *, int, int);
typedef switch_status_t (*switch_waitfor_write_hook_t) (switch_core_session_t *, int, int);
typedef switch_status_t (*switch_send_dtmf_hook_t) (switch_core_session_t *, char *);
typedef switch_status_t (*switch_state_change_hook_t) (switch_core_session_t *);
/*! \brief Node in which to store custom outgoing channel callback hooks */
struct switch_io_event_hook_outgoing_channel {
/*! the outgoing channel callback hook */
switch_outgoing_channel_hook_t outgoing_channel;
struct switch_io_event_hook_outgoing_channel *next;
};
/*! \brief Node in which to store custom answer channel callback hooks */
struct switch_io_event_hook_answer_channel {
/*! the answer channel callback hook */
switch_answer_channel_hook_t answer_channel;
struct switch_io_event_hook_answer_channel *next;
};
/*! \brief Node in which to store custom receive message callback hooks */
struct switch_io_event_hook_receive_message {
/*! the answer channel callback hook */
switch_receive_message_hook_t receive_message;
struct switch_io_event_hook_receive_message *next;
};
/*! \brief Node in which to store custom receive message callback hooks */
struct switch_io_event_hook_receive_event {
/*! the answer channel callback hook */
switch_receive_event_hook_t receive_event;
struct switch_io_event_hook_receive_event *next;
};
/*! \brief Node in which to store custom read frame channel callback hooks */
struct switch_io_event_hook_read_frame {
/*! the read frame channel callback hook */
switch_read_frame_hook_t read_frame;
struct switch_io_event_hook_read_frame *next;
};
/*! \brief Node in which to store custom write_frame channel callback hooks */
struct switch_io_event_hook_write_frame {
/*! the write_frame channel callback hook */
switch_write_frame_hook_t write_frame;
struct switch_io_event_hook_write_frame *next;
};
/*! \brief Node in which to store custom kill channel callback hooks */
struct switch_io_event_hook_kill_channel {
/*! the kill channel callback hook */
switch_kill_channel_hook_t kill_channel;
struct switch_io_event_hook_kill_channel *next;
};
/*! \brief Node in which to store custom waitfor read channel callback hooks */
struct switch_io_event_hook_waitfor_read {
/*! the waitfor read channel callback hook */
switch_waitfor_read_hook_t waitfor_read;
struct switch_io_event_hook_waitfor_read *next;
};
/*! \brief Node in which to store custom waitfor write channel callback hooks */
struct switch_io_event_hook_waitfor_write {
/*! the waitfor write channel callback hook */
switch_waitfor_write_hook_t waitfor_write;
struct switch_io_event_hook_waitfor_write *next;
};
/*! \brief Node in which to store custom send dtmf channel callback hooks */
struct switch_io_event_hook_send_dtmf {
/*! the send dtmf channel callback hook */
switch_send_dtmf_hook_t send_dtmf;
struct switch_io_event_hook_send_dtmf *next;
};
/*! \brief Node in which to store state change callback hooks */
struct switch_io_event_hook_state_change {
/*! the send dtmf channel callback hook */
switch_state_change_hook_t state_change;
struct switch_io_event_hook_state_change *next;
};
/*! \brief A table of lists of io_event_hooks to store the event hooks associated with a session */
struct switch_io_event_hooks {
/*! a list of outgoing channel hooks */
switch_io_event_hook_outgoing_channel_t *outgoing_channel;
/*! a list of answer channel hooks */
switch_io_event_hook_answer_channel_t *answer_channel;
/*! a list of receive message hooks */
switch_io_event_hook_receive_message_t *receive_message;
/*! a list of queue message hooks */
switch_io_event_hook_receive_event_t *receive_event;
/*! a list of read frame hooks */
switch_io_event_hook_read_frame_t *read_frame;
/*! a list of write frame hooks */
switch_io_event_hook_write_frame_t *write_frame;
/*! a list of kill channel hooks */
switch_io_event_hook_kill_channel_t *kill_channel;
/*! a list of wait for read hooks */
switch_io_event_hook_waitfor_read_t *waitfor_read;
/*! a list of wait for write hooks */
switch_io_event_hook_waitfor_write_t *waitfor_write;
/*! a list of send dtmf hooks */
switch_io_event_hook_send_dtmf_t *send_dtmf;
/*! a list of state change hooks */
switch_io_event_hook_state_change_t *state_change;
};
extern switch_io_event_hooks_t switch_core_session_get_event_hooks(switch_core_session_t *session);
///\defgroup shooks Session Hook Callbacks
///\ingroup core1
///\{
/*!
\brief Add an event hook to be executed when a session requests an outgoing extension
\param session session to bind hook to
\param outgoing_channel hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_outgoing_channel(switch_core_session_t *session,
switch_outgoing_channel_hook_t
outgoing_channel);
/*!
\brief Add an event hook to be executed when a session answers a channel
\param session session to bind hook to
\param answer_channel hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_answer_channel(switch_core_session_t *session,
switch_answer_channel_hook_t answer_channel);
/*!
\brief Add an event hook to be executed when a session sends a message
\param session session to bind hook to
\param receive_message hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_receive_message(switch_core_session_t *session,
switch_receive_message_hook_t
receive_message);
/*!
\brief Add an event hook to be executed when a session reads a frame
\param session session to bind hook to
\param read_frame hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_read_frame(switch_core_session_t *session,
switch_read_frame_hook_t read_frame);
/*!
\brief Add an event hook to be executed when a session writes a frame
\param session session to bind hook to
\param write_frame hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_write_frame(switch_core_session_t *session,
switch_write_frame_hook_t write_frame);
/*!
\brief Add an event hook to be executed when a session kills a channel
\param session session to bind hook to
\param kill_channel hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_kill_channel(switch_core_session_t *session,
switch_kill_channel_hook_t kill_channel);
/*!
\brief Add an event hook to be executed when a session waits for a read event
\param session session to bind hook to
\param waitfor_read hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_waitfor_read(switch_core_session_t *session,
switch_waitfor_read_hook_t waitfor_read);
/*!
\brief Add an event hook to be executed when a session waits for a write event
\param session session to bind hook to
\param waitfor_write hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_waitfor_write(switch_core_session_t *session,
switch_waitfor_write_hook_t waitfor_write);
/*!
\brief Add an event hook to be executed when a session sends dtmf
\param session session to bind hook to
\param send_dtmf hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_send_dtmf(switch_core_session_t *session,
switch_send_dtmf_hook_t send_dtmf);
/*!
\brief Add an event hook to be executed when a session receives a state change signal
\param session session to bind hook to
\param state_change hook to bind
\return SWITCH_STATUS_SUCCESS on suceess
*/
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_state_change(switch_core_session_t *session,
switch_answer_channel_hook_t state_change);
///\}
SWITCH_END_EXTERN_C
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/

View File

@ -0,0 +1,107 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* switch_scheduler.h -- Scheduler Engine
*
*/
#ifndef SWITCH_SCHEDULER_H
#define SWITCH_SCHEDULER_H
#include <switch.h>
SWITCH_BEGIN_EXTERN_C
///\defgroup sched1 Scheduler
///\ingroup core1
///\{
struct switch_scheduler_task {
time_t created;
time_t runtime;
uint32_t cmd_id;
char *group;
void *cmd_arg;
uint32_t task_id;
};
/*!
\brief Schedule a task in the future
\param runtime the time in epoch seconds to execute the task.
\param func the callback function to execute when the task is executed.
\param desc an arbitrary description of the task.
\param group a group id tag to link multiple tasks to a single entity.
\param cmd_id an arbitrary index number be used in the callback.
\param cmd_arg user data to be passed to the callback.
\param flags flags to alter behaviour
\return the id of the task
*/
SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
switch_scheduler_func_t func,
char *desc,
char *group,
uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags);
/*!
\brief Delete a scheduled task
\param task_id the id of the task
\return SWITCH_STATUS_SUCCESS if the task was deleted.
*/
SWITCH_DECLARE(switch_status_t) switch_scheduler_del_task_id(uint32_t task_id);
/*!
\brief Delete a scheduled task based on the group name
\param group the group name
\return SWITCH_STATUS_SUCCESS if any tasks were deleted
*/
SWITCH_DECLARE(switch_status_t) switch_scheduler_del_task_group(char *group);
/*!
\brief Start the scheduler system
*/
SWITCH_DECLARE(void) switch_scheduler_task_thread_start(void);
/*!
\brief Stop the scheduler system
*/
SWITCH_DECLARE(void) switch_scheduler_task_thread_stop(void);
///\}
SWITCH_END_EXTERN_C
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/

139
src/switch_core_asr.c Normal file
View File

@ -0,0 +1,139 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_asr.c -- Main Core Library (Speech Detection Interface)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_asr_open(switch_asr_handle_t *ah,
char *module_name,
char *codec,
int rate,
char *dest, switch_asr_flag_t *flags, switch_memory_pool_t *pool)
{
switch_status_t status;
assert(ah != NULL);
if ((ah->asr_interface = switch_loadable_module_get_asr_interface(module_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid asr module [%s]!\n", module_name);
return SWITCH_STATUS_GENERR;
}
ah->flags = *flags;
if (pool) {
ah->memory_pool = pool;
} else {
if ((status = switch_core_new_memory_pool(&ah->memory_pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_set_flag(ah, SWITCH_ASR_FLAG_FREE_POOL);
}
ah->rate = rate;
ah->name = switch_core_strdup(ah->memory_pool, module_name);
return ah->asr_interface->asr_open(ah, codec, rate, dest, flags);
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_load_grammar(switch_asr_handle_t *ah, char *grammar, char *path)
{
char *epath = NULL;
switch_status_t status;
assert(ah != NULL);
if (*path != '/') {
epath = switch_mprintf("%s%s%s", SWITCH_GLOBAL_dirs.grammar_dir, SWITCH_PATH_SEPARATOR, path);
path = epath;
}
status = ah->asr_interface->asr_load_grammar(ah, grammar, path);
switch_safe_free(epath);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_unload_grammar(switch_asr_handle_t *ah, char *grammar)
{
switch_status_t status;
assert(ah != NULL);
status = ah->asr_interface->asr_unload_grammar(ah, grammar);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_pause(switch_asr_handle_t *ah)
{
assert(ah != NULL);
return ah->asr_interface->asr_pause(ah);
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_resume(switch_asr_handle_t *ah)
{
assert(ah != NULL);
return ah->asr_interface->asr_resume(ah);
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
{
assert(ah != NULL);
return ah->asr_interface->asr_close(ah, flags);
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len,
switch_asr_flag_t *flags)
{
assert(ah != NULL);
return ah->asr_interface->asr_feed(ah, data, len, flags);
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
{
assert(ah != NULL);
return ah->asr_interface->asr_check_results(ah, flags);
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_get_results(switch_asr_handle_t *ah, char **xmlstr,
switch_asr_flag_t *flags)
{
assert(ah != NULL);
return ah->asr_interface->asr_get_results(ah, xmlstr, flags);
}

253
src/switch_core_codec.c Normal file
View File

@ -0,0 +1,253 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_codec.c -- Main Core Library (codec functions)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_codec(switch_core_session_t *session,
switch_codec_t *codec)
{
switch_event_t *event;
assert(session != NULL);
if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(session->channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-name", "%s",
codec->implementation->iananame);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-rate", "%d",
codec->implementation->samples_per_second);
switch_event_fire(&event);
}
session->read_codec = codec;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_codec_t *) switch_core_session_get_read_codec(switch_core_session_t *session)
{
return session->read_codec;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_set_write_codec(switch_core_session_t *session,
switch_codec_t *codec)
{
switch_event_t *event;
assert(session != NULL);
if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(session->channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-write-codec-name", "%s",
codec->implementation->iananame);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-write-codec-rate", "%d",
codec->implementation->samples_per_second);
switch_event_fire(&event);
}
session->write_codec = codec;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_codec_t *) switch_core_session_get_write_codec(switch_core_session_t *session)
{
return session->write_codec;
}
SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec, char *codec_name, char *fmtp,
uint32_t rate, int ms, int channels, uint32_t flags,
const switch_codec_settings_t *codec_settings,
switch_memory_pool_t *pool)
{
const switch_codec_interface_t *codec_interface;
const switch_codec_implementation_t *iptr, *implementation = NULL;
char *mode = fmtp;
assert(codec != NULL);
assert(codec_name != NULL);
memset(codec, 0, sizeof(*codec));
if ((codec_interface = switch_loadable_module_get_codec_interface(codec_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid codec %s!\n", codec_name);
return SWITCH_STATUS_GENERR;
}
if (!strcasecmp(codec_name, "ilbc") && mode && strncasecmp(mode, "mode=", 5)) {
int mms;
mode += 5;
if (mode) {
mms = atoi(mode);
if (mms > 0 && mms < 120) {
ms = mms;
}
}
}
/* If no specific codec interval is requested opt for 20ms above all else because lots of stuff assumes it */
if (!ms) {
for (iptr = codec_interface->implementations; iptr; iptr = iptr->next) {
if ((!rate || rate == iptr->samples_per_second) &&
(20 == (iptr->microseconds_per_frame / 1000)) && (!channels || channels == iptr->number_of_channels)) {
implementation = iptr;
goto found;
}
}
}
/* Either looking for a specific interval or there was no interval specified and there wasn't one @20ms available */
for (iptr = codec_interface->implementations; iptr; iptr = iptr->next) {
if ((!rate || rate == iptr->samples_per_second) &&
(!ms || ms == (iptr->microseconds_per_frame / 1000)) &&
(!channels || channels == iptr->number_of_channels)) {
implementation = iptr;
break;
}
}
found:
if (implementation) {
switch_status_t status;
codec->codec_interface = codec_interface;
codec->implementation = implementation;
codec->flags = flags;
if (pool) {
codec->memory_pool = pool;
} else {
if ((status = switch_core_new_memory_pool(&codec->memory_pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_set_flag(codec, SWITCH_CODEC_FLAG_FREE_POOL);
}
if (fmtp) {
codec->fmtp_in = switch_core_strdup(codec->memory_pool, fmtp);
}
implementation->init(codec, flags, codec_settings);
return SWITCH_STATUS_SUCCESS;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Codec %s Exists but not at the desired implementation. %dhz %dms\n", codec_name, rate, ms);
}
return SWITCH_STATUS_NOTIMPL;
}
SWITCH_DECLARE(switch_status_t) switch_core_codec_encode(switch_codec_t *codec,
switch_codec_t *other_codec,
void *decoded_data,
uint32_t decoded_data_len,
uint32_t decoded_rate,
void *encoded_data,
uint32_t * encoded_data_len, uint32_t * encoded_rate,
unsigned int *flag)
{
assert(codec != NULL);
assert(encoded_data != NULL);
assert(decoded_data != NULL);
if (!codec->implementation) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
if (!switch_test_flag(codec, SWITCH_CODEC_FLAG_ENCODE)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec's encoder is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
return codec->implementation->encode(codec,
other_codec,
decoded_data,
decoded_data_len,
decoded_rate, encoded_data, encoded_data_len, encoded_rate, flag);
}
SWITCH_DECLARE(switch_status_t) switch_core_codec_decode(switch_codec_t *codec,
switch_codec_t *other_codec,
void *encoded_data,
uint32_t encoded_data_len,
uint32_t encoded_rate,
void *decoded_data,
uint32_t * decoded_data_len,
uint32_t * decoded_rate, unsigned int *flag)
{
assert(codec != NULL);
assert(encoded_data != NULL);
assert(decoded_data != NULL);
if (!codec->implementation) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
if (!switch_test_flag(codec, SWITCH_CODEC_FLAG_DECODE)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec's decoder is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
return codec->implementation->decode(codec,
other_codec,
encoded_data,
encoded_data_len,
encoded_rate, decoded_data, decoded_data_len, decoded_rate, flag);
}
SWITCH_DECLARE(switch_status_t) switch_core_codec_destroy(switch_codec_t *codec)
{
assert(codec != NULL);
if (!codec->implementation) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
codec->implementation->destroy(codec);
if (switch_test_flag(codec, SWITCH_CODEC_FLAG_FREE_POOL)) {
switch_core_destroy_memory_pool(&codec->memory_pool);
}
return SWITCH_STATUS_SUCCESS;
}

107
src/switch_core_directory.c Normal file
View File

@ -0,0 +1,107 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_directory.c -- Main Core Library (Directory Interface)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_directory_open(switch_directory_handle_t *dh,
char *module_name,
char *source,
char *dsn, char *passwd, switch_memory_pool_t *pool)
{
switch_status_t status;
if ((dh->directory_interface = switch_loadable_module_get_directory_interface(module_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid directory module [%s]!\n", module_name);
return SWITCH_STATUS_GENERR;
}
if (pool) {
dh->memory_pool = pool;
} else {
if ((status = switch_core_new_memory_pool(&dh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_set_flag(dh, SWITCH_DIRECTORY_FLAG_FREE_POOL);
}
return dh->directory_interface->directory_open(dh, source, dsn, passwd);
}
SWITCH_DECLARE(switch_status_t) switch_core_directory_query(switch_directory_handle_t *dh, char *base, char *query)
{
return dh->directory_interface->directory_query(dh, base, query);
}
SWITCH_DECLARE(switch_status_t) switch_core_directory_next(switch_directory_handle_t *dh)
{
return dh->directory_interface->directory_next(dh);
}
SWITCH_DECLARE(switch_status_t) switch_core_directory_next_pair(switch_directory_handle_t *dh, char **var, char **val)
{
return dh->directory_interface->directory_next_pair(dh, var, val);
}
SWITCH_DECLARE(switch_status_t) switch_core_directory_close(switch_directory_handle_t *dh)
{
return dh->directory_interface->directory_close(dh);
}
SWITCH_DECLARE(switch_status_t) switch_core_speech_open(switch_speech_handle_t *sh,
char *module_name,
char *voice_name,
unsigned int rate,
switch_speech_flag_t *flags, switch_memory_pool_t *pool)
{
switch_status_t status;
if ((sh->speech_interface = switch_loadable_module_get_speech_interface(module_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid speech module [%s]!\n", module_name);
return SWITCH_STATUS_GENERR;
}
switch_copy_string(sh->engine, module_name, sizeof(sh->engine));
sh->flags = *flags;
if (pool) {
sh->memory_pool = pool;
} else {
if ((status = switch_core_new_memory_pool(&sh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_set_flag(sh, SWITCH_SPEECH_FLAG_FREE_POOL);
}
sh->rate = rate;
sh->name = switch_core_strdup(pool, module_name);
return sh->speech_interface->speech_open(sh, voice_name, rate, flags);
}

View File

@ -0,0 +1,239 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
* switch_core_event_hook.c Core Event Hooks
*
*/
#include "switch.h"
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_outgoing(switch_core_session_t *session,
switch_outgoing_channel_hook_t outgoing_channel)
{
switch_io_event_hook_outgoing_channel_t *hook, *ptr;
assert(outgoing_channel != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->outgoing_channel = outgoing_channel;
if (!session->event_hooks.outgoing_channel) {
session->event_hooks.outgoing_channel = hook;
} else {
for (ptr = session->event_hooks.outgoing_channel; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_answer_channel(switch_core_session_t *session,
switch_answer_channel_hook_t answer_channel)
{
switch_io_event_hook_answer_channel_t *hook, *ptr;
assert(answer_channel != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->answer_channel = answer_channel;
if (!session->event_hooks.answer_channel) {
session->event_hooks.answer_channel = hook;
} else {
for (ptr = session->event_hooks.answer_channel; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_state_change(switch_core_session_t *session,
switch_answer_channel_hook_t state_change)
{
switch_io_event_hook_state_change_t *hook, *ptr;
assert(state_change != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->state_change = state_change;
if (!session->event_hooks.state_change) {
session->event_hooks.state_change = hook;
} else {
for (ptr = session->event_hooks.state_change; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_read_frame(switch_core_session_t *session,
switch_read_frame_hook_t read_frame)
{
switch_io_event_hook_read_frame_t *hook, *ptr;
assert(read_frame != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->read_frame = read_frame;
if (!session->event_hooks.read_frame) {
session->event_hooks.read_frame = hook;
} else {
for (ptr = session->event_hooks.read_frame; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_write_frame(switch_core_session_t *session,
switch_write_frame_hook_t write_frame)
{
switch_io_event_hook_write_frame_t *hook, *ptr;
assert(write_frame != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->write_frame = write_frame;
if (!session->event_hooks.write_frame) {
session->event_hooks.write_frame = hook;
} else {
for (ptr = session->event_hooks.write_frame; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_kill_channel(switch_core_session_t *session,
switch_kill_channel_hook_t kill_channel)
{
switch_io_event_hook_kill_channel_t *hook, *ptr;
assert(kill_channel != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->kill_channel = kill_channel;
if (!session->event_hooks.kill_channel) {
session->event_hooks.kill_channel = hook;
} else {
for (ptr = session->event_hooks.kill_channel; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_waitfor_read(switch_core_session_t *session,
switch_waitfor_read_hook_t waitfor_read)
{
switch_io_event_hook_waitfor_read_t *hook, *ptr;
assert(waitfor_read != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->waitfor_read = waitfor_read;
if (!session->event_hooks.waitfor_read) {
session->event_hooks.waitfor_read = hook;
} else {
for (ptr = session->event_hooks.waitfor_read; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_waitfor_write(switch_core_session_t *session,
switch_waitfor_write_hook_t waitfor_write)
{
switch_io_event_hook_waitfor_write_t *hook, *ptr;
assert(waitfor_write != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->waitfor_write = waitfor_write;
if (!session->event_hooks.waitfor_write) {
session->event_hooks.waitfor_write = hook;
} else {
for (ptr = session->event_hooks.waitfor_write; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_send_dtmf(switch_core_session_t *session,
switch_send_dtmf_hook_t send_dtmf)
{
switch_io_event_hook_send_dtmf_t *hook, *ptr;
assert(send_dtmf != NULL);
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
hook->send_dtmf = send_dtmf;
if (!session->event_hooks.send_dtmf) {
session->event_hooks.send_dtmf = hook;
} else {
for (ptr = session->event_hooks.send_dtmf; ptr && ptr->next; ptr = ptr->next);
ptr->next = hook;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}

143
src/switch_core_file.c Normal file
View File

@ -0,0 +1,143 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_file.c -- Main Core Library (File I/O Functions)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_file_open(switch_file_handle_t *fh,
char *file_path,
uint8_t channels,
uint32_t rate, unsigned int flags, switch_memory_pool_t *pool)
{
char *ext;
switch_status_t status;
char stream_name[128] = "";
char *rhs = NULL;
if ((rhs = strstr(file_path, SWITCH_URL_SEPARATOR))) {
switch_copy_string(stream_name, file_path, (rhs + 1) - file_path);
ext = stream_name;
file_path = rhs + 3;
} else {
if ((ext = strrchr(file_path, '.')) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n");
return SWITCH_STATUS_FALSE;
}
ext++;
}
if ((fh->file_interface = switch_loadable_module_get_file_interface(ext)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid file format [%s]!\n", ext);
return SWITCH_STATUS_GENERR;
}
fh->flags = flags;
if (pool) {
fh->memory_pool = pool;
} else {
if ((status = switch_core_new_memory_pool(&fh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_set_flag(fh, SWITCH_FILE_FLAG_FREE_POOL);
}
if (rhs) {
fh->handler = switch_core_strdup(fh->memory_pool, rhs);
}
if (rate) {
fh->samplerate = rate;
} else {
rate = 8000;
}
if (channels) {
fh->channels = channels;
} else {
fh->channels = 1;
}
if ((status = fh->file_interface->file_open(fh, file_path)) == SWITCH_STATUS_SUCCESS) {
switch_set_flag(fh, SWITCH_FILE_OPEN);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, void *data, switch_size_t *len)
{
assert(fh != NULL);
return fh->file_interface->file_read(fh, data, len);
}
SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, void *data, switch_size_t *len)
{
assert(fh != NULL);
return fh->file_interface->file_write(fh, data, len);
}
SWITCH_DECLARE(switch_status_t) switch_core_file_seek(switch_file_handle_t *fh, unsigned int *cur_pos, int64_t samples,
int whence)
{
assert(fh != NULL);
switch_set_flag(fh, SWITCH_FILE_SEEK);
return fh->file_interface->file_seek(fh, cur_pos, samples, whence);
}
SWITCH_DECLARE(switch_status_t) switch_core_file_set_string(switch_file_handle_t *fh, switch_audio_col_t col,
const char *string)
{
assert(fh != NULL);
return fh->file_interface->file_set_string(fh, col, string);
}
SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(switch_file_handle_t *fh, switch_audio_col_t col,
const char **string)
{
assert(fh != NULL);
return fh->file_interface->file_get_string(fh, col, string);
}
SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh)
{
switch_clear_flag(fh, SWITCH_FILE_OPEN);
return fh->file_interface->file_close(fh);
}

75
src/switch_core_hash.c Normal file
View File

@ -0,0 +1,75 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_hash.c -- Main Core Library (hash functions)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_hash_init(switch_hash_t **hash, switch_memory_pool_t *pool)
{
assert(pool != NULL);
if ((*hash = apr_hash_make(pool)) != 0) {
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_GENERR;
}
SWITCH_DECLARE(switch_status_t) switch_core_hash_destroy(switch_hash_t *hash)
{
assert(hash != NULL);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_dup(switch_hash_t *hash, const char *key, const void *data)
{
apr_hash_set(hash, switch_core_strdup(apr_hash_pool_get(hash), key), APR_HASH_KEY_STRING, data);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_hash_insert(switch_hash_t *hash, const char *key, const void *data)
{
apr_hash_set(hash, key, APR_HASH_KEY_STRING, data);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_hash_delete(switch_hash_t *hash, const char *key)
{
apr_hash_set(hash, key, APR_HASH_KEY_STRING, NULL);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void *) switch_core_hash_find(switch_hash_t *hash, const char *key)
{
return apr_hash_get(hash, key, APR_HASH_KEY_STRING);
}

777
src/switch_core_io.c Normal file
View File

@ -0,0 +1,777 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_io.c -- Main Core Library (Media I/O)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_session_t *session, switch_frame_t **frame,
int timeout, int stream_id)
{
switch_io_event_hook_read_frame_t *ptr;
switch_status_t status;
int need_codec, perfect, do_bugs = 0;
unsigned int flag = 0;
top:
status = SWITCH_STATUS_FALSE;
need_codec = perfect = 0;
assert(session != NULL);
*frame = NULL;
if (switch_channel_test_flag(session->channel, CF_HOLD)) {
status = SWITCH_STATUS_BREAK;
goto done;
}
if (session->endpoint_interface->io_routines->read_frame) {
if ((status = session->endpoint_interface->io_routines->read_frame(session,
frame,
timeout,
SWITCH_IO_FLAG_NOOP,
stream_id)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.read_frame; ptr; ptr = ptr->next) {
if ((status =
ptr->read_frame(session, frame, timeout, SWITCH_IO_FLAG_NOOP,
stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
if (status != SWITCH_STATUS_SUCCESS) {
goto done;
}
if (!(*frame)) {
goto done;
}
assert(session != NULL);
assert(*frame != NULL);
if (switch_test_flag(*frame, SFF_CNG)) {
status = SWITCH_STATUS_SUCCESS;
goto done;
}
if ((session->read_codec && (*frame)->codec
&& session->read_codec->implementation != (*frame)->codec->implementation)) {
need_codec = TRUE;
}
if (session->read_codec && !(*frame)->codec) {
need_codec = TRUE;
}
if (!session->read_codec && (*frame)->codec) {
status = SWITCH_STATUS_FALSE;
goto done;
}
if (session->bugs && !need_codec) {
do_bugs = 1;
need_codec = 1;
}
if (status == SWITCH_STATUS_SUCCESS && need_codec) {
switch_frame_t *enc_frame, *read_frame = *frame;
if (read_frame->codec) {
session->raw_read_frame.datalen = session->raw_read_frame.buflen;
status = switch_core_codec_decode(read_frame->codec,
session->read_codec,
read_frame->data,
read_frame->datalen,
session->read_codec->implementation->samples_per_second,
session->raw_read_frame.data,
&session->raw_read_frame.datalen, &session->raw_read_frame.rate, &flag);
switch (status) {
case SWITCH_STATUS_RESAMPLE:
if (!session->read_resampler) {
if (switch_resample_create(&session->read_resampler,
read_frame->codec->implementation->samples_per_second,
read_frame->codec->implementation->bytes_per_frame * 20,
session->read_codec->implementation->samples_per_second,
session->read_codec->implementation->bytes_per_frame * 20,
session->pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to allocate resampler\n");
status = SWITCH_STATUS_FALSE;
goto done;
}
}
case SWITCH_STATUS_SUCCESS:
session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
session->raw_read_frame.rate = read_frame->rate;
session->raw_read_frame.timestamp = read_frame->timestamp;
read_frame = &session->raw_read_frame;
break;
case SWITCH_STATUS_NOOP:
status = SWITCH_STATUS_SUCCESS;
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s decoder error!\n",
session->read_codec->codec_interface->interface_name);
goto done;
}
}
if (session->read_resampler) {
short *data = read_frame->data;
session->read_resampler->from_len =
switch_short_to_float(data, session->read_resampler->from, (int) read_frame->datalen / 2);
session->read_resampler->to_len =
switch_resample_process(session->read_resampler, session->read_resampler->from,
session->read_resampler->from_len, session->read_resampler->to,
session->read_resampler->to_size, 0);
switch_float_to_short(session->read_resampler->to, data, read_frame->datalen);
read_frame->samples = session->read_resampler->to_len;
read_frame->datalen = session->read_resampler->to_len * 2;
read_frame->rate = session->read_resampler->to_rate;
}
if (session->bugs) {
switch_media_bug_t *bp, *dp, *last = NULL;
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
if (bp->ready && switch_test_flag(bp, SMBF_READ_STREAM)) {
switch_mutex_lock(bp->read_mutex);
switch_buffer_write(bp->raw_read_buffer, read_frame->data, read_frame->datalen);
if (bp->callback) {
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ) == SWITCH_FALSE) {
bp->ready = 0;
if (last) {
last->next = bp->next;
} else {
session->bugs = bp->next;
}
switch_mutex_unlock(bp->read_mutex);
dp = bp;
bp = last;
switch_core_media_bug_close(&dp);
if (!bp) {
break;
}
continue;
}
}
switch_mutex_unlock(bp->read_mutex);
}
last = bp;
}
switch_thread_rwlock_unlock(session->bug_rwlock);
}
if (do_bugs) {
goto done;
}
if (session->read_codec) {
if ((*frame)->datalen == session->read_codec->implementation->bytes_per_frame) {
perfect = TRUE;
} else {
if (!session->raw_read_buffer) {
switch_size_t bytes = session->read_codec->implementation->bytes_per_frame;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Engaging Read Buffer at %u bytes\n",
(uint32_t) bytes);
switch_buffer_create_dynamic(&session->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES,
bytes * SWITCH_BUFFER_START_FRAMES, 0);
}
if (!switch_buffer_write(session->raw_read_buffer, read_frame->data, read_frame->datalen)) {
status = SWITCH_STATUS_MEMERR;
goto done;
}
}
if (perfect
|| switch_buffer_inuse(session->raw_read_buffer) >=
session->read_codec->implementation->bytes_per_frame) {
if (perfect) {
enc_frame = *frame;
session->raw_read_frame.rate = (*frame)->rate;
} else {
session->raw_read_frame.datalen = (uint32_t) switch_buffer_read(session->raw_read_buffer,
session->raw_read_frame.data,
session->read_codec->
implementation->bytes_per_frame);
session->raw_read_frame.rate = session->read_codec->implementation->samples_per_second;
enc_frame = &session->raw_read_frame;
}
session->enc_read_frame.datalen = session->enc_read_frame.buflen;
assert(session->read_codec != NULL);
assert(enc_frame != NULL);
assert(enc_frame->data != NULL);
status = switch_core_codec_encode(session->read_codec,
enc_frame->codec,
enc_frame->data,
enc_frame->datalen,
session->read_codec->implementation->samples_per_second,
session->enc_read_frame.data,
&session->enc_read_frame.datalen,
&session->enc_read_frame.rate, &flag);
switch (status) {
case SWITCH_STATUS_RESAMPLE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "fixme 1\n");
case SWITCH_STATUS_SUCCESS:
session->enc_read_frame.codec = session->read_codec;
session->enc_read_frame.samples =
session->read_codec->implementation->bytes_per_frame / sizeof(int16_t);
session->enc_read_frame.timestamp = read_frame->timestamp;
session->enc_read_frame.payload = session->read_codec->implementation->ianacode;
*frame = &session->enc_read_frame;
break;
case SWITCH_STATUS_NOOP:
session->raw_read_frame.codec = session->read_codec;
session->raw_read_frame.samples = enc_frame->codec->implementation->samples_per_frame;
session->raw_read_frame.timestamp = read_frame->timestamp;
session->raw_read_frame.payload = enc_frame->codec->implementation->ianacode;
*frame = &session->raw_read_frame;
status = SWITCH_STATUS_SUCCESS;
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s encoder error!\n",
session->read_codec->codec_interface->interface_name);
*frame = NULL;
status = SWITCH_STATUS_GENERR;
break;
}
} else {
goto top;
}
}
}
done:
if (!(*frame)) {
status = SWITCH_STATUS_FALSE;
} else {
if (flag & SFF_CNG) {
switch_set_flag((*frame), SFF_CNG);
}
}
return status;
}
static switch_status_t perform_write(switch_core_session_t *session, switch_frame_t *frame, int timeout,
switch_io_flag_t flags, int stream_id)
{
switch_io_event_hook_write_frame_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->endpoint_interface->io_routines->write_frame) {
if ((status =
session->endpoint_interface->io_routines->write_frame(session, frame, timeout, flags,
stream_id)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.write_frame; ptr; ptr = ptr->next) {
if ((status = ptr->write_frame(session, frame, timeout, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_session_t *session, switch_frame_t *frame,
int timeout, int stream_id)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_frame_t *enc_frame = NULL, *write_frame = frame;
unsigned int flag = 0, need_codec = 0, perfect = 0, do_bugs = 0, do_write = 0;
switch_io_flag_t io_flag = SWITCH_IO_FLAG_NOOP;
assert(session != NULL);
assert(frame != NULL);
if (switch_channel_test_flag(session->channel, CF_HOLD)) {
return SWITCH_STATUS_SUCCESS;
}
if (switch_test_flag(frame, SFF_CNG)) {
if (switch_channel_test_flag(session->channel, CF_ACCEPT_CNG)) {
return perform_write(session, frame, timeout, flag, stream_id);
}
return SWITCH_STATUS_SUCCESS;
}
assert(frame->codec != NULL);
if ((session->write_codec && frame->codec && session->write_codec->implementation != frame->codec->implementation)) {
need_codec = TRUE;
}
if (session->write_codec && !frame->codec) {
need_codec = TRUE;
}
if (!session->write_codec && frame->codec) {
return SWITCH_STATUS_FALSE;
}
if (session->bugs && !need_codec) {
do_bugs = 1;
need_codec = 1;
}
if (need_codec) {
if (frame->codec) {
session->raw_write_frame.datalen = session->raw_write_frame.buflen;
status = switch_core_codec_decode(frame->codec,
session->write_codec,
frame->data,
frame->datalen,
session->write_codec->implementation->samples_per_second,
session->raw_write_frame.data,
&session->raw_write_frame.datalen, &session->raw_write_frame.rate, &flag);
switch (status) {
case SWITCH_STATUS_RESAMPLE:
write_frame = &session->raw_write_frame;
if (!session->write_resampler) {
status = switch_resample_create(&session->write_resampler,
frame->codec->implementation->samples_per_second,
frame->codec->implementation->bytes_per_frame * 20,
session->write_codec->implementation->samples_per_second,
session->write_codec->implementation->bytes_per_frame * 20,
session->pool);
if (status != SWITCH_STATUS_SUCCESS) {
goto done;
}
}
break;
case SWITCH_STATUS_SUCCESS:
session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t);
session->raw_write_frame.timestamp = frame->timestamp;
session->raw_write_frame.rate = frame->rate;
write_frame = &session->raw_write_frame;
break;
case SWITCH_STATUS_BREAK:
return SWITCH_STATUS_SUCCESS;
case SWITCH_STATUS_NOOP:
write_frame = frame;
status = SWITCH_STATUS_SUCCESS;
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s decoder error!\n",
frame->codec->codec_interface->interface_name);
return status;
}
}
if (session->write_resampler) {
short *data = write_frame->data;
session->write_resampler->from_len = write_frame->datalen / 2;
switch_short_to_float(data, session->write_resampler->from, session->write_resampler->from_len);
session->write_resampler->to_len = (uint32_t)
switch_resample_process(session->write_resampler, session->write_resampler->from,
session->write_resampler->from_len, session->write_resampler->to,
session->write_resampler->to_size, 0);
switch_float_to_short(session->write_resampler->to, data, session->write_resampler->to_len);
write_frame->samples = session->write_resampler->to_len;
write_frame->datalen = write_frame->samples * 2;
write_frame->rate = session->write_resampler->to_rate;
}
if (session->bugs) {
switch_media_bug_t *bp, *dp, *last = NULL;
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
switch_bool_t ok = SWITCH_TRUE;
if (!bp->ready) {
continue;
}
if (switch_test_flag(bp, SMBF_WRITE_STREAM)) {
switch_mutex_lock(bp->write_mutex);
switch_buffer_write(bp->raw_write_buffer, write_frame->data, write_frame->datalen);
switch_mutex_unlock(bp->write_mutex);
if (bp->callback) {
ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE);
}
} else if (switch_test_flag(bp, SMBF_WRITE_REPLACE)) {
do_bugs = 0;
if (bp->callback) {
bp->replace_frame_in = frame;
bp->replace_frame_out = NULL;
if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_REPLACE)) == SWITCH_TRUE) {
write_frame = bp->replace_frame_out;
}
}
}
if (ok == SWITCH_FALSE) {
bp->ready = 0;
if (last) {
last->next = bp->next;
} else {
session->bugs = bp->next;
}
dp = bp;
bp = last;
switch_core_media_bug_close(&dp);
if (!bp) {
break;
}
continue;
}
last = bp;
}
switch_thread_rwlock_unlock(session->bug_rwlock);
}
if (do_bugs) {
do_write = 1;
write_frame = frame;
goto done;
}
if (session->write_codec) {
if (write_frame->datalen == session->write_codec->implementation->bytes_per_frame) {
perfect = TRUE;
} else {
if (!session->raw_write_buffer) {
switch_size_t bytes = session->write_codec->implementation->bytes_per_frame;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"Engaging Write Buffer at %u bytes to accomodate %u->%u\n",
(uint32_t) bytes,
write_frame->datalen, session->write_codec->implementation->bytes_per_frame);
if ((status = switch_buffer_create_dynamic(&session->raw_write_buffer,
bytes * SWITCH_BUFFER_BLOCK_FRAMES,
bytes * SWITCH_BUFFER_START_FRAMES,
0)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Write Buffer Failed!\n");
return status;
}
}
if (!(switch_buffer_write(session->raw_write_buffer, write_frame->data, write_frame->datalen))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Write Buffer %u bytes Failed!\n",
write_frame->datalen);
return SWITCH_STATUS_MEMERR;
}
}
if (perfect) {
enc_frame = write_frame;
session->enc_write_frame.datalen = session->enc_write_frame.buflen;
status = switch_core_codec_encode(session->write_codec,
frame->codec,
enc_frame->data,
enc_frame->datalen,
session->write_codec->implementation->samples_per_second,
session->enc_write_frame.data,
&session->enc_write_frame.datalen,
&session->enc_write_frame.rate, &flag);
switch (status) {
case SWITCH_STATUS_RESAMPLE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "fixme 2\n");
case SWITCH_STATUS_SUCCESS:
session->enc_write_frame.codec = session->write_codec;
session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
session->enc_write_frame.timestamp = frame->timestamp;
session->enc_write_frame.payload = session->write_codec->implementation->ianacode;
write_frame = &session->enc_write_frame;
break;
case SWITCH_STATUS_NOOP:
enc_frame->codec = session->write_codec;
enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
enc_frame->timestamp = frame->timestamp;
enc_frame->payload = enc_frame->codec->implementation->ianacode;
write_frame = enc_frame;
status = SWITCH_STATUS_SUCCESS;
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s encoder error!\n",
session->read_codec->codec_interface->interface_name);
write_frame = NULL;
return status;
}
if (flag & SFF_CNG) {
switch_set_flag(write_frame, SFF_CNG);
}
status = perform_write(session, write_frame, timeout, io_flag, stream_id);
return status;
} else {
switch_size_t used = switch_buffer_inuse(session->raw_write_buffer);
uint32_t bytes = session->write_codec->implementation->bytes_per_frame;
switch_size_t frames = (used / bytes);
status = SWITCH_STATUS_SUCCESS;
if (!frames) {
return status;
} else {
switch_size_t x;
for (x = 0; x < frames; x++) {
if ((session->raw_write_frame.datalen = (uint32_t)
switch_buffer_read(session->raw_write_buffer, session->raw_write_frame.data, bytes)) != 0) {
enc_frame = &session->raw_write_frame;
session->raw_write_frame.rate = session->write_codec->implementation->samples_per_second;
session->enc_write_frame.datalen = session->enc_write_frame.buflen;
status = switch_core_codec_encode(session->write_codec,
frame->codec,
enc_frame->data,
enc_frame->datalen,
frame->codec->implementation->samples_per_second,
session->enc_write_frame.data,
&session->enc_write_frame.datalen,
&session->enc_write_frame.rate, &flag);
switch (status) {
case SWITCH_STATUS_RESAMPLE:
session->enc_write_frame.codec = session->write_codec;
session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
session->enc_write_frame.timestamp = frame->timestamp;
session->enc_write_frame.payload = session->write_codec->implementation->ianacode;
write_frame = &session->enc_write_frame;
if (!session->read_resampler) {
status = switch_resample_create(&session->read_resampler,
frame->codec->implementation->samples_per_second,
frame->codec->implementation->bytes_per_frame * 20,
session->write_codec->implementation->
samples_per_second,
session->write_codec->implementation->
bytes_per_frame * 20, session->pool);
if (status != SWITCH_STATUS_SUCCESS) {
goto done;
}
}
break;
case SWITCH_STATUS_SUCCESS:
session->enc_write_frame.codec = session->write_codec;
session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
session->enc_write_frame.timestamp = frame->timestamp;
session->enc_write_frame.payload = session->write_codec->implementation->ianacode;
write_frame = &session->enc_write_frame;
break;
case SWITCH_STATUS_NOOP:
enc_frame->codec = session->write_codec;
enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
enc_frame->timestamp = frame->timestamp;
enc_frame->payload = enc_frame->codec->implementation->ianacode;
write_frame = enc_frame;
status = SWITCH_STATUS_SUCCESS;
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s encoder error %d!\n",
session->read_codec->codec_interface->interface_name, status);
write_frame = NULL;
return status;
}
if (session->read_resampler) {
short *data = write_frame->data;
session->read_resampler->from_len = switch_short_to_float(data,
session->read_resampler->from,
(int) write_frame->datalen /
2);
session->read_resampler->to_len = (uint32_t)
switch_resample_process(session->read_resampler, session->read_resampler->from,
session->read_resampler->from_len,
session->read_resampler->to,
session->read_resampler->to_size, 0);
switch_float_to_short(session->read_resampler->to, data, write_frame->datalen * 2);
write_frame->samples = session->read_resampler->to_len;
write_frame->datalen = session->read_resampler->to_len * 2;
write_frame->rate = session->read_resampler->to_rate;
}
if (flag & SFF_CNG) {
switch_set_flag(write_frame, SFF_CNG);
}
if ((status =
perform_write(session, write_frame, timeout, io_flag,
stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
return status;
}
}
}
} else {
do_write = 1;
}
done:
if (do_write) {
return perform_write(session, frame, timeout, io_flag, stream_id);
}
return status;
}
static char *SIG_NAMES[] = {
"NONE",
"KILL",
"XFER",
"BREAK",
NULL
};
SWITCH_DECLARE(switch_status_t) switch_core_session_perform_kill_channel(switch_core_session_t *session,
const char *file,
const char *func,
int line, switch_signal_t sig)
{
switch_io_event_hook_kill_channel_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_INFO, "Kill %s [%s]\n",
switch_channel_get_name(session->channel), SIG_NAMES[sig]);
if (session->endpoint_interface->io_routines->kill_channel) {
if ((status = session->endpoint_interface->io_routines->kill_channel(session, sig)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.kill_channel; ptr; ptr = ptr->next) {
if ((status = ptr->kill_channel(session, sig)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_waitfor_read(switch_core_session_t *session, int timeout,
int stream_id)
{
switch_io_event_hook_waitfor_read_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->endpoint_interface->io_routines->waitfor_read) {
if ((status =
session->endpoint_interface->io_routines->waitfor_read(session, timeout,
stream_id)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.waitfor_read; ptr; ptr = ptr->next) {
if ((status = ptr->waitfor_read(session, timeout, stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_waitfor_write(switch_core_session_t *session, int timeout,
int stream_id)
{
switch_io_event_hook_waitfor_write_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->endpoint_interface->io_routines->waitfor_write) {
if ((status =
session->endpoint_interface->io_routines->waitfor_write(session, timeout,
stream_id)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.waitfor_write; ptr; ptr = ptr->next) {
if ((status = ptr->waitfor_write(session, timeout, stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_send_dtmf(switch_core_session_t *session, char *dtmf)
{
switch_io_event_hook_send_dtmf_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->endpoint_interface->io_routines->send_dtmf) {
if (strchr(dtmf, 'w') || strchr(dtmf, 'W')) {
char *d;
for (d = dtmf; d && *d; d++) {
char digit[2] = { 0 };
if (*d == 'w') {
switch_yield(500000);
continue;
} else if (*d == 'W') {
switch_yield(1000000);
continue;
}
digit[0] = *d;
if ((status =
session->endpoint_interface->io_routines->send_dtmf(session, digit)) != SWITCH_STATUS_SUCCESS) {
return status;
}
}
} else {
status = session->endpoint_interface->io_routines->send_dtmf(session, dtmf);
}
if (status == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.send_dtmf; ptr; ptr = ptr->next) {
if ((status = ptr->send_dtmf(session, dtmf)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
return status;
}

279
src/switch_core_media_bug.c Normal file
View File

@ -0,0 +1,279 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_media_bug.c -- Main Core Library (Media Bugs)
*
*/
#include "switch.h"
#include "private/switch_core.h"
static void switch_core_media_bug_destroy(switch_media_bug_t *bug)
{
switch_buffer_destroy(&bug->raw_read_buffer);
switch_buffer_destroy(&bug->raw_write_buffer);
}
SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_replace_frame(switch_media_bug_t *bug)
{
return bug->replace_frame_in;
}
SWITCH_DECLARE(void) switch_core_media_bug_set_replace_frame(switch_media_bug_t *bug, switch_frame_t *frame)
{
bug->replace_frame_out = frame;
}
SWITCH_DECLARE(void *) switch_core_media_bug_get_user_data(switch_media_bug_t *bug)
{
return bug->user_data;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame)
{
uint32_t bytes = 0;
uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
uint32_t datalen = 0;
int16_t *dp, *fp;
uint32_t x;
size_t rlen = 0;
size_t wlen = 0;
uint32_t blen;
size_t rdlen = 0;
uint32_t maxlen;
switch_codec_t *read_codec = switch_core_session_get_read_codec(bug->session);
if (bug->raw_read_buffer) {
rlen = switch_buffer_inuse(bug->raw_read_buffer);
}
if (bug->raw_write_buffer) {
wlen = switch_buffer_inuse(bug->raw_write_buffer);
}
if ((bug->raw_read_buffer && bug->raw_write_buffer) && (!rlen && !wlen)) {
return SWITCH_STATUS_FALSE;
}
maxlen = sizeof(data) > frame->buflen ? frame->buflen : sizeof(data);
if ((rdlen = rlen > wlen ? wlen : rlen) > maxlen) {
rdlen = maxlen;
}
if (!rdlen) {
rdlen = maxlen;
}
frame->datalen = 0;
if (rlen) {
switch_mutex_lock(bug->read_mutex);
frame->datalen = (uint32_t) switch_buffer_read(bug->raw_read_buffer, frame->data, rdlen);
switch_mutex_unlock(bug->read_mutex);
}
if (wlen) {
switch_mutex_lock(bug->write_mutex);
datalen = (uint32_t) switch_buffer_read(bug->raw_write_buffer, data, rdlen);
switch_mutex_unlock(bug->write_mutex);
}
bytes = (datalen > frame->datalen) ? datalen : frame->datalen;
if (bytes) {
dp = (int16_t *) data;
fp = (int16_t *) frame->data;
rlen = frame->datalen / 2;
wlen = datalen / 2;
blen = bytes / 2;
for (x = 0; x < blen; x++) {
int32_t z = 0;
if (x < rlen) {
z += (int32_t) *(fp + x);
}
if (x < wlen) {
z += (int32_t) *(dp + x);
}
switch_normalize_to_16bit(z);
*(fp + x) = (int16_t) z;
}
frame->datalen = bytes;
frame->samples = bytes / sizeof(int16_t);
frame->rate = read_codec->implementation->samples_per_second;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
#define MAX_BUG_BUFFER 1024 * 512
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t *session,
switch_media_bug_callback_t callback,
void *user_data,
switch_media_bug_flag_t flags, switch_media_bug_t **new_bug)
{
switch_media_bug_t *bug, *bp;
switch_size_t bytes;
if (flags & SMBF_WRITE_REPLACE) {
switch_thread_rwlock_wrlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
if (switch_test_flag(bp, SMBF_WRITE_REPLACE)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only one bug of this type allowed!\n");
switch_thread_rwlock_unlock(session->bug_rwlock);
return SWITCH_STATUS_GENERR;
}
}
switch_thread_rwlock_unlock(session->bug_rwlock);
}
if (!(bug = switch_core_session_alloc(session, sizeof(*bug)))) {
return SWITCH_STATUS_MEMERR;
}
bug->callback = callback;
bug->user_data = user_data;
bug->session = session;
bug->flags = flags;
bug->ready = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Attaching BUG to %s\n",
switch_channel_get_name(session->channel));
bytes = session->read_codec->implementation->bytes_per_frame;
if (!bug->flags) {
bug->flags = (SMBF_READ_STREAM | SMBF_WRITE_STREAM);
}
if (switch_test_flag(bug, SMBF_READ_STREAM)) {
switch_buffer_create_dynamic(&bug->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES,
bytes * SWITCH_BUFFER_START_FRAMES, MAX_BUG_BUFFER);
switch_mutex_init(&bug->read_mutex, SWITCH_MUTEX_NESTED, session->pool);
}
bytes = session->write_codec->implementation->bytes_per_frame;
if (switch_test_flag(bug, SMBF_WRITE_STREAM)) {
switch_buffer_create_dynamic(&bug->raw_write_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES,
bytes * SWITCH_BUFFER_START_FRAMES, MAX_BUG_BUFFER);
switch_mutex_init(&bug->write_mutex, SWITCH_MUTEX_NESTED, session->pool);
}
switch_thread_rwlock_wrlock(session->bug_rwlock);
bug->next = session->bugs;
session->bugs = bug;
switch_thread_rwlock_unlock(session->bug_rwlock);
*new_bug = bug;
if (bug->callback) {
switch_bool_t result = bug->callback(bug, bug->user_data, SWITCH_ABC_TYPE_INIT);
if (result == SWITCH_FALSE) {
return switch_core_media_bug_remove(session, new_bug);
}
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(switch_core_session_t *session)
{
switch_media_bug_t *bp;
if (session->bugs) {
switch_thread_rwlock_wrlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
if (bp->callback) {
bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_CLOSE);
}
switch_core_media_bug_destroy(bp);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing BUG from %s\n",
switch_channel_get_name(session->channel));
}
switch_thread_rwlock_unlock(session->bug_rwlock);
session->bugs = NULL;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(switch_media_bug_t **bug)
{
switch_media_bug_t *bp = *bug;
if (bp) {
if (bp->callback) {
bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_CLOSE);
bp->ready = 0;
}
switch_core_media_bug_destroy(bp);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing BUG from %s\n",
switch_channel_get_name(bp->session->channel));
*bug = NULL;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session_t *session, switch_media_bug_t **bug)
{
switch_media_bug_t *bp = NULL, *last = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->bugs) {
switch_thread_rwlock_wrlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
if (!bp->ready) {
continue;
}
if (bp == *bug) {
if (last) {
last->next = bp->next;
} else {
session->bugs = bp->next;
}
break;
}
last = bp;
}
switch_thread_rwlock_unlock(session->bug_rwlock);
status = switch_core_media_bug_close(&bp);
}
return status;
}

221
src/switch_core_memory.c Normal file
View File

@ -0,0 +1,221 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_memory.c -- Main Core Library (memory management)
*
*/
#include <switch.h>
#include "private/switch_core.h"
static struct {
switch_memory_pool_t *memory_pool;
} runtime;
SWITCH_DECLARE(switch_memory_pool_t *) switch_core_session_get_pool(switch_core_session_t *session)
{
return session->pool;
}
/* **ONLY** alloc things with this function that **WILL NOT** outlive
the session itself or expect an earth shattering KABOOM!*/
SWITCH_DECLARE(void *) switch_core_session_alloc(switch_core_session_t *session, switch_size_t memory)
{
void *ptr = NULL;
assert(session != NULL);
assert(session->pool != NULL);
#ifdef DEBUG_ALLOC
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Allocate %d\n", memory);
#endif
if ((ptr = apr_palloc(session->pool, memory)) != 0) {
memset(ptr, 0, memory);
}
return ptr;
}
/* **ONLY** alloc things with these functions that **WILL NOT** need
to be freed *EVER* ie this is for *PERMANENT* memory allocation */
SWITCH_DECLARE(void *) switch_core_permanent_alloc(switch_size_t memory)
{
void *ptr = NULL;
assert(runtime.memory_pool != NULL);
#ifdef DEBUG_ALLOC
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Perm Allocate %d\n", memory);
#endif
if ((ptr = apr_palloc(runtime.memory_pool, memory)) != 0) {
memset(ptr, 0, memory);
}
return ptr;
}
SWITCH_DECLARE(char *) switch_core_permanent_strdup(const char *todup)
{
char *duped = NULL;
switch_size_t len;
assert(runtime.memory_pool != NULL);
if (!todup)
return NULL;
len = strlen(todup) + 1;
#ifdef DEBUG_ALLOC
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Perm Allocate %d\n", len);
#endif
if (todup && (duped = apr_palloc(runtime.memory_pool, len)) != 0) {
strncpy(duped, todup, len);
}
return duped;
}
SWITCH_DECLARE(char *) switch_core_session_sprintf(switch_core_session_t *session, const char *fmt, ...)
{
va_list ap;
char *result = NULL;
assert(session != NULL);
assert(session->pool != NULL);
va_start(ap, fmt);
result = apr_pvsprintf(session->pool, fmt, ap);
va_end(ap);
return result;
}
SWITCH_DECLARE(char *) switch_core_sprintf(switch_memory_pool_t *pool, const char *fmt, ...)
{
va_list ap;
char *result = NULL;
assert(pool != NULL);
va_start(ap, fmt);
result = apr_pvsprintf(pool, fmt, ap);
va_end(ap);
return result;
}
SWITCH_DECLARE(char *) switch_core_session_strdup(switch_core_session_t *session, const char *todup)
{
char *duped = NULL;
switch_size_t len;
assert(session != NULL);
assert(session->pool != NULL);
if (!todup) {
return NULL;
}
len = strlen(todup) + 1;
#ifdef DEBUG_ALLOC
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Allocate %d\n", len);
#endif
if (todup && (duped = apr_palloc(session->pool, len)) != 0) {
strncpy(duped, todup, len);
}
return duped;
}
SWITCH_DECLARE(char *) switch_core_strdup(switch_memory_pool_t *pool, const char *todup)
{
char *duped = NULL;
switch_size_t len;
assert(pool != NULL);
if (!todup) {
return NULL;
}
len = strlen(todup) + 1;
#ifdef DEBUG_ALLOC
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Allocate %d\n", len);
#endif
if (todup && (duped = apr_palloc(pool, len)) != 0) {
strncpy(duped, todup, len);
}
return duped;
}
SWITCH_DECLARE(switch_status_t) switch_core_new_memory_pool(switch_memory_pool_t **pool)
{
if ((apr_pool_create(pool, NULL)) != SWITCH_STATUS_SUCCESS) {
*pool = NULL;
return SWITCH_STATUS_MEMERR;
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_destroy_memory_pool(switch_memory_pool_t **pool)
{
apr_pool_destroy(*pool);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void *) switch_core_alloc(switch_memory_pool_t *pool, switch_size_t memory)
{
void *ptr = NULL;
assert(pool != NULL);
#ifdef DEBUG_ALLOC
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Allocate %d\n", memory);
/* assert(memory < 600000); */
#endif
if ((ptr = apr_palloc(pool, memory)) != 0) {
memset(ptr, 0, memory);
}
return ptr;
}
SWITCH_DECLARE(switch_memory_pool_t *) switch_core_memory_init(void)
{
memset(&runtime, 0, sizeof(runtime));
apr_pool_create(&runtime.memory_pool, NULL);
return runtime.memory_pool;
}

View File

@ -0,0 +1,112 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_port_allocator.c -- Main Core Library (port allocator)
*
*/
#include <switch.h>
#include "private/switch_core.h"
struct switch_core_port_allocator {
switch_port_t start;
switch_port_t end;
switch_port_t next;
uint8_t inc;
switch_mutex_t *mutex;
switch_memory_pool_t *pool;
};
SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start,
switch_port_t end,
uint8_t inc,
switch_core_port_allocator_t **new_allocator)
{
switch_status_t status;
switch_memory_pool_t *pool;
switch_core_port_allocator_t *alloc;
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if (!(alloc = switch_core_alloc(pool, sizeof(*alloc)))) {
switch_core_destroy_memory_pool(&pool);
return SWITCH_STATUS_MEMERR;
}
alloc->start = start;
alloc->next = start;
alloc->end = end;
if (!(alloc->inc = inc)) {
alloc->inc = 2;
}
switch_mutex_init(&alloc->mutex, SWITCH_MUTEX_NESTED, pool);
alloc->pool = pool;
*new_allocator = alloc;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
switch_management_action_t action,
char *data, switch_size_t datalen)
{
const switch_management_interface_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if ((ptr = switch_loadable_module_get_management_interface(relative_oid))) {
status = ptr->management_function(relative_oid, action, data, datalen);
}
return status;
}
SWITCH_DECLARE(switch_port_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc)
{
switch_port_t port;
switch_mutex_lock(alloc->mutex);
port = alloc->next;
alloc->next = alloc->next + alloc->inc;
if (alloc->next > alloc->end) {
alloc->next = alloc->start;
}
switch_mutex_unlock(alloc->mutex);
return port;
}
SWITCH_DECLARE(void) switch_core_port_allocator_destroy(switch_core_port_allocator_t **alloc)
{
switch_memory_pool_t *pool = (*alloc)->pool;
switch_core_destroy_memory_pool(&pool);
*alloc = NULL;
}

91
src/switch_core_rwlock.c Normal file
View File

@ -0,0 +1,91 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_rwlock.c -- Main Core Library (read / write locks)
*
*/
#include <switch.h>
#include "private/switch_core.h"
#ifdef SWITCH_DEBUG_RWLOCKS
SWITCH_DECLARE(switch_status_t) switch_core_session_perform_read_lock(switch_core_session_t *session,
const char *file, const char *func, int line)
#else
SWITCH_DECLARE(switch_status_t) switch_core_session_read_lock(switch_core_session_t *session)
#endif
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->rwlock) {
if (switch_test_flag(session, SSF_DESTROYED)) {
status = SWITCH_STATUS_FALSE;
#ifdef SWITCH_DEBUG_RWLOCKS
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "%s Read lock FAIL\n",
switch_channel_get_name(session->channel));
#endif
} else {
status = (switch_status_t) switch_thread_rwlock_tryrdlock(session->rwlock);
#ifdef SWITCH_DEBUG_RWLOCKS
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "%s Read lock AQUIRED\n",
switch_channel_get_name(session->channel));
#endif
}
}
return status;
}
#ifdef SWITCH_DEBUG_RWLOCKS
SWITCH_DECLARE(void) switch_core_session_perform_write_lock(switch_core_session_t *session,
const char *file, const char *func, int line)
{
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "%s Write lock AQUIRED\n",
switch_channel_get_name(session->channel));
#else
SWITCH_DECLARE(void) switch_core_session_write_lock(switch_core_session_t *session)
{
#endif
switch_thread_rwlock_wrlock(session->rwlock);
}
#ifdef SWITCH_DEBUG_RWLOCKS
SWITCH_DECLARE(void) switch_core_session_perform_rwunlock(switch_core_session_t *session,
const char *file, const char *func, int line)
{
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "%s Read/Write lock CLEARED\n",
switch_channel_get_name(session->channel));
#else
SWITCH_DECLARE(void) switch_core_session_rwunlock(switch_core_session_t *session)
{
#endif
switch_thread_rwlock_unlock(session->rwlock);
}

936
src/switch_core_session.c Normal file
View File

@ -0,0 +1,936 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_session.c -- Main Core Library (session routines)
*
*/
#include <switch.h>
#include "private/switch_core.h"
static struct {
switch_memory_pool_t *memory_pool;
switch_hash_t *session_table;
switch_mutex_t *session_table_mutex;
uint32_t session_count;
uint32_t session_limit;
uint32_t session_id;
} runtime;
#ifdef SWITCH_DEBUG_RWLOCKS
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_perform_locate(char *uuid_str,
const char *file, const char *func, int line)
#else
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str)
#endif
{
switch_core_session_t *session = NULL;
if (uuid_str) {
switch_mutex_lock(runtime.session_table_mutex);
if ((session = switch_core_hash_find(runtime.session_table, uuid_str))) {
/* Acquire a read lock on the session */
#ifdef SWITCH_DEBUG_RWLOCKS
if (switch_core_session_perform_read_lock(session, file, func, line) != SWITCH_STATUS_SUCCESS) {
#else
if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
#endif
/* not available, forget it */
session = NULL;
}
}
switch_mutex_unlock(runtime.session_table_mutex);
}
/* if its not NULL, now it's up to you to rwunlock this */
return session;
}
SWITCH_DECLARE(void) switch_core_session_hupall(switch_call_cause_t cause)
{
switch_hash_index_t *hi;
void *val;
switch_core_session_t *session;
switch_channel_t *channel;
uint32_t loops = 0;
switch_mutex_lock(runtime.session_table_mutex);
for (hi = switch_hash_first(runtime.memory_pool, runtime.session_table); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &val);
if (val) {
session = (switch_core_session_t *) val;
channel = switch_core_session_get_channel(session);
switch_channel_hangup(channel, cause);
switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
}
}
switch_mutex_unlock(runtime.session_table_mutex);
while (runtime.session_count > 0) {
switch_yield(100000);
if (++loops == 100) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Giving up with %d session%s remaining\n",
runtime.session_count, runtime.session_count == 1 ? "" : "s");
break;
}
}
}
SWITCH_DECLARE(switch_status_t) switch_core_session_message_send(char *uuid_str, switch_core_session_message_t *message)
{
switch_core_session_t *session = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_mutex_lock(runtime.session_table_mutex);
if ((session = switch_core_hash_find(runtime.session_table, uuid_str)) != 0) {
/* Acquire a read lock on the session or forget it the channel is dead */
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
status = switch_core_session_receive_message(session, message);
}
switch_core_session_rwunlock(session);
}
}
switch_mutex_unlock(runtime.session_table_mutex);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_event_send(char *uuid_str, switch_event_t **event)
{
switch_core_session_t *session = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_mutex_lock(runtime.session_table_mutex);
if ((session = switch_core_hash_find(runtime.session_table, uuid_str)) != 0) {
/* Acquire a read lock on the session or forget it the channel is dead */
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
status = switch_core_session_queue_event(session, event);
}
switch_core_session_rwunlock(session);
}
}
switch_mutex_unlock(runtime.session_table_mutex);
return status;
}
SWITCH_DECLARE(void *) switch_core_session_get_private(switch_core_session_t *session)
{
assert(session != NULL);
return session->private_info;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_set_private(switch_core_session_t *session, void *private_info)
{
assert(session != NULL);
session->private_info = private_info;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(int) switch_core_session_add_stream(switch_core_session_t *session, void *private_info)
{
session->streams[session->stream_count++] = private_info;
return session->stream_count - 1;
}
SWITCH_DECLARE(void *) switch_core_session_get_stream(switch_core_session_t *session, int index)
{
return session->streams[index];
}
SWITCH_DECLARE(int) switch_core_session_get_stream_count(switch_core_session_t *session)
{
return session->stream_count;
}
SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_core_session_t *session,
char *endpoint_name,
switch_caller_profile_t *caller_profile,
switch_core_session_t **new_session,
switch_memory_pool_t **pool)
{
switch_io_event_hook_outgoing_channel_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
const switch_endpoint_interface_t *endpoint_interface;
switch_channel_t *channel = NULL;
switch_caller_profile_t *outgoing_profile = caller_profile;
switch_call_cause_t cause = SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
if ((endpoint_interface = switch_loadable_module_get_endpoint_interface(endpoint_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not locate channel type %s\n", endpoint_name);
return SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED;
}
if (endpoint_interface->io_routines->outgoing_channel) {
if (session) {
channel = switch_core_session_get_channel(session);
if (caller_profile) {
char *ecaller_id_name = NULL, *ecaller_id_number = NULL;
ecaller_id_name = switch_channel_get_variable(channel, "effective_caller_id_name");
ecaller_id_number = switch_channel_get_variable(channel, "effective_caller_id_number");
if (ecaller_id_name || ecaller_id_number) {
if (!ecaller_id_name) {
ecaller_id_name = caller_profile->caller_id_name;
}
if (!ecaller_id_number) {
ecaller_id_number = caller_profile->caller_id_number;
}
outgoing_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
caller_profile->username,
caller_profile->dialplan,
ecaller_id_name,
ecaller_id_number,
caller_profile->network_addr,
caller_profile->ani,
caller_profile->aniii,
caller_profile->rdnis,
caller_profile->source,
caller_profile->context,
caller_profile->destination_number);
outgoing_profile->flags = caller_profile->flags;
}
}
if (!outgoing_profile) {
outgoing_profile = switch_channel_get_caller_profile(channel);
}
}
if ((cause = endpoint_interface->io_routines->outgoing_channel(session,
outgoing_profile,
new_session, pool)) == SWITCH_CAUSE_SUCCESS) {
if (session) {
for (ptr = session->event_hooks.outgoing_channel; ptr; ptr = ptr->next) {
if ((status =
ptr->outgoing_channel(session, caller_profile, *new_session)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
} else {
return cause;
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not locate outgoing channel interface for %s\n",
endpoint_name);
return SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED;
}
if (*new_session) {
switch_caller_profile_t *profile = NULL, *peer_profile = NULL, *cloned_profile = NULL;
switch_event_t *event;
switch_channel_t *peer_channel = switch_core_session_get_channel(*new_session);
if (session && channel) {
profile = switch_channel_get_caller_profile(channel);
}
if (peer_channel) {
peer_profile = switch_channel_get_caller_profile(peer_channel);
}
if (channel && peer_channel) {
char *export_vars, *val;
switch_codec_t *read_codec = switch_core_session_get_read_codec(session);
if (read_codec) {
char tmp[80];
switch_codec2str(read_codec, tmp, sizeof(tmp));
switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_CODEC_VARIABLE, tmp);
}
switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_VARIABLE,
switch_core_session_get_uuid(session));
switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BOND_VARIABLE,
switch_core_session_get_uuid(session));
switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE,
switch_core_session_get_uuid(*new_session));
/* A comma (,) separated list of variable names that should ne propagated from originator to originatee */
if ((export_vars = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE))) {
char *cptmp = switch_core_session_strdup(session, export_vars);
int argc;
char *argv[256];
if ((argc = switch_separate_string(cptmp, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
int x;
for (x = 0; x < argc; x++) {
char *val;
if ((val = switch_channel_get_variable(channel, argv[x]))) {
switch_channel_set_variable(peer_channel, argv[x], val);
}
}
}
}
if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
switch_channel_set_variable(peer_channel, SWITCH_B_SDP_VARIABLE, val);
}
if ((val = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE))) {
switch_channel_set_variable(peer_channel, SWITCH_MAX_FORWARDS_VARIABLE, val);
}
if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
switch_channel_set_flag(peer_channel, CF_NOMEDIA);
}
if (profile) {
if ((cloned_profile = switch_caller_profile_clone(*new_session, profile)) != 0) {
switch_channel_set_originator_caller_profile(peer_channel, cloned_profile);
}
}
if (peer_profile) {
if (session && (cloned_profile = switch_caller_profile_clone(session, peer_profile)) != 0) {
switch_channel_set_originatee_caller_profile(channel, cloned_profile);
}
}
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_OUTGOING) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(peer_channel, event);
switch_event_fire(&event);
}
}
return cause;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_answer_channel(switch_core_session_t *session)
{
switch_io_event_hook_answer_channel_t *ptr;
switch_status_t status = SWITCH_STATUS_SUCCESS;
assert(session != NULL);
if (session->endpoint_interface->io_routines->answer_channel) {
status = session->endpoint_interface->io_routines->answer_channel(session);
}
if (status == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.answer_channel; ptr; ptr = ptr->next) {
if ((status = ptr->answer_channel(session)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_receive_message(switch_core_session_t *session,
switch_core_session_message_t *message)
{
switch_io_event_hook_receive_message_t *ptr;
switch_status_t status = SWITCH_STATUS_SUCCESS;
assert(session != NULL);
if (session->endpoint_interface->io_routines->receive_message) {
status = session->endpoint_interface->io_routines->receive_message(session, message);
}
if (status == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.receive_message; ptr; ptr = ptr->next) {
if ((status = ptr->receive_message(session, message)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
switch_core_session_kill_channel(session, SWITCH_SIG_BREAK);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_queue_indication(switch_core_session_t *session,
switch_core_session_message_types_t indication)
{
switch_core_session_message_t *msg;
if ((msg = malloc(sizeof(*msg)))) {
memset(msg, 0, sizeof(*msg));
msg->message_id = indication;
msg->from = __FILE__;
switch_core_session_queue_message(session, msg);
switch_set_flag(msg, SCSMF_DYNAMIC);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_queue_message(switch_core_session_t *session,
switch_core_session_message_t *message)
{
switch_status_t status = SWITCH_STATUS_FALSE;
assert(session != NULL);
if (!session->message_queue) {
switch_queue_create(&session->message_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool);
}
if (session->message_queue) {
if (switch_queue_trypush(session->message_queue, message) == SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_SUCCESS;
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_message(switch_core_session_t *session,
switch_core_session_message_t **message)
{
switch_status_t status = SWITCH_STATUS_FALSE;
void *pop;
assert(session != NULL);
if (session->message_queue) {
if ((status = (switch_status_t) switch_queue_trypop(session->message_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
*message = (switch_core_session_message_t *) pop;
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_flush_message(switch_core_session_t *session)
{
switch_core_session_message_t *message;
if (switch_core_session_dequeue_message(session, &message) == SWITCH_STATUS_SUCCESS) {
if (switch_test_flag(message, SCSMF_DYNAMIC)) {
switch_safe_free(message);
} else {
message = NULL;
}
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_receive_event(switch_core_session_t *session,
switch_event_t **event)
{
switch_io_event_hook_receive_event_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
assert(session != NULL);
/* Acquire a read lock on the session or forget it the channel is dead */
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
if (session->endpoint_interface->io_routines->receive_event) {
status = session->endpoint_interface->io_routines->receive_event(session, *event);
}
if (status == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.receive_event; ptr; ptr = ptr->next) {
if ((status = ptr->receive_event(session, *event)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
if (status == SWITCH_STATUS_BREAK) {
status = SWITCH_STATUS_SUCCESS;
}
if (status == SWITCH_STATUS_SUCCESS) {
switch_event_destroy(event);
}
}
switch_core_session_rwunlock(session);
}
switch_core_session_kill_channel(session, SWITCH_SIG_BREAK);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(switch_core_session_t *session, switch_event_t **event)
{
switch_status_t status = SWITCH_STATUS_FALSE;
assert(session != NULL);
if (!session->event_queue) {
switch_queue_create(&session->event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
}
if (session->event_queue) {
if (switch_queue_trypush(session->event_queue, *event) == SWITCH_STATUS_SUCCESS) {
*event = NULL;
status = SWITCH_STATUS_SUCCESS;
}
}
return status;
}
SWITCH_DECLARE(int32_t) switch_core_session_event_count(switch_core_session_t *session)
{
if (session->event_queue) {
return (int32_t) switch_queue_size(session->event_queue);
}
return -1;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_event(switch_core_session_t *session,
switch_event_t **event)
{
switch_status_t status = SWITCH_STATUS_FALSE;
void *pop;
assert(session != NULL);
if (session->event_queue) {
if ((status = (switch_status_t) switch_queue_trypop(session->event_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
*event = (switch_event_t *) pop;
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_queue_private_event(switch_core_session_t *session,
switch_event_t **event)
{
switch_status_t status = SWITCH_STATUS_FALSE;
assert(session != NULL);
if (!session->private_event_queue) {
switch_queue_create(&session->private_event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
}
if (session->private_event_queue) {
(*event)->event_id = SWITCH_EVENT_PRIVATE_COMMAND;
if (switch_queue_trypush(session->private_event_queue, *event) == SWITCH_STATUS_SUCCESS) {
*event = NULL;
switch_core_session_kill_channel(session, SWITCH_SIG_BREAK);
status = SWITCH_STATUS_SUCCESS;
}
}
return status;
}
SWITCH_DECLARE(int32_t) switch_core_session_private_event_count(switch_core_session_t *session)
{
if (session->private_event_queue) {
return (int32_t) switch_queue_size(session->private_event_queue);
}
return -1;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_private_event(switch_core_session_t *session,
switch_event_t **event)
{
switch_status_t status = SWITCH_STATUS_FALSE;
void *pop;
switch_channel_t *channel;
assert(session != NULL);
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if (switch_channel_test_flag(channel, CF_EVENT_PARSE)) {
return status;
}
if (session->private_event_queue) {
if ((status =
(switch_status_t) switch_queue_trypop(session->private_event_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
*event = (switch_event_t *) pop;
}
}
return status;
}
SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session)
{
switch_channel_t *channel;
char buf[256];
switch_size_t has;
/* sweep theese under the rug, they wont be leaked they will be reclaimed
when the session ends.
*/
session->read_resampler = NULL;
session->write_resampler = NULL;
/* clear indications */
switch_core_session_flush_message(session);
/* wipe theese, they will be recreated if need be */
switch_buffer_destroy(&session->raw_read_buffer);
switch_buffer_destroy(&session->raw_write_buffer);
/* flush dtmf */
channel = switch_core_session_get_channel(session);
while ((has = switch_channel_has_dtmf(channel))) {
switch_channel_dequeue_dtmf(channel, buf, sizeof(buf));
}
}
SWITCH_DECLARE(switch_channel_t *) switch_core_session_get_channel(switch_core_session_t *session)
{
return session->channel;
}
SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session_t *session)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_io_event_hook_state_change_t *ptr;
/* If trylock fails the signal is already awake so we needn't bother */
if (switch_mutex_trylock(session->mutex) == SWITCH_STATUS_SUCCESS) {
switch_thread_cond_signal(session->cond);
switch_mutex_unlock(session->mutex);
}
if (session->endpoint_interface->io_routines->state_change) {
status = session->endpoint_interface->io_routines->state_change(session);
}
if (status == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.state_change; ptr; ptr = ptr->next) {
if ((status = ptr->state_change(session)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
SWITCH_DECLARE(unsigned int) switch_core_session_running(switch_core_session_t *session)
{
return session->thread_running;
}
#ifdef CRASH_PROT
#if defined (__GNUC__) && defined (LINUX)
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#define STACK_LEN 10
/* Obtain a backtrace and print it to stdout. */
static void print_trace(void)
{
void *array[STACK_LEN];
size_t size;
char **strings;
size_t i;
size = backtrace(array, STACK_LEN);
strings = backtrace_symbols(array, size);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Obtained %zd stack frames.\n", size);
for (i = 0; i < size; i++) {
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CRIT, "%s\n", strings[i]);
}
free(strings);
}
#else
static void print_trace(void)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Trace not avaliable =(\n");
}
#endif
static void handle_fatality(int sig)
{
switch_thread_id_t thread_id;
jmp_buf *env;
if (sig && (thread_id = switch_thread_self())
&& (env = (jmp_buf *) apr_hash_get(runtime.stack_table, &thread_id, sizeof(thread_id)))) {
print_trace();
longjmp(*env, sig);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Caught signal %d for unmapped thread!", sig);
abort();
}
}
#endif
SWITCH_DECLARE(void) switch_core_session_destroy(switch_core_session_t **session)
{
switch_memory_pool_t *pool;
switch_event_t *event;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Close Channel %s\n",
switch_channel_get_name((*session)->channel));
switch_scheduler_del_task_group((*session)->uuid_str);
switch_mutex_lock(runtime.session_table_mutex);
switch_core_hash_delete(runtime.session_table, (*session)->uuid_str);
if (runtime.session_count) {
runtime.session_count--;
}
switch_mutex_unlock(runtime.session_table_mutex);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DESTROY) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data((*session)->channel, event);
switch_event_fire(&event);
}
switch_core_media_bug_remove_all(*session);
switch_buffer_destroy(&(*session)->raw_read_buffer);
switch_buffer_destroy(&(*session)->raw_write_buffer);
switch_channel_uninit((*session)->channel);
pool = (*session)->pool;
*session = NULL;
apr_pool_destroy(pool);
pool = NULL;
}
static void *SWITCH_THREAD_FUNC switch_core_session_thread(switch_thread_t *thread, void *obj)
{
switch_core_session_t *session = obj;
session->thread = thread;
switch_core_session_run(session);
switch_core_media_bug_remove_all(session);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %u (%s) Locked, Waiting on external entities\n",
session->id, switch_channel_get_name(session->channel));
switch_core_session_write_lock(session);
switch_set_flag(session, SSF_DESTROYED);
switch_core_session_rwunlock(session);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Session %u (%s) Ended\n", session->id,
switch_channel_get_name(session->channel));
switch_core_session_destroy(&session);
return NULL;
}
SWITCH_DECLARE(void) switch_core_session_thread_launch(switch_core_session_t *session)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr;;
switch_threadattr_create(&thd_attr, session->pool);
switch_threadattr_detach_set(thd_attr, 1);
if (!session->thread_running) {
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) !=
SWITCH_STATUS_SUCCESS) {
switch_core_session_destroy(&session);
}
}
}
SWITCH_DECLARE(void) switch_core_session_launch_thread(switch_core_session_t *session, switch_thread_start_t func,
void *obj)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, session->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, func, obj, session->pool);
}
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request(const switch_endpoint_interface_t
*endpoint_interface, switch_memory_pool_t **pool)
{
switch_memory_pool_t *usepool;
switch_core_session_t *session;
switch_uuid_t uuid;
uint32_t count = 0;
assert(endpoint_interface != NULL);
switch_mutex_lock(runtime.session_table_mutex);
count = runtime.session_count;
switch_mutex_unlock(runtime.session_table_mutex);
if ((count + 1) > runtime.session_limit) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Over Session Limit!\n");
return NULL;
}
if (!switch_core_ready()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Read my lips: no new sessions!\n");
return NULL;
}
if (pool && *pool) {
usepool = *pool;
*pool = NULL;
} else if (switch_core_new_memory_pool(&usepool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not allocate memory pool\n");
return NULL;
}
if ((session = switch_core_alloc(usepool, sizeof(switch_core_session_t))) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not allocate session\n");
apr_pool_destroy(usepool);
return NULL;
}
if (switch_channel_alloc(&session->channel, usepool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate channel structure\n");
apr_pool_destroy(usepool);
return NULL;
}
switch_channel_init(session->channel, session, CS_NEW, 0);
/* The session *IS* the pool you may not alter it because you have no idea how
its all private it will be passed to the thread run function */
switch_uuid_get(&uuid);
switch_uuid_format(session->uuid_str, &uuid);
session->pool = usepool;
session->endpoint_interface = endpoint_interface;
session->raw_write_frame.data = session->raw_write_buf;
session->raw_write_frame.buflen = sizeof(session->raw_write_buf);
session->raw_read_frame.data = session->raw_read_buf;
session->raw_read_frame.buflen = sizeof(session->raw_read_buf);
session->enc_write_frame.data = session->enc_write_buf;
session->enc_write_frame.buflen = sizeof(session->enc_write_buf);
session->enc_read_frame.data = session->enc_read_buf;
session->enc_read_frame.buflen = sizeof(session->enc_read_buf);
switch_mutex_init(&session->mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_thread_rwlock_create(&session->bug_rwlock, session->pool);
switch_thread_cond_create(&session->cond, session->pool);
switch_thread_rwlock_create(&session->rwlock, session->pool);
snprintf(session->name, sizeof(session->name), "%u", session->id);
switch_mutex_lock(runtime.session_table_mutex);
session->id = runtime.session_id++;
switch_core_hash_insert(runtime.session_table, session->uuid_str, session);
runtime.session_count++;
switch_mutex_unlock(runtime.session_table_mutex);
return session;
}
SWITCH_DECLARE(uint32_t) switch_core_session_count(void)
{
return runtime.session_count;
}
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_by_name(char *endpoint_name,
switch_memory_pool_t **pool)
{
const switch_endpoint_interface_t *endpoint_interface;
if ((endpoint_interface = switch_loadable_module_get_endpoint_interface(endpoint_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not locate channel type %s\n", endpoint_name);
return NULL;
}
return switch_core_session_request(endpoint_interface, pool);
}
#ifndef SWITCH_PREFIX_DIR
#define SWITCH_PREFIX_DIR "."
#endif
SWITCH_DECLARE(uint8_t) switch_core_session_compare(switch_core_session_t *a, switch_core_session_t *b)
{
assert(a != NULL);
assert(b != NULL);
return (uint8_t) (a->endpoint_interface == b->endpoint_interface);
}
SWITCH_DECLARE(char *) switch_core_session_get_uuid(switch_core_session_t *session)
{
return session->uuid_str;
}
SWITCH_DECLARE(uint32_t) switch_core_session_limit(uint32_t new_limit)
{
if (new_limit) {
runtime.session_limit = new_limit;
}
return runtime.session_limit;
}
SWITCH_DECLARE(void) switch_core_session_init(switch_memory_pool_t *pool)
{
memset(&runtime, 0, sizeof(runtime));
runtime.session_limit = 1000;
runtime.session_id = 1;
runtime.memory_pool = pool;
switch_core_hash_init(&runtime.session_table, runtime.memory_pool);
switch_mutex_init(&runtime.session_table_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool);
}

95
src/switch_core_speech.c Normal file
View File

@ -0,0 +1,95 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_speech.c -- Main Core Library (speech functions)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_speech_feed_tts(switch_speech_handle_t *sh, char *text,
switch_speech_flag_t *flags)
{
assert(sh != NULL);
return sh->speech_interface->speech_feed_tts(sh, text, flags);
}
SWITCH_DECLARE(void) switch_core_speech_flush_tts(switch_speech_handle_t *sh)
{
assert(sh != NULL);
if (sh->speech_interface->speech_flush_tts) {
sh->speech_interface->speech_flush_tts(sh);
}
}
SWITCH_DECLARE(void) switch_core_speech_text_param_tts(switch_speech_handle_t *sh, char *param, char *val)
{
assert(sh != NULL);
if (sh->speech_interface->speech_text_param_tts) {
sh->speech_interface->speech_text_param_tts(sh, param, val);
}
}
SWITCH_DECLARE(void) switch_core_speech_numeric_param_tts(switch_speech_handle_t *sh, char *param, int val)
{
assert(sh != NULL);
if (sh->speech_interface->speech_numeric_param_tts) {
sh->speech_interface->speech_numeric_param_tts(sh, param, val);
}
}
SWITCH_DECLARE(void) switch_core_speech_float_param_tts(switch_speech_handle_t *sh, char *param, double val)
{
assert(sh != NULL);
if (sh->speech_interface->speech_float_param_tts) {
sh->speech_interface->speech_float_param_tts(sh, param, val);
}
}
SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle_t *sh,
void *data,
switch_size_t *datalen,
uint32_t * rate, switch_speech_flag_t *flags)
{
assert(sh != NULL);
return sh->speech_interface->speech_read_tts(sh, data, datalen, rate, flags);
}
SWITCH_DECLARE(switch_status_t) switch_core_speech_close(switch_speech_handle_t *sh, switch_speech_flag_t *flags)
{
return sh->speech_interface->speech_close(sh, flags);
}

411
src/switch_core_sqldb.c Normal file
View File

@ -0,0 +1,411 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_sqldb.c -- Main Core Library (statistics tracker)
*
*/
#include <switch.h>
#include "private/switch_core.h"
static struct {
switch_core_db_t *db;
switch_core_db_t *event_db;
switch_queue_t *sql_queue;
switch_memory_pool_t *memory_pool;
} runtime;
static switch_status_t switch_core_db_persistant_execute_trans(switch_core_db_t *db, char *sql, uint32_t retries)
{
char *errmsg;
switch_status_t status = SWITCH_STATUS_FALSE;
uint8_t forever = 0;
unsigned begin_retries = 100;
uint8_t again = 0;
if (!retries) {
forever = 1;
retries = 1000;
}
again:
while (begin_retries > 0) {
again = 0;
switch_core_db_exec(db, "begin transaction", NULL, NULL, &errmsg);
if (errmsg) {
begin_retries--;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s]\n", errmsg);
if (strstr(errmsg, "cannot start a transaction within a transaction")) {
again = 1;
}
switch_core_db_free(errmsg);
if (again) {
switch_core_db_exec(db, "end transaction", NULL, NULL, &errmsg);
goto again;
}
switch_yield(100000);
if (begin_retries == 0) {
goto done;
}
} else {
break;
}
}
while (retries > 0) {
switch_core_db_exec(db, sql, NULL, NULL, &errmsg);
if (errmsg) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s]\n", errmsg);
switch_core_db_free(errmsg);
switch_yield(100000);
retries--;
if (retries == 0 && forever) {
retries = 1000;
continue;
}
} else {
status = SWITCH_STATUS_SUCCESS;
break;
}
}
done:
switch_core_db_exec(db, "end transaction", NULL, NULL, &errmsg);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_db_persistant_execute(switch_core_db_t *db, char *sql, uint32_t retries)
{
char *errmsg;
switch_status_t status = SWITCH_STATUS_FALSE;
uint8_t forever = 0;
if (!retries) {
forever = 1;
retries = 1000;
}
while (retries > 0) {
switch_core_db_exec(db, sql, NULL, NULL, &errmsg);
if (errmsg) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s]\n", errmsg);
switch_core_db_free(errmsg);
switch_yield(100000);
retries--;
if (retries == 0 && forever) {
retries = 1000;
continue;
}
} else {
status = SWITCH_STATUS_SUCCESS;
break;
}
}
return status;
}
#define SQLLEN 1024 * 64
static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, void *obj)
{
void *pop;
uint32_t itterations = 0;
uint8_t trans = 0, nothing_in_queue = 0;
uint32_t target = 1000;
switch_size_t len = 0, sql_len = SQLLEN;
char *sqlbuf = (char *) malloc(sql_len);
char *sql;
switch_size_t newlen;
if (!runtime.event_db) {
runtime.event_db = switch_core_db_handle();
}
switch_queue_create(&runtime.sql_queue, SWITCH_SQL_QUEUE_LEN, runtime.memory_pool);
for (;;) {
if (switch_queue_trypop(runtime.sql_queue, &pop) == SWITCH_STATUS_SUCCESS) {
sql = (char *) pop;
if (sql) {
newlen = strlen(sql) + 2;
if (itterations == 0) {
trans = 1;
}
/* ignore abnormally large strings sql strings as potential buffer overflow */
if (newlen < SQLLEN) {
itterations++;
if (len + newlen > sql_len) {
sql_len = len + SQLLEN;
if (!(sqlbuf = realloc(sqlbuf, sql_len))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "SQL thread ending on mem err\n");
break;
}
}
sprintf(sqlbuf + len, "%s;\n", sql);
len += newlen;
}
switch_core_db_free(sql);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "SQL thread ending\n");
break;
}
} else {
nothing_in_queue = 1;
}
if (trans && ((itterations == target) || nothing_in_queue)) {
if (switch_core_db_persistant_execute_trans(runtime.event_db, sqlbuf, 1000) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
"SQL thread unable to commit transaction, records lost!\n");
}
itterations = 0;
trans = 0;
nothing_in_queue = 0;
len = 0;
*sqlbuf = '\0';
}
if (nothing_in_queue) {
switch_yield(1000);
}
}
free(sqlbuf);
return NULL;
}
static void core_event_handler(switch_event_t *event)
{
char *sql = NULL;
switch (event->event_id) {
case SWITCH_EVENT_CHANNEL_DESTROY:
sql = switch_mprintf("delete from channels where uuid='%s'", switch_event_get_header(event, "unique-id"));
break;
case SWITCH_EVENT_CHANNEL_CREATE:
sql = switch_mprintf("insert into channels (uuid,created,name,state) values('%q','%q','%q','%q')",
switch_event_get_header(event, "unique-id"),
switch_event_get_header(event, "event-date-local"),
switch_event_get_header(event, "channel-name"),
switch_event_get_header(event, "channel-state")
);
break;
case SWITCH_EVENT_CODEC:
sql =
switch_mprintf
("update channels set read_codec='%q',read_rate='%q',write_codec='%q',write_rate='%q' where uuid='%q'",
switch_event_get_header(event, "channel-read-codec-name"), switch_event_get_header(event,
"channel-read-codec-rate"),
switch_event_get_header(event, "channel-write-codec-name"), switch_event_get_header(event,
"channel-write-codec-rate"),
switch_event_get_header(event, "unique-id"));
break;
case SWITCH_EVENT_CHANNEL_EXECUTE:
sql = switch_mprintf("update channels set application='%q',application_data='%q' where uuid='%q'",
switch_event_get_header(event, "application"),
switch_event_get_header(event, "application-data"),
switch_event_get_header(event, "unique-id")
);
break;
case SWITCH_EVENT_CHANNEL_STATE:
if (event) {
char *state = switch_event_get_header(event, "channel-state-number");
switch_channel_state_t state_i = atoi(state);
switch (state_i) {
case CS_HANGUP:
case CS_DONE:
break;
case CS_RING:
sql = switch_mprintf("update channels set state='%s',cid_name='%q',cid_num='%q',ip_addr='%s',dest='%q'"
"where uuid='%s'",
switch_event_get_header(event, "channel-state"),
switch_event_get_header(event, "caller-caller-id-name"),
switch_event_get_header(event, "caller-caller-id-number"),
switch_event_get_header(event, "caller-network-addr"),
switch_event_get_header(event, "caller-destination-number"),
switch_event_get_header(event, "unique-id")
);
break;
default:
sql = switch_mprintf("update channels set state='%s' where uuid='%s'",
switch_event_get_header(event, "channel-state"),
switch_event_get_header(event, "unique-id")
);
break;
}
}
break;
case SWITCH_EVENT_CHANNEL_BRIDGE:
sql = switch_mprintf("insert into calls values ('%s','%q','%q','%q','%q','%s','%q','%q','%q','%q','%s')",
switch_event_get_header(event, "event-calling-function"),
switch_event_get_header(event, "caller-caller-id-name"),
switch_event_get_header(event, "caller-caller-id-number"),
switch_event_get_header(event, "caller-destination-number"),
switch_event_get_header(event, "caller-channel-name"),
switch_event_get_header(event, "caller-unique-id"),
switch_event_get_header(event, "originatee-caller-id-name"),
switch_event_get_header(event, "originatee-caller-id-number"),
switch_event_get_header(event, "originatee-destination-number"),
switch_event_get_header(event, "originatee-channel-name"),
switch_event_get_header(event, "originatee-unique-id")
);
break;
case SWITCH_EVENT_CHANNEL_UNBRIDGE:
sql =
switch_mprintf("delete from calls where caller_uuid='%s'",
switch_event_get_header(event, "caller-unique-id"));
break;
case SWITCH_EVENT_SHUTDOWN:
sql = switch_mprintf("delete from channels;delete from interfaces;delete from calls");
break;
case SWITCH_EVENT_LOG:
return;
case SWITCH_EVENT_MODULE_LOAD:
{
const char *type = switch_event_get_header(event, "type");
const char *name = switch_event_get_header(event, "name");
const char *description = switch_event_get_header(event, "description");
const char *syntax = switch_event_get_header(event, "syntax");
if (!switch_strlen_zero(type) && !switch_strlen_zero(name)) {
sql =
switch_mprintf("insert into interfaces (type,name,description,syntax) values('%q','%q','%q','%q')",
type, name, switch_str_nil(description), switch_str_nil(syntax)
);
}
break;
}
default:
break;
}
if (sql) {
switch_queue_push(runtime.sql_queue, sql);
sql = NULL;
}
}
SWITCH_DECLARE(void) switch_core_sqldb_start(switch_memory_pool_t *pool)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr;;
runtime.memory_pool = pool;
/* Activate SQL database */
if ((runtime.db = switch_core_db_handle()) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n");
} else {
char create_channels_sql[] =
"CREATE TABLE channels (\n"
" uuid VARCHAR(255),\n"
" created VARCHAR(255),\n"
" name VARCHAR(255),\n"
" state VARCHAR(255),\n"
" cid_name VARCHAR(255),\n"
" cid_num VARCHAR(255),\n"
" ip_addr VARCHAR(255),\n"
" dest VARCHAR(255),\n"
" application VARCHAR(255),\n"
" application_data VARCHAR(255),\n"
" read_codec VARCHAR(255),\n"
" read_rate VARCHAR(255),\n" " write_codec VARCHAR(255),\n" " write_rate VARCHAR(255)\n" ");\n";
char create_calls_sql[] =
"CREATE TABLE calls (\n"
" function VARCHAR(255),\n"
" caller_cid_name VARCHAR(255),\n"
" caller_cid_num VARCHAR(255),\n"
" caller_dest_num VARCHAR(255),\n"
" caller_chan_name VARCHAR(255),\n"
" caller_uuid VARCHAR(255),\n"
" callee_cid_name VARCHAR(255),\n"
" callee_cid_num VARCHAR(255),\n"
" callee_dest_num VARCHAR(255),\n"
" callee_chan_name VARCHAR(255),\n" " callee_uuid VARCHAR(255)\n" ");\n";
char create_interfaces_sql[] =
"CREATE TABLE interfaces (\n"
" type VARCHAR(255),\n"
" name VARCHAR(255),\n"
" description VARCHAR(255),\n" " syntax VARCHAR(255)\n" ");\n";
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n");
switch_core_db_exec(runtime.db, "drop table channels", NULL, NULL, NULL);
switch_core_db_exec(runtime.db, "drop table calls", NULL, NULL, NULL);
switch_core_db_exec(runtime.db, "drop table interfaces", NULL, NULL, NULL);
switch_core_db_exec(runtime.db, create_channels_sql, NULL, NULL, NULL);
switch_core_db_exec(runtime.db, create_calls_sql, NULL, NULL, NULL);
switch_core_db_exec(runtime.db, create_interfaces_sql, NULL, NULL, NULL);
if (switch_event_bind("core_db", SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, core_event_handler, NULL) !=
SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind event handler!\n");
}
}
switch_threadattr_create(&thd_attr, runtime.memory_pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, switch_core_sql_thread, NULL, runtime.memory_pool);
}
SWITCH_DECLARE(void) switch_core_sqldb_stop(void)
{
switch_queue_push(runtime.sql_queue, NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Waiting for unfinished SQL transactions\n");
while (switch_queue_size(runtime.sql_queue) > 0) {
switch_yield(10000);
}
switch_core_db_close(runtime.db);
switch_core_db_close(runtime.event_db);
}

View File

@ -0,0 +1,626 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_state_maching.c -- Main Core Library (state machine)
*
*/
#include <switch.h>
#include "private/switch_core.h"
static void switch_core_standard_on_init(switch_core_session_t *session)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard INIT %s\n",
switch_channel_get_name(session->channel));
}
static void switch_core_standard_on_hangup(switch_core_session_t *session)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HANGUP %s, cause: %s\n",
switch_channel_get_name(session->channel),
switch_channel_cause2str(switch_channel_get_cause(session->channel)));
}
static void switch_core_standard_on_ring(switch_core_session_t *session)
{
switch_dialplan_interface_t *dialplan_interface = NULL;
switch_caller_profile_t *caller_profile;
switch_caller_extension_t *extension = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard RING %s\n",
switch_channel_get_name(session->channel));
if ((caller_profile = switch_channel_get_caller_profile(session->channel)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't get profile!\n");
switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return;
} else {
char *dp[25];
char *dpstr;
int argc, x, count = 0;
if (!switch_strlen_zero(caller_profile->dialplan)) {
if ((dpstr = switch_core_session_strdup(session, caller_profile->dialplan))) {
argc = switch_separate_string(dpstr, ',', dp, (sizeof(dp) / sizeof(dp[0])));
for (x = 0; x < argc; x++) {
char *dpname = dp[x];
char *dparg = NULL;
if (dpname) {
if ((dparg = strchr(dpname, ':'))) {
*dparg++ = '\0';
}
}
if (!(dialplan_interface = switch_loadable_module_get_dialplan_interface(dpname))) {
continue;
}
count++;
if ((extension = dialplan_interface->hunt_function(session, dparg)) != 0) {
switch_channel_set_caller_extension(session->channel, extension);
return;
}
}
}
}
if (!count) {
if (switch_channel_test_flag(session->channel, CF_OUTBOUND)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "No Dialplan, changing state to HOLD\n");
switch_channel_set_state(session->channel, CS_HOLD);
return;
}
}
}
if (!extension) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "No Route, Aborting\n");
switch_channel_hangup(session->channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
}
}
static void switch_core_standard_on_execute(switch_core_session_t *session)
{
switch_caller_extension_t *extension;
switch_event_t *event;
const switch_application_interface_t *application_interface;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard EXECUTE\n");
if ((extension = switch_channel_get_caller_extension(session->channel)) == 0) {
switch_channel_hangup(session->channel, SWITCH_CAUSE_NORMAL_CLEARING);
return;
}
while (switch_channel_get_state(session->channel) == CS_EXECUTE && extension->current_application) {
char *expanded = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Execute %s(%s)\n",
extension->current_application->application_name,
switch_str_nil(extension->current_application->application_data));
if ((application_interface =
switch_loadable_module_get_application_interface(extension->current_application->application_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Application %s\n",
extension->current_application->application_name);
switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return;
}
if (!application_interface->application_function) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Function for %s\n",
extension->current_application->application_name);
switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return;
}
if ((expanded =
switch_channel_expand_variables(session->channel,
extension->current_application->application_data)) !=
extension->current_application->application_data) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Expanded String %s(%s)\n",
extension->current_application->application_name, expanded);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(session->channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "%s",
extension->current_application->application_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data-Orig", "%s",
extension->current_application->application_data);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", expanded);
switch_event_fire(&event);
}
if (switch_channel_get_variable(session->channel, "presence_id")) {
char *arg = switch_mprintf("%s(%s)", extension->current_application->application_name, expanded);
if (arg) {
switch_channel_presence(session->channel, "unknown", arg);
switch_safe_free(arg);
}
}
application_interface->application_function(session, expanded);
if (expanded != extension->current_application->application_data) {
switch_safe_free(expanded);
}
extension->current_application = extension->current_application->next;
}
if (switch_channel_get_state(session->channel) == CS_EXECUTE) {
switch_channel_hangup(session->channel, SWITCH_CAUSE_NORMAL_CLEARING);
}
}
static void switch_core_standard_on_loopback(switch_core_session_t *session)
{
switch_frame_t *frame;
int stream_id;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard LOOPBACK\n");
while (switch_channel_get_state(session->channel) == CS_LOOPBACK) {
for (stream_id = 0; stream_id < session->stream_count; stream_id++) {
if (switch_core_session_read_frame(session, &frame, -1, stream_id) == SWITCH_STATUS_SUCCESS) {
switch_core_session_write_frame(session, frame, -1, stream_id);
}
}
}
}
static void switch_core_standard_on_transmit(switch_core_session_t *session)
{
assert(session != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard TRANSMIT\n");
}
static void switch_core_standard_on_hold(switch_core_session_t *session)
{
assert(session != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HOLD\n");
}
static void switch_core_standard_on_hibernate(switch_core_session_t *session)
{
assert(session != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HIBERNATE\n");
}
SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
{
switch_channel_state_t state = CS_NEW, laststate = CS_HANGUP, midstate = CS_DONE, endstate;
const switch_endpoint_interface_t *endpoint_interface;
const switch_state_handler_table_t *driver_state_handler = NULL;
const switch_state_handler_table_t *application_state_handler = NULL;
#ifdef CRASH_PROT
switch_thread_id_t thread_id = switch_thread_self();
jmp_buf env;
int sig;
signal(SIGSEGV, handle_fatality);
signal(SIGFPE, handle_fatality);
#ifndef WIN32
signal(SIGBUS, handle_fatality);
#endif
if ((sig = setjmp(env)) != 0) {
switch_event_t *event;
if (switch_event_create(&event, SWITCH_EVENT_SESSION_CRASH) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(session->channel, event);
switch_event_fire(&event);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Thread has crashed for channel %s\n",
switch_channel_get_name(session->channel));
switch_channel_hangup(session->channel, SWITCH_CAUSE_CRASH);
} else {
apr_hash_set(runtime.stack_table, &thread_id, sizeof(thread_id), &env);
}
#endif
/*
Life of the channel. you have channel and pool in your session
everywhere you go you use the session to malloc with
switch_core_session_alloc(session, <size>)
The enpoint module gets the first crack at implementing the state
if it wants to, it can cancel the default behaviour by returning SWITCH_STATUS_FALSE
Next comes the channel's event handler table that can be set by an application
which also can veto the next behaviour in line by returning SWITCH_STATUS_FALSE
Finally the default state behaviour is called.
*/
assert(session != NULL);
session->thread_running = 1;
endpoint_interface = session->endpoint_interface;
assert(endpoint_interface != NULL);
driver_state_handler = endpoint_interface->state_handler;
assert(driver_state_handler != NULL);
switch_mutex_lock(session->mutex);
while ((state = switch_channel_get_state(session->channel)) != CS_DONE) {
uint8_t exception = 0;
if (switch_channel_test_flag(session->channel, CF_REPEAT_STATE)) {
switch_channel_clear_flag(session->channel, CF_REPEAT_STATE);
exception = 1;
}
if (state != laststate || state == CS_HANGUP || exception) {
int index = 0;
int proceed = 1;
midstate = state;
switch (state) {
case CS_NEW: /* Just created, Waiting for first instructions */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State NEW\n",
switch_channel_get_name(session->channel));
break;
case CS_DONE:
goto done;
case CS_HANGUP: /* Deactivate and end the thread */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State HANGUP\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_hangup
|| (driver_state_handler->on_hangup
&& driver_state_handler->on_hangup(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hangup
|| (application_state_handler->on_hangup
&& application_state_handler->on_hangup(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hangup ||
(application_state_handler->on_hangup &&
application_state_handler->on_hangup(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_hangup(session);
}
}
goto done;
case CS_INIT: /* Basic setup tasks */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State INIT\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_init
|| (driver_state_handler->on_init && driver_state_handler->on_init(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_init
|| (application_state_handler->on_init
&& application_state_handler->on_init(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_init ||
(application_state_handler->on_init &&
application_state_handler->on_init(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_init(session);
}
}
break;
case CS_RING: /* Look for a dialplan and find something to do */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State RING\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_ring
|| (driver_state_handler->on_ring && driver_state_handler->on_ring(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_ring
|| (application_state_handler->on_ring
&& application_state_handler->on_ring(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_ring ||
(application_state_handler->on_ring &&
application_state_handler->on_ring(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_ring(session);
}
}
break;
case CS_EXECUTE: /* Execute an Operation */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State EXECUTE\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_execute
|| (driver_state_handler->on_execute
&& driver_state_handler->on_execute(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_execute
|| (application_state_handler->on_execute
&& application_state_handler->on_execute(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_execute ||
(application_state_handler->on_execute &&
application_state_handler->on_execute(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_execute(session);
}
}
break;
case CS_LOOPBACK: /* loop all data back to source */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State LOOPBACK\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_loopback
|| (driver_state_handler->on_loopback
&& driver_state_handler->on_loopback(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_loopback
|| (application_state_handler->on_loopback
&& application_state_handler->on_loopback(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_loopback ||
(application_state_handler->on_loopback &&
application_state_handler->on_loopback(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_loopback(session);
}
}
break;
case CS_TRANSMIT: /* send/recieve data to/from another channel */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State TRANSMIT\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_transmit
|| (driver_state_handler->on_transmit
&& driver_state_handler->on_transmit(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_transmit
|| (application_state_handler->on_transmit
&& application_state_handler->on_transmit(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_transmit ||
(application_state_handler->on_transmit &&
application_state_handler->on_transmit(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_transmit(session);
}
}
break;
case CS_HOLD: /* wait in limbo */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State HOLD\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_hold
|| (driver_state_handler->on_hold && driver_state_handler->on_hold(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hold
|| (application_state_handler->on_hold
&& application_state_handler->on_hold(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hold ||
(application_state_handler->on_hold &&
application_state_handler->on_hold(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_hold(session);
}
}
break;
case CS_HIBERNATE: /* wait in limbo */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State HIBERNATE\n",
switch_channel_get_name(session->channel));
if (!driver_state_handler->on_hibernate
|| (driver_state_handler->on_hibernate
&& driver_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
while ((application_state_handler =
switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hibernate
|| (application_state_handler->on_hibernate
&& application_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS
&& midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while (proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hibernate ||
(application_state_handler->on_hibernate &&
application_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_hibernate(session);
}
}
break;
}
if (midstate == CS_DONE) {
break;
}
laststate = midstate;
}
endstate = switch_channel_get_state(session->channel);
if (midstate == endstate) {
switch_thread_cond_wait(session->cond, session->mutex);
}
}
done:
switch_mutex_unlock(session->mutex);
#ifdef CRASH_PROT
apr_hash_set(runtime.stack_table, &thread_id, sizeof(thread_id), NULL);
#endif
session->thread_running = 0;
}

117
src/switch_core_timer.c Normal file
View File

@ -0,0 +1,117 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
*
*
* switch_core_timer.c -- Main Core Library (timer interface)
*
*/
#include <switch.h>
#include "private/switch_core.h"
SWITCH_DECLARE(switch_status_t) switch_core_timer_init(switch_timer_t *timer, char *timer_name, int interval,
int samples, switch_memory_pool_t *pool)
{
switch_timer_interface_t *timer_interface;
switch_status_t status;
memset(timer, 0, sizeof(*timer));
if ((timer_interface = switch_loadable_module_get_timer_interface(timer_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid timer %s!\n", timer_name);
return SWITCH_STATUS_GENERR;
}
timer->interval = interval;
timer->samples = samples;
timer->samplecount = 0;
timer->timer_interface = timer_interface;
if (pool) {
timer->memory_pool = pool;
} else {
if ((status = switch_core_new_memory_pool(&timer->memory_pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_set_flag(timer, SWITCH_TIMER_FLAG_FREE_POOL);
}
timer->timer_interface->timer_init(timer);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_timer_next(switch_timer_t *timer)
{
if (!timer->timer_interface) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Timer is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
if (timer->timer_interface->timer_next(timer) == SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_SUCCESS;
} else {
return SWITCH_STATUS_GENERR;
}
}
SWITCH_DECLARE(switch_status_t) switch_core_timer_step(switch_timer_t *timer)
{
if (!timer->timer_interface) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Timer is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
return timer->timer_interface->timer_step(timer);
}
SWITCH_DECLARE(switch_status_t) switch_core_timer_check(switch_timer_t *timer)
{
if (!timer->timer_interface) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Timer is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
return timer->timer_interface->timer_check(timer);
}
SWITCH_DECLARE(switch_status_t) switch_core_timer_destroy(switch_timer_t *timer)
{
if (!timer->timer_interface) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Timer is not initilized!\n");
return SWITCH_STATUS_GENERR;
}
timer->timer_interface->timer_destroy(timer);
if (switch_test_flag(timer, SWITCH_TIMER_FLAG_FREE_POOL)) {
switch_core_destroy_memory_pool(&timer->memory_pool);
}
return SWITCH_STATUS_SUCCESS;
}

797
src/switch_ivr_async.c Normal file
View File

@ -0,0 +1,797 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
*
* switch_ivr_async.c -- IVR Library (async operations)
*
*/
#include <switch.h>
static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_file_handle_t *fh = (switch_file_handle_t *) user_data;
uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_frame_t frame = { 0 };
frame.data = data;
frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
switch (type) {
case SWITCH_ABC_TYPE_INIT:
break;
case SWITCH_ABC_TYPE_CLOSE:
if (fh) {
switch_core_file_close(fh);
}
break;
case SWITCH_ABC_TYPE_READ:
if (fh) {
switch_size_t len;
if (switch_core_media_bug_read(bug, &frame) == SWITCH_STATUS_SUCCESS) {
len = (switch_size_t) frame.datalen / 2;
switch_core_file_write(fh, frame.data, &len);
}
}
break;
case SWITCH_ABC_TYPE_WRITE:
default:
break;
}
return SWITCH_TRUE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_session_t *session, char *file)
{
switch_media_bug_t *bug;
switch_channel_t *channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if ((bug = switch_channel_get_private(channel, file))) {
switch_channel_set_private(channel, file, NULL);
switch_core_media_bug_remove(session, &bug);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, char *file,
switch_file_handle_t *fh)
{
switch_channel_t *channel;
switch_codec_t *read_codec;
char *p;
const char *vval;
switch_media_bug_t *bug;
switch_status_t status;
if (!fh) {
if (!(fh = switch_core_session_alloc(session, sizeof(*fh)))) {
return SWITCH_STATUS_MEMERR;
}
}
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
read_codec = switch_core_session_get_read_codec(session);
assert(read_codec != NULL);
fh->channels = read_codec->implementation->number_of_channels;
fh->samplerate = read_codec->implementation->samples_per_second;
if (switch_core_file_open(fh,
file,
read_codec->implementation->number_of_channels,
read_codec->implementation->samples_per_second,
SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT,
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_core_session_reset(session);
return SWITCH_STATUS_GENERR;
}
switch_channel_answer(channel);
if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) {
vval = (const char *) switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_TITLE, vval);
switch_channel_set_variable(channel, "RECORD_TITLE", NULL);
}
if ((p = switch_channel_get_variable(channel, "RECORD_COPYRIGHT"))) {
vval = (const char *) switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, vval);
switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL);
}
if ((p = switch_channel_get_variable(channel, "RECORD_SOFTWARE"))) {
vval = (const char *) switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, vval);
switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL);
}
if ((p = switch_channel_get_variable(channel, "RECORD_ARTIST"))) {
vval = (const char *) switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, vval);
switch_channel_set_variable(channel, "RECORD_ARTIST", NULL);
}
if ((p = switch_channel_get_variable(channel, "RECORD_COMMENT"))) {
vval = (const char *) switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, vval);
switch_channel_set_variable(channel, "RECORD_COMMENT", NULL);
}
if ((p = switch_channel_get_variable(channel, "RECORD_DATE"))) {
vval = (const char *) switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval);
switch_channel_set_variable(channel, "RECORD_DATE", NULL);
}
if ((status = switch_core_media_bug_add(session, record_callback, fh, SMBF_BOTH, &bug)) != SWITCH_STATUS_SUCCESS) {
switch_core_file_close(fh);
return status;
}
switch_channel_set_private(channel, file, bug);
return SWITCH_STATUS_SUCCESS;
}
typedef struct {
switch_core_session_t *session;
teletone_dtmf_detect_state_t dtmf_detect;
} switch_inband_dtmf_t;
static switch_bool_t inband_dtmf_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_inband_dtmf_t *pvt = (switch_inband_dtmf_t *) user_data;
uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_frame_t frame = { 0 };
char digit_str[80];
switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
assert(channel != NULL);
frame.data = data;
frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
switch (type) {
case SWITCH_ABC_TYPE_INIT:
break;
case SWITCH_ABC_TYPE_CLOSE:
break;
case SWITCH_ABC_TYPE_READ:
if (switch_core_media_bug_read(bug, &frame) == SWITCH_STATUS_SUCCESS) {
teletone_dtmf_detect(&pvt->dtmf_detect, frame.data, frame.samples);
teletone_dtmf_get(&pvt->dtmf_detect, digit_str, sizeof(digit_str));
if (digit_str[0]) {
switch_channel_queue_dtmf(channel, digit_str);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "DTMF DETECTED: [%s]\n", digit_str);
}
}
break;
case SWITCH_ABC_TYPE_WRITE:
default:
break;
}
return SWITCH_TRUE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_inband_dtmf_session(switch_core_session_t *session)
{
switch_media_bug_t *bug;
switch_channel_t *channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if ((bug = switch_channel_get_private(channel, "dtmf"))) {
switch_channel_set_private(channel, "dtmf", NULL);
switch_core_media_bug_remove(session, &bug);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_inband_dtmf_session(switch_core_session_t *session)
{
switch_channel_t *channel;
switch_codec_t *read_codec;
switch_media_bug_t *bug;
switch_status_t status;
switch_inband_dtmf_t *pvt;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
read_codec = switch_core_session_get_read_codec(session);
assert(read_codec != NULL);
if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
return SWITCH_STATUS_MEMERR;
}
teletone_dtmf_detect_init(&pvt->dtmf_detect, read_codec->implementation->samples_per_second);
pvt->session = session;
switch_channel_answer(channel);
if ((status = switch_core_media_bug_add(session,
inband_dtmf_callback,
pvt, SMBF_READ_STREAM, &bug)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_channel_set_private(channel, "dtmf", bug);
return SWITCH_STATUS_SUCCESS;
}
struct speech_thread_handle {
switch_core_session_t *session;
switch_asr_handle_t *ah;
switch_media_bug_t *bug;
switch_mutex_t *mutex;
switch_thread_cond_t *cond;
switch_memory_pool_t *pool;
};
static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj)
{
struct speech_thread_handle *sth = (struct speech_thread_handle *) obj;
switch_channel_t *channel = switch_core_session_get_channel(sth->session);
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
switch_status_t status;
switch_thread_cond_create(&sth->cond, sth->pool);
switch_mutex_init(&sth->mutex, SWITCH_MUTEX_NESTED, sth->pool);
switch_core_session_read_lock(sth->session);
switch_mutex_lock(sth->mutex);
while (switch_channel_ready(channel) && !switch_test_flag(sth->ah, SWITCH_ASR_FLAG_CLOSED)) {
char *xmlstr = NULL;
switch_thread_cond_wait(sth->cond, sth->mutex);
if (switch_core_asr_check_results(sth->ah, &flags) == SWITCH_STATUS_SUCCESS) {
switch_event_t *event;
status = switch_core_asr_get_results(sth->ah, &xmlstr, &flags);
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
goto done;
}
if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {
if (status == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");
switch_event_add_body(event, "%s", xmlstr);
} else {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");
}
if (switch_test_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)) {
switch_event_t *dup;
if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
switch_event_fire(&dup);
}
}
if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event queue failed!\n");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
switch_event_fire(&event);
}
}
switch_safe_free(xmlstr);
}
}
done:
switch_mutex_unlock(sth->mutex);
switch_core_session_rwunlock(sth->session);
return NULL;
}
static switch_bool_t speech_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
struct speech_thread_handle *sth = (struct speech_thread_handle *) user_data;
uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_frame_t frame = { 0 };
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
frame.data = data;
frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
switch (type) {
case SWITCH_ABC_TYPE_INIT:{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, sth->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, speech_thread, sth, sth->pool);
}
break;
case SWITCH_ABC_TYPE_CLOSE:{
switch_core_asr_close(sth->ah, &flags);
switch_mutex_lock(sth->mutex);
switch_thread_cond_signal(sth->cond);
switch_mutex_unlock(sth->mutex);
}
break;
case SWITCH_ABC_TYPE_READ:
if (sth->ah) {
if (switch_core_media_bug_read(bug, &frame) == SWITCH_STATUS_SUCCESS) {
if (switch_core_asr_feed(sth->ah, frame.data, frame.datalen, &flags) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error Feeding Data\n");
return SWITCH_FALSE;
}
if (switch_core_asr_check_results(sth->ah, &flags) == SWITCH_STATUS_SUCCESS) {
switch_mutex_lock(sth->mutex);
switch_thread_cond_signal(sth->cond);
switch_mutex_unlock(sth->mutex);
}
}
}
break;
case SWITCH_ABC_TYPE_WRITE:
default:
break;
}
return SWITCH_TRUE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_detect_speech(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
struct speech_thread_handle *sth;
assert(channel != NULL);
if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
switch_channel_set_private(channel, SWITCH_SPEECH_KEY, NULL);
switch_core_media_bug_remove(session, &sth->bug);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_pause_detect_speech(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
struct speech_thread_handle *sth;
assert(channel != NULL);
if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
switch_core_asr_pause(sth->ah);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_resume_detect_speech(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
struct speech_thread_handle *sth;
assert(channel != NULL);
if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
switch_core_asr_resume(sth->ah);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, char *grammar,
char *path)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
struct speech_thread_handle *sth;
assert(channel != NULL);
if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
if (switch_core_asr_load_grammar(sth->ah, grammar, path) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error loading Grammar\n");
switch_core_asr_close(sth->ah, &flags);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, char *grammar)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
struct speech_thread_handle *sth;
assert(channel != NULL);
if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
if (switch_core_asr_unload_grammar(sth->ah, grammar) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error unloading Grammar\n");
switch_core_asr_close(sth->ah, &flags);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech(switch_core_session_t *session,
char *mod_name,
char *grammar, char *path, char *dest, switch_asr_handle_t *ah)
{
switch_channel_t *channel;
switch_codec_t *read_codec;
switch_status_t status;
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
struct speech_thread_handle *sth;
char *val;
if (!ah) {
if (!(ah = switch_core_session_alloc(session, sizeof(*ah)))) {
return SWITCH_STATUS_MEMERR;
}
}
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
read_codec = switch_core_session_get_read_codec(session);
assert(read_codec != NULL);
if ((val = switch_channel_get_variable(channel, "fire_asr_events"))) {
switch_set_flag(ah, SWITCH_ASR_FLAG_FIRE_EVENTS);
}
if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
if (switch_core_asr_load_grammar(sth->ah, grammar, path) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error loading Grammar\n");
switch_core_asr_close(sth->ah, &flags);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
if (switch_core_asr_open(ah,
mod_name,
"L16",
read_codec->implementation->samples_per_second,
dest, &flags, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
if (switch_core_asr_load_grammar(ah, grammar, path) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error loading Grammar\n");
switch_core_asr_close(ah, &flags);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}
} else {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}
sth = switch_core_session_alloc(session, sizeof(*sth));
sth->pool = switch_core_session_get_pool(session);
sth->session = session;
sth->ah = ah;
if ((status = switch_core_media_bug_add(session,
speech_callback,
sth, SMBF_READ_STREAM, &sth->bug)) != SWITCH_STATUS_SUCCESS) {
switch_core_asr_close(ah, &flags);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return status;
}
switch_channel_set_private(channel, SWITCH_SPEECH_KEY, sth);
return SWITCH_STATUS_SUCCESS;
}
struct hangup_helper {
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
switch_bool_t bleg;
switch_call_cause_t cause;
};
static void sch_hangup_callback(switch_scheduler_task_t *task)
{
struct hangup_helper *helper;
switch_core_session_t *session, *other_session;
char *other_uuid;
assert(task);
helper = (struct hangup_helper *) task->cmd_arg;
if ((session = switch_core_session_locate(helper->uuid_str))) {
switch_channel_t *channel = switch_core_session_get_channel(session);
if (helper->bleg) {
if ((other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) &&
(other_session = switch_core_session_locate(other_uuid))) {
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
switch_channel_hangup(other_channel, helper->cause);
switch_core_session_rwunlock(other_session);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No channel to hangup\n");
}
} else {
switch_channel_hangup(channel, helper->cause);
}
switch_core_session_rwunlock(session);
}
}
SWITCH_DECLARE(uint32_t) switch_ivr_schedule_hangup(time_t runtime, char *uuid, switch_call_cause_t cause,
switch_bool_t bleg)
{
struct hangup_helper *helper;
size_t len = sizeof(*helper);
switch_zmalloc(helper, len);
switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
helper->cause = cause;
helper->bleg = bleg;
return switch_scheduler_add_task(runtime, sch_hangup_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper,
SSHF_FREE_ARG);
}
struct transfer_helper {
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
char *extension;
char *dialplan;
char *context;
};
static void sch_transfer_callback(switch_scheduler_task_t *task)
{
struct transfer_helper *helper;
switch_core_session_t *session;
assert(task);
helper = (struct transfer_helper *) task->cmd_arg;
if ((session = switch_core_session_locate(helper->uuid_str))) {
switch_ivr_session_transfer(session, helper->extension, helper->dialplan, helper->context);
switch_core_session_rwunlock(session);
}
}
SWITCH_DECLARE(uint32_t) switch_ivr_schedule_transfer(time_t runtime, char *uuid, char *extension, char *dialplan,
char *context)
{
struct transfer_helper *helper;
size_t len = sizeof(*helper);
char *cur = NULL;
if (extension) {
len += strlen(extension) + 1;
}
if (dialplan) {
len += strlen(dialplan) + 1;
}
if (context) {
len += strlen(context) + 1;
}
switch_zmalloc(helper, len);
switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
cur = (char *) helper + sizeof(*helper);
if (extension) {
helper->extension = cur;
switch_copy_string(helper->extension, extension, strlen(extension) + 1);
cur += strlen(helper->extension) + 1;
}
if (dialplan) {
helper->dialplan = cur;
switch_copy_string(helper->dialplan, dialplan, strlen(dialplan) + 1);
cur += strlen(helper->dialplan) + 1;
}
if (context) {
helper->context = cur;
switch_copy_string(helper->context, context, strlen(context) + 1);
}
return switch_scheduler_add_task(runtime, sch_transfer_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper,
SSHF_FREE_ARG);
}
struct broadcast_helper {
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
char *path;
switch_media_flag_t flags;
};
static void sch_broadcast_callback(switch_scheduler_task_t *task)
{
struct broadcast_helper *helper;
assert(task);
helper = (struct broadcast_helper *) task->cmd_arg;
switch_ivr_broadcast(helper->uuid_str, helper->path, helper->flags);
}
SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, char *uuid, char *path,
switch_media_flag_t flags)
{
struct broadcast_helper *helper;
size_t len = sizeof(*helper) + strlen(path) + 1;
switch_zmalloc(helper, len);
switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
helper->flags = flags;
helper->path = (char *) helper + sizeof(*helper);
switch_copy_string(helper->path, path, len - sizeof(helper));
return switch_scheduler_add_task(runtime, sch_broadcast_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper,
SSHF_FREE_ARG);
}
SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(char *uuid, char *path, switch_media_flag_t flags)
{
switch_channel_t *channel;
int nomedia;
switch_core_session_t *session, *master;
switch_event_t *event;
switch_core_session_t *other_session = NULL;
char *other_uuid = NULL;
char *app = "playback";
assert(path);
if ((session = switch_core_session_locate(uuid))) {
char *cause = NULL;
char *mypath = strdup(path);
char *p;
master = session;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if ((nomedia = switch_channel_test_flag(channel, CF_NOMEDIA))) {
switch_ivr_media(uuid, SMF_REBRIDGE);
}
if ((p = strchr(mypath, ':'))) {
app = mypath;
*p++ = '\0';
path = p;
}
if ((cause = strchr(app, '!'))) {
*cause++ = '\0';
if (!cause) {
cause = "normal_clearing";
}
}
if ((flags & SMF_ECHO_BLEG) && (other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))
&& (other_session = switch_core_session_locate(other_uuid))) {
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path);
switch_core_session_queue_private_event(other_session, &event);
}
switch_core_session_rwunlock(other_session);
master = other_session;
other_session = NULL;
}
if ((flags & SMF_ECHO_ALEG)) {
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path);
switch_core_session_queue_private_event(session, &event);
}
master = session;
}
if (nomedia) {
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "nomedia");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "nomedia-uuid", "%s", uuid);
switch_core_session_queue_private_event(master, &event);
}
}
if (cause) {
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "hangup");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", cause);
switch_core_session_queue_private_event(session, &event);
}
}
switch_core_session_rwunlock(session);
switch_safe_free(mypath);
}
return SWITCH_STATUS_SUCCESS;
}

719
src/switch_ivr_bridge.c Normal file
View File

@ -0,0 +1,719 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
* switch_ivr_bridge.c -- IVR Library
*
*/
#include <switch.h>
static const switch_state_handler_table_t audio_bridge_peer_state_handlers;
static const switch_state_handler_table_t originate_state_handlers;
/* Bridge Related Stuff*/
/*********************************************************************************/
struct audio_bridge_data {
switch_core_session_t *session_a;
switch_core_session_t *session_b;
int running;
};
static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
{
switch_core_thread_session_t *his_thread, *data = obj;
int *stream_id_p;
int stream_id = 0, pre_b = 0, ans_a = 0, ans_b = 0, originator = 0;
switch_input_callback_function_t input_callback;
switch_core_session_message_t *message, msg = { 0 };
void *user_data;
switch_channel_t *chan_a, *chan_b;
switch_frame_t *read_frame;
switch_core_session_t *session_a, *session_b;
assert(!thread || thread);
session_a = data->objs[0];
session_b = data->objs[1];
stream_id_p = data->objs[2];
input_callback = data->input_callback;
user_data = data->objs[4];
his_thread = data->objs[5];
if (stream_id_p) {
stream_id = *stream_id_p;
}
chan_a = switch_core_session_get_channel(session_a);
chan_b = switch_core_session_get_channel(session_b);
ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
if ((originator = switch_channel_test_flag(chan_a, CF_ORIGINATOR))) {
pre_b = switch_channel_test_flag(chan_a, CF_EARLY_MEDIA);
ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
}
switch_core_session_read_lock(session_a);
switch_core_session_read_lock(session_b);
switch_channel_set_flag(chan_a, CF_BRIDGED);
while (switch_channel_ready(chan_a) && data->running > 0 && his_thread->running > 0) {
switch_channel_state_t b_state = switch_channel_get_state(chan_b);
switch_status_t status;
switch_event_t *event;
switch (b_state) {
case CS_HANGUP:
case CS_DONE:
switch_mutex_lock(data->mutex);
data->running = -1;
switch_mutex_unlock(data->mutex);
continue;
default:
break;
}
if (switch_channel_test_flag(chan_a, CF_TRANSFER)) {
switch_channel_clear_flag(chan_a, CF_HOLD);
switch_channel_clear_flag(chan_a, CF_SUSPEND);
break;
}
if (switch_core_session_dequeue_private_event(session_a, &event) == SWITCH_STATUS_SUCCESS) {
switch_channel_set_flag(chan_b, CF_SUSPEND);
switch_ivr_parse_event(session_a, event);
switch_channel_clear_flag(chan_b, CF_SUSPEND);
switch_event_destroy(&event);
}
/* if 1 channel has DTMF pass it to the other */
if (switch_channel_has_dtmf(chan_a)) {
char dtmf[128];
switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
switch_core_session_send_dtmf(session_b, dtmf);
if (input_callback) {
if (input_callback(session_a, dtmf, SWITCH_INPUT_TYPE_DTMF, user_data, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s ended call via DTMF\n",
switch_channel_get_name(chan_a));
switch_mutex_lock(data->mutex);
data->running = -1;
switch_mutex_unlock(data->mutex);
break;
}
}
}
if (switch_core_session_dequeue_event(session_a, &event) == SWITCH_STATUS_SUCCESS) {
if (input_callback) {
status = input_callback(session_a, event, SWITCH_INPUT_TYPE_EVENT, user_data, 0);
}
if (event->event_id != SWITCH_EVENT_MESSAGE
|| switch_core_session_receive_event(session_b, &event) != SWITCH_STATUS_SUCCESS) {
switch_event_destroy(&event);
}
}
if (switch_core_session_dequeue_message(session_b, &message) == SWITCH_STATUS_SUCCESS) {
switch_core_session_receive_message(session_a, message);
if (switch_test_flag(message, SCSMF_DYNAMIC)) {
switch_safe_free(message);
} else {
message = NULL;
}
}
if (!ans_a && originator) {
if (!ans_b && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
switch_channel_answer(chan_a);
ans_a++;
} else if (!pre_b && switch_channel_test_flag(chan_b, CF_EARLY_MEDIA)) {
switch_channel_pre_answer(chan_a);
pre_b++;
}
if (!pre_b) {
switch_yield(10000);
continue;
}
}
if (switch_channel_test_flag(chan_a, CF_SUSPEND) || switch_channel_test_flag(chan_b, CF_SUSPEND)) {
switch_yield(10000);
continue;
}
/* read audio from 1 channel and write it to the other */
status = switch_core_session_read_frame(session_a, &read_frame, -1, stream_id);
if (SWITCH_READ_ACCEPTABLE(status)) {
if (status != SWITCH_STATUS_BREAK && !switch_channel_test_flag(chan_a, CF_HOLD)) {
if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "write: %s Bad Frame....[%u] Bubye!\n",
switch_channel_get_name(chan_b), read_frame->datalen);
switch_mutex_lock(data->mutex);
data->running = -1;
switch_mutex_unlock(data->mutex);
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "read: %s Bad Frame.... Bubye!\n",
switch_channel_get_name(chan_a));
switch_mutex_lock(data->mutex);
data->running = -1;
switch_mutex_unlock(data->mutex);
}
}
switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK);
msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE;
msg.from = __FILE__;
switch_core_session_receive_message(session_a, &msg);
switch_channel_set_variable(chan_a, SWITCH_BRIDGE_VARIABLE, NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BRIDGE THREAD DONE [%s]\n",
switch_channel_get_name(chan_a));
switch_channel_clear_flag(chan_a, CF_BRIDGED);
switch_mutex_lock(data->mutex);
data->running = 0;
switch_mutex_unlock(data->mutex);
switch_core_session_rwunlock(session_a);
switch_core_session_rwunlock(session_b);
return NULL;
}
static switch_status_t audio_bridge_on_loopback(switch_core_session_t *session)
{
switch_channel_t *channel = NULL;
void *arg;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if ((arg = switch_channel_get_private(channel, "_bridge_"))) {
switch_channel_set_private(channel, "_bridge_", NULL);
audio_bridge_thread(NULL, (void *) arg);
} else {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
switch_channel_clear_state_handler(channel, &audio_bridge_peer_state_handlers);
if (!switch_channel_test_flag(channel, CF_TRANSFER)) {
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
}
return SWITCH_STATUS_FALSE;
}
static switch_status_t audio_bridge_on_ring(switch_core_session_t *session)
{
switch_channel_t *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM RING\n");
/* put the channel in a passive state so we can loop audio to it */
switch_channel_set_state(channel, CS_HOLD);
return SWITCH_STATUS_FALSE;
}
static switch_status_t audio_bridge_on_hold(switch_core_session_t *session)
{
switch_channel_t *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM HOLD\n");
/* put the channel in a passive state so we can loop audio to it */
return SWITCH_STATUS_FALSE;
}
static const switch_state_handler_table_t audio_bridge_peer_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ audio_bridge_on_ring,
/*.on_execute */ NULL,
/*.on_hangup */ NULL,
/*.on_loopback */ audio_bridge_on_loopback,
/*.on_transmit */ NULL,
/*.on_hold */ audio_bridge_on_hold,
};
static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
{
switch_channel_t *channel = NULL;
switch_core_session_t *other_session;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM TRANSMIT\n");
switch_channel_clear_state_handler(channel, NULL);
if (!switch_channel_test_flag(channel, CF_ORIGINATOR)) {
return SWITCH_STATUS_FALSE;
}
if ((other_session = switch_channel_get_private(channel, SWITCH_UUID_BRIDGE))) {
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
switch_channel_state_t state = switch_channel_get_state(other_channel);
switch_channel_state_t mystate = switch_channel_get_state(channel);
switch_event_t *event;
uint8_t ready_a, ready_b;
switch_caller_profile_t *profile, *new_profile;
switch_channel_clear_flag(channel, CF_TRANSFER);
switch_channel_set_private(channel, SWITCH_UUID_BRIDGE, NULL);
while (mystate <= CS_HANGUP && state <= CS_HANGUP && !switch_channel_test_flag(other_channel, CF_TAGGED)) {
switch_yield(1000);
state = switch_channel_get_state(other_channel);
mystate = switch_channel_get_state(channel);
}
switch_channel_clear_flag(other_channel, CF_TRANSFER);
switch_channel_clear_flag(other_channel, CF_TAGGED);
switch_core_session_reset(session);
switch_core_session_reset(other_session);
ready_a = switch_channel_ready(channel);
ready_b = switch_channel_ready(other_channel);
if (!ready_a || !ready_b) {
if (!ready_a) {
switch_channel_hangup(other_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
if (!ready_b) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
return SWITCH_STATUS_FALSE;
}
/* add another profile to both sessions for CDR's sake */
if ((profile = switch_channel_get_caller_profile(channel))) {
new_profile = switch_caller_profile_clone(session, profile);
new_profile->destination_number =
switch_core_session_strdup(session, switch_core_session_get_uuid(other_session));
switch_channel_set_caller_profile(channel, new_profile);
}
if ((profile = switch_channel_get_caller_profile(other_channel))) {
new_profile = switch_caller_profile_clone(other_session, profile);
new_profile->destination_number =
switch_core_session_strdup(other_session, switch_core_session_get_uuid(session));
switch_channel_set_caller_profile(other_channel, new_profile);
}
/* fire events that will change the data table from "show channels" */
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s",
switch_core_session_get_uuid(other_session));
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(other_channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s",
switch_core_session_get_uuid(session));
switch_event_fire(&event);
}
switch_ivr_multi_threaded_bridge(session, other_session, NULL, NULL, NULL);
} else {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
return SWITCH_STATUS_FALSE;
}
static const switch_state_handler_table_t uuid_bridge_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ NULL,
/*.on_execute */ NULL,
/*.on_hangup */ NULL,
/*.on_loopback */ NULL,
/*.on_transmit */ uuid_bridge_on_transmit,
/*.on_hold */ NULL
};
static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session)
{
switch_channel_t *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_channel_clear_flag(channel, CF_TRANSFER);
switch_channel_set_variable(channel, SWITCH_BRIDGE_VARIABLE,
switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE));
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session)
{
char *uuid;
switch_channel_t *channel = NULL;
switch_core_session_t *other_session;
switch_event_t *event;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if (switch_channel_test_flag(channel, CF_ORIGINATOR)) {
switch_channel_clear_flag(channel, CF_ORIGINATOR);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
}
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE))
&& (other_session = switch_core_session_locate(uuid))) {
switch_channel_t *other_channel = NULL;
other_channel = switch_core_session_get_channel(other_session);
assert(other_channel != NULL);
switch_channel_set_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, NULL);
switch_channel_set_variable(other_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, NULL);
switch_channel_set_variable(channel, SWITCH_BRIDGE_VARIABLE, NULL);
switch_channel_set_variable(other_channel, SWITCH_BRIDGE_VARIABLE, NULL);
if (switch_channel_get_state(other_channel) < CS_HANGUP &&
switch_true(switch_channel_get_variable(other_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) {
switch_channel_hangup(other_channel, switch_channel_get_cause(channel));
} else {
switch_channel_set_state(other_channel, CS_EXECUTE);
}
switch_core_session_rwunlock(other_session);
}
return SWITCH_STATUS_SUCCESS;
}
static const switch_state_handler_table_t signal_bridge_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ NULL,
/*.on_execute */ NULL,
/*.on_hangup */ signal_bridge_on_hangup,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL,
/*.on_hold */ NULL,
/*.on_hibernate */ signal_bridge_on_hibernate
};
SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session,
switch_core_session_t *peer_session)
{
switch_channel_t *caller_channel, *peer_channel;
switch_event_t *event;
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
peer_channel = switch_core_session_get_channel(peer_session);
assert(peer_channel != NULL);
if (!switch_channel_ready(peer_channel)) {
switch_channel_hangup(caller_channel, switch_channel_get_cause(peer_channel));
return SWITCH_STATUS_FALSE;
}
if (!switch_channel_ready(caller_channel)) {
switch_channel_hangup(peer_channel, SWITCH_CAUSE_ORIGINATOR_CANCEL);
return SWITCH_STATUS_FALSE;
}
switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE,
switch_core_session_get_uuid(peer_session));
switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
switch_channel_clear_state_handler(caller_channel, NULL);
switch_channel_clear_state_handler(peer_channel, NULL);
switch_channel_add_state_handler(caller_channel, &signal_bridge_state_handlers);
switch_channel_add_state_handler(peer_channel, &signal_bridge_state_handlers);
/* fire events that will change the data table from "show channels" */
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s",
switch_core_session_get_uuid(peer_session));
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(peer_channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s",
switch_core_session_get_uuid(session));
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_fire(&event);
}
switch_channel_set_state_flag(caller_channel, CF_TRANSFER);
switch_channel_set_state_flag(peer_channel, CF_TRANSFER);
switch_channel_set_state(caller_channel, CS_HIBERNATE);
switch_channel_set_state(peer_channel, CS_HIBERNATE);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_session_t *session,
switch_core_session_t *peer_session,
switch_input_callback_function_t input_callback,
void *session_data, void *peer_session_data)
{
switch_core_thread_session_t *this_audio_thread, *other_audio_thread;
switch_channel_t *caller_channel, *peer_channel;
int stream_id = 0;
switch_status_t status = SWITCH_STATUS_SUCCESS;
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
peer_channel = switch_core_session_get_channel(peer_session);
assert(peer_channel != NULL);
other_audio_thread = switch_core_session_alloc(peer_session, sizeof(switch_core_thread_session_t));
this_audio_thread = switch_core_session_alloc(peer_session, sizeof(switch_core_thread_session_t));
other_audio_thread->objs[0] = session;
other_audio_thread->objs[1] = peer_session;
other_audio_thread->objs[2] = &stream_id;
other_audio_thread->input_callback = input_callback;
other_audio_thread->objs[4] = session_data;
other_audio_thread->objs[5] = this_audio_thread;
other_audio_thread->running = 5;
switch_mutex_init(&other_audio_thread->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
this_audio_thread->objs[0] = peer_session;
this_audio_thread->objs[1] = session;
this_audio_thread->objs[2] = &stream_id;
this_audio_thread->input_callback = input_callback;
this_audio_thread->objs[4] = peer_session_data;
this_audio_thread->objs[5] = other_audio_thread;
this_audio_thread->running = 2;
switch_mutex_init(&this_audio_thread->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(peer_session));
switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
if (switch_channel_test_flag(peer_channel, CF_ANSWERED) && !switch_channel_test_flag(caller_channel, CF_ANSWERED)) {
switch_channel_answer(caller_channel);
}
if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
switch_event_t *event;
switch_core_session_message_t msg = { 0 };
switch_channel_set_state(peer_channel, CS_HOLD);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_fire(&event);
}
if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_set_variable(caller_channel, SWITCH_BRIDGE_VARIABLE,
switch_core_session_get_uuid(peer_session));
switch_channel_set_variable(peer_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
msg.from = __FILE__;
msg.pointer_arg = session;
switch_core_session_receive_message(peer_session, &msg);
if (!msg.pointer_arg) {
status = SWITCH_STATUS_FALSE;
switch_core_session_rwunlock(peer_session);
goto done;
}
msg.pointer_arg = peer_session;
switch_core_session_receive_message(session, &msg);
if (!msg.pointer_arg) {
status = SWITCH_STATUS_FALSE;
switch_core_session_rwunlock(peer_session);
goto done;
}
switch_channel_set_private(peer_channel, "_bridge_", other_audio_thread);
switch_channel_set_state(peer_channel, CS_LOOPBACK);
audio_bridge_thread(NULL, (void *) this_audio_thread);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_fire(&event);
}
this_audio_thread->objs[0] = NULL;
this_audio_thread->objs[1] = NULL;
this_audio_thread->objs[2] = NULL;
this_audio_thread->input_callback = NULL;
this_audio_thread->objs[4] = NULL;
this_audio_thread->objs[5] = NULL;
switch_mutex_lock(this_audio_thread->mutex);
this_audio_thread->running = 0;
switch_mutex_unlock(this_audio_thread->mutex);
switch_channel_clear_flag(caller_channel, CF_ORIGINATOR);
if (other_audio_thread->running > 0) {
switch_mutex_lock(other_audio_thread->mutex);
other_audio_thread->running = -1;
switch_mutex_unlock(other_audio_thread->mutex);
while (other_audio_thread->running) {
switch_yield(1000);
}
}
switch_core_session_rwunlock(peer_session);
} else {
status = SWITCH_STATUS_FALSE;
}
} else {
status = SWITCH_STATUS_FALSE;
}
if (status != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bridge Failed %s->%s\n",
switch_channel_get_name(caller_channel), switch_channel_get_name(peer_channel)
);
switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
}
done:
if (switch_channel_get_state(caller_channel) < CS_HANGUP &&
switch_true(switch_channel_get_variable(caller_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) {
switch_channel_hangup(caller_channel, switch_channel_get_cause(peer_channel));
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, char *originatee_uuid)
{
switch_core_session_t *originator_session, *originatee_session;
switch_channel_t *originator_channel, *originatee_channel;
switch_status_t status = SWITCH_STATUS_FALSE;
if ((originator_session = switch_core_session_locate(originator_uuid))) {
if ((originatee_session = switch_core_session_locate(originatee_uuid))) {
originator_channel = switch_core_session_get_channel(originator_session);
originatee_channel = switch_core_session_get_channel(originatee_session);
/* override transmit state for originator_channel to bridge to originatee_channel
* install pointer to originatee_session into originator_channel
* set CF_TRANSFER on both channels and change state to CS_TRANSMIT to
* inturrupt anything they are already doing.
* originatee_session will fall asleep and originator_session will bridge to it
*/
switch_channel_clear_state_handler(originator_channel, NULL);
switch_channel_clear_state_handler(originatee_channel, NULL);
switch_channel_set_flag(originator_channel, CF_ORIGINATOR);
switch_channel_add_state_handler(originator_channel, &uuid_bridge_state_handlers);
switch_channel_add_state_handler(originatee_channel, &uuid_bridge_state_handlers);
switch_channel_set_flag(originatee_channel, CF_TAGGED);
switch_channel_set_private(originator_channel, SWITCH_UUID_BRIDGE, originatee_session);
/* switch_channel_set_state_flag sets flags you want to be set when the next state change happens */
switch_channel_set_state_flag(originator_channel, CF_TRANSFER);
switch_channel_set_state_flag(originatee_channel, CF_TRANSFER);
/* release the read locks we have on the channels */
switch_core_session_rwunlock(originator_session);
switch_core_session_rwunlock(originatee_session);
/* change the states and let the chips fall where they may */
switch_channel_set_state(originator_channel, CS_TRANSMIT);
switch_channel_set_state(originatee_channel, CS_TRANSMIT);
status = SWITCH_STATUS_SUCCESS;
while (switch_channel_get_state(originatee_channel) < CS_HANGUP
&& switch_channel_test_flag(originatee_channel, CF_TAGGED)) {
switch_yield(20000);
}
} else {
switch_core_session_rwunlock(originator_session);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no channel for originatee uuid %s\n",
originatee_uuid);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no channel for originator uuid %s\n",
originator_uuid);
}
return status;
}

686
src/switch_ivr_menu.c Normal file
View File

@ -0,0 +1,686 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Neal Horman <neal at wanlink dot com>
*
* switch_ivr_menu.c -- IVR Library (menu code)
*
*/
#include <switch.h>
struct switch_ivr_menu_action;
struct switch_ivr_menu {
char *name;
char *greeting_sound;
char *short_greeting_sound;
char *invalid_sound;
char *exit_sound;
char *tts_engine;
char *tts_voice;
char *phrase_lang;
char *buf;
char *ptr;
int max_failures;
int timeout;
uint32_t inlen;
uint32_t flags;
struct switch_ivr_menu_action *actions;
struct switch_ivr_menu *next;
switch_memory_pool_t *pool;
};
struct switch_ivr_menu_action {
switch_ivr_menu_action_function_t *function;
switch_ivr_action_t ivr_action;
char *arg;
char *bind;
struct switch_ivr_menu_action *next;
};
static switch_ivr_menu_t *switch_ivr_menu_find(switch_ivr_menu_t *stack, const char *name)
{
switch_ivr_menu_t *ret;
for (ret = stack; ret; ret = ret->next) {
if (!name || !strcmp(ret->name, name))
break;
}
return ret;
}
static void switch_ivr_menu_stack_add(switch_ivr_menu_t **top, switch_ivr_menu_t *bottom)
{
switch_ivr_menu_t *ptr;
for (ptr = *top; ptr && ptr->next; ptr = ptr->next);
if (ptr) {
ptr->next = bottom;
} else {
*top = bottom;
}
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_menu,
switch_ivr_menu_t *main,
const char *name,
const char *greeting_sound,
const char *short_greeting_sound,
const char *invalid_sound,
const char *exit_sound,
const char *tts_engine,
const char *tts_voice,
const char *phrase_lang,
int timeout, int max_failures, switch_memory_pool_t *pool)
{
switch_ivr_menu_t *menu;
uint8_t newpool = 0;
if (!pool) {
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
return SWITCH_STATUS_MEMERR;
}
newpool = 1;
}
if (!(menu = switch_core_alloc(pool, sizeof(*menu)))) {
if (newpool) {
switch_core_destroy_memory_pool(&pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
return SWITCH_STATUS_MEMERR;
}
}
menu->pool = pool;
if (!switch_strlen_zero(name)) {
menu->name = switch_core_strdup(menu->pool, name);
}
if (!switch_strlen_zero(greeting_sound)) {
menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound);
}
if (!switch_strlen_zero(short_greeting_sound)) {
menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound);
}
if (!switch_strlen_zero(invalid_sound)) {
menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound);
}
if (!switch_strlen_zero(exit_sound)) {
menu->exit_sound = switch_core_strdup(menu->pool, exit_sound);
}
if (!switch_strlen_zero(tts_engine)) {
menu->tts_engine = switch_core_strdup(menu->pool, tts_engine);
}
if (!switch_strlen_zero(tts_voice)) {
menu->tts_voice = switch_core_strdup(menu->pool, tts_voice);
}
if (!switch_strlen_zero(phrase_lang)) {
menu->phrase_lang = switch_core_strdup(menu->pool, phrase_lang);
}
menu->max_failures = max_failures;
menu->timeout = timeout;
menu->actions = NULL;
if (newpool) {
menu->flags |= SWITCH_IVR_MENU_FLAG_FREEPOOL;
}
if (menu->timeout <= 0) {
menu->timeout = 10000;
}
if (main) {
switch_ivr_menu_stack_add(&main, menu);
} else {
menu->flags |= SWITCH_IVR_MENU_FLAG_STACK;
}
*new_menu = menu;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_action(switch_ivr_menu_t *menu, switch_ivr_action_t ivr_action,
const char *arg, const char *bind)
{
switch_ivr_menu_action_t *action;
uint32_t len;
if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
action->bind = switch_core_strdup(menu->pool, bind);
action->next = menu->actions;
action->arg = switch_core_strdup(menu->pool, arg);
len = (uint32_t) strlen(action->bind) + 1;
if (len > menu->inlen) {
menu->inlen = len;
}
action->ivr_action = ivr_action;
menu->actions = action;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu,
switch_ivr_menu_action_function_t * function,
const char *arg, const char *bind)
{
switch_ivr_menu_action_t *action;
uint32_t len;
if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
action->bind = switch_core_strdup(menu->pool, bind);
action->next = menu->actions;
action->arg = switch_core_strdup(menu->pool, arg);
len = (uint32_t) strlen(action->bind) + 1;
if (len > menu->inlen) {
menu->inlen = len;
}
action->function = function;
menu->actions = action;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_MEMERR;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_free(switch_ivr_menu_t *stack)
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (stack != NULL && stack->pool != NULL) {
if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK)
&& switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
switch_memory_pool_t *pool = stack->pool;
status = switch_core_destroy_memory_pool(&pool);
} else {
status = SWITCH_STATUS_SUCCESS;
}
}
return status;
}
static switch_status_t play_or_say(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, uint32_t need)
{
char terminator;
uint32_t len;
char *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_input_args_t args = { 0 };
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "play_or_say sound=[%s]\n", sound);
if (session != NULL && menu != NULL && !switch_strlen_zero(sound)) {
memset(menu->buf, 0, menu->inlen);
menu->ptr = menu->buf;
if (!need) {
len = 1;
ptr = NULL;
} else {
len = menu->inlen;
ptr = menu->ptr;
}
args.buf = ptr;
args.buflen = len;
if (*sound == '/' || *sound == '\\') {
status = switch_ivr_play_file(session, NULL, sound, &args);
} else {
if (strlen(sound) > 4 && strncmp(sound, "say:", 4) == 0) {
if (menu->tts_engine && menu->tts_voice) {
status = switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, 0, sound + 4, &args);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No TTS engine to play sound\n");
}
} else {
if (strlen(sound) > 7 && strncmp(sound, "phrase:", 7) == 0) {
status = switch_ivr_phrase_macro(session, sound + 7, "", menu->phrase_lang, &args);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"play_or_say: no player for [%s]. Use say: or phrase:\n", sound);
}
}
}
if (need) {
menu->ptr += strlen(menu->buf);
if (strlen(menu->buf) < need) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "waiting for %u digits\n", need);
status =
switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf), need, "#",
&terminator, menu->timeout);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "digits '%s'\n", menu->buf);
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "play_or_say returning [%d]\n", status);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *session, switch_ivr_menu_t *stack,
char *name, void *obj)
{
int reps = 0, errs = 0, match = 0, running = 1;
char *greeting_sound = NULL, *aptr = NULL;
char arg[512];
switch_ivr_action_t todo = SWITCH_IVR_ACTION_DIE;
switch_ivr_menu_action_t *ap;
switch_ivr_menu_t *menu;
switch_channel_t *channel;
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (session == NULL || stack == NULL || switch_strlen_zero(name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid menu context\n");
return SWITCH_STATUS_FALSE;
}
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if (!(menu = switch_ivr_menu_find(stack, name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Menu!\n");
return SWITCH_STATUS_FALSE;
}
if (!(menu->buf = malloc(menu->inlen))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Memory!\n");
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name);
for (reps = 0; (running && status == SWITCH_STATUS_SUCCESS && errs < menu->max_failures); reps++) {
if (!switch_channel_ready(channel)) {
break;
}
if (reps > 0 && menu->short_greeting_sound) {
greeting_sound = menu->short_greeting_sound;
} else {
greeting_sound = menu->greeting_sound;
}
match = 0;
aptr = NULL;
memset(arg, 0, sizeof(arg));
memset(menu->buf, 0, menu->inlen);
status = play_or_say(session, menu, greeting_sound, menu->inlen - 1);
if (!switch_strlen_zero(menu->buf)) {
for (ap = menu->actions; ap; ap = ap->next) {
if (!strcmp(menu->buf, ap->bind)) {
char *membuf;
match++;
errs = 0;
if (ap->function) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"IVR function on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf,
ap->arg);
todo = ap->function(menu, ap->arg, arg, sizeof(arg), obj);
aptr = arg;
} else {
todo = ap->ivr_action;
aptr = ap->arg;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"IVR action on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf,
aptr);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "switch_ivr_menu_execute todo=[%d]\n",
todo);
switch (todo) {
case SWITCH_IVR_ACTION_DIE:
status = SWITCH_STATUS_FALSE;
break;
case SWITCH_IVR_ACTION_PLAYSOUND:
status = switch_ivr_play_file(session, NULL, aptr, NULL);
break;
case SWITCH_IVR_ACTION_SAYTEXT:
status = switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, 0, aptr, NULL);
break;
case SWITCH_IVR_ACTION_SAYPHRASE:
status = switch_ivr_phrase_macro(session, aptr, "", menu->phrase_lang, NULL);
break;
case SWITCH_IVR_ACTION_TRANSFER:
switch_ivr_session_transfer(session, aptr, NULL, NULL);
running = 0;
break;
case SWITCH_IVR_ACTION_EXECMENU:
reps = -1;
status = switch_ivr_menu_execute(session, stack, aptr, obj);
break;
case SWITCH_IVR_ACTION_EXECAPP:{
const switch_application_interface_t *application_interface;
if ((membuf = strdup(aptr))) {
char *app_name = membuf;
char *app_arg = strchr(app_name, ' ');
if (app_arg) {
*app_arg = '\0';
app_arg++;
}
if (app_name && app_arg) {
if ((application_interface =
switch_loadable_module_get_application_interface(app_name))) {
if (application_interface->application_function) {
application_interface->application_function(session, app_arg);
}
}
}
}
}
break;
case SWITCH_IVR_ACTION_BACK:
running = 0;
status = SWITCH_STATUS_SUCCESS;
break;
case SWITCH_IVR_ACTION_TOMAIN:
switch_set_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
status = SWITCH_STATUS_BREAK;
break;
case SWITCH_IVR_ACTION_NOOP:
status = SWITCH_STATUS_SUCCESS;
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid TODO!\n");
break;
}
}
}
if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) { // top level
if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { // catch the fallback and recover
switch_clear_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
status = SWITCH_STATUS_SUCCESS;
running = 1;
continue;
}
}
}
if (!match) {
if (*menu->buf) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu '%s' caught invalid input '%s'\n",
menu->name, menu->buf);
if (menu->invalid_sound) {
play_or_say(session, menu, menu->invalid_sound, 0);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu '%s' no input detected\n",
menu->name);
}
errs++;
if (status == SWITCH_STATUS_SUCCESS) {
status = switch_ivr_sleep(session, 1000);
}
/* breaks are ok too */
if (SWITCH_STATUS_IS_BREAK(status)) {
status = SWITCH_STATUS_SUCCESS;
}
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "exit-sound '%s'\n", menu->exit_sound);
if (!switch_strlen_zero(menu->exit_sound)) {
play_or_say(session, menu, menu->exit_sound, 0);
}
switch_safe_free(menu->buf);
return status;
}
/******************************************************************************************************/
typedef struct switch_ivr_menu_xml_map {
char *name;
switch_ivr_action_t action;
switch_ivr_menu_action_function_t *function;
struct switch_ivr_menu_xml_map *next;
} switch_ivr_menu_xml_map_t;
struct switch_ivr_menu_xml_ctx {
switch_memory_pool_t *pool;
struct switch_ivr_menu_xml_map *map;
int autocreated;
};
static switch_ivr_menu_xml_map_t *switch_ivr_menu_stack_xml_find(switch_ivr_menu_xml_ctx_t *xml_ctx, char *name)
{
switch_ivr_menu_xml_map_t *map = (xml_ctx != NULL ? xml_ctx->map : NULL);
int rc = -1;
while (map != NULL && (rc = strcasecmp(map->name, name)) != 0) {
map = map->next;
}
return (rc == 0 ? map : NULL);
}
static switch_status_t switch_ivr_menu_stack_xml_add(switch_ivr_menu_xml_ctx_t *xml_ctx, char *name, int action,
switch_ivr_menu_action_function_t * function)
{
switch_status_t status = SWITCH_STATUS_FALSE;
// if this action/function does not exist yet
if (xml_ctx != NULL && name != NULL && xml_ctx->pool != NULL
&& switch_ivr_menu_stack_xml_find(xml_ctx, name) == NULL) {
switch_ivr_menu_xml_map_t *map = switch_core_alloc(xml_ctx->pool, sizeof(switch_ivr_menu_xml_map_t));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "switch_ivr_menu_stack_xml_add bindng '%s'\n", name);
// and we have memory
if (map != NULL) {
map->name = switch_core_strdup(xml_ctx->pool, name);
map->action = action;
map->function = function;
if (map->name != NULL) {
// insert map item at top of list
map->next = xml_ctx->map;
xml_ctx->map = map;
status = SWITCH_STATUS_SUCCESS;
} else {
status = SWITCH_STATUS_MEMERR;
}
} else {
status = SWITCH_STATUS_MEMERR;
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t **xml_menu_ctx,
switch_memory_pool_t *pool)
{
switch_status_t status = SWITCH_STATUS_FALSE;
int autocreated = 0;
// build a memory pool ?
if (pool == NULL) {
status = switch_core_new_memory_pool(&pool);
autocreated = 1;
}
// allocate the xml context
if (xml_menu_ctx != NULL && pool != NULL) {
*xml_menu_ctx = switch_core_alloc(pool, sizeof(switch_ivr_menu_xml_ctx_t));
if (*xml_menu_ctx != NULL) {
(*xml_menu_ctx)->pool = pool;
(*xml_menu_ctx)->autocreated = autocreated;
(*xml_menu_ctx)->map = NULL;
status = SWITCH_STATUS_SUCCESS;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to alloc xml_ctx\n");
status = SWITCH_STATUS_FALSE;
}
}
// build the standard/default xml menu handler mappings
if (status == SWITCH_STATUS_SUCCESS && xml_menu_ctx != NULL && *xml_menu_ctx != NULL) {
struct iam_s {
char *name;
switch_ivr_action_t action;
} iam[] = {
{
"menu-exit", SWITCH_IVR_ACTION_DIE}, {
"menu-sub", SWITCH_IVR_ACTION_EXECMENU}, {
"menu-exec-api", SWITCH_IVR_ACTION_EXECAPP}, {
"menu-play-sound", SWITCH_IVR_ACTION_PLAYSOUND}, {
"menu-say-text", SWITCH_IVR_ACTION_SAYTEXT}, {
"menu-say-phrase", SWITCH_IVR_ACTION_SAYPHRASE}, {
"menu-back", SWITCH_IVR_ACTION_BACK}, {
"menu-top", SWITCH_IVR_ACTION_TOMAIN}, {
"menu-call-transfer", SWITCH_IVR_ACTION_TRANSFER},};
int iam_qty = (sizeof(iam) / sizeof(iam[0]));
int i;
for (i = 0; i < iam_qty && status == SWITCH_STATUS_SUCCESS; i++) {
status = switch_ivr_menu_stack_xml_add(*xml_menu_ctx, iam[i].name, iam[i].action, NULL);
}
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_add_custom(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
char *name,
switch_ivr_menu_action_function_t * function)
{
return switch_ivr_menu_stack_xml_add(xml_menu_ctx, name, -1, function);
}
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_build(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
switch_ivr_menu_t **menu_stack,
switch_xml_t xml_menus, switch_xml_t xml_menu)
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (xml_menu_ctx != NULL && menu_stack != NULL && xml_menu != NULL) {
const char *menu_name = switch_xml_attr_soft(xml_menu, "name"); // if the attr doesn't exist, return ""
const char *greet_long = switch_xml_attr(xml_menu, "greet-long"); // if the attr doesn't exist, return NULL
const char *greet_short = switch_xml_attr(xml_menu, "greet-short"); // if the attr doesn't exist, return NULL
const char *invalid_sound = switch_xml_attr(xml_menu, "invalid-sound"); // if the attr doesn't exist, return NULL
const char *exit_sound = switch_xml_attr(xml_menu, "exit-sound"); // if the attr doesn't exist, return NULL
const char *tts_engine = switch_xml_attr(xml_menu, "tts-engine"); // if the attr doesn't exist, return NULL
const char *tts_voice = switch_xml_attr(xml_menu, "tts-voice"); // if the attr doesn't exist, return NULL
const char *phrase_lang = switch_xml_attr(xml_menu, "phrase-lang"); // if the attr doesn't exist, return NULL
const char *timeout = switch_xml_attr_soft(xml_menu, "timeout"); // if the attr doesn't exist, return ""
const char *max_failures = switch_xml_attr_soft(xml_menu, "max-failures"); // if the attr doesn't exist, return ""
switch_ivr_menu_t *menu = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "building menu '%s'\n", menu_name);
status = switch_ivr_menu_init(&menu,
*menu_stack,
menu_name,
greet_long,
greet_short,
invalid_sound,
exit_sound,
tts_engine,
tts_voice,
phrase_lang, atoi(timeout) * 1000, atoi(max_failures), xml_menu_ctx->pool);
// set the menu_stack for the caller
if (status == SWITCH_STATUS_SUCCESS && *menu_stack == NULL) {
*menu_stack = menu;
}
if (status == SWITCH_STATUS_SUCCESS && menu != NULL) {
switch_xml_t xml_kvp;
// build menu entries
for (xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL && status == SWITCH_STATUS_SUCCESS;
xml_kvp = xml_kvp->next) {
const char *action = switch_xml_attr(xml_kvp, "action");
const char *digits = switch_xml_attr(xml_kvp, "digits");
const char *param = switch_xml_attr_soft(xml_kvp, "param");
if (!switch_strlen_zero(action) && !switch_strlen_zero(digits)) {
switch_ivr_menu_xml_map_t *xml_map = xml_menu_ctx->map;
int found = 0;
// find and appropriate xml handler
while (xml_map != NULL && !found) {
if (!(found = (strcasecmp(xml_map->name, action) == 0))) {
xml_map = xml_map->next;
}
}
if (found && xml_map != NULL) {
// do we need to build a new sub-menu ?
if (xml_map->action == SWITCH_IVR_ACTION_EXECMENU
&& switch_ivr_menu_find(*menu_stack, param) == NULL) {
if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL) {
status = switch_ivr_menu_stack_xml_build(xml_menu_ctx, menu_stack, xml_menus, xml_menu);
}
}
// finally bind the menu entry
if (status == SWITCH_STATUS_SUCCESS) {
if (xml_map->function != NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"binding menu caller control '%s'/'%s' to '%s'\n", xml_map->name,
param, digits);
status = switch_ivr_menu_bind_function(menu, xml_map->function, param, digits);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"binding menu action '%s' to '%s'\n", xml_map->name, digits);
status = switch_ivr_menu_bind_action(menu, xml_map->action, param, digits);
}
}
}
} else {
status = SWITCH_STATUS_FALSE;
}
}
}
}
if (status != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to build xml menu\n");
}
return status;
}

963
src/switch_ivr_originate.c Normal file
View File

@ -0,0 +1,963 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
*
* switch_ivr_originate.c -- IVR Library (originate)
*
*/
#include <switch.h>
static const switch_state_handler_table_t originate_state_handlers;
static switch_status_t originate_on_ring(switch_core_session_t *session)
{
switch_channel_t *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
/* put the channel in a passive state so we can loop audio to it */
/* clear this handler so it only works once (next time (a.k.a. Transfer) we will do the real ring state) */
switch_channel_clear_state_handler(channel, &originate_state_handlers);
switch_channel_set_state(channel, CS_HOLD);
return SWITCH_STATUS_FALSE;
}
static const switch_state_handler_table_t originate_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ originate_on_ring,
/*.on_execute */ NULL,
/*.on_hangup */ NULL,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL,
/*.on_hold */ NULL
};
typedef enum {
IDX_CANCEL = -2,
IDX_NADA = -1
} abort_t;
struct key_collect {
char *key;
char *file;
switch_core_session_t *session;
};
static void *SWITCH_THREAD_FUNC collect_thread_run(switch_thread_t *thread, void *obj)
{
struct key_collect *collect = (struct key_collect *) obj;
switch_channel_t *channel = switch_core_session_get_channel(collect->session);
char buf[10] = "";
char *p, term;
if (!strcasecmp(collect->key, "exec")) {
char *data;
const switch_application_interface_t *application_interface;
char *app_name, *app_data;
if (!(data = collect->file)) {
goto wbreak;
}
app_name = data;
if ((app_data = strchr(app_name, ' '))) {
*app_data++ = '\0';
}
if ((application_interface = switch_loadable_module_get_application_interface(app_name)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Application %s\n", app_name);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
goto wbreak;
}
if (!application_interface->application_function) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Function for %s\n", app_name);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
goto wbreak;
}
application_interface->application_function(collect->session, app_data);
if (switch_channel_get_state(channel) < CS_HANGUP) {
switch_channel_set_flag(channel, CF_WINNER);
}
goto wbreak;
}
if (!switch_channel_ready(channel)) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
goto wbreak;
}
while (switch_channel_ready(channel)) {
memset(buf, 0, sizeof(buf));
if (collect->file) {
switch_input_args_t args = { 0 };
args.buf = buf;
args.buflen = sizeof(buf);
switch_ivr_play_file(collect->session, NULL, collect->file, &args);
} else {
switch_ivr_collect_digits_count(collect->session, buf, sizeof(buf), 1, "", &term, 0);
}
for (p = buf; *p; p++) {
if (*collect->key == *p) {
switch_channel_set_flag(channel, CF_WINNER);
goto wbreak;
}
}
}
wbreak:
return NULL;
}
static void launch_collect_thread(struct key_collect *collect)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, switch_core_session_get_pool(collect->session));
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, collect_thread_run, collect,
switch_core_session_get_pool(collect->session));
}
static uint8_t check_channel_status(switch_channel_t **peer_channels,
switch_core_session_t **peer_sessions,
uint32_t len,
int32_t *idx,
uint32_t * hups, char *file, char *key, uint8_t early_ok, uint8_t * ring_ready)
{
uint32_t i;
*hups = 0;
*idx = IDX_NADA;
for (i = 0; i < len; i++) {
if (!peer_channels[i]) {
continue;
}
if (!*ring_ready && switch_channel_test_flag(peer_channels[i], CF_RING_READY)) {
*ring_ready = 1;
}
if (switch_channel_get_state(peer_channels[i]) >= CS_HANGUP) {
(*hups)++;
} else if ((switch_channel_test_flag(peer_channels[i], CF_ANSWERED) ||
(early_ok && len == 1 && switch_channel_test_flag(peer_channels[i], CF_EARLY_MEDIA))) &&
!switch_channel_test_flag(peer_channels[i], CF_TAGGED)) {
if (key) {
struct key_collect *collect;
if ((collect = switch_core_session_alloc(peer_sessions[i], sizeof(*collect)))) {
switch_channel_set_flag(peer_channels[i], CF_TAGGED);
collect->key = key;
if (file) {
collect->file = switch_core_session_strdup(peer_sessions[i], file);
}
collect->session = peer_sessions[i];
launch_collect_thread(collect);
}
} else {
*idx = i;
return 0;
}
} else if (switch_channel_test_flag(peer_channels[i], CF_WINNER)) {
*idx = i;
return 0;
}
}
if (*hups == len) {
return 0;
} else {
return 1;
}
}
struct ringback {
switch_buffer_t *audio_buffer;
switch_buffer_t *loop_buffer;
teletone_generation_session_t ts;
switch_file_handle_t fhb;
switch_file_handle_t *fh;
uint8_t asis;
};
typedef struct ringback ringback_t;
static int teletone_handler(teletone_generation_session_t * ts, teletone_tone_map_t * map)
{
ringback_t *tto = ts->user_data;
int wrote;
if (!tto) {
return -1;
}
wrote = teletone_mux_tones(ts, map);
switch_buffer_write(tto->audio_buffer, ts->buffer, wrote * 2);
return 0;
}
#define MAX_PEERS 256
SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session,
switch_core_session_t **bleg,
switch_call_cause_t *cause,
char *bridgeto,
uint32_t timelimit_sec,
const switch_state_handler_table_t *table,
char *cid_name_override,
char *cid_num_override,
switch_caller_profile_t *caller_profile_override)
{
char *pipe_names[MAX_PEERS] = { 0 };
char *data = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *caller_channel = NULL;
char *peer_names[MAX_PEERS] = { 0 };
switch_core_session_t *peer_session, *peer_sessions[MAX_PEERS] = { 0 };
switch_caller_profile_t *caller_profiles[MAX_PEERS] = { 0 }, *caller_caller_profile;
char *chan_type = NULL, *chan_data;
switch_channel_t *peer_channel = NULL, *peer_channels[MAX_PEERS] = { 0 };
ringback_t ringback = { 0 };
time_t start;
switch_frame_t *read_frame = NULL;
switch_memory_pool_t *pool = NULL;
int r = 0, i, and_argc = 0, or_argc = 0;
int32_t sleep_ms = 1000, try = 0, retries = 1, idx = IDX_NADA;
switch_codec_t write_codec = { 0 };
switch_frame_t write_frame = { 0 };
uint8_t fdata[1024], pass = 0;
char *file = NULL, *key = NULL, *odata, *var;
switch_call_cause_t reason = SWITCH_CAUSE_UNALLOCATED;
uint8_t to = 0;
char *var_val, *vars = NULL, *ringback_data = NULL;
switch_codec_t *read_codec = NULL;
uint8_t sent_ring = 0, early_ok = 1;
switch_core_session_message_t *message = NULL;
switch_event_t *var_event = NULL;
uint8_t fail_on_single_reject = 0;
uint8_t ring_ready = 0;
char *loop_data = NULL;
write_frame.data = fdata;
*bleg = NULL;
odata = strdup(bridgeto);
data = odata;
/* strip leading spaces */
while (data && *data && *data == ' ') {
data++;
}
if (*data == '{') {
vars = data + 1;
if (!(data = strchr(data, '}'))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
status = SWITCH_STATUS_GENERR;
goto done;
}
*data++ = '\0';
}
/* strip leading spaces (again) */
while (data && *data && *data == ' ') {
data++;
}
if (switch_strlen_zero(data)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
status = SWITCH_STATUS_GENERR;
goto done;
}
/* Some channel are created from an originating channel and some aren't so not all outgoing calls have a way to get params
so we will normalize dialstring params and channel variables (when there is an originator) into an event that we
will use as a pseudo hash to consult for params as needed.
*/
if (switch_event_create(&var_event, SWITCH_EVENT_MESSAGE) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
status = SWITCH_STATUS_MEMERR;
goto done;
}
if (session) {
switch_hash_index_t *hi;
void *vval;
const void *vvar;
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
/* Copy all the channel variables into the event */
for (hi = switch_channel_variable_first(caller_channel, switch_core_session_get_pool(session)); hi;
hi = switch_hash_next(hi)) {
switch_hash_this(hi, &vvar, NULL, &vval);
if (vvar && vval) {
switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, (void *) vvar, "%s", (char *) vval);
}
}
}
if (vars) { /* Parse parameters specified from the dialstring */
char *var_array[1024] = { 0 };
int var_count = 0;
if ((var_count = switch_separate_string(vars, ',', var_array, (sizeof(var_array) / sizeof(var_array[0]))))) {
int x = 0;
for (x = 0; x < var_count; x++) {
char *inner_var_array[2];
int inner_var_count;
if ((inner_var_count =
switch_separate_string(var_array[x], '=', inner_var_array,
(sizeof(inner_var_array) / sizeof(inner_var_array[0])))) == 2) {
switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, inner_var_array[0], "%s",
inner_var_array[1]);
if (caller_channel) {
switch_channel_set_variable(caller_channel, inner_var_array[0], inner_var_array[1]);
}
}
}
}
}
if (caller_channel) { /* ringback is only useful when there is an originator */
ringback_data = switch_channel_get_variable(caller_channel, "ringback");
switch_channel_set_variable(caller_channel, "originate_disposition", "failure");
}
if ((var = switch_event_get_header(var_event, "group_confirm_key"))) {
key = switch_core_session_strdup(session, var);
if ((var = switch_event_get_header(var_event, "group_confirm_file"))) {
file = switch_core_session_strdup(session, var);
}
}
// When using the AND operator, the fail_on_single_reject flag may be set in order to indicate that a single
// rejections should terminate the attempt rather than a timeout, answer, or rejection by all.
if ((var = switch_event_get_header(var_event, "fail_on_single_reject")) && switch_true(var)) {
fail_on_single_reject = 1;
}
if (file && !strcmp(file, "undef")) {
file = NULL;
}
if ((var_val = switch_event_get_header(var_event, "ignore_early_media")) && switch_true(var_val)) {
early_ok = 0;
}
if ((var_val = switch_event_get_header(var_event, "originate_retries")) && switch_true(var_val)) {
int32_t tmp;
tmp = atoi(var_val);
if (tmp > 0 && tmp < 101) {
retries = tmp;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Invalid originate_retries setting of %d ignored, value must be between 1 and 100\n",
tmp);
}
}
if ((var_val = switch_event_get_header(var_event, "originate_retry_sleep_ms")) && switch_true(var_val)) {
int32_t tmp;
tmp = atoi(var_val);
if (tmp > 500 && tmp < 60000) {
sleep_ms = tmp;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Invalid originate_retry_sleep_ms setting of %d ignored, value must be between 500 and 60000\n",
tmp);
}
}
if (!cid_name_override) {
cid_name_override = switch_event_get_header(var_event, "origination_caller_id_name");
}
if (!cid_num_override) {
cid_num_override = switch_event_get_header(var_event, "origination_caller_id_number");
}
for (try = 0; try < retries; try++) {
switch_safe_free(loop_data);
assert(loop_data = strdup(data));
or_argc = switch_separate_string(loop_data, '|', pipe_names, (sizeof(pipe_names) / sizeof(pipe_names[0])));
if (caller_channel && or_argc > 1 && !ringback_data) {
switch_channel_ring_ready(caller_channel);
sent_ring = 1;
}
for (r = 0; r < or_argc; r++) {
uint32_t hups;
reason = SWITCH_CAUSE_UNALLOCATED;
memset(peer_names, 0, sizeof(peer_names));
peer_session = NULL;
memset(peer_sessions, 0, sizeof(peer_sessions));
memset(peer_channels, 0, sizeof(peer_channels));
memset(caller_profiles, 0, sizeof(caller_profiles));
chan_type = NULL;
chan_data = NULL;
peer_channel = NULL;
start = 0;
read_frame = NULL;
pool = NULL;
pass = 0;
file = NULL;
key = NULL;
var = NULL;
to = 0;
if (try > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Originate attempt %d/%d in %d ms\n", try + 1,
retries, sleep_ms);
switch_yield(sleep_ms * 1000);
}
and_argc =
switch_separate_string(pipe_names[r], ',', peer_names, (sizeof(peer_names) / sizeof(peer_names[0])));
if (caller_channel && !sent_ring && and_argc > 1 && !ringback_data) {
switch_channel_ring_ready(caller_channel);
sent_ring = 1;
}
for (i = 0; i < and_argc; i++) {
chan_type = peer_names[i];
if ((chan_data = strchr(chan_type, '/')) != 0) {
*chan_data = '\0';
chan_data++;
}
if (session) {
if (!switch_channel_ready(caller_channel)) {
status = SWITCH_STATUS_FALSE;
goto done;
}
caller_caller_profile =
caller_profile_override ? caller_profile_override :
switch_channel_get_caller_profile(caller_channel);
if (!cid_name_override) {
cid_name_override = caller_caller_profile->caller_id_name;
}
if (!cid_num_override) {
cid_num_override = caller_caller_profile->caller_id_number;
}
caller_profiles[i] = switch_caller_profile_new(switch_core_session_get_pool(session),
caller_caller_profile->username,
caller_caller_profile->dialplan,
cid_name_override,
cid_num_override,
caller_caller_profile->network_addr,
NULL,
NULL,
caller_caller_profile->rdnis,
caller_caller_profile->source,
caller_caller_profile->context, chan_data);
caller_profiles[i]->flags = caller_caller_profile->flags;
pool = NULL;
} else {
if (!cid_name_override) {
cid_name_override = "FreeSWITCH";
}
if (!cid_num_override) {
cid_num_override = "0000000000";
}
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
status = SWITCH_STATUS_TERM;
goto done;
}
if (caller_profile_override) {
caller_profiles[i] = switch_caller_profile_new(pool,
caller_profile_override->username,
caller_profile_override->dialplan,
caller_profile_override->caller_id_name,
caller_profile_override->caller_id_number,
caller_profile_override->network_addr,
caller_profile_override->ani,
caller_profile_override->aniii,
caller_profile_override->rdnis,
caller_profile_override->source,
caller_profile_override->context, chan_data);
} else {
caller_profiles[i] = switch_caller_profile_new(pool,
NULL,
NULL,
cid_name_override,
cid_num_override,
NULL,
NULL, NULL, NULL, __FILE__, NULL, chan_data);
}
}
if ((reason =
switch_core_session_outgoing_channel(session, chan_type, caller_profiles[i], &peer_sessions[i],
&pool)) != SWITCH_CAUSE_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Cannot Create Outgoing Channel! cause: %s\n", switch_channel_cause2str(reason));
if (pool) {
switch_core_destroy_memory_pool(&pool);
}
caller_profiles[i] = NULL;
peer_channels[i] = NULL;
peer_sessions[i] = NULL;
continue;
}
switch_core_session_read_lock(peer_sessions[i]);
pool = NULL;
peer_channels[i] = switch_core_session_get_channel(peer_sessions[i]);
assert(peer_channels[i] != NULL);
if (!table) {
table = &originate_state_handlers;
}
if (table) {
switch_channel_add_state_handler(peer_channels[i], table);
}
if (switch_core_session_running(peer_sessions[i])) {
switch_channel_set_state(peer_channels[i], CS_RING);
} else {
switch_core_session_thread_launch(peer_sessions[i]);
}
}
time(&start);
for (;;) {
uint32_t valid_channels = 0;
for (i = 0; i < and_argc; i++) {
int state;
if (!peer_channels[i]) {
continue;
}
valid_channels++;
state = switch_channel_get_state(peer_channels[i]);
if (state >= CS_HANGUP) {
goto notready;
} else if (state >= CS_RING) {
goto endfor1;
}
if (caller_channel && !switch_channel_ready(caller_channel)) {
goto notready;
}
if ((time(NULL) - start) > (time_t) timelimit_sec) {
to++;
idx = IDX_CANCEL;
goto notready;
}
switch_yield(1000);
}
if (valid_channels == 0) {
status = SWITCH_STATUS_GENERR;
goto done;
}
}
endfor1:
if (ringback_data && !switch_channel_test_flag(caller_channel, CF_ANSWERED)
&& !switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)) {
switch_channel_pre_answer(caller_channel);
}
if (session && (read_codec = switch_core_session_get_read_codec(session)) &&
(ringback_data || !switch_channel_test_flag(caller_channel, CF_NOMEDIA))) {
if (!(pass = (uint8_t) switch_test_flag(read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH))) {
if (switch_core_codec_init(&write_codec,
"L16",
NULL,
read_codec->implementation->samples_per_second,
read_codec->implementation->microseconds_per_frame / 1000,
1,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, pool) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"Raw Codec Activation Success L16@%uhz 1 channel %dms\n",
read_codec->implementation->samples_per_second,
read_codec->implementation->microseconds_per_frame / 1000);
write_frame.codec = &write_codec;
write_frame.datalen = read_codec->implementation->bytes_per_frame;
write_frame.samples = write_frame.datalen / 2;
memset(write_frame.data, 255, write_frame.datalen);
if (ringback_data) {
char *tmp_data = NULL;
switch_buffer_create_dynamic(&ringback.audio_buffer, 512, 1024, 0);
switch_buffer_create_dynamic(&ringback.loop_buffer, 512, 1024, 0);
if (*ringback_data == '/') {
char *ext;
if ((ext = strrchr(ringback_data, '.'))) {
switch_core_session_set_read_codec(session, &write_codec);
ext++;
} else {
ringback.asis++;
write_frame.codec = read_codec;
ext = read_codec->implementation->iananame;
tmp_data = switch_mprintf("%s.%s", ringback_data, ext);
ringback_data = tmp_data;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback File [%s]\n",
ringback_data);
ringback.fhb.channels = read_codec->implementation->number_of_channels;
ringback.fhb.samplerate = read_codec->implementation->samples_per_second;
if (switch_core_file_open(&ringback.fhb,
ringback_data,
read_codec->implementation->number_of_channels,
read_codec->implementation->samples_per_second,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
switch_core_session_get_pool(session)) !=
SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing File\n");
switch_safe_free(tmp_data);
goto notready;
}
ringback.fh = &ringback.fhb;
} else {
teletone_init_session(&ringback.ts, 0, teletone_handler, &ringback);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback Tone [%s]\n",
ringback_data);
//ringback.ts.debug = 1;
//ringback.ts.debug_stream = switch_core_get_console();
if (teletone_run(&ringback.ts, ringback_data)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing Tone\n");
teletone_destroy_session(&ringback.ts);
switch_buffer_destroy(&ringback.audio_buffer);
switch_buffer_destroy(&ringback.loop_buffer);
ringback_data = NULL;
}
}
switch_safe_free(tmp_data);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Error!");
switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
read_codec = NULL;
}
}
}
if (ringback_data) {
early_ok = 0;
}
while ((!caller_channel || switch_channel_ready(caller_channel)) &&
check_channel_status(peer_channels, peer_sessions, and_argc, &idx, &hups, file, key, early_ok,
&ring_ready)) {
// When the AND operator is being used, and fail_on_single_reject is set, a hangup indicates that the call should fail.
if ((to = (uint8_t) ((time(NULL) - start) >= (time_t) timelimit_sec))
|| (fail_on_single_reject && hups)) {
idx = IDX_CANCEL;
goto notready;
}
if (peer_sessions[0]
&& switch_core_session_dequeue_message(peer_sessions[0], &message) == SWITCH_STATUS_SUCCESS) {
if (session && !ringback_data && or_argc == 1 && and_argc == 1) { /* when there is only 1 channel to call and bridge and no ringback */
switch_core_session_receive_message(session, message);
}
if (switch_test_flag(message, SCSMF_DYNAMIC)) {
switch_safe_free(message);
} else {
message = NULL;
}
}
/* read from the channel while we wait if the audio is up on it */
if (session && (ringback_data || !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) &&
(switch_channel_test_flag(caller_channel, CF_ANSWERED)
|| switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) {
switch_status_t status = switch_core_session_read_frame(session, &read_frame, 1000, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
if (ring_ready && read_frame && !pass && !switch_test_flag(read_frame, SFF_CNG)
&& read_frame->datalen > 1) {
if (ringback.fh) {
uint8_t abuf[1024];
switch_size_t mlen, olen;
unsigned int pos = 0;
if (ringback.asis) {
mlen = read_frame->datalen;
} else {
mlen = read_frame->datalen / 2;
}
olen = mlen;
switch_core_file_read(ringback.fh, abuf, &olen);
if (olen == 0) {
olen = mlen;
ringback.fh->speed = 0;
switch_core_file_seek(ringback.fh, &pos, 0, SEEK_SET);
switch_core_file_read(ringback.fh, abuf, &olen);
if (olen == 0) {
break;
}
}
write_frame.data = abuf;
write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2);
if (switch_core_session_write_frame(session, &write_frame, 1000, 0) !=
SWITCH_STATUS_SUCCESS) {
break;
}
} else if (ringback.audio_buffer) {
if ((write_frame.datalen = (uint32_t) switch_buffer_read(ringback.audio_buffer,
write_frame.data,
write_frame.codec->implementation->
bytes_per_frame)) <= 0) {
switch_buffer_t *tmp;
tmp = ringback.audio_buffer;
ringback.audio_buffer = ringback.loop_buffer;
ringback.loop_buffer = tmp;
if ((write_frame.datalen = (uint32_t) switch_buffer_read(ringback.audio_buffer,
write_frame.data,
write_frame.codec->
implementation->
bytes_per_frame)) <= 0) {
break;
}
}
}
if (switch_core_session_write_frame(session, &write_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
break;
}
if (ringback.loop_buffer) {
switch_buffer_write(ringback.loop_buffer, write_frame.data, write_frame.datalen);
}
}
} else {
switch_yield(1000);
}
}
notready:
if (caller_channel && !switch_channel_ready(caller_channel)) {
idx = IDX_CANCEL;
}
if (session && (ringback_data || !switch_channel_test_flag(caller_channel, CF_NOMEDIA))) {
switch_core_session_reset(session);
}
for (i = 0; i < and_argc; i++) {
if (!peer_channels[i]) {
continue;
}
if (i != idx) {
if (idx == IDX_CANCEL) {
if (to) {
reason = SWITCH_CAUSE_NO_ANSWER;
} else {
reason = SWITCH_CAUSE_ORIGINATOR_CANCEL;
}
} else {
if (to) {
reason = SWITCH_CAUSE_NO_ANSWER;
} else if (and_argc > 1) {
reason = SWITCH_CAUSE_LOSE_RACE;
} else {
reason = SWITCH_CAUSE_NO_ANSWER;
}
}
switch_channel_hangup(peer_channels[i], reason);
}
}
if (idx > IDX_NADA) {
peer_session = peer_sessions[idx];
peer_channel = peer_channels[idx];
} else {
status = SWITCH_STATUS_FALSE;
goto done;
}
if (caller_channel) {
if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
switch_channel_answer(caller_channel);
} else if (switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
switch_channel_pre_answer(caller_channel);
}
}
if (switch_channel_test_flag(peer_channel, CF_ANSWERED)
|| switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
*bleg = peer_session;
status = SWITCH_STATUS_SUCCESS;
} else {
status = SWITCH_STATUS_FALSE;
}
done:
*cause = SWITCH_CAUSE_UNALLOCATED;
if (var_event) {
if (peer_channel && !caller_channel) { /* install the vars from the {} params */
switch_event_header_t *header;
for (header = var_event->headers; header; header = header->next) {
switch_channel_set_variable(peer_channel, header->name, header->value);
}
}
switch_event_destroy(&var_event);
}
if (status == SWITCH_STATUS_SUCCESS) {
if (caller_channel) {
switch_channel_set_variable(caller_channel, "originate_disposition", "call accepted");
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Originate Resulted in Success: [%s]\n",
switch_channel_get_name(peer_channel));
*cause = SWITCH_CAUSE_SUCCESS;
} else {
if (peer_channel) {
*cause = switch_channel_get_cause(peer_channel);
} else {
for (i = 0; i < and_argc; i++) {
if (!peer_channels[i]) {
continue;
}
*cause = switch_channel_get_cause(peer_channels[i]);
break;
}
}
if (!*cause) {
if (reason) {
*cause = reason;
} else if (caller_channel) {
*cause = switch_channel_get_cause(caller_channel);
} else {
*cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
}
if (idx == IDX_CANCEL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"Originate Cancelled by originator termination Cause: %d [%s]\n", *cause,
switch_channel_cause2str(*cause));
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"Originate Resulted in Error Cause: %d [%s]\n", *cause,
switch_channel_cause2str(*cause));
}
}
if (caller_channel) {
switch_channel_set_variable(caller_channel, "originate_disposition", switch_channel_cause2str(*cause));
}
if (!pass && write_codec.implementation) {
switch_core_codec_destroy(&write_codec);
}
if (ringback.fh) {
switch_core_file_close(ringback.fh);
ringback.fh = NULL;
if (read_codec && !ringback.asis) {
switch_core_session_set_read_codec(session, read_codec);
switch_core_session_reset(session);
}
} else if (ringback.audio_buffer) {
teletone_destroy_session(&ringback.ts);
switch_buffer_destroy(&ringback.audio_buffer);
switch_buffer_destroy(&ringback.loop_buffer);
}
for (i = 0; i < and_argc; i++) {
if (!peer_channels[i]) {
continue;
}
switch_core_session_rwunlock(peer_sessions[i]);
}
if (status == SWITCH_STATUS_SUCCESS) {
goto outer_for;
}
}
}
outer_for:
switch_safe_free(loop_data);
switch_safe_free(odata);
return status;
}

1321
src/switch_ivr_play_say.c Normal file

File diff suppressed because it is too large Load Diff

234
src/switch_scheduler.c Normal file
View File

@ -0,0 +1,234 @@
#include <switch.h>
struct switch_scheduler_task_container {
switch_scheduler_task_t task;
time_t executed;
int in_thread;
int destroyed;
switch_scheduler_func_t func;
switch_memory_pool_t *pool;
uint32_t flags;
char *desc;
struct switch_scheduler_task_container *next;
};
typedef struct switch_scheduler_task_container switch_scheduler_task_container_t;
static struct {
switch_scheduler_task_container_t *task_list;
switch_mutex_t *task_mutex;
uint32_t task_id;
int task_thread_running;
switch_memory_pool_t *memory_pool;
} globals;
static void switch_scheduler_execute(switch_scheduler_task_container_t * tp)
{
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing task %u %s (%s)\n", tp->task.task_id, tp->desc, switch_str_nil(tp->task.group));
tp->func(&tp->task);
if (tp->task.runtime > tp->executed) {
tp->executed = 0;
} else {
tp->destroyed = 1;
}
}
static void *SWITCH_THREAD_FUNC task_own_thread(switch_thread_t *thread, void *obj)
{
switch_scheduler_task_container_t *tp = (switch_scheduler_task_container_t *) obj;
switch_memory_pool_t *pool;
pool = tp->pool;
tp->pool = NULL;
switch_scheduler_execute(tp);
switch_core_destroy_memory_pool(&pool);
tp->in_thread = 0;
return NULL;
}
static int task_thread_loop(int done)
{
switch_scheduler_task_container_t *tofree, *tp, *last = NULL;
switch_mutex_lock(globals.task_mutex);
for (tp = globals.task_list; tp; tp = tp->next) {
if (done) {
tp->destroyed = 1;
} else {
time_t now = time(NULL);
if (now >= tp->task.runtime && !tp->in_thread) {
tp->executed = now;
if (switch_test_flag(tp, SSHF_OWN_THREAD)) {
switch_thread_t *thread;
switch_threadattr_t *thd_attr;
switch_core_new_memory_pool(&tp->pool);
switch_threadattr_create(&thd_attr, tp->pool);
switch_threadattr_detach_set(thd_attr, 1);
tp->in_thread = 1;
switch_thread_create(&thread, thd_attr, task_own_thread, tp, tp->pool);
} else {
switch_scheduler_execute(tp);
}
}
}
}
switch_mutex_unlock(globals.task_mutex);
switch_mutex_lock(globals.task_mutex);
for (tp = globals.task_list; tp;) {
if (tp->destroyed && !tp->in_thread) {
tofree = tp;
tp = tp->next;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleting task %u %s (%s)\n",
tofree->task.task_id, tofree->desc, switch_str_nil(tofree->task.group));
if (last) {
last->next = tofree->next;
} else {
globals.task_list = tofree->next;
}
switch_safe_free(tofree->task.group);
if (tofree->task.cmd_arg && switch_test_flag(tofree, SSHF_FREE_ARG)) {
free(tofree->task.cmd_arg);
}
switch_safe_free(tofree->desc);
free(tofree);
} else {
last = tp;
tp = tp->next;
}
}
switch_mutex_unlock(globals.task_mutex);
return done;
}
static void *SWITCH_THREAD_FUNC switch_scheduler_task_thread(switch_thread_t *thread, void *obj)
{
globals.task_thread_running = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Starting task thread\n");
while (globals.task_thread_running == 1) {
if (task_thread_loop(0)) {
break;
}
switch_yield(500000);
}
task_thread_loop(1);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Task thread ending\n");
globals.task_thread_running = 0;
return NULL;
}
SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
switch_scheduler_func_t func,
char *desc,
char *group,
uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags)
{
switch_scheduler_task_container_t *container, *tp;
switch_mutex_lock(globals.task_mutex);
switch_zmalloc(container, sizeof(*container));
assert(func);
container->func = func;
time(&container->task.created);
container->task.runtime = task_runtime;
container->task.group = strdup(group ? group : "none");
container->task.cmd_id = cmd_id;
container->task.cmd_arg = cmd_arg;
container->flags = flags;
container->desc = strdup(desc ? desc : "none");
for (tp = globals.task_list; tp && tp->next; tp = tp->next);
if (tp) {
tp->next = container;
} else {
globals.task_list = container;
}
for (container->task.task_id = 0; !container->task.task_id; container->task.task_id = ++globals.task_id);
switch_mutex_unlock(globals.task_mutex);
tp = container;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Added task %u %s (%s) to run at %" TIME_T_FMT "\n",
tp->task.task_id, tp->desc, switch_str_nil(tp->task.group), task_runtime);
return container->task.task_id;
}
SWITCH_DECLARE(switch_status_t) switch_scheduler_del_task_id(uint32_t task_id)
{
switch_scheduler_task_container_t *tp;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_mutex_lock(globals.task_mutex);
for (tp = globals.task_list; tp; tp = tp->next) {
if (tp->task.task_id == task_id) {
tp->destroyed++;
status = SWITCH_STATUS_SUCCESS;
break;
}
}
switch_mutex_unlock(globals.task_mutex);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_scheduler_del_task_group(char *group)
{
switch_scheduler_task_container_t *tp;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_mutex_lock(globals.task_mutex);
for (tp = globals.task_list; tp; tp = tp->next) {
if (!strcmp(tp->task.group, group)) {
tp->destroyed++;
status = SWITCH_STATUS_SUCCESS;
}
}
switch_mutex_unlock(globals.task_mutex);
return status;
}
SWITCH_DECLARE(void) switch_scheduler_task_thread_start(void)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr;
switch_core_new_memory_pool(&globals.memory_pool);
switch_threadattr_create(&thd_attr, globals.memory_pool);
switch_mutex_init(&globals.task_mutex, SWITCH_MUTEX_NESTED, globals.memory_pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_thread_create(&thread, thd_attr, switch_scheduler_task_thread, NULL, globals.memory_pool);
}
SWITCH_DECLARE(void) switch_scheduler_task_thread_stop(void)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Stopping Task Thread\n");
if (globals.task_thread_running == 1) {
int sanity = 0;
globals.task_thread_running = -1;
while (globals.task_thread_running) {
switch_yield(100000);
if (++sanity > 10) {
break;
}
}
}
}