//NetTalk
/*------------------------------------------------------------------------------*\
 =============================
   模块名称: AVIOMgr.h
 =============================
 
 [版权]
 
   2000-2002  115软件工厂  版权所有
                                              
\*------------------------------------------------------------------------------*/
//视频通讯的核心部分//

#ifndef _AVIOMGR_H_
#define _AVIOMGR_H_

#include "AudioRec.h"
#include "CodecMgr.h"
#include "VideoCapture.h"
#include "AudioPlay.h"
#include "UDPSocket.h"


//AVIO版本
#define VER_AVIO 102

//msg
//the LOWORD wParam specify the notify code
#define IOM_NOTIFY     WM_USER+50

//notify code
//the HIWORD of wParam specify the VER of AVIO
#define IOMN_CALL              0
#define IOMN_ACCEPT            1
#define IOMN_CONNECTED         2
//////////
#define IOMN_END               3//HIWORD of wParam identify the end code
#define E_TIMEOUT   1
#define E_USER      2
////////////////
#define IOMN_REFUSE            4 //HIWORD of wParam identify the refuse code

#define R_TIMEOUT    1
#define R_USER       2
#define R_BUSY       3

//the HIWORD of wParam specify the err code
#define IOMN_ERR               5      

//err code

#define IOME_STOP        0
#define IOME_SOCKET      1
#define IOME_AUDIO_IN    2
#define IOME_AUDIO_OUT   3
#define IOME_VIDEO_IN    4
#define IOME_VIDEO_OUT   5
#define IOME_AUDIO_CODEC 6
#define IOME_VIDEO_CODEC 7


#define IOMN_TXT                6//lParam point to the txt
#define IOMN_VQSET               7//Hiword :q
////////////////////////////////////////////
//data handle msg
//the lParam point to the AVIO object
//Use
//GetRemoteAudio
//GetRemoteVideo
//GetLocalAudio
//GetLocalVideo
//to Handle the data ,and proccess this as you like(paint or play)
//Warning:you should return these messages quickly,as these msg is sent by SendMessage
////the wParam identify the data type,0 local,or remote
#define IOM_AUDIO       WM_USER+51
#define IOM_VIDEO       WM_USER+52


///status
#define STA_FREE    0
#define STA_BUSY    1



//pack flag
#define FLAG_AUDIO 0x3131
#define FLAG_VIDEO 0x3132
#define FLAG_CMD   0x3133

//
#define SIZE_AUDIO_FRAME 960
#define SIZE_AUDIO_PACKED 60
//
//音频数据包（包含音频数据）
typedef struct
{
	short flag;
	BYTE session;
	BYTE  id;
	BYTE data[SIZE_AUDIO_PACKED];
}PACK_AUDIO;
//视频数据包（不包含视频数据）
typedef struct
{
	short flag;
	BYTE session;
	BYTE id;
	BYTE subid;
	BYTE key; //whether key frame
	unsigned int data_size_total;
	unsigned short data_size;
	
}PACK_VIDEO;

/////
#define CMD_CALL           1
#define CMD_REFUSE         2
#define CMD_ACCEPT	       3
#define CMD_END            4


#define CMD_TXT            20

//丢包率
#define CMD_DROPRATE      21
//命令数据包(文本信息也用该数据包)
#define SIZE_TXT 1024

typedef struct
{
	short flag;
	BYTE session;
	BYTE id;
	
	BYTE cmd;
	BYTE type;//0：始发 1：反馈
	BYTE ext;
	unsigned short data_size_extra;
}PACK_CMD;

typedef struct
{
	bool bVideoIn;
	bool bVideoOut;
	bool bAudioIn;
	bool bAudioOut;
	bool bVideoCodec;
	bool bAudioCodec;
}DEVICE_SUPPORT;
//////////////////
struct CMD_ITEM
{
	char resend;
	int ID;
	char* pbuf;
	UINT len;
	sockaddr_in addr;
	CMD_ITEM* pNext;
	CMD_ITEM* pPrev;
};
//Cmd queue implementation
class CCmdQueue
{
public:
	CCmdQueue()
	{
		InitializeCriticalSection(&m_cs);
		pHead=0;
		count=0;
	}
	~CCmdQueue()
	{
		CMD_ITEM* p=pHead,*temp;
		while(p)
		{
			temp=p->pNext;
			Remove(p);
			p=temp;
		}
		DeleteCriticalSection(&m_cs);
	}
	void Add(int ID,char* buf,UINT len,sockaddr_in &addr)
	{
		EnterCriticalSection(&m_cs);
		CMD_ITEM* p=new CMD_ITEM;
		p->pNext=pHead;
		if(pHead)
			pHead->pPrev=p;
		p->resend=1;
		p->pPrev=0;
		p->ID=ID;
		p->pbuf=new char[len];
		p->len=len;
		p->addr=addr;
		CopyMemory(p->pbuf,buf,len);
		pHead=p;
		count++;
		LeaveCriticalSection(&m_cs);
	}
	char* GetBuf(int ID,UINT& len,char& resend,sockaddr_in& addr)
	{
		
		CMD_ITEM* p=pHead;
		while(p)
		{
			if(p->ID==ID)
			{
				len=p->len;
				addr=p->addr;
				resend=p->resend++;
				return p->pbuf;
			}
			p=p->pNext;
		}
		return 0;
	}
	bool Remove(int ID)
	{
		EnterCriticalSection(&m_cs);
		bool ret=false;
		CMD_ITEM* p=pHead,*temp;
		
		while(p)
		{
			temp=p->pNext;
			if(p->ID==ID)
			{
			
				Remove(p);
				ret=true;
				break;
				
			}
			p=temp;			
		}
		LeaveCriticalSection(&m_cs);
		return ret;
	}
	bool Remove(CMD_ITEM* p)
	{
		if(p)
		{
			if(p==pHead)
				pHead=p->pNext;
			if(p->pbuf)
				delete []p->pbuf;
			if(p->pPrev)
				p->pPrev->pNext=p->pNext;
			if(p->pNext)
				p->pNext->pPrev=p->pPrev;
			delete p;
			count--;
			return true;
		}
		else
		{
			return false;
		}
	}
	int count;
private:
	
