个人理解

freeswitch中呼叫是基于一个具体的实体的,那就是channel。
channel和leg是一一对应的,单腿呼叫那就是只有一个channel,双腿呼叫就是两个channel。
甚至于3个腿及3个腿以上的会议呼叫。
但是最基础的单位还是channel。

对应到具体的应用上来,手机呼入到freeswitch,就会有一个呼入的channel。
freeswitch呼出到手机,就会有一个呼出的channel。

所以,channel中天然的,就需要绑定一些比如主被叫号码、呼叫方向、编码等等信息,来指代这通呼叫。
同时,channel也有自己的状态,代表着进入freeswitch之后,走过的各个阶段:从刚建立呼叫、寻找拨号规则、确认执行的命令、接通、挂断、销毁等等。

现在就来总结下freeswitch使用的基本数据结构。

Session与channel的关系

这里引用一下: 链接

Session 与 Channel

对每一次呼叫,FreeSWITCH 都会启动一个 Session(会话,它包含SIP会话,SIP会在每对UAC-UAS之间生成一个 SIP Session),用于控制整个呼叫,它会一直持续到通话结束。其中,每个 Session 都控制着一个 Channel(信道),Channel 是一对 UA 间通信的实体,相当于 FreeSWITCH 的一条腿(leg),每个 Channel 都有一个唯一的 UUID。另外,Channel 上可以绑定一些呼叫参数,称为 Channel Variable(信道变量)。Channel 中可能包含媒体(音频或视频流),也可能不包含。通话时,FreeSWITCH 的作用是将两个 Channel(a-leg 和 b-leg,通常先创建的或占主动的叫 a-leg)桥接(bridge)到一起,使双方可以通话。 通话中,媒体(音频或视频)数据流在 RTP 包中传送(不同于 SIP, RTP是另外的协议)。一般来说,Channel是双向的,因此,媒体流会有发送(Send/Write)和接收(Receive/Read)两个方向。

这里说的Session,对应的是代码中的switch_core_session结构体,该结构体里面就是包含了switch_channel_t。

简陋的UML图

originate简单理解 - 图1

基本数据结构

会话:switch_core_session

文件:switch_core_pvt.h
该文件属于内核私有数据,外部模块无法直接访问其数据内容,只能通过switch_core_session.c提供的函数来访问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. switch_io_event_hooks_t event_hooks;
  10. switch_codec_t *read_codec;
  11. switch_codec_t *real_read_codec;
  12. switch_codec_t *write_codec;
  13. switch_codec_t *real_write_codec;
  14. switch_codec_t *video_read_codec;
  15. switch_codec_t *video_write_codec;
  16. ...
  17. };

通道: switch_channel

文件: switch_channel.c

  1. struct switch_channel {
  2. char *name;
  3. switch_call_direction_t direction;
  4. switch_call_direction_t logical_direction;
  5. switch_queue_t *dtmf_queue;
  6. switch_queue_t *dtmf_log_queue;
  7. switch_mutex_t*dtmf_mutex;
  8. switch_mutex_t *flag_mutex;
  9. switch_mutex_t *state_mutex;
  10. switch_mutex_t *thread_mutex;
  11. switch_mutex_t *profile_mutex;
  12. switch_core_session_t *session;
  13. switch_channel_state_t state;
  14. switch_channel_state_t running_state;
  15. switch_channel_callstate_t callstate;
  16. uint32_t flags[CF_FLAG_MAX];
  17. uint32_t caps[CC_FLAG_MAX];
  18. uint8_t state_flags[CF_FLAG_MAX];
  19. uint32_t private_flags;
  20. switch_caller_profile_t *caller_profile;
  21. const switch_state_handler_table_t *state_handlers[SWITCH_MAX_STATE_HANDLERS];
  22. int state_handler_index;
  23. switch_event_t *variables;
  24. switch_event_t *scope_variables;
  25. switch_hash_t *private_hash;
  26. switch_hash_t *app_flag_hash;
  27. switch_call_cause_t hangup_cause;
  28. int vi;
  29. int event_count;
  30. int profile_index;
  31. opaque_channel_flag_t opaque_flags;
  32. switch_originator_type_t last_profile_type;
  33. switch_caller_extension_t *queued_extension;
  34. switch_event_t *app_list;
  35. switch_event_t *api_list;
  36. switch_event_t *var_list;
  37. switch_hold_record_t *hold_record;
  38. switch_device_node_t *device_node;
  39. char *device_id;
  40. };

通道状态:switch_channel_state_t

文件:switch_types.h

  1. typedef enum {
  2. CS_NEW, //channel刚建立
  3. CS_INIT, //channel完成初始化
  4. CS_ROUTING, //channel处于寻找合适的拨号规则中
  5. CS_SOFT_EXECUTE, //channel已可以接收来自esl等第三方发来的控制指令(该状态会被其他app重置)
  6. CS_EXECUTE, //channel找到拨号规则后,处于执行中
  7. CS_EXCHANGE_MEDIA, //channel和其他channel进行媒体交互(该状态会被其他app重置)
  8. CS_PARK, //channel处于媒体接收中,等待进一步的指令
  9. CS_CONSUME_MEDIA, //channel处于媒体消费中(该状态会被其他app重置)
  10. CS_HIBERNATE, //channel处于睡眠状态
  11. CS_RESET, //channel处于重置状态
  12. CS_HANGUP, //channel被标记为hangup,等待真正结束
  13. CS_REPORTING, //channel准备收集呼叫数据
  14. CS_DESTROY, //channel准备销毁,退出状态机
  15. CS_NONE
  16. } switch_channel_state_t;

