小小幸运
喜欢古典篮球的-程序员小哥
一通电话呼入、或呼出时候,freeswitch会有创建对应的session和channel,作为一个B2BUA,一次通话一般为两条腿,每一个都创建一个channel。
a ------------- b left
a ------------- b right
session代表描述了会话,更多的会话状态存储在session中。同时,fs中session与channel一一对应。
struct switch_channel;
/*! \brief A core session representing a call and all of it's resources */
struct switch_core_session;
strcut swtich_core_session, 我们看看它在源码中的定义
struct switch_core_session {
switch_memory_pool_t *pool;
switch_thread_t *thread;
switch_thread_id_t thread_id;
switch_endpoint_interface_t *endpoint_interface;
switch_size_t id;
switch_session_flag_t flags;
switch_channel_t *channel;
switch_io_event_hooks_t event_hooks;
switch_codec_t *read_codec;
switch_codec_t *real_read_codec;
switch_codec_t *write_codec;
switch_codec_t *real_write_codec;
switch_codec_t *video_read_codec;
switch_codec_t *video_write_codec;
switch_codec_implementation_t read_impl;
switch_codec_implementation_t real_read_impl;
switch_codec_implementation_t write_impl;
switch_codec_implementation_t video_read_impl;
switch_codec_implementation_t video_write_impl;
switch_audio_resampler_t *read_resampler;
switch_audio_resampler_t *write_resampler;
switch_mutex_t *mutex;
switch_mutex_t *resample_mutex;
switch_mutex_t *codec_read_mutex;
switch_mutex_t *codec_write_mutex;
switch_mutex_t *video_codec_read_mutex;
switch_mutex_t *video_codec_write_mutex;
switch_thread_cond_t *cond;
switch_mutex_t *frame_read_mutex;
switch_thread_rwlock_t *rwlock;
switch_thread_rwlock_t *io_rwlock;
void *streams[SWITCH_MAX_STREAMS];
int stream_count;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
void *private_info[SWITCH_CORE_SESSION_MAX_PRIVATES];
switch_queue_t *event_queue;
switch_queue_t *message_queue;
switch_queue_t *signal_data_queue;
switch_queue_t *private_event_queue;
switch_queue_t *private_event_queue_pri;
switch_thread_rwlock_t *bug_rwlock;
switch_media_bug_t *bugs;
switch_app_log_t *app_log;
uint32_t stack_count;
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];
/* video frame.data being trated differently than audio, allocate a dynamic data buffer if necessary*/
switch_buffer_t *video_raw_write_buffer;
switch_frame_t video_raw_write_frame;
// switch_frame_t video_enc_write_frame;
switch_buffer_t *video_raw_read_buffer;
switch_frame_t video_raw_read_frame;
// switch_frame_t video_enc_read_frame;
switch_codec_t bug_codec;
uint32_t read_frame_count;
uint32_t track_duration;
uint32_t track_id;
switch_log_level_t loglevel;
uint32_t soft_lock;
switch_ivr_dmachine_t *dmachine[2];
plc_state_t *plc;
switch_media_handle_t *media_handle;
uint32_t decoder_errors;
switch_core_video_thread_callback_func_t video_read_callback;
void *video_read_user_data;
switch_slin_data_t *sdata;
};
在这个结构体中,我们没有看见和channel的关系, 那系统方法:switch_coresession_get_ channel(session) 是如何实现的呢? 为何不直接 session->channel 呢,我没看明白。
struct switch_channel {
char *name;
switch_call_direction_t direction;
switch_call_direction_t logical_direction;
switch_queue_t *dtmf_queue;
switch_queue_t *dtmf_log_queue;
switch_mutex_t*dtmf_mutex;
switch_mutex_t *flag_mutex;
switch_mutex_t *state_mutex;
switch_mutex_t *thread_mutex;
switch_mutex_t *profile_mutex;
switch_core_session_t *session;
switch_channel_state_t state;
switch_channel_state_t running_state;
switch_channel_callstate_t callstate;
uint32_t flags[CF_FLAG_MAX];
uint32_t caps[CC_FLAG_MAX];
uint8_t state_flags[CF_FLAG_MAX];
uint32_t private_flags;
switch_caller_profile_t *caller_profile;
const switch_state_handler_table_t *state_handlers[SWITCH_MAX_STATE_HANDLERS];
int state_handler_index;
switch_event_t *variables;
switch_event_t *scope_variables;
switch_hash_t *private_hash;
switch_hash_t *app_flag_hash;
switch_call_cause_t hangup_cause;
int vi;
int event_count;
int profile_index;
opaque_channel_flag_t opaque_flags;
switch_originator_type_t last_profile_type;
switch_caller_extension_t *queued_extension;
switch_event_t *app_list;
switch_event_t *api_list;
switch_event_t *var_list;
switch_hold_record_t *hold_record;
switch_device_node_t *device_node;
char *device_id;
};
channel初始化函数,那么谁调用他了?
SWITCH_DECLARE(switch_status_t) switch_channel_init(switch_channel_t *channel, switch_core_session_t *session, switch_channel_state_t state,
switch_channel_flag_t flag)
{
switch_assert(channel != NULL);
channel->state = state;
switch_channel_set_flag(channel, flag);
channel->session = session;
channel->running_state = CS_NONE;
return SWITCH_STATUS_SUCCESS;
}
我们在switchcore_session.c 文件中找到了
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_endpoint_interface_t
*endpoint_interface,
switch_call_direction_t direction,
switch_originate_flag_t originate_flags,
switch_memory_pool_t **pool, const char *use_uuid)
{
switch_memory_pool_t *usepool;
switch_core_session_t *session;
switch_uuid_t uuid;
uint32_t count = 0;
int32_t sps = 0;
if (use_uuid && switch_core_hash_find(session_manager.session_table, use_uuid)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Duplicate UUID!\n");
return NULL;
}
if (direction == SWITCH_CALL_DIRECTION_INBOUND && !switch_core_ready_inbound()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The system cannot create any inbound sessions at this time.\n");
return NULL;
}
if (direction == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_core_ready_outbound()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The system cannot create any outbound sessions at this time.\n");
return NULL;
}
if (!switch_core_ready() || endpoint_interface == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The system cannot create any sessions at this time.\n");
return NULL;
}
if (runtime.min_idle_time > 0 && runtime.profile_time < runtime.min_idle_time) {
return NULL;
}
PROTECT_INTERFACE(endpoint_interface);
if (!(originate_flags & SOF_NO_LIMITS)) {
switch_mutex_lock(runtime.throttle_mutex);
count = session_manager.session_count;
sps = --runtime.sps;
switch_mutex_unlock(runtime.throttle_mutex);
if (sps <= 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Throttle Error! %d\n", session_manager.session_count);
UNPROTECT_INTERFACE(endpoint_interface);
return NULL;
}
if ((count + 1) > session_manager.session_limit) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Over Session Limit! %d\n", session_manager.session_limit);
UNPROTECT_INTERFACE(endpoint_interface);
return NULL;
}
}
if (pool && *pool) {
usepool = *pool;
*pool = NULL;
} else {
switch_core_new_memory_pool(&usepool);
}
session = switch_core_alloc(usepool, sizeof(*session));
session->pool = usepool;
switch_core_memory_pool_set_data(session->pool, "__session", session);
if (switch_channel_alloc(&session->channel, direction, session->pool) != SWITCH_STATUS_SUCCESS) {
abort();
}
switch_channel_init(session->channel, session, CS_NEW, 0);
if (direction == SWITCH_CALL_DIRECTION_OUTBOUND) {
switch_channel_set_flag(session->channel, CF_OUTBOUND);
}
/* 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 */
if (use_uuid) {
switch_set_string(session->uuid_str, use_uuid);
} else {
switch_uuid_get(&uuid);
switch_uuid_format(session->uuid_str, &uuid);
}
switch_channel_set_variable(session->channel, "uuid", session->uuid_str);
switch_channel_set_variable(session->channel, "call_uuid", session->uuid_str);
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_mutex_init(&session->resample_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->codec_write_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->video_codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->video_codec_write_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->frame_read_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);
switch_thread_rwlock_create(&session->io_rwlock, session->pool);
switch_queue_create(&session->message_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool);
switch_queue_create(&session->signal_data_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool);
switch_queue_create(&session->event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
switch_queue_create(&session->private_event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
switch_queue_create(&session->private_event_queue_pri, SWITCH_EVENT_QUEUE_LEN, session->pool);
switch_mutex_lock(runtime.session_hash_mutex);
switch_core_hash_insert(session_manager.session_table, session->uuid_str, session);
session->id = session_manager.session_id++;
session_manager.session_count++;
if (session_manager.session_count > (uint32_t)runtime.sessions_peak) {
runtime.sessions_peak = session_manager.session_count;
}
if (session_manager.session_count > (uint32_t)runtime.sessions_peak_fivemin) {
runtime.sessions_peak_fivemin = session_manager.session_count;
}
switch_mutex_unlock(runtime.session_hash_mutex);
switch_channel_set_variable_printf(session->channel, "session_id", "%u", session->id);
return session;
}
现在看关键的代码:
session = switch_core_alloc(usepool, sizeof(*session));
session->pool = usepool;
switch_core_memory_pool_set_data(session->pool, "__session", session);
if (switch_channel_alloc(&session->channel, direction, session->pool) != SWITCH_STATUS_SUCCESS) {
abort();
}
switch_channel_init(session->channel, session, CS_NEW, 0);
可以石锤,每一次 switch_core_session_request_uuid即创建了session,同时也为channel申请了内存,并进行了创建初始化。 由此可知 session--channel 一一对应。
我们通过查询 state_t 字符,发现只有channel有类似的状态情况,session并未定义。
typedef enum {
SDS_DOWN,
SDS_RINGING,
SDS_ACTIVE,
SDS_ACTIVE_MULTI,
SDS_HELD,
SDS_UNHELD,
SDS_HANGUP
} switch_device_state_t;
/*!
\enum switch_channel_state_t
\brief Channel States (these are the defaults, CS_SOFT_EXECUTE, CS_EXCHANGE_MEDIA, and CS_CONSUME_MEDIA are often overridden by specific apps)
CS_NEW - Channel is newly created.
CS_INIT - Channel has been initialized.
CS_ROUTING - Channel is looking for an extension to execute.
CS_SOFT_EXECUTE - Channel is ready to execute from 3rd party control.
CS_EXECUTE - Channel is executing it's dialplan.
CS_EXCHANGE_MEDIA - Channel is exchanging media with another channel.
CS_PARK - Channel is accepting media awaiting commands.
CS_CONSUME_MEDIA - Channel is consuming all media and dropping it.
CS_HIBERNATE - Channel is in a sleep state.
CS_RESET - Channel is in a reset state.
CS_HANGUP - Channel is flagged for hangup and ready to end.
CS_REPORTING - Channel is ready to collect call detail.
CS_DESTROY - Channel is ready to be destroyed and out of the state machine.
*/
typedef enum {
CS_NEW,
CS_INIT,
CS_ROUTING,
CS_SOFT_EXECUTE,
CS_EXECUTE,
CS_EXCHANGE_MEDIA,
CS_PARK,
CS_CONSUME_MEDIA,
CS_HIBERNATE,
CS_RESET,
CS_HANGUP,
CS_REPORTING,
CS_DESTROY,
CS_NONE
} switch_channel_state_t;
我们重点看一下 state状态,一个channel的都有哪些状态,同时freeswitch源码竟然做了如此详尽的描述。
CS_NEW - Channel is newly created.
CS_INIT - Channel has been initialized.
CS_ROUTING - Channel is looking for an extension to execute.
CS_SOFT_EXECUTE - Channel is ready to execute from 3rd party control.
CS_EXECUTE - Channel is executing it's dialplan.
CS_EXCHANGE_MEDIA - Channel is exchanging media with another channel.
CS_PARK - Channel is accepting media awaiting commands.
CS_CONSUME_MEDIA - Channel is consuming all media and dropping it.
CS_HIBERNATE - Channel is in a sleep state.
CS_RESET - Channel is in a reset state.
CS_HANGUP - Channel is flagged for hangup and ready to end.
CS_REPORTING - Channel is ready to collect call detail.
CS_DESTROY - Channel is ready to be destroyed and out of the state machine.
看了一圈源码,好像有点明白fs的session和channel的关系了,哈哈。 继续努力