AVIOMgr.cpp
上传用户:oldpeter23
上传日期:2013-01-09
资源大小:1111k
文件大小:28k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. //NetTalk
  2. /*------------------------------------------------------------------------------*
  3.  =============================
  4.    模块名称: AVIOMgr.cpp
  5.  =============================
  6.  
  7.  [版权]
  8.  
  9.    2000-2002  115软件工厂  版权所有
  10.                                               
  11. *------------------------------------------------------------------------------*/
  12. #include "WndX.h"
  13. #include <vfw.h> 
  14. #include "AVIOMgr.h"
  15. #include "UDPSocket.h"
  16. #include "g729a.h"
  17. #include "AudioPlay.h"
  18. #include <stdio.h>
  19. /*------------------------------------------------------------------------------*/
  20. CAVIOMgr* pMgrInst=0;
  21. /*------------------------------------------------------------------------------*/
  22. //声音输入线程,包括声音的压缩
  23. DWORD WINAPI CAVIOMgr::AudioInThreadProc(LPVOID lpParameter)
  24. {
  25. CAVIOMgr* pMgr=(CAVIOMgr*)lpParameter;
  26. MSG msg;
  27. while(GetMessage(&msg,0,0,0))
  28. {
  29. switch(msg.message)
  30. {
  31. case WIM_DATA:
  32. {
  33. WAVEHDR* pWH=(WAVEHDR*)msg.lParam;
  34. waveInUnprepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));
  35. if(pWH->dwBytesRecorded!=SIZE_AUDIO_FRAME)
  36. break;//it's not full recorded,i think the wave recorder has ben
  37. //stopped,discard it,and don't do anything!
  38. //
  39. CopyMemory(pMgr->m_AudioLocal,pWH->lpData,SIZE_AUDIO_FRAME);
  40. pMgr->OnEncodeAudioData(pMgr->m_AudioLocal,SIZE_AUDIO_FRAME);
  41. waveInPrepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));
  42. waveInAddBuffer((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));
  43. }
  44. break;
  45. }
  46. }
  47. return msg.wParam;
  48. }
  49. /*------------------------------------------------------------------------------*/
  50. //音频输出线程,包括音频解码
  51. DWORD WINAPI CAVIOMgr::AudioOutThreadProc(LPVOID lpParameter)
  52. {
  53. CAVIOMgr* pMgr=(CAVIOMgr*)lpParameter;
  54. MSG msg;
  55. while(GetMessage(&msg,0,0,0))
  56. {
  57. switch(msg.message)
  58. {
  59. case IOM_AUDIO:
  60. pMgr->OnDecodeAudioData((PACK_AUDIO*)msg.lParam,(int)msg.wParam);
  61. break;
  62. case WOM_DONE:
  63. {
  64. WAVEHDR* pwh=(WAVEHDR*)msg.lParam;
  65. waveOutUnprepareHeader((HWAVEOUT)msg.wParam,pwh,sizeof(WAVEHDR));
  66. pMgr->m_iAudioBuf--;
  67. delete []pwh->lpData;//删除Play调用时分配的内存
  68. delete pwh;
  69. }
  70. break;
  71. }
  72. }
  73. return msg.wParam;
  74. }
  75. /*------------------------------------------------------------------------------*/
  76. //视频流回调函数
  77. LRESULT CALLBACK CAVIOMgr::VideoStreamCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)
  78. {
  79. CAVIOMgr* pMgr=(CAVIOMgr*)capGetUserData(hWnd);
  80. if(pMgr)
  81. {
  82. //压缩视频数据
  83. pMgr->OnEncodeVideoData((char*)lpVHdr->lpData,lpVHdr->dwBytesUsed);
  84. }
  85. return TRUE;
  86. }
  87. /*------------------------------------------------------------------------------*/
  88. //Socket线程,负责接收数据
  89. DWORD WINAPI CAVIOMgr::SockThreadProc(LPVOID lpParameter)
  90. {
  91. CAVIOMgr* pMgr=(CAVIOMgr*)lpParameter;
  92. char buf[4096];
  93. int iLen=0;
  94. while(1)
  95. {
  96. iLen=pMgr->m_Socket.RecvFrom(buf,4096,(sockaddr*)&pMgr->m_sockaddr);
  97. if(iLen>0)
  98. {
  99. switch(*((short*)buf))//check the flag
  100. {
  101. case FLAG_CMD:
  102. {
  103. //命令
  104. pMgr->OnCommand((PACK_CMD*)buf,iLen);
  105. }
  106. break;
  107. case FLAG_AUDIO:
  108. {
  109. //音频数据
  110. if(pMgr->m_ds.bAudioOut&&
  111. pMgr->m_ds.bAudioCodec&&
  112. pMgr->m_hAudioOut&&
  113. ((PACK_AUDIO*)buf)->session==pMgr->m_session)
  114. {
  115. char* p=new char[iLen];
  116. if(p)
  117. {
  118. CopyMemory(p,buf,iLen);
  119. if(!PostThreadMessage(pMgr->m_dwAudioOutId,IOM_AUDIO,iLen,(LPARAM)p))
  120. delete []p;
  121. }
  122. }
  123. }
  124. break;
  125. case FLAG_VIDEO:
  126. {
  127. //视频数据
  128. if(pMgr->m_ds.bVideoOut&&
  129. pMgr->m_ds.bVideoCodec&&
  130. ((PACK_VIDEO*)buf)->session==pMgr->m_session)
  131. {
  132. pMgr->OnDecodeVideoData((PACK_VIDEO*)buf,iLen);
  133. }
  134. }
  135. break;
  136. }
  137. }
  138. else
  139. {
  140. if(!pMgr->m_Socket.IsSocket())
  141. break;
  142. }//the socket should be closed,that is m_Socket have been
  143. //destroyed,so break the loop and end the thread
  144. }
  145. return 0;
  146. }
  147. /*------------------------------------------------------------------------------*/
  148. CAVIOMgr::CAVIOMgr()
  149. {
  150. pMgrInst=this;
  151. m_hSockThread=NULL;
  152. m_hAudioOut=0;
  153. m_hAudioIn=0;
  154. m_idCmd=0;
  155. m_bEnable=TRUE;
  156. m_bEnableBandAdjust=TRUE;
  157. }
  158. /*------------------------------------------------------------------------------*/
  159. CAVIOMgr::~CAVIOMgr()
  160. {
  161. Destroy();
  162. pMgrInst=0;
  163. }
  164. /*------------------------------------------------------------------------------*/
  165. //初始化SOCKET,指定PORT
  166. BOOL CAVIOMgr::InitSocket(UINT nPort)
  167. {
  168. DestroySocket();
  169. BOOL bRet=FALSE;
  170. if(!m_Socket.Create(nPort))
  171. goto RET;
  172. //创建socket线程(socket为block方式)
  173. m_hSockThread=CreateThread(0,0,SockThreadProc,(LPVOID)this,0,&m_dwSockThreadId);
  174. if(!m_hSockThread)
  175. goto RET;
  176. bRet=TRUE;
  177. RET:
  178. if(!bRet)
  179. DestroySocket();
  180. return bRet;
  181. }
  182. /*------------------------------------------------------------------------------*/
  183. BOOL CAVIOMgr::DestroySocket()
  184. {
  185. m_Socket.Destroy();
  186. //
  187. if(m_hSockThread)
  188. {
  189. BOOL b=FALSE;
  190. DWORD ExitCode;
  191. int Timeout = 50; 
  192. while(Timeout)//等待线程结束,如果到一定时间还没结束,就强制结束
  193. {  //因为Socket已经destroy了,所以socket线程会返回
  194. GetExitCodeThread(m_hSockThread, &ExitCode);
  195. if (ExitCode != STILL_ACTIVE)
  196. {
  197. b=TRUE;
  198. // Thread has ended.
  199. break;
  200. }
  201. else
  202. {
  203. Sleep(10);
  204. }
  205. --Timeout;
  206. }
  207. if(!b)//time out ,terminate it
  208. TerminateThread(m_hSockThread,0);
  209. }
  210. m_hSockThread=NULL;
  211. return TRUE;
  212. }
  213. /*------------------------------------------------------------------------------*/
  214. //设定目标
  215. void CAVIOMgr::SetDst(char *ip, unsigned short port)
  216. {
  217. m_dst.sin_family=AF_INET;
  218. //将计算机名或IP转化为网络地址
  219. m_dst.sin_addr.s_addr=CUDPSocket::Name2Inet(ip);
  220. m_dst.sin_port=htons(port);
  221. }
  222. /*------------------------------------------------------------------------------*/
  223. //初始化音频输入,当初始化完成,录音就开始了
  224. BOOL CAVIOMgr::InitAudioRec()
  225. {
  226. DestroyAudioRec();
  227. BOOL bRet=FALSE;
  228. //创建录音线程
  229. m_hAudioIn=CreateThread(0,0,AudioInThreadProc,this,0,&m_dwAudioInId);
  230. if(!m_hAudioIn)
  231. goto RET;
  232. if(!m_AudioRec.Create(0,m_dwAudioInId,(DWORD)this,CALLBACK_THREAD,SIZE_AUDIO_FRAME))
  233. goto RET;
  234. //开始录音
  235. if(!m_AudioRec.Start())
  236. goto RET;
  237. bRet=TRUE;
  238. RET:
  239. if(!bRet)
  240. {
  241. //如果失败,就向主窗口发送出错消息
  242. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_AUDIO_IN),(LPARAM)this);
  243. DestroyAudioRec();
  244. }
  245. return bRet;
  246. }
  247. /*------------------------------------------------------------------------------*/
  248. //该死的waveIn函数,结束录音时老是出现死锁(XP下还是会出现这个问题,也不知道怎么解决,苦啊)
  249. BOOL CAVIOMgr::DestroyAudioRec()
  250. {
  251. m_AudioRec.Stop();
  252.     m_AudioRec.Destroy();
  253. if(m_hAudioIn)
  254. {
  255. int t=50;
  256. DWORD ExitCode;
  257. BOOL bEnd=FALSE;
  258. //向录音线程发送退出消息,并等待线程结束
  259. PostThreadMessage(m_dwAudioInId,WM_QUIT,0,0);
  260. while(t)
  261. {
  262. GetExitCodeThread(m_hAudioIn,&ExitCode);
  263. if(ExitCode!= STILL_ACTIVE)
  264. {
  265. bEnd=TRUE;
  266. break;
  267. }
  268. else
  269. Sleep(10);
  270. t--;
  271. }
  272. if(!bEnd)
  273. TerminateThread(m_hAudioIn,0);
  274. m_hAudioIn=0;
  275. }
  276. return TRUE;
  277. }
  278. /*------------------------------------------------------------------------------*/
  279. //初始化播放设备
  280. BOOL CAVIOMgr::InitAudioPlay()
  281. {
  282. BOOL bRet=FALSE;
  283. DestroyAudioPlay();
  284. m_iAudioBuf=0;
  285. m_hAudioOut=CreateThread(0,0,AudioOutThreadProc,this,0,&m_dwAudioOutId);
  286. if(!m_hAudioOut)
  287. goto RET;
  288. if(!m_AudioPlay.Create(0,m_dwAudioOutId,(DWORD)this,CALLBACK_THREAD))
  289. goto RET;
  290. bRet=TRUE;
  291. RET:
  292. if(!bRet)
  293. {
  294. //向主窗口发送出错消息
  295. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_AUDIO_OUT),(LPARAM)this);
  296. DestroyAudioPlay();
  297. }
  298. return bRet;
  299. }
  300. /*------------------------------------------------------------------------------*/
  301. //
  302. BOOL CAVIOMgr::DestroyAudioPlay()
  303. {
  304. m_AudioPlay.Destroy();
  305. if(m_hAudioOut)
  306. {
  307. int t=50;
  308. DWORD ExitCode;
  309. BOOL bEnd=FALSE;
  310. PostThreadMessage(m_dwAudioOutId,WM_QUIT,0,0);
  311. while(t)
  312. {
  313. GetExitCodeThread(m_hAudioOut,&ExitCode);
  314. if(ExitCode!= STILL_ACTIVE)
  315. {
  316. bEnd=TRUE;
  317. break;
  318. }
  319. else
  320. Sleep(10);
  321. t--;
  322. }
  323. if(!bEnd)
  324. TerminateThread(m_hAudioOut,0);
  325. m_hAudioOut=0;
  326. }
  327. return TRUE;
  328. }
  329. /*------------------------------------------------------------------------------*/
  330. //音频解码,并将音频数据发送到想要数据的窗口
  331. void CAVIOMgr::OnDecodeAudioData(PACK_AUDIO *ppa, int len)
  332. {
  333. if(m_CodecMgr.DecodeAudioData((char*)ppa->data,SIZE_AUDIO_PACKED,m_AudioRemote,0))
  334. {
  335. //为了避免延迟过长,当累积的缓冲超过六块时抛弃即将加入的缓冲
  336. if(m_iAudioBuf<6)
  337. {
  338. m_iAudioBuf++;
  339. m_AudioPlay.Play(m_AudioRemote,SIZE_AUDIO_FRAME);
  340. }
  341. if(m_hwndRemoteAudioRcv)
  342. SendMessage(m_hwndRemoteAudioRcv,IOM_AUDIO,1,(LPARAM)this);
  343. }
  344. m_uDataRcv+=sizeof(PACK_AUDIO);
  345. delete []ppa;
  346. }
  347. /*------------------------------------------------------------------------------*/
  348. //压缩音频原始数据并发送出去
  349. void CAVIOMgr::OnEncodeAudioData(char *pa, int len)
  350. {
  351. m_AudioPack.flag=FLAG_AUDIO;
  352. m_AudioPack.session=m_session;
  353. if(m_CodecMgr.EncodeAudioData(pa,len,(char*)m_AudioPack.data,0))
  354. {
  355. m_Socket.SendTo((char*)&m_AudioPack,sizeof(PACK_AUDIO),(sockaddr*)&m_dst);
  356. m_uDataSend+=sizeof(PACK_AUDIO);
  357. }
  358. if(m_hwndLocalAudioRcv)
  359. SendMessage(m_hwndLocalAudioRcv,IOM_AUDIO,0,(LPARAM)this);
  360. }
  361. /*------------------------------------------------------------------------------*/
  362. //视频解码
  363. void CAVIOMgr::OnDecodeVideoData(PACK_VIDEO *ppv, int len)
  364. {
  365. if(m_CodecMgr.DecodeVideoData(((char*)ppv)+sizeof(PACK_VIDEO),ppv->data_size,m_VideoRemote,0,0))
  366. {
  367. m_nFrameCount++;
  368. m_nCurVid=ppv->id;
  369. //将视频数据发送到视频显示窗口
  370. if(m_hwndRemoteVideoRcv)
  371. SendMessage(m_hwndRemoteVideoRcv,IOM_VIDEO,1,(LPARAM)this);
  372. }
  373. //统计收到的数据
  374. m_uDataRcv+=sizeof(PACK_VIDEO)+ppv->data_size;
  375. }
  376. /*------------------------------------------------------------------------------*/
  377. //视频压缩并发送
  378. void CAVIOMgr::OnEncodeVideoData(char *pv, int len)
  379. {
  380. int rlen;
  381. if(m_bVideoSend)
  382. {
  383. if(m_CodecMgr.EncodeVideoData(pv,len,m_VideoPack+sizeof(PACK_VIDEO),&rlen,0))
  384. {
  385. ((PACK_VIDEO*)m_VideoPack)->data_size=(unsigned short)rlen;
  386. ((PACK_VIDEO*)m_VideoPack)->id=m_idVideo++;
  387. ((PACK_VIDEO*)m_VideoPack)->session=m_session;
  388. m_Socket.SendTo(m_VideoPack,rlen+sizeof(PACK_VIDEO),(sockaddr*)&m_dst);
  389. //统计发送的数据
  390. m_uDataSend+=rlen+sizeof(PACK_VIDEO);
  391. }
  392. }
  393. m_VideoLocal=pv;
  394. if(m_hwndLocalVideoRcv)
  395. {
  396. //将视频数据发送到视频显示窗口
  397. SendMessage(m_hwndLocalVideoRcv,IOM_VIDEO,0,(LPARAM)this);
  398. }
  399. }
  400. /*------------------------------------------------------------------------------*/
  401. //初始化,创建SOCKET,并监听
  402. BOOL CAVIOMgr::Init(UINT nPort)
  403. {
  404. Destroy();
  405. m_hwndLocalVideoRcv=0;
  406. m_hwndLocalAudioRcv=0;
  407. m_hwndRemoteVideoRcv=0;
  408. m_hwndRemoteAudioRcv=0;
  409. m_hwndMainWnd=0;
  410. m_bVideoSend=TRUE;
  411. m_iStatus=STA_FREE;
  412. BOOL bRet=FALSE;
  413. m_uDataRcv=0;
  414. m_uDataSend=0;
  415. if(!InitSocket(nPort))
  416. goto RET;
  417. //创建消息接收窗口,主要用于超时重发机制,因为要设定很多不同ID的定时器
  418. m_MsgRcvWnd.Create(0,0,0,0,CRectX(0,0,0,0),0,0);
  419. bRet=TRUE;
  420. RET:
  421. return bRet;
  422. }
  423. /*------------------------------------------------------------------------------*/
  424. //初始化视频捕捉设备
  425. BOOL CAVIOMgr::InitCap()//
  426. {
  427. HWND hCap;
  428. m_ViCap.Destroy();
  429. BOOL bRet=FALSE;
  430. if(!m_ViCap.Init())
  431. goto RET;
  432. //得到驱动数
  433. if(!m_ViCap.GetDriverNum())
  434. goto RET;
  435. //连接到驱动
  436. if(!m_ViCap.ConnectToDriver(0))
  437. goto RET;
  438. hCap=m_ViCap.GetCapWindow();
  439. //设置视频格式
  440. if(!capSetVideoFormat(hCap,&m_CodecMgr.m_BmpU,sizeof(BITMAPINFO)))
  441. goto RET;
  442. //设置视频流回调函数
  443. if(!capSetCallbackOnVideoStream(hCap,VideoStreamCallbackProc))
  444. goto RET;
  445. //将user数据设为AVIOMgr对象指针
  446. if(!capSetUserData(hCap,(DWORD)this))
  447. goto RET;
  448. //开始视频流
  449. if(!capCaptureSequenceNoFile(hCap))
  450. goto RET;
  451. bRet=TRUE;
  452. RET:
  453. if(!bRet)
  454. {
  455. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_VIDEO_IN),(LPARAM)this);
  456. m_ViCap.Destroy();
  457. }
  458. return bRet;
  459. }
  460. /*------------------------------------------------------------------------------*/
  461. BOOL CAVIOMgr::DestroyCap()
  462. {
  463. m_ViCap.Destroy();
  464. return TRUE;
  465. }
  466. /*------------------------------------------------------------------------------*/
  467. void CAVIOMgr::Destroy()
  468. {
  469. EndTalk();
  470. DestroySocket();
  471. DestroyAudioRec();
  472. DestroyCap();
  473. DestroyAudioPlay();
  474. DestroyAudioCodec();
  475. DestroyVideoCodec();
  476. }
  477. /*------------------------------------------------------------------------------*/
  478. //
  479. BOOL CAVIOMgr::InitAudioCodec()
  480. {
  481. BOOL bRet=FALSE;
  482. if(!m_CodecMgr.InitCodecA())
  483. goto RET;
  484. //启动丢包率定时器
  485. SetTimer(m_hwndMainWnd,100,1000,DropRateCounter);
  486. bRet=TRUE;
  487. RET:
  488. if(!bRet)
  489. {
  490. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_AUDIO_CODEC),(LPARAM)this);
  491. DestroyAudioCodec();
  492. }
  493. return bRet;
  494. }
  495. /*------------------------------------------------------------------------------*/
  496. //
  497. void CAVIOMgr::DestroyAudioCodec()
  498. {
  499. //关闭丢包率定时器
  500. KillTimer(m_hwndMainWnd,100);
  501. m_CodecMgr.DestroyCodecA();
  502. }
  503. /*------------------------------------------------------------------------------*/
  504. //初始化视频编码解码器
  505. BOOL CAVIOMgr::InitVideoCodec()
  506. {
  507. m_idVideo=0;
  508. m_nFps=0;
  509. m_nFrameCount=0;
  510. m_nLastFrameCount=0;
  511. m_nDropRate=0;
  512. m_nCurVid=0;
  513. m_nLastVid=0;
  514. BOOL bRet=FALSE;
  515. //
  516. if(!m_CodecMgr.InitCodecV())
  517. goto RET;
  518. ((PACK_VIDEO*)m_VideoPack)->flag=FLAG_VIDEO;
  519. bRet=TRUE;
  520. RET:
  521. if(!bRet)
  522. {
  523. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ERR,IOME_VIDEO_CODEC),(LPARAM)this);
  524. DestroyVideoCodec();
  525. }
  526. return bRet;
  527. }
  528. /*------------------------------------------------------------------------------*/
  529. void CAVIOMgr::DestroyVideoCodec()
  530. {
  531. m_CodecMgr.DestroyCodecV();
  532. }
  533. /*------------------------------------------------------------------------------*/
  534. void CAVIOMgr::GetDeviceSupport(DEVICE_SUPPORT &ds)
  535. {
  536. }
  537. /*------------------------------------------------------------------------------*/
  538. //呼叫某个IP
  539. BOOL CAVIOMgr::Call(char *ip, unsigned short port)
  540. {
  541. BOOL bRet=FALSE;
  542. if(m_iStatus!=STA_FREE)
  543. goto RET;
  544. SetDst(ip,port);
  545. PACK_CMD pc;
  546. m_session=rand()&0xff;
  547. pc.flag=FLAG_CMD;
  548. pc.cmd=CMD_CALL;
  549. pc.type=0;
  550. pc.data_size_extra=0;
  551. pc.ext=VER_AVIO&0xff;//AVIO 的版本
  552. if(!SendCmd(&pc,sizeof(pc),m_dst,TRUE))
  553. goto RET;
  554. m_iStatus=STA_BUSY;
  555. bRet=TRUE;
  556. m_uDataSend=0;
  557. m_uDataRcv=0;
  558. RET:
  559. return bRet;
  560. }
  561. /*------------------------------------------------------------------------------*/
  562. //结束通话
  563. BOOL CAVIOMgr::EndTalk()
  564. {
  565. BOOL bRet=FALSE;
  566. if(m_iStatus==STA_FREE)
  567. goto RET;
  568. if(m_iStatus==STA_BUSY)
  569. {
  570. m_iStatus=STA_FREE;
  571. PACK_CMD pc;
  572. pc.flag=FLAG_CMD;
  573. pc.cmd=CMD_END;
  574. pc.data_size_extra=0;
  575. pc.type=0;
  576. SendCmd(&pc,sizeof(pc),m_dst,FALSE);
  577. ZeroMemory(&m_dst,sizeof(m_dst));
  578. DestroyVideoCodec();
  579. DestroyAudioCodec();
  580. DestroyAudioPlay();
  581. DestroyAudioRec();
  582. DestroyCap();
  583. }
  584. bRet=TRUE;
  585. RET:
  586. return bRet;
  587. }
  588. /*------------------------------------------------------------------------------*/
  589. //接受请求
  590. BOOL CAVIOMgr::Accept()
  591. {
  592. BOOL bRet=FALSE;
  593. if(m_iStatus!=STA_BUSY)
  594. goto RET;
  595. PACK_CMD pc;
  596. pc.flag=FLAG_CMD;
  597. pc.cmd=CMD_ACCEPT;
  598. pc.data_size_extra=0;
  599. pc.type=0;
  600. SendCmd(&pc,sizeof(pc),m_dst,TRUE);
  601. ZeroMemory(&m_ds,sizeof(m_ds));
  602. m_ds.bVideoOut=true;//always ok
  603. if(InitVideoCodec())//why this must ahead InitAudioCodec??i don't know why
  604. m_ds.bVideoCodec=true;
  605. if(InitAudioCodec())
  606. m_ds.bAudioCodec=true;
  607. if(InitAudioPlay())
  608. m_ds.bAudioOut=true;
  609. if(InitAudioRec())
  610. m_ds.bAudioIn=true;
  611. if(m_ds.bVideoCodec&&InitCap())
  612. m_ds.bVideoIn=true;
  613. if(!m_ds.bAudioCodec&&!m_ds.bVideoCodec)
  614. {
  615. DestroyCap();
  616. DestroyAudioRec();
  617. DestroyAudioPlay();
  618. DestroyAudioCodec();
  619. DestroyVideoCodec();
  620. m_iStatus=STA_FREE;
  621. }
  622. bRet=TRUE;
  623. RET:
  624. return bRet;
  625. }
  626. /*------------------------------------------------------------------------------*/
  627. //拒绝请求
  628. BOOL CAVIOMgr::Refuse()
  629. {
  630. BOOL bRet=FALSE;
  631. if(m_iStatus!=STA_BUSY)
  632. goto RET;
  633. PACK_CMD pc;
  634. pc.flag=FLAG_CMD;
  635. pc.cmd=CMD_REFUSE;
  636. pc.ext=R_USER;
  637. pc.data_size_extra=0;
  638. pc.type=0;
  639. m_iStatus=STA_FREE;
  640. SendCmd(&pc,sizeof(pc),m_dst,TRUE);
  641. bRet=TRUE;
  642. RET:
  643. return bRet;
  644. }
  645. /*------------------------------------------------------------------------------*/
  646. //解释发送来的命令
  647. void CAVIOMgr::OnCommand(PACK_CMD *ppc, int len)
  648. {
  649. switch(ppc->cmd)
  650. {
  651. case CMD_CALL:
  652. {
  653. if(ppc->type==0)
  654. {
  655. if(m_bEnable)
  656. {
  657. //如果是空闲的,就保存地址,设置状态为工作状态
  658. //并向主窗口发送呼叫通知
  659. if(m_iStatus==STA_FREE)
  660. {
  661. m_dst=m_sockaddr;
  662. m_iStatus=STA_BUSY;
  663. m_session=ppc->session;
  664. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_CALL,VER_AVIO),(LPARAM)this);
  665. //返回请求确认
  666. PACK_CMD pc;
  667. pc.flag=FLAG_CMD;
  668. pc.data_size_extra=0;
  669. pc.cmd=CMD_CALL;
  670. pc.ext=VER_AVIO&0xff;// AVIO的版本
  671. pc.type=1;
  672. pc.id=ppc->id;
  673. pc.session=m_session;
  674. m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);
  675. }
  676. else
  677. if(m_iStatus==STA_BUSY&&m_session!=ppc->session)
  678. {
  679. /*//有另一台机请求通话,拒绝!
  680. PACK_CMD pc;
  681. pc.flag=FLAG_CMD;
  682. pc.cmd=CMD_REFUSE;
  683. pc.data_size_extra=0;
  684. pc.ext=R_BUSY;
  685. pc.type=0;
  686. pc.id=ppc->id;
  687. pc.session=ppc->session;
  688. m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);*/
  689. }
  690. }
  691. }
  692. //回应
  693. else
  694. {
  695. if(ppc->session==m_session)
  696. {
  697. KillTimer(m_MsgRcvWnd,ppc->id);
  698. m_CmdQueue.Remove(ppc->id);
  699. PostMessage(m_hwndMainWnd,IOM_NOTIFY,IOMN_CONNECTED,(LPARAM)this);
  700. }
  701. }
  702. }break;
  703. case CMD_END:
  704. {
  705. if(ppc->session==m_session)
  706. {
  707. if(ppc->type==0)
  708. {
  709. if(m_iStatus==STA_BUSY)
  710. {
  711. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_END,E_USER),(LPARAM)this);
  712. }
  713. PACK_CMD pc;
  714. pc.flag=FLAG_CMD;
  715. pc.data_size_extra=0;
  716. pc.cmd=CMD_END;
  717. pc.type=1;
  718. pc.id=ppc->id;
  719. pc.session=m_session;
  720. m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);
  721. }
  722. else
  723. {
  724. KillTimer(m_MsgRcvWnd,ppc->id);
  725. m_CmdQueue.Remove(ppc->id);
  726. }
  727. }
  728. }
  729. break;
  730. case CMD_REFUSE:
  731. {
  732. if(ppc->session==m_session)
  733. {
  734. if(ppc->type==0)
  735. {
  736. if(m_iStatus==STA_BUSY)
  737. {
  738. m_iStatus=STA_FREE;
  739. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_REFUSE,ppc->ext),(LPARAM)this);
  740. }
  741. PACK_CMD pc;
  742. pc.flag=FLAG_CMD;
  743. pc.data_size_extra=0;
  744. pc.cmd=CMD_REFUSE;
  745. pc.type=1;
  746. pc.id=ppc->id;
  747. pc.session=m_session;
  748. m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);
  749. }
  750. else
  751. {
  752. KillTimer(m_MsgRcvWnd,ppc->id);
  753. m_CmdQueue.Remove(ppc->id);
  754. }
  755. }
  756. }
  757. break;
  758. case CMD_ACCEPT:
  759. {
  760. if(ppc->session==m_session)
  761. {
  762. if(ppc->type==0)
  763. {
  764. if(m_iStatus==STA_BUSY)
  765. {
  766. PostMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_ACCEPT,VER_AVIO),(LPARAM)this);
  767. }
  768. PACK_CMD pc;
  769. pc.flag=FLAG_CMD;
  770. pc.data_size_extra=0;
  771. pc.cmd=CMD_ACCEPT;
  772. pc.type=1;
  773. pc.id=ppc->id;
  774. pc.session=m_session;
  775. m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);
  776. }
  777. else
  778. {
  779. KillTimer(m_MsgRcvWnd,ppc->id);
  780. m_CmdQueue.Remove(ppc->id);
  781. }
  782. }
  783. }
  784. break;
  785. case CMD_TXT:
  786. {
  787. if(ppc->type==0)
  788. {
  789. //bug exist
  790. SendMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_TXT,0),(LPARAM)(((char*)ppc)+sizeof(PACK_CMD)));
  791. PACK_CMD pc;
  792. pc.flag=FLAG_CMD;
  793. pc.data_size_extra=0;
  794. pc.cmd=CMD_TXT;
  795. pc.type=1;
  796. pc.id=ppc->id;
  797. m_Socket.SendTo((char*)&pc,sizeof(pc),(sockaddr*)&m_sockaddr);
  798. }
  799. else
  800. {
  801. KillTimer(m_MsgRcvWnd,ppc->id);
  802. UINT len;char resend;sockaddr_in addr;
  803. char* p=m_CmdQueue.GetBuf(ppc->id,len,resend,addr);
  804. if(p)
  805. {
  806. SendMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_TXT,1),(LPARAM)(p+sizeof(PACK_CMD)));
  807. }
  808. m_CmdQueue.Remove(ppc->id);
  809. }
  810. }
  811. break;
  812. case CMD_DROPRATE:
  813. {
  814. //根据丢包率来调整视频质量
  815. if(ppc->type==0&&ppc->session&&m_bEnableBandAdjust)
  816. {
  817. SetVideoQuality(100-ppc->ext);
  818. SendMessage(m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_VQSET,100-ppc->ext),(LPARAM)this);
  819. }
  820. }break;
  821. }
  822. }
  823. /*------------------------------------------------------------------------------*/
  824. //以下是设置对外消息接口
  825. //设置主窗口
  826. void CAVIOMgr::SetMainWnd(HWND hwnd)
  827. {
  828. m_hwndMainWnd=hwnd;
  829. }
  830. void CAVIOMgr::SetLocalVideoRcvWnd(HWND hwnd)
  831. {
  832. m_hwndLocalVideoRcv=hwnd;
  833. }
  834. void CAVIOMgr::SetLocalAudioRcvWnd(HWND hwnd)
  835. {
  836. m_hwndLocalAudioRcv=hwnd;
  837. }
  838. void CAVIOMgr::SetRemoteVideoRcvWnd(HWND hwnd)
  839. {
  840. m_hwndRemoteVideoRcv=hwnd;
  841. }
  842. void CAVIOMgr::SetRemoteAudioRcvWnd(HWND hwnd)
  843. {
  844. m_hwndRemoteAudioRcv=hwnd;
  845. }
  846. /*------------------------------------------------------------------------------*/
  847. //得到当前状态
  848. int CAVIOMgr::GetStatus()
  849. {
  850. return m_iStatus;
  851. }
  852. /*------------------------------------------------------------------------------*/
  853. //调用以下函数要谨慎
  854. //只有在收到相应消息时才能调用
  855. /////////////////////////
  856. ///
  857. char* CAVIOMgr::GetLocalVideo(UINT &len)
  858. {
  859. len=m_CodecMgr.m_BmpU.bmiHeader.biSizeImage;
  860. return m_VideoLocal;
  861. }
  862. char* CAVIOMgr::GetLocalAudio(UINT &len)
  863. {
  864. len=SIZE_AUDIO_FRAME;
  865. return m_AudioLocal;
  866. }
  867. char* CAVIOMgr::GetRemoteVideo(UINT &len)
  868. {
  869. len=m_CodecMgr.m_BmpU.bmiHeader.biSizeImage;
  870. return m_VideoRemote;
  871. }
  872. char* CAVIOMgr::GetRemoteAudio(UINT &len)
  873. {
  874. len=SIZE_AUDIO_FRAME;
  875. return m_AudioRemote;
  876. }
  877. /*------------------------------------------------------------------------------*/
  878. //得到原始视频格式
  879. BITMAPINFO* CAVIOMgr::GetBitampInfo()
  880. {
  881. return &m_CodecMgr.m_BmpU;
  882. }
  883. /*------------------------------------------------------------------------------*/
  884. //得到数据发送量
  885. UINT CAVIOMgr::GetDataSend()
  886. {
  887. return m_uDataSend;
  888. }
  889. /*------------------------------------------------------------------------------*/
  890. //得到数据接收量
  891. UINT CAVIOMgr::GetDataRcv()
  892. {
  893. return m_uDataRcv;
  894. }
  895. /*------------------------------------------------------------------------------*/
  896. //设置是否传输视频
  897. void CAVIOMgr::VideoSend(BOOL b)
  898. {
  899. m_bVideoSend=b;
  900. }
  901. /*------------------------------------------------------------------------------*/
  902. //得到对方地址
  903. sockaddr_in CAVIOMgr::GetRemoteAddr()
  904. {
  905. return m_dst;
  906. }
  907. /*------------------------------------------------------------------------------*/
  908. //设置视频质量
  909. void CAVIOMgr::SetVideoQuality(UINT q)
  910. {
  911. m_CodecMgr.m_cv.lQ=q*100;
  912. }
  913. /*------------------------------------------------------------------------------*/
  914. //预览
  915. BOOL CAVIOMgr::EnablePreview(BOOL b)
  916. {
  917. if(m_iStatus==STA_FREE&&b)
  918. {
  919. return InitCap();
  920. }
  921. else
  922. if(m_iStatus==STA_FREE&&!b)
  923. {
  924. DestroyCap();
  925. }
  926. return TRUE;
  927. }
  928. /*------------------------------------------------------------------------------*/
  929. //当对方接收请求后,会受到Accept的消息,这时必须调用此函数,来打开各种设备
  930. void CAVIOMgr::OnAccept()
  931. {
  932. if(m_iStatus==STA_FREE) return;
  933. ZeroMemory(&m_ds,sizeof(m_ds));
  934. m_ds.bVideoOut=true;//always ok
  935. if(InitVideoCodec())
  936. m_ds.bVideoCodec=true;
  937. if(InitAudioCodec())
  938. m_ds.bAudioCodec=true;
  939. if(InitAudioPlay())
  940. m_ds.bAudioOut=true;
  941. if(InitAudioRec())
  942. m_ds.bAudioIn=true;
  943. if(m_ds.bVideoCodec&&InitCap())
  944. m_ds.bVideoIn=true;
  945. if(!m_ds.bAudioCodec&&!m_ds.bVideoCodec)
  946. {
  947. DestroyCap();
  948. DestroyAudioRec();
  949. DestroyAudioPlay();
  950. DestroyAudioCodec();
  951. DestroyVideoCodec();
  952. m_iStatus=STA_FREE;
  953. }
  954. }
  955. /*------------------------------------------------------------------------------*/
  956. //得到帧数
  957. UINT CAVIOMgr::GetFrameCount()
  958. {
  959. return m_nFrameCount;
  960. }
  961. /*------------------------------------------------------------------------------*/
  962. //发送命令(比较可靠)
  963. BOOL CAVIOMgr::SendCmd(PACK_CMD *pCmd, UINT nLen,sockaddr_in &addr, BOOL bFlag)
  964. {
  965. if(!pCmd) return FALSE;
  966. pCmd->id=m_idCmd++;
  967. pCmd->session=m_session;
  968. int l=m_Socket.SendTo((char*)pCmd,nLen,(sockaddr*)&addr);
  969. if(l>0)
  970. {
  971. if(bFlag)
  972. {
  973. m_CmdQueue.Add(pCmd->id,(char*)pCmd,nLen,addr);//把命令加入命令表
  974. SetTimer(m_MsgRcvWnd,pCmd->id,800,CmdTimeOutProc);
  975. }
  976. return TRUE;
  977. }
  978. else
  979. return FALSE;
  980. }
  981. /*------------------------------------------------------------------------------*/
  982. //命令超时重发
  983. void CALLBACK CAVIOMgr::CmdTimeOutProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
  984. {
  985. if(pMgrInst)
  986. {
  987. UINT len;char resend;sockaddr_in addr;
  988. char* p=pMgrInst->m_CmdQueue.GetBuf(idEvent,len,resend,addr);//找出相应ID的命令(已经超时,需要重发)
  989. if(p)
  990. {
  991. if(resend<5)
  992. pMgrInst->m_Socket.SendTo(p,len,(sockaddr*)&addr);
  993. else//当重发次数超过4次时,宣布失败
  994. {
  995. KillTimer(hwnd,idEvent);//
  996. if(pMgrInst)
  997. {
  998. PACK_CMD* pCmd=(PACK_CMD*)p;
  999. switch(pCmd->cmd)
  1000. {
  1001. case CMD_CALL:
  1002. {
  1003. PostMessage(pMgrInst->m_hwndMainWnd,IOM_NOTIFY,MAKEWPARAM(IOMN_REFUSE,R_TIMEOUT),(LPARAM)pMgrInst);
  1004. pMgrInst->m_iStatus=STA_FREE;
  1005. }
  1006. break;
  1007. case CMD_REFUSE:
  1008. break;
  1009. case CMD_ACCEPT:
  1010. break;
  1011. case CMD_END:
  1012. break;
  1013. case CMD_TXT:
  1014. break;
  1015. }
  1016. }
  1017. pMgrInst->m_CmdQueue.Remove(idEvent);//把命令从表中移除
  1018. }
  1019. }
  1020. else
  1021. KillTimer(hwnd,idEvent);
  1022. }
  1023. }
  1024. /*------------------------------------------------------------------------------*/
  1025. //丢包率计算(包括帧频率计算)
  1026. void CALLBACK CAVIOMgr::DropRateCounter(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
  1027. {
  1028. //计算丢包率
  1029. if(pMgrInst)
  1030. {
  1031. UINT delt;
  1032. if(pMgrInst->m_nCurVid<pMgrInst->m_nLastVid)
  1033. delt=pMgrInst->m_nCurVid+256-pMgrInst->m_nLastVid;
  1034. else
  1035. delt=pMgrInst->m_nCurVid-pMgrInst->m_nLastVid;
  1036. if(delt>0)
  1037. pMgrInst->m_nDropRate=100-(pMgrInst->m_nFrameCount-pMgrInst->m_nLastFrameCount)*100/delt;
  1038. pMgrInst->m_nLastVid=pMgrInst->m_nCurVid;
  1039. //发送丢包率
  1040. PACK_CMD pc;
  1041. pc.flag=FLAG_CMD;
  1042. pc.cmd=CMD_DROPRATE;
  1043. pc.session=pMgrInst->m_session;
  1044. pc.type=0;
  1045. pc.data_size_extra=0;
  1046. pc.ext=pMgrInst->m_nDropRate;
  1047. pMgrInst->m_Socket.SendTo((char*)&pc,sizeof(PACK_CMD),(SOCKADDR*)&pMgrInst->m_dst);
  1048. //计算帧频率
  1049. pMgrInst->m_nFps=(pMgrInst->m_nFrameCount-pMgrInst->m_nLastFrameCount);
  1050. pMgrInst->m_nLastFrameCount=pMgrInst->m_nFrameCount;
  1051. }
  1052. }
  1053. /*------------------------------------------------------------------------------*/
  1054. UINT CAVIOMgr::GetFps()
  1055. {
  1056. return m_nFps;
  1057. }
  1058. /*------------------------------------------------------------------------------*/
  1059. //发送文本信息
  1060. BOOL CAVIOMgr::SendTxt(char *ip, unsigned short port, char *txt)
  1061. {
  1062. BOOL bRet=FALSE;
  1063. PACK_CMD *ppc=(PACK_CMD*)new char[sizeof(PACK_CMD)+strlen(txt)+1];
  1064. strcpy(((char*)ppc)+sizeof(PACK_CMD),txt);
  1065. ppc->flag=FLAG_CMD;
  1066. ppc->cmd=CMD_TXT;
  1067. ppc->type=0;
  1068. ppc->data_size_extra=strlen(txt)+1;
  1069. //将ip和port转化
  1070. sockaddr_in addr;
  1071. addr.sin_family=AF_INET;
  1072. addr.sin_addr.s_addr=CUDPSocket::Name2Inet(ip);
  1073. addr.sin_port=htons(port);
  1074. //
  1075. if(!SendCmd(ppc,sizeof(PACK_CMD)+ppc->data_size_extra,addr,TRUE))
  1076. goto RET;
  1077. bRet=TRUE;
  1078. RET:
  1079. return bRet;
  1080. }
  1081. /*------------------------------------------------------------------------------*/
  1082. //得到前一次发来数据的地址
  1083. sockaddr_in& CAVIOMgr::GetCurrentAddr()
  1084. {
  1085. return m_sockaddr;
  1086. }
  1087. /*------------------------------------------------------------------------------*/
  1088. //
  1089. BOOL CAVIOMgr::Enable(BOOL bEnable)
  1090. {
  1091. BOOL t=m_bEnable;
  1092. m_bEnable=bEnable;
  1093. return t;
  1094. }
  1095. /*------------------------------------------------------------------------------*/
  1096. //是否自动调整图象质量
  1097. BOOL CAVIOMgr::EnableBandAdjust(BOOL bEnable)
  1098. {
  1099. BOOL t=m_bEnableBandAdjust;
  1100. m_bEnableBandAdjust=bEnable;
  1101. return t;
  1102. }