Home > Enterprise >  XAudio2 `SubmitSourceBuffer` method failed with the error code XAUDIO2_E_INVALID_CALL (0x88960001)
XAudio2 `SubmitSourceBuffer` method failed with the error code XAUDIO2_E_INVALID_CALL (0x88960001)

Time:01-30

I'm making the pac-man with the winapi32, and using XAudio2 API for playing multiple sounds simultanueosly. I played my sound file pacman_beginning.wav, pacman_death.wav, pacman_chomp.wav, pacman_eatfruit.wav, pacman_eatghost.wav, pacman_intermission.wav, pacman_siren.wav, and all of them worked fine, but pacman_siren.wav (I download them from Pac-Man Sounds, and Pacman Sound Effects, and pacman_siren.wav is renamed from 8d82b5_Pacman_Siren_Sound_Effect.wav ).

the following is part of my code(for XAudio2, I referred to How to: Play a Sound with XAudio2 )

PacmanApp.hpp:

////////////////////
// PacmanApp      //
////////////////////

# include<Windows.h>
# include<functional>
# include<xaudio2.h>
# include<vector>
# include"resource.h"  // `IDB_BITMAP1` is defined.

class PacmanApp {
  struct AudioData {
    BYTE*                pDataBuffer;
    DWORD                dwChunkSize;
    IXAudio2SourceVoice* pSourceVoice;
    WAVEFORMATEXTENSIBLE wfx;
  };

  using Delegate = std::function<void(HDC,HDC)>;

  // the window procedure.
  static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

  // find chunk from `fFile`.
  static HRESULT FindChunk(HANDLE hFile, DWORD fourcc, DWORD& dwChunkSize, DWORD dwChunkDataPosition);  

  // read chunk data from `fFile`.
  static HRESULT ReadChunkData(HANDLE hFile, void* buffer, DWORD bufferSize, DWORD bufferoffset);

private:
  // for message loop.
  HINSTANCE hInstance = NULL;
  HWND      hwnd      = NULL;
  WNDCLASS  wc        = { 0 };
  MSG       msg       = { 0 };

  
  // for rendering.
  HBITMAP hBM  = NULL;  // for pac-man sprite.
  HBITMAP hBM2 = NULL;  // for back-buffer.
  RECT    rect;
  BITMAP  bm;


  // for application
  Delegate callbackFn     = nullptr; // callback function.
  bool     keyState[255]  = { 0 };   // for key-down events.
  bool     isTimeout[256] = { 0 };   // for timer events.

  // for sound.
  IXAudio2*              pXAudio2     = nullptr;
  IXAudioMasteringVoice* pMasterVoice = nullptr;
  XAUDIO2_BUFFER         buffer       = { 0 };
  std::vector<AudioData> audioList;

private:
  PacmanApp()                 = default;
  PacmanApp(const PacmanApp&) = delete;
  PacmanApp(PacmanApp&&)      = delete;
  
  ~PacmanApp() {
    if(hBM)  DeleteObject(hBM);
    if(hBM2) DeleteObject(hBM2);

    for(auto& i : audioList) {
      delete[] i.pDataBuffer;
    }
  }

public:
  static PacmanApp inst; // for single-ton.

  // initialize the pacman application.
  bool Init(HINSTANCE hInstance, int nWidth, int nHeight);

  // load the desired sound file.
  bool LoadSound(const wchar_t strFileName[]);
  
  // start the sound identified by `sndID`.
  bool StartSound(UINT sndID, float playLength);


  // run the pacman application.
  template<typename Functor>
  void Run(Functor&& callbackFn, int nCmdShow, UINT fps){
    if(this->callbackFn = std::forward<Functor>(callbackFn) ) {
       ShowWindow(hwnd, nCmdShow);
       SetTimer(hwnd, 256, (1000 / fps), NULL);

       while(GetMessage(&msg, 0, 0, 0) ) {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
       }
        KillTimer(hwnd, 256);
    }
  }

