text: /*
   * Unit tests for duplex functions
   *
   * Copyright (c) 2006 Robert Reif
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   */
  
  #define COBJMACROS
  #include <windows.h>
  #include <stdio.h>
  
  #include "wine/test.h"
  #include "mmsystem.h"
  #include "dsound.h"
  #include "dsconf.h"
  
  #include "dsound_test.h"
  
  static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID, LPCGUID,
      LPCDSCBUFFERDESC, LPCDSBUFFERDESC, HWND, DWORD, LPDIRECTSOUNDFULLDUPLEX *,
      LPDIRECTSOUNDCAPTUREBUFFER8*, LPDIRECTSOUNDBUFFER8*, LPUNKNOWN)=NULL;
  
  static void IDirectSoundFullDuplex_test(LPDIRECTSOUNDFULLDUPLEX dsfdo,
                                          BOOL initialized, LPCGUID lpGuidCapture,
                                          LPCGUID lpGuidRender)
  {
      HRESULT rc;
      int ref;
      IUnknown * unknown;
      IDirectSound * ds;
      IDirectSound8 * ds8;
      IDirectSoundCapture * dsc;
      IDirectSoundFullDuplex * dsfd;
  
      /* Try to Query for objects */
      rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IUnknown,(LPVOID*)&unknown);
      ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IUnknown) failed: %08x\n", rc);
      if (rc==DS_OK) {
          ref = IUnknown_Release(unknown);
          ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, "
             "should have 0\n", ref);
      }
  
      rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound,(LPVOID*)&ds);
      ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound) failed: %08x\n", rc);
      if (rc==DS_OK) {
          ref=IDirectSound_Release(ds);
          ok(ref==0, "IDirectSound_Release() has %d references, "
             "should have 0\n", ref);
      }
  
      rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound8,(LPVOID*)&ds8);
      ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound8) "
         "failed: %08x\n",rc);
      if (rc==DS_OK) {
          IDirectSoundFullDuplex * dsfd1;
          rc=IDirectSound8_QueryInterface(ds8,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd1);
          ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSoundFullDuplex) "
             "failed: %08x\n",rc);
          if (rc==DS_OK) {
              ref=IDirectSoundFullDuplex_Release(dsfd1);
              ok(ref==1, "IDirectSoundFullDuplex_Release() has %d references, "
                 "should have 1\n", ref);
          }
          ref=IDirectSound8_Release(ds8);
          ok(ref==0, "IDirectSound8_Release() has %d references, "
             "should have 0\n", ref);
      }
  
      rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundCapture,(LPVOID*)&dsc);
      ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundCapture) "
         "failed: %08x\n",rc);
      if (rc==DS_OK) {
          ref=IDirectSoundCapture_Release(dsc);
          ok(ref==0, "IDirectSoundCapture_Release() has %d references, "
             "should have 0\n", ref);
      }
  
      rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd);
      ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundFullDuplex) "
         "failed: %08x\n",rc);
      if (rc==DS_OK) {
          ok(dsfdo==dsfd, "different interfaces\n");
          ref=IDirectSoundFullDuplex_Release(dsfd);
          ok(ref==1, "IDirectSoundFullDuplex_Release() has %d references, should have 1\n", ref);
      }
  
      ref=IDirectSoundFullDuplex_Release(dsfdo);
      ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, "
         "should have 0\n", ref);
  }
  
  static void IDirectSoundFullDuplex_tests(void)
  {
      HRESULT rc;
      LPDIRECTSOUNDFULLDUPLEX dsfdo = NULL;
      DSCBUFFERDESC DSCBufferDesc;
      DSBUFFERDESC DSBufferDesc;
      LPDIRECTSOUNDCAPTUREBUFFER8 pDSCBuffer8;
      LPDIRECTSOUNDBUFFER8 pDSBuffer8;
      WAVEFORMATEX wfex;
  
      trace("Testing IDirectSoundFullDuplex\n");
  
      /* try the COM class factory method of creation with no devices specified */
      rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
                          CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex,
                          (void**)&dsfdo);
      ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG||rc==CLASS_E_CLASSNOTAVAILABLE,
         "CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc);
      if (rc==REGDB_E_CLASSNOTREG) {
          trace("  Class Not Registered\n");
          return;
      } else if (rc==CLASS_E_CLASSNOTAVAILABLE) {
          trace("  Class Not Available\n");
          return;
      }
      if (dsfdo)
          IDirectSoundFullDuplex_test(dsfdo, FALSE, NULL, NULL);
  
      /* try the COM class factory method of creation with default devices
       * specified */
      rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
                          CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex,
                          (void**)&dsfdo);
      ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc);
      if (dsfdo)
          IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultCapture,
                                      &DSDEVID_DefaultPlayback);
  
      /* try the COM class factory method of creation with default voice
       * devices specified */
      rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
                          CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex,
                          (void**)&dsfdo);
      ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc);
      if (dsfdo)
          IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultVoiceCapture,
                                      &DSDEVID_DefaultVoicePlayback);
  
      /* try the COM class factory method of creation with a bad
       * IID specified */
      rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
                          CLSCTX_INPROC_SERVER, &CLSID_DirectSoundPrivate,
                          (void**)&dsfdo);
      ok(rc==E_NOINTERFACE,
         "CoCreateInstance(CLSID_DirectSoundFullDuplex,CLSID_DirectSoundPrivate) "
         "should have failed: 0x%08x\n", rc);
  
      ZeroMemory(&wfex, sizeof(wfex));
      wfex.wFormatTag = WAVE_FORMAT_PCM;
      wfex.nChannels = 1;
      wfex.nSamplesPerSec = 8000;
      wfex.wBitsPerSample = 16;
      wfex.nBlockAlign = (wfex.wBitsPerSample * wfex.nChannels) / 8;
      wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
  
      ZeroMemory(&DSCBufferDesc, sizeof(DSCBufferDesc));
      DSCBufferDesc.dwSize = sizeof(DSCBufferDesc);
      DSCBufferDesc.dwFlags = DSCBCAPS_WAVEMAPPED;
      DSCBufferDesc.dwBufferBytes = 8192;
      DSCBufferDesc.lpwfxFormat = &wfex;
  
      ZeroMemory(&DSBufferDesc, sizeof(DSBufferDesc));
      DSBufferDesc.dwSize = sizeof(DSBufferDesc);
      DSBufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
      DSBufferDesc.dwBufferBytes = 8192;
      DSBufferDesc.lpwfxFormat = &wfex;
  
      /* try with no device specified */
      rc=pDirectSoundFullDuplexCreate(NULL,NULL,&DSCBufferDesc,&DSBufferDesc,
                                      get_hwnd(),DSSCL_EXCLUSIVE ,&dsfdo,&pDSCBuffer8,
                                      &pDSBuffer8,NULL);
      ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL,
         "DirectSoundFullDuplexCreate(NULL,NULL) failed: %08x\n",rc);
      if (rc==S_OK && dsfdo)
          IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL);
  
      /* try with default devices specified */
      rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultCapture,
                                      &DSDEVID_DefaultPlayback,&DSCBufferDesc,
                                      &DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,&dsfdo,
                                      &pDSCBuffer8,&pDSBuffer8,NULL);
      ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL,
         "DirectSoundFullDuplexCreate(DSDEVID_DefaultCapture,"
         "DSDEVID_DefaultPlayback) failed: %08x\n", rc);
      if (rc==DS_OK && dsfdo)
          IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL);
  
      /* try with default voice devices specified */
      rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoiceCapture,
                                      &DSDEVID_DefaultVoicePlayback,
                                      &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,
                                      &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL);
      ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL,
         "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoiceCapture,"
         "DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc);
      if (rc==DS_OK && dsfdo)
          IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL);
  
      /* try with bad devices specified */
      rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoicePlayback,
                                      &DSDEVID_DefaultVoiceCapture,
                                      &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,
                                      &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL);
      ok(rc==DSERR_NODRIVER||rc==DSERR_INVALIDCALL,
         "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoicePlayback,"
         "DSDEVID_DefaultVoiceCapture) should have failed: %08x\n", rc);
      if (rc==DS_OK && dsfdo)
          IDirectSoundFullDuplex_Release(dsfdo);
  }
  
  static void test_COM(void)
  {
      IDirectSoundFullDuplex *dsfd = (IDirectSoundFullDuplex*)0xdeadbeef;
      IDirectSound *ds;
      IDirectSound8 *ds8;
      IDirectSoundCapture *dsc;
      IUnknown *unk, *unk8;
      IDirectSoundBuffer8 *dsb8;
      IDirectSoundCaptureBuffer8 *dscb8;
      DSBUFFERDESC bufdesc;
      DSCBUFFERDESC cbufdesc;
      WAVEFORMATEX wfx;
      ULONG refcount;
      HRESULT hr;
  
      /* COM aggregation */
      hr = CoCreateInstance(&CLSID_DirectSoundFullDuplex, (IUnknown*)0xdeadbeef, CLSCTX_INPROC_SERVER,
              &IID_IUnknown, (void**)&dsfd);
      ok(hr == CLASS_E_NOAGGREGATION,
              "DirectSoundFullDuplex create failed: %08x, expected CLASS_E_NOAGGREGATION\n", hr);
      ok(!dsfd, "dsfd = %p\n", dsfd);
  
      /* Invalid RIID */
      hr = CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, CLSCTX_INPROC_SERVER,
              &IID_IDirectSound3DBuffer, (void**)&dsfd);
      ok(hr == E_NOINTERFACE,
              "DirectSoundFullDuplex create failed: %08x, expected E_NOINTERFACE\n", hr);
  
      /* Different refcount for IDirectSoundFullDuplex and for IUnknown */
      hr = CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, CLSCTX_INPROC_SERVER,
              &IID_IDirectSoundFullDuplex, (void**)&dsfd);
      ok(hr == S_OK, "DirectSoundFullDuplex create failed: %08x, expected S_OK\n", hr);
      refcount = IDirectSoundFullDuplex_AddRef(dsfd);
      ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
      hr = IDirectSoundFullDuplex_QueryInterface(dsfd, &IID_IUnknown, (void**)&unk);
      ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr);
      refcount = IUnknown_AddRef(unk);
      ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
  
      /* Not initialized */
      hr = IDirectSoundFullDuplex_QueryInterface(dsfd, &IID_IDirectSound8, (void**)&ds8);
      ok(hr == E_NOINTERFACE,
              "QueryInterface for IID_IDirectSound8 failed: %08x, expected E_NOINTERFACE\n", hr);
      hr = IDirectSoundFullDuplex_QueryInterface(dsfd, &IID_IDirectSoundCapture, (void**)&dsc);
      ok(hr == E_NOINTERFACE,
              "QueryInterface for IID_IDirectSoundCapture failed: %08x, expected E_NOINTERFACE\n", hr);
  
      init_format(&wfx, WAVE_FORMAT_PCM, 44100, 16, 1);
      ZeroMemory(&bufdesc, sizeof(bufdesc));
      bufdesc.dwSize = sizeof(bufdesc);
      bufdesc.dwBufferBytes = wfx.nAvgBytesPerSec;
      bufdesc.lpwfxFormat = &wfx;
      ZeroMemory(&cbufdesc, sizeof(cbufdesc));
      cbufdesc.dwSize = sizeof(cbufdesc);
      cbufdesc.dwBufferBytes = wfx.nAvgBytesPerSec;
      cbufdesc.lpwfxFormat = &wfx;
      hr = IDirectSoundFullDuplex_Initialize(dsfd, NULL, NULL, &cbufdesc, &bufdesc, get_hwnd(),
              DSSCL_EXCLUSIVE, NULL, NULL);
      ok(hr == E_INVALIDARG,
              "IDirectSoundFullDuplex_Initialize failed: %08x, expected E_INVALIDARG\n", hr);
      hr = IDirectSoundFullDuplex_Initialize(dsfd, NULL, NULL, &cbufdesc, &bufdesc, get_hwnd(),
              DSSCL_EXCLUSIVE, &dscb8, &dsb8);
      if (hr == DSERR_NODRIVER || hr == DSERR_INVALIDCALL) {
          skip("No driver\n");
          return;
      }
      ok(hr == S_OK, "IDirectSoundFullDuplex_Initialize failed: %08x\n", hr);
  
      /* IDirectSound and IDirectSound8 */
      hr = IDirectSoundFullDuplex_QueryInterface(dsfd, &IID_IDirectSound8, (void**)&ds8);
      ok(hr == S_OK, "QueryInterface for IID_IDirectSound8 failed: %08x\n", hr);
      refcount = IDirectSound8_AddRef(ds8);
      ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
      hr = IDirectSoundFullDuplex_QueryInterface(dsfd, &IID_IDirectSound, (void**)&ds);
      ok(hr == S_OK, "QueryInterface for IID_IDirectSound failed: %08x\n", hr);
      refcount = IDirectSound8_AddRef(ds8);
      ok(refcount == 4, "refcount == %u, expected 4\n", refcount);
      refcount = IDirectSound_AddRef(ds);
      ok(refcount == 5, "refcount == %u, expected 5\n", refcount);
      hr = IDirectSound8_QueryInterface(ds8, &IID_IUnknown, (void**)&unk8);
      ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr);
      ok(unk == unk8, "Got different IUnknown when QI'ing IDirectSoundFullDuplex and IDirectSound\n");
      refcount = IUnknown_AddRef(unk8);
      ok(refcount == 4, "refcount == %u, expected 4\n", refcount);
      refcount = IDirectSound_AddRef(ds);
      ok(refcount == 6, "refcount == %u, expected 6\n", refcount);
      refcount = IDirectSoundFullDuplex_AddRef(dsfd);
      ok(refcount == 3, "refcount == %u, expected 3\n", refcount);
  
      /* IDirectSoundCapture */
      hr = IDirectSoundFullDuplex_QueryInterface(dsfd, &IID_IDirectSoundCapture, (void**)&dsc);
      ok(hr == S_OK, "QueryInterface for IID_IDirectSoundCapture failed: %08x\n", hr);
      refcount = IDirectSoundCapture_AddRef(dsc);
      ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
      refcount = IDirectSoundFullDuplex_AddRef(dsfd);
      ok(refcount == 4, "refcount == %u, expected 4\n", refcount);
      hr = IDirectSound8_QueryInterface(ds8, &IID_IUnknown, (void**)&unk8);
      ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr);
      ok(unk == unk8,
              "Got different IUnknown when QI'ing IDirectSoundFullDuplex and IDirectSoundCapture\n");
      refcount = IUnknown_AddRef(unk8);
      ok(refcount == 6, "refcount == %u, expected 6\n", refcount);
  
      IDirectSoundBuffer8_Release(dsb8);
      IDirectSoundCaptureBuffer8_Release(dscb8);
      while (IDirectSound8_Release(ds8));
      while (IDirectSoundCapture_Release(dsc));
      while (IDirectSoundFullDuplex_Release(dsfd));
      while (IUnknown_Release(unk));
  }
  
  START_TEST(duplex)
  {
      HMODULE hDsound;
  
      CoInitialize(NULL);
  
      hDsound = LoadLibraryA("dsound.dll");
      if (hDsound)
      {
  
          pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound,
              "DirectSoundFullDuplexCreate");
          if (pDirectSoundFullDuplexCreate) {
              test_COM();
              IDirectSoundFullDuplex_tests();
          } else
              skip("DirectSoundFullDuplexCreate missing - skipping all tests\n");
  
          FreeLibrary(hDsound);
      }
      else
          skip("dsound.dll not found - skipping all tests\n");
  
      CoUninitialize();
  }
  