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.

387 lines
10KB

  1. /*
  2. * AudioRender.cpp
  3. * Under Artistic License.
  4. * This code is part of Panda framework (moduleloader.cpp)
  5. * http://xpanda.sourceforge.net
  6. *
  7. * Created by Johnny Petrantoni on Fri Jan 30 2004.
  8. * Copyright (c) 2004 Johnny Petrantoni. All rights reserved.
  9. *
  10. */
  11. #include <unistd.h>
  12. #include "AudioRender.h"
  13. float AudioRender::gSampleRate = 0.0;
  14. long AudioRender::gBufferSize = 0;
  15. int AudioRender::gInputChannels = 0;
  16. int AudioRender::gOutputChannels = 0;
  17. AudioRender *AudioRender::theRender = NULL;
  18. bool AudioRender::isProcessing = false;
  19. const AudioTimeStamp *AudioRender::gTime;
  20. extern "C" void JCALog(char *fmt, ...)
  21. {
  22. va_list ap;
  23. va_start(ap, fmt);
  24. fprintf(stderr, "JCA: ");
  25. vfprintf(stderr, fmt, ap);
  26. va_end(ap);
  27. }
  28. void PrintStreamDesc(AudioStreamBasicDescription * inDesc)
  29. {
  30. if (!inDesc) {
  31. JCALog("Can't print a NULL desc!\n");
  32. return;
  33. }
  34. JCALog("- - - - - - - - - - - - - - - - - - - -\n");
  35. JCALog(" Sample Rate:%f\n", inDesc->mSampleRate);
  36. JCALog(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID),
  37. (char *) &inDesc->mFormatID);
  38. JCALog(" Format Flags:%lX\n", inDesc->mFormatFlags);
  39. JCALog(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
  40. JCALog(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
  41. JCALog(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
  42. JCALog(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
  43. JCALog(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
  44. JCALog("- - - - - - - - - - - - - - - - - - - -\n");
  45. }
  46. AudioRender::AudioRender(float sampleRate, long bufferSize, int inChannels,
  47. int outChannels,
  48. char *device):vSampleRate(sampleRate),
  49. vBufferSize(bufferSize)
  50. {
  51. inBuffers = NULL;
  52. outBuffers = NULL;
  53. status =
  54. ConfigureAudioProc(sampleRate, bufferSize, outChannels, inChannels,
  55. device);
  56. AudioRender::gSampleRate = vSampleRate;
  57. AudioRender::gBufferSize = vBufferSize;
  58. AudioRender::gInputChannels = vInChannels;
  59. AudioRender::gOutputChannels = vChannels;
  60. AudioRender::theRender = this;
  61. isProcessing = false;
  62. if (status) {
  63. inBuffers = (float **) malloc(sizeof(float *) * vInChannels);
  64. outBuffers = (float **) malloc(sizeof(float *) * vChannels);
  65. JCALog("AudioRender created.\n");
  66. JCALog("Standard driver.\n");
  67. } else
  68. JCALog("error while creating AudioRender.\n");
  69. }
  70. AudioRender::~AudioRender()
  71. {
  72. if (status) {
  73. if (isProcessing)
  74. AudioDeviceStop(vDevice, process);
  75. OSStatus err = AudioDeviceRemoveIOProc(vDevice, process);
  76. if (err == noErr)
  77. status = false;
  78. free(inBuffers);
  79. free(outBuffers);
  80. }
  81. }
  82. bool AudioRender::ConfigureAudioProc(float sampleRate, long bufferSize,
  83. int channels, int inChannels,
  84. char *device)
  85. {
  86. OSStatus err;
  87. UInt32 size;
  88. Boolean isWritable;
  89. JCALog("Wanted DEVICE: %s\n", device);
  90. err =
  91. AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size,
  92. &isWritable);
  93. if (err != noErr)
  94. return false;
  95. int manyDevices = size / sizeof(AudioDeviceID);
  96. AudioDeviceID devices[manyDevices];
  97. err =
  98. AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size,
  99. &devices);
  100. if (err != noErr)
  101. return false;
  102. bool found = false;
  103. for (int i = 0; i < manyDevices; i++) {
  104. size = sizeof(char) * 256;
  105. char name[256];
  106. err =
  107. AudioDeviceGetProperty(devices[i], 0, false,
  108. kAudioDevicePropertyDeviceName, &size,
  109. &name);
  110. JCALog("Read DEVICE: %s\n", name);
  111. if (err != noErr)
  112. return false;
  113. if (strncmp(device, name, strlen(device)) == 0) { // steph : name seems to be limited to 32 character, thus compare the common part only
  114. JCALog("Found DEVICE: %s %ld\n", name, device);
  115. vDevice = devices[i];
  116. found = true;
  117. }
  118. }
  119. if (!found) {
  120. JCALog("Cannot find device \"%s\".\n", device);
  121. return false;
  122. }
  123. char deviceName[256];
  124. err =
  125. AudioDeviceGetProperty(vDevice, 0, false,
  126. kAudioDevicePropertyDeviceName, &size,
  127. &deviceName);
  128. if (err != noErr)
  129. return false;
  130. JCALog("DEVICE: %s.\n", deviceName);
  131. size = sizeof(AudioStreamBasicDescription);
  132. AudioStreamBasicDescription SR;
  133. err =
  134. AudioDeviceGetProperty(vDevice, 0, false,
  135. kAudioDevicePropertyStreamFormat, &size,
  136. &SR);
  137. if (err != noErr)
  138. return false;
  139. err =
  140. AudioDeviceGetPropertyInfo(vDevice, 0, false,
  141. kAudioDevicePropertyStreams, &size,
  142. &isWritable);
  143. if (err != noErr)
  144. return false;
  145. vChannels =
  146. (int) SR.mChannelsPerFrame * (size / sizeof(AudioStreamID));
  147. n_out_streams = size / sizeof(AudioStreamID);
  148. if (channels > vChannels) {
  149. JCALog("cannot find requested output channels\n");
  150. return false;
  151. }
  152. if (vChannels >= channels)
  153. vChannels = channels;
  154. JCALog("OUTPUT CHANNELS: %d.\n", vChannels);
  155. err =
  156. AudioDeviceGetPropertyInfo(vDevice, 0, true,
  157. kAudioDevicePropertyStreamFormat, &size,
  158. &isWritable);
  159. if (err != noErr) {
  160. vInChannels = 0;
  161. goto endInChan;
  162. }
  163. size = sizeof(AudioStreamBasicDescription);
  164. AudioStreamBasicDescription inSR;
  165. err =
  166. AudioDeviceGetProperty(vDevice, 0, true,
  167. kAudioDevicePropertyStreamFormat, &size,
  168. &inSR);
  169. if (err != noErr)
  170. return false;
  171. err =
  172. AudioDeviceGetPropertyInfo(vDevice, 0, true,
  173. kAudioDevicePropertyStreams, &size,
  174. &isWritable);
  175. if (err != noErr)
  176. return false;
  177. vInChannels =
  178. (int) inSR.mChannelsPerFrame * (size / sizeof(AudioStreamID));
  179. n_streams = size / sizeof(AudioStreamID);
  180. endInChan:
  181. if (inChannels > vInChannels) {
  182. JCALog("cannot find requested input channels\n");
  183. return false;
  184. }
  185. if (vInChannels >= inChannels)
  186. vInChannels = inChannels;
  187. JCALog("INPUT CHANNELS: %d.\n", vInChannels);
  188. UInt32 bufFrame;
  189. size = sizeof(UInt32);
  190. err =
  191. AudioDeviceGetProperty(vDevice, 0, false,
  192. kAudioDevicePropertyBufferFrameSize, &size,
  193. &bufFrame);
  194. if (err != noErr)
  195. return false;
  196. vBufferSize = (long) bufFrame;
  197. if ((long) bufFrame != bufferSize) {
  198. JCALog("I'm trying to set a new buffer size.\n");
  199. UInt32 theSize = sizeof(UInt32);
  200. UInt32 newBufferSize = (UInt32) bufferSize;
  201. err =
  202. AudioDeviceSetProperty(vDevice, NULL, 0, false,
  203. kAudioDevicePropertyBufferFrameSize,
  204. theSize, &newBufferSize);
  205. if (err != noErr) {
  206. JCALog("Cannot set a new buffer size.\n");
  207. return false;
  208. } else {
  209. UInt32 newBufFrame;
  210. size = sizeof(UInt32);
  211. err =
  212. AudioDeviceGetProperty(vDevice, 0, false,
  213. kAudioDevicePropertyBufferFrameSize,
  214. &size, &newBufFrame);
  215. if (err != noErr)
  216. return false;
  217. vBufferSize = (long) newBufFrame;
  218. }
  219. }
  220. JCALog("BUFFER SIZE: %ld.\n", vBufferSize);
  221. vSampleRate = (float) SR.mSampleRate;
  222. if ((float) SR.mSampleRate != sampleRate) {
  223. JCALog("I'm trying to set a new sample rate.\n");
  224. UInt32 theSize = sizeof(AudioStreamBasicDescription);
  225. SR.mSampleRate = (Float64) sampleRate;
  226. err =
  227. AudioDeviceSetProperty(vDevice, NULL, 0, false,
  228. kAudioDevicePropertyStreamFormat,
  229. theSize, &SR);
  230. if (err != noErr) {
  231. JCALog("Cannot set a new sample rate.\n");
  232. return false;
  233. } else {
  234. size = sizeof(AudioStreamBasicDescription);
  235. AudioStreamBasicDescription newCheckSR;
  236. err =
  237. AudioDeviceGetProperty(vDevice, 0, false,
  238. kAudioDevicePropertyStreamFormat,
  239. &size, &newCheckSR);
  240. if (err != noErr)
  241. return false;
  242. vSampleRate = (float) newCheckSR.mSampleRate;
  243. }
  244. }
  245. JCALog("SAMPLE RATE: %f.\n", vSampleRate);
  246. PrintStreamDesc(&SR);
  247. err = AudioDeviceAddIOProc(vDevice, process, this);
  248. if (err != noErr)
  249. return false;
  250. return true;
  251. }
  252. bool AudioRender::StartAudio()
  253. {
  254. if (status) {
  255. OSStatus err = AudioDeviceStart(vDevice, process);
  256. if (err != noErr)
  257. return false;
  258. AudioRender::isProcessing = true;
  259. return true;
  260. }
  261. return false;
  262. }
  263. bool AudioRender::StopAudio()
  264. {
  265. if (status) {
  266. OSStatus err = AudioDeviceStop(vDevice, process);
  267. if (err != noErr)
  268. return false;
  269. AudioRender::isProcessing = false;
  270. return true;
  271. }
  272. return false;
  273. }
  274. OSStatus AudioRender::process(AudioDeviceID inDevice,
  275. const AudioTimeStamp * inNow,
  276. const AudioBufferList * inInputData,
  277. const AudioTimeStamp * inInputTime,
  278. AudioBufferList * outOutputData,
  279. const AudioTimeStamp * inOutputTime,
  280. void *inClientData)
  281. {
  282. AudioRender *classe = (AudioRender *) inClientData;
  283. int channel = 0;
  284. AudioRender::gTime = inInputTime;
  285. *classe->isInterleaved = (inInputData->mNumberBuffers != 0
  286. && inInputData->mBuffers[0].
  287. mNumberChannels == 1) ? FALSE : TRUE;
  288. if (!*classe->isInterleaved) {
  289. for (unsigned int a = 0; a < inInputData->mNumberBuffers; a++) {
  290. classe->inBuffers[channel] =
  291. (float *) inInputData->mBuffers[a].mData;
  292. channel++;
  293. if (channel == classe->vInChannels)
  294. break;
  295. }
  296. channel = 0;
  297. for (unsigned int a = 0; a < outOutputData->mNumberBuffers; a++) {
  298. classe->outBuffers[channel] =
  299. (float *) outOutputData->mBuffers[a].mData;
  300. channel++;
  301. if (channel == classe->vChannels)
  302. break;
  303. }
  304. } else {
  305. for (unsigned int b = 0; b < inInputData->mNumberBuffers; b++) {
  306. classe->channelsPerStream[b] =
  307. (int) inInputData->mBuffers[b].mNumberChannels;
  308. classe->inBuffers[b] = (float *) inInputData->mBuffers[b].mData; // but jack will read only the inBuffers[0], anyway that should not be a problem.
  309. }
  310. for (unsigned int b = 0; b < outOutputData->mNumberBuffers; b++) {
  311. classe->out_channelsPerStream[b] =
  312. (int) outOutputData->mBuffers[b].mNumberChannels;
  313. classe->outBuffers[b] = (float *) outOutputData->mBuffers[b].mData; // but jack will read only the outBuffers[0], anyway that should not be a problem.
  314. }
  315. }
  316. classe->f_JackRunCycle(classe->jackData, classe->vBufferSize);
  317. return noErr;
  318. }
  319. float **AudioRender::getADC()
  320. {
  321. if (AudioRender::theRender == NULL)
  322. return NULL;
  323. return AudioRender::theRender->inBuffers;
  324. }
  325. float **AudioRender::getDAC()
  326. {
  327. if (AudioRender::theRender == NULL)
  328. return NULL;
  329. return AudioRender::theRender->outBuffers;
  330. }