  /* omitted */
};

PacmanApp.cpp:

# include"PacmanApp.hpp"

#ifdef _XBOX //Big-Endian
  # define fourccRIFF 'RIFF'
  # define fourccDATA 'data'
  # define fourccFMT  'fmt '
  # define fourccWAVE 'WAVE'
  # define fourccXWMA 'XWMA'
  # define fourccDPDS 'dpds'
#endif

#ifndef _XBOX //Little-Endian
  # define fourccRIFF 'FFIR'
  # define fourccDATA 'atad'
  # define fourccFMT ' tmf'
  # define fourccWAVE 'EVAW'
  # define fourccXWMA 'AMWX'
  # define fourccDPDS 'sdpd'
#endif


// for single-ton.
PacmanApp PacmanApp::inst;


// initialize the pac-man application.
bool PacmanApp::Init(HINSTANCE hInstance, int nWidth, int nHeight) {
  /* ommitted. RegisterClass, CreateWindowEx, etc is here. */

  // init COM
  if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)) ) {
       return false;
  }

  // create XAudio engine.
  if (FAILED(XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR) ) ) {
       return false;
  }

  // create mastering voice.
  if (FAILED(pXAudio2->CreateMasteringVoice(&pMasterVoice) ) ) {
       return false;
  }
  return true;
}


// find chunk from `fFile`.
HRESULT PacmanApp::FindChunk(HANDLE hFile, DWORD fourcc, DWORD& dwChunkSize, DWORD& dwChunkDataPosition) {
    HRESULT hr = S_OK;

    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) {
        return HRESULT_FROM_WIN32(GetLastError() );
    }

    DWORD dwChunkType;
    DWORD dwChunkDataSize;
    DWORD dwRIFFDataSize = 0;
    DWORD dwFileType;
    DWORD bytesRead = 0;
    DWORD dwOffset  = 0;

    while (hr == S_OK) {
        DWORD dwRead;

        // read ChunkID.
        if (0 == ReadFile(hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL)) {
            hr = HRESULT_FROM_WIN32(GetLastError() );
        }

        // read ChunkDataSize.
        if(0 == ReadFile(hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL) )  {
            hr = HRESULT_FROM_WIN32(GetLastError() );
        }


        if (dwChunkType == fourccRIFF) {
            dwRIFFDataSize  = dwChunkDataSize;
            dwChunkDataSize = 4;

            // read RIFFType.
            if (0 == ReadFile(hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL) ) {
                hr = HRESULT_FROM_WIN32(GetLastError() );
            }
        }
        else {
            if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, dwChunkDataSize, NULL, FILE_CURRENT) ) {
                return HRESULT_FROM_WIN32(GetLastError() );
            }
        }

        dwOffset  = sizeof(DWORD) * 2;

        if (dwChunkType == fourcc) {
            dwChunkSize         = dwChunkDataSize;
            dwChunkDataPosition = dwOffset;
            return S_OK;
        }

        dwOffset  = dwChunkDataSize;

        if (bytesRead >= dwRIFFDataSize) {
            return S_FALSE;
        }
    }
    return S_OK;
}


// read chunk data from `hFile`.
HRESULT PacmanApp::ReadChunkData(HANDLE hFile, void* buffer, DWORD buffersize, DWORD bufferoffset) {
    HRESULT hr = S_OK;
    DWORD   dwRead;

    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, bufferoffset, NULL, FILE_BEGIN) ) {
        return HRESULT_FROM_WIN32(GetLastError() );
    }
    if (0 == ReadFile(hFile, buffer, buffersize, &dwRead, NULL) ) {
        hr = HRESULT_FROM_WIN32(GetLastError() );
    }
    return hr;
}



