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.

411 lines
12KB

  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. bufferList = (AudioBufferList*)malloc(outSize);
  57. err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
  58. if (err == noErr) {
  59. for (i = 0; i < bufferList->mNumberBuffers; i++)
  60. *channelCount += bufferList->mBuffers[i].mNumberChannels;
  61. }
  62. free(bufferList);
  63. }
  64. return (err);
  65. }
  66. void PrintStreamDesc(AudioStreamBasicDescription * inDesc)
  67. {
  68. if (!inDesc) {
  69. JCALog("Can't print a NULL desc!\n");
  70. return;
  71. }
  72. JCALog("- - - - - - - - - - - - - - - - - - - -\n");
  73. JCALog(" Sample Rate:%f\n", inDesc->mSampleRate);
  74. JCALog(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID),
  75. (char *) &inDesc->mFormatID);
  76. JCALog(" Format Flags:%lX\n", inDesc->mFormatFlags);
  77. JCALog(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
  78. JCALog(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
  79. JCALog(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
  80. JCALog(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
  81. JCALog(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
  82. JCALog("- - - - - - - - - - - - - - - - - - - -\n");
  83. }
  84. AudioRender::AudioRender(float sampleRate, long bufferSize, int inChannels,
  85. int outChannels,
  86. char *device):vSampleRate(sampleRate),
  87. vBufferSize(bufferSize)
  88. {
  89. inBuffers = NULL;
  90. outBuffers = NULL;
  91. status =
  92. ConfigureAudioProc(sampleRate, bufferSize, outChannels, inChannels,
  93. device);
  94. AudioRender::gSampleRate = vSampleRate;
  95. AudioRender::gBufferSize = vBufferSize;
  96. AudioRender::gInputChannels = vInChannels;
  97. AudioRender::gOutputChannels = vOutChannels;
  98. AudioRender::theRender = this;
  99. isProcessing = false;
  100. if (status) {
  101. inBuffers = (float **) malloc(sizeof(float *) * vInChannels);
  102. outBuffers = (float **) malloc(sizeof(float *) * vOutChannels);
  103. JCALog("AudioRender created.\n");
  104. JCALog("Standard driver.\n");
  105. } else
  106. JCALog("error while creating AudioRender.\n");
  107. }
  108. AudioRender::~AudioRender()
  109. {
  110. if (status) {
  111. if (isProcessing)
  112. AudioDeviceStop(vDevice, process);
  113. OSStatus err = AudioDeviceRemoveIOProc(vDevice, process);
  114. if (err == noErr)
  115. status = false;
  116. free(inBuffers);
  117. free(outBuffers);
  118. }
  119. }
  120. bool AudioRender::ConfigureAudioProc(float sampleRate, long bufferSize,
  121. int channels, int inChannels,
  122. char *device)
  123. {
  124. OSStatus err;
  125. UInt32 size;
  126. Boolean isWritable;
  127. JCALog("Wanted DEVICE: %s\n", device);
  128. err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size,
  129. &isWritable);
  130. if (err != noErr) return false;
  131. int manyDevices = size / sizeof(AudioDeviceID);
  132. AudioDeviceID devices[manyDevices];
  133. err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size,
  134. &devices);
  135. if (err != noErr) return false;
  136. bool found = false;
  137. for (int i = 0; i < manyDevices; i++) {
  138. size = sizeof(char) * 256;
  139. char name[256];
  140. err =
  141. AudioDeviceGetProperty(devices[i], 0, false,
  142. kAudioDevicePropertyDeviceName, &size,
  143. &name);
  144. JCALog("Read DEVICE: %s\n", name);
  145. if (err != noErr)
  146. return false;
  147. if (strncmp(device, name, strlen(device)) == 0) { // steph : name seems to be limited to 32 character, thus compare the common part only
  148. JCALog("Found DEVICE: %s %ld\n", name, device);
  149. vDevice = devices[i];
  150. found = true;
  151. }
  152. }
  153. if (!found) {
  154. JCALog("Cannot find device \"%s\".\n", device);
  155. return false;
  156. }
  157. char deviceName[256];
  158. err = AudioDeviceGetProperty(vDevice, 0, false,
  159. kAudioDevicePropertyDeviceName, &size,
  160. &deviceName);
  161. if (err != noErr) return false;
  162. JCALog("DEVICE: %s.\n", deviceName);
  163. size = sizeof(AudioStreamBasicDescription);
  164. AudioStreamBasicDescription SR;
  165. err = AudioDeviceGetProperty(vDevice, 0, false,
  166. kAudioDevicePropertyStreamFormat, &size,
  167. &SR);
  168. if (err != noErr) return false;
  169. err = AudioDeviceGetPropertyInfo(vDevice, 0, false,
  170. kAudioDevicePropertyStreams, &size,
  171. &isWritable);
  172. if (err != noErr) return false;
  173. err = GetTotalChannels(vDevice,(UInt32*)&vOutChannels,false);
  174. if (err != noErr) return false;
  175. n_out_streams = size / sizeof(AudioStreamID);
  176. if (channels > vOutChannels) {
  177. JCALog("cannot find requested output channels\n");
  178. return false;
  179. }
  180. if (vOutChannels >= channels)
  181. vOutChannels = channels;
  182. JCALog("OUTPUT CHANNELS: %d.\n", vOutChannels);
  183. err = AudioDeviceGetPropertyInfo(vDevice, 0, true,
  184. kAudioDevicePropertyStreamFormat, &size,
  185. &isWritable);
  186. if (err != noErr) {
  187. vInChannels = 0;
  188. goto endInChan;
  189. }
  190. size = sizeof(AudioStreamBasicDescription);
  191. AudioStreamBasicDescription inSR;
  192. err = AudioDeviceGetProperty(vDevice, 0, true,
  193. kAudioDevicePropertyStreamFormat, &size,
  194. &inSR);
  195. if (err != noErr) return false;
  196. err = AudioDeviceGetPropertyInfo(vDevice, 0, true,
  197. kAudioDevicePropertyStreams, &size,
  198. &isWritable);
  199. if (err != noErr) return false;
  200. err = GetTotalChannels(vDevice,(UInt32*)&vInChannels,true);
  201. if (err != noErr) return false;
  202. n_in_streams = size / sizeof(AudioStreamID);
  203. endInChan:
  204. if (inChannels > vInChannels) {
  205. JCALog("cannot find requested input channels\n");
  206. return false;
  207. }
  208. if (vInChannels >= inChannels)
  209. vInChannels = inChannels;
  210. JCALog("INPUT CHANNELS: %d.\n", vInChannels);
  211. UInt32 bufFrame;
  212. size = sizeof(UInt32);
  213. err = AudioDeviceGetProperty(vDevice, 0, false,
  214. kAudioDevicePropertyBufferFrameSize, &size,
  215. &bufFrame);
  216. if (err != noErr) return false;
  217. vBufferSize = (long) bufFrame;
  218. if ((long) bufFrame != bufferSize) {
  219. JCALog("I'm trying to set a new buffer size.\n");
  220. UInt32 theSize = sizeof(UInt32);
  221. UInt32 newBufferSize = (UInt32) bufferSize;
  222. err =
  223. AudioDeviceSetProperty(vDevice, NULL, 0, false,
  224. kAudioDevicePropertyBufferFrameSize,
  225. theSize, &newBufferSize);
  226. if (err != noErr) {
  227. JCALog("Cannot set a new buffer size.\n");
  228. return false;
  229. } else {
  230. UInt32 newBufFrame;
  231. size = sizeof(UInt32);
  232. err =
  233. AudioDeviceGetProperty(vDevice, 0, false,
  234. kAudioDevicePropertyBufferFrameSize,
  235. &size, &newBufFrame);
  236. if (err != noErr) return false;
  237. vBufferSize = (long) newBufFrame;
  238. }
  239. }
  240. JCALog("BUFFER SIZE: %ld.\n", vBufferSize);
  241. vSampleRate = (float) SR.mSampleRate;
  242. if ((float) SR.mSampleRate != sampleRate) {
  243. JCALog("I'm trying to set a new sample rate.\n");
  244. UInt32 theSize = sizeof(AudioStreamBasicDescription);
  245. SR.mSampleRate = (Float64) sampleRate;
  246. err =
  247. AudioDeviceSetProperty(vDevice, NULL, 0, false,
  248. kAudioDevicePropertyStreamFormat,
  249. theSize, &SR);
  250. if (err != noErr) {
  251. JCALog("Cannot set a new sample rate.\n");
  252. return false;
  253. } else {
  254. size = sizeof(AudioStreamBasicDescription);
  255. AudioStreamBasicDescription newCheckSR;
  256. err =
  257. AudioDeviceGetProperty(vDevice, 0, false,
  258. kAudioDevicePropertyStreamFormat,
  259. &size, &newCheckSR);
  260. if (err != noErr)
  261. return false;
  262. vSampleRate = (float) newCheckSR.mSampleRate;
  263. }
  264. }
  265. JCALog("SAMPLE RATE: %f.\n", vSampleRate);
  266. PrintStreamDesc(&SR);
  267. err = AudioDeviceAddIOProc(vDevice, process, this);
  268. if (err != noErr) return false;
  269. return true;
  270. }
  271. bool AudioRender::StartAudio()
  272. {
  273. if (status) {
  274. OSStatus err = AudioDeviceStart(vDevice, process);
  275. if (err != noErr)
  276. return false;
  277. AudioRender::isProcessing = true;
  278. return true;
  279. }
  280. return false;
  281. }
  282. bool AudioRender::StopAudio()
  283. {
  284. if (status) {
  285. OSStatus err = AudioDeviceStop(vDevice, process);
  286. if (err != noErr)
  287. return false;
  288. AudioRender::isProcessing = false;
  289. return true;
  290. }
  291. return false;
  292. }
  293. OSStatus AudioRender::process(AudioDeviceID inDevice,
  294. const AudioTimeStamp * inNow,
  295. const AudioBufferList * inInputData,
  296. const AudioTimeStamp * inInputTime,
  297. AudioBufferList * outOutputData,
  298. const AudioTimeStamp * inOutputTime,
  299. void *inClientData)
  300. {
  301. AudioRender *classe = (AudioRender *) inClientData;
  302. int channel = 0;
  303. AudioRender::gTime = inInputTime;
  304. *classe->isInterleaved = (inInputData->mNumberBuffers != 0
  305. && inInputData->mBuffers[0].
  306. mNumberChannels == 1) ? FALSE : TRUE;
  307. if (!*classe->isInterleaved) {
  308. for (unsigned int a = 0; a < inInputData->mNumberBuffers; a++) {
  309. classe->inBuffers[channel] =
  310. (float *) inInputData->mBuffers[a].mData;
  311. channel++;
  312. if (channel == classe->vInChannels)
  313. break;
  314. }
  315. channel = 0;
  316. for (unsigned int a = 0; a < outOutputData->mNumberBuffers; a++) {
  317. classe->outBuffers[channel] =
  318. (float *) outOutputData->mBuffers[a].mData;
  319. channel++;
  320. if (channel == classe->vOutChannels)
  321. break;
  322. }
  323. } else {
  324. for (unsigned int b = 0; b < inInputData->mNumberBuffers; b++) {
  325. classe->channelsPerStream[b] =
  326. (int) inInputData->mBuffers[b].mNumberChannels;
  327. classe->inBuffers[b] = (float *) inInputData->mBuffers[b].mData; // but jack will read only the inBuffers[0], anyway that should not be a problem.
  328. }
  329. for (unsigned int b = 0; b < outOutputData->mNumberBuffers; b++) {
  330. classe->out_channelsPerStream[b] =
  331. (int) outOutputData->mBuffers[b].mNumberChannels;
  332. classe->outBuffers[b] = (float *) outOutputData->mBuffers[b].mData; // but jack will read only the outBuffers[0], anyway that should not be a problem.
  333. }
  334. }
  335. classe->f_JackRunCycle(classe->jackData, classe->vBufferSize);
  336. return noErr;
  337. }
  338. float **AudioRender::getADC()
  339. {
  340. if (AudioRender::theRender == NULL)
  341. return NULL;
  342. return AudioRender::theRender->inBuffers;
  343. }
  344. float **AudioRender::getDAC()
  345. {
  346. if (AudioRender::theRender == NULL)
  347. return NULL;
  348. return AudioRender::theRender->outBuffers;
  349. }