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.

401 lines
11KB

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