?? aviomgr.cpp
字號:
//NetTalk
/*------------------------------------------------------------------------------*\
=============================
模塊名稱: AVIOMgr.cpp
=============================
[版權]
2000-2002 115軟件工廠 版權所有
\*------------------------------------------------------------------------------*/
#include "WndX.h"
#include <vfw.h>
#include "AVIOMgr.h"
#include "UDPSocket.h"
#include "g729a.h"
#include "AudioPlay.h"
#include <stdio.h>
/*------------------------------------------------------------------------------*/
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)
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -