coreaudio.cpp 23 KB

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