	CMD_ITEM* pHead;
protected:
	CRITICAL_SECTION m_cs;
};

//

class CAVIOMgr
{
public:
	BOOL EnableBandAdjust(BOOL bEnable);
	BOOL Enable(BOOL bEnable);
	sockaddr_in& GetCurrentAddr();
	BOOL SendTxt(char* ip,unsigned short port,char* txt);
	
	UINT GetFps();
	CAVIOMgr();
	virtual  ~CAVIOMgr();
	
	BOOL Init(UINT nPort);
	void Destroy();

	BOOL Call(char* ip,unsigned short port);
	BOOL Accept();
	void OnAccept();
	BOOL Refuse();
	BOOL EndTalk();

	UINT GetFrameCount();
	UINT GetDataRcv();
	UINT GetDataSend();

	BOOL EnablePreview(BOOL b);
	
	sockaddr_in GetRemoteAddr();
	int GetStatus();
	void GetDeviceSupport(DEVICE_SUPPORT& ds);

	BITMAPINFO* GetBitampInfo();
	char* GetRemoteAudio(UINT& len);
	char* GetRemoteVideo(UINT& len);
	char* GetLocalAudio(UINT&len);
	char* GetLocalVideo(UINT& len);
	
	
	void SetRemoteAudioRcvWnd(HWND hwnd);
	void SetRemoteVideoRcvWnd(HWND hwnd);
	void SetLocalAudioRcvWnd(HWND hwnd);
	void SetLocalVideoRcvWnd(HWND hwnd);
	void SetMainWnd(HWND hwnd);
	
	void VideoSend(BOOL b);
	void SetVideoQuality(UINT q);

	friend class CCodecMgr;

protected:
	BOOL InitCap();
	BOOL DestroyCap();

	void DestroyVideoCodec();
	BOOL InitVideoCodec();

	void DestroyAudioCodec();
	BOOL InitAudioCodec();
	
	BOOL DestroyAudioPlay();
	BOOL InitAudioPlay();

	BOOL DestroyAudioRec();
	BOOL InitAudioRec();
	
	BOOL DestroySocket();
	BOOL InitSocket(UINT nPort);

	void OnEncodeVideoData(char* pv,int len);
	void OnEncodeAudioData(char* pa,int len);
	void OnDecodeVideoData(PACK_VIDEO* ppv,int len);
	void OnDecodeAudioData(PACK_AUDIO* ppa,int len);
	void OnCommand(PACK_CMD* ppc,int len);

	void SetDst(char* ip,unsigned short port);
	
	static DWORD WINAPI AudioInThreadProc(LPVOID lpParameter);
	static DWORD WINAPI AudioOutThreadProc(LPVOID lpParameter);
	static DWORD WINAPI SockThreadProc(LPVOID lpParameter);
	static void CALLBACK CmdTimeOutProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
	static void CALLBACK DropRateCounter(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
	static LRESULT CALLBACK VideoStreamCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr);
	
protected:
	BOOL m_bEnableBandAdjust;
	BOOL m_bEnable;
	CWndX m_MsgRcvWnd;
	BYTE m_session;

	
	BYTE m_idCmd;
	BYTE m_idVideo;
	BOOL SendCmd(PACK_CMD* pCmd,UINT nLen,sockaddr_in &addr,BOOL bFlag);

	CCmdQueue m_CmdQueue;
	UINT m_nFrameCount;
	UINT m_nLastFrameCount;
	UINT m_nDropRate;
	UINT m_nFps;
	UINT m_uDataRcv;
	UINT m_uDataSend;
	UINT m_nCurVid;
	UINT m_nLastVid;

	HANDLE m_hAudioOut;
	HANDLE m_hAudioIn;
	DWORD m_dwAudioOutId;
	DWORD m_dwAudioInId;

	BOOL m_bVideoSend;
	

	
	PACK_AUDIO m_AudioPack;
	char m_VideoPack[MAX_UDP_SIZE];

	char m_AudioLocal[SIZE_AUDIO_FRAME];
	char m_VideoRemote[76032];
	char m_AudioRemote[SIZE_AUDIO_FRAME];
	char* m_VideoLocal;


	
	int m_iStatus;	
	DEVICE_SUPPORT m_ds;

	HWND m_hwndMainWnd;
	HWND m_hwndLocalVideoRcv;
	HWND m_hwndLocalAudioRcv;
	HWND m_hwndRemoteVideoRcv;
	HWND m_hwndRemoteAudioRcv;
	
	

	int m_iAudioBuf;
	
	CAudioPlay m_AudioPlay;
	CAudioRec m_AudioRec;
	
	CCodecMgr m_CodecMgr;
	CVideoCapture m_ViCap;
	CUDPSocket m_Socket;


	sockaddr_in m_sockaddr;
	sockaddr_in m_dst;
	
	
	CAPSTATUS m_CapStauts;

	HANDLE m_hSockThread;
	DWORD m_dwSockThreadId;
};


#endif