1

I've looked pretty thoroughly for a similar question but haven't really found the exact case I have.

I have an unmanaged dll for an audio app that creates a thread and waits for an event from the sound card to fill the output buffer.

The app works fine with the onboard sound card but if I switch to any usb audio device the thread just hangs.

Here's the main code bits: I initialize my Event in my Initialize function

::Initialize()
{
    _AudioSamplesReadyEvent = CreateEventEx(NULL, L"InputReady", 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
}

And pass it to the sound device after it has been initialized

::InitiAudioEngine()
{
    hr = _AudioClient->SetEventHandle(_AudioSamplesReadyEvent);
}

Here's the thread

//HRESULT hr = CoInitializeEx(NULL, COINIT_SPEED_OVER_MEMORY); //gets called in the constructor of my renderthread class

DWORD DoRenderThread()
{
    HANDLE waitArray[2] = {_ShutdownEvent, _AudioSamplesReadyEvent};
    HANDLE mmcssHandle = NULL;
    DWORD mmcssTaskIndex = 0;

    mmcssHandle = AvSetMmThreadCharacteristics(L"Audio", &mmcssTaskIndex);

    while (_StillPlaying)
    {
        HRESULT hr;
        DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, INFINITE);
        switch (waitResult)
        {
        case WAIT_OBJECT_0 + 0:     // _ShutdownEvent
            _StillPlaying = false;       // We're done, exit the loop.
            break;
        case WAIT_OBJECT_0 + 1:     // _AudioSamplesReadyEvent
            //  We need to provide the next buffer of samples to the audio renderer.
            BYTE *pData;
            //invoke the callback to the managed app to fill our buffer
            _Handler(NULL, 0);

            hr = _RenderClient->GetBuffer(_BufferSizePerPeriod, &pData);
            if (SUCCEEDED(hr))
            {
                  //  Copy data from the render buffer to the output buffer and bump our render pointer.

               if(_FrameSize == QUAD_FRAME)
               {
                  //we have to remux the stream data in to an L,R,LR,RR frame
                  //inserting silence for the rear channels
                  const int bufmuxsz = FIXED_FRAME_SIZE * QUAD_FRAME;
                  BYTE  muxarray[bufmuxsz] = {0};
                  BYTE  tempbuffer[FIXED_FRAME_SIZE * STEREO_FRAME];
                  CopyMemory(tempbuffer, _Buffer, FIXED_FRAME_SIZE * STEREO_FRAME);
                  int i = 0;
                  for(int x = 0; x < bufmuxsz; ++x)
                  {
                     muxarray[x++] = tempbuffer[i++];
                     muxarray[x++] = tempbuffer[i++];
                     muxarray[x++] = tempbuffer[i++];
                     muxarray[x++] = tempbuffer[i++];
                     x += 3; //the array is initialized to '0' so skip the assignments
                  }
                  CopyMemory(pData, muxarray, _BufferSizePerPeriod*_FrameSize);
               }
               else
               {
                  CopyMemory(pData, _Buffer, _BufferSizePerPeriod * _FrameSize);

               }
               hr = _RenderClient->ReleaseBuffer(_BufferSizePerPeriod, 0); 
               if (!SUCCEEDED(hr))
               {
                  printf("Playback Failed!!\n");
                  _StillPlaying = false;
               }
            }
            else
            {
               _StillPlaying = false;
            }
            break;
        }
    }
    AvRevertMmThreadCharacteristics(mmcssHandle);
    CoUninitialize();
    return 0;
}

My 2 events that I wait for are a shutdown event and the samplesready event from the sound card. It always hits once but then hangs . Again this is only with usb audio interfaces.

  • Since your `_AudioSamplesReadyEvent` is never set again, perhaps it is more relevant to see how you are initializing it to be set for you. – Roman R. Oct 12 '12 at 17:30
  • Hint: you can update your orignial question instead. – Roman R. Oct 12 '12 at 17:46
  • I am looking at your code... Okay you get and release render client buffers. Where do you do capture buffer? As far as I understand you don't get the event for capture, not for render. – Roman R. Oct 12 '12 at 17:53
  • `_Buffer` is a pointer to an array in managed code and the callback `_Handler` is what pumps the managed side to refill that array. – Carse O'Mighty Oct 12 '12 at 17:59
  • No call to CoInitializeEx(), that's scary. If it is STA then MsgWaitForMultipleObjects() is required to avoid deadlock. If the thread was started by C# then CoUninitialize() is wrong. – Hans Passant Oct 12 '12 at 18:35
  • `HRESULT hr = CoInitializeEx(NULL, COINIT_SPEED_OVER_MEMORY);` gets called in the constructor of my renderthread class – Carse O'Mighty Oct 12 '12 at 18:37
  • I have a basic troubleshooting question: does the USB audio device work outside of your application? This would rule out any issues that may be outside the scope of your application. – cowboydan Oct 12 '12 at 18:42
  • yes, in fact I have the dll code in a command line app and it works with 2 different usb interfaces just fine, its only the c# app that hangs. – Carse O'Mighty Oct 12 '12 at 18:46
  • I have found if I manually send one buffer worth of data to the render client before starting the thread things seem to work but not entirely solid. Still haven't found any real solution. – Carse O'Mighty Oct 19 '12 at 07:45
  • No one have any suggestions? Bump? – Carse O'Mighty Nov 16 '12 at 18:19

0 Answers0