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.

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