netphonedlg.cpp
来自「《Visual C++视频技术方案宝典》配套光盘」· C++ 代码 · 共 471 行
CPP
471 行
// NetPhoneDlg.cpp : implementation file
//
#include "stdafx.h"
#include "NetPhone.h"
#include "NetPhoneDlg.h"
#include "mmsystem.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define BUFFERSIZE 5120 //缓冲区大小
static HWAVEIN hWaveIn ; //录音设备句柄
static HWAVEOUT hWaveOut ; //播放设备句柄
static PBYTE pBufferIn[2]; //用于接收和播放的两块缓冲区
static PBYTE pBufferOut[2]; //用于发送和录音的两块缓冲区
static PWAVEHDR pWHIn[2]; //用于录音的PWAVEHDR结构数组
static PWAVEHDR pWHOut[2]; //用于播放的PWAVEHDR结构数组
static WAVEFORMATEX waveform ; //用于打开音频设备的WAVEFORMATEX结构
int nIn = 0; //当前播放缓冲区号
int nOut = 0; //当前录音缓冲区号
int nComState = 1; //显示通话状态信息的变量
CString LocalIP; //本机IP地址
CString RemoteIP; //远端主机IP地址
CServerAS sServer; //服务器套接字
CClientAS sClient; //客户端套接字
CServerAS sListen; //监听套接字
BOOL ConnectDown = FALSE; //“连接”按钮是否被按下
BOOL sState = FALSE; //是否处于服务器端状态
BOOL cState = FALSE; //是否处于客户端状态
CNetPhoneDlg* pDlg;
extern CNetPhoneApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNetPhoneDlg dialog
CNetPhoneDlg::CNetPhoneDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNetPhoneDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CNetPhoneDlg)
m_edit = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_frAudio = TRUE;
}
void CNetPhoneDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNetPhoneDlg)
DDX_Text(pDX, IDC_EDIT1, m_edit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CNetPhoneDlg, CDialog)
//{{AFX_MSG_MAP(CNetPhoneDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTCONNECT, OnButconnect)
ON_BN_CLICKED(IDC_BUTCOMMUNICATE, OnButcommunicate)
ON_MESSAGE(MM_WOM_OPEN,OnOpen)
ON_MESSAGE(MM_WIM_DATA,OnData)
ON_MESSAGE(MM_WIM_CLOSE,OnClose)
ON_BN_CLICKED(IDC_BUTEXIT, OnButexit)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNetPhoneDlg message handlers
BOOL CNetPhoneDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
pDlg=(CNetPhoneDlg *)theApp.m_pMainWnd; // 得到对话框句柄
DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
char Buffer[MAX_COMPUTERNAME_LENGTH + 1];
GetComputerName(Buffer,&nSize);
CString str="",name;
struct hostent * pHost;
pHost = gethostbyname(Buffer);
for(int i=0;i<4;i++)
{
CString addr;
if(i > 0)
{
str += ".";
}
addr.Format("%u",(unsigned int)((unsigned char*)pHost->h_addr_list[0])[i]);
str += addr;
}
LocalIP = str;
//创建侦听套接字
sListen.Create(50);
//绑定侦听套接字到本地IP
sListen.Bind(50,LocalIP);
//开始侦听
sListen.Listen();
//创建客户端套接字
sClient.Create(51);
GetDlgItem(IDC_BUTCOMMUNICATE)->EnableWindow(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
void CNetPhoneDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CNetPhoneDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CNetPhoneDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CNetPhoneDlg::AcceptConnect()
{
if(!ConnectDown)
{
UINT Port;
//得到呼叫端IP地址及端口
sServer.GetPeerName(RemoteIP,Port);
//设置各个按钮状态
pDlg->GetDlgItem(IDC_BUTCOMMUNICATE)->EnableWindow(TRUE);
m_edit = RemoteIP+":呼叫您";
UpdateData(FALSE);
}
}
BOOL CNetPhoneDlg::InitAudioDevice()
{
//初始化waveform
waveform.wFormatTag = WAVE_FORMAT_PCM; //采样方式,PCM(脉冲编码调制)
waveform.nChannels = 2; //双声道
waveform.nSamplesPerSec = 11025; //采样率
waveform.nAvgBytesPerSec = 11025; //数据率
waveform.nBlockAlign = 2; //最小块单元
waveform.wBitsPerSample = 8; //样本大小为8bit
waveform.cbSize = 0; //附加格式信息
//准备pWHIn和pWHOut
for(int i=0;i<=1;i++)
{
//为缓冲区分配内存
pBufferIn[i] = (PBYTE)malloc(BUFFERSIZE);
pBufferOut[i] = (PBYTE)malloc(BUFFERSIZE);
if(!pBufferIn[i] || !pBufferOut[i])
{
if(pBufferIn[i])
free(pBufferIn[i]);
if(pBufferOut[i])
free(pBufferIn[i]);
AfxMessageBox(_T("内存分配失败!"),MB_ICONINFORMATION|MB_OK,NULL);
}
pWHIn[i] = new WAVEHDR;
pWHOut[i] = new WAVEHDR;
pWHOut[i]->lpData = (char *)pBufferIn[i];
pWHOut[i]->dwBufferLength = BUFFERSIZE;
pWHOut[i]->dwBytesRecorded = 0;
pWHOut[i]->dwUser = 0;
pWHOut[i]->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
pWHOut[i]->dwLoops = 1;
pWHOut[i]->lpNext = NULL;
pWHOut[i]->reserved = 0;
pWHIn[i]->lpData = (char *)pBufferOut[i];
pWHIn[i]->dwBufferLength = BUFFERSIZE;
pWHIn[i]->dwBytesRecorded = 0;
pWHIn[i]->dwUser = 0;
pWHIn[i]->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
pWHIn[i]->dwLoops = 1;
pWHIn[i]->lpNext = NULL;
pWHIn[i]->reserved = 0;
}
//打开播放波形音频设备
MMRESULT result;
result = waveOutOpen(&hWaveOut,WAVE_MAPPER,&waveform,
(DWORD)pDlg->m_hWnd,0,CALLBACK_WINDOW);
//打开录制波形音频设备
if(result == MMSYSERR_NOERROR)
result = waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,
(DWORD)pDlg->m_hWnd,0,CALLBACK_WINDOW);
//为播放和录音准备
for(int j=0;j<=1;j++)
{
if(result == MMSYSERR_NOERROR)
result = waveOutPrepareHeader(hWaveOut,pWHOut[j],sizeof(WAVEHDR));
if(result == MMSYSERR_NOERROR)
result = waveInPrepareHeader(hWaveIn,pWHIn[j],sizeof(WAVEHDR));
}
//设置音量
if(result == MMSYSERR_NOERROR)
result = waveOutSetVolume(hWaveOut,65535);
if(result == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
AfxMessageBox(_T("打开音频设备时发生错误!"),MB_ICONINFORMATION | MB_OK,NULL);
return FALSE;
}
}
void CNetPhoneDlg::RecordBegin()
{
//准备录音缓冲区
waveInAddBuffer(hWaveIn,pWHIn[nOut],sizeof(WAVEHDR));
//开始录音
waveInStart(hWaveIn);
}
void CNetPhoneDlg::OnOpen()
{
//接收对方发送过来的音频数据
sServer.Receive((void *)pBufferIn[nIn],BUFFERSIZE);
//播放接收缓冲区中音频数据
waveOutWrite(hWaveOut,pWHOut[nIn],sizeof(WAVEHDR));
nIn = 1 - nIn;
//显示通话状态
if (nComState == 1)
{
SetDlgItemText(IDC_TEXT,"通话状态:");
m_edit = "通话中";
}
else
{
SetDlgItemText(IDC_TEXT,"通话状态:");
m_edit = "";
}
UpdateData(FALSE);
nComState++;
if(nComState == 10)
nComState = 1;
}
void CNetPhoneDlg::OnData()
{
//发送缓冲区中录制的音频数据
sClient.Send(pBufferOut[nOut],BUFFERSIZE);
//缓冲区循环
nOut = 1 - nOut;
RecordBegin(); //开始下一轮录音
}
void CNetPhoneDlg::OnClose()
{
waveInUnprepareHeader(hWaveIn,pWHIn[0],sizeof(WAVEHDR));
waveInUnprepareHeader(hWaveIn,pWHIn[1],sizeof(WAVEHDR));
waveInClose (hWaveIn);
hWaveIn=NULL;
}
void CNetPhoneDlg::OnButconnect()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
//连接按钮被按下
ConnectDown = TRUE;
cState = TRUE;
//连接被呼叫主机,端口50
sClient.Connect(m_edit,50);
GetDlgItem(IDC_BUTCONNECT)->EnableWindow(FALSE);
}
void CNetPhoneDlg::OnReceive()
{
//判断电话是否被接听
if(ConnectDown == TRUE && cState == TRUE && sState == FALSE)
{
//接收信息
int i;
i = sServer.Receive(cAck,5);
cAck[i] = '\0';
sAck.Format("%s",cAck);
if(sAck == "AGREE")
{
sState = TRUE;
m_edit = "对方已接听电话";
::SendMessage(pDlg->m_hWnd,WM_COMMAND,IDC_BUTCOMMUNICATE,0);
}
else
{
sState = FALSE;
}
UpdateData(FALSE);
}
//如果用户同时处于通话状态,播放接收到的音频数据
if(cState == TRUE && sState == TRUE)
{
OnOpen();
}
}
void CNetPhoneDlg::OnButcommunicate()
{
// TODO: Add your control notification handler code here
GetDlgItem(IDC_BUTCOMMUNICATE)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTCONNECT)->EnableWindow(FALSE);
//程序运行后,只初始化一次音频设备
if(m_frAudio==TRUE)
{
if(InitAudioDevice())
m_frAudio=FALSE;
else
{
AfxMessageBox(_T("初始化音频设备失败!"),MB_ICONINFORMATION | MB_OK,NULL);
return;
}
}
//“通话”按钮按下之前,程序不处于客户端状态
if(cState==FALSE)
{
//连接呼叫主机,端口50
sClient.Connect(RemoteIP,50);
Sleep(100);
//发送“AGREE”给呼叫主机,表示同意通话
sClient.Send("AGREE",5);
m_edit = RemoteIP;
UpdateData(FALSE);
cState = TRUE;
sState = TRUE;
//开始录音
RecordBegin();
}
else
{
RecordBegin();
}
}
void CNetPhoneDlg::OnButexit()
{
// TODO: Add your control notification handler code here
//关闭套接字
sServer.Close();
sListen.Close();
sClient.Close();
//释放缓冲区内存
for(int i=0;i<=1;i++)
{
delete pWHIn[i];
delete pWHOut[i];
free(pBufferIn[i]);
free(pBufferOut[i]);
waveInUnprepareHeader(hWaveIn,pWHIn[i],sizeof(WAVEHDR));
waveOutUnprepareHeader(hWaveOut,pWHOut[i],sizeof(WAVEHDR));
}
//关闭音频设备
waveInClose(hWaveIn);
waveOutClose(hWaveOut);
CDialog::OnCancel();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?