Bad audio while sending through TCP/IP connection - c#

I'm making an application that sends audio through TCP/IP connection using NAudio.
This is my server code:
// 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();
This is my client code:
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();
}
}
My application works fine. But there is one problem I'm facing with :
- The recorded voice cannot be heard while sending to server end-point. If I save it to memory stream and play it back, the quality is ok.
Should I compress my recorded voice before sending to server ? Are there any ways to solve this issue ?
Thank you,

Your _tcpConnectionListeningThread should be writing directly into the BufferedWaveProvider, not going through an intermediate step of copying into an non-thread safe list. _waveBufferCheckThread is completely unnecessary. Update the listening thread to do something like:
while ((iReadBytes = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
_bufferedWaveProvider.AddSamples(buffer, 0, iReadBytes);
}
Also you must ensure the WaveFormat on the server side is exactly the same as used on the client side.

Related

Socket.Avaliable loss C#

I wrote this method using UDP socket with ReceiveTimeout = 1000. And sometimes it loses second packet:
private static byte[] ReceivePlainData(Socket socket) {
var recievedData = new List<byte>();
var buffer = new byte[1024];
do {
int recievedAmount;
while (true) {
try {
recievedAmount = socket.Receive(buffer);
}
catch (SocketException) {
continue;
}
break;
}
recievedData.AddRange(buffer.Take(recievedAmount));
} while (socket.Available > 0);
return recievedData.ToArray();
}
Socket initialization:
using (var socket = new Socket(SocketType.Dgram, ProtocolType.Udp) {
ReceiveTimeout = 1000
})
What do i need to change to make this method work correctly?
Socket.Available only tells you if data has been received and available for immediate reading. It doesn't tell you if the stream is complete or not. The sender may still be in the process of generating or transmitting more data. If you intend to consume the entire response and are relying on the socket to be closed by the sender when there is no more data, continue reading from the socket until the number of bytes returned is 0 (indicating the socket was closed normally) or an exception occurs (indicating abnormal termination).
MemoryStream stream = new MemoryStream();
int received;
var buffer = new byte[8096];
do {
received = socket.Receive(buffer);
stream.Write(buffer, 0, received);
} while (received > 0);
// Use the stream
// byte[] bytes = stream.ToArray();
Set your socket's ReceiveTimeout to the maximum amount of time you're willing to wait between bytes before aborting.

length header suddenly has wrong value when use read int32?

I wrote a tcp listener to receive a sequence of images from single client , this is the code of server :
new Thread(() =>
{
while (true)
{
displayingFrame.Start(); // another thread to display images
Socket socket = listener.AcceptSocket();
TcpClient client = new TcpClient();
client.Client = socket;
Debug.WriteLine("Connection accepted.");
var childSocketThread = new Thread(() =>
{
NetworkStream ns = client.GetStream();
BinaryReader br = new BinaryReader(ns);
while (true)
{
using (MemoryStream ms = new MemoryStream())
{
int length = br.ReadInt32();
Debug.WriteLine("length : " + length);
byte[] buf = new byte[1024];
int totalReaded = 0;
int readed = 0;
while (totalReaded < length)
{
readed = br.Read(buf, 0, buf.Length);
ms.Write(buf, 0, readed);
totalReaded += readed;
}
byte[] frame = ms.ToArray();
this.frames.Enqueue(frame);
Debug.WriteLine("frame enqueued with length " + frame.Length);
}
}
});
childSocketThread.Start();
}
}).Start();
it receive frames very well but suddenly br.ReadInt32(); returns a very big length so br.Read(buf, 0, buf.Length); takes a very long time writing to memory stream and it writes a wrong data inside frame .
this is the client :
TcpClient client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Loopback, 20000));
NetworkStream ns = client.GetStream();
BinaryWriter bw = new BinaryWriter(ns);
while ( true )
{
byte[] frame = Screenshot();
bw.Write(frame.Length);
Console.WriteLine("a frame length has flushed : " + frame.Length);
bw.Write(frame);
Console.WriteLine("a frame itself has flushed");
}
Console.ReadKey();
and here the debug info :
If you check the hex value you're getting - 1196314761 - you'll get 0x474E5089 and finally convert to ASCII you will get GNP\x89 which gives us the known magic value \x89PNG that is the marker of PNG file. You're actually reading the content of your screenshot as the length.
Make sure that you're code for reading the data does not read too much from the previous frame. I think you code for reading the data does not include the fact that you might get content of 2 frames in one .Read but then later you just don't care if you have too much data. You only check if it's not less than length.

c# TCP NetworkStream is not receiving data

