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