freeswitch的session和channel

小小幸运

小小幸运

喜欢古典篮球的-程序员小哥

一通电话呼入、或呼出时候,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的关系了,哈哈。 继续努力

你可能感兴趣的:(智能外呼,freeswitch)