www.pudn.com > vc-network-communication.rar > AVIOMgr.cpp


//NetTalk 
/*------------------------------------------------------------------------------*\ 
 ============================= 
   模块名称: AVIOMgr.cpp 
 ============================= 
  
 [版权] 
  
   2000-2002  115软件工厂  版权所有 
                                               
\*------------------------------------------------------------------------------*/ 
 
#include "WndX.h" 
#include   
 
#include "AVIOMgr.h" 
#include "UDPSocket.h" 
#include "g729a.h" 
#include "AudioPlay.h" 
#include  
/*------------------------------------------------------------------------------*/ 
CAVIOMgr* pMgrInst=0; 
 
 
/*------------------------------------------------------------------------------*/ 
//声音输入线程,包括声音的压缩 
DWORD WINAPI CAVIOMgr::AudioInThreadProc(LPVOID lpParameter) 
{ 
	CAVIOMgr* pMgr=(CAVIOMgr*)lpParameter; 
	MSG msg; 
	while(GetMessage(&msg,0,0,0)) 
	{ 
		switch(msg.message) 
		{ 
		case WIM_DATA: 
			{ 
				WAVEHDR* pWH=(WAVEHDR*)msg.lParam; 
				waveInUnprepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR)); 
							 
				if(pWH->dwBytesRecorded!=SIZE_AUDIO_FRAME) 
					break;//it's not full recorded,i think the wave recorder has ben 
				//stopped,discard it,and don't do anything! 
				// 
				CopyMemory(pMgr->m_AudioLocal,pWH->lpData,SIZE_AUDIO_FRAME); 
				pMgr->OnEncodeAudioData(pMgr->m_AudioLocal,SIZE_AUDIO_FRAME); 
				 
				waveInPrepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR)); 
				waveInAddBuffer((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR)); 
			} 
			break; 
		} 
	}	 
	return msg.wParam; 
} 
 
/*------------------------------------------------------------------------------*/ 
//音频输出线程,包括音频解码 
DWORD WINAPI CAVIOMgr::AudioOutThreadProc(LPVOID lpParameter) 
{ 
	 
	CAVIOMgr* pMgr=(CAVIOMgr*)lpParameter; 
	MSG msg; 
	while(GetMessage(&msg,0,0,0)) 
	{ 
		switch(msg.message) 
		{ 
		case IOM_AUDIO: 
			pMgr->OnDecodeAudioData((PACK_AUDIO*)msg.lParam,(int)msg.wParam); 
			break; 
		case WOM_DONE: 
			{ 
				WAVEHDR* pwh=(WAVEHDR*)msg.lParam; 
				waveOutUnprepareHeader((HWAVEOUT)msg.wParam,pwh,sizeof(WAVEHDR)); 
				pMgr->m_iAudioBuf--; 
				delete []pwh->lpData;//删除Play调用时分配的内存 
				delete pwh; 
			} 
			break; 
		} 
	} 
	return msg.wParam; 
} 
 
/*------------------------------------------------------------------------------*/ 
//视频流回调函数 
LRESULT CALLBACK CAVIOMgr::VideoStreamCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) 
{ 
	 
	CAVIOMgr* pMgr=(CAVIOMgr*)capGetUserData(hWnd); 
	if(pMgr) 
	{ 
		//压缩视频数据 
		pMgr->OnEncodeVideoData((char*)lpVHdr->lpData,lpVHdr->dwBytesUsed); 
		 
	}	 
	return TRUE; 
} 
 
/*------------------------------------------------------------------------------*/ 
//Socket线程,负责接收数据 
DWORD WINAPI CAVIOMgr::SockThreadProc(LPVOID lpParameter) 
{ 
	CAVIOMgr* pMgr=(CAVIOMgr*)lpParameter; 
 
	char buf[4096]; 
	int iLen=0; 
	while(1) 
	{ 
		iLen=pMgr->m_Socket.RecvFrom(buf,4096,(sockaddr*)&pMgr->m_sockaddr); 
		if(iLen>0) 
		{ 
			 
			switch(*((short*)buf))//check the flag 
			{ 
			case FLAG_CMD: 
				{ 
				//命令 
					pMgr->OnCommand((PACK_CMD*)buf,iLen); 
				} 
				break; 
			case FLAG_AUDIO: 
				{ 
					//音频数据 
					if(pMgr->m_ds.bAudioOut&& 
						pMgr->m_ds.bAudioCodec&& 
						pMgr->m_hAudioOut&& 
						((PACK_AUDIO*)buf)->session==pMgr->m_session) 
					{ 
						char* p=new char[iLen]; 
						if(p) 
						{ 
							CopyMemory(p,buf,iLen); 
							if(!PostThreadMessage(pMgr->m_dwAudioOutId,IOM_AUDIO,iLen,(LPARAM)p)) 
								delete []p; 
						} 
					} 
				} 
				break; 
			case FLAG_VIDEO: 
				{ 
					//视频数据 
					if(pMgr->m_ds.bVideoOut&& 
						pMgr->m_ds.bVideoCodec&& 
						((PACK_VIDEO*)buf)->session==pMgr->m_session) 
					{ 
						 
						pMgr->OnDecodeVideoData((PACK_VIDEO*)buf,iLen);			 
						 
					} 
				} 
				 
				break; 
			} 
		} 
		else 
		{ 
			if(!pMgr->m_Socket.IsSocket()) 
				break; 
		}//the socket should be closed,that is m_Socket have been 
		//destroyed,so break the loop and end the thread 
	} 
	return 0; 
} 
 
