🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

944 lines
32 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "coreaudio.h"
  22. #include <inttypes.h>
  23. #include <stdint.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. #include <cmath>
  29. #include <memory>
  30. #include <string>
  31. #include "alnumeric.h"
  32. #include "core/converter.h"
  33. #include "core/device.h"
  34. #include "core/logging.h"
  35. #include "ringbuffer.h"
  36. #include <AudioUnit/AudioUnit.h>
  37. #include <AudioToolbox/AudioToolbox.h>
  38. namespace {
  39. #if TARGET_OS_IOS || TARGET_OS_TV
  40. #define CAN_ENUMERATE 0
  41. #else
  42. #define CAN_ENUMERATE 1
  43. #endif
  44. #if CAN_ENUMERATE
  45. struct DeviceEntry {
  46. AudioDeviceID mId;
  47. std::string mName;
  48. };
  49. std::vector<DeviceEntry> PlaybackList;
  50. std::vector<DeviceEntry> CaptureList;
  51. OSStatus GetHwProperty(AudioHardwarePropertyID propId, UInt32 dataSize, void *propData)
  52. {
  53. const AudioObjectPropertyAddress addr{propId, kAudioObjectPropertyScopeGlobal,
  54. kAudioObjectPropertyElementMaster};
  55. return AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, nullptr, &dataSize,
  56. propData);
  57. }
  58. OSStatus GetHwPropertySize(AudioHardwarePropertyID propId, UInt32 *outSize)
  59. {
  60. const AudioObjectPropertyAddress addr{propId, kAudioObjectPropertyScopeGlobal,
  61. kAudioObjectPropertyElementMaster};
  62. return AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, nullptr, outSize);
  63. }
  64. OSStatus GetDevProperty(AudioDeviceID devId, AudioDevicePropertyID propId, bool isCapture,
  65. UInt32 elem, UInt32 dataSize, void *propData)
  66. {
  67. static const AudioObjectPropertyScope scopes[2]{kAudioDevicePropertyScopeOutput,
  68. kAudioDevicePropertyScopeInput};
  69. const AudioObjectPropertyAddress addr{propId, scopes[isCapture], elem};
  70. return AudioObjectGetPropertyData(devId, &addr, 0, nullptr, &dataSize, propData);
  71. }
  72. OSStatus GetDevPropertySize(AudioDeviceID devId, AudioDevicePropertyID inPropertyID,
  73. bool isCapture, UInt32 elem, UInt32 *outSize)
  74. {
  75. static const AudioObjectPropertyScope scopes[2]{kAudioDevicePropertyScopeOutput,
  76. kAudioDevicePropertyScopeInput};
  77. const AudioObjectPropertyAddress addr{inPropertyID, scopes[isCapture], elem};
  78. return AudioObjectGetPropertyDataSize(devId, &addr, 0, nullptr, outSize);
  79. }
  80. std::string GetDeviceName(AudioDeviceID devId)
  81. {
  82. std::string devname;
  83. CFStringRef nameRef;
  84. /* Try to get the device name as a CFString, for Unicode name support. */
  85. OSStatus err{GetDevProperty(devId, kAudioDevicePropertyDeviceNameCFString, false, 0,
  86. sizeof(nameRef), &nameRef)};
  87. if(err == noErr)
  88. {
  89. const CFIndex propSize{CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef),
  90. kCFStringEncodingUTF8)};
  91. devname.resize(static_cast<size_t>(propSize)+1, '\0');
  92. CFStringGetCString(nameRef, &devname[0], propSize+1, kCFStringEncodingUTF8);
  93. CFRelease(nameRef);
  94. }
  95. else
  96. {
  97. /* If that failed, just get the C string. Hopefully there's nothing bad
  98. * with this.
  99. */
  100. UInt32 propSize{};
  101. if(GetDevPropertySize(devId, kAudioDevicePropertyDeviceName, false, 0, &propSize))
  102. return devname;
  103. devname.resize(propSize+1, '\0');
  104. if(GetDevProperty(devId, kAudioDevicePropertyDeviceName, false, 0, propSize, &devname[0]))
  105. {
  106. devname.clear();
  107. return devname;
  108. }
  109. }
  110. /* Clear extraneous nul chars that may have been written with the name
  111. * string, and return it.
  112. */
  113. while(!devname.back())
  114. devname.pop_back();
  115. return devname;
  116. }
  117. UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture)
  118. {
  119. UInt32 propSize{};
  120. auto err = GetDevPropertySize(devId, kAudioDevicePropertyStreamConfiguration, isCapture, 0,
  121. &propSize);
  122. if(err)
  123. {
  124. ERR("kAudioDevicePropertyStreamConfiguration size query failed: %u\n", err);
  125. return 0;
  126. }
  127. auto buflist_data = std::make_unique<char[]>(propSize);
  128. auto *buflist = reinterpret_cast<AudioBufferList*>(buflist_data.get());
  129. err = GetDevProperty(devId, kAudioDevicePropertyStreamConfiguration, isCapture, 0, propSize,
  130. buflist);
  131. if(err)
  132. {
  133. ERR("kAudioDevicePropertyStreamConfiguration query failed: %u\n", err);
  134. return 0;
  135. }
  136. UInt32 numChannels{0};
  137. for(size_t i{0};i < buflist->mNumberBuffers;++i)
  138. numChannels += buflist->mBuffers[i].mNumberChannels;
  139. return numChannels;
  140. }
  141. void EnumerateDevices(std::vector<DeviceEntry> &list, bool isCapture)
  142. {
  143. UInt32 propSize{};
  144. if(auto err = GetHwPropertySize(kAudioHardwarePropertyDevices, &propSize))
  145. {
  146. ERR("Failed to get device list size: %u\n", err);
  147. return;
  148. }
  149. auto devIds = std::vector<AudioDeviceID>(propSize/sizeof(AudioDeviceID), kAudioDeviceUnknown);
  150. if(auto err = GetHwProperty(kAudioHardwarePropertyDevices, propSize, devIds.data()))
  151. {
  152. ERR("Failed to get device list: %u\n", err);
  153. return;
  154. }
  155. std::vector<DeviceEntry> newdevs;
  156. newdevs.reserve(devIds.size());
  157. AudioDeviceID defaultId{kAudioDeviceUnknown};
  158. GetHwProperty(isCapture ? kAudioHardwarePropertyDefaultInputDevice :
  159. kAudioHardwarePropertyDefaultOutputDevice, sizeof(defaultId), &defaultId);
  160. if(defaultId != kAudioDeviceUnknown)
  161. {
  162. newdevs.emplace_back(DeviceEntry{defaultId, GetDeviceName(defaultId)});
  163. const auto &entry = newdevs.back();
  164. TRACE("Got device: %s = ID %u\n", entry.mName.c_str(), entry.mId);
  165. }
  166. for(const AudioDeviceID devId : devIds)
  167. {
  168. if(devId == kAudioDeviceUnknown)
  169. continue;
  170. auto match_devid = [devId](const DeviceEntry &entry) noexcept -> bool
  171. { return entry.mId == devId; };
  172. auto match = std::find_if(newdevs.cbegin(), newdevs.cend(), match_devid);
  173. if(match != newdevs.cend()) continue;
  174. auto numChannels = GetDeviceChannelCount(devId, isCapture);
  175. if(numChannels > 0)
  176. {
  177. newdevs.emplace_back(DeviceEntry{devId, GetDeviceName(devId)});
  178. const auto &entry = newdevs.back();
  179. TRACE("Got device: %s = ID %u\n", entry.mName.c_str(), entry.mId);
  180. }
  181. }
  182. if(newdevs.size() > 1)
  183. {
  184. /* Rename entries that have matching names, by appending '#2', '#3',
  185. * etc, as needed.
  186. */
  187. for(auto curitem = newdevs.begin()+1;curitem != newdevs.end();++curitem)
  188. {
  189. auto check_match = [curitem](const DeviceEntry &entry) -> bool
  190. { return entry.mName == curitem->mName; };
  191. if(std::find_if(newdevs.begin(), curitem, check_match) != curitem)
  192. {
  193. std::string name{curitem->mName};
  194. size_t count{1};
  195. auto check_name = [&name](const DeviceEntry &entry) -> bool
  196. { return entry.mName == name; };
  197. do {
  198. name = curitem->mName;
  199. name += " #";
  200. name += std::to_string(++count);
  201. } while(std::find_if(newdevs.begin(), curitem, check_name) != curitem);
  202. curitem->mName = std::move(name);
  203. }
  204. }
  205. }
  206. newdevs.shrink_to_fit();
  207. newdevs.swap(list);
  208. }
  209. #else
  210. static constexpr char ca_device[] = "CoreAudio Default";
  211. #endif
  212. struct CoreAudioPlayback final : public BackendBase {
  213. CoreAudioPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
  214. ~CoreAudioPlayback() override;
  215. OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags,
  216. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
  217. AudioBufferList *ioData) noexcept;
  218. static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
  219. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
  220. AudioBufferList *ioData) noexcept
  221. {
  222. return static_cast<CoreAudioPlayback*>(inRefCon)->MixerProc(ioActionFlags, inTimeStamp,
  223. inBusNumber, inNumberFrames, ioData);
  224. }
  225. void open(const char *name) override;
  226. bool reset() override;
  227. void start() override;
  228. void stop() override;
  229. AudioUnit mAudioUnit{};
  230. uint mFrameSize{0u};
  231. AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD
  232. DEF_NEWDEL(CoreAudioPlayback)
  233. };
  234. CoreAudioPlayback::~CoreAudioPlayback()
  235. {
  236. AudioUnitUninitialize(mAudioUnit);
  237. AudioComponentInstanceDispose(mAudioUnit);
  238. }
  239. OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32,
  240. UInt32, AudioBufferList *ioData) noexcept
  241. {
  242. for(size_t i{0};i < ioData->mNumberBuffers;++i)
  243. {
  244. auto &buffer = ioData->mBuffers[i];
  245. mDevice->renderSamples(buffer.mData, buffer.mDataByteSize/mFrameSize,
  246. buffer.mNumberChannels);
  247. }
  248. return noErr;
  249. }
  250. void CoreAudioPlayback::open(const char *name)
  251. {
  252. #if CAN_ENUMERATE
  253. AudioDeviceID audioDevice{kAudioDeviceUnknown};
  254. if(!name)
  255. GetHwProperty(kAudioHardwarePropertyDefaultOutputDevice, sizeof(audioDevice),
  256. &audioDevice);
  257. else
  258. {
  259. if(PlaybackList.empty())
  260. EnumerateDevices(PlaybackList, false);
  261. auto find_name = [name](const DeviceEntry &entry) -> bool
  262. { return entry.mName == name; };
  263. auto devmatch = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), find_name);
  264. if(devmatch == PlaybackList.cend())
  265. throw al::backend_exception{al::backend_error::NoDevice,
  266. "Device name \"%s\" not found", name};
  267. audioDevice = devmatch->mId;
  268. }
  269. #else
  270. if(!name)
  271. name = ca_device;
  272. else if(strcmp(name, ca_device) != 0)
  273. throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
  274. name};
  275. #endif
  276. /* open the default output unit */
  277. AudioComponentDescription desc{};
  278. desc.componentType = kAudioUnitType_Output;
  279. #if CAN_ENUMERATE
  280. desc.componentSubType = (audioDevice == kAudioDeviceUnknown) ?
  281. kAudioUnitSubType_DefaultOutput : kAudioUnitSubType_HALOutput;
  282. #else
  283. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  284. #endif
  285. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  286. desc.componentFlags = 0;
  287. desc.componentFlagsMask = 0;
  288. AudioComponent comp{AudioComponentFindNext(NULL, &desc)};
  289. if(comp == nullptr)
  290. throw al::backend_exception{al::backend_error::NoDevice, "Could not find audio component"};
  291. AudioUnit audioUnit{};
  292. OSStatus err{AudioComponentInstanceNew(comp, &audioUnit)};
  293. if(err != noErr)
  294. throw al::backend_exception{al::backend_error::NoDevice,
  295. "Could not create component instance: %u", err};
  296. #if CAN_ENUMERATE
  297. if(audioDevice != kAudioDeviceUnknown)
  298. AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_CurrentDevice,
  299. kAudioUnitScope_Global, 0, &audioDevice, sizeof(AudioDeviceID));
  300. #endif
  301. err = AudioUnitInitialize(audioUnit);
  302. if(err != noErr)
  303. throw al::backend_exception{al::backend_error::DeviceError,
  304. "Could not initialize audio unit: %u", err};
  305. /* WARNING: I don't know if "valid" audio unit values are guaranteed to be
  306. * non-0. If not, this logic is broken.
  307. */
  308. if(mAudioUnit)
  309. {
  310. AudioUnitUninitialize(mAudioUnit);
  311. AudioComponentInstanceDispose(mAudioUnit);
  312. }
  313. mAudioUnit = audioUnit;
  314. #if CAN_ENUMERATE
  315. if(name)
  316. mDevice->DeviceName = name;
  317. else
  318. {
  319. UInt32 propSize{sizeof(audioDevice)};
  320. audioDevice = kAudioDeviceUnknown;
  321. AudioUnitGetProperty(audioUnit, kAudioOutputUnitProperty_CurrentDevice,
  322. kAudioUnitScope_Global, 0, &audioDevice, &propSize);
  323. std::string devname{GetDeviceName(audioDevice)};
  324. if(!devname.empty()) mDevice->DeviceName = std::move(devname);
  325. else mDevice->DeviceName = "Unknown Device Name";
  326. }
  327. #else
  328. mDevice->DeviceName = name;
  329. #endif
  330. }
  331. bool CoreAudioPlayback::reset()
  332. {
  333. OSStatus err{AudioUnitUninitialize(mAudioUnit)};
  334. if(err != noErr)
  335. ERR("-- AudioUnitUninitialize failed.\n");
  336. /* retrieve default output unit's properties (output side) */
  337. AudioStreamBasicDescription streamFormat{};
  338. UInt32 size{sizeof(streamFormat)};
  339. err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
  340. 0, &streamFormat, &size);
  341. if(err != noErr || size != sizeof(streamFormat))
  342. {
  343. ERR("AudioUnitGetProperty failed\n");
  344. return false;
  345. }
  346. #if 0
  347. TRACE("Output streamFormat of default output unit -\n");
  348. TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
  349. TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
  350. TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
  351. TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
  352. TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
  353. TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
  354. #endif
  355. /* Use the sample rate from the output unit's current parameters, but reset
  356. * everything else.
  357. */
  358. if(mDevice->Frequency != streamFormat.mSampleRate)
  359. {
  360. mDevice->BufferSize = static_cast<uint>(uint64_t{mDevice->BufferSize} *
  361. streamFormat.mSampleRate / mDevice->Frequency);
  362. mDevice->Frequency = static_cast<uint>(streamFormat.mSampleRate);
  363. }
  364. /* FIXME: How to tell what channels are what in the output device, and how
  365. * to specify what we're giving? e.g. 6.0 vs 5.1
  366. */
  367. streamFormat.mChannelsPerFrame = mDevice->channelsFromFmt();
  368. streamFormat.mFramesPerPacket = 1;
  369. streamFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
  370. streamFormat.mFormatID = kAudioFormatLinearPCM;
  371. switch(mDevice->FmtType)
  372. {
  373. case DevFmtUByte:
  374. mDevice->FmtType = DevFmtByte;
  375. /* fall-through */
  376. case DevFmtByte:
  377. streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
  378. streamFormat.mBitsPerChannel = 8;
  379. break;
  380. case DevFmtUShort:
  381. mDevice->FmtType = DevFmtShort;
  382. /* fall-through */
  383. case DevFmtShort:
  384. streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
  385. streamFormat.mBitsPerChannel = 16;
  386. break;
  387. case DevFmtUInt:
  388. mDevice->FmtType = DevFmtInt;
  389. /* fall-through */
  390. case DevFmtInt:
  391. streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
  392. streamFormat.mBitsPerChannel = 32;
  393. break;
  394. case DevFmtFloat:
  395. streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
  396. streamFormat.mBitsPerChannel = 32;
  397. break;
  398. }
  399. streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame*streamFormat.mBitsPerChannel/8;
  400. streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame*streamFormat.mFramesPerPacket;
  401. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
  402. 0, &streamFormat, sizeof(streamFormat));
  403. if(err != noErr)
  404. {
  405. ERR("AudioUnitSetProperty failed\n");
  406. return false;
  407. }
  408. setDefaultWFXChannelOrder();
  409. /* setup callback */
  410. mFrameSize = mDevice->frameSizeFromFmt();
  411. AURenderCallbackStruct input{};
  412. input.inputProc = CoreAudioPlayback::MixerProcC;
  413. input.inputProcRefCon = this;
  414. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback,
  415. kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
  416. if(err != noErr)
  417. {
  418. ERR("AudioUnitSetProperty failed\n");
  419. return false;
  420. }
  421. /* init the default audio unit... */
  422. err = AudioUnitInitialize(mAudioUnit);
  423. if(err != noErr)
  424. {
  425. ERR("AudioUnitInitialize failed\n");
  426. return false;
  427. }
  428. return true;
  429. }
  430. void CoreAudioPlayback::start()
  431. {
  432. const OSStatus err{AudioOutputUnitStart(mAudioUnit)};
  433. if(err != noErr)
  434. throw al::backend_exception{al::backend_error::DeviceError,
  435. "AudioOutputUnitStart failed: %d", err};
  436. }
  437. void CoreAudioPlayback::stop()
  438. {
  439. OSStatus err{AudioOutputUnitStop(mAudioUnit)};
  440. if(err != noErr)
  441. ERR("AudioOutputUnitStop failed\n");
  442. }
  443. struct CoreAudioCapture final : public BackendBase {
  444. CoreAudioCapture(DeviceBase *device) noexcept : BackendBase{device} { }
  445. ~CoreAudioCapture() override;
  446. OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
  447. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
  448. UInt32 inNumberFrames, AudioBufferList *ioData) noexcept;
  449. static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
  450. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
  451. AudioBufferList *ioData) noexcept
  452. {
  453. return static_cast<CoreAudioCapture*>(inRefCon)->RecordProc(ioActionFlags, inTimeStamp,
  454. inBusNumber, inNumberFrames, ioData);
  455. }
  456. void open(const char *name) override;
  457. void start() override;
  458. void stop() override;
  459. void captureSamples(al::byte *buffer, uint samples) override;
  460. uint availableSamples() override;
  461. AudioUnit mAudioUnit{0};
  462. uint mFrameSize{0u};
  463. AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD
  464. SampleConverterPtr mConverter;
  465. RingBufferPtr mRing{nullptr};
  466. DEF_NEWDEL(CoreAudioCapture)
  467. };
  468. CoreAudioCapture::~CoreAudioCapture()
  469. {
  470. if(mAudioUnit)
  471. AudioComponentInstanceDispose(mAudioUnit);
  472. mAudioUnit = 0;
  473. }
  474. OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*,
  475. const AudioTimeStamp *inTimeStamp, UInt32, UInt32 inNumberFrames,
  476. AudioBufferList*) noexcept
  477. {
  478. AudioUnitRenderActionFlags flags = 0;
  479. union {
  480. al::byte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2];
  481. AudioBufferList list;
  482. } audiobuf{};
  483. auto rec_vec = mRing->getWriteVector();
  484. inNumberFrames = static_cast<UInt32>(minz(inNumberFrames,
  485. rec_vec.first.len+rec_vec.second.len));
  486. // Fill the ringbuffer's two segments with data from the input device
  487. if(rec_vec.first.len >= inNumberFrames)
  488. {
  489. audiobuf.list.mNumberBuffers = 1;
  490. audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
  491. audiobuf.list.mBuffers[0].mData = rec_vec.first.buf;
  492. audiobuf.list.mBuffers[0].mDataByteSize = inNumberFrames * mFormat.mBytesPerFrame;
  493. }
  494. else
  495. {
  496. const auto remaining = static_cast<uint>(inNumberFrames - rec_vec.first.len);
  497. audiobuf.list.mNumberBuffers = 2;
  498. audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
  499. audiobuf.list.mBuffers[0].mData = rec_vec.first.buf;
  500. audiobuf.list.mBuffers[0].mDataByteSize = static_cast<UInt32>(rec_vec.first.len) *
  501. mFormat.mBytesPerFrame;
  502. audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame;
  503. audiobuf.list.mBuffers[1].mData = rec_vec.second.buf;
  504. audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame;
  505. }
  506. OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, audiobuf.list.mNumberBuffers,
  507. inNumberFrames, &audiobuf.list)};
  508. if(err != noErr)
  509. {
  510. ERR("AudioUnitRender error: %d\n", err);
  511. return err;
  512. }
  513. mRing->writeAdvance(inNumberFrames);
  514. return noErr;
  515. }
  516. void CoreAudioCapture::open(const char *name)
  517. {
  518. #if CAN_ENUMERATE
  519. AudioDeviceID audioDevice{kAudioDeviceUnknown};
  520. if(!name)
  521. GetHwProperty(kAudioHardwarePropertyDefaultInputDevice, sizeof(audioDevice),
  522. &audioDevice);
  523. else
  524. {
  525. if(CaptureList.empty())
  526. EnumerateDevices(CaptureList, true);
  527. auto find_name = [name](const DeviceEntry &entry) -> bool
  528. { return entry.mName == name; };
  529. auto devmatch = std::find_if(CaptureList.cbegin(), CaptureList.cend(), find_name);
  530. if(devmatch == CaptureList.cend())
  531. throw al::backend_exception{al::backend_error::NoDevice,
  532. "Device name \"%s\" not found", name};
  533. audioDevice = devmatch->mId;
  534. }
  535. #else
  536. if(!name)
  537. name = ca_device;
  538. else if(strcmp(name, ca_device) != 0)
  539. throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
  540. name};
  541. #endif
  542. AudioComponentDescription desc{};
  543. desc.componentType = kAudioUnitType_Output;
  544. #if CAN_ENUMERATE
  545. desc.componentSubType = (audioDevice == kAudioDeviceUnknown) ?
  546. kAudioUnitSubType_DefaultOutput : kAudioUnitSubType_HALOutput;
  547. #else
  548. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  549. #endif
  550. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  551. desc.componentFlags = 0;
  552. desc.componentFlagsMask = 0;
  553. // Search for component with given description
  554. AudioComponent comp{AudioComponentFindNext(NULL, &desc)};
  555. if(comp == NULL)
  556. throw al::backend_exception{al::backend_error::NoDevice, "Could not find audio component"};
  557. // Open the component
  558. OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)};
  559. if(err != noErr)
  560. throw al::backend_exception{al::backend_error::NoDevice,
  561. "Could not create component instance: %u", err};
  562. #if CAN_ENUMERATE
  563. if(audioDevice != kAudioDeviceUnknown)
  564. AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
  565. kAudioUnitScope_Global, 0, &audioDevice, sizeof(AudioDeviceID));
  566. #endif
  567. // Turn off AudioUnit output
  568. UInt32 enableIO{0};
  569. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO,
  570. kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
  571. if(err != noErr)
  572. throw al::backend_exception{al::backend_error::DeviceError,
  573. "Could not disable audio unit output property: %u", err};
  574. // Turn on AudioUnit input
  575. enableIO = 1;
  576. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO,
  577. kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
  578. if(err != noErr)
  579. throw al::backend_exception{al::backend_error::DeviceError,
  580. "Could not enable audio unit input property: %u", err};
  581. // set capture callback
  582. AURenderCallbackStruct input{};
  583. input.inputProc = CoreAudioCapture::RecordProcC;
  584. input.inputProcRefCon = this;
  585. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback,
  586. kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
  587. if(err != noErr)
  588. throw al::backend_exception{al::backend_error::DeviceError,
  589. "Could not set capture callback: %u", err};
  590. // Disable buffer allocation for capture
  591. UInt32 flag{0};
  592. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_ShouldAllocateBuffer,
  593. kAudioUnitScope_Output, 1, &flag, sizeof(flag));
  594. if(err != noErr)
  595. throw al::backend_exception{al::backend_error::DeviceError,
  596. "Could not disable buffer allocation property: %u", err};
  597. // Initialize the device
  598. err = AudioUnitInitialize(mAudioUnit);
  599. if(err != noErr)
  600. throw al::backend_exception{al::backend_error::DeviceError,
  601. "Could not initialize audio unit: %u", err};
  602. // Get the hardware format
  603. AudioStreamBasicDescription hardwareFormat{};
  604. UInt32 propertySize{sizeof(hardwareFormat)};
  605. err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
  606. 1, &hardwareFormat, &propertySize);
  607. if(err != noErr || propertySize != sizeof(hardwareFormat))
  608. throw al::backend_exception{al::backend_error::DeviceError,
  609. "Could not get input format: %u", err};
  610. // Set up the requested format description
  611. AudioStreamBasicDescription requestedFormat{};
  612. switch(mDevice->FmtType)
  613. {
  614. case DevFmtByte:
  615. requestedFormat.mBitsPerChannel = 8;
  616. requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
  617. break;
  618. case DevFmtUByte:
  619. requestedFormat.mBitsPerChannel = 8;
  620. requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
  621. break;
  622. case DevFmtShort:
  623. requestedFormat.mBitsPerChannel = 16;
  624. requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger
  625. | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  626. break;
  627. case DevFmtUShort:
  628. requestedFormat.mBitsPerChannel = 16;
  629. requestedFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  630. break;
  631. case DevFmtInt:
  632. requestedFormat.mBitsPerChannel = 32;
  633. requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger
  634. | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  635. break;
  636. case DevFmtUInt:
  637. requestedFormat.mBitsPerChannel = 32;
  638. requestedFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  639. break;
  640. case DevFmtFloat:
  641. requestedFormat.mBitsPerChannel = 32;
  642. requestedFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian
  643. | kAudioFormatFlagIsPacked;
  644. break;
  645. }
  646. switch(mDevice->FmtChans)
  647. {
  648. case DevFmtMono:
  649. requestedFormat.mChannelsPerFrame = 1;
  650. break;
  651. case DevFmtStereo:
  652. requestedFormat.mChannelsPerFrame = 2;
  653. break;
  654. case DevFmtQuad:
  655. case DevFmtX51:
  656. case DevFmtX61:
  657. case DevFmtX71:
  658. case DevFmtAmbi3D:
  659. throw al::backend_exception{al::backend_error::DeviceError, "%s not supported",
  660. DevFmtChannelsString(mDevice->FmtChans)};
  661. }
  662. requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
  663. requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
  664. requestedFormat.mSampleRate = mDevice->Frequency;
  665. requestedFormat.mFormatID = kAudioFormatLinearPCM;
  666. requestedFormat.mReserved = 0;
  667. requestedFormat.mFramesPerPacket = 1;
  668. // save requested format description for later use
  669. mFormat = requestedFormat;
  670. mFrameSize = mDevice->frameSizeFromFmt();
  671. // Use intermediate format for sample rate conversion (outputFormat)
  672. // Set sample rate to the same as hardware for resampling later
  673. AudioStreamBasicDescription outputFormat{requestedFormat};
  674. outputFormat.mSampleRate = hardwareFormat.mSampleRate;
  675. // The output format should be the requested format, but using the hardware sample rate
  676. // This is because the AudioUnit will automatically scale other properties, except for sample rate
  677. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
  678. 1, &outputFormat, sizeof(outputFormat));
  679. if(err != noErr)
  680. throw al::backend_exception{al::backend_error::DeviceError,
  681. "Could not set input format: %u", err};
  682. /* Calculate the minimum AudioUnit output format frame count for the pre-
  683. * conversion ring buffer. Ensure at least 100ms for the total buffer.
  684. */
  685. double srateScale{double{outputFormat.mSampleRate} / mDevice->Frequency};
  686. auto FrameCount64 = maxu64(static_cast<uint64_t>(std::ceil(mDevice->BufferSize*srateScale)),
  687. static_cast<UInt32>(outputFormat.mSampleRate)/10);
  688. FrameCount64 += MaxResamplerPadding;
  689. if(FrameCount64 > std::numeric_limits<int32_t>::max())
  690. throw al::backend_exception{al::backend_error::DeviceError,
  691. "Calculated frame count is too large: %" PRIu64, FrameCount64};
  692. UInt32 outputFrameCount{};
  693. propertySize = sizeof(outputFrameCount);
  694. err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice,
  695. kAudioUnitScope_Global, 0, &outputFrameCount, &propertySize);
  696. if(err != noErr || propertySize != sizeof(outputFrameCount))
  697. throw al::backend_exception{al::backend_error::DeviceError,
  698. "Could not get input frame count: %u", err};
  699. outputFrameCount = static_cast<UInt32>(maxu64(outputFrameCount, FrameCount64));
  700. mRing = RingBuffer::Create(outputFrameCount, mFrameSize, false);
  701. /* Set up sample converter if needed */
  702. if(outputFormat.mSampleRate != mDevice->Frequency)
  703. mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType,
  704. mFormat.mChannelsPerFrame, static_cast<uint>(hardwareFormat.mSampleRate),
  705. mDevice->Frequency, Resampler::FastBSinc24);
  706. #if CAN_ENUMERATE
  707. if(name)
  708. mDevice->DeviceName = name;
  709. else
  710. {
  711. UInt32 propSize{sizeof(audioDevice)};
  712. audioDevice = kAudioDeviceUnknown;
  713. AudioUnitGetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
  714. kAudioUnitScope_Global, 0, &audioDevice, &propSize);
  715. std::string devname{GetDeviceName(audioDevice)};
  716. if(!devname.empty()) mDevice->DeviceName = std::move(devname);
  717. else mDevice->DeviceName = "Unknown Device Name";
  718. }
  719. #else
  720. mDevice->DeviceName = name;
  721. #endif
  722. }
  723. void CoreAudioCapture::start()
  724. {
  725. OSStatus err{AudioOutputUnitStart(mAudioUnit)};
  726. if(err != noErr)
  727. throw al::backend_exception{al::backend_error::DeviceError,
  728. "AudioOutputUnitStart failed: %d", err};
  729. }
  730. void CoreAudioCapture::stop()
  731. {
  732. OSStatus err{AudioOutputUnitStop(mAudioUnit)};
  733. if(err != noErr)
  734. ERR("AudioOutputUnitStop failed\n");
  735. }
  736. void CoreAudioCapture::captureSamples(al::byte *buffer, uint samples)
  737. {
  738. if(!mConverter)
  739. {
  740. mRing->read(buffer, samples);
  741. return;
  742. }
  743. auto rec_vec = mRing->getReadVector();
  744. const void *src0{rec_vec.first.buf};
  745. auto src0len = static_cast<uint>(rec_vec.first.len);
  746. uint got{mConverter->convert(&src0, &src0len, buffer, samples)};
  747. size_t total_read{rec_vec.first.len - src0len};
  748. if(got < samples && !src0len && rec_vec.second.len > 0)
  749. {
  750. const void *src1{rec_vec.second.buf};
  751. auto src1len = static_cast<uint>(rec_vec.second.len);
  752. got += mConverter->convert(&src1, &src1len, buffer + got*mFrameSize, samples-got);
  753. total_read += rec_vec.second.len - src1len;
  754. }
  755. mRing->readAdvance(total_read);
  756. }
  757. uint CoreAudioCapture::availableSamples()
  758. {
  759. if(!mConverter) return static_cast<uint>(mRing->readSpace());
  760. return mConverter->availableOut(static_cast<uint>(mRing->readSpace()));
  761. }
  762. } // namespace
  763. BackendFactory &CoreAudioBackendFactory::getFactory()
  764. {
  765. static CoreAudioBackendFactory factory{};
  766. return factory;
  767. }
  768. bool CoreAudioBackendFactory::init() { return true; }
  769. bool CoreAudioBackendFactory::querySupport(BackendType type)
  770. { return type == BackendType::Playback || type == BackendType::Capture; }
  771. std::string CoreAudioBackendFactory::probe(BackendType type)
  772. {
  773. std::string outnames;
  774. #if CAN_ENUMERATE
  775. auto append_name = [&outnames](const DeviceEntry &entry) -> void
  776. {
  777. /* Includes null char. */
  778. outnames.append(entry.mName.c_str(), entry.mName.length()+1);
  779. };
  780. switch(type)
  781. {
  782. case BackendType::Playback:
  783. EnumerateDevices(PlaybackList, false);
  784. std::for_each(PlaybackList.cbegin(), PlaybackList.cend(), append_name);
  785. break;
  786. case BackendType::Capture:
  787. EnumerateDevices(CaptureList, true);
  788. std::for_each(CaptureList.cbegin(), CaptureList.cend(), append_name);
  789. break;
  790. }
  791. #else
  792. switch(type)
  793. {
  794. case BackendType::Playback:
  795. case BackendType::Capture:
  796. /* Includes null char. */
  797. outnames.append(ca_device, sizeof(ca_device));
  798. break;
  799. }
  800. #endif
  801. return outnames;
  802. }
  803. BackendPtr CoreAudioBackendFactory::createBackend(DeviceBase *device, BackendType type)
  804. {
  805. if(type == BackendType::Playback)
  806. return BackendPtr{new CoreAudioPlayback{device}};
  807. if(type == BackendType::Capture)
  808. return BackendPtr{new CoreAudioCapture{device}};
  809. return nullptr;
  810. }