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.

734 lines
27KB

  1. /*
  2. Copyright (C) 2006 Grame
  3. Portable Audio I/O Library for ASIO Drivers
  4. Author: Stephane Letz
  5. Based on the Open Source API proposed by Ross Bencina
  6. Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include "pa_asio.h"
  20. #include "JackDriverLoader.h"
  21. #include "driver_interface.h"
  22. #include "JackASIODriver.h"
  23. #include "JackEngineControl.h"
  24. #include "JackGraphManager.h"
  25. #include "JackError.h"
  26. #include "JackClientControl.h"
  27. #include "JackGlobals.h"
  28. #include <iostream>
  29. #include <windows.h>
  30. #include <mmsystem.h>
  31. #include "asiosys.h"
  32. #include "asio.h"
  33. #include "asiodrivers.h"
  34. #include "iasiothiscallresolver.h"
  35. /* external references */
  36. extern AsioDrivers* asioDrivers ;
  37. bool loadAsioDriver(char *name);
  38. namespace Jack
  39. {
  40. /*
  41. load the asio driver named by <driverName> and return statistics about
  42. the driver in info. If no error occurred, the driver will remain open
  43. and must be closed by the called by calling ASIOExit() - if an error
  44. is returned the driver will already be closed.
  45. */
  46. static PaError LoadAsioDriver( const char *driverName,
  47. PaAsioDriverInfo *driverInfo, void *systemSpecific )
  48. {
  49. PaError result = paNoError;
  50. ASIOError asioError;
  51. int asioIsInitialized = 0;
  52. if ( !loadAsioDriver(const_cast<char*>(driverName))) {
  53. result = paUnanticipatedHostError;
  54. PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
  55. goto error;
  56. }
  57. memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) );
  58. driverInfo->asioDriverInfo.asioVersion = 2;
  59. driverInfo->asioDriverInfo.sysRef = systemSpecific;
  60. if ( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK ) {
  61. result = paUnanticipatedHostError;
  62. PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
  63. goto error;
  64. } else {
  65. asioIsInitialized = 1;
  66. }
  67. if ( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount,
  68. &driverInfo->outputChannelCount)) != ASE_OK ) {
  69. result = paUnanticipatedHostError;
  70. PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
  71. goto error;
  72. }
  73. if ( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize,
  74. &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
  75. &driverInfo->bufferGranularity)) != ASE_OK ) {
  76. result = paUnanticipatedHostError;
  77. PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
  78. goto error;
  79. }
  80. if ( ASIOOutputReady() == ASE_OK )
  81. driverInfo->postOutput = true;
  82. else
  83. driverInfo->postOutput = false;
  84. return result;
  85. error:
  86. if ( asioIsInitialized )
  87. ASIOExit();
  88. return result;
  89. }
  90. int JackASIODriver::bufferSwitch(long index, ASIOBool directProcess)
  91. {
  92. JackASIODriver* driver = (JackASIODriver*)userData;
  93. // the actual processing callback.
  94. // Beware that this is normally in a seperate thread, hence be sure that
  95. // you take care about thread synchronization. This is omitted here for
  96. // simplicity.
  97. // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
  98. // to be created though it will only set the timeInfo.samplePosition and
  99. // timeInfo.systemTime fields and the according flags
  100. ASIOTime timeInfo;
  101. memset(&timeInfo, 0, sizeof(timeInfo));
  102. // get the time stamp of the buffer, not necessary if no
  103. // synchronization to other media is required
  104. if ( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
  105. timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
  106. driver->fLastWaitUst = GetMicroSeconds(); // Take callback date here
  107. driver->fInputBuffer = (float**)inputBuffer;
  108. driver->fOutputBuffer = (float**)outputBuffer;
  109. // Call the real callback
  110. bufferSwitchTimeInfo( &timeInfo, index, directProcess );
  111. return driver->Process();
  112. }
  113. int JackASIODriver::Read()
  114. {
  115. return 0;
  116. }
  117. int JackASIODriver::Write()
  118. {
  119. return 0;
  120. }
  121. int JackASIODriver::Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
  122. {
  123. PaError result = paNoError;
  124. int i, driverCount;
  125. PaAsioHostApiRepresentation *asioHostApi;
  126. PaAsioDeviceInfo *deviceInfoArray;
  127. char **names;
  128. PaAsioDriverInfo paAsioDriverInfo;
  129. asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
  130. if ( !asioHostApi ) {
  131. result = paInsufficientMemory;
  132. goto error;
  133. }
  134. asioHostApi->allocations = PaUtil_CreateAllocationGroup();
  135. if ( !asioHostApi->allocations ) {
  136. result = paInsufficientMemory;
  137. goto error;
  138. }
  139. asioHostApi->systemSpecific = 0;
  140. asioHostApi->openAsioDeviceIndex = paNoDevice;
  141. *hostApi = &asioHostApi->inheritedHostApiRep;
  142. (*hostApi)->info.structVersion = 1;
  143. (*hostApi)->info.type = paASIO;
  144. (*hostApi)->info.name = "ASIO";
  145. (*hostApi)->info.deviceCount = 0;
  146. #ifdef WINDOWS
  147. /* use desktop window as system specific ptr */
  148. asioHostApi->systemSpecific = GetDesktopWindow();
  149. CoInitialize(NULL);
  150. #endif
  151. /* MUST BE CHECKED : to force fragments loading on Mac */
  152. loadAsioDriver( "dummy" );
  153. /* driverCount is the number of installed drivers - not necessarily
  154. the number of installed physical devices. */
  155. #if MAC
  156. driverCount = asioDrivers->getNumFragments();
  157. #elif WINDOWS
  158. driverCount = asioDrivers->asioGetNumDev();
  159. #endif
  160. if ( driverCount > 0 ) {
  161. names = GetAsioDriverNames( asioHostApi->allocations, driverCount );
  162. if ( !names ) {
  163. result = paInsufficientMemory;
  164. goto error;
  165. }
  166. /* allocate enough space for all drivers, even if some aren't installed */
  167. (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
  168. asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
  169. if ( !(*hostApi)->deviceInfos ) {
  170. result = paInsufficientMemory;
  171. goto error;
  172. }
  173. /* allocate all device info structs in a contiguous block */
  174. deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
  175. asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
  176. if ( !deviceInfoArray ) {
  177. result = paInsufficientMemory;
  178. goto error;
  179. }
  180. for ( i = 0; i < driverCount; ++i ) {
  181. PA_DEBUG(("ASIO names[%d]:%s\n", i, names[i]));
  182. // Since portaudio opens ALL ASIO drivers, and no one else does that,
  183. // we face fact that some drivers were not meant for it, drivers which act
  184. // like shells on top of REAL drivers, for instance.
  185. // so we get duplicate handles, locks and other problems.
  186. // so lets NOT try to load any such wrappers.
  187. // The ones i [davidv] know of so far are:
  188. if ( strcmp (names[i], "ASIO DirectX Full Duplex Driver") == 0
  189. || strcmp (names[i], "ASIO Multimedia Driver") == 0
  190. || strncmp(names[i], "Premiere", 8) == 0 //"Premiere Elements Windows Sound 1.0"
  191. || strncmp(names[i], "Adobe", 5) == 0 ) //"Adobe Default Windows Sound 1.5"
  192. {
  193. PA_DEBUG(("BLACKLISTED!!!\n"));
  194. continue;
  195. }
  196. /* Attempt to load the asio driver... */
  197. if ( LoadAsioDriver( names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError ) {
  198. PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
  199. PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
  200. deviceInfo->structVersion = 2;
  201. deviceInfo->hostApi = hostApiIndex;
  202. deviceInfo->name = names[i];
  203. PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i, deviceInfo->name));
  204. PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriverInfo.inputChannelCount));
  205. PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriverInfo.outputChannelCount));
  206. PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriverInfo.bufferMinSize));
  207. PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriverInfo.bufferMaxSize));
  208. PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize));
  209. PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriverInfo.bufferGranularity));
  210. deviceInfo->maxInputChannels = paAsioDriverInfo.inputChannelCount;
  211. deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
  212. deviceInfo->defaultSampleRate = 0.;
  213. bool foundDefaultSampleRate = false;
  214. for ( int j = 0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j ) {
  215. ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
  216. if ( asioError != ASE_NoClock && asioError != ASE_NotPresent ) {
  217. deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
  218. foundDefaultSampleRate = true;
  219. break;
  220. }
  221. }
  222. PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
  223. if ( foundDefaultSampleRate ) {
  224. /* calculate default latency values from bufferPreferredSize
  225. for default low latency, and bufferPreferredSize * 3
  226. for default high latency.
  227. use the default sample rate to convert from samples to
  228. seconds. Without knowing what sample rate the user will
  229. use this is the best we can do.
  230. */
  231. double defaultLowLatency =
  232. paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
  233. deviceInfo->defaultLowInputLatency = defaultLowLatency;
  234. deviceInfo->defaultLowOutputLatency = defaultLowLatency;
  235. long defaultHighLatencyBufferSize =
  236. paAsioDriverInfo.bufferPreferredSize * 3;
  237. if ( defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize )
  238. defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize;
  239. double defaultHighLatency =
  240. defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate;
  241. if ( defaultHighLatency < defaultLowLatency )
  242. defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */
  243. deviceInfo->defaultHighInputLatency = defaultHighLatency;
  244. deviceInfo->defaultHighOutputLatency = defaultHighLatency;
  245. } else {
  246. deviceInfo->defaultLowInputLatency = 0.;
  247. deviceInfo->defaultLowOutputLatency = 0.;
  248. deviceInfo->defaultHighInputLatency = 0.;
  249. deviceInfo->defaultHighOutputLatency = 0.;
  250. }
  251. PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency));
  252. PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency));
  253. PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
  254. PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
  255. asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
  256. asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
  257. asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
  258. asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
  259. asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
  260. asioHostApi->allocations,
  261. sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
  262. + deviceInfo->maxOutputChannels) );
  263. if ( !asioDeviceInfo->asioChannelInfos ) {
  264. result = paInsufficientMemory;
  265. goto error;
  266. }
  267. int a;
  268. for ( a = 0; a < deviceInfo->maxInputChannels; ++a ) {
  269. asioDeviceInfo->asioChannelInfos[a].channel = a;
  270. asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
  271. ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
  272. if ( asioError != ASE_OK ) {
  273. result = paUnanticipatedHostError;
  274. PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
  275. goto error;
  276. }
  277. }
  278. for ( a = 0; a < deviceInfo->maxOutputChannels; ++a ) {
  279. int b = deviceInfo->maxInputChannels + a;
  280. asioDeviceInfo->asioChannelInfos[b].channel = a;
  281. asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
  282. ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
  283. if ( asioError != ASE_OK ) {
  284. result = paUnanticipatedHostError;
  285. PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
  286. goto error;
  287. }
  288. }
  289. /* unload the driver */
  290. ASIOExit();
  291. (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
  292. ++(*hostApi)->info.deviceCount;
  293. }
  294. }
  295. }
  296. if ( (*hostApi)->info.deviceCount > 0 ) {
  297. (*hostApi)->info.defaultInputDevice = 0;
  298. (*hostApi)->info.defaultOutputDevice = 0;
  299. } else {
  300. (*hostApi)->info.defaultInputDevice = paNoDevice;
  301. (*hostApi)->info.defaultOutputDevice = paNoDevice;
  302. }
  303. (*hostApi)->Terminate = Terminate;
  304. (*hostApi)->OpenStream = OpenStream;
  305. (*hostApi)->IsFormatSupported = IsFormatSupported;
  306. PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
  307. StopStream, AbortStream, IsStreamStopped, IsStreamActive,
  308. GetStreamTime, GetStreamCpuLoad,
  309. PaUtil_DummyRead, PaUtil_DummyWrite,
  310. PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
  311. PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
  312. StopStream, AbortStream, IsStreamStopped, IsStreamActive,
  313. GetStreamTime, PaUtil_DummyGetCpuLoad,
  314. ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
  315. return result;
  316. error:
  317. if ( asioHostApi ) {
  318. if ( asioHostApi->allocations ) {
  319. PaUtil_FreeAllAllocations( asioHostApi->allocations );
  320. PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
  321. }
  322. PaUtil_FreeMemory( asioHostApi );
  323. }
  324. return result;
  325. }
  326. void JackASIODriverTerminate( struct PaUtilHostApiRepresentation *hostApi )
  327. {
  328. PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
  329. /*
  330. IMPLEMENT ME:
  331. - clean up any resources not handled by the allocation group
  332. */
  333. if ( asioHostApi->allocations )
  334. {
  335. PaUtil_FreeAllAllocations( asioHostApi->allocations );
  336. PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
  337. }
  338. PaUtil_FreeMemory( asioHostApi );
  339. }
  340. int JackASIODriver::Open(jack_nframes_t nframes,
  341. jack_nframes_t samplerate,
  342. int capturing,
  343. int playing,
  344. int inchannels,
  345. int outchannels,
  346. bool monitor,
  347. const char* capture_driver_uid,
  348. const char* playback_driver_uid,
  349. jack_nframes_t capture_latency,
  350. jack_nframes_t playback_latency)
  351. {
  352. return 0;
  353. error:
  354. return -1;
  355. }
  356. int JackASIODriver::Close()
  357. {
  358. return 0;
  359. }
  360. int JackASIODriver::Start()
  361. {
  362. jack_log("JackASIODriver::Start");
  363. return 0;
  364. }
  365. int JackASIODriver::Stop()
  366. {
  367. jack_log("JackASIODriver::Stop");
  368. return 0;
  369. }
  370. int JackASIODriver::SetBufferSize(jack_nframes_t nframes)
  371. {
  372. return 0;
  373. }
  374. void JackASIODriver::PrintState()
  375. {
  376. int i;
  377. std::cout << "JackASIODriver state" << std::endl;
  378. jack_port_id_t port_index;
  379. std::cout << "Input ports" << std::endl;
  380. /*
  381. for (i = 0; i < fPlaybackChannels; i++) {
  382. port_index = fCapturePortList[i];
  383. JackPort* port = fGraphManager->GetPort(port_index);
  384. std::cout << port->GetName() << std::endl;
  385. if (fGraphManager->GetConnectionsNum(port_index)) {}
  386. }
  387. std::cout << "Output ports" << std::endl;
  388. for (i = 0; i < fCaptureChannels; i++) {
  389. port_index = fPlaybackPortList[i];
  390. JackPort* port = fGraphManager->GetPort(port_index);
  391. std::cout << port->GetName() << std::endl;
  392. if (fGraphManager->GetConnectionsNum(port_index)) {}
  393. }
  394. */
  395. }
  396. } // end of namespace
  397. #ifdef __cplusplus
  398. extern "C"
  399. {
  400. #endif
  401. #include "JackExports.h"
  402. EXPORT jack_driver_desc_t* driver_get_descriptor() {
  403. jack_driver_desc_t *desc;
  404. unsigned int i;
  405. desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
  406. strcpy(desc->name, "ASIO");
  407. desc->nparams = 13;
  408. desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
  409. i = 0;
  410. strcpy(desc->params[i].name, "channels");
  411. desc->params[i].character = 'c';
  412. desc->params[i].type = JackDriverParamInt;
  413. desc->params[i].value.ui = 0;
  414. strcpy(desc->params[i].short_desc, "Maximum number of channels");
  415. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  416. i++;
  417. strcpy(desc->params[i].name, "inchannels");
  418. desc->params[i].character = 'i';
  419. desc->params[i].type = JackDriverParamInt;
  420. desc->params[i].value.ui = 0;
  421. strcpy(desc->params[i].short_desc, "Maximum number of input channels");
  422. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  423. i++;
  424. strcpy(desc->params[i].name, "outchannels");
  425. desc->params[i].character = 'o';
  426. desc->params[i].type = JackDriverParamInt;
  427. desc->params[i].value.ui = 0;
  428. strcpy(desc->params[i].short_desc, "Maximum number of output channels");
  429. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  430. i++;
  431. strcpy(desc->params[i].name, "capture");
  432. desc->params[i].character = 'C';
  433. desc->params[i].type = JackDriverParamString;
  434. strcpy(desc->params[i].value.str, "will take default PortAudio input device");
  435. strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set PortAudio device name");
  436. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  437. i++;
  438. strcpy(desc->params[i].name, "playback");
  439. desc->params[i].character = 'P';
  440. desc->params[i].type = JackDriverParamString;
  441. strcpy(desc->params[i].value.str, "will take default PortAudio output device");
  442. strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set PortAudio device name");
  443. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  444. i++;
  445. strcpy (desc->params[i].name, "monitor");
  446. desc->params[i].character = 'm';
  447. desc->params[i].type = JackDriverParamBool;
  448. desc->params[i].value.i = 0;
  449. strcpy(desc->params[i].short_desc, "Provide monitor ports for the output");
  450. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  451. i++;
  452. strcpy(desc->params[i].name, "duplex");
  453. desc->params[i].character = 'D';
  454. desc->params[i].type = JackDriverParamBool;
  455. desc->params[i].value.i = TRUE;
  456. strcpy(desc->params[i].short_desc, "Provide both capture and playback ports");
  457. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  458. i++;
  459. strcpy(desc->params[i].name, "rate");
  460. desc->params[i].character = 'r';
  461. desc->params[i].type = JackDriverParamUInt;
  462. desc->params[i].value.ui = 44100U;
  463. strcpy(desc->params[i].short_desc, "Sample rate");
  464. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  465. i++;
  466. strcpy(desc->params[i].name, "period");
  467. desc->params[i].character = 'p';
  468. desc->params[i].type = JackDriverParamUInt;
  469. desc->params[i].value.ui = 128U;
  470. strcpy(desc->params[i].short_desc, "Frames per period");
  471. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  472. i++;
  473. strcpy(desc->params[i].name, "device");
  474. desc->params[i].character = 'd';
  475. desc->params[i].type = JackDriverParamString;
  476. desc->params[i].value.ui = 128U;
  477. strcpy(desc->params[i].value.str, "will take default CoreAudio device name");
  478. strcpy(desc->params[i].short_desc, "CoreAudio device name");
  479. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  480. i++;
  481. strcpy(desc->params[i].name, "input-latency");
  482. desc->params[i].character = 'I';
  483. desc->params[i].type = JackDriverParamUInt;
  484. desc->params[i].value.i = 0;
  485. strcpy(desc->params[i].short_desc, "Extra input latency");
  486. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  487. i++;
  488. strcpy(desc->params[i].name, "output-latency");
  489. desc->params[i].character = 'O';
  490. desc->params[i].type = JackDriverParamUInt;
  491. desc->params[i].value.i = 0;
  492. strcpy(desc->params[i].short_desc, "Extra output latency");
  493. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  494. i++;
  495. strcpy(desc->params[i].name, "list-devices");
  496. desc->params[i].character = 'l';
  497. desc->params[i].type = JackDriverParamBool;
  498. desc->params[i].value.i = TRUE;
  499. strcpy(desc->params[i].short_desc, "Display available CoreAudio devices");
  500. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  501. return desc;
  502. }
  503. EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackEngine* engine, Jack::JackSynchro** table, const JSList* params) {
  504. jack_nframes_t srate = 44100;
  505. jack_nframes_t frames_per_interrupt = 512;
  506. int capture = FALSE;
  507. int playback = FALSE;
  508. int chan_in = 0;
  509. int chan_out = 0;
  510. bool monitor = false;
  511. char* capture_pcm_name = "";
  512. char* playback_pcm_name = "";
  513. const JSList *node;
  514. const jack_driver_param_t *param;
  515. jack_nframes_t systemic_input_latency = 0;
  516. jack_nframes_t systemic_output_latency = 0;
  517. for (node = params; node; node = jack_slist_next(node)) {
  518. param = (const jack_driver_param_t *) node->data;
  519. switch (param->character) {
  520. case 'd':
  521. capture_pcm_name = strdup(param->value.str);
  522. playback_pcm_name = strdup(param->value.str);
  523. break;
  524. case 'D':
  525. capture = TRUE;
  526. playback = TRUE;
  527. break;
  528. case 'c':
  529. chan_in = chan_out = (int) param->value.ui;
  530. break;
  531. case 'i':
  532. chan_in = (int) param->value.ui;
  533. break;
  534. case 'o':
  535. chan_out = (int) param->value.ui;
  536. break;
  537. case 'C':
  538. capture = TRUE;
  539. if (strcmp(param->value.str, "none") != 0) {
  540. capture_pcm_name = strdup(param->value.str);
  541. }
  542. break;
  543. case 'P':
  544. playback = TRUE;
  545. if (strcmp(param->value.str, "none") != 0) {
  546. playback_pcm_name = strdup(param->value.str);
  547. }
  548. break;
  549. case 'm':
  550. monitor = param->value.i;
  551. break;
  552. case 'r':
  553. srate = param->value.ui;
  554. break;
  555. case 'p':
  556. frames_per_interrupt = (unsigned int) param->value.ui;
  557. break;
  558. case 'I':
  559. systemic_input_latency = param->value.ui;
  560. break;
  561. case 'O':
  562. systemic_output_latency = param->value.ui;
  563. break;
  564. case 'l':
  565. Jack::DisplayDeviceNames();
  566. break;
  567. }
  568. }
  569. // duplex is the default
  570. if (!capture && !playback) {
  571. capture = TRUE;
  572. playback = TRUE;
  573. }
  574. Jack::JackDriverClientInterface* driver = new Jack::JackASIODriver("ASIO", engine, table);
  575. if (driver->Open(frames_per_interrupt, srate, capture, playback, chan_in, chan_out, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency) == 0) {
  576. return driver;
  577. } else {
  578. delete driver;
  579. return NULL;
  580. }
  581. }
  582. #ifdef __cplusplus
  583. }
  584. #endif