/*------------------------------------------------------------------------------*/ 
 
CAVIOMgr::CAVIOMgr() 
{ 
	pMgrInst=this;	 
 
	m_hSockThread=NULL; 
 
	m_hAudioOut=0; 
	m_hAudioIn=0; 
 
	m_idCmd=0; 
 
	m_bEnable=TRUE; 
	m_bEnableBandAdjust=TRUE; 
	 
} 
 
/*------------------------------------------------------------------------------*/ 
CAVIOMgr::~CAVIOMgr() 
{ 
	Destroy(); 
	pMgrInst=0; 
} 
 
/*------------------------------------------------------------------------------*/ 
//初始化SOCKET,指定PORT 
BOOL CAVIOMgr::InitSocket(UINT nPort) 
{ 
	 
	DestroySocket();	 
	 
	BOOL bRet=FALSE;	 
	if(!m_Socket.Create(nPort)) 
		goto RET; 
	//创建socket线程(socket为block方式) 
	m_hSockThread=CreateThread(0,0,SockThreadProc,(LPVOID)this,0,&m_dwSockThreadId); 
	if(!m_hSockThread)	 
		goto RET; 
	 
	 
	bRet=TRUE; 
RET: 
	if(!bRet) 
		DestroySocket(); 
		 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
 
BOOL CAVIOMgr::DestroySocket() 
{ 
	m_Socket.Destroy(); 
	// 
	 
	if(m_hSockThread) 
	{ 
		BOOL b=FALSE; 
		DWORD ExitCode; 
		int Timeout = 50;  
		while(Timeout)//等待线程结束,如果到一定时间还没结束,就强制结束 
		{			 //因为Socket已经destroy了,所以socket线程会返回 
			GetExitCodeThread(m_hSockThread, &ExitCode); 
			 
			if (ExitCode != STILL_ACTIVE) 
			{ 
				b=TRUE; 
				// Thread has ended. 
				break; 
			} 
			else 
			{ 
				Sleep(10); 
			} 
			 
			--Timeout; 
		} 
		if(!b)//time out ,terminate it 
			TerminateThread(m_hSockThread,0); 
				 
	} 
	m_hSockThread=NULL; 
	return TRUE; 
} 
 
/*------------------------------------------------------------------------------*/ 
//设定目标 
void CAVIOMgr::SetDst(char *ip, unsigned short port) 
{ 
	m_dst.sin_family=AF_INET; 
	//将计算机名或IP转化为网络地址 
	m_dst.sin_addr.s_addr=CUDPSocket::Name2Inet(ip); 
	m_dst.sin_port=htons(port); 
	 
} 
 
/*------------------------------------------------------------------------------*/ 
//初始化音频输入,当初始化完成,录音就开始了 
BOOL CAVIOMgr::InitAudioRec() 
{ 
	DestroyAudioRec(); 
	BOOL bRet=FALSE; 
	//创建录音线程 
	m_hAudioIn=CreateThread(0,0,AudioInThreadProc,this,0,&m_dwAudioInId); 
	if(!m_hAudioIn) 
		goto RET; 
	if(!m_AudioRec.Create(0,m_dwAudioInId,(DWORD)this,CALLBACK_THREAD,SIZE_AUDIO_FRAME)) 
		goto RET; 
	//开始录音 
	if(!m_AudioRec.Start()) 
		goto RET; 
	 
	bRet=TRUE; 
RET: 
	if(!bRet) 
	{ 
		//如果失败,就向主窗口发送出错消息 
		PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_AUDIO_IN),(LPARAM)this); 
		DestroyAudioRec(); 
	} 
	 
	return bRet; 
 
} 
 
/*------------------------------------------------------------------------------*/ 
//该死的waveIn函数,结束录音时老是出现死锁(XP下还是会出现这个问题,也不知道怎么解决,苦啊) 
BOOL CAVIOMgr::DestroyAudioRec() 
{ 
	 
	m_AudioRec.Stop(); 
    m_AudioRec.Destroy(); 
	if(m_hAudioIn) 
	{ 
		int t=50; 
		DWORD ExitCode; 
		BOOL bEnd=FALSE; 
		//向录音线程发送退出消息,并等待线程结束 
		PostThreadMessage(m_dwAudioInId,WM_QUIT,0,0); 
		while(t) 
		{ 
			 
			GetExitCodeThread(m_hAudioIn,&ExitCode); 
			if(ExitCode!= STILL_ACTIVE) 
			{ 
				bEnd=TRUE; 
				break; 
			} 
			else 
				Sleep(10); 
			t--; 
		} 
		if(!bEnd) 
			TerminateThread(m_hAudioIn,0); 
		m_hAudioIn=0; 
		 
	}	 
		 
	return TRUE; 
 
} 
 
