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.

462 lines
13KB

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