// load the desired sound file.
bool PacmanApp::LoadSound(const wchar_t strFileName[]) {
   HANDLE hFile = CreateFile(
       strFileName,
       GENERIC_READ,
       FILE_SHARE_READ,
       NULL,
       OPEN_EXISTING,
       0,
       NULL
   );

   if (INVALID_HANDLE_VALUE == hFile) {
       return false;
   }

   if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN) ) {
       CloseHandle(hFile);
       return false;
   }

   DWORD dwChunkSize;
   DWORD dwChunkPosition;
   DWORD filetype;
   WAVEFORMATEXTENSIBLE wfx = { 0 };

   // check the file type, should be fourccWAVE or 'XWMA'
   FindChunk(hFile, fourccRIFF, dwChunkSize, dwChunkPosition);
   ReadChunkData(hFile, &filetype, sizeof(DWORD), dwChunkPosition);

   if (filetype != fourccWAVE) {
       CloseHandle(hFile);
       return false;
   }

   FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition);
   ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition);

   // fill out the audio data buffer with the contents of the fourccDATA
   FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition);
   audioList.push_back({
       new BYTE[dwChunkSize], 
       dwChunkSize, 
       nullptr,
       wfx
   });

   ReadChunkData(hFile, audioList.back().pDataBuffer, dwChunkSize, dwChunkPosition);

   CloseHandle(hFile);
   return true;
}


// start the sound identified by `sndID`.
bool PacmanApp::StartSound(UINT sndID, float playLength) {  // playLength is in [0, 1.0f]
    if (sndID < audioList.size() ) {
           auto& curAudio = audioList[sndID];

           buffer.AudioBytes = curAudio.dwChunkSize;  // size of the audio buffer in bytes.
           buffer.pAudioData = curAudio.pDataBuffer;  // buffer containing audio data.
           buffer.Flags      = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after the buffer.
           buffer.PlayBegin  = 0;
           buffer.PlayLength = curAudio.dwChunkSize * playLength;

           HRESULT hr;
           if (FAILED(hr = pXAudio2->CreateSourceVoice(&curAudio.pSourceVoice, (WAVEFORMATEX*)&curAudio.wfx)) ) {
               return false;
           }
           if (FAILED(hr = curAudio.pSourceVoice->SubmitSourceBuffer(&buffer) )   ) {
                return false;
           }
           if (FAILED(hr = curAudio.pSourceVoice->Start(0) ) ) {
                return false;
           }
    }
    return true;
}


main.cpp:

# include"PacmanApp.hpp"
# include"PacmanObject.hpp"

/////////////////////
// wWinMain        //
/////////////////////


int APIENTRY wWinMain(_In_     HINSTANCE hInstance,
                      _In_opt_ HINSTANCE hPrevInstance,
                      _In_     LPWSTR    nCmdLine,
                      _In_     int       nCmdShow)
{
   if(!PacmanApp::inst.Init(hInstance, 1400, 650) {
     return 0;
   }

   /* omitted */

   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_beginning.wav");
   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_death.wav");
   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_chomp.wav");
   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_eatfruit.wav");
   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_eatghost.wav");
   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_intermission.wav");
   PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_siren.wav");

   enum struct PacmanSound : UINT {
       INTRO, DEATH, CHOMP, EAT_FRUIT, EAT_GHOST, INTERMISSION, SIREN
   };


   // main loop.
   PacmanApp::inst.Run([&](HDC srcDC, HDC destDC) {
     
     PacmanApp::inst.StartSound((UINT)PacmanSound::INTRO, 1.0f); // OK. rest of them is same ,but..
     // PacmanApp::inst.StartSound((UINT)PacmanSound::SIREN, 1.0f); // only this statement returns false.
   

   }, nCmdShow, 60);
}

In the beginning, I thought that LoadSound have some problem. but,

pacman_beginning.wav:

  • hex dump:
52 49 46 46 EA B5 00 00   57 41 56 45 66 6D 74 20  RIFF....WAVEfmt 
10 00 00 00 01 00 01 00   11 2B 00 00 11 2B 00 00  ......... ... ..
01 00 08 00 64 61 74 61   9A B5 00 00 80 7F 80 7F  ....data........
  • WAV format reader output:
C:\Users\user>"C:\Users\user\Desktop\WAV format reader\x64\Debug\WAV format reader.exe" "C:\Users\user\Desktop\pacman_beginning.wav"
WAVE file C:\Users\user\Desktop\pacman_beginning.wav
riff 'WAVE', chunk 'fmt ', 16 bytes
format tag 0001 (PCM)
number of channels 1
samples per second 11025
avg bytes per second 11025
sample block size 1 bytes
bits per sample 8
  • when PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_beginning.wav"); is excuting:
   FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition); // result: dwChunkSize => 0x10, dwChunkPosition => 0x14
   ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition); 

   // fill out the audio data buffer with the contents of the fourccDATA
   FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition); // result: dwChunkSize => 0x0x0000b59a, dwChunkPosition => 0x0000002c
   audioList.push_back({
       new BYTE[dwChunkSize], 
       dwChunkSize, 
       nullptr,
       wfx
   });
  • the LoadSound result:
auto& curAudio = audioList.back();

curAudio.dwChunkSize = 46490

curAudio.wfx.Format = { 
  .wFormatTag      = 1, 
  .nChannels       = 1, 
  .nSamplesPerSec  = 11025, 
  .nAvgBytesPerSec = 11025, 
  .nBlockAlign     = 1, 
  .wBitsPerSample  = 8, 
  .cbSize          = 0 
}




pacman_death.wav:

  • hex dump:
52 49 46 46 68 42 00 00   57 41 56 45 4C 49 53 54 RIFFhB..WAVELIST
28 00 00 00 49 4E 46 4F   49 53 46 54 1C 00 00 00 (...INFOISFT....
57 48 41 4D 20 31 2E 33   31 20 62 79 20 41 6E 64 WHAM 1.31 by And
72 65 77 20 42 75 6C 68   61 6B 00 00 66 6D 74 20 rew Bulhak..fmt 
10 00 00 00 01 00 01 00   11 2B 00 00 11 2B 00 00 ......... ... ..
01 00 08 00 64 61 74 61   14 42 00 00 80 80 82 7F ....data.B......
  • WAV format reader output:
C:\Users\user>"C:\Users\user\Desktop\WAV format reader\x64\Debug\WAV format reader.exe" "C:\Users\user\Desktop\pacman_death.wav"
WAVE file C:\Users\user\Desktop\pacman_death.wav
riff 'WAVE', chunk 'fmt ', 16 bytes
format tag 0001 (PCM)
number of channels 1
samples per second 11025
avg bytes per second 11025
sample block size 1 bytes
bits per sample 8
  • when PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_death.wav"); is excuting:
   FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition); // result: dwChunkSize => 0x10, dwChunkPosition => 0x44
   ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition); 

   // fill out the audio data buffer with the contents of the fourccDATA
   FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition); // result: dwChunkSize => 0x00004214, dwChunkPosition => 0x0000005c
   audioList.push_back({
       new BYTE[dwChunkSize], 
       dwChunkSize, 
       nullptr,
       wfx
   });
  • the LoadSound result:
auto& curAudio = audioList.back();

curAudio.dwChunkSize = 16916

curAudio.wfx.Format = { 
  .wFormatTag      = 1, 
  .nChannels       = 1, 
  .nSamplesPerSec  = 11025, 
  .nAvgBytesPerSec = 11025, 
  .nBlockAlign     = 1, 
  .wBitsPerSample  = 8, 
  .cbSize          = 0 
}




pacman_siren.wav:

hex dump:

