gusucode.com > 嵌入式linux系统的网络编程源码程序 > 嵌入式linux系统的网络编程源码程序/视频会议源码/network_ctrl_send_thread.cpp

    ///////////////////////////////////////////////////////
// FileName:	network_ctrl_send_thread.cpp
// Author:		b1gm0use
// Project:		myvideo

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <qapplication.h>
#include <qthread.h>
#include <poll.h>
#include <qevent.h>

#include "network_ctrl_send_thread.h"
#include "network_audio_send_thread.h"
#include "network_video_send_thread.h"
#include "video_cap.h"
#include "capture_event.h"
#include "video_send.h"
#include "network_audio_send.h"
#include "network_video_send.h"
#include "network_ctrl.h"
#include "video.h"
#include "network.h"
#include "common.h"
#include "audio.h"
#include "avi.h"
#include "signal_def.h"

using namespace std;

///////////////////////////////////////////////////////
// Public Functions
///////////////////////////////////////////////////////

// 构造函数
// 传入参数为
// nc_in 上层network_ctrl对象指针
// stackSize QThread所用的参数
network_ctrl_send_thread::network_ctrl_send_thread ( avi * avi_ptr_in, network_ctrl * nc_in, unsigned int stackSize )
		:QThread( stackSize ) // {{{
{
	verbose_output( 2, "create network_ctrl_send_thread." );

	nc = nc_in;

	fd_ctrl = 0;

	recv_buff = new BUFF [ PACKET_LENGTH ];
	send_buff = new BUFF [ PACKET_LENGTH ];

	addr_accept = new sockaddr_in;
	acclen = new socklen_t;

	packet_num = 0;
	expect_num = 0;

	nast = NULL;
	nvst = NULL;

	avi_ptr = avi_ptr_in;

	client_num = 0;

} // }}}

// 析构函数
network_ctrl_send_thread::~network_ctrl_send_thread ( void ) // {{{
{

	if ( 0 != fd_ctrl )
	{
		close( fd_ctrl );
	}

	if ( NULL != nast )
	{
		if ( nast->running() )
		{
			nast->terminate();
			cerr << "Warning! Terminate network audio send thread." << endl;
		}

		delete nast;
	}

	if ( NULL != nvst )
	{
		if ( nvst->running() )
		{
			nvst->terminate();
			cerr << "Warning! Terminate network video send thread." << endl;
		}

		delete nvst;
	}

	delete [] recv_buff;
	delete [] send_buff;
	delete addr_accept;
	delete acclen;

} // }}}

// 运行部分,线程代码在这里
void network_ctrl_send_thread::run ( void ) // {{{
{

	verbose_output( 1, "network ctrl send thread running..." );

	if ( avi_ptr->use_multicast )
	{
		listen_init_mc();
	}
	else
	{
		listen_init();
	}

	if ( avi_ptr->va_mode != AUDIO_ONLY )
	{
		// 使用视频
		nvst = new network_video_send_thread( avi_ptr, nc );
		nvst->start();
	}

	if ( avi_ptr->va_mode != VIDEO_ONLY )
	{
		// 使用音频
		nast = new network_audio_send_thread( avi_ptr, nc );
		nast->start();
	}

	if ( avi_ptr->use_multicast )
	{
		listen_handle_mc();
	}
	else
	{
		listen_handle();
	}

	return;

} // }}}


///////////////////////////////////////////////////////
// Private Functions
///////////////////////////////////////////////////////


// 连接初始化,创建套接字
void network_ctrl_send_thread::listen_init ( void ) // {{{
{

	verbose_output( 3, "net_mode LISTEN" );

	/////////////////////////////////////////
	// 创建控制端口
	sockaddr_in addr_listen;
	socklen_t len = sizeof( addr_listen );
	int port = DEFAULT_CTRL_PORT;

	
	// 创建一个等待server daemon的监听端口
	// 创建控制端监听socket
	verbose_output( 3, "creating listen socket..." );
	fd_ctrl = socket( AF_INET, SOCK_DGRAM, 0 );
		
	// 绑定指定端口
	memset( &addr_listen, 0, sizeof( addr_listen ) );
	addr_listen.sin_family = AF_INET;
	addr_listen.sin_addr.s_addr = htonl( INADDR_ANY );
	addr_listen.sin_port = htons( port );
	
	// 绑定端口
	if ( bind( fd_ctrl, (sockaddr*) & addr_listen, len ) == -1 )
	{
		cerr << "Can't bind to the listen port [" << port << "]" << endl;
		::exit( 1 );
	}

	verbose_output( 3, "waiting for connection...", avi_ptr->ip );

	*acclen = sizeof( *addr_accept );
	memset( addr_accept, 0, *acclen );


} // }}}


