jack1 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.

488 lines
14KB

  1. /*
  2. * AudioRender.cpp
  3. *
  4. * Copyright (c) 2004 Johnny Petrantoni. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public License
  8. * as published by the Free Software Foundation; either version 2.1
  9. * of the License, or (at your option) any later version.
  10. *
  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 GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this program; if not, write to the Free
  18. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  19. * 02111-1307, USA.
  20. *
  21. * Created by Johnny Petrantoni on Fri Jan 30 2004.
  22. * This code is part of Panda framework (moduleloader.cpp)
  23. * http://xpanda.sourceforge.net
  24. */
  25. #include <unistd.h>
  26. #include "AudioRender.h"
  27. float AudioRender::gSampleRate = 0.0;
  28. long AudioRender::gBufferSize = 0;
  29. int AudioRender::gInputChannels = 0;
  30. int AudioRender::gOutputChannels = 0;
  31. AudioRender *AudioRender::theRender = NULL;
  32. bool AudioRender::isProcessing = false;
  33. const AudioTimeStamp *AudioRender::gTime;
  34. #define PRINTDEBUG 1
  35. extern "C" void JCALog(char *fmt, ...)
  36. {
  37. #ifdef PRINTDEBUG
  38. va_list ap;
  39. va_start(ap, fmt);
  40. fprintf(stderr, "JCA: ");
  41. vfprintf(stderr, fmt, ap);
  42. va_end(ap);
  43. #endif
  44. }
  45. static OSStatus GetTotalChannels(AudioDeviceID device, UInt32 *channelCount, Boolean isInput)
  46. {
  47. OSStatus err = noErr;
  48. UInt32 outSize;
  49. Boolean outWritable;
  50. AudioBufferList *bufferList = NULL;
  51. unsigned short i;
  52. *channelCount = 0;
  53. err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
  54. if (err == noErr)
  55. {
  56. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamConfiguration: OK\n");
  57. bufferList = (AudioBufferList*)malloc(outSize);
  58. err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
  59. if (err == noErr) {
  60. for (i = 0; i < bufferList->mNumberBuffers; i++)
  61. *channelCount += bufferList->mBuffers[i].mNumberChannels;
  62. }
  63. free(bufferList);
  64. }
  65. return (err);
  66. }
  67. static void PrintStreamDesc(AudioStreamBasicDescription * inDesc)
  68. {
  69. if (!inDesc) {
  70. JCALog("Can't print a NULL desc!\n");
  71. return;
  72. }
  73. JCALog("- - - - - - - - - - - - - - - - - - - -\n");
  74. JCALog(" Sample Rate:%f\n", inDesc->mSampleRate);
  75. JCALog(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID),
  76. (char *) &inDesc->mFormatID);
  77. JCALog(" Format Flags:%lX\n", inDesc->mFormatFlags);
  78. JCALog(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
  79. JCALog(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
  80. JCALog(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
  81. JCALog(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
  82. JCALog(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
  83. JCALog("- - - - - - - - - - - - - - - - - - - -\n");
  84. }
  85. static void printError(OSStatus err)
  86. {
  87. #ifdef PRINTDEBUG
  88. switch (err) {
  89. case kAudioHardwareNoError:
  90. JCALog("error code : kAudioHardwareNoError\n");
  91. break;
  92. case kAudioHardwareNotRunningError:
  93. JCALog("error code : kAudioHardwareNotRunningError\n");
  94. break;
  95. case kAudioHardwareUnspecifiedError:
  96. printf("error code : kAudioHardwareUnspecifiedError\n");
  97. case kAudioHardwareUnknownPropertyError:
  98. JCALog("error code : kAudioHardwareUnknownPropertyError\n");
  99. break;
  100. case kAudioHardwareBadPropertySizeError:
  101. JCALog("error code : kAudioHardwareBadPropertySizeError\n");
  102. break;
  103. case kAudioHardwareIllegalOperationError:
  104. JCALog("error code : kAudioHardwareIllegalOperationError\n");
  105. break;
  106. case kAudioHardwareBadDeviceError:
  107. JCALog("error code : kAudioHardwareBadDeviceError\n");
  108. break;
  109. case kAudioHardwareBadStreamError:
  110. JCALog("error code : kAudioHardwareBadStreamError\n");
  111. break;
  112. case kAudioDeviceUnsupportedFormatError:
  113. JCALog("error code : kAudioDeviceUnsupportedFormatError\n");
  114. break;
  115. case kAudioDevicePermissionsError:
  116. JCALog("error code : kAudioDevicePermissionsError\n");
  117. break;
  118. default:
  119. JCALog("error code : unknown\n");
  120. break;
  121. }
  122. #endif
  123. }
  124. AudioRender::AudioRender(float sampleRate, long bufferSize, int inChannels,
  125. int outChannels,
  126. char *device):vSampleRate(sampleRate),
  127. vBufferSize(bufferSize)
  128. {
  129. inBuffers = NULL;
  130. outBuffers = NULL;
  131. status =
  132. ConfigureAudioProc(sampleRate, bufferSize, outChannels, inChannels,
  133. device);
  134. AudioRender::gSampleRate = vSampleRate;
  135. AudioRender::gBufferSize = vBufferSize;
  136. AudioRender::gInputChannels = vInChannels;
  137. AudioRender::gOutputChannels = vOutChannels;
  138. AudioRender::theRender = this;
  139. isProcessing = false;
  140. if (status) {
  141. inBuffers = (float **) malloc(sizeof(float *) * vInChannels);
  142. outBuffers = (float **) malloc(sizeof(float *) * vOutChannels);
  143. JCALog("AudioRender created.\n");
  144. JCALog("Standard driver.\n");
  145. } else
  146. JCALog("error while creating AudioRender.\n");
  147. }
  148. AudioRender::~AudioRender()
  149. {
  150. if (status) {
  151. if (isProcessing) AudioDeviceStop(vDevice, process);
  152. AudioDeviceRemoveIOProc(vDevice, process);
  153. AudioDeviceRemovePropertyListener(vDevice,0,true,kAudioDeviceProcessorOverload,notification);
  154. free(inBuffers);
  155. free(outBuffers);
  156. }
  157. }
  158. bool AudioRender::ConfigureAudioProc(float sampleRate, long bufferSize,
  159. int outChannels, int inChannels,
  160. char *device)
  161. {
  162. OSStatus err;
  163. UInt32 size;
  164. Boolean isWritable;
  165. AudioStreamBasicDescription SR;
  166. JCALog("Wanted DEVICE: %s\n", device);
  167. err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size,
  168. &isWritable);
  169. if (err != noErr) return false;
  170. int manyDevices = size / sizeof(AudioDeviceID);
  171. AudioDeviceID devices[manyDevices];
  172. err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size,
  173. &devices);
  174. if (err != noErr) return false;
  175. bool found = false;
  176. for (int i = 0; i < manyDevices; i++) {
  177. size = sizeof(char) * 256;
  178. char name[256];
  179. err = AudioDeviceGetProperty(devices[i], 0, false,
  180. kAudioDevicePropertyDeviceName, &size,
  181. &name);
  182. JCALog("Read DEVICE: %s\n", name);
  183. if (err != noErr) return false;
  184. if (strncmp(device, name, strlen(device)) == 0) { // steph : name seems to be limited to 32 character, thus compare the common part only
  185. JCALog("Found DEVICE: %s %ld\n", name, devices[i]);
  186. vDevice = devices[i];
  187. found = true;
  188. }
  189. }
  190. if (!found) {
  191. JCALog("Cannot find device \"%s\".\n", device);
  192. return false;
  193. }
  194. char deviceName[256];
  195. err = AudioDeviceGetProperty(vDevice, 0, false,
  196. kAudioDevicePropertyDeviceName, &size,
  197. &deviceName);
  198. if (err != noErr) return false;
  199. JCALog("DEVICE: %s.\n", deviceName);
  200. JCALog("WANTED OUTPUT CHANNELS: %d.\n", outChannels);
  201. err = AudioDeviceGetPropertyInfo(vDevice, 0, false,
  202. kAudioDevicePropertyStreamFormat, &size,
  203. &isWritable);
  204. if (err != noErr) {
  205. vOutChannels = 0;
  206. }else{
  207. size = sizeof(AudioStreamBasicDescription);
  208. err = AudioDeviceGetProperty(vDevice, 0, false,
  209. kAudioDevicePropertyStreamFormat, &size,
  210. &SR);
  211. if (err != noErr) {
  212. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamFormat error: %ld\n",err);
  213. printError(err);
  214. return false;
  215. }
  216. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamFormat: OK\n");
  217. err = AudioDeviceGetPropertyInfo(vDevice, 0, false,
  218. kAudioDevicePropertyStreams, &size,
  219. &isWritable);
  220. if (err != noErr) {
  221. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams error: %ld\n",err);
  222. printError(err);
  223. return false;
  224. }
  225. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams: OK\n");
  226. err = GetTotalChannels(vDevice,(UInt32*)&vOutChannels,false);
  227. if (err != noErr) return false;
  228. n_out_streams = size / sizeof(AudioStreamID);
  229. }
  230. if (outChannels > vOutChannels) {
  231. JCALog("cannot find requested output channels\n");
  232. return false;
  233. }
  234. if (vOutChannels >= outChannels)
  235. vOutChannels = outChannels;
  236. JCALog("OUTPUT CHANNELS: %d.\n", vOutChannels);
  237. JCALog("WANTED INPUT CHANNELS: %d.\n", inChannels);
  238. err = AudioDeviceGetPropertyInfo(vDevice, 0, true,
  239. kAudioDevicePropertyStreamFormat, &size,
  240. &isWritable);
  241. if (err != noErr) {
  242. vInChannels = 0;
  243. }else{
  244. size = sizeof(AudioStreamBasicDescription);
  245. err = AudioDeviceGetProperty(vDevice, 0, true,
  246. kAudioDevicePropertyStreamFormat, &size,
  247. &SR);
  248. if (err != noErr) {
  249. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamForma terror: %ld\n",err);
  250. printError(err);
  251. return false;
  252. }
  253. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamFormat: OK\n");
  254. err = AudioDeviceGetPropertyInfo(vDevice, 0, true,
  255. kAudioDevicePropertyStreams, &size,
  256. &isWritable);
  257. if (err != noErr) {
  258. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams error: %ld\n",err);
  259. printError(err);
  260. return false;
  261. }
  262. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams: OK\n");
  263. err = GetTotalChannels(vDevice,(UInt32*)&vInChannels,true);
  264. if (err != noErr) return false;
  265. n_in_streams = size / sizeof(AudioStreamID);
  266. }
  267. if (inChannels > vInChannels) {
  268. JCALog("cannot find requested input channels\n");
  269. return false;
  270. }
  271. if (vInChannels >= inChannels)
  272. vInChannels = inChannels;
  273. JCALog("INPUT CHANNELS: %d.\n", vInChannels);
  274. UInt32 bufFrame;
  275. size = sizeof(UInt32);
  276. err = AudioDeviceGetProperty(vDevice, 0, false,
  277. kAudioDevicePropertyBufferFrameSize, &size,
  278. &bufFrame);
  279. if (err != noErr) return false;
  280. JCALog("Internal buffer size %d.\n", bufFrame);
  281. vBufferSize = (long) bufFrame;
  282. if ((long) bufFrame != bufferSize) {
  283. JCALog("I'm trying to set a new buffer size.\n");
  284. UInt32 theSize = sizeof(UInt32);
  285. UInt32 newBufferSize = (UInt32) bufferSize;
  286. err =
  287. AudioDeviceSetProperty(vDevice, NULL, 0, false,
  288. kAudioDevicePropertyBufferFrameSize,
  289. theSize, &newBufferSize);
  290. if (err != noErr) {
  291. JCALog("Cannot set a new buffer size.\n");
  292. return false;
  293. } else {
  294. UInt32 newBufFrame;
  295. size = sizeof(UInt32);
  296. err =
  297. AudioDeviceGetProperty(vDevice, 0, false,
  298. kAudioDevicePropertyBufferFrameSize,
  299. &size, &newBufFrame);
  300. if (err != noErr) return false;
  301. vBufferSize = (long) newBufFrame;
  302. }
  303. }
  304. JCALog("BUFFER SIZE: %ld.\n", vBufferSize);
  305. vSampleRate = (float) SR.mSampleRate;
  306. if ((float) SR.mSampleRate != sampleRate) {
  307. JCALog("I'm trying to set a new sample rate.\n");
  308. UInt32 theSize = sizeof(AudioStreamBasicDescription);
  309. SR.mSampleRate = (Float64) sampleRate;
  310. err = AudioDeviceSetProperty(vDevice, NULL, 0, false,
  311. kAudioDevicePropertyStreamFormat,
  312. theSize, &SR);
  313. if (err != noErr) {
  314. JCALog("Cannot set a new sample rate.\n");
  315. return false;
  316. } else {
  317. size = sizeof(AudioStreamBasicDescription);
  318. AudioStreamBasicDescription newCheckSR;
  319. err =
  320. AudioDeviceGetProperty(vDevice, 0, false,
  321. kAudioDevicePropertyStreamFormat,
  322. &size, &newCheckSR);
  323. if (err != noErr) return false;
  324. vSampleRate = (float) newCheckSR.mSampleRate;
  325. }
  326. }
  327. JCALog("SAMPLE RATE: %f.\n", vSampleRate);
  328. PrintStreamDesc(&SR);
  329. err = AudioDeviceAddIOProc(vDevice, process, this);
  330. if (err != noErr) return false;
  331. err = AudioDeviceAddPropertyListener(vDevice,0,true,kAudioDeviceProcessorOverload,notification,this);
  332. if (err != noErr) return false;
  333. return true;
  334. }
  335. bool AudioRender::StartAudio()
  336. {
  337. if (status) {
  338. OSStatus err = AudioDeviceStart(vDevice, process);
  339. if (err != noErr)
  340. return false;
  341. AudioRender::isProcessing = true;
  342. return true;
  343. }
  344. return false;
  345. }
  346. bool AudioRender::StopAudio()
  347. {
  348. if (status) {
  349. OSStatus err = AudioDeviceStop(vDevice, process);
  350. if (err != noErr)
  351. return false;
  352. AudioRender::isProcessing = false;
  353. return true;
  354. }
  355. return false;
  356. }
  357. OSStatus AudioRender::notification(AudioDeviceID inDevice,
  358. UInt32 inChannel,
  359. Boolean isInput,
  360. AudioDevicePropertyID inPropertyID,
  361. void* inClientData)
  362. {
  363. AudioRender *classe = (AudioRender *) inClientData;
  364. switch(inPropertyID) {
  365. case kAudioDeviceProcessorOverload:
  366. JCALog("notification kAudioDeviceProcessorOverload\n");
  367. break;
  368. }
  369. }
  370. OSStatus AudioRender::process(AudioDeviceID inDevice,
  371. const AudioTimeStamp * inNow,
  372. const AudioBufferList * inInputData,
  373. const AudioTimeStamp * inInputTime,
  374. AudioBufferList * outOutputData,
  375. const AudioTimeStamp * inOutputTime,
  376. void *inClientData)
  377. {
  378. AudioRender *classe = (AudioRender *) inClientData;
  379. int channel = 0;
  380. AudioRender::gTime = inInputTime;
  381. *classe->isInterleaved = (inInputData->mNumberBuffers != 0
  382. && inInputData->mBuffers[0].
  383. mNumberChannels == 1) ? FALSE : TRUE;
  384. if (!*classe->isInterleaved) {
  385. for (unsigned int a = 0; a < inInputData->mNumberBuffers; a++) {
  386. classe->inBuffers[channel] =
  387. (float *) inInputData->mBuffers[a].mData;
  388. channel++;
  389. if (channel == classe->vInChannels) break;
  390. }
  391. channel = 0;
  392. for (unsigned int a = 0; a < outOutputData->mNumberBuffers; a++) {
  393. classe->outBuffers[channel] =
  394. (float *) outOutputData->mBuffers[a].mData;
  395. channel++;
  396. if (channel == classe->vOutChannels) break;
  397. }
  398. } else {
  399. for (unsigned int b = 0; b < inInputData->mNumberBuffers; b++) {
  400. classe->channelsPerStream[b] =
  401. (int) inInputData->mBuffers[b].mNumberChannels;
  402. classe->inBuffers[b] = (float *) inInputData->mBuffers[b].mData; // but jack will read only the inBuffers[0], anyway that should not be a problem.
  403. }
  404. for (unsigned int b = 0; b < outOutputData->mNumberBuffers; b++) {
  405. classe->out_channelsPerStream[b] =
  406. (int) outOutputData->mBuffers[b].mNumberChannels;
  407. classe->outBuffers[b] = (float *) outOutputData->mBuffers[b].mData; // but jack will read only the outBuffers[0], anyway that should not be a problem.
  408. }
  409. }
  410. classe->f_JackRunCycle(classe->jackData, classe->vBufferSize);
  411. return noErr;
  412. }
  413. float **AudioRender::getADC()
  414. {
  415. return (AudioRender::theRender == NULL) ? NULL : AudioRender::theRender->inBuffers;
  416. }
  417. float **AudioRender::getDAC()
  418. {
  419. return (AudioRender::theRender == NULL) ? NULL : AudioRender::theRender->outBuffers;
  420. }