locked
Rendering a stream using WASAPI RRS feed

  • Question

  • Hi all,

    I am a startup this.

    I have used the WASAPIs to render an audio stream from a file"44k_stereo_16bit.pcm".

    But the code below does not work. It only generates lots of noise.

    Please help in this regard.

    Thanks,

    Tulika

    The code is as below:

    #include

     

    <stdio.h>

    #include

     

    <Objbase.h>

    //#include<Audioclient.h>

    //#include<Mmdeviceapi.h>

    #include

     

    <Mmreg.h>

    #include

     

    <MMDeviceAPI.h>

    #include

     

    <AudioClient.h>

    #include

     

    <AudioPolicy.h>

    #include

     

    "Endpointvolume.h"

     

    // #define WAVE_FORMAT_PCM

    //typedef IID* REFIID;

    #pragma

     

    comment(lib, "ole32.lib"

    )

    const

     

    CLSID CLSID_MMDeviceEnumerator = __uuidof

    (MMDeviceEnumerator);

    const

     

    IID IID_IMMDeviceEnumerator = __uuidof

    (IMMDeviceEnumerator);

    const

     

    IID IID_IAudioClient = __uuidof

    (IAudioClient);

    const

     

    IID IID_IAudioRenderClient = __uuidof

    (IAudioRenderClient);

    void

     

    PlayAnAudioStream()

    {

    HRESULT hresult;

    IMMDeviceEnumerator *pDeviceEnumerator=NULL;

    IMMDevice *pDevice=NULL;

    IAudioClient *pAudioInterface=NULL;

    IAudioRenderClient *pAudioRenderClient=NULL;

     

    //WAVEFORMATEX *pDeviceFormat = NULL;

    WAVEFORMATEXTENSIBLE *pDeviceFormat;

    DWORD flags = 0;

    REFERENCE_TIME hnsBufferDuration = 10000000,hnsActualDuration;

    UINT32 pNumBufferFrames;

    UINT32 pNumPaddingFrames,pNumAvFrames;

    BYTE *pData;

    FILE *InputStreamData = NULL;

    BYTE *intermediatedata= NULL;

     

    //pData = (BYTE*)malloc(4*44100);

    intermediatedata = (BYTE*) malloc(44100*

    sizeof

    (BYTE)*2);

    HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);

     

    /* Creating a object for Enumerating a device */

    hresult = CoCreateInstance(CLSID_MMDeviceEnumerator,

    NULL,

    /*Object is not created as the part of the aggregate */

    CLSCTX_ALL,IID_IMMDeviceEnumerator,(

    void

    **)&pDeviceEnumerator);

    IMMDeviceCollection* dev_collection = NULL;

    hr = pDeviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &dev_collection);

    /* Retrieve the endpoint device using the Enumerator */

    hresult = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender,eMultimedia,&pDevice);

    hresult = pDevice->Activate(IID_IAudioClient,CLSCTX_ALL,NULL,(

    void

    **)&pAudioInterface);

    IAudioEndpointVolume* endpoint_vol = NULL;

    hresult = pDevice->Activate(

    __uuidof(IAudioEndpointVolume),CLSCTX_ALL,NULL,(void

    **)&endpoint_vol);

    hresult = pAudioInterface->GetMixFormat((WAVEFORMATEX**)&pDeviceFormat);

    hresult = pAudioInterface->Initialize( AUDCLNT_SHAREMODE_SHARED,0,hnsBufferDuration,0,(WAVEFORMATEX *)pDeviceFormat,NULL );

    hresult = pAudioInterface->GetService(IID_IAudioRenderClient,(

    void

    **)&pAudioRenderClient);

    hresult = pAudioInterface->GetBufferSize(&pNumBufferFrames);

    printf(

    "\n the no of frames are %d"

    ,pNumBufferFrames);

    //hresult = pAudioRenderClient->GetBuffer( pNumBufferFrames, &pData );

     

    /* Set Audio Format */

     

    //pDeviceFormat->wFormatTag = WAVE_FORMAT_PCM;

    pDeviceFormat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;

    pDeviceFormat->Format.nChannels = 2;

    pDeviceFormat->Format.nSamplesPerSec = 44100;

    pDeviceFormat->Format.wBitsPerSample = 16;

    pDeviceFormat->Format.nBlockAlign = (pDeviceFormat->Format.nChannels * pDeviceFormat->Format.wBitsPerSample)/8;

    pDeviceFormat->Format.nAvgBytesPerSec = pDeviceFormat->Format.nSamplesPerSec * pDeviceFormat->Format.nBlockAlign;

    pDeviceFormat->Format.cbSize =

    sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);

    //0;

    pDeviceFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO;

    pDeviceFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

    pDeviceFormat->Samples.wValidBitsPerSample = 16;

     

    hresult = pAudioInterface->Initialize( AUDCLNT_SHAREMODE_SHARED,NULL,hnsBufferDuration,0,(WAVEFORMATEX *)pDeviceFormat,NULL );

    hresult = pAudioInterface->GetService(IID_IAudioRenderClient,(

    void

    **)&pAudioRenderClient);

     

    /* Load the buffer to pdata */

    InputStreamData = fopen(

    "44k_stereo_16bit.pcm","r"

    );

    fread(intermediatedata,

    sizeof(BYTE),4*pNumBufferFrames,InputStreamData);

    // + intermediatedata 0x005F3CA8 "" char*

    hresult = pAudioRenderClient->GetBuffer( pNumBufferFrames, &pData );

    memcpy(pData,intermediatedata,pNumBufferFrames);

    //+ pData 0x00D81C00 unsigned char*

     

    //hresult = pAudioRenderClient->GetBuffer( pNumBufferFrames, &pData );

    /* Release this buffer to audio device */

    hresult = pAudioRenderClient->ReleaseBuffer(pNumBufferFrames,flags);

    hnsActualDuration = (

    double

    )10000000 *

    pNumBufferFrames / pDeviceFormat->Format.nSamplesPerSec;

    /* Play the data */

    hresult = pAudioInterface->Start();

    //lseek(InputStreamData,pNumBufferFrames,SEEK_CUR);

    //sleep(3);

    /* Stop playing */

     

    while

    (EOF)

    {

    Sleep(hnsActualDuration/10000/2);

    hresult = pAudioInterface->GetCurrentPadding(&pNumPaddingFrames);

    pNumAvFrames = pNumBufferFrames - pNumPaddingFrames;

    hresult = pAudioRenderClient->GetBuffer( pNumAvFrames, &pData );

     

    //hresult = pAudioRenderClient->GetBuffer( pNumAvFrames, &pData );

     

    //fread(pData,sizeof(char),pNumAvFrames,InputStreamData);

    fread(intermediatedata,

    sizeof(BYTE),4*pNumAvFrames,InputStreamData);

    // + intermediatedata 0x005F3CA8 "" char*

    memcpy(pData,intermediatedata,pNumAvFrames);

    //+ pData 0x00D81C00 unsigned char*

     

    hresult = pAudioRenderClient->ReleaseBuffer(pNumAvFrames,flags);

     

    //lseek(InputStreamData,pNumAvFrames,SEEK_CUR);

    }

    printf(

    "I am here"

    );

    hresult = pAudioInterface->Stop();

    CoTaskMemFree(pDeviceFormat);

    fclose(InputStreamData);

    }

    int

     

    main()

    {

    PlayAnAudioStream();

    printf(

    "Played going to exit"

    );

    exit(1);

    }

    

    Thursday, April 28, 2011 4:36 AM

