🛠️🐜 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.

712 lines
23 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 "backends/coreaudio.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "alMain.h"
  26. #include "alu.h"
  27. #include "ringbuffer.h"
  28. #include "converter.h"
  29. #include "backends/base.h"
  30. #include <unistd.h>
  31. #include <AudioUnit/AudioUnit.h>
  32. #include <AudioToolbox/AudioToolbox.h>
  33. namespace {
  34. static const ALCchar ca_device[] = "CoreAudio Default";
  35. struct CoreAudioPlayback final : public BackendBase {
  36. CoreAudioPlayback(ALCdevice *device) noexcept : BackendBase{device} { }
  37. ~CoreAudioPlayback() override;
  38. static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
  39. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
  40. AudioBufferList *ioData);
  41. OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags,
  42. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
  43. AudioBufferList *ioData);
  44. ALCenum open(const ALCchar *name) override;
  45. ALCboolean reset() override;
  46. ALCboolean start() override;
  47. void stop() override;
  48. AudioUnit mAudioUnit;
  49. ALuint mFrameSize{0u};
  50. AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD
  51. static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioPlayback::"; }
  52. DEF_NEWDEL(CoreAudioPlayback)
  53. };
  54. CoreAudioPlayback::~CoreAudioPlayback()
  55. {
  56. AudioUnitUninitialize(mAudioUnit);
  57. AudioComponentInstanceDispose(mAudioUnit);
  58. }
  59. OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon,
  60. AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
  61. UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
  62. {
  63. return static_cast<CoreAudioPlayback*>(inRefCon)->MixerProc(ioActionFlags, inTimeStamp,
  64. inBusNumber, inNumberFrames, ioData);
  65. }
  66. OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags),
  67. const AudioTimeStamp* UNUSED(inTimeStamp), UInt32 UNUSED(inBusNumber),
  68. UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData)
  69. {
  70. lock();
  71. aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize);
  72. unlock();
  73. return noErr;
  74. }
  75. ALCenum CoreAudioPlayback::open(const ALCchar *name)
  76. {
  77. if(!name)
  78. name = ca_device;
  79. else if(strcmp(name, ca_device) != 0)
  80. return ALC_INVALID_VALUE;
  81. /* open the default output unit */
  82. AudioComponentDescription desc{};
  83. desc.componentType = kAudioUnitType_Output;
  84. #if TARGET_OS_IOS
  85. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  86. #else
  87. desc.componentSubType = kAudioUnitSubType_DefaultOutput;
  88. #endif
  89. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  90. desc.componentFlags = 0;
  91. desc.componentFlagsMask = 0;
  92. AudioComponent comp{AudioComponentFindNext(NULL, &desc)};
  93. if(comp == nullptr)
  94. {
  95. ERR("AudioComponentFindNext failed\n");
  96. return ALC_INVALID_VALUE;
  97. }
  98. OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)};
  99. if(err != noErr)
  100. {
  101. ERR("AudioComponentInstanceNew failed\n");
  102. return ALC_INVALID_VALUE;
  103. }
  104. /* init and start the default audio unit... */
  105. err = AudioUnitInitialize(mAudioUnit);
  106. if(err != noErr)
  107. {
  108. ERR("AudioUnitInitialize failed\n");
  109. AudioComponentInstanceDispose(mAudioUnit);
  110. return ALC_INVALID_VALUE;
  111. }
  112. mDevice->DeviceName = name;
  113. return ALC_NO_ERROR;
  114. }
  115. ALCboolean CoreAudioPlayback::reset()
  116. {
  117. OSStatus err{AudioUnitUninitialize(mAudioUnit)};
  118. if(err != noErr)
  119. ERR("-- AudioUnitUninitialize failed.\n");
  120. /* retrieve default output unit's properties (output side) */
  121. AudioStreamBasicDescription streamFormat{};
  122. auto size = static_cast<UInt32>(sizeof(AudioStreamBasicDescription));
  123. err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
  124. 0, &streamFormat, &size);
  125. if(err != noErr || size != sizeof(AudioStreamBasicDescription))
  126. {
  127. ERR("AudioUnitGetProperty failed\n");
  128. return ALC_FALSE;
  129. }
  130. #if 0
  131. TRACE("Output streamFormat of default output unit -\n");
  132. TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
  133. TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
  134. TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
  135. TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
  136. TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
  137. TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
  138. #endif
  139. /* set default output unit's input side to match output side */
  140. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
  141. 0, &streamFormat, size);
  142. if(err != noErr)
  143. {
  144. ERR("AudioUnitSetProperty failed\n");
  145. return ALC_FALSE;
  146. }
  147. if(mDevice->Frequency != streamFormat.mSampleRate)
  148. {
  149. mDevice->BufferSize = static_cast<ALuint>(uint64_t{mDevice->BufferSize} *
  150. streamFormat.mSampleRate / mDevice->Frequency);
  151. mDevice->Frequency = streamFormat.mSampleRate;
  152. }
  153. /* FIXME: How to tell what channels are what in the output device, and how
  154. * to specify what we're giving? eg, 6.0 vs 5.1 */
  155. switch(streamFormat.mChannelsPerFrame)
  156. {
  157. case 1:
  158. mDevice->FmtChans = DevFmtMono;
  159. break;
  160. case 2:
  161. mDevice->FmtChans = DevFmtStereo;
  162. break;
  163. case 4:
  164. mDevice->FmtChans = DevFmtQuad;
  165. break;
  166. case 6:
  167. mDevice->FmtChans = DevFmtX51;
  168. break;
  169. case 7:
  170. mDevice->FmtChans = DevFmtX61;
  171. break;
  172. case 8:
  173. mDevice->FmtChans = DevFmtX71;
  174. break;
  175. default:
  176. ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
  177. mDevice->FmtChans = DevFmtStereo;
  178. streamFormat.mChannelsPerFrame = 2;
  179. break;
  180. }
  181. SetDefaultWFXChannelOrder(mDevice);
  182. /* use channel count and sample rate from the default output unit's current
  183. * parameters, but reset everything else */
  184. streamFormat.mFramesPerPacket = 1;
  185. streamFormat.mFormatFlags = 0;
  186. switch(mDevice->FmtType)
  187. {
  188. case DevFmtUByte:
  189. mDevice->FmtType = DevFmtByte;
  190. /* fall-through */
  191. case DevFmtByte:
  192. streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
  193. streamFormat.mBitsPerChannel = 8;
  194. break;
  195. case DevFmtUShort:
  196. mDevice->FmtType = DevFmtShort;
  197. /* fall-through */
  198. case DevFmtShort:
  199. streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
  200. streamFormat.mBitsPerChannel = 16;
  201. break;
  202. case DevFmtUInt:
  203. mDevice->FmtType = DevFmtInt;
  204. /* fall-through */
  205. case DevFmtInt:
  206. streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
  207. streamFormat.mBitsPerChannel = 32;
  208. break;
  209. case DevFmtFloat:
  210. streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
  211. streamFormat.mBitsPerChannel = 32;
  212. break;
  213. }
  214. streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame *
  215. streamFormat.mBitsPerChannel / 8;
  216. streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame;
  217. streamFormat.mFormatID = kAudioFormatLinearPCM;
  218. streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian |
  219. kLinearPCMFormatFlagIsPacked;
  220. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
  221. 0, &streamFormat, sizeof(AudioStreamBasicDescription));
  222. if(err != noErr)
  223. {
  224. ERR("AudioUnitSetProperty failed\n");
  225. return ALC_FALSE;
  226. }
  227. /* setup callback */
  228. mFrameSize = mDevice->frameSizeFromFmt();
  229. AURenderCallbackStruct input{};
  230. input.inputProc = CoreAudioPlayback::MixerProcC;
  231. input.inputProcRefCon = this;
  232. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback,
  233. kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
  234. if(err != noErr)
  235. {
  236. ERR("AudioUnitSetProperty failed\n");
  237. return ALC_FALSE;
  238. }
  239. /* init the default audio unit... */
  240. err = AudioUnitInitialize(mAudioUnit);
  241. if(err != noErr)
  242. {
  243. ERR("AudioUnitInitialize failed\n");
  244. return ALC_FALSE;
  245. }
  246. return ALC_TRUE;
  247. }
  248. ALCboolean CoreAudioPlayback::start()
  249. {
  250. OSStatus err{AudioOutputUnitStart(mAudioUnit)};
  251. if(err != noErr)
  252. {
  253. ERR("AudioOutputUnitStart failed\n");
  254. return ALC_FALSE;
  255. }
  256. return ALC_TRUE;
  257. }
  258. void CoreAudioPlayback::stop()
  259. {
  260. OSStatus err{AudioOutputUnitStop(mAudioUnit)};
  261. if(err != noErr)
  262. ERR("AudioOutputUnitStop failed\n");
  263. }
  264. struct CoreAudioCapture final : public BackendBase {
  265. CoreAudioCapture(ALCdevice *device) noexcept : BackendBase{device} { }
  266. ~CoreAudioCapture() override;
  267. static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
  268. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
  269. AudioBufferList *ioData);
  270. OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
  271. const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
  272. UInt32 inNumberFrames, AudioBufferList *ioData);
  273. ALCenum open(const ALCchar *name) override;
  274. ALCboolean start() override;
  275. void stop() override;
  276. ALCenum captureSamples(void *buffer, ALCuint samples) override;
  277. ALCuint availableSamples() override;
  278. AudioUnit mAudioUnit{0};
  279. ALuint mFrameSize{0u};
  280. AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD
  281. SampleConverterPtr mConverter;
  282. RingBufferPtr mRing{nullptr};
  283. static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioCapture::"; }
  284. DEF_NEWDEL(CoreAudioCapture)
  285. };
  286. CoreAudioCapture::~CoreAudioCapture()
  287. {
  288. if(mAudioUnit)
  289. AudioComponentInstanceDispose(mAudioUnit);
  290. mAudioUnit = 0;
  291. }
  292. OSStatus CoreAudioCapture::RecordProcC(void *inRefCon,
  293. AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
  294. UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
  295. {
  296. return static_cast<CoreAudioCapture*>(inRefCon)->RecordProc(ioActionFlags, inTimeStamp,
  297. inBusNumber, inNumberFrames, ioData);
  298. }
  299. OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags),
  300. const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), UInt32 inNumberFrames,
  301. AudioBufferList* UNUSED(ioData))
  302. {
  303. AudioUnitRenderActionFlags flags = 0;
  304. union {
  305. ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2];
  306. AudioBufferList list;
  307. } audiobuf = { { 0 } };
  308. auto rec_vec = mRing->getWriteVector();
  309. inNumberFrames = minz(inNumberFrames, rec_vec.first.len+rec_vec.second.len);
  310. // Fill the ringbuffer's two segments with data from the input device
  311. if(rec_vec.first.len >= inNumberFrames)
  312. {
  313. audiobuf.list.mNumberBuffers = 1;
  314. audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
  315. audiobuf.list.mBuffers[0].mData = rec_vec.first.buf;
  316. audiobuf.list.mBuffers[0].mDataByteSize = inNumberFrames * mFormat.mBytesPerFrame;
  317. }
  318. else
  319. {
  320. const size_t remaining{inNumberFrames-rec_vec.first.len};
  321. audiobuf.list.mNumberBuffers = 2;
  322. audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
  323. audiobuf.list.mBuffers[0].mData = rec_vec.first.buf;
  324. audiobuf.list.mBuffers[0].mDataByteSize = rec_vec.first.len * mFormat.mBytesPerFrame;
  325. audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame;
  326. audiobuf.list.mBuffers[1].mData = rec_vec.second.buf;
  327. audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame;
  328. }
  329. OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, audiobuf.list.mNumberBuffers,
  330. inNumberFrames, &audiobuf.list)};
  331. if(err != noErr)
  332. {
  333. ERR("AudioUnitRender error: %d\n", err);
  334. return err;
  335. }
  336. mRing->writeAdvance(inNumberFrames);
  337. return noErr;
  338. }
  339. ALCenum CoreAudioCapture::open(const ALCchar *name)
  340. {
  341. AudioStreamBasicDescription requestedFormat; // The application requested format
  342. AudioStreamBasicDescription hardwareFormat; // The hardware format
  343. AudioStreamBasicDescription outputFormat; // The AudioUnit output format
  344. AURenderCallbackStruct input;
  345. AudioComponentDescription desc;
  346. UInt32 outputFrameCount;
  347. UInt32 propertySize;
  348. AudioObjectPropertyAddress propertyAddress;
  349. UInt32 enableIO;
  350. AudioComponent comp;
  351. OSStatus err;
  352. if(!name)
  353. name = ca_device;
  354. else if(strcmp(name, ca_device) != 0)
  355. return ALC_INVALID_VALUE;
  356. desc.componentType = kAudioUnitType_Output;
  357. #if TARGET_OS_IOS
  358. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  359. #else
  360. desc.componentSubType = kAudioUnitSubType_HALOutput;
  361. #endif
  362. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  363. desc.componentFlags = 0;
  364. desc.componentFlagsMask = 0;
  365. // Search for component with given description
  366. comp = AudioComponentFindNext(NULL, &desc);
  367. if(comp == NULL)
  368. {
  369. ERR("AudioComponentFindNext failed\n");
  370. return ALC_INVALID_VALUE;
  371. }
  372. // Open the component
  373. err = AudioComponentInstanceNew(comp, &mAudioUnit);
  374. if(err != noErr)
  375. {
  376. ERR("AudioComponentInstanceNew failed\n");
  377. return ALC_INVALID_VALUE;
  378. }
  379. // Turn off AudioUnit output
  380. enableIO = 0;
  381. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO,
  382. kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
  383. if(err != noErr)
  384. {
  385. ERR("AudioUnitSetProperty failed\n");
  386. return ALC_INVALID_VALUE;
  387. }
  388. // Turn on AudioUnit input
  389. enableIO = 1;
  390. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO,
  391. kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
  392. if(err != noErr)
  393. {
  394. ERR("AudioUnitSetProperty failed\n");
  395. return ALC_INVALID_VALUE;
  396. }
  397. #if !TARGET_OS_IOS
  398. {
  399. // Get the default input device
  400. AudioDeviceID inputDevice = kAudioDeviceUnknown;
  401. propertySize = sizeof(AudioDeviceID);
  402. propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
  403. propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
  404. propertyAddress.mElement = kAudioObjectPropertyElementMaster;
  405. err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice);
  406. if(err != noErr)
  407. {
  408. ERR("AudioObjectGetPropertyData failed\n");
  409. return ALC_INVALID_VALUE;
  410. }
  411. if(inputDevice == kAudioDeviceUnknown)
  412. {
  413. ERR("No input device found\n");
  414. return ALC_INVALID_VALUE;
  415. }
  416. // Track the input device
  417. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
  418. kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
  419. if(err != noErr)
  420. {
  421. ERR("AudioUnitSetProperty failed\n");
  422. return ALC_INVALID_VALUE;
  423. }
  424. }
  425. #endif
  426. // set capture callback
  427. input.inputProc = CoreAudioCapture::RecordProcC;
  428. input.inputProcRefCon = this;
  429. err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback,
  430. kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
  431. if(err != noErr)
  432. {
  433. ERR("AudioUnitSetProperty failed\n");
  434. return ALC_INVALID_VALUE;
  435. }
  436. // Initialize the device
  437. err = AudioUnitInitialize(mAudioUnit);
  438. if(err != noErr)
  439. {
  440. ERR("AudioUnitInitialize failed\n");
  441. return ALC_INVALID_VALUE;
  442. }
  443. // Get the hardware format
  444. propertySize = sizeof(AudioStreamBasicDescription);
  445. err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
  446. 1, &hardwareFormat, &propertySize);
  447. if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
  448. {
  449. ERR("AudioUnitGetProperty failed\n");
  450. return ALC_INVALID_VALUE;
  451. }
  452. // Set up the requested format description
  453. switch(mDevice->FmtType)
  454. {
  455. case DevFmtUByte:
  456. requestedFormat.mBitsPerChannel = 8;
  457. requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
  458. break;
  459. case DevFmtShort:
  460. requestedFormat.mBitsPerChannel = 16;
  461. requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  462. break;
  463. case DevFmtInt:
  464. requestedFormat.mBitsPerChannel = 32;
  465. requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  466. break;
  467. case DevFmtFloat:
  468. requestedFormat.mBitsPerChannel = 32;
  469. requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
  470. break;
  471. case DevFmtByte:
  472. case DevFmtUShort:
  473. case DevFmtUInt:
  474. ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType));
  475. return ALC_INVALID_VALUE;
  476. }
  477. switch(mDevice->FmtChans)
  478. {
  479. case DevFmtMono:
  480. requestedFormat.mChannelsPerFrame = 1;
  481. break;
  482. case DevFmtStereo:
  483. requestedFormat.mChannelsPerFrame = 2;
  484. break;
  485. case DevFmtQuad:
  486. case DevFmtX51:
  487. case DevFmtX51Rear:
  488. case DevFmtX61:
  489. case DevFmtX71:
  490. case DevFmtAmbi3D:
  491. ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans));
  492. return ALC_INVALID_VALUE;
  493. }
  494. requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
  495. requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
  496. requestedFormat.mSampleRate = mDevice->Frequency;
  497. requestedFormat.mFormatID = kAudioFormatLinearPCM;
  498. requestedFormat.mReserved = 0;
  499. requestedFormat.mFramesPerPacket = 1;
  500. // save requested format description for later use
  501. mFormat = requestedFormat;
  502. mFrameSize = mDevice->frameSizeFromFmt();
  503. // Use intermediate format for sample rate conversion (outputFormat)
  504. // Set sample rate to the same as hardware for resampling later
  505. outputFormat = requestedFormat;
  506. outputFormat.mSampleRate = hardwareFormat.mSampleRate;
  507. // The output format should be the requested format, but using the hardware sample rate
  508. // This is because the AudioUnit will automatically scale other properties, except for sample rate
  509. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
  510. 1, (void*)&outputFormat, sizeof(outputFormat));
  511. if(err != noErr)
  512. {
  513. ERR("AudioUnitSetProperty failed\n");
  514. return ALC_INVALID_VALUE;
  515. }
  516. // Set the AudioUnit output format frame count
  517. uint64_t FrameCount64{mDevice->UpdateSize};
  518. FrameCount64 = (FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) /
  519. mDevice->Frequency;
  520. FrameCount64 += MAX_RESAMPLE_PADDING*2;
  521. if(FrameCount64 > std::numeric_limits<uint32_t>::max()/2)
  522. {
  523. ERR("FrameCount too large\n");
  524. return ALC_INVALID_VALUE;
  525. }
  526. outputFrameCount = static_cast<uint32_t>(FrameCount64);
  527. err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice,
  528. kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
  529. if(err != noErr)
  530. {
  531. ERR("AudioUnitSetProperty failed: %d\n", err);
  532. return ALC_INVALID_VALUE;
  533. }
  534. // Set up sample converter if needed
  535. if(outputFormat.mSampleRate != mDevice->Frequency)
  536. mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType,
  537. mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, mDevice->Frequency,
  538. BSinc24Resampler);
  539. mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false);
  540. if(!mRing) return ALC_INVALID_VALUE;
  541. mDevice->DeviceName = name;
  542. return ALC_NO_ERROR;
  543. }
  544. ALCboolean CoreAudioCapture::start()
  545. {
  546. OSStatus err{AudioOutputUnitStart(mAudioUnit)};
  547. if(err != noErr)
  548. {
  549. ERR("AudioOutputUnitStart failed\n");
  550. return ALC_FALSE;
  551. }
  552. return ALC_TRUE;
  553. }
  554. void CoreAudioCapture::stop()
  555. {
  556. OSStatus err{AudioOutputUnitStop(mAudioUnit)};
  557. if(err != noErr)
  558. ERR("AudioOutputUnitStop failed\n");
  559. }
  560. ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples)
  561. {
  562. if(!mConverter)
  563. {
  564. mRing->read(buffer, samples);
  565. return ALC_NO_ERROR;
  566. }
  567. auto rec_vec = mRing->getReadVector();
  568. const void *src0{rec_vec.first.buf};
  569. auto src0len = static_cast<ALsizei>(rec_vec.first.len);
  570. auto got = static_cast<ALuint>(mConverter->convert(&src0, &src0len, buffer, samples));
  571. size_t total_read{rec_vec.first.len - src0len};
  572. if(got < samples && !src0len && rec_vec.second.len > 0)
  573. {
  574. const void *src1{rec_vec.second.buf};
  575. auto src1len = static_cast<ALsizei>(rec_vec.second.len);
  576. got += static_cast<ALuint>(mConverter->convert(&src1, &src1len,
  577. static_cast<char*>(buffer)+got, samples-got));
  578. total_read += rec_vec.second.len - src1len;
  579. }
  580. mRing->readAdvance(total_read);
  581. return ALC_NO_ERROR;
  582. }
  583. ALCuint CoreAudioCapture::availableSamples()
  584. {
  585. if(!mConverter) return mRing->readSpace();
  586. return mConverter->availableOut(mRing->readSpace());
  587. }
  588. } // namespace
  589. BackendFactory &CoreAudioBackendFactory::getFactory()
  590. {
  591. static CoreAudioBackendFactory factory{};
  592. return factory;
  593. }
  594. bool CoreAudioBackendFactory::init() { return true; }
  595. bool CoreAudioBackendFactory::querySupport(BackendType type)
  596. { return type == BackendType::Playback || type == BackendType::Capture; }
  597. void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames)
  598. {
  599. switch(type)
  600. {
  601. case DevProbe::Playback:
  602. case DevProbe::Capture:
  603. /* Includes null char. */
  604. outnames->append(ca_device, sizeof(ca_device));
  605. break;
  606. }
  607. }
  608. BackendPtr CoreAudioBackendFactory::createBackend(ALCdevice *device, BackendType type)
  609. {
  610. if(type == BackendType::Playback)
  611. return BackendPtr{new CoreAudioPlayback{device}};
  612. if(type == BackendType::Capture)
  613. return BackendPtr{new CoreAudioCapture{device}};
  614. return nullptr;
  615. }