/*------------------------------------------------------------------------------*/ 
//初始化播放设备 
BOOL CAVIOMgr::InitAudioPlay() 
{ 
	BOOL bRet=FALSE; 
	DestroyAudioPlay(); 
	m_iAudioBuf=0; 
	m_hAudioOut=CreateThread(0,0,AudioOutThreadProc,this,0,&m_dwAudioOutId); 
	if(!m_hAudioOut) 
		goto RET; 
	if(!m_AudioPlay.Create(0,m_dwAudioOutId,(DWORD)this,CALLBACK_THREAD)) 
		goto RET; 
	bRet=TRUE; 
	 
	 
RET: 
	if(!bRet) 
	{ 
		//向主窗口发送出错消息 
		PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_AUDIO_OUT),(LPARAM)this); 
		DestroyAudioPlay(); 
	} 
	 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
// 
BOOL CAVIOMgr::DestroyAudioPlay() 
{ 
 
	m_AudioPlay.Destroy(); 
	if(m_hAudioOut) 
	{ 
		int t=50; 
		DWORD ExitCode; 
		BOOL bEnd=FALSE; 
		PostThreadMessage(m_dwAudioOutId,WM_QUIT,0,0); 
		while(t) 
		{ 
			 
			GetExitCodeThread(m_hAudioOut,&ExitCode); 
			if(ExitCode!= STILL_ACTIVE) 
			{ 
				bEnd=TRUE; 
				break; 
			} 
			else 
				Sleep(10); 
			t--; 
		} 
		if(!bEnd) 
			TerminateThread(m_hAudioOut,0); 
		m_hAudioOut=0; 
		 
	} 
	return TRUE; 
} 
 
/*------------------------------------------------------------------------------*/ 
//音频解码,并将音频数据发送到想要数据的窗口 
void CAVIOMgr::OnDecodeAudioData(PACK_AUDIO *ppa, int len) 
{ 
	 
	if(m_CodecMgr.DecodeAudioData((char*)ppa->data,SIZE_AUDIO_PACKED,m_AudioRemote,0)) 
	{	 
		//为了避免延迟过长,当累积的缓冲超过六块时抛弃即将加入的缓冲 
		if(m_iAudioBuf<6) 
		{ 
			m_iAudioBuf++; 
			m_AudioPlay.Play(m_AudioRemote,SIZE_AUDIO_FRAME); 
		} 
		if(m_hwndRemoteAudioRcv) 
			SendMessage(m_hwndRemoteAudioRcv,IOM_AUDIO,1,(LPARAM)this); 
	} 
	 
	m_uDataRcv+=sizeof(PACK_AUDIO); 
	delete []ppa; 
 
} 
 
/*------------------------------------------------------------------------------*/ 
//压缩音频原始数据并发送出去 
void CAVIOMgr::OnEncodeAudioData(char *pa, int len) 
{ 
	 
	m_AudioPack.flag=FLAG_AUDIO; 
	m_AudioPack.session=m_session; 
	 
	if(m_CodecMgr.EncodeAudioData(pa,len,(char*)m_AudioPack.data,0)) 
	{			 
		m_Socket.SendTo((char*)&m_AudioPack,sizeof(PACK_AUDIO),(sockaddr*)&m_dst); 
		m_uDataSend+=sizeof(PACK_AUDIO); 
	} 
	 
	if(m_hwndLocalAudioRcv) 
		SendMessage(m_hwndLocalAudioRcv,IOM_AUDIO,0,(LPARAM)this); 
		 
} 
 
/*------------------------------------------------------------------------------*/ 
//视频解码 
void CAVIOMgr::OnDecodeVideoData(PACK_VIDEO *ppv, int len) 
{	 
	 
	if(m_CodecMgr.DecodeVideoData(((char*)ppv)+sizeof(PACK_VIDEO),ppv->data_size,m_VideoRemote,0,0)) 
	{ 
		m_nFrameCount++; 
		 
		m_nCurVid=ppv->id; 
		//将视频数据发送到视频显示窗口 
		if(m_hwndRemoteVideoRcv) 
			SendMessage(m_hwndRemoteVideoRcv,IOM_VIDEO,1,(LPARAM)this); 
		 
	} 
	//统计收到的数据 
	m_uDataRcv+=sizeof(PACK_VIDEO)+ppv->data_size; 
} 
 
/*------------------------------------------------------------------------------*/ 
//视频压缩并发送 
void CAVIOMgr::OnEncodeVideoData(char *pv, int len) 
{ 
	 
	int rlen; 
	 
	if(m_bVideoSend) 
	{			 
		if(m_CodecMgr.EncodeVideoData(pv,len,m_VideoPack+sizeof(PACK_VIDEO),&rlen,0)) 
		{ 
			 
			((PACK_VIDEO*)m_VideoPack)->data_size=(unsigned short)rlen; 
			((PACK_VIDEO*)m_VideoPack)->id=m_idVideo++; 
			((PACK_VIDEO*)m_VideoPack)->session=m_session; 
			m_Socket.SendTo(m_VideoPack,rlen+sizeof(PACK_VIDEO),(sockaddr*)&m_dst); 
			//统计发送的数据 
			m_uDataSend+=rlen+sizeof(PACK_VIDEO); 
		} 
	} 
	m_VideoLocal=pv; 
	if(m_hwndLocalVideoRcv) 
	{ 
		//将视频数据发送到视频显示窗口 
		SendMessage(m_hwndLocalVideoRcv,IOM_VIDEO,0,(LPARAM)this); 
	} 
 
	 
} 
 
