マイクで取った音をUDPで送って別のマシンのスピーカから再生させる

ManagedDirectXのDirectSoundでマイクを拾ってUDPに詰め込んでネットワークに流し、受け取った側で再生させる例。
ハウリングの防止とか、認証とか何もしてない。圧縮もせず44.1KHzのwaveをだだ流ししてるだけ。


送信側

using Org.Shokai.Net;
VoiceChat chat = new VoiceChat(this); // 使用するFormなどのcontrolを渡す
chat.StartSend("192.168.0.3", 6656); // IPアドレス、Port番号

音声入力デバイスの選択はまだ作ってない



受信側

chat.StartReceive(6656); // Port番号

再生デバイスの選択まだ作ってない



VoiceChat.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX.DirectSound;
using System.IO;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;

namespace Org.Shokai.Net
{

    public partial class VoiceChat
    {
        public string userName;
        private Control owner;
        private Device device;
        private Capture capture;

        private WaveFormat format;
        private CaptureBuffer captureBuffer;
        private CaptureBufferDescription captureBufferDescription;

        private Thread threadSend, threadReceive;
        private UdpClient sendClient, receiveClient;

        private bool sending;
        /// <summary>
        /// 送信中かどうか
        /// </summary>
        public bool Sending
        {
            get
            {
                return sending;
            }
        }

        private bool receiving;
        /// <summary>
        /// 受信中かどうか
        /// </summary>
        public bool Receiving
        {
            get
            {
                return receiving;
            }
        }

        public VoiceChat(Control owner)
        {
            this.owner = owner;
            sending = false;
            receiving = false;

            format = new WaveFormat();
            format.Channels = 1;
            format.FormatTag = WaveFormatTag.Pcm;
            format.BitsPerSample = 16;
            format.SamplesPerSecond = 44100; // 44.1KHz
            format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / (short)8));
            format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;

            device = new Device();
            device.SetCooperativeLevel(owner, CooperativeLevel.Normal);
            CaptureDevicesCollection captureDevices = new CaptureDevicesCollection();
            DeviceInformation deviceInfo = captureDevices[0];
            capture = new Capture(deviceInfo.DriverGuid);

        }

        /// <summary>
        /// 集音/送信開始
        /// </summary>
        /// <param name="ipaddr">送信先IPアドレス or ホスト名</param>
        /// <param name="port">送信先Port番号</param>
        public void StartSend(string ipaddr, int port)
        {
            sending = true;
            try
            {
                captureBufferDescription = new CaptureBufferDescription();
                captureBufferDescription.BufferBytes = format.AverageBytesPerSecond / 5; // 200ms分確保
                captureBufferDescription.Format = format;

                sendClient = new UdpClient();

                threadSend = new Thread(delegate()
                {
                    captureBuffer = new CaptureBuffer(captureBufferDescription, capture);
                    captureBuffer.Start(true);
                    bool readFirstBufferPart = true;
                    int offset = 0;

                    MemoryStream ms = new MemoryStream(captureBufferDescription.BufferBytes / 2);
                    while (true)
                    {
                        ms.Seek(0, SeekOrigin.Begin);
                        captureBuffer.Read(offset, ms, captureBufferDescription.BufferBytes / 2, LockFlag.None);
                        readFirstBufferPart = !readFirstBufferPart;
                        offset = readFirstBufferPart ? 0 : captureBufferDescription.BufferBytes / 2;

                        byte[] bytes = ms.GetBuffer();
                        sendClient.Send(bytes, bytes.Length, ipaddr, port);
                        Thread.Sleep(10);
                    }
                });
                threadSend.Start();
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        /// <summary>
        /// 受信/再生開始
        /// </summary>
        /// <param name="port">受信Port番号</param>
        public void StartReceive(int port)
        {
            BufferDescription playbackBufferDescription = new BufferDescription();
            playbackBufferDescription.BufferBytes = format.AverageBytesPerSecond / 5;
            playbackBufferDescription.Format = format;

            receiving = true;
            try
            {
                receiveClient = new UdpClient(port);
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, port);
                threadReceive = new Thread(delegate()
                {
                    while (true)
                    {
                        byte[] bytes = receiveClient.Receive(ref remoteEP);
                        byte[] decoded = new byte[bytes.Length * 2];
                        SecondaryBuffer playbackBuffer = new SecondaryBuffer(playbackBufferDescription, device);
                        playbackBuffer.Write(0, bytes, LockFlag.None);
                        playbackBuffer.Play(0, BufferPlayFlags.Default);
                        Thread.Sleep(10);
                    }
                });
                threadReceive.Start();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        public void StopSend()
        {
            if (captureBuffer != null && captureBuffer.Looping)
            {
                captureBuffer.Stop();
                captureBuffer = null;
            }
            if (sendClient != null)
            {
                sendClient.Close();
                sendClient = null;
            }
            if (threadSend != null)
            {
                threadSend.Abort();
                threadSend = null;
            }
            sending = false;
        }

        public void StopReceive()
        {

            if (receiveClient != null)
            {
                receiveClient.Close();
                receiveClient = null;
            }
            if (threadReceive != null)
            {
                threadReceive.Abort();
                threadReceive = null;
            }
            receiving = false;
        }

        public void Close()
        {
            StopSend();
            StopReceive();
            if (device != null)
            {
                device.Dispose();
                device = null;
            }
        }

    }

}