audio_driver_coreaudio.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /**************************************************************************/
  2. /* audio_driver_coreaudio.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "audio_driver_coreaudio.h"
  31. #ifdef COREAUDIO_ENABLED
  32. #include "core/config/project_settings.h"
  33. #include "core/os/os.h"
  34. #define kOutputBus 0
  35. #define kInputBus 1
  36. #ifdef MACOS_ENABLED
  37. OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID,
  38. UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
  39. void *inClientData) {
  40. AudioDriverCoreAudio *driver = static_cast<AudioDriverCoreAudio *>(inClientData);
  41. // If our selected input device is the Default, call set_input_device to update the
  42. // kAudioOutputUnitProperty_CurrentDevice property
  43. if (driver->input_device_name == "Default") {
  44. driver->set_input_device("Default");
  45. }
  46. return noErr;
  47. }
  48. OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID,
  49. UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
  50. void *inClientData) {
  51. AudioDriverCoreAudio *driver = static_cast<AudioDriverCoreAudio *>(inClientData);
  52. // If our selected output device is the Default call set_output_device to update the
  53. // kAudioOutputUnitProperty_CurrentDevice property
  54. if (driver->output_device_name == "Default") {
  55. driver->set_output_device("Default");
  56. }
  57. return noErr;
  58. }
  59. #endif
  60. Error AudioDriverCoreAudio::init() {
  61. AudioComponentDescription desc;
  62. memset(&desc, 0, sizeof(desc));
  63. desc.componentType = kAudioUnitType_Output;
  64. #ifdef MACOS_ENABLED
  65. desc.componentSubType = kAudioUnitSubType_HALOutput;
  66. #else
  67. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  68. #endif
  69. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  70. AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
  71. ERR_FAIL_NULL_V(comp, FAILED);
  72. OSStatus result = AudioComponentInstanceNew(comp, &audio_unit);
  73. ERR_FAIL_COND_V(result != noErr, FAILED);
  74. #ifdef MACOS_ENABLED
  75. AudioObjectPropertyAddress prop;
  76. prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
  77. prop.mScope = kAudioObjectPropertyScopeGlobal;
  78. prop.mElement = kAudioObjectPropertyElementMaster;
  79. result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
  80. ERR_FAIL_COND_V(result != noErr, FAILED);
  81. #endif
  82. AudioStreamBasicDescription strdesc;
  83. memset(&strdesc, 0, sizeof(strdesc));
  84. UInt32 size = sizeof(strdesc);
  85. result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size);
  86. ERR_FAIL_COND_V(result != noErr, FAILED);
  87. switch (strdesc.mChannelsPerFrame) {
  88. case 2: // Stereo
  89. case 4: // Surround 3.1
  90. case 6: // Surround 5.1
  91. case 8: // Surround 7.1
  92. channels = strdesc.mChannelsPerFrame;
  93. break;
  94. default:
  95. // Unknown number of channels, default to stereo
  96. channels = 2;
  97. break;
  98. }
  99. mix_rate = _get_configured_mix_rate();
  100. memset(&strdesc, 0, sizeof(strdesc));
  101. strdesc.mFormatID = kAudioFormatLinearPCM;
  102. strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
  103. strdesc.mChannelsPerFrame = channels;
  104. strdesc.mSampleRate = mix_rate;
  105. strdesc.mFramesPerPacket = 1;
  106. strdesc.mBitsPerChannel = 16;
  107. strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
  108. strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
  109. result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
  110. ERR_FAIL_COND_V(result != noErr, FAILED);
  111. int latency = Engine::get_singleton()->get_audio_output_latency();
  112. // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
  113. buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
  114. #ifdef MACOS_ENABLED
  115. result = AudioUnitSetProperty(audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, kOutputBus, &buffer_frames, sizeof(UInt32));
  116. ERR_FAIL_COND_V(result != noErr, FAILED);
  117. #endif
  118. unsigned int buffer_size = buffer_frames * channels;
  119. samples_in.resize(buffer_size);
  120. input_buf.resize(buffer_size);
  121. print_verbose("CoreAudio: detected " + itos(channels) + " channels");
  122. print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
  123. AURenderCallbackStruct callback;
  124. memset(&callback, 0, sizeof(AURenderCallbackStruct));
  125. callback.inputProc = &AudioDriverCoreAudio::output_callback;
  126. callback.inputProcRefCon = this;
  127. result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
  128. ERR_FAIL_COND_V(result != noErr, FAILED);
  129. result = AudioUnitInitialize(audio_unit);
  130. ERR_FAIL_COND_V(result != noErr, FAILED);
  131. if (GLOBAL_GET("audio/driver/enable_input")) {
  132. return init_input_device();
  133. }
  134. return OK;
  135. }
  136. OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
  137. AudioUnitRenderActionFlags *ioActionFlags,
  138. const AudioTimeStamp *inTimeStamp,
  139. UInt32 inBusNumber, UInt32 inNumberFrames,
  140. AudioBufferList *ioData) {
  141. AudioDriverCoreAudio *ad = static_cast<AudioDriverCoreAudio *>(inRefCon);
  142. if (!ad->active || !ad->try_lock()) {
  143. for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
  144. AudioBuffer *abuf = &ioData->mBuffers[i];
  145. memset(abuf->mData, 0, abuf->mDataByteSize);
  146. }
  147. return 0;
  148. }
  149. ad->start_counting_ticks();
  150. for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
  151. AudioBuffer *abuf = &ioData->mBuffers[i];
  152. unsigned int frames_left = inNumberFrames;
  153. int16_t *out = (int16_t *)abuf->mData;
  154. while (frames_left) {
  155. unsigned int frames = MIN(frames_left, ad->buffer_frames);
  156. ad->audio_server_process(frames, ad->samples_in.ptrw());
  157. for (unsigned int j = 0; j < frames * ad->channels; j++) {
  158. out[j] = ad->samples_in[j] >> 16;
  159. }
  160. frames_left -= frames;
  161. out += frames * ad->channels;
  162. }
  163. }
  164. ad->stop_counting_ticks();
  165. ad->unlock();
  166. return 0;
  167. }
  168. OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
  169. AudioUnitRenderActionFlags *ioActionFlags,
  170. const AudioTimeStamp *inTimeStamp,
  171. UInt32 inBusNumber, UInt32 inNumberFrames,
  172. AudioBufferList *ioData) {
  173. AudioDriverCoreAudio *ad = static_cast<AudioDriverCoreAudio *>(inRefCon);
  174. if (!ad->active) {
  175. return 0;
  176. }
  177. ad->lock();
  178. ad->start_counting_ticks();
  179. AudioBufferList bufferList;
  180. bufferList.mNumberBuffers = 1;
  181. bufferList.mBuffers[0].mData = ad->input_buf.ptrw();
  182. bufferList.mBuffers[0].mNumberChannels = ad->capture_channels;
  183. bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t);
  184. OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
  185. if (result == noErr) {
  186. for (unsigned int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
  187. int32_t sample = ad->input_buf[i] << 16;
  188. ad->input_buffer_write(sample);
  189. if (ad->capture_channels == 1) {
  190. // In case input device is single channel convert it to Stereo
  191. ad->input_buffer_write(sample);
  192. }
  193. }
  194. } else {
  195. ERR_PRINT("AudioUnitRender failed, code: " + itos(result));
  196. }
  197. ad->stop_counting_ticks();
  198. ad->unlock();
  199. return result;
  200. }
  201. void AudioDriverCoreAudio::start() {
  202. if (!active) {
  203. OSStatus result = AudioOutputUnitStart(audio_unit);
  204. if (result != noErr) {
  205. ERR_PRINT("AudioOutputUnitStart failed, code: " + itos(result));
  206. } else {
  207. active = true;
  208. }
  209. }
  210. }
  211. void AudioDriverCoreAudio::stop() {
  212. if (active) {
  213. OSStatus result = AudioOutputUnitStop(audio_unit);
  214. if (result != noErr) {
  215. ERR_PRINT("AudioOutputUnitStop failed, code: " + itos(result));
  216. } else {
  217. active = false;
  218. }
  219. }
  220. }
  221. int AudioDriverCoreAudio::get_mix_rate() const {
  222. return mix_rate;
  223. }
  224. AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
  225. return get_speaker_mode_by_total_channels(channels);
  226. }
  227. void AudioDriverCoreAudio::lock() {
  228. mutex.lock();
  229. }
  230. void AudioDriverCoreAudio::unlock() {
  231. mutex.unlock();
  232. }
  233. bool AudioDriverCoreAudio::try_lock() {
  234. return mutex.try_lock();
  235. }
  236. void AudioDriverCoreAudio::finish() {
  237. finish_input_device();
  238. if (audio_unit) {
  239. OSStatus result;
  240. lock();
  241. AURenderCallbackStruct callback;
  242. memset(&callback, 0, sizeof(AURenderCallbackStruct));
  243. result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
  244. if (result != noErr) {
  245. ERR_PRINT("AudioUnitSetProperty failed");
  246. }
  247. if (active) {
  248. result = AudioOutputUnitStop(audio_unit);
  249. if (result != noErr) {
  250. ERR_PRINT("AudioOutputUnitStop failed");
  251. }
  252. active = false;
  253. }
  254. result = AudioUnitUninitialize(audio_unit);
  255. if (result != noErr) {
  256. ERR_PRINT("AudioUnitUninitialize failed");
  257. }
  258. #ifdef MACOS_ENABLED
  259. AudioObjectPropertyAddress prop;
  260. prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
  261. prop.mScope = kAudioObjectPropertyScopeGlobal;
  262. prop.mElement = kAudioObjectPropertyElementMaster;
  263. result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
  264. if (result != noErr) {
  265. ERR_PRINT("AudioObjectRemovePropertyListener failed");
  266. }
  267. #endif
  268. result = AudioComponentInstanceDispose(audio_unit);
  269. if (result != noErr) {
  270. ERR_PRINT("AudioComponentInstanceDispose failed");
  271. }
  272. audio_unit = nullptr;
  273. unlock();
  274. }
  275. }
  276. Error AudioDriverCoreAudio::init_input_device() {
  277. AudioComponentDescription desc;
  278. memset(&desc, 0, sizeof(desc));
  279. desc.componentType = kAudioUnitType_Output;
  280. #ifdef MACOS_ENABLED
  281. desc.componentSubType = kAudioUnitSubType_HALOutput;
  282. #else
  283. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  284. #endif
  285. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  286. AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
  287. ERR_FAIL_NULL_V(comp, FAILED);
  288. OSStatus result = AudioComponentInstanceNew(comp, &input_unit);
  289. ERR_FAIL_COND_V(result != noErr, FAILED);
  290. #ifdef MACOS_ENABLED
  291. AudioObjectPropertyAddress prop;
  292. prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
  293. prop.mScope = kAudioObjectPropertyScopeGlobal;
  294. prop.mElement = kAudioObjectPropertyElementMaster;
  295. result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
  296. ERR_FAIL_COND_V(result != noErr, FAILED);
  297. #endif
  298. UInt32 flag = 1;
  299. result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
  300. ERR_FAIL_COND_V(result != noErr, FAILED);
  301. flag = 0;
  302. result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag));
  303. ERR_FAIL_COND_V(result != noErr, FAILED);
  304. UInt32 size;
  305. #ifdef MACOS_ENABLED
  306. AudioDeviceID deviceId;
  307. size = sizeof(AudioDeviceID);
  308. AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
  309. result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &deviceId);
  310. ERR_FAIL_COND_V(result != noErr, FAILED);
  311. result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
  312. ERR_FAIL_COND_V(result != noErr, FAILED);
  313. #endif
  314. AudioStreamBasicDescription strdesc;
  315. memset(&strdesc, 0, sizeof(strdesc));
  316. size = sizeof(strdesc);
  317. result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
  318. ERR_FAIL_COND_V(result != noErr, FAILED);
  319. switch (strdesc.mChannelsPerFrame) {
  320. case 1: // Mono
  321. capture_channels = 1;
  322. break;
  323. case 2: // Stereo
  324. capture_channels = 2;
  325. break;
  326. default:
  327. // Unknown number of channels, default to stereo
  328. capture_channels = 2;
  329. break;
  330. }
  331. mix_rate = _get_configured_mix_rate();
  332. memset(&strdesc, 0, sizeof(strdesc));
  333. strdesc.mFormatID = kAudioFormatLinearPCM;
  334. strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
  335. strdesc.mChannelsPerFrame = capture_channels;
  336. strdesc.mSampleRate = mix_rate;
  337. strdesc.mFramesPerPacket = 1;
  338. strdesc.mBitsPerChannel = 16;
  339. strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
  340. strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
  341. result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
  342. ERR_FAIL_COND_V(result != noErr, FAILED);
  343. AURenderCallbackStruct callback;
  344. memset(&callback, 0, sizeof(AURenderCallbackStruct));
  345. callback.inputProc = &AudioDriverCoreAudio::input_callback;
  346. callback.inputProcRefCon = this;
  347. result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback));
  348. ERR_FAIL_COND_V(result != noErr, FAILED);
  349. result = AudioUnitInitialize(input_unit);
  350. ERR_FAIL_COND_V(result != noErr, FAILED);
  351. return OK;
  352. }
  353. void AudioDriverCoreAudio::finish_input_device() {
  354. if (input_unit) {
  355. lock();
  356. AURenderCallbackStruct callback;
  357. memset(&callback, 0, sizeof(AURenderCallbackStruct));
  358. OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
  359. if (result != noErr) {
  360. ERR_PRINT("AudioUnitSetProperty failed");
  361. }
  362. result = AudioUnitUninitialize(input_unit);
  363. if (result != noErr) {
  364. ERR_PRINT("AudioUnitUninitialize failed");
  365. }
  366. #ifdef MACOS_ENABLED
  367. AudioObjectPropertyAddress prop;
  368. prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
  369. prop.mScope = kAudioObjectPropertyScopeGlobal;
  370. prop.mElement = kAudioObjectPropertyElementMaster;
  371. result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
  372. if (result != noErr) {
  373. ERR_PRINT("AudioObjectRemovePropertyListener failed");
  374. }
  375. #endif
  376. result = AudioComponentInstanceDispose(input_unit);
  377. if (result != noErr) {
  378. ERR_PRINT("AudioComponentInstanceDispose failed");
  379. }
  380. input_unit = nullptr;
  381. unlock();
  382. }
  383. }
  384. Error AudioDriverCoreAudio::input_start() {
  385. input_buffer_init(buffer_frames);
  386. OSStatus result = AudioOutputUnitStart(input_unit);
  387. if (result != noErr) {
  388. ERR_PRINT("AudioOutputUnitStart failed, code: " + itos(result));
  389. }
  390. return OK;
  391. }
  392. Error AudioDriverCoreAudio::input_stop() {
  393. if (input_unit) {
  394. OSStatus result = AudioOutputUnitStop(input_unit);
  395. if (result != noErr) {
  396. ERR_PRINT("AudioOutputUnitStop failed, code: " + itos(result));
  397. }
  398. }
  399. return OK;
  400. }
  401. #ifdef MACOS_ENABLED
  402. PackedStringArray AudioDriverCoreAudio::_get_device_list(bool input) {
  403. PackedStringArray list;
  404. list.push_back("Default");
  405. AudioObjectPropertyAddress prop;
  406. prop.mSelector = kAudioHardwarePropertyDevices;
  407. prop.mScope = kAudioObjectPropertyScopeGlobal;
  408. prop.mElement = kAudioObjectPropertyElementMaster;
  409. UInt32 size = 0;
  410. AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
  411. AudioDeviceID *audioDevices = (AudioDeviceID *)memalloc(size);
  412. ERR_FAIL_NULL_V_MSG(audioDevices, list, "Out of memory.");
  413. AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
  414. UInt32 deviceCount = size / sizeof(AudioDeviceID);
  415. for (UInt32 i = 0; i < deviceCount; i++) {
  416. prop.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
  417. prop.mSelector = kAudioDevicePropertyStreamConfiguration;
  418. AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
  419. AudioBufferList *bufferList = (AudioBufferList *)memalloc(size);
  420. ERR_FAIL_NULL_V_MSG(bufferList, list, "Out of memory.");
  421. AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
  422. UInt32 channelCount = 0;
  423. for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) {
  424. channelCount += bufferList->mBuffers[j].mNumberChannels;
  425. }
  426. memfree(bufferList);
  427. if (channelCount >= 1) {
  428. CFStringRef cfname;
  429. size = sizeof(CFStringRef);
  430. prop.mSelector = kAudioObjectPropertyName;
  431. AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, &cfname);
  432. CFIndex length = CFStringGetLength(cfname);
  433. CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
  434. char *buffer = (char *)memalloc(maxSize);
  435. ERR_FAIL_NULL_V_MSG(buffer, list, "Out of memory.");
  436. if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
  437. // Append the ID to the name in case we have devices with duplicate name
  438. list.push_back(String::utf8(buffer) + " (" + itos(audioDevices[i]) + ")");
  439. }
  440. memfree(buffer);
  441. }
  442. }
  443. memfree(audioDevices);
  444. return list;
  445. }
  446. void AudioDriverCoreAudio::_set_device(const String &output_device, bool input) {
  447. AudioDeviceID deviceId;
  448. bool found = false;
  449. if (output_device != "Default") {
  450. AudioObjectPropertyAddress prop;
  451. prop.mSelector = kAudioHardwarePropertyDevices;
  452. prop.mScope = kAudioObjectPropertyScopeGlobal;
  453. prop.mElement = kAudioObjectPropertyElementMaster;
  454. UInt32 size = 0;
  455. AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
  456. AudioDeviceID *audioDevices = (AudioDeviceID *)memalloc(size);
  457. ERR_FAIL_NULL_MSG(audioDevices, "Out of memory.");
  458. AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
  459. UInt32 deviceCount = size / sizeof(AudioDeviceID);
  460. for (UInt32 i = 0; i < deviceCount && !found; i++) {
  461. prop.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
  462. prop.mSelector = kAudioDevicePropertyStreamConfiguration;
  463. AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
  464. AudioBufferList *bufferList = (AudioBufferList *)memalloc(size);
  465. ERR_FAIL_NULL_MSG(bufferList, "Out of memory.");
  466. AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
  467. UInt32 channelCount = 0;
  468. for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) {
  469. channelCount += bufferList->mBuffers[j].mNumberChannels;
  470. }
  471. memfree(bufferList);
  472. if (channelCount >= 1) {
  473. CFStringRef cfname;
  474. size = sizeof(CFStringRef);
  475. prop.mSelector = kAudioObjectPropertyName;
  476. AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, &cfname);
  477. CFIndex length = CFStringGetLength(cfname);
  478. CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
  479. char *buffer = (char *)memalloc(maxSize);
  480. ERR_FAIL_NULL_MSG(buffer, "Out of memory.");
  481. if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
  482. String name = String::utf8(buffer) + " (" + itos(audioDevices[i]) + ")";
  483. if (name == output_device) {
  484. deviceId = audioDevices[i];
  485. found = true;
  486. }
  487. }
  488. memfree(buffer);
  489. }
  490. }
  491. memfree(audioDevices);
  492. }
  493. if (!found) {
  494. // If we haven't found the desired device get the system default one
  495. UInt32 size = sizeof(AudioDeviceID);
  496. UInt32 elem = input ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice;
  497. AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
  498. OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &deviceId);
  499. ERR_FAIL_COND(result != noErr);
  500. found = true;
  501. }
  502. if (found) {
  503. OSStatus result = AudioUnitSetProperty(input ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
  504. ERR_FAIL_COND(result != noErr);
  505. if (input) {
  506. // Reset audio input to keep synchronization.
  507. input_position = 0;
  508. input_size = 0;
  509. }
  510. }
  511. }
  512. PackedStringArray AudioDriverCoreAudio::get_output_device_list() {
  513. return _get_device_list();
  514. }
  515. String AudioDriverCoreAudio::get_output_device() {
  516. return output_device_name;
  517. }
  518. void AudioDriverCoreAudio::set_output_device(const String &p_name) {
  519. output_device_name = p_name;
  520. if (active) {
  521. _set_device(output_device_name);
  522. }
  523. }
  524. PackedStringArray AudioDriverCoreAudio::get_input_device_list() {
  525. return _get_device_list(true);
  526. }
  527. String AudioDriverCoreAudio::get_input_device() {
  528. return input_device_name;
  529. }
  530. void AudioDriverCoreAudio::set_input_device(const String &p_name) {
  531. input_device_name = p_name;
  532. if (active) {
  533. _set_device(input_device_name, true);
  534. }
  535. }
  536. #endif
  537. AudioDriverCoreAudio::AudioDriverCoreAudio() {
  538. samples_in.clear();
  539. }
  540. #endif // COREAUDIO_ENABLED