/*------------------------------------------------------------------------------*/ 
//初始化,创建SOCKET,并监听 
BOOL CAVIOMgr::Init(UINT nPort) 
{ 
	Destroy(); 
		 
	m_hwndLocalVideoRcv=0; 
	m_hwndLocalAudioRcv=0; 
	m_hwndRemoteVideoRcv=0; 
	m_hwndRemoteAudioRcv=0; 
	m_hwndMainWnd=0; 
	m_bVideoSend=TRUE; 
	 
	m_iStatus=STA_FREE; 
	BOOL bRet=FALSE; 
	m_uDataRcv=0; 
	m_uDataSend=0; 
	if(!InitSocket(nPort)) 
		goto RET; 
	//创建消息接收窗口,主要用于超时重发机制,因为要设定很多不同ID的定时器 
	m_MsgRcvWnd.Create(0,0,0,0,CRectX(0,0,0,0),0,0); 
	bRet=TRUE; 
RET: 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
//初始化视频捕捉设备 
BOOL CAVIOMgr::InitCap()// 
{ 
	HWND hCap; 
	 
	m_ViCap.Destroy(); 
	BOOL bRet=FALSE; 
	if(!m_ViCap.Init()) 
		goto RET; 
	//得到驱动数 
	if(!m_ViCap.GetDriverNum()) 
		goto RET; 
	//连接到驱动 
	if(!m_ViCap.ConnectToDriver(0)) 
		goto RET; 
	hCap=m_ViCap.GetCapWindow(); 
	//设置视频格式 
	if(!capSetVideoFormat(hCap,&m_CodecMgr.m_BmpU,sizeof(BITMAPINFO))) 
		goto RET; 
	//设置视频流回调函数 
	if(!capSetCallbackOnVideoStream(hCap,VideoStreamCallbackProc)) 
		goto RET; 
	//将user数据设为AVIOMgr对象指针 
	if(!capSetUserData(hCap,(DWORD)this)) 
		goto RET; 
	//开始视频流 
	if(!capCaptureSequenceNoFile(hCap)) 
		goto RET; 
	 
	bRet=TRUE; 
RET: 
	if(!bRet) 
	{ 
		PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_VIDEO_IN),(LPARAM)this); 
		m_ViCap.Destroy(); 
	} 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
BOOL CAVIOMgr::DestroyCap() 
{ 
	 
	m_ViCap.Destroy(); 
	return TRUE; 
} 
 
/*------------------------------------------------------------------------------*/ 
void CAVIOMgr::Destroy() 
{ 
	EndTalk(); 
	DestroySocket(); 
	DestroyAudioRec(); 
	DestroyCap(); 
	DestroyAudioPlay(); 
	DestroyAudioCodec(); 
	DestroyVideoCodec(); 
} 
 
/*------------------------------------------------------------------------------*/ 
// 
BOOL CAVIOMgr::InitAudioCodec() 
{ 
	 
	BOOL bRet=FALSE; 
	 
	if(!m_CodecMgr.InitCodecA()) 
		goto RET; 
	//启动丢包率定时器	 
	SetTimer(m_hwndMainWnd,100,1000,DropRateCounter); 
	bRet=TRUE; 
RET: 
	if(!bRet) 
	{ 
		PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_AUDIO_CODEC),(LPARAM)this); 
		DestroyAudioCodec(); 
	} 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
// 
void CAVIOMgr::DestroyAudioCodec() 
{	 
	//关闭丢包率定时器 
	KillTimer(m_hwndMainWnd,100); 
	m_CodecMgr.DestroyCodecA(); 
} 
 
/*------------------------------------------------------------------------------*/ 
//初始化视频编码解码器 
BOOL CAVIOMgr::InitVideoCodec() 
{ 
	m_idVideo=0; 
	m_nFps=0; 
	m_nFrameCount=0; 
	m_nLastFrameCount=0; 
	m_nDropRate=0; 
	m_nCurVid=0; 
	m_nLastVid=0; 
	BOOL bRet=FALSE; 
	// 
	if(!m_CodecMgr.InitCodecV()) 
		goto RET; 
	 
	((PACK_VIDEO*)m_VideoPack)->flag=FLAG_VIDEO; 
 
		 
	bRet=TRUE; 
RET: 
	if(!bRet) 
	{ 
		PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_VIDEO_CODEC),(LPARAM)this); 
		DestroyVideoCodec(); 
	} 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
void CAVIOMgr::DestroyVideoCodec() 
{ 
	 
	 
		 
	m_CodecMgr.DestroyCodecV(); 
} 
 
 
/*------------------------------------------------------------------------------*/ 
void CAVIOMgr::GetDeviceSupport(DEVICE_SUPPORT &ds) 
{ 
 
} 
 