呼叫状态:switch_channel_callstate_t

文件:

  1. typedef enum {
  2. CCS_DOWN,
  3. CCS_DIALING,
  4. CCS_RINGING,
  5. CCS_EARLY,
  6. CCS_ACTIVE,
  7. CCS_HELD,
  8. CCS_RING_WAIT,
  9. CCS_HANGUP,
  10. CCS_UNHOLD
  11. } switch_channel_callstate_t;

主叫上下文:switch_caller_profile

从呼入的场景来看, caller profile主要是保存主叫的相关信息,在拨号方案中都可以用着这里变量。
文件:switch_caller.h

  1. struct switch_caller_profile {
  2. /*! The Call's User Name */
  3. const char *username;
  4. /*! The name of the dialplan */
  5. const char *dialplan;
  6. /*! Caller ID Name */
  7. const char *caller_id_name;
  8. /*! Caller ID Number */
  9. const char *caller_id_number;
  10. /*! Original Caller ID Name */
  11. const char *orig_caller_id_name;
  12. /*! Original Caller ID Number */
  13. const char *orig_caller_id_number;
  14. /*! Callee ID Name */
  15. const char *callee_id_name;
  16. /*! Callee ID Number */
  17. const char *callee_id_number;
  18. uint8_t caller_ton;
  19. uint8_t caller_numplan;
  20. /*! Caller Network Address (when applicable) */
  21. const char *network_addr;
  22. /*! ANI (when applicable) */
  23. const char *ani;
  24. uint8_t ani_ton;
  25. uint8_t ani_numplan;
  26. /*! ANI II (when applicable) */
  27. const char *aniii;
  28. /*! RDNIS */
  29. const char *rdnis;
  30. uint8_t rdnis_ton;
  31. uint8_t rdnis_numplan;
  32. /*! Destination Number */
  33. char *destination_number;
  34. uint8_t destination_number_ton;
  35. uint8_t destination_number_numplan;
  36. /*! channel type */
  37. const char *source;
  38. /*! channel name */
  39. char *chan_name;
  40. /*! unique id */
  41. char *uuid;
  42. /*! context */
  43. const char *context;
  44. /*! profile index */
  45. const char *profile_index;
  46. /*! flags */
  47. switch_caller_profile_flag_t flags;
  48. struct switch_caller_profile *originator_caller_profile;
  49. struct switch_caller_profile *originatee_caller_profile;
  50. struct switch_caller_profile *origination_caller_profile;
  51. struct switch_caller_profile *hunt_caller_profile;
  52. struct switch_channel_timetable *times;
  53. struct switch_channel_timetable *old_times;
  54. struct switch_caller_extension *caller_extension;
  55. switch_memory_pool_t *pool;
  56. struct switch_caller_profile *next;
  57. switch_call_direction_t direction;
  58. switch_call_direction_t logical_direction;
  59. profile_node_t *soft;
  60. char *uuid_str;
  61. char *clone_of;
  62. char *transfer_source;
  63. };

基本流程

简化流程

|&() [] [] [] [] []

  1. originate命令实例
    1. originate sofia/internal/18xxxx@xx:xx &record_session(/test.wav)
    2. originate sofia/internal/18xxxx@xx:xx calloutbot XML default
  2. 收到命令后,效验参数
  3. 调用switch_ivr_originate发起呼叫,如果呼叫成功的话,将session赋给switch_core_session_t *caller_session
  4. 如果命令中含有&,处理如下:
    1. 基于当前session,新建一个extension
    2. 将&后面的app和app参数,保存到extension中
    3. 将extension设置到channel中
    4. 将channel状态设置为CS_EXECUTE
  5. 命令中不含有&,处理如下:
    1. 调用switch_ivr_session_transfer,直接将session转到命令参数中指定的extension上。

新建extension,并增加app

如果是解析xml文件生成的extension,则里面保存的是解析完成后所有的action列表。
此处originate不需要走拨号规则,所以直接跳过一步,直接创建extension,然后往里面存app

  1. if ((extension = switch_caller_extension_new(caller_session, app_name, arg)) == 0) {
  2. switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
  3. abort();
  4. }
  5. switch_caller_extension_add_application(caller_session, extension, app_name, arg);
  6. switch_channel_set_caller_extension(caller_channel, extension);

extension数据结构

文件:switch_caller.h

  1. struct switch_caller_extension {
  2. /*! The name of the extension */
  3. char *extension_name;
  4. /*! The number of the extension */
  5. char *extension_number;
  6. /*! Pointer to the current application for this extension */
  7. switch_caller_application_t *current_application;
  8. /*! Pointer to the last application for this extension */
  9. switch_caller_application_t *last_application;
  10. /*! Pointer to the entire stack of applications for this extension */
  11. switch_caller_application_t *applications;
  12. struct switch_caller_profile *children;
  13. struct switch_caller_extension *next;
  14. };