WEB开发网
开发学院软件开发VC 实时语音通信的实现 阅读

实时语音通信的实现

 2010-08-15 20:47:46 来源:WEB开发网   
核心提示:(2)放音处理void CRecTestDlg::OnMM_WOM_DONE(UINT wParam,LONG lParam) { //释放播放完的缓冲区,并准备新的数据free(m_AudioDataOut[nAudioOut].lpdata);m_AudioDataOut[nAudioOut].lpdata = r

(2)放音处理

void CRecTestDlg::OnMM_WOM_DONE(UINT wParam,LONG lParam)
{ //释放播放完的缓冲区,并准备新的数据
  free(m_AudioDataOut[nAudioOut].lpdata);
  m_AudioDataOut[nAudioOut].lpdata = reinterpret_cast<PBYTE>(malloc(1));
  m_AudioDataOut[nAudioOut].dwLength = 0;
    nAudioOut= (nAudioOut+1)%OutBlocks;
  ((PWAVEHDR)lParam)->lpData     = (LPTSTR) m_AudioDataOut[nAudioOut].lpdata ;
  ((PWAVEHDR)lParam)->dwBufferLength = m_AudioDataOut [nAudioOut].dwLength ;
    waveOutPrepareHeader (hWaveOut,(PWAVEHDR)lParam,sizeof (WAVEHDR));
    waveOutWrite(hWaveOut,(PWAVEHDR)lParam,sizeof(WAVEHDR));
  return;
}

(三)套接字发送、接收线程

其实,经过刚才的讨论,现在这两个线程的运作很简单---只是循环地操 作nReceive和nSend指针。首先发送(接收)声音块的长度,然后发送(接收)声 音内容。注意:拿CSocket::Send(buffer,count)为例,其返回值(发送出去的字 结数)只是1到count之间的某值,所以要添加检测机制,否则将出现错误,这也 是socket编程必须注意的。本文是用一个循环,直到发送出去的字节总数等于 “块”的长度才发送第二个数据块的信息。

例外这两个线程稍加改动即可实现多人的语音会议。

UINT Audio_Listen_Thread(LPVOID lParam)
{
  CRecTestDlg *pdlg = (CRecTestDlg*)lParam;
  CSocket m_Server;
  DWORD   length;
  if(!m_Server.Create(4002))
    AfxMessageBox("Listen Socket create error"+pdlg- >GetError(GetLastError()));
  if(!m_Server.Listen())
    AfxMessageBox("m_server.Listen ERROR"+pdlg- >GetError(GetLastError()));
  CSocket recSo;
  if(! m_Server.Accept(recSo))
    AfxMessageBox("m_server.Accept() error"+pdlg- >GetError(GetLastError()));
  m_Server.Close();
  int ret ;
  while(1)
  {  //开始循环接收声音文件,首先接收文件长度
    ret = recSo.Receive(&length,sizeof(DWORD));
    if(ret== SOCKET_ERROR )
      AfxMessageBox("服务器端接收声音文件长度出错,原因 : "+pdlg->GetError(GetLastError()));
    if(ret!=sizeof(DWORD))
    {
      AfxMessageBox("接收文件头错误,将关闭该线程 ");
      recSo.Close();
      return -1;
    }//接下来开辟length长的内存空间
    pdlg->m_AudioDataOut[pdlg->nReceive].lpdata =(PBYTE) realloc (0,length);
    if (pdlg->m_AudioDataOut[pdlg->nReceive].lpdata == NULL)
    {
      AfxMessageBox("erro memory_ReceiveAudio");
      recSo.Close();
      return -1;
    }
    else//内存申请成功,可以进行循环检测接受
    {
      DWORD dwReceived = 0,dwret;
      while(length>dwReceived)
      {
        dwret = recSo.Receive((pdlg->m_AudioDataOut [pdlg->nReceive].lpdata+dwReceived),
          (length-dwReceived));
        dwReceived +=dwret;
        if(dwReceived ==length)
        {
          pdlg->m_AudioDataOut[pdlg- >nReceive].dwLength = length;
          break;
        }
      }
    }//本轮声音文件接收完毕
    pdlg->nReceive=(pdlg->nReceive+1)%OutBlocks;
  }
  recSo.Close();
  return 0;
}
UINT Audio_Send_Thread(LPVOID lParam)
{
  CRecTestDlg *pdlg = (CRecTestDlg*)lParam;
  CSocket m_Client;
  m_Client.Create();
  if( m_Client.Connect("127.0.0.1",4002))
  {
    DWORD ret, length;
    int count=0;
    while(1)//循环使用指针nSend
    {
      length =pdlg->m_AudioDataIn[pdlg- >nSend].dwLength;
      if(length !=0)
      {  //首先发送块的长度
        if(((ret = m_Client.Send(&length,sizeof (DWORD)))
           != sizeof(DWORD))||(ret==SOCKET_ERROR))
        {
          AfxMessageBox("声音文件头传输错误! "+pdlg->GetError(GetLastError()));
          pdlg->OnOK();
          break;
        }//其次发送块的内容,循环检测是否发送完毕
        DWORD dwSent = 0;//已经发送掉的字节数
        while(1)//==============================发送声音数 据开始
        {
          ret = m_Client.Send((pdlg->m_AudioDataIn [pdlg->nSend].lpdata+dwSent),
                     (length-dwSent));
          if(ret==SOCKET_ERROR)//检错
          {
            AfxMessageBox("声音文件传输错误! "+pdlg->GetError(GetLastError()));
            break;
          }
          else //发送未发送完的
          {
            dwSent += ret;
            if(dwSent ==length)//发送完毕,则释放当前 “块”
            {
              free(pdlg->m_AudioDataIn[pdlg- >nSend].lpdata);
              pdlg->m_AudioDataIn[pdlg- >nSend].dwLength = 0;
              break;
            }
          }
        } //======================================发送声音 数据结束
      }
      pdlg->nSend = (pdlg->nSend +1)% InBlocks;
    }

  }
  else
    AfxMessageBox("Socket连接失败"+pdlg->GetError (GetLastError()));
  m_Client.Close();
  return 0;
}

存在的问题

(1) 一旦添加声音控制waveSetGetVolume(),耳机就变成单声的,打开系统 的音量控制,发现“波形”选项完全不平衡。

(2) 声音的录入运 用双缓冲技术,使得无懈可击,但是在播放时,采用双缓冲调试时未能取得成功 ,相反使用单缓冲却基本上能够满足一般的音效。

(3) 可能还有尚未暴露的 错误,恳请广大朋友不吝赐教。E-mail: candy0624@163.com

Finally,Thank Candy Lee(my special friend) for her help.

本文配套源码

上一页  1 2 3 

Tags:实时 语音 通信

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接