Chinaunix首页 | 论坛 | 博客
  • 博客访问: 430764
  • 博文数量: 127
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 810
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-02 20:51
文章分类

全部博文(127)

文章存档

2018年(6)

2015年(18)

2014年(33)

2013年(70)

分类: LINUX

2013-07-05 18:19:31


国标gb181详细流程图

1、  程序起来后首先执行avserver_init();之后初始化信号init_signals();

2、  创建check_system_info线程,该线程负责检查/mnt/nand下是否有pu_info.cfg,如果没有则使用默认配置。同时检查配置文件升级标志g_info_update,如果该标志为1,则将全局变量g_system_info写入到配置文件pu_info.cfg中。

3、  创建net_thread线程,该线程所创建的socket和客户端设置配置的工具进行交互,首先通过create_server_socket()创建一个tcp套接字,然后进入select_loop循环,使用select函数来判断是否有客户端连接和数据的读写。

4、  创建rtp_stream_task线程,在该线程中首先又创建了rtp_stream_session_mng线程,该线程负责rtp会话active状态的改变。之后通过is_session_list_empty()来判断rtp会话中active状态,如果为RTP_RUNNING_NOW,则开始传输数据。由于rtp视频流有严格的时间戳定义,通过get_current_timestamp来获得时间戳信息,该时间戳信息在get_av_ps_stream函数中使用,该函数将音视频数据都打包成ps包格式,之后再将ps包格式的数据打包成rtp包发送。最后调用rtp_session_create_packet ()函数和rtp_session_sendm_with_ts函数将rtp数据发送出去。

5、  创建sip_dialog_task线程,该线程是整个代码架构中最为关键的部分,里面状态机的使用最为重要。要理解该线程的作用,首先几个结构体必须首先了解,struct sip_dialog_liststruct sip_dialog_nodestruct sip_dialogstruct _tag_sip_message;其中像设备的注册,设备心跳的发送,视频的请求等都经历了一个对话的创建和消亡。在该线程中首先创建一个udp套接字用于和平台交互,同时初始化sip对话链表。然后进入循环同样使用select函数进行处理。下面结合register流程来该状态机的使用。

6、  在主函数中调用do_register函数,在该函数中调用create_register函数,来进行注册信息的组织,在该函数中调用sip_dialog_init来初始化一个sip_dialog_t结构体,此时要注意将sip_dialog_t结构体中的state变量初始化为p_sip_dialog->state = SIP_PRE_INIT;这个状态在sip_dialog_task中有使用。然后将各个注册信息项填充到sip_dialog_t结构体中的sip_msg_in中,同时调用sip_dialog_node_init()初始化sip_dialog_node结构体,将填充好的sip_dialog_t结构体添加到sip_dialog_node中,最后调用sip_add_node_to_dialog_list函数将sip_dialog_node结构体添加到sip_dialog_list链表中,至此注册函数中要做的工作就算完成了,至于链表中的数据如何处理在sip_dialog_task中实现。

7、  sip_dialog_task的无限循环中,首先通过select函数判断是否有数据可读,如果没有数据可读,则通过跳转指令跳到list_process处,这是再判断g_sip_dialog_list->dialog_list_head->dialog->state的状态,如果为SIP_SEND_WAITSIP_SEND_FINISH,则调用sendto执行发送操作,如果为SIP_PRE_INIT,则调用状态转换函数turn_status_machine,在该函数中首先调用analyse_request来解析g_sip_dialog_list->dialog_list_head->dialog->sip_msg_in中的信息,解析之后调用request_new_register函数,同时将其state状态设置为SIP_SEND_WAIT;在request_new_register函数中,首先调用sip_message_to_str( in ) sip_message_t结构体中的各元素信息添加到sip_message_t结构体中的message字符串中;之后又调用sip_message_parser( in->message , out )函数将sip_message_t in中的字符串解析后放到sip_message_t out结构体对应的各个元素中,因为数据的发送要通过sip_message_t out发送出去;最后调用callback_create_register函数,设置g_register_status 状态为 REGISTER_CONTINUE_ON ;至此状态转换函数任务完成。但是此时由于register注册信息还没有发送出去,select仍未不可读,继续在list_process中处理,在上述状态转换函数中改变了g_sip_dialog_list->dialog_list_head->dialog->state 的状态为SIP_SEND_WAIT,因此执行sendto发送函数,将register注册信息发送出去,但是在发送之前要调用sip_message_to_str( dialog->sip_msg_out )将注册信息都放到dialog->sip_msg_out->message中。之后会得到注册的回复信息,通过recvfrom函数将接收到的回复信息放到recvbuf中,之后通过调用sip_message_parser( recvbuf , &sip_message )函数来解析收到的请求并将有效信息放到sip_message结构体中;然后判断该收到的信息是否为我们的注册回复信息,通过sip_message->callid->number可以判断,如果注册信息和收到信息的callid相同,则注册信息和收到的信息属于同一个对话,该收到的信息就是注册回复信息。如果收到的信息不是回复信息,则创建新的对话,否则调用sip_message_to_str( sip_message )函数通过解析sip_message结构体中的各个元素来填充sip_message结构体中的message字符串,调用sip_message_parser ( sip_message->message , &(sip_dialog->sip_msg_in) )函数将sip_message->message字符串解析后填充到sip_msg_in结构体,因为接收到的信息都是首先放到sip_msg_in结构体中的。最后设置其状态为sip_dialog->state = SIP_PRE_INIT ;再次进入turn_status_machine状态转换函数中,由于这次收到的状态码为REQUEST_ACK_401,调用request_authenticate( in , out )函数来重新组织sip_message_t out 信息,由于之前发送的register消息就存放在sip_message_t out中,而这次发送的sip_message_t消息和之前发送的register消息有大部分元素相似,因此可以再sip_message_t out的基础上修改部分元素即可,主要修改了branchcseqauthorization等成员。之后重复上述发送过程将新的register注册信息发送出去,然后获得一个register的回应消息,将该消息解析到sip_message_t in结构体之后,再次进入状态转换函数,由于这次收到的状态码为REQUEST_ACK_200,调用get_answer_200ok函数,在callback_register_ok函数中设置g_register_status = REGISTER_OK,同时设置*status = SIP_FINISH ;sip_dialog_task函数中检测到sip_dialog_node->dialog->state == SIP_FINISH,则调用sip_free_node_from__dialog_list( g_sip_dialog_list , sip_dialog_node ) ;函数将sip_dialog_node从该对话链表中移除,至此,一个register注册过程完成。

阅读(1710) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~