freeswitch系列4 session

  1. 初始化

session在switch_core_session.c实现,在switch_core_pvt.h定义相关数据结构。在第2章节初始化的时候,在核心初始化里会调用session初始化。

 

  1. void switch_core_session_init(switch_memory_pool_t *pool)  
  2. {  
  3.     memset(&session_manager, 0, sizeof(session_manager));  
  4.     session_manager.session_limit = 1000;  
  5.     session_manager.session_id = 1;  
  6.     session_manager.memory_pool = pool;  
  7.     switch_core_hash_init(&session_manager.session_table);  
  8.     switch_mutex_init(&session_manager.mutex, SWITCH_MUTEX_DEFAULT, session_manager.memory_pool);  
  9.     switch_thread_cond_create(&session_manager.cond, session_manager.memory_pool);  
  10.     switch_queue_create(&session_manager.thread_queue, 100000, session_manager.memory_pool);  
  11. }  
  1.  

...

  1. struct switch_session_manager {  
  2.     switch_memory_pool_t *memory_pool;  
  3.     switch_hash_t *session_table;  
  4.     uint32_t session_count;  
  5.     uint32_t session_limit;  
  6.     switch_size_t session_id;  
  7.     switch_queue_t *thread_queue;  
  8.     switch_mutex_t *mutex;  
  9.     switch_thread_cond_t *cond;  
  10.     int running;  
  11.     int busy;  
  12. };  
  13.   
  14. extern struct switch_session_manager session_manager;  

 

初始化内容比较简单,就是对session全局结构体session_manager进行初始化默认值。这个结构体管理以后创建的会话,其中哈希表session_table作为会话容器,session_count表示当前会话个数,session_limit限制最大会话个数,session_id每次创建都会++,为会话生成唯一id,thread_queue线程队列,运行sesson可以使用此线程池,当然也可以不用线程池。

 

  1. 创建session

当收到invite信令的时候,sip逻辑层mod_sofia就会调用switch_core_session_request_uuid创建会话。

 

  1. SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_endpoint_interface_t  
  2.                                                                          *endpoint_interface,  
  3.                                                                          switch_call_direction_t direction,  
  4.                                                                          switch_originate_flag_t originate_flags,  
  5.                                                                          switch_memory_pool_t **pool, const char *use_uuid)  
  6. {  
  7.     switch_memory_pool_t *usepool;  
  8.     switch_core_session_t *session;  
  9.     switch_uuid_t uuid;  
  10.   
  11.     //判断是否已经添加到哈希表  
  12.     if (use_uuid && switch_core_hash_find(session_manager.session_table, use_uuid)) {  
  13.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Duplicate UUID!\n");  
  14.         return NULL;  
  15.     }  
  16.   
  17.     //申请switch_core_session_t内存  
  18.     session = switch_core_alloc(usepool, sizeof(*session));  
  19.     session->pool = usepool;  
  20.   
  21.     switch_core_memory_pool_set_data(session->pool, "__session", session);  
  22.   
  23.     //申请session的channel内存  
  24.     if (switch_channel_alloc(&session->channel, direction, session->pool) != SWITCH_STATUS_SUCCESS) {  
  25.         abort();  
  26.     }  
  27.   
  28.     //初始化channel  
  29.     switch_channel_init(session->channel, session, CS_NEW, 0);  
  30.   
  31.     if (direction == SWITCH_CALL_DIRECTION_OUTBOUND) {  
  32.         switch_channel_set_flag(session->channel, CF_OUTBOUND);  
  33.     }  
  34.   
  35.     //设置一些session和channel的值  
  36.     if (use_uuid) {  
  37.         switch_set_string(session->uuid_str, use_uuid);  
  38.     } else {  
  39.         switch_uuid_get(&uuid);  
  40.         switch_uuid_format(session->uuid_str, &uuid);  
  41.     }  
  42.   
  43.     switch_channel_set_variable(session->channel, "uuid", session->uuid_str);  
  44.     switch_channel_set_variable(session->channel, "call_uuid", session->uuid_str);  
  45.   
  46.     session->endpoint_interface = endpoint_interface;  
  47.     ...  
  48.     //创建消息队列  
  49.     switch_queue_create(&session->message_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool);  
  50.   
  51.     //添加当前会话到会话容器哈希表,更新session_manager的一些值  
  52.     switch_mutex_lock(runtime.session_hash_mutex);  
  53.     switch_core_hash_insert(session_manager.session_table, session->uuid_str, session);  
  54.     session->id = session_manager.session_id++;  
  55.     session_manager.session_count++;  
  56.     switch_mutex_unlock(runtime.session_hash_mutex);  
  57.   
  58.     switch_channel_set_variable_printf(session->channel, "session_id""%u", session->id);  
  59.   
  60.     return session;  
  61. }

 