/*------------------------------------------------------------------------------*/ 
//呼叫某个IP 
BOOL CAVIOMgr::Call(char *ip, unsigned short port) 
{ 
	BOOL bRet=FALSE; 
	if(m_iStatus!=STA_FREE) 
		goto RET; 
	SetDst(ip,port); 
	PACK_CMD pc; 
	m_session=rand()&0xff; 
	pc.flag=FLAG_CMD; 
	pc.cmd=CMD_CALL; 
	pc.type=0; 
	pc.data_size_extra=0; 
	pc.ext=VER_AVIO&0xff;//AVIO 的版本 
	if(!SendCmd(&pc,sizeof(pc),m_dst,TRUE)) 
		goto RET; 
	 
	m_iStatus=STA_BUSY; 
	bRet=TRUE; 
	m_uDataSend=0; 
	m_uDataRcv=0; 
	 
RET: 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
//结束通话 
BOOL CAVIOMgr::EndTalk() 
{ 
	BOOL bRet=FALSE; 
	if(m_iStatus==STA_FREE) 
		goto RET; 
	if(m_iStatus==STA_BUSY) 
	{ 
		m_iStatus=STA_FREE; 
	 
		PACK_CMD pc; 
		pc.flag=FLAG_CMD; 
		 
		pc.cmd=CMD_END; 
		pc.data_size_extra=0; 
		pc.type=0; 
		SendCmd(&pc,sizeof(pc),m_dst,FALSE); 
		ZeroMemory(&m_dst,sizeof(m_dst)); 
		DestroyVideoCodec(); 
		DestroyAudioCodec(); 
		DestroyAudioPlay(); 
		DestroyAudioRec(); 
		DestroyCap(); 
		 
		 
	} 
	 
	bRet=TRUE; 
RET: 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
//接受请求 
BOOL CAVIOMgr::Accept() 
{ 
	BOOL bRet=FALSE; 
	if(m_iStatus!=STA_BUSY) 
		goto RET; 
	PACK_CMD pc; 
	pc.flag=FLAG_CMD; 
	pc.cmd=CMD_ACCEPT; 
	 
	pc.data_size_extra=0; 
	pc.type=0; 
	SendCmd(&pc,sizeof(pc),m_dst,TRUE); 
		 
	ZeroMemory(&m_ds,sizeof(m_ds)); 
	m_ds.bVideoOut=true;//always ok 
	if(InitVideoCodec())//why this must ahead InitAudioCodec??i don't know why 
		m_ds.bVideoCodec=true; 
	if(InitAudioCodec()) 
		m_ds.bAudioCodec=true; 
	if(InitAudioPlay()) 
		m_ds.bAudioOut=true; 
	if(InitAudioRec()) 
		m_ds.bAudioIn=true; 
	 
	if(m_ds.bVideoCodec&&InitCap()) 
		m_ds.bVideoIn=true; 
	 
	if(!m_ds.bAudioCodec&&!m_ds.bVideoCodec) 
	{ 
		DestroyCap(); 
		DestroyAudioRec(); 
		DestroyAudioPlay(); 
		DestroyAudioCodec(); 
		DestroyVideoCodec(); 
		 
		m_iStatus=STA_FREE; 
	} 
	bRet=TRUE; 
RET: 
	return bRet; 
 
} 
 
/*------------------------------------------------------------------------------*/ 
//拒绝请求 
BOOL CAVIOMgr::Refuse() 
{ 
	BOOL bRet=FALSE; 
	if(m_iStatus!=STA_BUSY) 
		goto RET; 
	PACK_CMD pc; 
	pc.flag=FLAG_CMD; 
	pc.cmd=CMD_REFUSE; 
	 
	pc.ext=R_USER; 
	pc.data_size_extra=0; 
	pc.type=0; 
	m_iStatus=STA_FREE; 
 
	SendCmd(&pc,sizeof(pc),m_dst,TRUE);	 
	 
	bRet=TRUE; 
RET: 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
//解释发送来的命令 
void CAVIOMgr::OnCommand(PACK_CMD *ppc, int len) 
{ 
	switch(ppc->cmd) 
	{ 
	case CMD_CALL: 
		{ 
			if(ppc->type==0) 
			{ 
				if(m_bEnable) 
				{ 
					//如果是空闲的,就保存地址,设置状态为工作状态 
					//并向主窗口发送呼叫通知 
					if(m_iStatus==STA_FREE) 
					{ 
						m_dst=m_sockaddr; 
						m_iStatus=STA_BUSY; 
						m_session=ppc->session; 
						PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_CALL,VER_AVIO),(LPARAM)this); 
						//返回请求确认 
						PACK_CMD pc; 
						pc.flag=FLAG_CMD; 
						pc.data_size_extra=0; 
						 
						pc.cmd=CMD_CALL; 
						pc.ext=VER_AVIO&0xff;// AVIO的版本 
						pc.type=1; 
						pc.id=ppc->id; 
						pc.session=m_session; 
						m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr); 
						 
						 
					} 
					else 
					if(m_iStatus==STA_BUSY&&m_session!=ppc->session) 
					{					 
						/*//有另一台机请求通话,拒绝! 
						 
						PACK_CMD pc; 
						pc.flag=FLAG_CMD; 
						pc.cmd=CMD_REFUSE; 
						pc.data_size_extra=0; 
						pc.ext=R_BUSY; 
						pc.type=0; 
						pc.id=ppc->id; 
						pc.session=ppc->session; 
						m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);*/ 
					} 
				} 
			} 
			//回应 
			else 
			{ 
				if(ppc->session==m_session) 
				{ 
					KillTimer(m_MsgRcvWnd,ppc->id); 
					m_CmdQueue.Remove(ppc->id); 
					PostMessage(m_hwndMainWnd,IOM_NOTIFY,IOMN_CONNECTED,(LPARAM)this); 
				} 
			} 
		}break; 
	case CMD_END: 
		{ 
			if(ppc->session==m_session) 
			{ 
				if(ppc->type==0) 
				{ 
					 
					if(m_iStatus==STA_BUSY) 
					{ 
						PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_END,E_USER),(LPARAM)this); 
					} 
					PACK_CMD pc; 
					pc.flag=FLAG_CMD; 
					pc.data_size_extra=0; 
					pc.cmd=CMD_END; 
					pc.type=1; 
					pc.id=ppc->id; 
					pc.session=m_session; 
					m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr); 
					 
				} 
				else 
				{ 
					KillTimer(m_MsgRcvWnd,ppc->id); 
					m_CmdQueue.Remove(ppc->id); 
				} 
			} 
			 
		} 
		break; 
	case CMD_REFUSE: 
		{ 
			if(ppc->session==m_session) 
			{ 
				 
				if(ppc->type==0) 
				{ 
					 
					if(m_iStatus==STA_BUSY) 
					{ 
						m_iStatus=STA_FREE; 
						PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_REFUSE,ppc->ext),(LPARAM)this); 
					} 
					PACK_CMD pc; 
					pc.flag=FLAG_CMD; 
					pc.data_size_extra=0; 
					pc.cmd=CMD_REFUSE; 
					pc.type=1; 
					pc.id=ppc->id; 
					pc.session=m_session;				 
					m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr); 
					 
					 
				} 
				else 
				{ 
					KillTimer(m_MsgRcvWnd,ppc->id); 
					m_CmdQueue.Remove(ppc->id); 
				} 
			} 
		} 
		break; 
	case CMD_ACCEPT: 
		{ 
			if(ppc->session==m_session) 
			{ 
				if(ppc->type==0) 
				{ 
					 
					if(m_iStatus==STA_BUSY) 
					{ 
						PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ACCEPT,VER_AVIO),(LPARAM)this); 
					} 
					PACK_CMD pc; 
					pc.flag=FLAG_CMD; 
					pc.data_size_extra=0; 
					pc.cmd=CMD_ACCEPT; 
					pc.type=1; 
					pc.id=ppc->id; 
					pc.session=m_session; 
					m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr); 
					 
				} 
				else 
				{ 
					KillTimer(m_MsgRcvWnd,ppc->id); 
					m_CmdQueue.Remove(ppc->id); 
				} 
			} 
			 
		} 
		break; 
	case CMD_TXT: 
		{ 
			if(ppc->type==0) 
			{ 
				//bug exist 
				SendMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_TXT,0),(LPARAM)(((char*)ppc)+sizeof(PACK_CMD))); 
				PACK_CMD pc; 
				pc.flag=FLAG_CMD; 
				pc.data_size_extra=0; 
				pc.cmd=CMD_TXT; 
				pc.type=1; 
				pc.id=ppc->id; 
				m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr); 
			} 
			else 
			{ 
				 
				KillTimer(m_MsgRcvWnd,ppc->id); 
				UINT len;char resend;sockaddr_in addr; 
				char* p=m_CmdQueue.GetBuf(ppc->id,len,resend,addr); 
				if(p) 
				{ 
					SendMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_TXT,1),(LPARAM)(p+sizeof(PACK_CMD))); 
				} 
				m_CmdQueue.Remove(ppc->id); 
			} 
		} 
		break; 
 
	case CMD_DROPRATE: 
		{ 
			//根据丢包率来调整视频质量 
			if(ppc->type==0&&ppc->session&&m_bEnableBandAdjust) 
			{ 
				SetVideoQuality(100-ppc->ext); 
				SendMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_VQSET,100-ppc->ext),(LPARAM)this); 
			} 
		}break; 
		 
	} 
 
} 
 
