wasapi.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include <avrt.h>
  2. #include <mmdeviceapi.h>
  3. #include <audioclient.h>
  4. #include <audiopolicy.h>
  5. #include <devicetopology.h>
  6. #include <endpointvolume.h>
  7. #include <functiondiscoverykeys_devpkey.h>
  8. struct AudioWASAPI : AudioDriver {
  9. AudioWASAPI& self = *this;
  10. AudioWASAPI(Audio& super) : AudioDriver(super) { construct(); }
  11. ~AudioWASAPI() { destruct(); }
  12. auto create() -> bool override {
  13. super.setExclusive(false);
  14. super.setDevice(hasDevices().first());
  15. super.setBlocking(false);
  16. super.setChannels(2);
  17. super.setFrequency(48000);
  18. super.setLatency(40);
  19. return initialize();
  20. }
  21. auto driver() -> string override { return "WASAPI"; }
  22. auto ready() -> bool override { return self.isReady; }
  23. auto hasExclusive() -> bool override { return true; }
  24. auto hasBlocking() -> bool override { return true; }
  25. auto hasDevices() -> vector<string> override {
  26. vector<string> devices;
  27. for(auto& device : self.devices) devices.append(device.name);
  28. return devices;
  29. }
  30. auto hasChannels() -> vector<uint> override {
  31. return {self.channels};
  32. }
  33. auto hasFrequencies() -> vector<uint> override {
  34. return {self.frequency};
  35. }
  36. auto hasLatencies() -> vector<uint> override {
  37. return {0, 20, 40, 60, 80, 100};
  38. }
  39. auto setExclusive(bool exclusive) -> bool override { return initialize(); }
  40. auto setDevice(string device) -> bool override { return initialize(); }
  41. auto setBlocking(bool blocking) -> bool override { return true; }
  42. auto setFrequency(uint frequency) -> bool override { return initialize(); }
  43. auto setLatency(uint latency) -> bool override { return initialize(); }
  44. auto clear() -> void override {
  45. self.queue.read = 0;
  46. self.queue.write = 0;
  47. self.queue.count = 0;
  48. self.audioClient->Stop();
  49. self.audioClient->Reset();
  50. self.audioClient->Start();
  51. }
  52. auto output(const double samples[]) -> void override {
  53. for(uint n : range(self.channels)) {
  54. self.queue.samples[self.queue.write][n] = samples[n];
  55. }
  56. self.queue.write++;
  57. self.queue.count++;
  58. if(self.queue.count >= self.bufferSize) {
  59. if(WaitForSingleObject(self.eventHandle, self.blocking ? INFINITE : 0) == WAIT_OBJECT_0) {
  60. write();
  61. }
  62. }
  63. }
  64. private:
  65. struct Device {
  66. string id;
  67. string name;
  68. };
  69. vector<Device> devices;
  70. auto construct() -> bool {
  71. if(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&self.enumerator) != S_OK) return false;
  72. IMMDevice* defaultDeviceContext = nullptr;
  73. if(self.enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDeviceContext) != S_OK) return false;
  74. Device defaultDevice;
  75. LPWSTR defaultDeviceString = nullptr;
  76. defaultDeviceContext->GetId(&defaultDeviceString);
  77. defaultDevice.id = (const char*)utf8_t(defaultDeviceString);
  78. CoTaskMemFree(defaultDeviceString);
  79. IMMDeviceCollection* deviceCollection = nullptr;
  80. if(self.enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) != S_OK) return false;
  81. uint deviceCount = 0;
  82. if(deviceCollection->GetCount(&deviceCount) != S_OK) return false;
  83. for(uint deviceIndex : range(deviceCount)) {
  84. IMMDevice* deviceContext = nullptr;
  85. if(deviceCollection->Item(deviceIndex, &deviceContext) != S_OK) continue;
  86. Device device;
  87. LPWSTR deviceString = nullptr;
  88. deviceContext->GetId(&deviceString);
  89. device.id = (const char*)utf8_t(deviceString);
  90. CoTaskMemFree(deviceString);
  91. IPropertyStore* propertyStore = nullptr;
  92. deviceContext->OpenPropertyStore(STGM_READ, &propertyStore);
  93. PROPVARIANT propVariant;
  94. propertyStore->GetValue(PKEY_Device_FriendlyName, &propVariant);
  95. device.name = (const char*)utf8_t(propVariant.pwszVal);
  96. propertyStore->Release();
  97. if(device.id == defaultDevice.id) {
  98. self.devices.prepend(device);
  99. } else {
  100. self.devices.append(device);
  101. }
  102. }
  103. deviceCollection->Release();
  104. return true;
  105. }
  106. auto destruct() -> void {
  107. terminate();
  108. if(self.enumerator) {
  109. self.enumerator->Release();
  110. self.enumerator = nullptr;
  111. }
  112. }
  113. auto initialize() -> bool {
  114. terminate();
  115. string deviceID;
  116. if(auto index = self.devices.find([&](auto& device) { return device.name == self.device; })) {
  117. deviceID = self.devices[*index].id;
  118. } else {
  119. return false;
  120. }
  121. utf16_t deviceString(deviceID);
  122. if(self.enumerator->GetDevice(deviceString, &self.audioDevice) != S_OK) return false;
  123. if(self.audioDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&self.audioClient) != S_OK) return false;
  124. WAVEFORMATEXTENSIBLE waveFormat{};
  125. if(self.exclusive) {
  126. IPropertyStore* propertyStore = nullptr;
  127. if(self.audioDevice->OpenPropertyStore(STGM_READ, &propertyStore) != S_OK) return false;
  128. PROPVARIANT propVariant;
  129. if(propertyStore->GetValue(PKEY_AudioEngine_DeviceFormat, &propVariant) != S_OK) return false;
  130. waveFormat = *(WAVEFORMATEXTENSIBLE*)propVariant.blob.pBlobData;
  131. propertyStore->Release();
  132. if(self.audioClient->GetDevicePeriod(nullptr, &self.devicePeriod) != S_OK) return false;
  133. auto latency = max(self.devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units
  134. auto result = self.audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr);
  135. if(result == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
  136. if(self.audioClient->GetBufferSize(&self.bufferSize) != S_OK) return false;
  137. self.audioClient->Release();
  138. latency = (REFERENCE_TIME)(10'000 * 1'000 * self.bufferSize / waveFormat.Format.nSamplesPerSec);
  139. if(self.audioDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&self.audioClient) != S_OK) return false;
  140. result = self.audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr);
  141. }
  142. if(result != S_OK) return false;
  143. DWORD taskIndex = 0;
  144. self.taskHandle = AvSetMmThreadCharacteristics(L"Pro Audio", &taskIndex);
  145. } else {
  146. WAVEFORMATEX* waveFormatEx = nullptr;
  147. if(self.audioClient->GetMixFormat(&waveFormatEx) != S_OK) return false;
  148. waveFormat = *(WAVEFORMATEXTENSIBLE*)waveFormatEx;
  149. CoTaskMemFree(waveFormatEx);
  150. if(self.audioClient->GetDevicePeriod(&self.devicePeriod, nullptr)) return false;
  151. auto latency = max(self.devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units
  152. if(self.audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, 0, &waveFormat.Format, nullptr) != S_OK) return false;
  153. }
  154. self.eventHandle = CreateEvent(nullptr, false, false, nullptr);
  155. if(self.audioClient->SetEventHandle(self.eventHandle) != S_OK) return false;
  156. if(self.audioClient->GetService(IID_IAudioRenderClient, (void**)&self.renderClient) != S_OK) return false;
  157. if(self.audioClient->GetBufferSize(&self.bufferSize) != S_OK) return false;
  158. self.channels = waveFormat.Format.nChannels;
  159. self.frequency = waveFormat.Format.nSamplesPerSec;
  160. self.mode = waveFormat.SubFormat.Data1;
  161. self.precision = waveFormat.Format.wBitsPerSample;
  162. clear();
  163. return self.isReady = true;
  164. }
  165. auto terminate() -> void {
  166. self.isReady = false;
  167. if(self.audioClient) self.audioClient->Stop();
  168. if(self.renderClient) self.renderClient->Release(), self.renderClient = nullptr;
  169. if(self.audioClient) self.audioClient->Release(), self.audioClient = nullptr;
  170. if(self.audioDevice) self.audioDevice->Release(), self.audioDevice = nullptr;
  171. if(self.eventHandle) CloseHandle(self.eventHandle), self.eventHandle = nullptr;
  172. if(self.taskHandle) AvRevertMmThreadCharacteristics(self.taskHandle), self.taskHandle = nullptr;
  173. }
  174. auto write() -> void {
  175. uint32_t available = self.bufferSize;
  176. if(!self.exclusive) {
  177. uint32_t padding = 0;
  178. self.audioClient->GetCurrentPadding(&padding);
  179. available = self.bufferSize - padding;
  180. }
  181. uint32_t length = min(available, self.queue.count);
  182. uint8_t* buffer = nullptr;
  183. if(self.renderClient->GetBuffer(length, &buffer) == S_OK) {
  184. uint bufferFlags = 0;
  185. for(uint _ : range(length)) {
  186. double samples[8] = {};
  187. if(self.queue.count) {
  188. for(uint n : range(self.channels)) {
  189. samples[n] = self.queue.samples[self.queue.read][n];
  190. }
  191. self.queue.read++;
  192. self.queue.count--;
  193. }
  194. if(self.mode == 1 && self.precision == 16) {
  195. auto output = (uint16_t*)buffer;
  196. for(uint n : range(self.channels)) *output++ = (uint16_t)sclamp<16>(samples[n] * (32768.0 - 1.0));
  197. buffer = (uint8_t*)output;
  198. } else if(self.mode == 1 && self.precision == 32) {
  199. auto output = (uint32_t*)buffer;
  200. for(uint n : range(self.channels)) *output++ = (uint32_t)sclamp<32>(samples[n] * (65536.0 * 32768.0 - 1.0));
  201. buffer = (uint8_t*)output;
  202. } else if(self.mode == 3 && self.precision == 32) {
  203. auto output = (float*)buffer;
  204. for(uint n : range(self.channels)) *output++ = float(max(-1.0, min(+1.0, samples[n])));
  205. buffer = (uint8_t*)output;
  206. } else {
  207. //output silence for unsupported sample formats
  208. bufferFlags = AUDCLNT_BUFFERFLAGS_SILENT;
  209. break;
  210. }
  211. }
  212. self.renderClient->ReleaseBuffer(length, bufferFlags);
  213. }
  214. }
  215. bool isReady = false;
  216. uint mode = 0;
  217. uint precision = 0;
  218. struct Queue {
  219. double samples[65536][8];
  220. uint16_t read;
  221. uint16_t write;
  222. uint16_t count;
  223. } queue;
  224. IMMDeviceEnumerator* enumerator = nullptr;
  225. IMMDevice* audioDevice = nullptr;
  226. IAudioClient* audioClient = nullptr;
  227. IAudioRenderClient* renderClient = nullptr;
  228. HANDLE eventHandle = nullptr;
  229. HANDLE taskHandle = nullptr;
  230. REFERENCE_TIME devicePeriod = 0;
  231. uint32_t bufferSize = 0; //in frames
  232. };