每个session对应一个channel,session更多地是描述信令状态,channel更多地描述传输状态。创建session的时候,同时会创建channel,session会添加到会话管理session_manager。创建的时候,会初始化session和channel的一些变量,这里比较重要的是session的消息队列message_queue。channel本章节先不讨论,下面看看session结构体。

 

  1. struct switch_core_session {  
  2.     switch_memory_pool_t *pool;  
  3.     switch_thread_t *thread;  
  4.     switch_thread_id_t thread_id;  
  5.     switch_endpoint_interface_t *endpoint_interface;  
  6.     switch_size_t id;  
  7.     switch_session_flag_t flags;  
  8.     switch_channel_t *channel;  
  9.   
  10.     //codec相关  
  11.     switch_codec_t  
  12.   
  13.     //消息队列  
  14.     switch_queue_t *event_queue;  
  15.     switch_queue_t *message_queue;  
  16.   
  17.     //读写缓冲区相关  
  18.     switch_buffer_t *raw_write_buffer;  
  19.     switch_frame_t raw_write_frame;  
  20.     switch_frame_t enc_write_frame;  
  21.     uint8_t raw_write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];  
  22.     uint8_t enc_write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];  
  23.   
  24.     switch_buffer_t *raw_read_buffer;  
  25.     switch_frame_t raw_read_frame;  
  26.     switch_frame_t enc_read_frame;  
  27.     uint8_t raw_read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];  
  28.     uint8_t enc_read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];  
  29. };

 

session结构体有不少成员,这里列出比较重要的,一个session会有一个线程thread来处理消息,消息队列message_queue;有一个channel,有codec相关的结构体,读写一帧的缓冲区等。

 

  1. session线程

创建完session之后,还不能工作,会随后创建并启动session线程,至于在什么时候启动,后面分析mod_sofia会分析。这里查看session相关的API,启动session线程的接口有四个。

 

  1. //创建线程的四个接口  
  2. switch_thread_pool_launch_thread(switch_thread_data_t **tdp);  
  3. switch_core_session_thread_pool_launch(switch_core_session_t *session);  
  4.   
  5. switch_core_session_thread_launch(_In_ switch_core_session_t *session);  
  6. switch_core_session_launch_thread(_In_ switch_core_session_t *session,  
  7.              _In_ void *(*func) (switch_thread_t *, void *), _In_opt_ void *obj);  

 

 

