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.

474 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)
  152. AudioDeviceStop(vDevice, process);
  153. OSStatus err = AudioDeviceRemoveIOProc(vDevice, process);
  154. if (err == noErr)
  155. status = false;
  156. free(inBuffers);
  157. free(outBuffers);
  158. }
  159. }
  160. bool AudioRender::ConfigureAudioProc(float sampleRate, long bufferSize,
  161. int outChannels, int inChannels,
  162. char *device)
  163. {
  164. OSStatus err;
  165. UInt32 size;
  166. Boolean isWritable;
  167. AudioStreamBasicDescription SR;
  168. JCALog("Wanted DEVICE: %s\n", device);
  169. err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size,
  170. &isWritable);
  171. if (err != noErr) return false;
  172. int manyDevices = size / sizeof(AudioDeviceID);
  173. AudioDeviceID devices[manyDevices];
  174. err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size,
  175. &devices);
  176. if (err != noErr) return false;
  177. bool found = false;
  178. for (int i = 0; i < manyDevices; i++) {
  179. size = sizeof(char) * 256;
  180. char name[256];
  181. err = AudioDeviceGetProperty(devices[i], 0, false,
  182. kAudioDevicePropertyDeviceName, &size,
  183. &name);
  184. JCALog("Read DEVICE: %s\n", name);
  185. if (err != noErr) return false;
  186. if (strncmp(device, name, strlen(device)) == 0) { // steph : name seems to be limited to 32 character, thus compare the common part only
  187. JCALog("Found DEVICE: %s %ld\n", name, devices[i]);
  188. vDevice = devices[i];
  189. found = true;
  190. }
  191. }
  192. if (!found) {
  193. JCALog("Cannot find device \"%s\".\n", device);
  194. return false;
  195. }
  196. char deviceName[256];
  197. err = AudioDeviceGetProperty(vDevice, 0, false,
  198. kAudioDevicePropertyDeviceName, &size,
  199. &deviceName);
  200. if (err != noErr) return false;
  201. JCALog("DEVICE: %s.\n", deviceName);
  202. JCALog("WANTED OUTPUT CHANNELS: %d.\n", outChannels);
  203. err = AudioDeviceGetPropertyInfo(vDevice, 0, false,
  204. kAudioDevicePropertyStreamFormat, &size,
  205. &isWritable);
  206. if (err != noErr) {
  207. vOutChannels = 0;
  208. }else{
  209. size = sizeof(AudioStreamBasicDescription);
  210. err = AudioDeviceGetProperty(vDevice, 0, false,
  211. kAudioDevicePropertyStreamFormat, &size,
  212. &SR);
  213. if (err != noErr) {
  214. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamFormat error: %ld\n",err);
  215. printError(err);
  216. return false;
  217. }
  218. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamFormat: OK\n");
  219. err = AudioDeviceGetPropertyInfo(vDevice, 0, false,
  220. kAudioDevicePropertyStreams, &size,
  221. &isWritable);
  222. if (err != noErr) {
  223. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams error: %ld\n",err);
  224. printError(err);
  225. return false;
  226. }
  227. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams: OK\n");
  228. err = GetTotalChannels(vDevice,(UInt32*)&vOutChannels,false);
  229. if (err != noErr) return false;
  230. n_out_streams = size / sizeof(AudioStreamID);
  231. }
  232. if (outChannels > vOutChannels) {
  233. JCALog("cannot find requested output channels\n");
  234. return false;
  235. }
  236. if (vOutChannels >= outChannels)
  237. vOutChannels = outChannels;
  238. JCALog("OUTPUT CHANNELS: %d.\n", vOutChannels);
  239. JCALog("WANTED INPUT CHANNELS: %d.\n", inChannels);
  240. err = AudioDeviceGetPropertyInfo(vDevice, 0, true,
  241. kAudioDevicePropertyStreamFormat, &size,
  242. &isWritable);
  243. if (err != noErr) {
  244. vInChannels = 0;
  245. }else{
  246. size = sizeof(AudioStreamBasicDescription);
  247. err = AudioDeviceGetProperty(vDevice, 0, true,
  248. kAudioDevicePropertyStreamFormat, &size,
  249. &SR);
  250. if (err != noErr) {
  251. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamForma terror: %ld\n",err);
  252. printError(err);
  253. return false;
  254. }
  255. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreamFormat: OK\n");
  256. err = AudioDeviceGetPropertyInfo(vDevice, 0, true,
  257. kAudioDevicePropertyStreams, &size,
  258. &isWritable);
  259. if (err != noErr) {
  260. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams error: %ld\n",err);
  261. printError(err);
  262. return false;
  263. }
  264. JCALog("AudioDeviceGetPropertyInfo kAudioDevicePropertyStreams: OK\n");
  265. err = GetTotalChannels(vDevice,(UInt32*)&vInChannels,true);
  266. if (err != noErr) return false;
  267. n_in_streams = size / sizeof(AudioStreamID);
  268. }
  269. if (inChannels > vInChannels) {
  270. JCALog("cannot find requested input channels\n");
  271. return false;
  272. }
  273. if (vInChannels >= inChannels)
  274. vInChannels = inChannels;
  275. JCALog("INPUT CHANNELS: %d.\n", vInChannels);
  276. UInt32 bufFrame;
  277. size = sizeof(UInt32);
  278. err = AudioDeviceGetProperty(vDevice, 0, false,
  279. kAudioDevicePropertyBufferFrameSize, &size,
  280. &bufFrame);
  281. if (err != noErr) return false;
  282. vBufferSize = (long) bufFrame;
  283. if ((long) bufFrame != bufferSize) {
  284. JCALog("I'm trying to set a new buffer size.\n");
  285. UInt32 theSize = sizeof(UInt32);
  286. UInt32 newBufferSize = (UInt32) bufferSize;
  287. err =
  288. AudioDeviceSetProperty(vDevice, NULL, 0, false,
  289. kAudioDevicePropertyBufferFrameSize,
  290. theSize, &newBufferSize);
  291. if (err != noErr) {
  292. JCALog("Cannot set a new buffer size.\n");
  293. return false;
  294. } else {
  295. UInt32 newBufFrame;
  296. size = sizeof(UInt32);
  297. err =
  298. AudioDeviceGetProperty(vDevice, 0, false,
  299. kAudioDevicePropertyBufferFrameSize,
  300. &size, &newBufFrame);
  301. if (err != noErr) return false;
  302. vBufferSize = (long) newBufFrame;
  303. }
  304. }
  305. JCALog("BUFFER SIZE: %ld.\n", vBufferSize);
  306. vSampleRate = (float) SR.mSampleRate;
  307. if ((float) SR.mSampleRate != sampleRate) {
  308. JCALog("I'm trying to set a new sample rate.\n");
  309. UInt32 theSize = sizeof(AudioStreamBasicDescription);
  310. SR.mSampleRate = (Float64) sampleRate;
  311. err = AudioDeviceSetProperty(vDevice, NULL, 0, false,
  312. kAudioDevicePropertyStreamFormat,
  313. theSize, &SR);
  314. if (err != noErr) {
  315. JCALog("Cannot set a new sample rate.\n");
  316. return false;
  317. } else {
  318. size = sizeof(AudioStreamBasicDescription);
  319. AudioStreamBasicDescription newCheckSR;
  320. err =
  321. AudioDeviceGetProperty(vDevice, 0, false,
  322. kAudioDevicePropertyStreamFormat,
  323. &size, &newCheckSR);
  324. if (err != noErr) return false;
  325. vSampleRate = (float) newCheckSR.mSampleRate;
  326. }
  327. }
  328. JCALog("SAMPLE RATE: %f.\n", vSampleRate);
  329. PrintStreamDesc(&SR);
  330. err = AudioDeviceAddIOProc(vDevice, process, this);
  331. if (err != noErr) return false;
  332. return true;
  333. }
  334. bool AudioRender::StartAudio()
  335. {
  336. if (status) {
  337. OSStatus err = AudioDeviceStart(vDevice, process);
  338. if (err != noErr)
  339. return false;
  340. AudioRender::isProcessing = true;
  341. return true;
  342. }
  343. return false;
  344. }
  345. bool AudioRender::StopAudio()
  346. {
  347. if (status) {
  348. OSStatus err = AudioDeviceStop(vDevice, process);
  349. if (err != noErr)
  350. return false;
  351. AudioRender::isProcessing = false;
  352. return true;
  353. }
  354. return false;
  355. }
  356. OSStatus AudioRender::process(AudioDeviceID inDevice,
  357. const AudioTimeStamp * inNow,
  358. const AudioBufferList * inInputData,
  359. const AudioTimeStamp * inInputTime,
  360. AudioBufferList * outOutputData,
  361. const AudioTimeStamp * inOutputTime,
  362. void *inClientData)
  363. {
  364. AudioRender *classe = (AudioRender *) inClientData;
  365. int channel = 0;
  366. AudioRender::gTime = inInputTime;
  367. *classe->isInterleaved = (inInputData->mNumberBuffers != 0
  368. && inInputData->mBuffers[0].
  369. mNumberChannels == 1) ? FALSE : TRUE;
  370. if (!*classe->isInterleaved) {
  371. for (unsigned int a = 0; a < inInputData->mNumberBuffers; a++) {
  372. classe->inBuffers[channel] =
  373. (float *) inInputData->mBuffers[a].mData;
  374. channel++;
  375. if (channel == classe->vInChannels)
  376. break;
  377. }
  378. channel = 0;
  379. for (unsigned int a = 0; a < outOutputData->mNumberBuffers; a++) {
  380. classe->outBuffers[channel] =
  381. (float *) outOutputData->mBuffers[a].mData;
  382. channel++;
  383. if (channel == classe->vOutChannels)
  384. break;
  385. }
  386. } else {
  387. for (unsigned int b = 0; b < inInputData->mNumberBuffers; b++) {
  388. classe->channelsPerStream[b] =
  389. (int) inInputData->mBuffers[b].mNumberChannels;
  390. classe->inBuffers[b] = (float *) inInputData->mBuffers[b].mData; // but jack will read only the inBuffers[0], anyway that should not be a problem.
  391. }
  392. for (unsigned int b = 0; b < outOutputData->mNumberBuffers; b++) {
  393. classe->out_channelsPerStream[b] =
  394. (int) outOutputData->mBuffers[b].mNumberChannels;
  395. classe->outBuffers[b] = (float *) outOutputData->mBuffers[b].mData; // but jack will read only the outBuffers[0], anyway that should not be a problem.
  396. }
  397. }
  398. classe->f_JackRunCycle(classe->jackData, classe->vBufferSize);
  399. return noErr;
  400. }
  401. float **AudioRender::getADC()
  402. {
  403. if (AudioRender::theRender == NULL)
  404. return NULL;
  405. return AudioRender::theRender->inBuffers;
  406. }
  407. float **AudioRender::getDAC()
  408. {
  409. if (AudioRender::theRender == NULL)
  410. return NULL;
  411. return AudioRender::theRender->outBuffers;
  412. }