// 处理连接后的数据发送工作
void network_ctrl_send_thread::listen_handle ( void ) // {{{
{

	// 接收进来的连接
	int recv_num;
	BUFF * buff;
	bool should_exit = false;
	int lost_heartbeat = 0;
	packet_head_t * packet_head = NULL;

	while ( 1 )
	{
		(*(nc->term_sub_thread_sema))++;
		should_exit = nc->term_sub_thread;
		(*(nc->term_sub_thread_sema))--;

		if ( should_exit )
		{
			cout << "before nast" << endl;
			nast->wait();
			cout << "after nvst" << endl;
			cout << "before nvst" << endl;
			nvst->wait();
			cout << "after nvst" << endl;

			QCustomEvent * event = new QCustomEvent( SIG_STOP_OK );
			QApplication::postEvent( avi_ptr, event );

			return;
		}

		// 监听端口
		pollfd connect_in = { fd_ctrl, POLLIN, 0 };
		int result = poll( &connect_in, 1, DEFAULT_TIMEOUT );

		if ( result < 0 )
		{
			perror( "Error in video listening" );
		}
		
		if ( result == 0 && client_num > 0 ) // {{{
		{
			// 超时,无heartbeat
			lost_heartbeat++;
			
			if ( lost_heartbeat >= MAX_LOST_HEARTBEAT )
			{
				// 客户端丢失
				QCustomEvent * event = new QCustomEvent( SIG_LOST_CLIENT );
				QApplication::postEvent( avi_ptr, event );
				client_num--;
				nast->wait();
				nvst->wait();
				return;
			}
		}
		else
		{
			// 有数据可读?
			if ( ( connect_in.revents & POLLIN ) != 0 ) // {{{
			{
				recv_line( fd_ctrl, addr_accept, recv_buff, buff, packet_head );

				if ( TEST_CTRL_SYN_BIT( packet_head->opt_bits ) )
				{
					packet_num = recv_num;

					QCustomEvent * event = new QCustomEvent( SIG_ACCEPT_CONNECT );
					QApplication::postEvent( avi_ptr, event );

					client_num++;

					// 写入参数
					option_t opt_buf;
					opt_buf.factor = avi_ptr->video_opt.factor;
					opt_buf.va_mode = avi_ptr->va_mode;

					if ( avi_ptr->use_g723 )
					{
						opt_buf.use_g723 = 1;
					}
					else
					{
						opt_buf.use_g723 = 0;
					}

					int length = sizeof( opt_buf );
					send_data( fd_ctrl, addr_accept, send_buff, (BUFF *) &opt_buf, length, packet_num, SYN );

					verbose_output( 4, "transfer configuration" );
					verbose_output( 4, "va_mode\t", avi_ptr->va_mode );
					verbose_output( 4, "factor\t", avi_ptr->video_opt.factor );
					verbose_output( 4, "use_g723\t", avi_ptr->use_g723 );

				}
				else
				{
					if ( TEST_CTRL_HEARTBEAT_BIT( packet_head->opt_bits ) )
					{
						lost_heartbeat = 0;
					}
					else
					{
						if ( TEST_CTRL_GOODBYE_BIT( packet_head->opt_bits ) )
						{
							// 客户端正常退出
							QCustomEvent * event = new QCustomEvent( SIG_ACCEPT_DISCONNECT );
							QApplication::postEvent( avi_ptr, event );
							nast->wait();
							nvst->wait();
							client_num--;
							return;
						}
					}
				}
			} // if ( ( connect_in.revents & POLLIN ) != 0 ) }}}
		} // if ( result == 0 ) // }}}

	} // while ( 1 )

	return;

} // }}}


// 组播初始化,创建套接字
void network_ctrl_send_thread::listen_init_mc ( void ) // {{{
{

	verbose_output( 3, "network ctrl send thread Multicast init." );

	/////////////////////////////////////////
	// 创建控制端口
	/////////////////////////////////////////
	
	*acclen = sizeof( *addr_accept );
	memset( addr_accept, 0, *acclen );
	
	// 网络连接的参数设置
	addr_accept->sin_family = AF_INET;
	addr_accept->sin_port = htons( DEFAULT_MC_CTRL_PORT );
	inet_pton( AF_INET, static_cast< const char* >( avi_ptr->mc_addr ), 
			&addr_accept->sin_addr );

	// 创建控制端发送socket
	fd_ctrl = socket( AF_INET, SOCK_DGRAM, 0 );
	
	// 初始化组播
	ip_mreq mreq;
	memcpy( &mreq.imr_multiaddr, &(((sockaddr_in*) addr_accept)->sin_addr),
			sizeof( in_addr ) );
	mreq.imr_interface.s_addr = htonl( INADDR_ANY );

	// 加入组播
	setsockopt( fd_ctrl, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof( mreq ) );

	verbose_output( 3, "ready to send data", avi_ptr->ip );


} // }}}


// 处理组播连接后的数据接收工作
void network_ctrl_send_thread::listen_handle_mc ( void ) // {{{
{
	verbose_output( 3, "network ctrl send thread Multicast handle." );

	nast->wait();
	cout << "nast wait" << endl;
	nvst->wait();
	cout << "nvst wait" << endl;
} // }}}