/*------------------------------------------------------------------------------*/ 
//以下是设置对外消息接口 
//设置主窗口 
void CAVIOMgr::SetMainWnd(HWND hwnd) 
{ 
	m_hwndMainWnd=hwnd; 
} 
 
void CAVIOMgr::SetLocalVideoRcvWnd(HWND hwnd) 
{ 
	m_hwndLocalVideoRcv=hwnd; 
} 
 
void CAVIOMgr::SetLocalAudioRcvWnd(HWND hwnd) 
{ 
	m_hwndLocalAudioRcv=hwnd; 
} 
 
void CAVIOMgr::SetRemoteVideoRcvWnd(HWND hwnd) 
{ 
	m_hwndRemoteVideoRcv=hwnd; 
} 
 
void CAVIOMgr::SetRemoteAudioRcvWnd(HWND hwnd) 
{ 
	m_hwndRemoteAudioRcv=hwnd; 
} 
 
/*------------------------------------------------------------------------------*/ 
//得到当前状态 
int CAVIOMgr::GetStatus() 
{ 
	return m_iStatus; 
} 
 
/*------------------------------------------------------------------------------*/ 
//调用以下函数要谨慎 
//只有在收到相应消息时才能调用 
///////////////////////// 
/// 
char* CAVIOMgr::GetLocalVideo(UINT &len) 
{ 
	len=m_CodecMgr.m_BmpU.bmiHeader.biSizeImage; 
	return m_VideoLocal; 
} 
 
