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

    ///////////////////////////////////////////////////////
// FileName:	network_ctrl_recv_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 <linux/if.h>

#include "network_ctrl_recv_thread.h"
#include "network_audio_recv_thread.h"
#include "network_video_recv_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"
#include "capture_event.h"

using namespace std;

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

// 构造函数
// 传入参数为
// nc_in 上层network_ctrl对象指针
// stackSize QThread所用的参数
network_ctrl_recv_thread::network_ctrl_recv_thread ( avi * avi_ptr_in, 
		network_ctrl * nc_in, unsigned int stackSize )
		:QThread( stackSize ) // {{{
{
	verbose_output( 2, "create network_ctrl_recv_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;

	nart = NULL;
	nvrt = NULL;

	avi_ptr = avi_ptr_in;

} // }}}


// 析构函数
network_ctrl_recv_thread::~network_ctrl_recv_thread ( void ) // {{{
{
	if ( 0 != fd_ctrl )
	{
		close( fd_ctrl );
	}

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


		delete nart;
	}

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

		delete nvrt;
	}

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

} // }}}

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

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

	int init_ok;

	if ( avi_ptr->use_multicast )
	{
		init_ok = connect_init_mc();
	}
	else
	{
		init_ok = connect_init();
	}

	if ( init_ok == SUCCEED )
	{
		if ( avi_ptr->va_mode != AUDIO_ONLY )
		{
			verbose_output( 1, "create new network_video_recv_thread." );
			nvrt = new network_video_recv_thread( avi_ptr, nc );
			nvrt->start();
		}

		if ( avi_ptr->va_mode != VIDEO_ONLY )
		{
			verbose_output( 1, "create new network_audio_recv_thread." );
			nart = new network_audio_recv_thread( avi_ptr, nc );
			nart->start();
		}

		if ( avi_ptr->use_multicast )
		{
			connect_handle_mc();
		}
		else
		{
			connect_handle();
		}

	}

	verbose_output( 1, "end of network_audio_recv_thread" );

	return;

} // }}}

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

// 连接初始化,创建套接字
int network_ctrl_recv_thread::connect_init ( void ) // {{{
{

	verbose_output( 3, "network_ctrl_recv_thread init." );

	//expect_num = WELCOME_NUM;

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

	// 网络连接的参数设置
	addr_accept->sin_family = AF_INET;
	addr_accept->sin_port = htons( DEFAULT_CTRL_PORT );
	inet_pton( AF_INET, static_cast< const char* > ( avi_ptr->ip ), &addr_accept->sin_addr );

	verbose_output( 3, "creating ctrl connect socket..." );

	fd_ctrl = socket( AF_INET, SOCK_DGRAM, 0 );
	
	pollfd connect_to = { fd_ctrl, POLLIN, 0, };


	bool read_ok = false;
	option_t * opt_buf = NULL;
	BUFF * temp;
	int connect_times = 0;

	bool should_exit = false;
	packet_head_t * packet_head = NULL;

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

		if ( should_exit )
		{
			QCustomEvent * event = new QCustomEvent( SIG_DISCONNECT_OK );

			QApplication::postEvent( avi_ptr, event );

			return FAILED;
		}

		verbose_output( 3, "send ctrl Hello message ..." );
		send_data( fd_ctrl, addr_accept, send_buff, NULL, 0, expect_num, SYN );

		int result = poll( &connect_to, 1, DEFAULT_TIMEOUT );

		if ( result == 0 )
		{
			// 超时返回
			connect_times++;
			if ( connect_times >= DEFAULT_CONNECT_TIMES )
			{
				cerr << "Warning! Can't connect to peer host." << endl;
				QCustomEvent * event = new QCustomEvent( SIG_CONNECT_TIMEOUT );
				QApplication::postEvent( avi_ptr, event );
				return FAILED;
			}
			continue;
		}
		else
		{
			if ( result > 0 )
			{
				// 网络可读
				recv_line( fd_ctrl, addr_accept, recv_buff, temp, packet_head );
				opt_buf = (option_t *) temp;

				if ( !TEST_CTRL_SYN_BIT( packet_head->opt_bits ) )
				{
					cerr << "Warning! not the Welcome reply." << endl;
				}
				else
				{
					read_ok = true;
				}

			}
			else
			{
				// 套接口错误
				perror( "Error in connecting" );
				::exit( 1 );
			}
		}
	}
	while ( !read_ok );

	expect_num++;

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

	// 获得参数设置
	avi_ptr->va_mode = opt_buf->va_mode;
	avi_ptr->video_opt.factor = opt_buf->factor;
	
	if ( opt_buf->use_g723 == 0 )
	{
		avi_ptr->use_g723 = false;
	}
	else
	{
		if ( opt_buf->use_g723 == 1 )
		{
			avi_ptr->use_g723 = true;
		}
	}

	verbose_output( 4, "get peer 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", opt_buf->use_g723 );

	return SUCCEED;

} // }}}


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

	bool should_exit = false;
	int count = 0;
	
	while( 1 )
	{

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

		if ( should_exit )
		{
			send_data( fd_ctrl, addr_accept, send_buff, NULL, 0, packet_num, GOODBYE );
			QCustomEvent * event = new QCustomEvent( SIG_DISCONNECT_OK );
			QApplication::postEvent( avi_ptr, event );

			nart->wait();
			cout << " wait nart ok " << endl;
			nvrt->wait();
			cout << " wait nvrt ok " << endl;

			return;
		}

		msleep( HEARTBEAT_INTERVAL / 4 );
		count = ( count + 1 ) % 4;

		if ( count == 3 )
		{
			cout << "send heartbeat" << endl;
			send_data( fd_ctrl, addr_accept, send_buff, NULL, 0, packet_num, HEARTBEAT );
		}
	}

	return;

} // }}}


// 组播初始化,创建套接字
int network_ctrl_recv_thread::connect_init_mc ( void ) // {{{
{

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

	/////////////////////////////////////////
	// 创建控制端口
	/////////////////////////////////////////
	
	*acclen = sizeof( *addr_accept );
	memset( addr_accept, 0, *acclen );

	// 创建控制端监听socket
	verbose_output( 3, "creating multicast listen socket..." );

	fd_ctrl = socket( AF_INET, SOCK_DGRAM, 0 );
		
	// 绑定指定端口
	addr_accept->sin_family = AF_INET;
	inet_pton( AF_INET, static_cast< const char* >( avi_ptr->mc_addr ), 
			&addr_accept->sin_addr );
	addr_accept->sin_port = htons( DEFAULT_MC_CTRL_PORT );
	
	// 绑定端口
	if ( bind( fd_ctrl, (sockaddr*) addr_accept, *acclen ) == -1 )
	{
		cerr << "Can't bind to the listen port [" << DEFAULT_MC_CTRL_PORT << "]" << endl;
		::exit( 1 );
	}

	// 初始化组播
	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 ) );

	return SUCCEED;

} // }}}


// 处理组播连接后的数据接收工作
void network_ctrl_recv_thread::connect_handle_mc ( void ) // {{{
{

	nart->wait();
	cout << " wait nart ok " << endl;
	nvrt->wait();
	cout << " wait nvrt ok " << endl;

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


	return;
} // }}}