I try to Split packet (fragmentation) using PcapDotNet and found this
So this is my function:
private IEnumerable<Packet> SplitPacket(Packet packet, int numberOfFragments)
{
IpV4Datagram ipV4Datagram = packet.Ethernet.IpV4;
if (ipV4Datagram.Protocol == IpV4Protocol.Tcp || ipV4Datagram.Protocol == IpV4Protocol.Udp)
{
EthernetLayer ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
ILayer layer = packet.Ethernet.IpV4.ExtractLayer();
TcpLayer tcpLayer = (TcpLayer)packet.Ethernet.IpV4.Tcp.ExtractLayer();
tcpLayer.Checksum = null;
IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
ipV4Layer.HeaderChecksum = null;
DateTime packetTimestamp = packet.Timestamp;
PayloadLayer payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer(); //extract the data
int totalLength = payload.Length;
int partialLength = totalLength / numberOfFragments; //split data into smaller segments
partialLength = (partialLength / 8) * 8; //make sure it's divisible with 8
//(http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly)
ushort offset = 0; //send one by one
while (offset < totalLength)
{
int fragmentLength = partialLength; //get length for this fragment
IpV4FragmentationOptions options = IpV4FragmentationOptions.MoreFragments;
if (offset + fragmentLength >= totalLength) //is this the last fragment ? trim length if needed
{
options = IpV4FragmentationOptions.None;
fragmentLength = totalLength - offset;
}
byte[] newBuffer = ipV4Datagram.Payload.ToArray(); //copy the actual data into a new buffer
PayloadLayer newPayload = new PayloadLayer { Data = new Datagram(newBuffer, offset, fragmentLength) };
ipV4Layer.Fragmentation = new IpV4Fragmentation(options, offset); //change IP layer fragmentation options
yield return PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, tcpLayer, newPayload); //return
offset += (ushort)fragmentLength; //next offset
}
}
}
The problem is that after play this file i can see the same number of packets like in the original Wireshark file so it mean that something not working and the protocol field in Wiresahrk recognized this packet as IPV4 and this is how this packet looks (i think i have build this packet in invalid way):
Related
I'm using UdpClient to get a RTP stream from phone calls through Avaya DMCC sdk. I would like to play this stream through the computer's speakers. After a lot of searching I've only been able to find solutions that require saving to a file and then playing the file but I need to play the stream through the speakers without saving to a file. I'd like to send audio to the speakers as I receive it.
public void StartClient()
{
// Create new UDP client. The IP end point tells us which IP is sending the data
client = new UdpClient(port);
endPoint = new IPEndPoint(System.Net.IPAddress.Any, port);
selectedCodec = new MuLawChatCodec();
waveOut = new WaveOut();
waveProvider = new BufferedWaveProvider(selectedCodec.RecordFormat);
waveOut.Init(waveProvider);
waveOut.Play();
listening = true;
listenerThread = new Thread(ReceiveCallback);
listenerThread.Start();
}
private void ReceiveCallback()
{
// Begin looking for the next packet
while (listening)
{
// Receive packet
byte[] packet = client.Receive(ref endPoint);
// Packet header
int version = GetRTPValue(packet, 0, 1);
int padding = GetRTPValue(packet, 2, 2);
int extension = GetRTPValue(packet, 3, 3);
int csrcCount = GetRTPValue(packet, 4, 7);
int marker = GetRTPValue(packet, 8, 8);
int payloadType = GetRTPValue(packet, 9, 15);
int sequenceNum = GetRTPValue(packet, 16, 31);
int timestamp = GetRTPValue(packet, 32, 63);
int ssrcId = GetRTPValue(packet, 64, 95);
int csrcid = (csrcCount == 0) ? -1 : GetRTPValue(packet, 96, 95 + 32 * (csrcCount));
int extHeader = (csrcCount == 0) ? -1 : GetRTPValue(packet, 128 + (32 * csrcCount), 127 + (32 * csrcCount));
int payloadIndex = csrcCount == 0 ? 96 : 128 + 32 * csrcCount;
int payload = GetRTPValue(packet, payloadIndex, packet.Length);
byte[] Payload = new byte[packet.Length - payloadIndex];
Buffer.BlockCopy(packet, payloadIndex, Payload, 0, packet.Length - payloadIndex);
byte[] decoded = selectedCodec.Decode(Payload, 0, Payload.Length);
}
}
private int GetRTPValue(byte[] packet, int startBit, int endBit)
{
int result = 0;
// Number of bits in value
int length = endBit - startBit + 1;
// Values in RTP header are big endian, so need to do these conversions
for (int i = startBit; i <= endBit; i++)
{
int byteIndex = i / 8;
int bitShift = 7 - (i % 8);
result += ((packet[byteIndex] >> bitShift) & 1) * (int)Math.Pow(2, length - i + startBit - 1);
}
return result;
}
I now successfully have audio from the call being played over the speakers by adding a byte[] containing just the payload to NAudio's BufferedWaveProvider
There's a demo of how to play audio received over the network included with the NAudio source code (see Network Chat Demo in the NAudioDemo project). Basically use an AcmStream to decode the audio, and then put it into a BufferedWaveProvider which the soundcard is playing from.
I am using PcapDorNet DLLs and i try to fragment my traffic:
private IEnumerable<Packet> SplitPacket(Packet packet, int numberOfFragments)
{
IpV4Datagram ipV4Datagram = packet.Ethernet.IpV4;
Datagram datagram = packet.Ethernet.IpV4.Payload;
TransportLayer transportlayer = GetTransportLayer(packet);
if (transportlayer != null)
{
EthernetLayer ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
ILayer layer = packet.Ethernet.IpV4.ExtractLayer();
IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
ipV4Layer.HeaderChecksum = null;
DateTime packetTimestamp = packet.Timestamp;
PayloadLayer payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer(); //extract the data
int totalLength = payload.Length;
int partialLength = totalLength / numberOfFragments; //split data into smaller segments
partialLength = (partialLength / 8) * 8; //make sure it's divisible with 8
if (partialLength == 0)
partialLength = 8;
//(http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly)
ushort offset = 0; //send one by one
while (offset < totalLength)
{
int fragmentLength = partialLength; //get length for this fragment
IpV4FragmentationOptions options = IpV4FragmentationOptions.MoreFragments;
if (offset + fragmentLength >= totalLength) //is this the last fragment ? trim length if needed
{
options = IpV4FragmentationOptions.None;
fragmentLength = totalLength - offset;
}
byte[] newBuffer = ipV4Datagram.Payload.ToArray(); //copy the actual data into a new buffer
PayloadLayer newPayload = new PayloadLayer { Data = new Datagram(newBuffer, offset, fragmentLength) };
ipV4Layer.Fragmentation = new IpV4Fragmentation(options, offset); //change IP layer fragmentation options
transportlayer.Checksum = null;
yield return PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, transportlayer, newPayload);
offset += (ushort)fragmentLength; //next offset
}
}
}
My input packet is TCP packet and the output is 4 packets: 3 IPv4 packets and the last is TCP but this packet i received is show under TCP layer field this message:
Checksum: 0x5d17 [incorrect, should be 0xabb7 (maybe caused by "TCP
checksum offload"?)]
with UDP it seems that also every UDP packet split into several IPv4 packet and the last one is UDP but in UDP case it look fine.
I am i doing something wrong ?
Please see the original packet and the fragmentation: http://www.filedropper.com/desktop_122
It seems there is a very similar question in Pcap.Net site with corrections to the code.
I believe following the advice there would help solve your issues.
I'm currently trying to do pitch shifting of a wave file using this algorithm
https://sites.google.com/site/mikescoderama/pitch-shifting
Here my code which use the above implementation, but with no luck. The outputted wave file seems to be corrupted or not valid.
The code is quite simple, except for the pitch shift algorithm :)
It load a wave file, it reads the wave file data and put it in a
byte[] array.
Then it "normalize" bytes data into -1.0f to 1.0f format (as
requested by the creator of the pitch shift algorithm).
It applies the pitch shift algorithm and then convert back the
normalized data into a bytes[] array.
Finally saves a wave file with the same header of the original wave
file and the pitch shifted data.
Am I missing something?
static void Main(string[] args)
{
// Read the wave file data bytes
byte[] waveheader = null;
byte[] wavedata = null;
using (BinaryReader reader = new BinaryReader(File.OpenRead("sound.wav")))
{
// Read first 44 bytes (header);
waveheader= reader.ReadBytes(44);
// Read data
wavedata = reader.ReadBytes((int)reader.BaseStream.Length - 44);
}
short nChannels = BitConverter.ToInt16(waveheader, 22);
int sampleRate = BitConverter.ToInt32(waveheader, 24);
short bitRate = BitConverter.ToInt16(waveheader, 34);
// Normalized data store. Store values in the format -1.0 to 1.0
float[] in_data = new float[wavedata.Length / 2];
// Normalize wave data into -1.0 to 1.0 values
using(BinaryReader reader = new BinaryReader(new MemoryStream(wavedata)))
{
for (int i = 0; i < in_data.Length; i++)
{
if(bitRate == 16)
in_data[i] = reader.ReadInt16() / 32768f;
if (bitRate == 8)
in_data[i] = (reader.ReadByte() - 128) / 128f;
}
}
//PitchShifter.PitchShift(1f, in_data.Length, (long)1024, (long)32, sampleRate, in_data);
// Backup wave data
byte[] copydata = new byte[wavedata.Length];
Array.Copy(wavedata, copydata, wavedata.Length);
// Revert data to byte format
Array.Clear(wavedata, 0, wavedata.Length);
using (BinaryWriter writer = new BinaryWriter(new MemoryStream(wavedata)))
{
for (int i = 0; i < in_data.Length; i++)
{
if(bitRate == 16)
writer.Write((short)(in_data[i] * 32768f));
if (bitRate == 8)
writer.Write((byte)((in_data[i] * 128f) + 128));
}
}
// Compare new wavedata with copydata
if (wavedata.SequenceEqual(copydata))
{
Console.WriteLine("Data has no changes");
}
else
{
Console.WriteLine("Data has changed!");
}
// Save modified wavedata
string targetFilePath = "sound_low.wav";
if (File.Exists(targetFilePath))
File.Delete(targetFilePath);
using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(targetFilePath)))
{
writer.Write(waveheader);
writer.Write(wavedata);
}
Console.ReadLine();
}
The algorithm here works fine
https://sites.google.com/site/mikescoderama/pitch-shifting
My mistake was on how i was reading the wave header and wave data. I post here the fully working code
WARNING: this code works only for PCM 16 bit (stereo/mono) waves. Can be easily adapted to works with PCM 8 bit.
static void Main(string[] args)
{
// Read header, data and channels as separated data
// Normalized data stores. Store values in the format -1.0 to 1.0
byte[] waveheader = null;
byte[] wavedata = null;
int sampleRate = 0;
float[] in_data_l = null;
float[] in_data_r = null;
GetWaveData("sound.wav", out waveheader, out wavedata, out sampleRate, out in_data_l, out in_data_r);
//
// Apply Pitch Shifting
//
if(in_data_l != null)
PitchShifter.PitchShift(2f, in_data_l.Length, (long)1024, (long)10, sampleRate, in_data_l);
if(in_data_r != null)
PitchShifter.PitchShift(2f, in_data_r.Length, (long)1024, (long)10, sampleRate, in_data_r);
//
// Time to save the processed data
//
// Backup wave data
byte[] copydata = new byte[wavedata.Length];
Array.Copy(wavedata, copydata, wavedata.Length);
GetWaveData(in_data_l, in_data_r, ref wavedata);
//
// Check if data actually changed
//
bool noChanges = true;
for (int i = 0; i < wavedata.Length; i++)
{
if (wavedata[i] != copydata[i])
{
noChanges = false;
Console.WriteLine("Data has changed!");
break;
}
}
if(noChanges)
Console.WriteLine("Data has no changes");
// Save modified wavedata
string targetFilePath = "sound_low.wav";
if (File.Exists(targetFilePath))
File.Delete(targetFilePath);
using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(targetFilePath)))
{
writer.Write(waveheader);
writer.Write(wavedata);
}
Console.ReadLine();
}
// Returns left and right float arrays. 'right' will be null if sound is mono.
public static void GetWaveData(string filename, out byte[] header, out byte[] data, out int sampleRate, out float[] left, out float[] right)
{
byte[] wav = File.ReadAllBytes(filename);
// Determine if mono or stereo
int channels = wav[22]; // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels
// Get sample rate
sampleRate = BitConverter.ToInt32(wav, 24);
int pos = 12;
// Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))
while(!(wav[pos]==100 && wav[pos+1]==97 && wav[pos+2]==116 && wav[pos+3]==97)) {
pos += 4;
int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
pos += 4 + chunkSize;
}
pos += 4;
int subchunk2Size = BitConverter.ToInt32(wav, pos);
pos += 4;
// Pos is now positioned to start of actual sound data.
int samples = subchunk2Size / 2; // 2 bytes per sample (16 bit sound mono)
if (channels == 2)
samples /= 2; // 4 bytes per sample (16 bit stereo)
// Allocate memory (right will be null if only mono sound)
left = new float[samples];
if (channels == 2)
right = new float[samples];
else
right = null;
header = new byte[pos];
Array.Copy(wav, header, pos);
data = new byte[subchunk2Size];
Array.Copy(wav, pos, data, 0, subchunk2Size);
// Write to float array/s:
int i=0;
while (pos < subchunk2Size)
{
left[i] = BytesToNormalized_16(wav[pos], wav[pos + 1]);
pos += 2;
if (channels == 2)
{
right[i] = BytesToNormalized_16(wav[pos], wav[pos + 1]);
pos += 2;
}
i++;
}
}
// Return byte data from left and right float data. Ignore right when sound is mono
public static void GetWaveData(float[] left, float[] right, ref byte[] data)
{
// Calculate k
// This value will be used to convert float to Int16
// We are not using Int16.Max to avoid peaks due to overflow conversions
float k = (float)Int16.MaxValue / left.Select(x => Math.Abs(x)).Max();
// Revert data to byte format
Array.Clear(data, 0, data.Length);
int dataLenght = left.Length;
int byteId = -1;
using (BinaryWriter writer = new BinaryWriter(new MemoryStream(data)))
{
for (int i = 0; i < dataLenght; i++)
{
byte byte1 = 0;
byte byte2 = 0;
byteId++;
NormalizedToBytes_16(left[i], k, out byte1, out byte2);
writer.Write(byte1);
writer.Write(byte2);
if (right != null)
{
byteId++;
NormalizedToBytes_16(right[i], k, out byte1, out byte2);
writer.Write(byte1);
writer.Write(byte2);
}
}
}
}
// Convert two bytes to one double in the range -1 to 1
static float BytesToNormalized_16(byte firstByte, byte secondByte)
{
// convert two bytes to one short (little endian)
short s = (short)((secondByte << 8) | firstByte);
// convert to range from -1 to (just below) 1
return s / 32678f;
}
// Convert a float value into two bytes (use k as conversion value and not Int16.MaxValue to avoid peaks)
static void NormalizedToBytes_16(float value, float k, out byte firstByte, out byte secondByte)
{
short s = (short)(value * k);
firstByte = (byte)(s & 0x00FF);
secondByte = (byte)(s >> 8);
}
sorry to revive this but I tried that pitchshifter class and, while it works, I get crackles in the audio while pitching down(0.5f). You work out a way around that?
I've been trying to write a C# application that send data to a stage light using the Enttec DMX USB Pro box. There are provided C# wrappers that I'm using and I've gotten the light to respond as expected but it very rarely works. I seem to have to switch between using from off the shelf application to "reset" the connection a few times before I can get it to start responding to my writes.
My DMX Code is
class DmxDriver
{
const int DMX_PACKET_SIZE = 513;
private bool connected;
private FTDI device;
private int startAddr;
private byte[] packet;
public DmxDriver(int baseDmxAddr)
{
startAddr = baseDmxAddr;
device = new FTDI();
FTDI.FT_STATUS result = device.OpenByIndex(0);
if (result == FTDI.FT_STATUS.FT_OK)
{
connected = true;
Console.WriteLine("DMX connected");
}
else
{
connected = false;
Console.WriteLine("DMX CONNECTION FAILED");
}
packet = new byte[DMX_PACKET_SIZE];
for (int i = 0; i < DMX_PACKET_SIZE; i++)
{
packet[i] = 0;
}
}
~DmxDriver()
{
device.Close();
}
public bool deviceConnected()
{
return connected;
}
public void sendData()
{
if (packet.Length != 513)
{
return;
}
uint written = 0;
FTDI.FT_STATUS result;
byte[] header = new byte[4];
header[0] = 0x7E; //start code
header[1] = 6; //DMX TX
header[2] = 255 & 0xFF; //pack length logical and with max packet size
header[3] = 255 >> 8; //packet length shifted by byte length? DMX standard idk
result = device.Write(header, 4, ref written);//send dmx header
Console.WriteLine(result);
Console.WriteLine(written);
result = device.Write(packet, 513, ref written);//send data array
Console.WriteLine(result);
Console.WriteLine(written);
byte[] endcode = new byte[1];
endcode[0] = 0xE7;
device.Write(endcode, 1, ref written);//send dmx end code
}
Now I'm working on Websockets, I'm new in that, I finally can send a message of 126 bytes, but I need send longer messages but when I try the connection is closed automatically, my code is:
public void sendMessage(Stream stream, string message)
{
try
{
List<byte> lb = new List<byte>();
string aux = message;
bool flagStart = false;
int size;
while (message.Length > _maxLengthMessage)
{
lb = new List<byte>();
// I cut the mesasge in smaller pieces to send
message = aux.Substring(0, _maxLengthMessage);
aux = aux.Substring(_maxLengthMessage);
if (!flagStart)
{
// In doc of Websockets i sign this piece: not the end, text
lb.Add(0x01);
flagStart = !flagStart;
}
else
{
// In doc of Websockets i sign this piece: not the end, continuation
lb.Add(0x00);
}
size = message.Length;
lb.Add((byte)size);
lb.AddRange(Encoding.UTF8.GetBytes(message));
stream.Write(lb.ToArray(), 0, size + 2);
}
lb = new List<byte>();
if (!flagStart)
{
// If is this the only message we mark with: end of message, text
lb.Add(0x81);
flagStart = !flagStart;
}
else
{
//else Is the end of the message but is the continuation frame
lb.Add(0x80);
}
size = aux.Length;
lb.Add((byte)size);
lb.AddRange(Encoding.UTF8.GetBytes(aux));
//lb.AddRange(Encoding.UTF8.GetBytes(i.ToString()));
stream.Write(lb.ToArray(), 0, size+2);
}
catch (Exception ex)
{
throw ex;
}
}
Some answers say "Go to the The WebSocket protocol", but it didn't work for me.
Your code to write the message length needs to be extended. The extended payload in the data framing diagram of the protocol spec shows what's missing.
For messages up to 125 bytes, your code is correct.
For messages > 125 but <= 65536 bytes, you need to write 3 bytes - the first byte is 126; the following 2 bytes give the message length.
For messages > 65536 bytes, you need to write 9 bytes - the first byte is 127; the following 8 bytes give the message length.
Ye, you have to create correct frame, here is the method:
static private byte[] CreateFrame(string message, MessageType messageType = MessageType.Text, bool messageContinues = false)
{
byte b1 = 0;
byte b2 = 0;
switch (messageType)
{
case MessageType.Continuos:
b1 = 0;
break;
case MessageType.Text:
b1 = 1;
break;
case MessageType.Binary:
b1 = 2;
break;
case MessageType.Close:
b1 = 8;
break;
case MessageType.Ping:
b1 = 9;
break;
case MessageType.Pong:
b1 = 10;
break;
}
b1 = (byte)(b1 + 128); // set FIN bit to 1
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
if (messageBytes.Length < 126)
{
b2 = (byte)messageBytes.Length;
}
else
{
if (messageBytes.Length < Math.Pow(2,16)-1)
{
b2 = 126;
}
else
{
b2 = 127;
}
}
byte[] frame = null;
if(b2 < 126)
{
frame = new byte[messageBytes.Length + 2];
frame[0] = b1;
frame[1] = b2;
Array.Copy(messageBytes, 0, frame, 2, messageBytes.Length);
}
if(b2 == 126)
{
frame = new byte[messageBytes.Length + 4];
frame[0] = b1;
frame[1] = b2;
byte[] lenght = BitConverter.GetBytes(messageBytes.Length);
frame[2] = lenght[1];
frame[3] = lenght[0];
Array.Copy(messageBytes, 0, frame, 4, messageBytes.Length);
}
if(b2 == 127)
{
frame = new byte[messageBytes.Length + 10];
frame[0] = b1;
frame[1] = b2;
byte[] lenght = BitConverter.GetBytes((long)messageBytes.Length);
for(int i = 7, j = 2; i >= 0; i--, j++)
{
frame[j] = lenght[i];
}
}
return frame;
}