char* CAVIOMgr::GetLocalAudio(UINT &len) 
{ 
	len=SIZE_AUDIO_FRAME; 
	return m_AudioLocal; 
} 
 
char* CAVIOMgr::GetRemoteVideo(UINT &len) 
{ 
	len=m_CodecMgr.m_BmpU.bmiHeader.biSizeImage; 
	return m_VideoRemote; 
} 
 
char* CAVIOMgr::GetRemoteAudio(UINT &len) 
{ 
	len=SIZE_AUDIO_FRAME; 
	return m_AudioRemote; 
} 
 
/*------------------------------------------------------------------------------*/ 
//得到原始视频格式 
BITMAPINFO* CAVIOMgr::GetBitampInfo() 
{ 
	return &m_CodecMgr.m_BmpU; 
} 
 
/*------------------------------------------------------------------------------*/ 
//得到数据发送量 
UINT CAVIOMgr::GetDataSend() 
{ 
	return m_uDataSend; 
} 
/*------------------------------------------------------------------------------*/ 
//得到数据接收量 
UINT CAVIOMgr::GetDataRcv() 
{ 
	return m_uDataRcv; 
} 
/*------------------------------------------------------------------------------*/ 
//设置是否传输视频 
void CAVIOMgr::VideoSend(BOOL b) 
{ 
	m_bVideoSend=b; 
	 
} 
/*------------------------------------------------------------------------------*/ 
//得到对方地址 
sockaddr_in CAVIOMgr::GetRemoteAddr() 
{ 
	return m_dst; 
} 
/*------------------------------------------------------------------------------*/ 
//设置视频质量 
void CAVIOMgr::SetVideoQuality(UINT q) 
{ 
	m_CodecMgr.m_cv.lQ=q*100; 
} 
/*------------------------------------------------------------------------------*/ 
//预览 
BOOL CAVIOMgr::EnablePreview(BOOL b) 
{ 
	if(m_iStatus==STA_FREE&&b) 
	{ 
		return InitCap();			 
	} 
	else 
	if(m_iStatus==STA_FREE&&!b) 
	{ 
		DestroyCap(); 
		 
	} 
	return TRUE; 
} 
 
/*------------------------------------------------------------------------------*/ 
//当对方接收请求后,会受到Accept的消息,这时必须调用此函数,来打开各种设备 
void CAVIOMgr::OnAccept() 
{ 
	if(m_iStatus==STA_FREE) return; 
	ZeroMemory(&m_ds,sizeof(m_ds)); 
 
	m_ds.bVideoOut=true;//always ok 
	if(InitVideoCodec()) 
		m_ds.bVideoCodec=true; 
	if(InitAudioCodec()) 
		m_ds.bAudioCodec=true; 
	if(InitAudioPlay()) 
		m_ds.bAudioOut=true; 
	if(InitAudioRec()) 
		m_ds.bAudioIn=true; 
	 
	if(m_ds.bVideoCodec&&InitCap()) 
		m_ds.bVideoIn=true; 
	 
	if(!m_ds.bAudioCodec&&!m_ds.bVideoCodec) 
	{ 
		DestroyCap(); 
		DestroyAudioRec(); 
		DestroyAudioPlay(); 
		DestroyAudioCodec(); 
		DestroyVideoCodec(); 
		 
		m_iStatus=STA_FREE; 
	} 
 
 
	 
} 
 
/*------------------------------------------------------------------------------*/ 
//得到帧数 
UINT CAVIOMgr::GetFrameCount() 
{ 
	return m_nFrameCount; 
} 
 
/*------------------------------------------------------------------------------*/ 
//发送命令(比较可靠) 
BOOL CAVIOMgr::SendCmd(PACK_CMD *pCmd, UINT nLen,sockaddr_in &addr, BOOL bFlag) 
{ 
	if(!pCmd) return FALSE; 
	pCmd->id=m_idCmd++; 
	pCmd->session=m_session; 
	 
	int l=m_Socket.SendTo((char*)pCmd,nLen,(sockaddr*)&addr); 
	if(l>0) 
	{ 
		if(bFlag) 
		{ 
			m_CmdQueue.Add(pCmd->id,(char*)pCmd,nLen,addr);//把命令加入命令表 
			SetTimer(m_MsgRcvWnd,pCmd->id,800,CmdTimeOutProc); 
		} 
		return TRUE; 
	} 
	else 
		return FALSE; 
} 
 
