jack2 codebase
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.

706 lines
25KB

  1. /*
  2. Copyright (C) 2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackCoreAudioAdapter.h"
  16. #include "JackError.h"
  17. #include <unistd.h>
  18. namespace Jack
  19. {
  20. static void printError(OSStatus err)
  21. {
  22. switch (err) {
  23. case kAudioHardwareNoError:
  24. jack_log("error code : kAudioHardwareNoError");
  25. break;
  26. case kAudioConverterErr_FormatNotSupported:
  27. jack_log("error code : kAudioConverterErr_FormatNotSupported");
  28. break;
  29. case kAudioConverterErr_OperationNotSupported:
  30. jack_log("error code : kAudioConverterErr_OperationNotSupported");
  31. break;
  32. case kAudioConverterErr_PropertyNotSupported:
  33. jack_log("error code : kAudioConverterErr_PropertyNotSupported");
  34. break;
  35. case kAudioConverterErr_InvalidInputSize:
  36. jack_log("error code : kAudioConverterErr_InvalidInputSize");
  37. break;
  38. case kAudioConverterErr_InvalidOutputSize:
  39. jack_log("error code : kAudioConverterErr_InvalidOutputSize");
  40. break;
  41. case kAudioConverterErr_UnspecifiedError:
  42. jack_log("error code : kAudioConverterErr_UnspecifiedError");
  43. break;
  44. case kAudioConverterErr_BadPropertySizeError:
  45. jack_log("error code : kAudioConverterErr_BadPropertySizeError");
  46. break;
  47. case kAudioConverterErr_RequiresPacketDescriptionsError:
  48. jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
  49. break;
  50. case kAudioConverterErr_InputSampleRateOutOfRange:
  51. jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
  52. break;
  53. case kAudioConverterErr_OutputSampleRateOutOfRange:
  54. jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
  55. break;
  56. case kAudioHardwareNotRunningError:
  57. jack_log("error code : kAudioHardwareNotRunningError");
  58. break;
  59. case kAudioHardwareUnknownPropertyError:
  60. jack_log("error code : kAudioHardwareUnknownPropertyError");
  61. break;
  62. case kAudioHardwareIllegalOperationError:
  63. jack_log("error code : kAudioHardwareIllegalOperationError");
  64. break;
  65. case kAudioHardwareBadDeviceError:
  66. jack_log("error code : kAudioHardwareBadDeviceError");
  67. break;
  68. case kAudioHardwareBadStreamError:
  69. jack_log("error code : kAudioHardwareBadStreamError");
  70. break;
  71. case kAudioDeviceUnsupportedFormatError:
  72. jack_log("error code : kAudioDeviceUnsupportedFormatError");
  73. break;
  74. case kAudioDevicePermissionsError:
  75. jack_log("error code : kAudioDevicePermissionsError");
  76. break;
  77. case kAudioHardwareBadObjectError:
  78. jack_log("error code : kAudioHardwareBadObjectError");
  79. break;
  80. case kAudioHardwareUnsupportedOperationError:
  81. jack_log("error code : kAudioHardwareUnsupportedOperationError");
  82. break;
  83. default:
  84. jack_log("error code : unknown");
  85. break;
  86. }
  87. }
  88. OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice,
  89. UInt32 inChannel,
  90. Boolean isInput,
  91. AudioDevicePropertyID inPropertyID,
  92. void* inClientData)
  93. {
  94. JackCoreAudioAdapter* driver = static_cast<JackCoreAudioAdapter*>(inClientData);
  95. switch (inPropertyID) {
  96. case kAudioDevicePropertyNominalSampleRate: {
  97. jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
  98. driver->fState = true;
  99. break;
  100. }
  101. }
  102. return noErr;
  103. }
  104. OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
  105. AudioUnitRenderActionFlags *ioActionFlags,
  106. const AudioTimeStamp *inTimeStamp,
  107. UInt32 inBusNumber,
  108. UInt32 inNumberFrames,
  109. AudioBufferList *ioData)
  110. {
  111. JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon);
  112. AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData);
  113. bool failure = false;
  114. jack_nframes_t time1, time2;
  115. adapter->ResampleFactor(time1, time2);
  116. for (int i = 0; i < adapter->fCaptureChannels; i++) {
  117. adapter->fCaptureRingBuffer[i]->SetRatio(time1, time2);
  118. if (adapter->fCaptureRingBuffer[i]->WriteResample((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames) < inNumberFrames)
  119. failure = true;
  120. }
  121. for (int i = 0; i < adapter->fPlaybackChannels; i++) {
  122. adapter->fPlaybackRingBuffer[i]->SetRatio(time2, time1);
  123. if (adapter->fPlaybackRingBuffer[i]->ReadResample((float*)ioData->mBuffers[i].mData, inNumberFrames) < inNumberFrames)
  124. failure = true;
  125. }
  126. #ifdef DEBUG
  127. adapter->fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1),
  128. adapter->fCaptureRingBuffer[0]->ReadSpace(), adapter->fPlaybackRingBuffer[0]->WriteSpace());
  129. #endif
  130. // Reset all ringbuffers in case of failure
  131. if (failure) {
  132. jack_error("JackCoreAudioAdapter::Render ringbuffer failure... reset");
  133. adapter->ResetRingBuffers();
  134. }
  135. return noErr;
  136. }
  137. JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
  138. :JackAudioAdapterInterface(buffer_size, sample_rate),fInputData(0),fState(false)
  139. {
  140. const JSList* node;
  141. const jack_driver_param_t* param;
  142. fCaptureChannels = 2;
  143. fPlaybackChannels = 2;
  144. for (node = params; node; node = jack_slist_next(node)) {
  145. param = (const jack_driver_param_t*) node->data;
  146. switch (param->character) {
  147. case 'c' :
  148. break;
  149. case 'i':
  150. fCaptureChannels = param->value.ui;
  151. break;
  152. case 'o':
  153. fPlaybackChannels = param->value.ui;
  154. break;
  155. case 'C':
  156. break;
  157. case 'P':
  158. break;
  159. case 'D':
  160. break;
  161. case 'r':
  162. SetIntSampleRate(param->value.ui);
  163. break;
  164. case 'l':
  165. break;
  166. }
  167. }
  168. }
  169. OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id)
  170. {
  171. OSStatus res;
  172. UInt32 theSize = sizeof(UInt32);
  173. AudioDeviceID inDefault;
  174. AudioDeviceID outDefault;
  175. if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
  176. return res;
  177. if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
  178. return res;
  179. jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
  180. // Get the device only if default input and ouput are the same
  181. if (inDefault == outDefault) {
  182. *id = inDefault;
  183. return noErr;
  184. } else {
  185. jack_error("Default input and output devices are not the same !!");
  186. return kAudioHardwareBadDeviceError;
  187. }
  188. }
  189. OSStatus JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
  190. {
  191. OSStatus err = noErr;
  192. UInt32 outSize;
  193. Boolean outWritable;
  194. AudioBufferList* bufferList = 0;
  195. *channelCount = 0;
  196. err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
  197. if (err == noErr) {
  198. bufferList = (AudioBufferList*)malloc(outSize);
  199. err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
  200. if (err == noErr) {
  201. for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
  202. *channelCount += bufferList->mBuffers[i].mNumberChannels;
  203. }
  204. if (bufferList)
  205. free(bufferList);
  206. }
  207. return err;
  208. }
  209. // Setup
  210. int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
  211. const char* playback_driver_uid,
  212. char* capture_driver_name,
  213. char* playback_driver_name)
  214. {
  215. if (GetDefaultDevice(&fDeviceID) != noErr) {
  216. jack_error("Cannot open default device");
  217. return -1;
  218. }
  219. return 0;
  220. }
  221. int JackCoreAudioAdapter::SetupChannels(bool capturing,
  222. bool playing,
  223. int& inchannels,
  224. int& outchannels,
  225. int& in_nChannels,
  226. int& out_nChannels,
  227. bool strict)
  228. {
  229. OSStatus err = noErr;
  230. err = GetTotalChannels(fDeviceID, &in_nChannels, true);
  231. if (err != noErr) {
  232. jack_error("Cannot get input channel number");
  233. printError(err);
  234. return -1;
  235. }
  236. err = GetTotalChannels(fDeviceID, &out_nChannels, false);
  237. if (err != noErr) {
  238. jack_error("Cannot get output channel number");
  239. printError(err);
  240. return -1;
  241. }
  242. return 0;
  243. }
  244. int JackCoreAudioAdapter::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate)
  245. {
  246. OSStatus err = noErr;
  247. UInt32 outSize;
  248. Float64 sampleRate;
  249. // Setting buffer size
  250. outSize = sizeof(UInt32);
  251. err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes);
  252. if (err != noErr) {
  253. jack_error("Cannot set buffer size %ld", nframes);
  254. printError(err);
  255. return -1;
  256. }
  257. // Get sample rate
  258. outSize = sizeof(Float64);
  259. err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
  260. if (err != noErr) {
  261. jack_error("Cannot get current sample rate");
  262. printError(err);
  263. return -1;
  264. }
  265. // If needed, set new sample rate
  266. if (samplerate != (jack_nframes_t)sampleRate) {
  267. sampleRate = (Float64)samplerate;
  268. // To get SR change notification
  269. err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
  270. if (err != noErr) {
  271. jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
  272. printError(err);
  273. return -1;
  274. }
  275. err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
  276. if (err != noErr) {
  277. jack_error("Cannot set sample rate = %ld", samplerate);
  278. printError(err);
  279. return -1;
  280. }
  281. // Waiting for SR change notification
  282. int count = 0;
  283. while (!fState && count++ < 100) {
  284. usleep(100000);
  285. jack_log("Wait count = %ld", count);
  286. }
  287. // Remove SR change notification
  288. AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
  289. }
  290. return 0;
  291. }
  292. int JackCoreAudioAdapter::SetupBuffers(int inchannels, int outchannels)
  293. {
  294. jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld output = %ld", inchannels, outchannels);
  295. // Prepare buffers
  296. fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
  297. if (fInputData == 0) {
  298. jack_error("Cannot allocate memory for input buffers");
  299. return -1;
  300. }
  301. fInputData->mNumberBuffers = inchannels;
  302. for (int i = 0; i < fCaptureChannels; i++) {
  303. fInputData->mBuffers[i].mNumberChannels = 1;
  304. fInputData->mBuffers[i].mDataByteSize = fBufferSize * sizeof(float);
  305. fInputData->mBuffers[i].mData = malloc(fBufferSize * sizeof(float));
  306. }
  307. return 0;
  308. }
  309. void JackCoreAudioAdapter::DisposeBuffers()
  310. {
  311. if (fInputData) {
  312. for (int i = 0; i < fCaptureChannels; i++)
  313. free(fInputData->mBuffers[i].mData);
  314. free(fInputData);
  315. fInputData = 0;
  316. }
  317. }
  318. int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
  319. bool playing,
  320. int inchannels,
  321. int outchannels,
  322. int in_nChannels,
  323. int out_nChannels,
  324. jack_nframes_t nframes,
  325. jack_nframes_t samplerate,
  326. bool strict)
  327. {
  328. ComponentResult err1;
  329. UInt32 enableIO;
  330. AudioStreamBasicDescription srcFormat, dstFormat;
  331. jack_log("OpenAUHAL capturing = %ld playing = %ld playing = %ld outchannels = %ld in_nChannels = %ld out_nChannels = %ld ", capturing, playing, inchannels, inchannels, in_nChannels, out_nChannels);
  332. // AUHAL
  333. ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
  334. Component HALOutput = FindNextComponent(NULL, &cd);
  335. err1 = OpenAComponent(HALOutput, &fAUHAL);
  336. if (err1 != noErr) {
  337. jack_error("Error calling OpenAComponent");
  338. printError(err1);
  339. return -1;
  340. }
  341. err1 = AudioUnitInitialize(fAUHAL);
  342. if (err1 != noErr) {
  343. jack_error("Cannot initialize AUHAL unit");
  344. printError(err1);
  345. return -1;
  346. }
  347. // Start I/O
  348. enableIO = 1;
  349. if (capturing && inchannels > 0) {
  350. jack_log("Setup AUHAL input");
  351. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
  352. if (err1 != noErr) {
  353. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
  354. printError(err1);
  355. if (strict)
  356. return -1;
  357. }
  358. }
  359. if (playing && outchannels > 0) {
  360. jack_log("Setup AUHAL output");
  361. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
  362. if (err1 != noErr) {
  363. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
  364. printError(err1);
  365. if (strict)
  366. return -1;
  367. }
  368. }
  369. // Setup up choosen device, in both input and output cases
  370. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
  371. if (err1 != noErr) {
  372. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
  373. printError(err1);
  374. if (strict)
  375. return -1;
  376. }
  377. // Set buffer size
  378. if (capturing && inchannels > 0) {
  379. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*) & nframes, sizeof(UInt32));
  380. if (err1 != noErr) {
  381. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
  382. printError(err1);
  383. if (strict)
  384. return -1;
  385. }
  386. }
  387. if (playing && outchannels > 0) {
  388. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*) & nframes, sizeof(UInt32));
  389. if (err1 != noErr) {
  390. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
  391. printError(err1);
  392. if (strict)
  393. return -1;
  394. }
  395. }
  396. // Setup channel map
  397. if (capturing && inchannels > 0 && inchannels < in_nChannels) {
  398. SInt32 chanArr[in_nChannels];
  399. for (int i = 0; i < in_nChannels; i++) {
  400. chanArr[i] = -1;
  401. }
  402. for (int i = 0; i < inchannels; i++) {
  403. chanArr[i] = i;
  404. }
  405. AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
  406. if (err1 != noErr) {
  407. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
  408. printError(err1);
  409. }
  410. }
  411. if (playing && outchannels > 0 && outchannels < out_nChannels) {
  412. SInt32 chanArr[out_nChannels];
  413. for (int i = 0; i < out_nChannels; i++) {
  414. chanArr[i] = -1;
  415. }
  416. for (int i = 0; i < outchannels; i++) {
  417. chanArr[i] = i;
  418. }
  419. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
  420. if (err1 != noErr) {
  421. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
  422. printError(err1);
  423. }
  424. }
  425. // Setup stream converters
  426. jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
  427. srcFormat.mSampleRate = samplerate;
  428. srcFormat.mFormatID = kAudioFormatLinearPCM;
  429. srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
  430. srcFormat.mBytesPerPacket = sizeof(float);
  431. srcFormat.mFramesPerPacket = 1;
  432. srcFormat.mBytesPerFrame = sizeof(float);
  433. srcFormat.mChannelsPerFrame = outchannels;
  434. srcFormat.mBitsPerChannel = 32;
  435. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription));
  436. if (err1 != noErr) {
  437. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
  438. printError(err1);
  439. }
  440. jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
  441. dstFormat.mSampleRate = samplerate;
  442. dstFormat.mFormatID = kAudioFormatLinearPCM;
  443. dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
  444. dstFormat.mBytesPerPacket = sizeof(float);
  445. dstFormat.mFramesPerPacket = 1;
  446. dstFormat.mBytesPerFrame = sizeof(float);
  447. dstFormat.mChannelsPerFrame = inchannels;
  448. dstFormat.mBitsPerChannel = 32;
  449. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription));
  450. if (err1 != noErr) {
  451. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
  452. printError(err1);
  453. }
  454. // Setup callbacks
  455. if (inchannels > 0 && outchannels == 0) {
  456. AURenderCallbackStruct output;
  457. output.inputProc = Render;
  458. output.inputProcRefCon = this;
  459. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
  460. if (err1 != noErr) {
  461. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
  462. printError(err1);
  463. return -1;
  464. }
  465. } else {
  466. AURenderCallbackStruct output;
  467. output.inputProc = Render;
  468. output.inputProcRefCon = this;
  469. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
  470. if (err1 != noErr) {
  471. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
  472. printError(err1);
  473. return -1;
  474. }
  475. }
  476. return 0;
  477. }
  478. void JackCoreAudioAdapter::CloseAUHAL()
  479. {
  480. AudioUnitUninitialize(fAUHAL);
  481. CloseComponent(fAUHAL);
  482. }
  483. int JackCoreAudioAdapter::Open()
  484. {
  485. OSStatus err;
  486. int in_nChannels = 0;
  487. int out_nChannels = 0;
  488. if (SetupDevices("", "", "", "") < 0)
  489. return -1;
  490. if (SetupChannels(true, true, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0)
  491. return -1;
  492. if (SetupBufferSizeAndSampleRate(fBufferSize, fSampleRate) < 0)
  493. return -1;
  494. if (OpenAUHAL(true, true, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fBufferSize, fSampleRate, true) < 0)
  495. goto error;
  496. if (SetupBuffers(fCaptureChannels, fPlaybackChannels) < 0)
  497. goto error;
  498. err = AudioOutputUnitStart(fAUHAL);
  499. if (err != noErr)
  500. goto error;
  501. return 0;
  502. error:
  503. Close();
  504. return -1;
  505. }
  506. int JackCoreAudioAdapter::Close()
  507. {
  508. #ifdef DEBUG
  509. fTable.Save();
  510. #endif
  511. AudioOutputUnitStop(fAUHAL);
  512. DisposeBuffers();
  513. CloseAUHAL();
  514. return 0;
  515. }
  516. int JackCoreAudioAdapter::SetBufferSize(jack_nframes_t buffer_size)
  517. {
  518. JackAudioAdapterInterface::SetBufferSize(buffer_size);
  519. Close();
  520. return Open();
  521. }
  522. } // namespace
  523. #ifdef __cplusplus
  524. extern "C"
  525. {
  526. #endif
  527. EXPORT jack_driver_desc_t* jack_get_descriptor()
  528. {
  529. jack_driver_desc_t *desc;
  530. unsigned int i;
  531. desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
  532. strcpy(desc->name, "coreaudio-adapter");
  533. desc->nparams = 9;
  534. desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
  535. i = 0;
  536. strcpy(desc->params[i].name, "channels");
  537. desc->params[i].character = 'c';
  538. desc->params[i].type = JackDriverParamInt;
  539. desc->params[i].value.ui = 0;
  540. strcpy(desc->params[i].short_desc, "Maximum number of channels");
  541. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  542. i++;
  543. strcpy(desc->params[i].name, "inchannels");
  544. desc->params[i].character = 'i';
  545. desc->params[i].type = JackDriverParamInt;
  546. desc->params[i].value.ui = 0;
  547. strcpy(desc->params[i].short_desc, "Maximum number of input channels");
  548. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  549. i++;
  550. strcpy(desc->params[i].name, "outchannels");
  551. desc->params[i].character = 'o';
  552. desc->params[i].type = JackDriverParamInt;
  553. desc->params[i].value.ui = 0;
  554. strcpy(desc->params[i].short_desc, "Maximum number of output channels");
  555. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  556. i++;
  557. strcpy(desc->params[i].name, "capture");
  558. desc->params[i].character = 'C';
  559. desc->params[i].type = JackDriverParamString;
  560. strcpy(desc->params[i].value.str, "will take default CoreAudio input device");
  561. strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set CoreAudio device name");
  562. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  563. i++;
  564. strcpy(desc->params[i].name, "playback");
  565. desc->params[i].character = 'P';
  566. desc->params[i].type = JackDriverParamString;
  567. strcpy(desc->params[i].value.str, "will take default CoreAudio output device");
  568. strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set CoreAudio device name");
  569. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  570. i++;
  571. strcpy(desc->params[i].name, "rate");
  572. desc->params[i].character = 'r';
  573. desc->params[i].type = JackDriverParamUInt;
  574. desc->params[i].value.ui = 44100U;
  575. strcpy(desc->params[i].short_desc, "Sample rate");
  576. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  577. i++;
  578. strcpy(desc->params[i].name, "duplex");
  579. desc->params[i].character = 'D';
  580. desc->params[i].type = JackDriverParamBool;
  581. desc->params[i].value.i = TRUE;
  582. strcpy(desc->params[i].short_desc, "Provide both capture and playback ports");
  583. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  584. i++;
  585. strcpy(desc->params[i].name, "device");
  586. desc->params[i].character = 'd';
  587. desc->params[i].type = JackDriverParamString;
  588. strcpy(desc->params[i].value.str, "will take default CoreAudio device name");
  589. strcpy(desc->params[i].short_desc, "CoreAudio device name");
  590. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  591. i++;
  592. strcpy(desc->params[i].name, "list-devices");
  593. desc->params[i].character = 'l';
  594. desc->params[i].type = JackDriverParamBool;
  595. desc->params[i].value.i = TRUE;
  596. strcpy(desc->params[i].short_desc, "Display available CoreAudio devices");
  597. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  598. return desc;
  599. }
  600. #ifdef __cplusplus
  601. }
  602. #endif