win32_audio_output.cc (3808B)
1 // https://github.com/walbourn/directx-sdk-samples/blob/master/XAudio2/XAudio2AsyncStream/XAudio2AsyncStream.cpp 2 3 #include <windows.h> 4 #include <wrl/client.h> 5 #include <comdecl.h> 6 7 #pragma warning( push ) 8 #pragma warning( disable : 4800 ) 9 #include <xaudio2.h> 10 #pragma warning( pop ) 11 12 #include "intrinsics.h" 13 #include "log.h" 14 #include "platform_audio_output.h" 15 #include "platform_library.h" 16 #include "platform_thread.h" 17 #include "platform_atomic.h" 18 19 struct XAudioCallbacks : public IXAudio2VoiceCallback { 20 void __stdcall OnBufferEnd( void * data ) { 21 HANDLE event = ( HANDLE ) data; 22 SetEvent( event ); 23 } 24 25 void __stdcall OnBufferStart( void * ) { } 26 void __stdcall OnLoopEnd( void * ) { } 27 void __stdcall OnStreamEnd() { } 28 void __stdcall OnVoiceError( void *, HRESULT ) { } 29 void __stdcall OnVoiceProcessingPassStart( u32 ) { } 30 void __stdcall OnVoiceProcessingPassEnd() { } 31 }; 32 33 static Library xaudio2_lib = NULL; 34 35 static IXAudio2 * xaudio2 = NULL; 36 static IXAudio2MasteringVoice * mastering_voice = NULL; 37 38 static XAudioCallbacks callbacks; 39 40 void audio_output_init() { 41 if( FAILED( CoInitializeEx( nullptr, COINIT_MULTITHREADED ) ) ) { 42 FATAL( "CoInitializeEx" ); 43 } 44 45 xaudio2_lib = library_open( "XAudio2_7.dll" ); 46 if( xaudio2_lib == NULL ) { 47 FATAL( "Couldn't open XAudio2_7.dll: {}", library_last_error() ); 48 } 49 50 if( FAILED( XAudio2Create( &xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR ) ) ) { 51 FATAL( "XAudio2Create" ); 52 } 53 54 if( FAILED( xaudio2->CreateMasteringVoice( &mastering_voice ) ) ) { 55 FATAL( "CreateMasteringVoice" ); 56 } 57 } 58 59 void audio_output_term() { 60 xaudio2->StopEngine(); 61 mastering_voice->DestroyVoice(); 62 xaudio2->Release(); 63 library_close( xaudio2_lib ); 64 CoUninitialize(); 65 66 xaudio2_lib = NULL; 67 xaudio2 = NULL; 68 mastering_voice = NULL; 69 } 70 71 static THREAD( audio_output_thread ) { 72 AudioOutputDevice * device = ( AudioOutputDevice * ) data; 73 74 while( load_acquire( &device->shutting_down ) == 0 ) { 75 constexpr u32 num_samples = 512; 76 STATIC_ASSERT( ARRAY_COUNT( device->buffer.samples ) % num_samples == 0 ); 77 78 for( ;; ) { 79 XAUDIO2_VOICE_STATE state; 80 device->voice->GetState( &state ); 81 if( state.BuffersQueued < 2 ) { 82 break; 83 } 84 85 WaitForSingleObject( device->event, INFINITE ); 86 } 87 88 u32 cursor = load_acquire( &device->buffer.cursor ); 89 90 XAUDIO2_BUFFER buf = { }; 91 buf.AudioBytes = num_samples * sizeof( device->buffer.samples[ 0 ] ); 92 buf.pAudioData = ( const BYTE * )( device->buffer.samples + cursor ); 93 buf.pContext = device->event; 94 95 if( FAILED( device->voice->SubmitSourceBuffer( &buf ) ) ) { 96 FATAL( "SubmitSourceBuffer" ); 97 } 98 99 store_release( &device->buffer.cursor, ( cursor + num_samples ) % ARRAY_COUNT( device->buffer.samples ) ); 100 } 101 102 THREAD_END; 103 } 104 105 void audio_output_open( AudioOutputDevice * device ) { 106 WAVEFORMATEX format = { }; 107 format.wFormatTag = WAVE_FORMAT_PCM; 108 format.nChannels = 1; 109 format.nSamplesPerSec = 44100; 110 format.wBitsPerSample = 16; 111 format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; 112 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; 113 114 if( FAILED( xaudio2->CreateSourceVoice( &device->voice, &format, 0, 1.0f, &callbacks ) ) ) { 115 FATAL( "CreateSourceVoice" ); 116 } 117 118 device->event = CreateEvent( NULL, FALSE, FALSE, NULL ); 119 if( device->event == NULL ) { 120 FATAL( "CreateEvent" ); 121 } 122 123 device->voice->Start( 0 ); 124 125 memset( &device->buffer, 0, sizeof( device->buffer ) ); 126 127 store_release( &device->shutting_down, 0 ); 128 thread_init( &device->thread, audio_output_thread, device ); 129 } 130 131 void audio_output_close( AudioOutputDevice * device ) { 132 store_release( &device->shutting_down, 1 ); 133 thread_join( &device->thread ); 134 135 device->voice->Stop( 0 ); 136 device->voice->FlushSourceBuffers(); 137 device->voice->DestroyVoice(); 138 if( CloseHandle( device->event ) == 0 ) { 139 FATAL( "CloseHandle" ); 140 } 141 }