I'm trying to send files after sending their's information via TCP connection. At the end of receiver host, the data packets are received. I used Wireshark to confirm it. However the data couldn't be received in NetworkStream.
public class FileTransporter
{
public void ReceiveFiles(IPAddress IP, int port)
{
TcpListener tcpListener = new TcpListener(IP, port);
tcpListener.Start();
using (TcpClient tcpClient = tcpListener.AcceptTcpClient())
{
if (tcpClient.Connected)
{
using (NetworkStream networkStream = tcpClient.GetStream())
{
int pointer = 0;
byte[] fileNameLengthBytes = new byte[sizeof(int)];
networkStream.Read(fileNameLengthBytes, pointer, fileNameLengthBytes.Length);
int fileNameLength = BitConverter.ToInt32(fileNameLengthBytes, pointer);
// code to read fileName and it's size
networkStream.Close();
}
}
tcpClient.Close();
}
tcpListener.Stop();
}
public void SendFiles(IPAddress IP, int port, string[] paths)
{
for(int i=0; i<paths.Length; i++)
{
FilePackage filePackage = new FilePackage(paths[i]);
byte[] infoBytes = filePackage.EncodeInfoToByte();
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.Connect(IP, port);
using (NetworkStream networkStream = tcpClient.GetStream())
{
networkStream.Write(infoBytes, 0, infoBytes.Length);
networkStream.Close();
}
tcpClient.Close();
}
}
}
}
public class FilePackage
{
public FilePackage(string fileName)
{
this.Info = new FileInfo(fileName);
}
public byte[] EncodeInfoToByte()
{
List<byte> infoByte = new List<byte>();
infoByte.AddRange(BitConverter.GetBytes(this.Info.Name.Length));
infoByte.AddRange(Encoding.UTF8.GetBytes(this.Info.Name));
infoByte.AddRange(BitConverter.GetBytes(this.Info.Length));
return infoByte.ToArray();
}
I am going to Assume that ReadFiles is invoked somehow / somewhere else.
I have a very similar implementation, however my "Read" of the stream is much smaller:
// Read the first batch of the TcpServer response bytes.
var bytes = new byte[512];
// Loop to receive all the data sent by the Server.
var sb = new StringBuilder();
do
{
var i = stream.Read(bytes, 0, bytes.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(bytes, 0, i));
} while (stream.DataAvailable);
Perhaps using "stream.DataAvailable" will allow you to test for data existence and that way you can make sure that you only process when data is available.
Also I don't see where "pointer" is being initialized in your code.
If it is not set to 0 each time, you will not be processing from the beginning of the data packet.
Your problem is probably being caused by the nagle algorithm, prevent small amounts of data being sent to reduce congestion. You could try disabling it by setting the following properties on your tcpClient
tcpClient.NoDelay = true;
tcpClient.Client.NoDelay = true

C# sockets: can't read after writing to socket

In my client/server application my client wiil communicate with the server for 2 functions: the client will either request data from the server or it will send data so the server will save it. I'm using one socket for both methods, and the method to be used is defined by the first byte sent. If the first byte is "1" it is requesting data. If it is "2", it will send data (data bytes are sent after the "2" byte). It works perfectly for sending data. But when I'm requesting data it works, as long as I don't read the socket stream in the client. It's like if I make the client read data after sending data, the server will have no data to read, and it just crashes when trying to read the data.
Here is my server code:
private const int BufferSize = 1024;
NetworkStream netstream = null;
byte[] RecData = new byte[BufferSize];
int RecBytes;
try {
netstream = clientSocket.GetStream();
int totalrecbytes = 0;
using (MemoryStream ms = new MemoryStream()) {
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
byte[] bytes = ms.ToArray();
byte b = bytes[0];
switch (b) {
case 1:
//Here I gather data and put it in "stream" variable
byte[] SendingBuffer = null;
int NoOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(stream.Length) / Convert.ToDouble(BufferSize)));
int TotalLength = (int)stream.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++) {
if (TotalLength > BufferSize) {
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
stream.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
}
netstream.Flush();
}
catch (Exception e) {
Console.WriteLine("EXCEPTION:\n" + e.ToString());
}
break;
case 2:
//Code to read data
break;
}
}
netstream.Close()
clientSocket.Close();
And here is my client code:
using (System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient()) {
string returnData = "";
IAsyncResult ar = clientSocket.BeginConnect("127.0.0.1", 8080, null, null);
System.Threading.WaitHandle wh = ar.AsyncWaitHandle;
try {
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false)) {
clientSocket.Close();
Console.WriteLine("Timeout");
return;
}
System.Net.Sockets.NetworkStream serverStream = clientSocket.GetStream();
byte b = 1;
byte[] outStream = { b };
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
//If I comment following lines, the server can read sent data, but server can't otherwise
byte[] RecData = new byte[1024];
int RecBytes;
int totalrecbytes = 0;
MemoryStream MS = new MemoryStream();
while ((RecBytes = serverStream.Read(RecData, 0, RecData.Length)) > 0) {
MS.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
serverStream.Close();
clientSocket.Close();
clientSocket.EndConnect(ar);
}
catch (Exception ex) {
Console.WriteLine("Exceção: " + ex.ToString());
}
finally {
wh.Close();
}
}
So, how can I send data to server and read the response? (I tried even putting the thread to sleep after sending data, with no luck.)
Thanks in advance.
EDIT:
With some debug messages I discovered that the server do read the "1" byte that was sent, but somehow it gets stuck inside the while loop, like, the server just stops there, no more loops and it does not leave the while loop. I saw that after writing "loop" in console inside the while loop, and writing read bytes also in console. It wrote "loop" once, and the read byte.
This code worries me:
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
You are reading until the client closes the connection (or shuts down sending, which you don't do). But the client only closes when the server has replied. The server reply will never come. It is a deadlock.
Solution: Read a single byte to determine the requests command (b).
Unrelated to the question, your "packetised" sending (NoOfPackets, ...) does not seem to serve any purpose. Just use Stream.Copy to write. TCP does not have packets.
An even better solution would be to abandon your custom TCP protocol and use an HTTP library. All these concerns just go away. There are various smaller problems with your code that are very typical to see in TCP code.

TcpListener truncating byte array randomly

I am writing what is essentially an image backup server to store images. It is a one way service that will not return anything beyond a basic success or failure message to the client.
The issue that I am experienceing is that when I send a byte array through the network stream, it is being cut-off before the end of the stream at random locations. I do not have this issue when I run the server on my development machine and connect locally, but rather it only occurs when the server is deployed on a remote server.
When I send very small arrays ( < 512 bytes) the server recieves the entire stream successfully, but on streams larger than 2000 bytes I experience issues. The code for the client is as follows:
try
{
TcpClient Voice = new System.Net.Sockets.TcpClient();
//Obviously I use the remote IP when it is deployed - but have altered it for privacy.
IPEndPoint BackupServer = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 57000);
Voice.Connect(BackupServer);
NetworkStream DataStream = Voice.GetStream();
byte[] buffer = new ASCIIEncoding().GetBytes(ImageData.GetXml());
DataStream.Write(buffer, 0, buffer.Length);
DataStream.Flush();
}
catch
{
}
try
{
buffer = new byte[4096];
int read = DataStream.Read(buffer, 0, buffer.Length);
MessageBox.Show(new ASCIIEncoding().GetString(buffer) + " : " + read.ToString());
}
catch
{
}
The client code executes without any errors or problems regardless of the size of data I send.
And the code for the server side is as follows:
private void BackMeUp(object voice)
{
TcpClient Voice = (TcpClient)voice;
Voice.ReceiveTimeout = 30000;
NetworkStream DataStream = Voice.GetStream();
try
{
bool ShouldLoop = true;
//int loops = 0;
int loops = -1;
byte[] input = new byte[2048];
byte[] buffer = new byte[0];
//while (ShouldLoop)
while(loops != 0)
{
loops = DataStream.Read(input, 0, 2048);
for (int x = 0; x < loops; x++)
{
Array.Resize(ref buffer, buffer.Length + 1);
buffer[buffer.Length - 1] = input[x];
}
//if (loops < 2048)
//{
//ShouldLoop = false;
//break;
//}
}
while (true)
{
StringReader Reader = new StringReader(new ASCIIEncoding().GetString(buffer, 0, buffer.Length));
DataSet DS = new DataSet();
DS.ReadXml(Reader);
if (DS.Tables.Count > 0)
{
if (DS.Tables["Images"].Rows.Count > 0)
{
foreach (DataRow row in DS.Tables["Images"].Rows)
{
//
}
}
}
string response = "Got it!";
DataStream.Write(new ASCIIEncoding().GetBytes(response), 0, response.Length);
DataStream.Flush();
Voice.Close();
break;
}
}
catch (Exception Ex)
{
File.WriteAllText("Elog.txt", Ex.Message + " " + (Ex.InnerException != null ? Ex.InnerException.ToString() : " no Inner"));
Voice.Close();
}
}
The server recieves the data fine, and closes the stream when it reaches the end, however the data is cut-off and I get an error when I try to rebuild the dataset.
I have the impression this has to do with the time it takes to send the stream, and I have played around with the Close and Flush commands but I feel like I'm just shooting in the dark. Any help would be appreciated.
Concise version of question: What factors are involved with a TcpListener that could cause a) the truncation of the stream. or b) premature closing of the stream prior to all bytes being read. When the listener in question is on a remote host rather than a local server.
The Read method doesn't have to return the number of bytes that you requested, or the entire stream at once. Especially if the stream is slow, it will be returned in small chunks.
Call the Read method repeatedly, and handle the data for each block that you get. The Read method returns zero when the stream is read to the end:
buffer = new byte[4096];
do {
int read = DataStream.Read(buffer, 0, buffer.Length);
if (read != 0) {
// handle the first "read" bytes of the buffer (index 0 to read-1)
}
} while (read != 0);
If you know that your buffer is enough for any stream, you can fill up the buffer and handle it afterwards:
buffer = new byte[4096];
int offset = 0;
do {
int read = DataStream.Read(buffer, offset, buffer.Length - offset);
offset += read;
} while (read != 0);
// handle the first "offset" bytes of the buffer (index 0 to offset-1)

Categories