static void XAudio2_Update(void) { if (do_update && pSourceVoice) { do_update = 0; while (1) { XAUDIO2_VOICE_STATE state; XAUDIO2_BUFFER audio_buf; #if !defined(DRV_XAUDIO28) IXAudio2SourceVoice_GetState(pSourceVoice, &state); #else IXAudio2SourceVoice_GetState(pSourceVoice, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); #endif if (state.BuffersQueued > 0) break; current_buf %= XAUDIO2_NUM_BUFFERS; if (Player_Paused_internal()) VC_SilenceBytes((SBYTE *) buffers[current_buf], (ULONG) XAUDIO2_BUFFER_SIZE); else VC_WriteBytes((SBYTE *) buffers[current_buf], (ULONG) XAUDIO2_BUFFER_SIZE); memset(&audio_buf, 0, sizeof(XAUDIO2_BUFFER)); audio_buf.AudioBytes = XAUDIO2_BUFFER_SIZE; audio_buf.pAudioData = buffers[current_buf]; IXAudio2SourceVoice_SubmitSourceBuffer(pSourceVoice, &audio_buf, NULL); current_buf++; current_buf %= XAUDIO2_NUM_BUFFERS; } IXAudio2SourceVoice_Start(pSourceVoice, 0, 0); threadInUse = 1; ResumeThread(UpdateBufferHandle); } }
size_t xaudio2_write(xaudio2_t *handle, const void *buf, size_t bytes_) { unsigned bytes = bytes_; const uint8_t *buffer = (const uint8_t*)buf; while (bytes) { unsigned need = min(bytes, handle->bufsize - handle->bufptr); memcpy(handle->buf + handle->write_buffer * handle->bufsize + handle->bufptr, buffer, need); handle->bufptr += need; buffer += need; bytes -= need; if (handle->bufptr == handle->bufsize) { while (handle->buffers == MAX_BUFFERS - 1) WaitForSingleObject(handle->hEvent, INFINITE); XAUDIO2_BUFFER xa2buffer = {0}; xa2buffer.AudioBytes = handle->bufsize; xa2buffer.pAudioData = handle->buf + handle->write_buffer * handle->bufsize; if (FAILED(IXAudio2SourceVoice_SubmitSourceBuffer(handle->pSourceVoice, &xa2buffer, NULL))) return 0; InterlockedIncrement(&handle->buffers); handle->bufptr = 0; handle->write_buffer = (handle->write_buffer + 1) & MAX_BUFFERS_MASK; } } return bytes_; }
static DWORD WINAPI UpdateBufferProc(LPVOID lpParameter) { while (threadInUse) { while (1) { XAUDIO2_VOICE_STATE state; XAUDIO2_BUFFER audio_buf; #if !defined(DRV_XAUDIO28) IXAudio2SourceVoice_GetState(pSourceVoice, &state); #else IXAudio2SourceVoice_GetState(pSourceVoice, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); #endif if (state.BuffersQueued >= XAUDIO2_NUM_BUFFERS - 1) break; MUTEX_LOCK(vars); if (Player_Paused_internal()) VC_SilenceBytes((SBYTE *) buffers[current_buf], (ULONG) XAUDIO2_BUFFER_SIZE); else VC_WriteBytes((SBYTE *) buffers[current_buf], (ULONG) XAUDIO2_BUFFER_SIZE); MUTEX_UNLOCK(vars); memset(&audio_buf, 0, sizeof(XAUDIO2_BUFFER)); audio_buf.AudioBytes = XAUDIO2_BUFFER_SIZE; audio_buf.pAudioData = buffers[current_buf]; IXAudio2SourceVoice_SubmitSourceBuffer(pSourceVoice, &audio_buf, NULL); current_buf++; current_buf %= XAUDIO2_NUM_BUFFERS; } WaitForSingleObject(hBufferEvent, INFINITE); } return 0; }
static void INLINE wrbuf(IXAudio2SourceVoice *source, XAUDIO2_BUFFER *x2buf, const BYTE *buffer) { x2buf->pAudioData = buffer; if(IXAudio2SourceVoice_SubmitSourceBuffer(source, x2buf, NULL) != S_OK) { fprintf(stderr, "Unable to submit source buffer\n"); } }
gc_result gaX_device_queue_xaudio2(ga_DeviceImpl_XAudio2* in_device, void* in_buffer) { XAUDIO2_BUFFER buf; void* data; ZeroMemory(&buf, sizeof(XAUDIO2_BUFFER)); buf.AudioBytes = in_device->numSamples * in_device->sampleSize; data = in_device->buffers[in_device->nextBuffer++]; in_device->nextBuffer %= in_device->numBuffers; memcpy(data, in_buffer, buf.AudioBytes); buf.pAudioData = data; IXAudio2SourceVoice_SubmitSourceBuffer(in_device->source, &buf, 0); return GC_SUCCESS; }
static size_t xaudio2_write(xaudio2_t *handle, const uint8_t *buffer, size_t bytes_) { unsigned bytes = bytes_; while (bytes) { unsigned need = MIN(bytes, handle->bufsize - handle->bufptr); memcpy(handle->buf + handle->write_buffer * handle->bufsize + handle->bufptr, buffer, need); handle->bufptr += need; buffer += need; bytes -= need; if (handle->bufptr == handle->bufsize) { XAUDIO2_BUFFER xa2buffer; while (handle->buffers == MAX_BUFFERS - 1) WaitForSingleObject(handle->hEvent, INFINITE); xa2buffer.Flags = 0; xa2buffer.AudioBytes = handle->bufsize; xa2buffer.pAudioData = handle->buf + handle->write_buffer * handle->bufsize; xa2buffer.PlayBegin = 0; xa2buffer.PlayLength = 0; xa2buffer.LoopBegin = 0; xa2buffer.LoopLength = 0; xa2buffer.LoopCount = 0; xa2buffer.pContext = NULL; if (FAILED(IXAudio2SourceVoice_SubmitSourceBuffer( handle->pSourceVoice, &xa2buffer, NULL))) return 0; InterlockedIncrement((LONG volatile*)&handle->buffers); handle->bufptr = 0; handle->write_buffer = (handle->write_buffer + 1) & MAX_BUFFERS_MASK; } } return bytes_; }
static void XAUDIO2_PlayDevice(_THIS) { XAUDIO2_BUFFER buffer; Uint8 *mixbuf = this->hidden->mixbuf; Uint8 *nextbuf = this->hidden->nextbuf; const int mixlen = this->hidden->mixlen; IXAudio2SourceVoice *source = this->hidden->source; HRESULT result = S_OK; if (!this->enabled) { /* shutting down? */ return; } /* Submit the next filled buffer */ SDL_zero(buffer); buffer.AudioBytes = mixlen; buffer.pAudioData = nextbuf; buffer.pContext = this; if (nextbuf == mixbuf) { nextbuf += mixlen; } else { nextbuf = mixbuf; } this->hidden->nextbuf = nextbuf; result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL); if (result == XAUDIO2_E_DEVICE_INVALIDATED) { /* !!! FIXME: possibly disconnected or temporary lost. Recover? */ } if (result != S_OK) { /* uhoh, panic! */ IXAudio2SourceVoice_FlushSourceBuffers(source); SDL_OpenedAudioDeviceDisconnected(this); } }
static void test_looping(IXAudio2 *xa) { HRESULT hr; IXAudio2MasteringVoice *master; IXAudio2SourceVoice *src; WAVEFORMATEX fmt; XAUDIO2_BUFFER buf; UINT32 played, running_total = 0; XA2CALL_0V(StopEngine); if(xaudio27) hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL); else hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects); ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr); fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; fmt.nChannels = 2; fmt.nSamplesPerSec = 44100; fmt.wBitsPerSample = 32; fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; fmt.cbSize = 0; XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &loop_buf, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf, 0, sizeof(buf)); buf.AudioBytes = 44100 * fmt.nBlockAlign; buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes); fill_buf((float*)buf.pAudioData, &fmt, 440, 44100); XA2CALL_0(StartEngine); ok(hr == S_OK, "StartEngine failed: %08x\n", hr); /* play from middle to end */ buf.PlayBegin = 22050; buf.PlayLength = 0; buf.LoopBegin = 0; buf.LoopLength = 0; buf.LoopCount = 0; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 22050, "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends); /* play 4410 samples from middle */ buf.PlayBegin = 22050; buf.PlayLength = 4410; buf.LoopBegin = 0; buf.LoopLength = 0; buf.LoopCount = 0; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 4410, "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends); /* loop 4410 samples in middle */ buf.PlayBegin = 0; buf.PlayLength = 0; buf.LoopBegin = 22050; buf.LoopLength = 4410; buf.LoopCount = 1; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 44100 + 4410, "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends); /* play last half, then loop the whole buffer */ buf.PlayBegin = 22050; buf.PlayLength = 0; buf.LoopBegin = 0; buf.LoopLength = 0; buf.LoopCount = 1; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 22050 + 44100, "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends); /* play short segment from middle, loop to the beginning, and end at PlayEnd */ buf.PlayBegin = 22050; buf.PlayLength = 4410; buf.LoopBegin = 0; buf.LoopLength = 0; buf.LoopCount = 1; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 4410 + (22050 + 4410), "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends); /* invalid: LoopEnd must be <= PlayEnd * xaudio27: play until LoopEnd, loop to beginning, play until PlayEnd */ buf.PlayBegin = 22050; buf.PlayLength = 4410; buf.LoopBegin = 0; buf.LoopLength = 22050 + 4410 * 2; buf.LoopCount = 1; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); if(xaudio27){ ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 4410 + (22050 + 4410 * 2), "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends); }else ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr); /* invalid: LoopEnd must be within play range * xaudio27: plays only play range */ buf.PlayBegin = 22050; buf.PlayLength = 0; /* == until end of buffer */ buf.LoopBegin = 0; buf.LoopLength = 22050; buf.LoopCount = 1; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); if(xaudio27){ ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, -1); ok(played - running_total == 22050, "Got wrong samples played: %u\n", played - running_total); running_total = played; ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends); }else ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr); /* invalid: LoopBegin must be before PlayEnd * xaudio27: crashes */ if(!xaudio27){ buf.PlayBegin = 0; buf.PlayLength = 4410; buf.LoopBegin = 22050; buf.LoopLength = 4410; buf.LoopCount = 1; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr); } /* infinite looping buffer */ buf.PlayBegin = 22050; buf.PlayLength = 0; buf.LoopBegin = 0; buf.LoopLength = 0; buf.LoopCount = 255; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); played = play_to_completion(src, running_total + 88200); ok(played - running_total == 22050 + 44100 * 2, "Got wrong samples played: %u\n", played - running_total); ok(nloopends == (played - running_total) / 88200 + 1, "Got wrong OnLoopEnd calls: %u\n", nloopends); running_total = played; }
static void test_buffer_callbacks(IXAudio2 *xa) { HRESULT hr; IXAudio2MasteringVoice *master; IXAudio2SourceVoice *src; WAVEFORMATEX fmt; XAUDIO2_BUFFER buf; XAUDIO2_VOICE_STATE state; struct vcb_buf_testdata testdata[5]; int i; obs_calls = 0; obe_calls = 0; XA2CALL_0V(StopEngine); if(xaudio27) hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL); else hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects); ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr); fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; fmt.nChannels = 2; fmt.nSamplesPerSec = 44100; fmt.wBitsPerSample = 32; fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; fmt.cbSize = 0; XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb_buf, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf, 0, sizeof(buf)); buf.AudioBytes = 4410 * fmt.nBlockAlign; buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes); fill_buf((float*)buf.pAudioData, &fmt, 440, 4410); /* submit same buffer fragment 5 times */ for(i = 0; i < 5; ++i){ testdata[i].idx = i; testdata[i].src = src; buf.pContext = &testdata[i]; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); } hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW); ok(hr == S_OK, "Start failed: %08x\n", hr); XA2CALL_0(StartEngine); ok(hr == S_OK, "StartEngine failed: %08x\n", hr); while(1){ if(xaudio27) IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state); else IXAudio2SourceVoice_GetState(src, &state, 0); if(state.SamplesPlayed >= 4410 * 5) break; Sleep(100); } ok(state.SamplesPlayed == 4410 * 5, "Got wrong samples played\n"); HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData); if(xaudio27) IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src); else IXAudio2SourceVoice_DestroyVoice(src); IXAudio2MasteringVoice_DestroyVoice(master); }
static void test_simple_streaming(IXAudio2 *xa) { HRESULT hr; IXAudio2MasteringVoice *master; IXAudio2SourceVoice *src, *src2; IUnknown *vumeter; WAVEFORMATEX fmt; XAUDIO2_BUFFER buf, buf2; XAUDIO2_VOICE_STATE state; XAUDIO2_EFFECT_DESCRIPTOR effect; XAUDIO2_EFFECT_CHAIN chain; memset(&ecb_state, 0, sizeof(ecb_state)); memset(&src1_state, 0, sizeof(src1_state)); memset(&src2_state, 0, sizeof(src2_state)); XA2CALL_0V(StopEngine); /* Tests show in native XA2.8, ECB is called from a mixer thread, but VCBs * may be called from other threads in any order. So we can't rely on any * sequencing between VCB calls. * * XA2.7 does all mixing from a single thread, so call sequence can be * tested. */ XA2CALL(RegisterForCallbacks, &ecb); ok(hr == S_OK, "RegisterForCallbacks failed: %08x\n", hr); if(xaudio27) hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL); else hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects); ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr); /* create first source voice */ fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; fmt.nChannels = 2; fmt.nSamplesPerSec = 44100; fmt.wBitsPerSample = 32; fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; fmt.cbSize = 0; XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb1, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf, 0, sizeof(buf)); buf.AudioBytes = 22050 * fmt.nBlockAlign; buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes); fill_buf((float*)buf.pAudioData, &fmt, 440, 22050); hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW); ok(hr == S_OK, "Start failed: %08x\n", hr); /* create second source voice */ XA2CALL(CreateSourceVoice, &src2, &fmt, 0, 1.f, &vcb2, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf2, 0, sizeof(buf2)); buf2.AudioBytes = 22050 * fmt.nBlockAlign; buf2.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf2.AudioBytes); fill_buf((float*)buf2.pAudioData, &fmt, 220, 22050); hr = IXAudio2SourceVoice_SubmitSourceBuffer(src2, &buf2, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); hr = IXAudio2SourceVoice_Start(src2, 0, XAUDIO2_COMMIT_NOW); ok(hr == S_OK, "Start failed: %08x\n", hr); XA2CALL_0(StartEngine); ok(hr == S_OK, "StartEngine failed: %08x\n", hr); /* hook up volume meter */ if(xaudio27){ hr = CoCreateInstance(&CLSID_AudioVolumeMeter, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&vumeter); ok(hr == S_OK, "CoCreateInstance(AudioVolumeMeter) failed: %08x\n", hr); }else{ hr = pCreateAudioVolumeMeter(&vumeter); ok(hr == S_OK, "CreateAudioVolumeMeter failed: %08x\n", hr); } effect.InitialState = TRUE; effect.OutputChannels = 2; effect.pEffect = vumeter; chain.EffectCount = 1; chain.pEffectDescriptors = &effect; hr = IXAudio2MasteringVoice_SetEffectChain(master, &chain); ok(hr == S_OK, "SetEffectchain failed: %08x\n", hr); IUnknown_Release(vumeter); while(1){ if(xaudio27) IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state); else IXAudio2SourceVoice_GetState(src, &state, 0); if(state.SamplesPlayed >= 22050) break; Sleep(100); } ok(state.SamplesPlayed == 22050, "Got wrong samples played\n"); HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData); HeapFree(GetProcessHeap(), 0, (void*)buf2.pAudioData); if(xaudio27){ IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src); IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src2); }else{ IXAudio2SourceVoice_DestroyVoice(src); IXAudio2SourceVoice_DestroyVoice(src2); } IXAudio2MasteringVoice_DestroyVoice(master); XA2CALL_V(UnregisterForCallbacks, &ecb); }
static void test_buffer_callbacks(IXAudio2 *xa) { HRESULT hr; IXAudio2MasteringVoice *master; IXAudio2SourceVoice *src; WAVEFORMATEX fmt; XAUDIO2_BUFFER buf; XAUDIO2_VOICE_STATE state; struct vcb_buf_testdata testdata[5]; int i, timeout; obs_calls = 0; obe_calls = 0; XA2CALL_0V(StopEngine); if(xaudio27) hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL); else hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects); ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr); /* test OnBufferStart/End callbacks */ fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; fmt.nChannels = 2; fmt.nSamplesPerSec = 44100; fmt.wBitsPerSample = 32; fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; fmt.cbSize = 0; XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb_buf, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf, 0, sizeof(buf)); buf.AudioBytes = 4410 * fmt.nBlockAlign; buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes); fill_buf((float*)buf.pAudioData, &fmt, 440, 4410); /* submit same buffer fragment 5 times */ for(i = 0; i < 5; ++i){ testdata[i].idx = i; testdata[i].src = src; buf.pContext = &testdata[i]; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); } hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW); ok(hr == S_OK, "Start failed: %08x\n", hr); XA2CALL_0(StartEngine); ok(hr == S_OK, "StartEngine failed: %08x\n", hr); if(xaudio27){ hr = IXAudio27SourceVoice_SetSourceSampleRate((IXAudio27SourceVoice*)src, 48000); todo_wine ok(hr == S_OK, "SetSourceSampleRate failed: %08x\n", hr); }else{ hr = IXAudio2SourceVoice_SetSourceSampleRate(src, 48000); ok(hr == XAUDIO2_E_INVALID_CALL, "SetSourceSampleRate should have failed: %08x\n", hr); } while(1){ if(xaudio27) IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state); else IXAudio2SourceVoice_GetState(src, &state, 0); if(state.SamplesPlayed >= 4410 * 5) break; Sleep(100); } ok(state.SamplesPlayed == 4410 * 5, "Got wrong samples played\n"); if(xaudio27) IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src); else IXAudio2SourceVoice_DestroyVoice(src); /* test OnStreamEnd callback */ XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &loop_buf, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); buf.Flags = XAUDIO2_END_OF_STREAM; hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW); ok(hr == S_OK, "Start failed: %08x\n", hr); timeout = 0; while(nstreamends == 0 && timeout < 1000){ Sleep(100); timeout += 100; } ok(nstreamends == 1, "Got wrong number of OnStreamEnd calls: %u\n", nstreamends); /* xaudio resets SamplesPlayed after processing an end-of-stream buffer */ if(xaudio27) IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state); else IXAudio2SourceVoice_GetState(src, &state, 0); ok(state.SamplesPlayed == 0, "Got wrong samples played\n"); if(xaudio27) IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src); else IXAudio2SourceVoice_DestroyVoice(src); IXAudio2MasteringVoice_DestroyVoice(master); HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData); }
BYTE snd_start(void) { int psamples; if (!cfg->apu.channel[APU_MASTER]) { return (EXIT_OK); } // come prima cosa blocco eventuali riproduzioni snd_stop(); memset(&snd, 0x00, sizeof(_snd)); memset(&xaudio2, 0x00, sizeof(xaudio2)); memset(&cbd, 0x00, sizeof(_callback_data)); snd.cache = &cbd; audio_channels(cfg->channels_mode); switch (cfg->samplerate) { case S48000: snd.samplerate = 48000; break; case S44100: snd.samplerate = 44100; break; case S22050: snd.samplerate = 22050; break; case S11025: snd.samplerate = 11025; break; } if (XAudio2Create(&xaudio2.engine, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { MessageBox(NULL, "ATTENTION: Unable to create XAudio2 object. Probably you\n" "have an incomplete installation of DirectX 10." , "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } if (IXAudio2_CreateMasteringVoice(xaudio2.engine, &xaudio2.master, snd.channels, snd.samplerate, 0, 0, NULL) != S_OK) { MessageBox(NULL, "ATTENTION: Unable to create XAudio2 master voice.", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } { WAVEFORMATEX wfm; memset(&wfm, 0, sizeof(wfm)); wfm.wFormatTag = WAVE_FORMAT_PCM; wfm.nChannels = snd.channels; wfm.wBitsPerSample = 16; wfm.nSamplesPerSec = snd.samplerate; wfm.nBlockAlign = (wfm.nChannels * wfm.wBitsPerSample) / 8; wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign; wfm.cbSize = sizeof(wfm); if (IXAudio2_CreateSourceVoice(xaudio2.engine, &xaudio2.source, &wfm, XAUDIO2_VOICE_NOSRC | XAUDIO2_VOICE_NOPITCH, XAUDIO2_DEFAULT_FREQ_RATIO, &callbacks, NULL, NULL) != S_OK) { MessageBox(NULL, "ATTENTION: Unable to create XAudio2 source voice.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } } { double factor = (1.0f / 48000.0f) * (double) snd.samplerate; psamples = ((1024 * factor) + ((512 * factor) * cfg->audio_buffer_factor)); } snd.samples = psamples * 2; snd.frequency = machine.cpu_hz / (double) snd.samplerate; xaudio2.opened = TRUE; #if !defined (RELEASE) xaudio2.tick = gui_get_ms(); #endif { // dimensione in bytes del buffer snd.buffer.size = (psamples * snd.channels * sizeof(*cbd.write)) * 5; snd.buffer.limit.low = (snd.buffer.size / 100) * 25; snd.buffer.limit.high = (snd.buffer.size / 100) * 55; #if !defined (RELEASE) printf("softw bsize : %-6d - %-6d\n", snd.buffer.size, snd.samples); printf("softw limit : %-6d - %-6d\n", snd.buffer.limit.low, snd.buffer.limit.high); #endif // alloco il buffer in memoria if (!(cbd.start = (SWORD *) malloc(snd.buffer.size))) { MessageBox(NULL, "ATTENTION: Unable to allocate audio buffers.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } if (!(cbd.silence = (SWORD *) malloc(snd.buffer.size))) { MessageBox(NULL, "ATTENTION: Unable to allocate silence buffer.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } // inizializzo il frame di scrittura cbd.write = cbd.start; // inizializzo il frame di lettura cbd.read = (SBYTE *) cbd.start; // punto alla fine del buffer cbd.end = cbd.read + snd.buffer.size; // creo il lock if ((xaudio2.semaphore = CreateSemaphore(NULL, 1, 2, NULL)) == NULL) { MessageBox(NULL, "ATTENTION: Unable to create XAudio2 semaphore.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } // azzero completamente i buffers memset(cbd.start, 0x00, snd.buffer.size); // azzero completamente il buffer del silenzio memset(cbd.silence, 0x00, snd.buffer.size); // azzero completamente la struttura XAUDIO2_BUFFER memset(&xaudio2.buffer, 0x00, sizeof(xaudio2.buffer)); xaudio2.buffer.AudioBytes = psamples * sizeof(*cbd.write) * snd.channels; //xaudio2.buffer.pAudioData = (const BYTE *) cbd.read; xaudio2.buffer.pAudioData = (const BYTE *) cbd.silence; xaudio2.buffer.PlayBegin = 0; xaudio2.buffer.PlayLength = psamples; xaudio2.buffer.LoopBegin = 0; xaudio2.buffer.LoopLength = 0; xaudio2.buffer.LoopCount = 0; xaudio2.buffer.pContext = snd.cache; cbd.xa2buffer = &xaudio2.buffer; cbd.xa2source = xaudio2.source; cbd.lock = xaudio2.semaphore; if (IXAudio2SourceVoice_SubmitSourceBuffer(xaudio2.source, (const XAUDIO2_BUFFER *) cbd.xa2buffer, NULL) != S_OK) { MessageBox(NULL, "ATTENTION: Unable to set sound engine.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } } if (extcl_snd_start) { extcl_snd_start((WORD) snd.samplerate); } audio_channels_init_mode(); audio_quality(cfg->audio_quality); if(IXAudio2_StartEngine(xaudio2.engine) != S_OK) { MessageBox(NULL, "ATTENTION: Unable to start sound engine.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } if(IXAudio2SourceVoice_Start(xaudio2.source, 0, XAUDIO2_COMMIT_NOW) != S_OK) { MessageBox(NULL, "ATTENTION: Unable to start source voice.\n", "Error!", MB_ICONEXCLAMATION | MB_OK); return (EXIT_ERROR); } return (EXIT_OK); }