It is not comfortable to use the Sound API in .NET, because there is no support by the class library itself. So I decided to write my own small Audio Assembly WinSound.dll
by using PInvoke and the native WMM API (Windows Multi Media). With help of this library you can play or capture audio sound in an easy way. In addition i wrote some Network Assemblies, to stream and play Audio Data over Network by Multicast.
In addition i implemented a similar C++ Version for the sound part of this project as a COM Server with name WinSoundServer. In the project is also included a little WinSoundServerTester.sln for VisualStudio 2012 that shows the recording and playing methods in an example. I did not intend to publish that, but maybe anybody will find it useful anyway. You must first compile the WinSoundServer project, so that the vc100.tlb and the WinSoundServer.dll will be created. Before starting the test app you have to register the COM Server with help of the reg.bat file including in the project directory. This will register the WinSoundServer.dll. After that the test application must refers to the typelibrary by an import statement, so you have access to all interfaces and classes (like adding a reference in C#)
#import "WinSoundServer\\vc100.tlb" no_namespace
The WaveOut and WaveIn functions of WMM are very tricky, because you have to know some special features of how to work
with the internal buffers and handles. For example you can not stop a recording, without waiting for all buffers to finish. You are not allowed to stay too long in the
Callback functions. You have to swap from managed to unmanaged code. The Repeater is the most sensitive one, because you have to balance the recording and playing buffers all the time.
Using the code
The assemblies which are to be used as DLLs are
For common sound operations
For network operations
Example Projects are
- MulticastPlayer (Plays a RTP-Multicast to Soundcard)
- MulticastStreamer (Sends a RTP-Multicast from Soundcard)
- Player Tester (Plays or records a wav-File)
- RepeaterTester (Plays from Soundcard to Soundcard)
The heart of all this is WinSound.dll. All example projects need this DLL (add as reference).
Using the Sound Recorder
buffercount must be optimized to your Sounddevice and used
WinSound.Recorder recorder = new WinSound.Recorder();
recorder.DataRecorded += new WinSound.Recorder.DelegateDataRecorded(OnDataRecorded);
recorder.RecordingStopped += new WinSound.Recorder.DelegateStopped(OnRecordingStopped);
recorder.Start("Line 1 (Virtual Audio Cable)", 44100, 16, 2, 8, 4096);
bool isStarted = recorder.Started;
private void OnDataRecorded(Byte data)
private void OnRecordingStopped()
Using the Sound Player
buffercount must be optimized to your Sounddevice and used SamplesPerSecond.
WinSound.Player player = new WinSound.Player();
player.PlayerStopped += new WinSound.Player.DelegateStopped(OnPlayerStopped);
player.PlayerClosed += new WinSound.Player.DelegateStopped(OnPlayerClosed);
player.Open("Realtek", 44100, 16, 2, 8);
bool isOpen = player.Opened;
Byte data = GetDatas();
bool isPlaying = player.Playing
bool isPaused = player.Paused;
private void OnPlayerStopped()
private void OnPlayerClosed()
The linear data bytes you write or read from soundcard, are depending on BitsPerSample and Channel Count. Each "Data Packet" is to interpret as this picture shows.
The Player (Recorder) Tester
This example uses WinSound.dll to play or record a Wav-file.
Channels are only used in record mode.
WinSound.Player playerOne = new WinSound.Player();
playerOne.PlayerClosed += new WinSound.Player.DelegateStopped(OnPlayerClosed);
playerOne.PlayerStopped += new WinSound.Player.DelegateStopped(OnPlayerStopped);
bool hr = playerOne.Close();
WinSound.WaveFileHeader header = WinSound.WaveFile.Read(@"C:\Record.wav");
uint dataSize = header.DATASize;
Byte data = header.Payload;
WinSound.WaveFile.Create(@"C:\Record.wav", 44100, 16, 2, data);
The Repeater Tester
This example is recording Sound-Data from one sound device (WaveIn) to
Every sound device has its special features, so you have to change the
BufferCount and BufferSize for optimal performance. It also differs from
operating System Windows-XP, Vista or Windows 7.
WinSound.Repeater repeaterOne = new WinSound.Repeater();
repeaterOne.Start("Line 6", "Realtek", samplesPerSecond, bitsPerSample, channels, bufferCount, bufferSize);
The Multicast Streamer
This example Streams ULAW RTP-Multicast data from a sound device or a Wav-File. When using sound device streaming, it is possible to synchronise it with the "Time Sync" checkbox. Buffer Count is the amout of buffers, that are used by capturing from sound-device (Use 8 as standard). You
can use the Multicast Player to play this Multicast. Also you can use
the VLC Media Player
for testing (Use Samples Per Second = 8000 and BitsPerSample = 16 with VLC).
NF.MulticastSender m_MulticastSender = new NF.MulticastSender(Address, Port, TTL);
WinSound.Recorder m_Recorder = new WinSound.Recorder();
m_Recorder.DataRecorded += new WinSound.Recorder.DelegateDataRecorded(OnDataReceivedFromSoundcard);
m_Recorder.Start(SoundDeviceName, SamplesPerSecond, BitsPerSample, ChannelCount, BufferCount, BufferSize)
Byte mulawData = WinSound.Utils.LinearToMulaw(linearData, Config.BitsPerSample, Config.Channels);
Byte rtpBytes = RTPHeader.ToBytes();
Byte bytes = new Byte[mulawData.Length + WinSound.RTPPacket.MinHeaderLength];
Array.Copy(rtpBytes, 0, bytes, 0, WinSound.RTPPacket.MinHeaderLength);
Array.Copy(mulawData, 0, bytes, WinSound.RTPPacket.MinHeaderLength, mulawData.Length);
The Multicast Player
This example plays a ULAW RTP-Multicast stream to a sound device. You
can use the Multicast Streamer for this purpose. Note, the packet size
of the Multicast Player must
be greater or equal than the packet size of the multicast streamer (Use 16000 Bytes as standard) . A Jitter Buffer is used, when entering a minimum value of "2" as jitter count. Jitter count means the amount of RTP-Packets that will be queued as maximum. Values of "0" or "1" means, there is no Jitter Buffer in use. (Use 20 as standard)
NF.MulticastReceiver m_Receiver = new NF.MulticastReceiver(PacketSize);
WinSound.Player m_Player = new WinSound.Player();
m_Receiver.DataReceived += new NF.MulticastReceiver.DelegateDataReceived(OnDataReceived);
m_Player.Open(SoundDeviceName, SamplesPerSecond, BitsPerSample, Channels, BufferCount);
WinSound.RTPPacket rtp = new WinSound.RTPPacket(bytes);
Byte linearBytes = WinSound.Utils.MuLawToLinear(rtp.Data, Config.BitsPerSample, Config.Channels);
- 31.05.2012 - Added.
- 30.06.2012 - Updated. Using the CSRC Count Information in RTP Header for Multicast Player.
- 08.07.2012 - Updated. Wav-File Read/Write operations for Player Tester.
- 11.08.2012 - Updated. Error resolved, when calling Player.PlayData in blocking mode = true
- 21.08.2012 - Updated. Error resolved. Garbage Collection caused Application crash.
- 07.09.2012 - Updated. Error resolved. Reading Wave-Files in different formats.
- 09.09.2012 - Updated. Better performance when playing wav files.
- 19.10.2012 - Updated. Added Jitter buffer. Added streaming wav-files directly.
- 22.10.2013 - Updated. Drawing the linear datas as curve
- 12.04.2014 - Added Source. WinSound implementation written in C++ as a COM Server (Optional)
- 22.04.2014 - Updated. Solved possible stability problems