52 49 46 46 54 3B 01 00   57 41 56 45 66 6D 74 20 RIFFT;..WAVEfmt 
10 00 00 00 01 00 01 00   22 56 00 00 44 AC 00 00 ........"V..D...
02 00 10 00 4C 49 53 54   28 00 00 00 49 4E 46 4F ....LIST(...INFO
49 47 4E 52 06 00 00 00   4F 74 68 65 72 00 49 53 IGNR....Other.IS
46 54 0E 00 00 00 4C 61   76 66 35 39 2E 32 37 2E FT....Lavf59.27.
31 30 30 00 64 61 74 61   00 3B 01 00 00 00 00 00 100.data.;......

WAV format reader output:

C:\Users\user>"C:\Users\user\Desktop\WAV format reader\x64\Debug\WAV format reader.exe" "C:\Users\user\Desktop\pacman_siren.wav"
WAVE file C:\Users\user\Desktop\pacman_siren.wav
riff 'WAVE', chunk 'fmt ', 16 bytes
format tag 0001 (PCM)
number of channels 1
samples per second 22050
avg bytes per second 44100
sample block size 2 bytes
bits per sample 16

when PacmanApp::inst.LoadSound(L"C:/Users/user/Desktop/pacman_siren.wav"); is excuting:

   FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition); // result: dwChunkSize => 0x10, dwChunkPosition => 0x14
   ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition); 

   // fill out the audio data buffer with the contents of the fourccDATA
   FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition); // result: dwChunkSize => 0x00013b00, dwChunkPosition => 0x0000005c
   audioList.push_back({
       new BYTE[dwChunkSize], 
       dwChunkSize, 
       nullptr,
       wfx
   });
  • the LoadSound result:
auto& curAudio = audioList.back();

curAudio.dwChunkSize = 80640

curAudio.wfx.Format = { 
  .wFormatTag      = 1, 
  .nChannels       = 1, 
  .nSamplesPerSec  = 22050, 
  .nAvgBytesPerSec = 44100, 
  .nBlockAlign     = 2, 
  .wBitsPerSample  = 16, 
  .cbSize          = 0 
}

every calls to LoadSound work correctly. so, I think there is not any WAVEFORMATEX structure corruption, or incorrect uninitialized data.SubmitSourceBuffer is failed when onlysndID = PacmanSound::SIREN:


bool PacmanApp::StartSound(UINT sndID, float playLength) {  // sndID = 6 (=PacmanSound::SIREN)
 /* omitted */

 HRESULT hr;
 if (FAILED(hr = pXAudio2->CreateSourceVoice(&curAudio.pSourceVoice, (WAVEFORMATEX*)&curAudio.wfx)) ) {
   return false;
 }
 if (FAILED(hr = curAudio.pSourceVoice->SubmitSourceBuffer(&buffer) )   ) {
   return false; // hr is XAUDIO2_E_INVALID_CALL (=0x88960001)
 }
 if (FAILED(hr = curAudio.pSourceVoice->Start(0) ) ) {
   return false;
 }

 /* omitted */
}

MSDN says

Returned by XAudio2 for certain API usage errors (invalid calls and so on) that are hard to avoid completely and should be handled by a title at runtime. (API usage errors that are completely avoidable, such as invalid parameters, cause an ASSERT in debug builds and undefined behavior in retail builds, so no error code is defined for them.)

But, I don't know what I'm missing.. Could anyone help me to solve this issue??.

23/01/29 EDIT:

CodePudding user response:

I believe the problem you are having is that buffer.PlayLength is not valid. You are currently using:

buffer.PlayLength = curAudio.dwChunkSize * playLength;

This means you are setting it in terms of BYTES. Both PlayLength and LoopLength must be in terms of SAMPLES.

First, try using buffer.PlayLength = 0; to verify it works.

Computing sample counts is challenging in a general case, but I have code for it in the DirectX Tool Kit for Audio in SoundEffect.cpp for PCM, ADPCM, xWMA, and XMA2.

For PCM data, you use:

// You'll want to do this with 64-bit integer math to avoid overflow.
samples = (curAudio.dwChunkSize * 8) / (wfx.wBitsPerSample * wfx.nChannels)
  • Related