Click here to Skip to main content
11,428,876 members (62,855 online)
Click here to Skip to main content

A full-duplex audio player in C# using the waveIn/waveOut APIs

, 31 Aug 2003
Rate this:
Please Sign up or sign in to vote.
An article on low-level audio capture and playback using the waveIn/waveOut APIs through P/Invoke in C#.

Sample Image - cswavrec.gif

Introduction

As I already mentioned in my article A low-level audio player in C#, there are no built-in classes in the .NET framework for dealing with sound. This holds true not only for audio playback, but also for audio capture.

It should be noted, though, that the Managed DirectX 9 SDK does include classes for high-level and low-level audio manipulation. However, sometimes you don’t want your application to depend on the full DX 9 runtime, just to do basic sound playback and capture, and there are also some areas where Managed DirectSound doesn’t help at all (for example, multi-channel sound playback and capture).

Nevertheless, I strongly recommend you to use Managed DirectSound for sound playback and capture unless you have a good reason for not doing so.

This article describes a sample application that uses the waveIn and waveOut APIs in C# through P/Invoke to capture an audio signal from the sound card’s input, and play it back (almost) at the same time.

Using the code

The sample code reuses the WaveOutPlayer class from my article A low-level audio player in C#. The new classes in this sample are WaveInRecorder and FifoStream.

The FifoStream class extends System.IO.Stream to implement a FIFO (first-in first-out) of bytes. The overridden Write method adds data to the FIFO’s tail, and the Read method peeks and removes data from the FIFO’s head. The Length property returns the amount of buffered data at any time. Calling Flush will clear all pending data.

The WaveInRecorder class is analogous to the WaveOutPlayer class. In fact, if you look at the source files, you’ll notice that the implementations of these classes are very similar. As with WaveOutPlayer, the interface of this class has been reduced to the strict minimum.

Creating an instance of WaveInRecorder will cause the system to start recording immediately. Here’s the code that creates the WaveOutPlayer and WaveInRecorder instances.

private void Start()
{
    Stop();
    try
    {
        WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(44100, 16, 2);
        m_Player = new WaveLib.WaveOutPlayer(-1, fmt, 16384, 3, 
                        new WaveLib.BufferFillEventHandler(Filler));
        m_Recorder = new WaveLib.WaveInRecorder(-1, fmt, 16384, 3, 
                        new WaveLib.BufferDoneEventHandler(DataArrived));
    }
    catch
    {
        Stop();
        throw;
    }
}

The WaveInRecorder constructor takes five parameters. Except for the last parameter, their meaning is the same as in WaveOutPlayer.

The first parameter is the ID of the wave input device that you want to use. The value -1 represents the default system device, but if your system has more than one sound card, then you can pass any number from 0 to the number of installed sound cards minus one, to select a particular device.

The second parameter is the format of the audio samples.

The third and forth parameters are the size of the internal wave buffers and the number of buffers to allocate. You should set these to reasonable values. Smaller buffers will give you less latency, but the captured audio may have gaps on it if your computer is not fast enough.

The fifth and last parameter is a delegate that will be called periodically as internal audio buffers are full of captured data. In the sample application we just write the captured data to the FIFO, like this:

private void DataArrived(IntPtr data, int size)
{
    if (m_RecBuffer == null || m_RecBuffer.Length < size)
        m_RecBuffer = new byte[size];
    System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 0, size);
    m_Fifo.Write(m_RecBuffer, 0, m_RecBuffer.Length);
}

Similarly, the Filler method is called every time the player needs more data. Our implementation just reads the data from the FIFO, as shown below:

private void Filler(IntPtr data, int size)
{
    if (m_PlayBuffer == null || m_PlayBuffer.Length < size)
        m_PlayBuffer = new byte[size];
    if (m_Fifo.Length >= size)
        m_Fifo.Read(m_PlayBuffer, 0, size);
    else
        for (int i = 0; i < m_PlayBuffer.Length; i++)
            m_PlayBuffer[i] = 0;
    System.Runtime.InteropServices.Marshal.Copy(m_PlayBuffer, 
                                                 0, data, size);
}

