1. 程式人生 > >C#中利用Socket實現網路語音通訊[初級版本]

C#中利用Socket實現網路語音通訊[初級版本]


        ///<summary>/// 設定音訊格式,如取樣率等
        
///</summary>///<returns>設定完成後的格式</returns>        private WaveFormat SetWaveFormat()
        {
            WaveFormat format = new WaveFormat();
            format.FormatTag = WaveFormatTag.Pcm;//設定音訊型別            format.SamplesPerSecond = 11025;//
取樣率(單位:赫茲)典型值:11025、22050、44100Hz            format.BitsPerSample = 16;//取樣位數            format.Channels = 1;//聲道            format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));//單位取樣點的位元組數            format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;

            return
 format;
            //按照以上取樣規格,可知取樣1秒鐘的位元組數為22050*2=44100B 約為 43K        }

        ///<summary>/// 建立捕捉裝置物件
        
///</summary>///<returns>如果建立成功返回true</returns>        private bool CreateCaputerDevice()
        {
            //首先要玫舉可用的捕捉裝置            CaptureDevicesCollection capturedev = new CaptureDevicesCollection();
            Guid devguid;
            if
 (capturedev.Count > 0)
            {
                devguid = capturedev[0].DriverGuid;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("當前沒有可用於音訊捕捉的裝置""系統提示");
                return false;
            }
            //利用裝置GUID來建立一個捕捉裝置物件            capture = new Capture(devguid);
            return true;
        }

        ///<summary>/// 建立捕捉緩衝區物件
        
///</summary>        private void CreateCaptureBuffer()
        {
            //想要建立一個捕捉緩衝區必須要兩個引數:緩衝區資訊(描述這個緩衝區中的格式等),緩衝裝置。            WaveFormat mWavFormat = SetWaveFormat();
            CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
            bufferdescription.Format = mWavFormat;//設定緩衝區要捕捉的資料格式            iNotifySize = mWavFormat.AverageBytesPerSecond / iNotifyNum;//1秒的資料量/設定的通知數得到的每個通知大小小於0.2s的資料量,話音延遲小於200ms為優質話音            iBufferSize = iNotifyNum * iNotifySize;
            bufferdescription.BufferBytes = iBufferSize;
            bufferdescription.ControlEffects = true;
            bufferdescription.WaveMapped = true;
            capturebuffer = new CaptureBuffer(bufferdescription, capture);//建立裝置緩衝區物件
        }

        //設定通知        private void CreateNotification()
        {
            BufferPositionNotify[] bpn = new BufferPositionNotify[iNotifyNum];//設定緩衝區通知個數
            
//設定通知事件            notifyEvent = new AutoResetEvent(false);
            notifyThread = new Thread(RecoData);//通知觸發事件            notifyThread.IsBackground = true;
            notifyThread.Start();
            for (int i = 0; i < iNotifyNum; i++)
            {
                bpn[i].Offset = iNotifySize + i * iNotifySize - 1;//設定具體每個的位置                bpn[i].EventNotifyHandle = notifyEvent.Handle;
            }
            myNotify = new Notify(capturebuffer);
            myNotify.SetNotificationPositions(bpn);

        }

        //執行緒中的事件        private void RecoData()
        {
            while (true)
            {
                // 等待緩衝區的通知訊息                notifyEvent.WaitOne(Timeout.Infinite, true);
                // 錄製資料                RecordCapturedData(Client,epServer);
            }
        }

        //真正轉移資料的事件,其實就是把資料傳送到網路上去。        private void RecordCapturedData(Socket Client,EndPoint epServer )
        {
            byte[] capturedata = null;
            int readpos = 0, capturepos = 0, locksize = 0;
            capturebuffer.GetCurrentPosition(out capturepos, out readpos);
            locksize = readpos - iBufferOffset;//這個大小就是我們可以安全讀取的大小            if (locksize == 0)
            {
                return;
            }
            if (locksize < 0)
            {//因為我們是迴圈的使用緩衝區,所以有一種情況下為負:當文以載讀指標回到第一個通知點,而Ibuffeoffset還在最後一個通知處                locksize += iBufferSize;
            }
            capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize);
            //capturedata = g729.Encode(capturedata);//語音編碼            try
            {
                Client.SendTo(capturedata, epServer);//傳送語音            }
            catch
            {
                throw new Exception();
            }
            iBufferOffset += capturedata.Length;
            iBufferOffset %= iBufferSize;//取模是因為緩衝區是迴圈的。        }