All replies

  • Shared Mode requires a floating point data format.

     

     

    Thursday, April 28, 2011 11:42 AM
  • Actually you can sometimes get away with an implicit int -> float conversion as long as the sample rate and channel counts match.  You can call IAudioClient::IsFormatSupported(...) to make sure; if the format is not supported, IAudioClient::Initialize will fail.
    Matthew van Eerde
    Thursday, April 28, 2011 11:26 PM
  • Actually you can sometimes get away with an implicit int -> float conversion

    Alas, memcpy() won't do that.

    Neither will fread(), will it?

     

    Friday, April 29, 2011 1:54 PM
  • I am facing some problem with fread().

    The fread() function call doesnot return the no of bytes what I specified it to read.

    :(


    Tulika Keshri
    Friday, April 29, 2011 2:46 PM
  • Well, what I mean is, if you have integer data, you can sometimes get away with opening a shared-mode stream in an integer format.  IsFormatSupported(...) is the way you can tell which formats are supported; the mix format should always be supported, and you shouldn't expect a format of a different sample rate or channel count than the mix format to be supported, but you might be able to use an int format of the same sample rate and channel count as the mix format.
    Matthew van Eerde
    Friday, April 29, 2011 5:07 PM
  • Hello,

    Thanks for the help.

    I have made some changes to the code.I used IsFormatSupported(...) to the mix format. it returns success.

    There was some problem with file open. It should be in "rb" mode instead of "r" mode.

    But yet this code doesnt run successfully.

    I am sharing the new code below.

    #include

     

    <stdio.h>

    #include

     

    <Objbase.h>

    //#include<Audioclient.h>

    //#include<Mmdeviceapi.h>

    #include

     

    <Mmreg.h>

    #include

     

    <MMDeviceAPI.h>

    #include

     

    <AudioClient.h>

    #include

     

    <AudioPolicy.h>

    #include

     

    "Endpointvolume.h"

     

    // #define WAVE_FORMAT_PCM

    //typedef IID* REFIID;

    #pragma

     

    comment(lib, "ole32.lib"

    )

    const

     

    CLSID CLSID_MMDeviceEnumerator = __uuidof

    (MMDeviceEnumerator);

    const

     

    IID IID_IMMDeviceEnumerator = __uuidof

    (IMMDeviceEnumerator);

    const

     

    IID IID_IAudioClient = __uuidof

    (IAudioClient);

    const

     

    IID IID_IAudioRenderClient = __uuidof

    (IAudioRenderClient);

    void

     

    PlayAnAudioStream()

    {

    HRESULT hresult,hr;

    IMMDeviceEnumerator *pDeviceEnumerator=NULL;

    IMMDevice *pDevice=NULL;

    IAudioClient *pAudioInterface=NULL;

    IAudioRenderClient *pAudioRenderClient=NULL;

    WAVEFORMATEX *pDeviceFormat = NULL;

    DWORD flags = 0;

    REFERENCE_TIME hnsBufferDuration = 10000000

    /*In 100 nano units, 1 sec of PCM data*/

    ,hnsActualDuration;

    UINT32 pNumBufferFrames=0;

    UINT32 pNumPaddingFrames,pNumAvFrames;

    BYTE *pData;

    FILE *InputStreamData = NULL;

    BYTE *intermediatedata=NULL;

     

     

    /* Creating a object for Enumerating a device */

    hresult = CoCreateInstance(CLSID_MMDeviceEnumerator,NULL,

    /*Object is not created as the part of the aggregate */

    CLSCTX_ALL,IID_IMMDeviceEnumerator,(

    void

    **)&pDeviceEnumerator);

    IMMDeviceCollection* dev_collection = NULL;

    hr = pDeviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &dev_collection);

     

    /* Retrieve the endpoint device using the Enumerator */

    hresult = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender,eMultimedia,&pDevice);

    hresult = pDevice->Activate(IID_IAudioClient,CLSCTX_ALL,NULL,(

    void

    **)&pAudioInterface);

     

    IAudioEndpointVolume* endpoint_vol = NULL;

    hresult = pDevice->Activate(

    __uuidof(IAudioEndpointVolume),CLSCTX_ALL,NULL,(void

    **)&endpoint_vol);

    hresult = pAudioInterface->GetMixFormat(&pDeviceFormat);

     

    hresult = pAudioInterface->Initialize(AUDCLNT_SHAREMODE_SHARED

    /*AUDCLNT_SHAREMODE_EXCLUSIVE*/

    ,0,hnsBufferDuration,0,(WAVEFORMATEX *)pDeviceFormat,NULL );

     

    if

    (hresult == S_OK)

    printf(

    "\n The buffer for 1sec duration is successfully allocated."

    );

     

    else

    printf(

    "\n The Intialisation returns with an error"

    );

    printf(

    "\n The no of frames before are %d"

    ,pNumBufferFrames);

    hresult = pAudioInterface->GetBufferSize(&pNumBufferFrames);

    printf(

    "\n The no of frames after are %d"

    ,pNumBufferFrames);

     

     

    /* Set Audio Format */

     

     

    /*//pDeviceFormat->wFormatTag = WAVE_FORMAT_PCM;

    pDeviceFormat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;

    pDeviceFormat->Format.nChannels = 2;

    pDeviceFormat->Format.nSamplesPerSec = 44100;

    pDeviceFormat->Format.wBitsPerSample = 16;

    pDeviceFormat->Format.nBlockAlign = (pDeviceFormat->Format.nChannels * pDeviceFormat->Format.wBitsPerSample)/8;

    pDeviceFormat->Format.nAvgBytesPerSec = pDeviceFormat->Format.nSamplesPerSec * pDeviceFormat->Format.nBlockAlign;

    pDeviceFormat->Format.cbSize = 0;//sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);//0;

    pDeviceFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO;

    pDeviceFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

    pDeviceFormat->Samples.wValidBitsPerSample = 16;

    */

     

    pDeviceFormat->wFormatTag = WAVE_FORMAT_PCM;

    pDeviceFormat->nChannels = 2;

    pDeviceFormat->nSamplesPerSec = 44100;

    pDeviceFormat->wBitsPerSample = 16;

    pDeviceFormat->nBlockAlign = (pDeviceFormat->nChannels * pDeviceFormat->wBitsPerSample)/8;

    pDeviceFormat->nAvgBytesPerSec = pDeviceFormat->nSamplesPerSec * pDeviceFormat->nBlockAlign;

    pDeviceFormat->cbSize = 0;

     

    hresult = pAudioInterface->GetService(IID_IAudioRenderClient,(

    void

    **)&pAudioRenderClient);

    WAVEFORMATEX* closest_format = NULL;

    hr = pAudioInterface->IsFormatSupported(

    /*AUDCLNT_SHAREMODE_EXCLUSIVE*/

    AUDCLNT_SHAREMODE_SHARED,pDeviceFormat, &closest_format);

     

    if

    (hr == S_OK)

    printf(

    "The format is supported!\n"

    );

     

    else if

    (hr == S_FALSE)

    printf(

    "The requested format is not supported, but an alternative was provided.\n"

    );

     

    else

    printf(

    "Cant get a mix format.\n"

    );

     

    /* The function above returns success */

     

    /* Load the buffer to pdata */

    InputStreamData = fopen(

    "44k_stereo_16bit.pcm","rb"

    );

     

    if

    (InputStreamData)

    printf(

    "\n File opened for reading"

    );

     

    else

    printf(

    "\n Couldn't open the file"

    );

     

     

    // obtain file size:

     

    int

    lSize,count,Tcount,FrameSize;

    fseek (InputStreamData , 0 , SEEK_END);

    lSize = ftell (InputStreamData);

    printf(

    "\n File Size %d"

    ,lSize);

    rewind (InputStreamData);

    FrameSize = 4*44100;

    intermediatedata = (BYTE*) malloc(FrameSize);

    count=fread(intermediatedata,1,FrameSize,InputStreamData);

     

    if

    (count!=FrameSize)

    {

     

    if

    (ferror (InputStreamData))

    printf (

    "Error Reading from 44k_stereo_16bit.pcm\n"

    );

     

    }

     

    printf(

    "\n The no of bytes read %d"

    ,count);

    Tcount=Tcount+count;

    printf(

    "\nTotal no of bytes read %d"

    ,Tcount);

    hresult = pAudioRenderClient->GetBuffer( pNumBufferFrames, &pData );

    memcpy(pData,intermediatedata,4*44100

    /*4*pNumBufferFrames*/

    );

     

     

    /* Release this buffer to audio device */

    hresult = pAudioRenderClient->ReleaseBuffer(pNumBufferFrames,flags);

    hnsActualDuration = (

    double

    )10000000 * pNumBufferFrames / pDeviceFormat->nSamplesPerSec;

     

    /* Play the data */

    hresult = pAudioInterface->Start();

     

     

    while

    (1)

    {

     

    Sleep(hnsActualDuration/10000/2);

    count=fread(intermediatedata,1,4*44100,InputStreamData);

    Tcount=Tcount+count;

    printf(

    "\nTotal no of bytes read %d"

    ,Tcount);

     

    //hresult = pAudioInterface->GetCurrentPadding(&pNumPaddingFrames);

     

    //pNumAvFrames = pNumBufferFrames - pNumPaddingFrames;

     

    if

    (Tcount <= lSize)

    {

    hresult = pAudioRenderClient->GetBuffer( pNumBufferFrames, &pData );

     

    //hresult = pAudioRenderClient->GetBuffer( pNumAvFrames, &pData );

    memcpy(pData,intermediatedata,count);

    hresult = pAudioRenderClient->ReleaseBuffer(pNumBufferFrames,flags);

     

    if

    (Tcount == lSize)

     

    break

    ;

    }

     

    }

     

    /* Stop playing */

    printf(

    "Player is going to stop now"

    );

    hresult = pAudioInterface->Stop();

    CoTaskMemFree(pDeviceFormat);

    fclose(InputStreamData);

    }

    int

     

    main()

    {

    PlayAnAudioStream();

    printf(

    "Player is going to exit"

    );

    exit(1);

    }


    Tulika Keshri
    Saturday, April 30, 2011 7:07 AM
  • Please make a point of checking all the returned HRESULTS using the FAILED(...) macro.  That will help diagnose where the problem is.  If a function returns a failing HRESULT, let us know which function it was, and what the failing HRESULT was.

    Matthew van Eerde
    Monday, May 2, 2011 4:35 AM
  • Hello,

    The log of each function is as below:

    The GetBuffer() fails is while loop after reading few buffers.

    There is some memory violation in memcpy.This happens after 10 frames of data.

    But the 10 frames are alos not played at all. 

    CoInitializeEx(..)

    output: The COM library is already initialized: 1

    CoCreateInstance(..)

    output: The Instance was successfully created: 0

    pDeviceEnumerator->EnumAudioEndpoints(..)

    output: EnumAudioEndpoints Successful: 0

    pDeviceEnumerator->GetDefaultAudioEndpoint(..)

    output: GetDefaultAudioEndpoint Successful: 0

    pDevice->Activate(IID_IAudioClient..)

    output: Activate(IID_IAudioClient) Successful: 0

    pDevice->Activate(

    __uuidof

    (IAudioEndpointVolume)..)

    output: Activate(IAudioEndpointVolume) Successful: 0

    pAudioInterface->GetMixFormat(..)

    output: GetMixFormat Successful: 0

    pAudioInterface->Initialize(AUDCLNT_SHAREMODE_SHARED..)

    output: (Initialize)The buffer for 1sec duration is successfully allocated.

    pAudioInterface->GetBufferSize

     

    (..)

    output: GetBufferSize Successful: 0

    pAudioInterface->GetService(..)

    output: GetService Successful: 0

    pAudioInterface->IsFormatSupported(..)

    output:The format is supported!

    pAudioRenderClient->GetBuffer(..)

    output: GetBuffer Successful: 0

    pAudioRenderClient->ReleaseBuffer(..)

    output: ReleaseBuffer Successful: 0

    pAudioInterface->Start()

    output:Start Successful: 0

      

     

     

     


    Tulika Keshri
    Monday, May 2, 2011 5:23 PM
  • An AV in memcpy?  Are you trying to copy too many frames for the buffer?
    Matthew van Eerde
    Monday, May 2, 2011 7:00 PM
  • No I am copying one frame data that is 2*2*44100 for 44.1kHz,stereo,16 bit PCM.

    The Getbuffer() returns 44100 frames. 


    Tulika Keshri
    Tuesday, May 3, 2011 4:50 AM
  • Ah!

    That's the problem - you're copying twice as many frames as there are in the buffer.

    An individual 16-bit value is a "sample."  The samples are laid out in this fashion:

    L R
    L R
    ...

    Each line is a "frame".  Note that each frame contains a sample for each channel.


    Matthew van Eerde
    Tuesday, May 3, 2011 4:04 PM
  • I was calling the APIs in wrong sequence:

    1.pAudioInterface->GetMixFormat(..)

    2.pAudioInterface->Initialize(AUDCLNT_SHAREMODE_SHARED..)

    3. Setting audio format to the one I desire.

    Now the new sequence is:

    1.pAudioInterface->GetMixFormat(..)

    2. Setting audio format to the one I desire.

    3. pAudioInterface->Initialize(AUDCLNT_SHAREMODE_SHARED..)

    After making the changes above and incorporating your suggestion the "AUDIO Finally works"

    But now there are gaps in the playback. Audio doesnot play in a continous flow.

    Thanks for your help.

     


    Tulika Keshri
    Wednesday, May 4, 2011 9:39 AM
  • How big is your audio buffer, and how often are you waking up?  Consider registering with the Multimedia Class Scheduler Service to guarantee you will be woken up in a timely manner.


    Matthew van Eerde
    Wednesday, May 4, 2011 10:39 PM
  • The audio playback now works fine :)

    Each time I am copying 4*44100 bytes of data.

    If I need to play MP3 or any encoded format, How do we proceed further?


    Tulika Keshri
    Friday, May 6, 2011 10:47 AM
  • WASAPI shared mode does not support encoded formats.

    If the audio device you're playing to supports the encoded format in question, you can use WASAPI exclusive mode - see http://blogs.msdn.com/b/matthew_van_eerde/archive/2009/04/03/sample-wasapi-exclusive-mode-event-driven-playback-app-including-the-hd-audio-alignment-dance.aspx

    A more general solution is to use Media Foundation to decode the stream and play it back for you.  Media Foundation comes with an MP3 file source and an MP3 decoder.

    http://msdn.microsoft.com/en-us/library/dd757927(VS.85).aspx

     


    Matthew van Eerde
    Friday, May 6, 2011 4:26 PM
  • Hello,

    I am using Media foundation to decode the stream.

    But creating a filter graph manager returns "Class not registered" error.

    Please help in this regard.

    IGraphBuilder *pGraph = NULL;

    IBaseFilter *pAudioDecFilter = NULL;

    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pGraph));

     

    if

    (hr == S_OK)

    printf(

    "The Instance was successfully created: %x\n"

    , hr );

     

    else if

    (hr == REGDB_E_CLASSNOTREG)

    printf(

    "Not registered: %x\n"

    , hr );

     

    else if

    (hr == CLASS_E_NOAGGREGATION)

    printf(

    "Cannot be created: %x\n"

    , hr );

     

    else if

    (hr == E_NOINTERFACE)

    printf(

    "Cannot be created: %x\n"

    , hr );

     

    else if

    (hr == E_POINTER)

    printf(

    "Cannot be created: %x\n"

    , hr );


    Tulika Keshri
    Wednesday, May 11, 2011 4:03 PM
  • Take a look at the MF samples in the Windows SDK:

    http://msdn.microsoft.com/en-us/library/aa371827(VS.85).aspx

    There's also a forum specific to Media Foundation:

    http://social.msdn.microsoft.com/Forums/en-US/mediafoundationdevelopment/threads


    Matthew van Eerde
    Thursday, May 12, 2011 1:47 AM
  • Hello,

    Thanks for the guidance.

    I am able to create a Filter and play MP3 music using Media foundation.

    Are there any APIs that I can use at the driver level to send PCM or Encoded data to Driver APIs directly for playback.

    Please guide me in this regard.

    Thanks


    Tulika Keshri
    Wednesday, May 18, 2011 5:58 AM
  • The most direct API that comes with Windows is the Kernel Streaming API.  You can download the DirectKS sample here:

    http://www.microsoft.com/downloads/en/details.aspx?FamilyID=d7667686-8467-4b10-8713-bf0281536320

    There's a non-Windows API which some third-party audio drivers expose called ASIO.  I don't know much about this.

    The next-most-direct API is exclusive-mode WASAPI.  There are samples in the SDK and here:

    http://blogs.msdn.com/b/matthew_van_eerde/archive/2009/04/03/sample-wasapi-exclusive-mode-event-driven-playback-app-including-the-hd-audio-alignment-dance.aspx


    Matthew van Eerde
    Wednesday, May 18, 2011 3:22 PM