Note that we declared the temporary buffers m_RecBuffer and m_PlayBuffer as member fields in order to improve performance by saving some garbage collections.

To stop streaming, just call Dispose on the player and capture objects. We also need to flush the FIFO so that the next time Start is called there is no residual data to play.

private void Stop()
{
    if (m_Player != null)
        try
        {
            m_Player.Dispose();
        }
        finally
        {
            m_Player = null;
        }
    if (m_Recorder != null)
        try
        {
            m_Recorder.Dispose();
        }
        finally
        {
            m_Recorder = null;
        }
    m_Fifo.Flush(); // clear all pending data
}

Conclusion

This sample demonstrates how to combine the waveIn and waveOut APIs in C#. As an exercise, you may want to combine this code with the audio effect framework in the article Programming Audio Effects in C#, to apply effects to a live audio input in real-time, although latency may be an issue for certain applications.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Ianier Munoz
Web Developer
Luxembourg Luxembourg
Ianier Munoz lives in France and works as a senior consultant and analyst for an international consulting firm. His specialty is in multimedia applications, and he has authored some popular software, such as American DJ's Pro-Mix, Chronotron and Adapt-X.

Comments and Discussions

 
GeneralRe: Doesn't work if running on a 64 bit application. Pin
me200724-Feb-10 1:38
memberme200724-Feb-10 1:38 
QuestionWhy is the size fixed to 16384? Pin
ralphigo27-Oct-09 4:31
memberralphigo27-Oct-09 4:31 
Generala better mothod Pin
mutasimmo17-Oct-09 0:15
membermutasimmo17-Oct-09 0:15 
QuestionHow to Save the voice record file in the client system Using MCI in c# .net 2.0 web application Pin
bruze21-Sep-09 10:59
memberbruze21-Sep-09 10:59 
GeneralProblem using wave API's [modified] Pin
Member 211727530-Jun-09 4:26
memberMember 211727530-Jun-09 4:26 
GeneralRe: Problem using wave API's Pin
Member 21172751-Jul-09 2:31
memberMember 21172751-Jul-09 2:31 
QuestionWill it work on Vista ? Pin
Jack987316-Jun-09 2:39
memberJack987316-Jun-09 2:39 
GeneralWhy not use the Queue object Pin
Member 474314211-Jun-09 10:48
memberMember 474314211-Jun-09 10:48 
GeneralYet another latency question.. Pin
MrGALit9-May-09 10:22
memberMrGALit9-May-09 10:22 
GeneralRe: Yet another latency question.. Pin
MrGALit12-May-09 12:05
memberMrGALit12-May-09 12:05 
Generalsend voice over bluetooth Pin
Idantovi1-May-09 23:07
memberIdantovi1-May-09 23:07 
QuestionTry-Catch on WaveOutProc Pin
keltins14-Apr-09 7:11
memberkeltins14-Apr-09 7:11 
QuestionWhat License this Code under Pin
Member 603819625-Mar-09 4:09
memberMember 603819625-Mar-09 4:09 
AnswerRe: What License this Code under Pin
cloudraven12-May-09 16:13
membercloudraven12-May-09 16:13 
QuestionWhy I need to check stereo mix option? Pin
ummarbhutta23-Mar-09 23:18
memberummarbhutta23-Mar-09 23:18 
GeneralProblem on vista Pin
sshawn19-Mar-09 16:31
membersshawn19-Mar-09 16:31 
GeneralRe: Problem on vista Pin
gamosemalaka11-Jun-09 4:41
membergamosemalaka11-Jun-09 4:41 
Questionhow to get wavein data? Pin
zoe5-Mar-09 0:05
memberzoe5-Mar-09 0:05 
GeneralPlaying back with delay Pin
BazKhan23-Jan-09 19:04
memberBazKhan23-Jan-09 19:04 
GeneralRe: Playing back with delay Pin
jachubiz14-Mar-10 10:20
memberjachubiz14-Mar-10 10:20 
GeneralLooking to make a voice changer for robot costume Pin
goatmonkey19-Jan-09 11:34
membergoatmonkey19-Jan-09 11:34 
GeneralRe: Looking to make a voice changer for robot costume Pin
goatmonkey20-Jan-09 11:44
membergoatmonkey20-Jan-09 11:44 
Questionhow can i display filename in listbox.. Pin
treoboy14-Jan-09 9:02
membertreoboy14-Jan-09 9:02 
General!!!!!URGENT Pin
khan7772-Jan-09 18:58
memberkhan7772-Jan-09 18:58 
GeneralSound Recorder Pin
anki1233-Dec-08 4:00
memberanki1233-Dec-08 4:00 
GeneralFull Duplex Pin
GoldGate3-Nov-08 0:36
memberGoldGate3-Nov-08 0:36 
Questionhow to use directSound in C#? Pin
emma_liu22-Oct-08 20:01
memberemma_liu22-Oct-08 20:01 
AnswerRe: how to use directSound in C#? Pin
keltins15-Apr-09 18:27
memberkeltins15-Apr-09 18:27 
GeneralI found a bug of this project -- about the delay!!! Pin
iamchristina7-Oct-08 22:57
memberiamchristina7-Oct-08 22:57 
GeneralRe: I found a bug of this project -- about the delay!!! Pin
Ianier Munoz1-Nov-08 8:00
memberIanier Munoz1-Nov-08 8:00 
GeneralHelp with multiple microphones Pin
serima nazarian15-Sep-08 7:58
memberserima nazarian15-Sep-08 7:58 
GeneralRe: Help with multiple microphones Pin
Member 215831823-Nov-08 22:44
memberMember 215831823-Nov-08 22:44 
QuestionHow to calculate maximum decibel / decible value from a wav file Pin
NiyaHere21-Aug-08 0:54
memberNiyaHere21-Aug-08 0:54 
GeneralLicense Pin
slavior20-May-08 17:13
memberslavior20-May-08 17:13 
Generalidentifying the end of the incoming signal Pin
bethany24-Apr-08 23:00
memberbethany24-Apr-08 23:00 
GeneralVirtual Audio Device Pin
Veerubhotla Chakravarthy25-Mar-08 18:45
memberVeerubhotla Chakravarthy25-Mar-08 18:45 
QuestionUSB (HID) Audio Device Pin
JohnPool21-Mar-08 3:54
memberJohnPool21-Mar-08 3:54 
GeneralProblem with recording (buffer problem perhaps?) [modified] Pin
guden21-Jan-08 4:52
memberguden21-Jan-08 4:52 
Questionhow to record audio Pin
Janardhan Mysore1-Dec-07 1:49
memberJanardhan Mysore1-Dec-07 1:49 
AnswerRe: how to record audio an create wave file Pin
dr.namvar14-Dec-07 22:52
memberdr.namvar14-Dec-07 22:52 
GeneralRe: how to record audio an create wave file Pin
Janardhan Mysore14-Dec-07 23:35
memberJanardhan Mysore14-Dec-07 23:35 
GeneralRe: how to record audio an create wave file Pin
fine_peng22-Feb-08 16:27
memberfine_peng22-Feb-08 16:27 
GeneralRe: how to record audio an create wave file Pin
lang10-Mar-08 5:59
memberlang10-Mar-08 5:59 
GeneralRe: how to record audio an create wave file Pin
Gx Lam12-May-08 21:27
memberGx Lam12-May-08 21:27 
GeneralRe: how to record audio an create wave file Pin
usman_dastgeer20-Jun-08 22:28
memberusman_dastgeer20-Jun-08 22:28 
GeneralRe: how to record audio an create wave file Pin
ha2e15-Nov-08 6:53
memberha2e15-Nov-08 6:53 
GeneralRe: how to record audio an create wave file Pin
maria1919-Jan-11 5:03
membermaria1919-Jan-11 5:03 
AnswerRe: how to record audio an create wave file Pin
boizer7-Jun-11 13:07
memberboizer7-Jun-11 13:07 
GeneralRe: how to record audio an create wave file Pin
braveheart4u8-Aug-11 3:30
memberbraveheart4u8-Aug-11 3:30 
AnswerRe: how to record audio Pin
wallaces52826-Aug-08 0:39
memberwallaces52826-Aug-08 0:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150428.2 | Last Updated 1 Sep 2003
Article Copyright 2003 by Ianier Munoz
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid