jack2 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.

410 lines
16KB

  1. /*
  2. Copyright (C) 2010 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "TiPhoneCoreAudioRenderer.h"
  16. static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
  17. {
  18. printf("- - - - - - - - - - - - - - - - - - - -\n");
  19. printf(" Sample Rate:%f\n", inDesc->mSampleRate);
  20. printf(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
  21. printf(" Format Flags:%lX\n", inDesc->mFormatFlags);
  22. printf(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
  23. printf(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
  24. printf(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
  25. printf(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
  26. printf(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
  27. printf("- - - - - - - - - - - - - - - - - - - -\n");
  28. }
  29. static void printError(OSStatus err)
  30. {
  31. switch (err) {
  32. case kAudioConverterErr_FormatNotSupported:
  33. printf("error code : kAudioConverterErr_FormatNotSupported\n");
  34. break;
  35. case kAudioConverterErr_OperationNotSupported:
  36. printf("error code : kAudioConverterErr_OperationNotSupported\n");
  37. break;
  38. case kAudioConverterErr_PropertyNotSupported:
  39. printf("error code : kAudioConverterErr_PropertyNotSupported\n");
  40. break;
  41. case kAudioConverterErr_InvalidInputSize:
  42. printf("error code : kAudioConverterErr_InvalidInputSize\n");
  43. break;
  44. case kAudioConverterErr_InvalidOutputSize:
  45. printf("error code : kAudioConverterErr_InvalidOutputSize\n");
  46. break;
  47. case kAudioConverterErr_UnspecifiedError:
  48. printf("error code : kAudioConverterErr_UnspecifiedError\n");
  49. break;
  50. case kAudioConverterErr_BadPropertySizeError:
  51. printf("error code : kAudioConverterErr_BadPropertySizeError\n");
  52. break;
  53. case kAudioConverterErr_RequiresPacketDescriptionsError:
  54. printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
  55. break;
  56. case kAudioConverterErr_InputSampleRateOutOfRange:
  57. printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
  58. break;
  59. case kAudioConverterErr_OutputSampleRateOutOfRange:
  60. printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
  61. break;
  62. default:
  63. printf("error code : unknown\n");
  64. break;
  65. }
  66. }
  67. OSStatus TiPhoneCoreAudioRenderer::Render(void *inRefCon,
  68. AudioUnitRenderActionFlags *ioActionFlags,
  69. const AudioTimeStamp *inTimeStamp,
  70. UInt32,
  71. UInt32 inNumberFrames,
  72. AudioBufferList *ioData)
  73. {
  74. TiPhoneCoreAudioRendererPtr renderer = (TiPhoneCoreAudioRendererPtr)inRefCon;
  75. AudioUnitRender(renderer->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, renderer->fCAInputData);
  76. float coef = float(LONG_MAX);
  77. float inv_coef = 1.f/float(LONG_MAX);
  78. for (int chan = 0; chan < renderer->fDevNumInChans; chan++) {
  79. for (int frame = 0; frame < inNumberFrames; frame++) {
  80. renderer->fInChannel[chan][frame] = float(((int*)renderer->fCAInputData->mBuffers[chan].mData)[frame]) * inv_coef;
  81. }
  82. }
  83. renderer->PerformAudioCallback((int)inNumberFrames);
  84. for (int chan = 0; chan < renderer->fDevNumOutChans; chan++) {
  85. for (int frame = 0; frame < inNumberFrames; frame++) {
  86. ((int*)ioData->mBuffers[chan].mData)[frame] = int(renderer->fOutChannel[chan][frame] * coef);
  87. }
  88. }
  89. return 0;
  90. }
  91. void TiPhoneCoreAudioRenderer::InterruptionListener(void *inClientData, UInt32 inInterruption)
  92. {
  93. TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inClientData;
  94. printf("Session interrupted! --- %s ---", inInterruption == kAudioSessionBeginInterruption ? "Begin Interruption" : "End Interruption");
  95. if (inInterruption == kAudioSessionEndInterruption) {
  96. // make sure we are again the active session
  97. AudioSessionSetActive(true);
  98. AudioOutputUnitStart(obj->fAUHAL);
  99. }
  100. if (inInterruption == kAudioSessionBeginInterruption) {
  101. AudioOutputUnitStop(obj->fAUHAL);
  102. }
  103. }
  104. int TiPhoneCoreAudioRenderer::Open(int bufferSize, int samplerate)
  105. {
  106. OSStatus err1;
  107. UInt32 outSize;
  108. UInt32 enableIO;
  109. AudioStreamBasicDescription srcFormat, dstFormat;
  110. printf("Open fDevNumInChans = %ld fDevNumOutChans = %ld bufferSize = %ld samplerate = %ld\n", fDevNumInChans, fDevNumOutChans, bufferSize, samplerate);
  111. // Initialize and configure the audio session
  112. err1 = AudioSessionInitialize(NULL, NULL, InterruptionListener, this);
  113. if (err1 != noErr) {
  114. printf("Couldn't initialize audio session\n");
  115. printError(err1);
  116. return OPEN_ERR;
  117. }
  118. err1 = AudioSessionSetActive(true);
  119. if (err1 != noErr) {
  120. printf("Couldn't set audio session active\n");
  121. printError(err1);
  122. return OPEN_ERR;
  123. }
  124. UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
  125. err1 = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
  126. if (err1 != noErr) {
  127. printf("Couldn't set audio category\n");
  128. printError(err1);
  129. return OPEN_ERR;
  130. }
  131. //err1 = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self), "couldn't set property listener");
  132. Float64 hwSampleRate;
  133. outSize = sizeof(hwSampleRate);
  134. err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate);
  135. if (err1 != noErr) {
  136. printf("Couldn't get hw sample rate\n");
  137. printError(err1);
  138. return OPEN_ERR;
  139. } else {
  140. printf("Get hw sample rate %f\n", hwSampleRate);
  141. }
  142. Float32 hwBufferSize;
  143. outSize = sizeof(hwBufferSize);
  144. err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize);
  145. if (err1 != noErr) {
  146. printf("Couldn't get hw buffer duration\n");
  147. printError(err1);
  148. return OPEN_ERR;
  149. } else {
  150. printf("Get hw buffer duration %f\n", hwBufferSize);
  151. }
  152. UInt32 hwInput;
  153. outSize = sizeof(hwInput);
  154. err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &hwInput);
  155. if (err1 != noErr) {
  156. printf("Couldn't get hw input channels\n");
  157. printError(err1);
  158. return OPEN_ERR;
  159. } else {
  160. printf("Get hw input channels %d\n", hwInput);
  161. }
  162. UInt32 hwOutput;
  163. outSize = sizeof(hwOutput);
  164. err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &hwOutput);
  165. if (err1 != noErr) {
  166. printf("Couldn't get hw output channels\n");
  167. printError(err1);
  168. return OPEN_ERR;
  169. } else {
  170. printf("Get hw output channels %d\n", hwOutput);
  171. }
  172. Float32 preferredBufferSize = float(bufferSize) / float(samplerate);
  173. printf("preferredBufferSize %f \n", preferredBufferSize);
  174. err1 = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
  175. if (err1 != noErr) {
  176. printf("Couldn't set i/o buffer duration\n");
  177. printError(err1);
  178. return OPEN_ERR;
  179. }
  180. Float64 preferredSamplerate = float(samplerate);
  181. err1 = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, sizeof(preferredSamplerate), &preferredSamplerate);
  182. if (err1 != noErr) {
  183. printf("Couldn't set i/o sample rate\n");
  184. printError(err1);
  185. return OPEN_ERR;
  186. }
  187. // AUHAL
  188. AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple, 0, 0};
  189. AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
  190. err1 = AudioComponentInstanceNew(HALOutput, &fAUHAL);
  191. if (err1 != noErr) {
  192. printf("Error calling OpenAComponent\n");
  193. printError(err1);
  194. goto error;
  195. }
  196. enableIO = 1;
  197. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
  198. if (err1 != noErr) {
  199. printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
  200. printError(err1);
  201. goto error;
  202. }
  203. enableIO = 1;
  204. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
  205. if (err1 != noErr) {
  206. printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
  207. printError(err1);
  208. goto error;
  209. }
  210. UInt32 maxFPS;
  211. outSize = sizeof(maxFPS);
  212. err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, &outSize);
  213. if (err1 != noErr) {
  214. printf("Couldn't get kAudioUnitProperty_MaximumFramesPerSlice\n");
  215. printError(err1);
  216. goto error;
  217. } else {
  218. printf("Get kAudioUnitProperty_MaximumFramesPerSlice %d\n", maxFPS);
  219. }
  220. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
  221. if (err1 != noErr) {
  222. printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
  223. printError(err1);
  224. goto error;
  225. }
  226. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
  227. if (err1 != noErr) {
  228. printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
  229. printError(err1);
  230. goto error;
  231. }
  232. err1 = AudioUnitInitialize(fAUHAL);
  233. if (err1 != noErr) {
  234. printf("Cannot initialize AUHAL unit\n");
  235. printError(err1);
  236. goto error;
  237. }
  238. // Setting format
  239. if (fDevNumInChans > 0) {
  240. outSize = sizeof(AudioStreamBasicDescription);
  241. err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
  242. if (err1 != noErr) {
  243. printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
  244. printError(err1);
  245. }
  246. PrintStreamDesc(&srcFormat);
  247. srcFormat.mFormatID = kAudioFormatLinearPCM;
  248. srcFormat.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved;
  249. srcFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
  250. srcFormat.mFramesPerPacket = 1;
  251. srcFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
  252. srcFormat.mChannelsPerFrame = fDevNumInChans;
  253. srcFormat.mBitsPerChannel = 32;
  254. PrintStreamDesc(&srcFormat);
  255. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
  256. if (err1 != noErr) {
  257. printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
  258. printError(err1);
  259. }
  260. }
  261. if (fDevNumOutChans > 0) {
  262. outSize = sizeof(AudioStreamBasicDescription);
  263. err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
  264. if (err1 != noErr) {
  265. printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
  266. printError(err1);
  267. }
  268. PrintStreamDesc(&dstFormat);
  269. dstFormat.mFormatID = kAudioFormatLinearPCM;
  270. dstFormat.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved;
  271. dstFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
  272. dstFormat.mFramesPerPacket = 1;
  273. dstFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
  274. dstFormat.mChannelsPerFrame = fDevNumOutChans;
  275. dstFormat.mBitsPerChannel = 32;
  276. PrintStreamDesc(&dstFormat);
  277. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
  278. if (err1 != noErr) {
  279. printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
  280. printError(err1);
  281. }
  282. }
  283. if (fDevNumInChans > 0 && fDevNumOutChans == 0) {
  284. AURenderCallbackStruct output;
  285. output.inputProc = Render;
  286. output.inputProcRefCon = this;
  287. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
  288. if (err1 != noErr) {
  289. printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
  290. printError(err1);
  291. goto error;
  292. }
  293. } else {
  294. AURenderCallbackStruct output;
  295. output.inputProc = Render;
  296. output.inputProcRefCon = this;
  297. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
  298. if (err1 != noErr) {
  299. printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
  300. printError(err1);
  301. goto error;
  302. }
  303. }
  304. // Prepare buffers
  305. fCAInputData = (AudioBufferList*)malloc(sizeof(UInt32) + fDevNumInChans * sizeof(AudioBuffer));
  306. fCAInputData->mNumberBuffers = fDevNumInChans;
  307. for (int i = 0; i < fDevNumInChans; i++) {
  308. fCAInputData->mBuffers[i].mNumberChannels = 1;
  309. fCAInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(int);
  310. fCAInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(int));
  311. }
  312. /*
  313. // Add listeners
  314. err1 = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
  315. if (err != noErr) {
  316. jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
  317. printError(err);
  318. return -1;
  319. }
  320. */
  321. return NO_ERR;
  322. error:
  323. AudioUnitUninitialize(fAUHAL);
  324. AudioComponentInstanceDispose(fAUHAL);
  325. return OPEN_ERR;
  326. }
  327. int TiPhoneCoreAudioRenderer::Close()
  328. {
  329. AudioUnitUninitialize(fAUHAL);
  330. AudioComponentInstanceDispose(fAUHAL);
  331. return NO_ERR;
  332. }
  333. int TiPhoneCoreAudioRenderer::Start()
  334. {
  335. AudioSessionSetActive(true);
  336. OSStatus err = AudioOutputUnitStart(fAUHAL);
  337. if (err != noErr) {
  338. printf("Error while opening device : device open error \n");
  339. return OPEN_ERR;
  340. } else {
  341. return NO_ERR;
  342. }
  343. }
  344. int TiPhoneCoreAudioRenderer::Stop()
  345. {
  346. OSStatus err = AudioOutputUnitStop(fAUHAL);
  347. if (err != noErr) {
  348. printf("Error while closing device : device close error \n");
  349. return OPEN_ERR;
  350. } else {
  351. return NO_ERR;
  352. }
  353. }