前面两个是使用线程池,后面两个是普通线程。

 

  1. SWITCH_DECLARE(switch_status_t) switch_thread_pool_launch_thread(switch_thread_data_t **tdp)  
  2. {  
  3.     switch_status_t status = SWITCH_STATUS_SUCCESS;  
  4.     switch_thread_data_t *td;  
  5.   
  6.     td = *tdp;  
  7.     *tdp = NULL;  
  8.   
  9.     status = switch_queue_push(session_manager.thread_queue, td);  
  10.     check_queue();  
  11.   
  12.     return status;    
  13. }  
  14.   
  15. SWITCH_DECLARE(switch_status_t) switch_core_session_thread_pool_launch(switch_core_session_t *session)  
  16. {  
  17.     switch_status_t status = SWITCH_STATUS_INUSE;  
  18.     switch_thread_data_t *td;  
  19.   
  20.     switch_mutex_lock(session->mutex);  
  21.     if (switch_test_flag(session, SSF_THREAD_RUNNING)) {  
  22.         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n");  
  23.     } else if (switch_test_flag(session, SSF_THREAD_STARTED)) {  
  24.         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot launch thread again after it has already been run!\n");  
  25.     } else {  
  26.         switch_set_flag(session, SSF_THREAD_RUNNING);  
  27.         switch_set_flag(session, SSF_THREAD_STARTED);  
  28.         td = switch_core_session_alloc(session, sizeof(*td));  
  29.         td->obj = session;  
  30.         td->func = switch_core_session_thread;  
  31.         status = switch_queue_push(session_manager.thread_queue, td);  
  32.         check_queue();  
  33.     }  
  34.     switch_mutex_unlock(session->mutex);  
  35.   
  36.     return status;  

 

如果使用线程池,则添加到会话管理session_manager.thread_queue线程队列,switch_thread_pool_launch_thread的线程执行函数由外部传入,switch_core_session_thread_pool_launch的线程执行函数是switch_core_session_thread,由此猜测,第一个函数主要给外部模块调用,第二个供core调用。然后再看看非线程池的两个接口。

 

 

  1. SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(switch_core_session_t *session)  
  2. {  
  3.     switch_status_t status = SWITCH_STATUS_FALSE;  
  4.     switch_thread_t *thread;  
  5.     switch_threadattr_t *thd_attr;  
  6.       
  7.     if (switch_test_flag(session, SSF_THREAD_RUNNING) || switch_test_flag(session, SSF_THREAD_STARTED)) {  
  8.         status = SWITCH_STATUS_INUSE;  
  9.         goto end;  
  10.     }  
  11.   
  12.     if (switch_test_flag((&runtime), SCF_SESSION_THREAD_POOL)) {  
  13.         return switch_core_session_thread_pool_launch(session);  
  14.     }  
  15.       
  16.     switch_mutex_lock(session->mutex);  
  17.   
  18.     if (switch_test_flag(session, SSF_THREAD_RUNNING)) {  
  19.         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n");  
  20.     } else if (switch_test_flag(session, SSF_THREAD_STARTED)) {  
  21.         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot launch thread again after it has already been run!\n");  
  22.     } else {  
  23.         switch_set_flag(session, SSF_THREAD_RUNNING);  
  24.         switch_set_flag(session, SSF_THREAD_STARTED);  
  25.   
  26.         switch_threadattr_create(&thd_attr, session->pool);  
  27.         switch_threadattr_detach_set(thd_attr, 1);  
  28.         switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);  
  29.   
  30.         if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) == SWITCH_STATUS_SUCCESS) {  
  31.             switch_set_flag(session, SSF_THREAD_STARTED);  
  32.             status = SWITCH_STATUS_SUCCESS;  
  33.         } else {  
  34.             switch_clear_flag(session, SSF_THREAD_RUNNING);  
  35.             switch_clear_flag(session, SSF_THREAD_STARTED);   
  36.             switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot create thread!\n");  
  37.             thread_launch_failure();  
  38.         }  
  39.     }  
  40.   
  41.     switch_mutex_unlock(session->mutex);  
  42.   
  43.  end:  
  44.   
  45.     return status;  
  46. }  
  47.   
  48.  
  49. SWITCH_DECLARE(void) switch_core_session_launch_thread(switch_core_session_t *session, switch_thread_start_t func, void *obj)  
  50. {  
  51.     switch_thread_t *thread;  
  52.     switch_threadattr_t *thd_attr = NULL;  
  53.     switch_threadattr_create(&thd_attr, session->pool);  
  54.     switch_threadattr_detach_set(thd_attr, 1);  
  55.   
  56.     switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);  
  57.     if (switch_thread_create(&thread, thd_attr, func, obj, session->pool) != SWITCH_STATUS_SUCCESS) {  
  58.         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot create thread!\n");  
  59.         thread_launch_failure();  
  60.     }  
  61.   
  62. }

 

同样的,switch_core_session_thread_launch默认使用执行函数switch_core_session_thread,switch_core_session_launch_thread使用外部自定义函数func。还有注意,把session作为参数传给switch_core_session_thread。如果全局配置标志位SCF_SESSION_THREAD_POOL,则使用线程池版本。

  1. 线程函数
  1. static void *SWITCH_THREAD_FUNC switch_core_session_thread(switch_thread_t *threadvoid *obj)  
  2. {  
  3.     switch_core_session_t *session = obj;  
  4.   
  5.     session->thread = thread;  
  6.     session->thread_id = switch_thread_self();  
  7.   
  8.     switch_core_session_run(session);  
  9.     ...  
  10.     switch_core_session_destroy(&session);  
  11.     return NULL;  
  12. } 

 