/*------------------------------------------------------------------------------*/ 
//命令超时重发 
void CALLBACK CAVIOMgr::CmdTimeOutProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime) 
{ 
	if(pMgrInst) 
	{ 
		UINT len;char resend;sockaddr_in addr; 
		char* p=pMgrInst->m_CmdQueue.GetBuf(idEvent,len,resend,addr);//找出相应ID的命令(已经超时,需要重发) 
		if(p) 
		{ 
			if(resend<5) 
				pMgrInst->m_Socket.SendTo(p,len,(sockaddr*)&addr); 
			else//当重发次数超过4次时,宣布失败 
			{ 
				KillTimer(hwnd,idEvent);// 
				 
				if(pMgrInst) 
				{ 
					PACK_CMD* pCmd=(PACK_CMD*)p; 
					switch(pCmd->cmd) 
					{ 
					case CMD_CALL: 
						{ 
							PostMessage(pMgrInst->m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_REFUSE,R_TIMEOUT),(LPARAM)pMgrInst); 
							pMgrInst->m_iStatus=STA_FREE; 
							 
						} 
						break; 
					case CMD_REFUSE: 
						break; 
					case CMD_ACCEPT: 
						break; 
					case CMD_END: 
						break; 
					case CMD_TXT: 
						break; 
					} 
				} 
				pMgrInst->m_CmdQueue.Remove(idEvent);//把命令从表中移除 
			} 
		} 
		else 
			KillTimer(hwnd,idEvent); 
	} 
} 
 
/*------------------------------------------------------------------------------*/ 
//丢包率计算(包括帧频率计算) 
void CALLBACK CAVIOMgr::DropRateCounter(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime) 
{ 
	//计算丢包率 
	if(pMgrInst) 
	{ 
		UINT delt; 
		if(pMgrInst->m_nCurVidm_nLastVid) 
			delt=pMgrInst->m_nCurVid+256-pMgrInst->m_nLastVid; 
		else 
			delt=pMgrInst->m_nCurVid-pMgrInst->m_nLastVid; 
		if(delt>0) 
			pMgrInst->m_nDropRate=100-(pMgrInst->m_nFrameCount-pMgrInst->m_nLastFrameCount)*100/delt; 
		pMgrInst->m_nLastVid=pMgrInst->m_nCurVid; 
		//发送丢包率 
		PACK_CMD pc; 
		pc.flag=FLAG_CMD; 
		pc.cmd=CMD_DROPRATE; 
		pc.session=pMgrInst->m_session; 
		pc.type=0; 
		pc.data_size_extra=0; 
		pc.ext=pMgrInst->m_nDropRate; 
		pMgrInst->m_Socket.SendTo((char*)&pc,sizeof(PACK_CMD),(SOCKADDR*)&pMgrInst->m_dst);		 
		//计算帧频率 
		pMgrInst->m_nFps=(pMgrInst->m_nFrameCount-pMgrInst->m_nLastFrameCount); 
		 
		 
		pMgrInst->m_nLastFrameCount=pMgrInst->m_nFrameCount; 
	} 
 
} 
 
/*------------------------------------------------------------------------------*/ 
UINT CAVIOMgr::GetFps() 
{ 
	return m_nFps; 
} 
 
/*------------------------------------------------------------------------------*/ 
//发送文本信息 
BOOL CAVIOMgr::SendTxt(char *ip, unsigned short port, char *txt) 
{ 
	BOOL bRet=FALSE; 
	 
	PACK_CMD *ppc=(PACK_CMD*)new char[sizeof(PACK_CMD)+strlen(txt)+1]; 
	strcpy(((char*)ppc)+sizeof(PACK_CMD),txt); 
	ppc->flag=FLAG_CMD; 
	ppc->cmd=CMD_TXT; 
	ppc->type=0; 
	ppc->data_size_extra=strlen(txt)+1; 
	//将ip和port转化 
	sockaddr_in addr; 
	addr.sin_family=AF_INET; 
	addr.sin_addr.s_addr=CUDPSocket::Name2Inet(ip); 
	addr.sin_port=htons(port); 
	// 
	if(!SendCmd(ppc,sizeof(PACK_CMD)+ppc->data_size_extra,addr,TRUE)) 
		goto RET; 
	 
	bRet=TRUE; 
		 
RET: 
	return bRet; 
} 
 
/*------------------------------------------------------------------------------*/ 
//得到前一次发来数据的地址 
sockaddr_in& CAVIOMgr::GetCurrentAddr() 
{ 
	return m_sockaddr; 
} 
 
/*------------------------------------------------------------------------------*/ 
// 
BOOL CAVIOMgr::Enable(BOOL bEnable) 
{ 
	BOOL t=m_bEnable; 
	m_bEnable=bEnable; 
	return t; 
} 
 
/*------------------------------------------------------------------------------*/ 
//是否自动调整图象质量 
BOOL CAVIOMgr::EnableBandAdjust(BOOL bEnable) 
{ 
	BOOL t=m_bEnableBandAdjust; 
	m_bEnableBandAdjust=bEnable; 
	return t; 
}