通过TCP / IP连接发送时音频不佳

时间:2018-03-25 12:18:16

标签: c# sockets tcpclient naudio tcplistener

我正在创建一个使用NAudio通过TCP / IP连接发送音频的应用程序。

这是我的服务器代码:

        // Get server port.
        var iServerPort = GetServerPort();

        // Initialize memory stream.
        _bytes = new List<byte>();

        // Initialize tcp listener.
        var tcpListener = new TcpListener(IPAddress.Any, iServerPort);
        tcpListener.Start();

        // Accept a tcp client.
        Console.WriteLine("Waiting for incoming connection");
        _tcpClient = tcpListener.AcceptTcpClient();
        Console.WriteLine("Client found !");

        // Buffered wave provider.
        _bufferedWaveProvider = new BufferedWaveProvider(new WaveFormat());
        _bufferedWaveProvider.DiscardOnBufferOverflow = true;
        _bufferedWaveProvider.BufferLength = iBufferBytes;

        _waveOut = new WaveOut();
        _waveOut.Init(_bufferedWaveProvider);
        _waveOut.Play();

        // Initialize a thread to listen to incoming data from another source.
        _tcpConnectionListeningThread = new Thread(() =>
        {
            // Get data stream of tcp connection.
            var networkStream = _tcpClient.GetStream();

            // Initalize buffer.
            var buffer = new byte[iBufferBytes];

            // Number of bytes which have been read.

            while (true)
            {
                try
                {
                    int iReadBytes;
                    while ((iReadBytes = networkStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        //var memoryStream = new MemoryStream();
                        //memoryStream.Write(buffer, 0, iReadBytes);
                        //_memoryStreams.Enqueue(memoryStream);
                        //_memoryStream.CopyTo();
                        //_memoryStream.Write(buffer, 0, iReadBytes);
                        var realBytes = buffer.Take(iReadBytes).ToList();
                        _bytes.AddRange(realBytes);
                        Console.WriteLine($"Read: {iReadBytes} bytes. Enqueue a stream. Count: {realBytes.Count}");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    break;
                }
            }
        });

        // Initialize a thread to check audio buffer. Reload as audio stream consumes whole data.
        _waveBufferCheckThread = new Thread(() =>
        {
            while (true)
            {
                // Get remaining bytes in buffer.
                var iRemainingBytes = _bufferedWaveProvider.BufferedBytes;

                // No byte is available in buffer. 
                // Check memory stream to find available bytes array. If nothing found, terminate this thread.
                if (iRemainingBytes >= iBufferBytes)
                    continue;

                // No byte available.
                if (_bytes.Count < 1)
                {
                    //Console.WriteLine("No data in memory stream");
                    continue;
                }

                // Get bytes array from memory stream.
                var iDifferent = iBufferBytes - iRemainingBytes;
                if (iDifferent > _bytes.Count)
                    iDifferent = _bytes.Count;

                var bytes = _bytes.GetRange(0, iDifferent).ToArray();
                _bytes.RemoveRange(0, iDifferent);

                //var bytes = new byte[iBufferBytes];
                _bufferedWaveProvider.AddSamples(bytes, 0, bytes.Length);
                //Console.WriteLine($"Wrote {iReadBytes} to buffer. Count: {_memoryStream.Length}");
                //Thread.Sleep(TimeSpan.FromSeconds(1));
                //_waveOut.Play();
            }
        });

        _tcpConnectionListeningThread.IsBackground = true;
        _waveBufferCheckThread.IsBackground = true;

        _tcpConnectionListeningThread.Start();
        _waveBufferCheckThread.Start();

        Console.ReadLine();

        _tcpConnectionListeningThread.Abort();
        _waveBufferCheckThread.Abort();
        _bufferedWaveProvider.ClearBuffer();
        _waveOut.Stop();
        tcpListener.Stop();

这是我的客户代码:

    public Main()
    {
        InitializeComponent();

        // Initialize tcp client.
        _tcpClient = new TcpClient();
        _recordingStream = new MemoryStream();

        _soundRecorder = new WaveIn();
        _waveOut = new WaveOut();
        _playbackBufferedWaveProvider = new BufferedWaveProvider(_soundRecorder.WaveFormat);
        _waveOut.Init(_playbackBufferedWaveProvider);
        _soundRecorder.DataAvailable += SoundRecorderOnDataAvailable;

        btnRecord.Enabled = true;
    }

    private void SoundRecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
    {
        if (_networkStream != null)
        {
            _networkStream.Write(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
            _networkStream.Flush();
        }
    }

我的应用程序运行正常。但是我面临的一个问题是: - 发送到服务器端点时无法听到录制的语音。如果我将它保存到内存流并播放,质量就可以了。

我应该在发送到服务器之前压缩录制的语音吗?有什么方法可以解决这个问题吗?

谢谢,

1 个答案:

答案 0 :(得分:0)

您的_tcpConnectionListeningThread应直接写入BufferedWaveProvider,而不是经过复制到非线程安全列表的中间步骤。 _waveBufferCheckThread完全没必要。更新监听线程以执行以下操作:

while ((iReadBytes = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
    _bufferedWaveProvider.AddSamples(buffer, 0, iReadBytes);
}

此外,您必须确保服务器端的WaveFormat与客户端使用的完全相同。