session线程函数除了赋值session->thread外,只调用switch_core_session_run。

  1. 状态机state_machine
  1. SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)  
  2. {  
  3.     switch_channel_state_t state = CS_NEW, midstate = CS_DESTROY, endstate;  
  4.     const switch_endpoint_interface_t *endpoint_interface;  
  5.     const switch_state_handler_table_t *driver_state_handler = NULL;  
  6.     const switch_state_handler_table_t *application_state_handler = NULL;  
  7.   
  8.     endpoint_interface = session->endpoint_interface;  
  9.     driver_state_handler = endpoint_interface->state_handler;  
  10.   
  11.     state = switch_channel_get_state(session->channel);  
  12.     if (state != switch_channel_get_running_state(session->channel))  
  13.     {  
  14.         switch (state) {  
  15.             case CS_NEW:        /* Just created, Waiting for first instructions */  
  16.                 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) State NEW\n", switch_channel_get_name(session->channel));  
  17.                 break;  
  18.             case CS_INIT:       /* Basic setup tasks */  
  19.                 {  
  20.                     STATE_MACRO(init, "INIT");  
  21.                 }  
  22.                 break;  
  23.                 ...  
  24.             default:  
  25.                 break;  
  26.         }  
  27.     }  
  28.   

 

如果channel的状态改变,则根据新状态执行不同的操作,比如CS_NEW只打印一条日志,CS_INIT调用宏STATE_MACRO,这里省略了大部分case,因为基本上都是调用STATE_MACRO。

    1. STATE_MACRO

 

  1. #define STATE_MACRO(__STATE, __STATE_STR)                       do {  
  2.     //1、先进行外部回调  
  3.     //通道channel的状态回调  
  4.     while (do_extra_handlers && (application_state_handler = switch_channel_get_state_handler(session->channel, index++)) != 0) {  
  5.         application_state_handler->on_##__STATE(session);  
  6.     }  
  7.       
  8.     //runtime的状态回调  
  9.     while (do_extra_handlers && proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {   
  10.     }  
  11.       
  12.     //2、驱动回调  
  13.     if (!driver_state_handler->on_##__STATE || (driver_state_handler->on_##__STATE(session) == SWITCH_STATUS_SUCCESS )) {   
  14.     }  
  15. }while (silly) 

 

STATE_MACRO宏展开大概如上,意思其实是调用状态回调接口xx_state_hander,这些回调接口有几类。第一类叫驱动回调driver_state_handler,从driver_state_handler = endpoint_interface->state_handler可以看出,驱动回调在端点接口,比如mod_sofia,在load函数中,会添加这个回调。

 

  1. sofia_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);  
  2. sofia_endpoint_interface->interface_name = "sofia";  
  3. sofia_endpoint_interface->io_routines = &sofia_io_routines;  
  4. sofia_endpoint_interface->state_handler = &sofia_event_handlers;  
  5. sofia_endpoint_interface->recover_callback = sofia_recover_callback;  
  6.   
  7. switch_state_handler_table_t sofia_event_handlers = {  
  8.     /*.on_init */ sofia_on_init,  
  9.     /*.on_routing */ sofia_on_routing,  
  10.     /*.on_execute */ sofia_on_execute,  
  11.     /*.on_hangup */ sofia_on_hangup,  
  12.     /*.on_exchange_media */ sofia_on_exchange_media,  
  13.     /*.on_soft_execute */ sofia_on_soft_execute,  
  14.     /*.on_consume_media */ NULL,  
  15.     /*.on_hibernate */ sofia_on_hibernate,  
  16.     /*.on_reset */ sofia_on_reset,  
  17.     /*.on_park */ NULL,  
  18.     /*.on_reporting */ NULL,  
  19.     /*.on_destroy */ sofia_on_destroy  
  20. };  

 

应用回调application_state_handler,可以自定义往channel设置状态回调,然后此时通过switch_channel_get_state_handler就得到那些回调。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值