签到

05月05日
尚未签到

共有回帖数 2

    人心难测

    等级:
    引言本人虽已学习VC++一年半载,仍觉捉襟见肘,好在有VCKBASE的帮忙,确实学 到了不少东西,www.biancheng123.com也成了我每次上民网必到之处(阁下有所不知, 鄙人接受最为严格的管理,上民网是要申请的)。近日在做一个通信 方面的程序 ,实时的语音和视频通信当然是大家所喜欢的。本文将向您展示局域网环境下实 时语音通信的的一个解决方案(视频这一块正在做,估计很快就能出炉),Winxp环 境下测试效果良好,并且具有网络 拥塞处理机制,您不妨一看。本文以第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表 感谢。雷同之处将不再赘述,主要做了以下发展:(1) 利用多线程机制,实现录音、网络传输、放音同时进行。(2) 网 络壅塞处理,保证数据不丢失。例子程序运行画面:





    (1)正常网速下:nAudioIn 在 nSend 之前, nReceive 在 nAuioOu t之前 ,周而复始的走下去。(2)超快网速下:发送端:--nSend追上 nAudioIn--“空转”(绕了一圈又回来了)--〉接收端:因为录、放音的采样频率设置为相等,故不可能出现 nReceive 在n AudioOut 之后,即收到的声音文件太多,来不及播放的现象。(3)超慢网速下:(极端情况,网速几乎为0也没关系)发送端:nAudioIn 绕一圈反追上 nSend,于是将数据接在当前块的尾部 ,以待发送接收端:nAudioOut 追上 nReceive 后,发现没有数据可播放了,就 “空转”。综合以上情况,相关实现如下:(二)声音的录制与播放(1)录音处理


    );
        m_AudioDataIn[nAudioIn].dwLength +=((PWAVEHDR) lParam)- dwBytesRecorded;
      }
      else //把PWAVEHDR(即pBUfferi)里的数据拷贝到下一“块” 中
      {
        nAudioIn = (nAudioIn+1)% InBlocks;
        m_AudioDataIn[nAudioIn].lpdata = (PBYTE)realloc
          (0,((PWAVEHDR) lParam)-dwBytesRecorded);
        CopyMemory(m_AudioDataIn[nAudioIn].lpdata,
            ((PWAVEHDR) lParam)-lpData,
            ((PWAVEHDR) lParam)-dwBytesRecorded) ;
        m_AudioDataIn[nAudioIn].dwLength =((PWAVEHDR) lParam)- dwBytesRecorded;
      }
      // Send out a new buffer
      waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;
      return ;
    }(2)放音处理


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


    楼主 2016-07-28 11:24 回复

    人心难测

    等级:
    ;+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(lengthdwReceived)
          {
            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)//==============================发送声音数

    1楼 2016-07-28 11:24 回复

    人心难测

    等级:
    据开始
            {
              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.comFinally,Thank Candy Lee(my special friend) for her help.

    2楼 2016-07-28 11:24 回复

共有回帖数 2
  • 回 帖
  • 表情 图片 视频
  • 发表

登录直线网账号

Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号 意见反馈 | 关于直线 | 版权声明 | 会员须知