I'm trying to use FAudio, which is a cross platform replacement for XAudio2.
I'm dealing with a class
class FAudio_BufferNotify : public FAudioVoiceCallback {
public:
HANDLE hBufferEndEvent;
FAudio_BufferNotify()
{
hBufferEndEvent = NULL;
hBufferEndEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
assert(hBufferEndEvent != NULL);
}
~FAudio_BufferNotify()
{
CloseHandle(hBufferEndEvent);
hBufferEndEvent = NULL;
}
STDMETHOD_(void, OnBufferEnd)
(void* pBufferContext)
{
assert(hBufferEndEvent != NULL);
SetEvent(hBufferEndEvent);
}
// dummies:
STDMETHOD_(void, OnVoiceProcessingPassStart)
(UINT32 BytesRequired) {}
STDMETHOD_(void, OnVoiceProcessingPassEnd)
() {}
STDMETHOD_(void, OnStreamEnd)
() {}
STDMETHOD_(void, OnBufferStart)
(void* pBufferContext) {}
STDMETHOD_(void, OnLoopEnd)
(void* pBufferContext) {}
STDMETHOD_(void, OnVoiceError)
(void* pBufferContext, HRESULT Error){};
};
And while it works, its use of com calls is not quite cross platform, so I opted to use
void OnBufferEnd(void * pBufferContext) {
assert(hBufferEndEvent != NULL);
SetEvent(hBufferEndEvent);
}
void OnVoiceProcessingPassStart(uint32_t BytesRequired) {}
void OnVoiceProcessingPassEnd() {}
void OnStreamEnd() {}
void OnBufferStart(void * pBufferContext) {}
void OnLoopEnd(void * pBufferContext) {}
void OnVoiceError(void * pBufferContext, uint32_t Error) {}
Which does compile still, but for some reason causes a segmentation fault and according to lldb seems to be related to OnVoiceProcessingPassStart.
So as mentioned, I just went with using void OnVoiceProcessingPassStart() instead of the STDMETHOD that the old XAudio2 code uses, and as stated I did get it to compile, but when I load something that uses that, it just segfaults. Ideally it should have just loaded, playing sounds properly.
here's the backtrace from lldb
* thread #8, stop reason = Exception 0xc0000005 encountered at address 0x7ff6e05de8dc: Access violation reading location 0xffffffffffffffff
frame #0: 0x00007ff6e05de8dc visualboyadvance-m.exe`FAudio_INTERNAL_MixSource(voice=0x00000249d9bbc150) at FAudio_internal.c:829:3
826 FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
827 LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
828
-> 829 voice->src.callback->OnVoiceProcessingPassStart(
830 voice->src.callback,
831 FAudio_INTERNAL_GetBytesRequested(voice, (uint32_t) toDecode)
832 );
(lldb) bt
* thread #8, stop reason = Exception 0xc0000005 encountered at address 0x7ff6e05de8dc: Access violation reading location 0xffffffffffffffff
* frame #0: 0x00007ff6e05de8dc visualboyadvance-m.exe`FAudio_INTERNAL_MixSource(voice=0x00000249d9bbc150) at FAudio_internal.c:829:3
frame #1: 0x00007ff6e05dc227 visualboyadvance-m.exe`FAudio_INTERNAL_GenerateOutput(audio=0x00000249d9b9d490, output=0x00000249d9bb38e0) at FAudio_internal.c:1337:4
frame #2: 0x00007ff6e05dbea7 visualboyadvance-m.exe`FAudio_INTERNAL_UpdateEngine(audio=0x00000249d9b9d490, output=0x00000249d9bb38e0) at FAudio_internal.c:1435:3
frame #3: 0x00007ff6e05e20fc visualboyadvance-m.exe`FAudio_INTERNAL_MixCallback(userdata=0x00000249d9b9d490, stream="", len=3840) at FAudio_platform_sdl2.c:46:3
frame #4: 0x00007ff6e05215fd visualboyadvance-m.exe`SDL_RunAudio + 317
frame #5: 0x00007ff6e0514539 visualboyadvance-m.exe`SDL_RunThread + 41
frame #6: 0x00007ff6e056480e visualboyadvance-m.exe`RunThreadViaCreateThread + 14
frame #7: 0x00007ff98687257d kernel32.dll`BaseThreadInitThunk + 29
frame #8: 0x00007ff98866aa58 ntdll.dll`RtlUserThreadStart + 40
After some research I noticed that
FAudioVoiceCallbacklooks like this:If you look at the crashing code, you will see that a functions is selected from
src.callbackand the first argument issrc.callback. So you can do the following:You can now create an instance of
FAudio_BufferNotifyand register&f.cbas the callback address. Sincecbis the first member ofFAudio_BufferNotify, their addresses are the same, so you can use thereinterpret_castto convert the callback into the full object.