coreaudio.cpp 24 KB

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