Hi all, I've been trying to get some streaming code working with XAudio2. Unfortunately at best all I've gotten are a handful of clicks, and so I was wondering if someone could provide a little help.
I've implemented the code according to a few tutorials I've seen, and it's fairly simple. I just have one source voice and a master voice, and I'm submitting buffers to the source voice periodically.
Here's the setup code:
//Audio init section
if(FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
return false;
}
UINT32 flags = XAUDIO2_DEBUG_ENGINE;
if(FAILED(XAudio2Create(&g_xAudioEngine)))
{
MessageBox(NULL, L"Failed on XAudio2Create", L"Sadface", MB_OK);
CoUninitialize();
return false;
}
if(FAILED(g_xAudioEngine->CreateMasteringVoice(&g_masterVoice, XAUDIO2_DEFAULT_CHANNELS,(UINT32) SAMPLERATE, 0,0,NULL)))
{
MessageBox(NULL, L"Failed to create mastering voice!", L"Sadface", MB_OK);
CoUninitialize();
return false;
}
WAVEFORMATEX wfx = {0};
wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx.nChannels = 1;
wfx.nSamplesPerSec = 44100;
wfx.nAvgBytesPerSec = 44100 * sizeof(float);
wfx.nBlockAlign = sizeof(float);
wfx.wBitsPerSample = sizeof(float) * 8;
wfx.cbSize = 0;
std::stringstream debugstream;
debugstream << "nBlockAlign: " << wfx.nBlockAlign << " bitspersample: " << wfx.wBitsPerSample << std::endl;
OutputDebugStringA(debugstream.str().c_str());
if(FAILED(g_xAudioEngine->CreateSourceVoice(&g_sourceVoice, (WAVEFORMATEX*)&wfx)))
{
MessageBox(NULL, L"Failed to create source voice!", L"sadface", MB_OK);
}
I've also tried this with signed 16-bit PCM instead of IEEE float to no avail.
Here's where I'm feeding the source voice:
void streamNextChunk(const boost::system::error_code& error, boost::asio::deadline_timer & timer)
{
static bool comInitThisThread = false;
if(!comInitThisThread)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
comInitThisThread = true;
}
timer.expires_from_now(boost::posix_time::milliseconds(1000));
timer.async_wait(boost::bind(streamNextChunk, _1, boost::ref(timer)));
static __int64 sampleCount = 0;
float* buff = new float[44100];
for(size_t i = 0 ;i < 44100; i++)
{
float t = (float)sampleCount++;
t /= 44100.0;
buff[i] = cos(2 * 3.14159 * t * 260);
}
XAUDIO2_BUFFER xAudioBuff = {0};
xAudioBuff.AudioBytes = (44100) * sizeof(float);
xAudioBuff.pAudioData = (BYTE*) buff;
if(FAILED(g_sourceVoice->SubmitSourceBuffer(&xAudioBuff)))
{
OutputDebugStringA("Failed on submit source buffer!!! D:\n");
}
g_sourceVoice->Start(0, XAUDIO2_COMMIT_NOW);
XAUDIO2_VOICE_STATE state;
g_sourceVoice->GetState(&state);
float volume;
g_sourceVoice->GetVolume(&volume);
std::stringstream debugstream;
float gvolume;
g_masterVoice->GetVolume(&gvolume);
debugstream << "PTR: " << buff << " Q: " << state.BuffersQueued << " S: " << state.SamplesPlayed << " SC: " << sampleCount << " V: " << volume << " GV: " << gvolume << std::endl;
OutputDebugStringA(debugstream.str().c_str());
}
This function is on a boost asio timer that ensures it's called once per second. The timer is handled in a separate thread from where the XAudio2 library is initialized (the ASIO run thread). The function also generates 1 second of data each call. As you can see I'm trying to generate a simple 2600Hz test tone, but at best all I have been able to get are some short clicks. (Yes I'm aware this leaks memory, but at the moment my main concern is getting any sound output at all). The debug printouts show that the source voice seems to be queuing the buffers and the samplesplayed count is increasing as expected.
This code seems to be simple enough, and mostly matches the code examples I've seen for streaming wav files off a disk (with the obvious exception that I'm creating the data on the fly).
Can anyone tell me what I'm missing?