CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

iphoneIO.cpp
Go to the documentation of this file.
1 //
2 // iphoneIO.cpp -- DAC IO using CoreAudio for the iphone
3 // Abstract AUIO class and concrete CAIO class
4 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
5 //
6
7 #include "iphoneIO.h"
8
9 using namespace csl;
10
11 //float maxSampEver = 0.0f;
12 //extern float maxSampEver;
13
14 #define CHECK_SAMP(sam) \
15 if (fabs(*sam) > maxSampEver) \
16 maxSampEver = fabs(*sam);
17
18 // This callback routine will be called by CoreAudio/AudioUnits
19
20 static OSStatus RenderCallback(void * userData, AudioUnitRenderActionFlags * ioActionFlags,
21 const AudioTimeStamp * inTimeStamp, UInt32 inOutputBusNumber,
22 UInt32 inNumberFrames, AudioBufferList * ioData) {
23 AUIO * auio = (AUIO *) userData; // cast uder data ptr
24 unsigned numChannels = ioData->buffer(0].mNumberChannels; // interleaved buffers
25 Buffer * auBuffer = &auio->mOutputBuffer; // temp buffer for passing ptrs to CSL
26
27 if ( ! auio->mGraph) // if graph not set
28 return noErr;
29
30 auBuffer->mNumChannels = numChannels; // set up buffer
31 auBuffer->mNumFrames = inNumberFrames;
32
33 auio->pullInput(*auBuffer); ////// get data from the DSP graph //////
34
35 auio->mNumFramesPlayed += inNumberFrames;
36
37 sample * samp = auBuffer->buffer(0]; // src buffer ptr
38 SInt16 * outData = (SInt16 *) ioData->buffer(0].mData; // output ptr
39 SInt16 final;
40 if (numChannels == 1) { // mono case
41 for (unsigned i = 0; i < inNumberFrames; i++) { // output copy loop
42 final = (SInt16) (*samp++ * 32768.0f);
43 *outData++ = final;
44 }
45 } else { // stereo case; interleave samples
46 sample * samp2 = auBuffer->buffer(1]; // other channel
47 for (unsigned i = 0; i < inNumberFrames; i++) {
48 // CHECK_SAMP(samp)
49 final = (SInt16) (*samp++ * 32767.0f);
50 *outData++ = final;
51 // CHECK_SAMP(samp2)
52 final = (SInt16) (*samp2++ * 32767.0f);
53 *outData++ = final;
54 }
55 }
56 return noErr;
57 }
58
59 // AUIO Constructors
60
61 AUIO :: AUIO() : IO() {
62 mOutputBuffer.setSize(2, CGestalt::maxBufferFrames()); // allocate extra just for sure
63 mOutputBuffer.allocateBuffers();
64 }
65
66 AUIO :: AUIO(unsigned s_rate, unsigned b_size, int in_device, int out_device,
67 unsigned in_chans, unsigned out_chans)
68 : IO(s_rate, b_size, in_device, out_device, in_chans, out_chans) {
69 mOutputBuffer.setSize(2, CGestalt::maxBufferFrames()); // allocate extra just for sure
70 mOutputBuffer.allocateBuffers();
71 }
72
73 AUIO :: ~AUIO() { }
74
75 void AUIO :: handleError(OSStatus err) throw(CException) {
76 logMsg(kLogError, "An error occured while using the AudioUnit");
77 logMsg(kLogError, "Error number: %d", (int) err);
78 throw IOError("AUIO error");
79 }
80
81 // Open
82
83 void AUIO :: open() throw(CException) { }
84
85 // Start/stop plugs in the callback function
86
87 void AUIO :: start() throw(CException) {
88 mNumFramesPlayed = 0;
89 #ifdef DO_TIMING
90 mThisSec = mTimeVals = mTimeSum = 0;
91 #endif
92 OSStatus result;
93 AURenderCallbackStruct renderCallback;
94
95 renderCallback.inputProc = RenderCallback;
96 renderCallback.inputProcRefCon = this;
97 // plug in the audio renderer callback
98 result = AudioUnitSetProperty (mAudioUnit, kAudioUnitProperty_SetRenderCallback,
99 kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback));
100 if (noErr != result)
101 handleError(result);
102 }
103
104 void AUIO :: stop() throw(CException) {
105 OSStatus result;
106 AURenderCallbackStruct renderCallback;
107
108 renderCallback.inputProc = NULL; //clear the callback pointer
109 renderCallback.inputProcRefCon = this;
110
111 result = AudioUnitSetProperty (mAudioUnit, kAudioUnitProperty_SetRenderCallback,
112 kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback));
113 if (noErr != result)
114 handleError(result);
115 }
116
117 // Close -- don't need to do anything
118
119 void AUIO :: close() throw(CException) { }
120
121 // Answer the most recent input buffer
122
123 Buffer & AUIO :: getInput() throw(CException) {
124 return getInput(mInputBuffer.mNumFrames, mInputBuffer.mNumChannels);
125 }
126
127 // really get the desired format of input
128
129 Buffer & AUIO :: getInput(unsigned numFrames, unsigned numChannels) throw(CException) {
130 if (mNumInChannels == 0)
131 throw IOError("Can't get unopened input");
132 mInputBuffer.mIsPopulated = true;
133 return(mInputBuffer);
134 }
135
136 /////////////////////// iPhoneIO IO /////////////////////////////////
137
138 // Constructor creates input/output device list
139
140 extern vector < IODevice *> gIODevices; // Global list of all known IO devices
141
142 // iphoneIO constructor -- verbose version loads a table of the iphoneIO devices
143
144 iPhoneIO :: iPhoneIO() : AUIO() { }
145
146 // this version is not used
147
148 iPhoneIO :: iPhoneIO(unsigned s_rate, unsigned b_size,
149 int in_device, int out_device, unsigned in_chans, unsigned out_chans)
150 : AUIO(s_rate, b_size, in_device, out_device, in_chans, out_chans) {
151 // if (gIODevices.empty()) { // if we've never set up before
152 // IODevice * newDev = new IODevice("iPhoneIO", 0, 1, 2, true, true);
153 // newDev->mFrameRate = 44100;
154 // gIODevices.push_back(newDev); // push onto global list
155 // newDev->dump();
156 // } else {
157 // for (unsigned i = 0; i < gIODevices.size(); i++)
158 // gIODevices[i]->dump();
159 // }
160 }
161
162 iPhoneIO :: ~iPhoneIO() { }
163
164 // Error function
165
166 void iPhoneIO :: handleError(OSStatus result) throw(CException) {
167 AudioUnitUninitialize(mAudioUnit);
168 AUIO::handleError(result);
169 }
170
171 // Open sets up iPhoneIO
172
173 void iPhoneIO :: open() throw(CException) { // Get the output audio unit
174 OSStatus result = noErr;
175 AudioComponentDescription desc;
176 desc.componentType = kAudioUnitType_Output; // set up the component description
177 // kAudioUnitType_Output = kAudioFormatFlagIsSignedInteger
178 // + kAudioFormatFlagIsPacked + kAudioFormatFlagIsNonInterleaved
179 // + (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift)
180 desc.componentSubType = kAudioUnitSubType_RemoteIO;
181 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
182 desc.componentFlags = 0;
183 desc.componentFlagsMask = 0;
184 // find a component
185 AudioComponent comp = AudioComponentFindNext(NULL, &desc);
186 if (comp == NULL) { // check it
187 logMsg(kLogError, "An error occured while finding the AudioUnit default output\n");
188 throw IOError("CoreAudio error in AudioComponentFindNext");
189 }
190 result = AudioComponentInstanceNew(comp, &mAudioUnit); // open it up
191 if (noErr != result)
192 handleError(result);
193
194 result = AudioUnitInitialize(mAudioUnit); // AU init it
195 if (noErr != result)
196 handleError(result);
197
198 AudioStreamBasicDescription audioFormat;
199 audioFormat.mSampleRate = (Float64) CGestalt::frameRate(); // FS
200 audioFormat.mFormatID = kAudioFormatLinearPCM;
201 audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
202 audioFormat.mFramesPerPacket = 1;
203 audioFormat.mChannelsPerFrame = 2; // stereo
204 audioFormat.mBitsPerChannel = 16; // 16-bit
205 audioFormat.mBytesPerPacket = 4;
206 audioFormat.mBytesPerFrame = 4;
207
208 result = AudioUnitSetProperty(mAudioUnit,
209 kAudioUnitProperty_StreamFormat,
210 kAudioUnitScope_Output,
211 0,
212 &audioFormat,
213 sizeof(audioFormat));
214 if (noErr != result)
215 handleError(result);
216
217 // result = AudioUnitInitialize (mAudioUnit); // AU init it
218 // if (noErr != result)
219 // handleError(result);
220
221 AUIO::open(); // AU open
222 // logMsg("AUIO::open OK");
223
224 // Initialize and configure the audio session
225 AudioSessionInitialize(NULL, NULL, NULL, this);
226
227 // set the audio category
228 UInt32 audioCategory = kAudioSessionCategory_LiveAudio;
229 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
230 UInt32 getAudioCategory = sizeof(audioCategory);
231 AudioSessionGetProperty(kAudioSessionProperty_AudioCategory, &getAudioCategory, &getAudioCategory);
232
233 // set block rate
234 Float32 preferredBufferSize = (float) CGestalt::blockSize() / (float) CGestalt::frameRate();
235
236 AudioSessionSetProperty (kAudioSessionProperty_PreferredHardwareIOBufferDuration,
237 sizeof(preferredBufferSize), &preferredBufferSize);
238
239 // set the audio session active
240 AudioSessionSetActive(true);
241
242 // ask whether we support stereo output
243 // UInt32 numOutputChannels;
244 // UInt32 dataSize = sizeof(UInt32);
245 // result = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels,
246 // & dataSize, & numOutputChannels);
247 // logMsg("AudioUnit outputs: %d\n", numOutputChannels);
248 }
249
250 void iPhoneIO :: start() throw(CException) {
251 AUIO::start();
252 OSStatus result = AudioOutputUnitStart(mAudioUnit); // Start 'er up!
253 if (noErr != result)
254 handleError(result);
255 logMsg("iPhoneIO :: start");
256 }
257
258 void iPhoneIO :: stop() throw(CException) {
259 AUIO::stop();
260 OSStatus result = AudioOutputUnitStop(mAudioUnit);
261 if (noErr != result)
262 handleError(result);
263 logMsg("iPhoneIO :: stop");
264 }
265
266 void iPhoneIO :: close() throw(CException) {
267 AudioUnitUninitialize(mAudioUnit);
268 //CloseComponent(mAudioUnit);
269 AUIO::close();
270 }