CSL 5.2

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

- File List
- File Members

CAIO.cpp
Go to the documentation of this file.
1 //
2 // CAIO.cpp -- DAC IO using CoreAudio
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5
6 #include "CAIO.h"
7
8 #include "CAAudioHardwareDevice.h"
9 #include "CAAudioHardwareSystem.h"
10
11 using namespace csl;
12
13 // This callback routine will be called by CoreAudio/AudioUnits
14
15 static ComponentResult RenderCallback (void * userData, AudioUnitRenderActionFlags * ioActionFlags,
16 const AudioTimeStamp * inTimeStamp, UInt32 inOutputBusNumber,
17 UInt32 inNumberFrames, AudioBufferList * ioData) {
18 AUIO * auio = (AUIO *) userData; // cast uder data ptr
19 unsigned numChannels = ioData->mNumberBuffers; // assumes non-interleaved buffers
20 Buffer * auBuffer = & auio->mOutputBuffer; // temp buffer for passing ptrs to CSL
21 for (unsigned i = 0; i < numChannels; i++) // copy IO data ptrs to buffer
22 auBuffer->mBuffers[i] = (sample *) ioData->mBuffers[i].mData;
23 auBuffer->mAreBuffersAllocated = true; // set up buffer
24 auBuffer->mDidIAllocateBuffers = false;
25 auBuffer->mIsPopulated = false;
26 auio->mNumFramesPlayed += inNumberFrames;
27 auio->pullInput( * auBuffer);
28 return noErr;
29 }
30
31 // AUIO Constructors
32
33 AUIO :: AUIO() : IO() { }
34
35 AUIO :: AUIO(unsigned s_rate, unsigned b_size, int in_device, int out_device, unsigned in_chans, unsigned out_chans)
36 : IO(s_rate, b_size, in_device, out_device, in_chans, out_chans) { }
37
38 AUIO :: ~AUIO() { }
39
40 void AUIO :: handleError(OSStatus err) throw(CException) {
41 logMsg(kLogError, "An error occured while using the AudioUnit default output\n");
42 logMsg(kLogError, "Error number: %d\n", (int)err);
43 throw IOError("CoreAudio error");
44 }
45
46 // Open plugs in the callback function
47
48 void AUIO :: open() throw(CException) {
49 #ifdef DO_TIMING
50 mThisSec = mTimeVals = mTimeSum = 0;
51 #endif
52 OSStatus result;
53 AURenderCallbackStruct renderCallback;
54 renderCallback.inputProc = RenderCallback;
55 renderCallback.inputProcRefCon = this;
56 // plug in the audio renderer callback
57 result = AudioUnitSetProperty (mAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0,
58 &renderCallback, sizeof(renderCallback));
59 if (noErr != result)
60 handleError(result);
61 }
62
63 // Start/stop
64
65 void AUIO :: start() throw(CException) {
66 mNumFramesPlayed = 0;
67 }
68
69 void AUIO :: stop() throw(CException) {
70 // don't need to do anything
71 }
72
73 // Close stop the callback
74
75 void AUIO :: close() throw(CException) {
76 OSStatus result;
77 AURenderCallbackStruct renderCallback;
78 renderCallback.inputProc = NULL;
79 renderCallback.inputProcRefCon = this;
80 result = AudioUnitSetProperty (mAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0,
81 &renderCallback, sizeof(renderCallback));
82 if (noErr != result)
83 handleError(result);
84 }
85
86 // Answer the most recent input buffer
87
88 Buffer & AUIO :: getInput() throw(CException) {
89 return getInput(mInputBuffer.mNumFrames, mInputBuffer.mNumChannels);
90 }
91
92 // really get the desired format of input
93
94 Buffer & AUIO :: getInput(unsigned numFrames, unsigned numChannels) throw(CException) {
95 if (mNumInChannels == 0)
96 throw IOError("Can't get unopened input");
97 // Interleaver interleaver;
98 // interleaver.deinterleave(mInputBuffer, mInputPointer, numFrames, numChannels);
99 mInputBuffer.mIsPopulated = true;
100 return(mInputBuffer);
101 }
102
103 /////////////////////// CoreAudio IO /////////////////////////////////
104
105 // Constructor creates input/output device list
106
107 extern vector < IODevice *> gIODevices; // Global list of all known IO devices
108
109 // CAIO constructor -- verbose version loads a table of the CAIO devices
110
111 CAIO :: CAIO() : AUIO() { }
112
113 CAIO :: CAIO(unsigned s_rate, unsigned b_size, int in_device, int out_device, unsigned in_chans, unsigned out_chans)
114 : AUIO(s_rate, b_size, in_device, out_device, in_chans, out_chans) {
115 if (gIODevices.empty()) { // if we've never set up before
116 UInt32 numDevs = CAAudioHardwareSystem::GetNumberDevices();
117 if (numDevs > 0) { // if you found any devices
118 logMsg("");
119 logMsg("IO Table");
120 UInt32 devIndex = 0;
121 AudioDeviceID defInID = CAAudioHardwareSystem::GetDefaultDevice(kAudioDeviceSectionInput, false);
122 AudioDeviceID defOutID = CAAudioHardwareSystem::GetDefaultDevice(kAudioDeviceSectionOutput, false);
123 while (devIndex < numDevs) { // loop over devices
124 IODevice * newDev = new IODevice;
125 CAAudioHardwareDevice theDevice(CAAudioHardwareSystem::GetDeviceAtIndex(devIndex));
126 newDev->mIndex = theDevice.GetAudioDeviceID(); // copy index, name, rates, etc.
127 CFStringGetCString(theDevice.CopyName(), newDev->mName, CSL_NAME_LEN, 0);
128 newDev->mFrameRate = (float) theDevice.GetNominalSampleRate();
129 // get # of I/O channels for device
130 newDev->mMaxInputChannels = theDevice.GetTotalNumberChannels(kAudioDeviceSectionInput);
131 newDev->mMaxOutputChannels = theDevice.GetTotalNumberChannels(kAudioDeviceSectionOutput);
132 if (newDev->mIndex == defInID)
133 newDev->mIsDefaultIn = 1;
134 else newDev->mIsDefaultIn = 0;
135 if (newDev->mIndex == defOutID)
136 newDev->mIsDefaultOut = 1;
137 else newDev->mIsDefaultOut = 0;
138 gIODevices.push_back(newDev); // push onto global list
139 ++devIndex;
140 // Print out the CoreAudio device list
141 newDev->dump();
142 }
143 }
144 logMsg("");
145 }
146 }
147
148 CAIO :: ~CAIO() { }
149
150 // Error fnuction
151
152 void CAIO :: handleError(OSStatus result) throw(CException) {
153 AudioUnitUninitialize(mAudioUnit);
154 CloseComponent(mAudioUnit);
155 AUIO::handleError(result);
156 }
157
158 // Open sets up CAIO
159
160 void CAIO :: open() throw(CException) { // Get the output audio unit
161 OSStatus result = noErr;
162 ComponentDescription desc;
163 // get the cmoponent
164 desc.componentType = kAudioUnitType_Output;
165 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
166 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
167 desc.componentFlags = 0;
168 desc.componentFlagsMask = 0;
169 Component comp = FindNextComponent(NULL, &desc);
170 // check it
171 if (comp == NULL)
172 logMsg(kLogError, "An error occured while opening the AudioUnit default output\n");
173 // open up
174 result = OpenAComponent(comp, &mAudioUnit);
175 if (noErr != result)
176 handleError(result);
177 // AU init!
178 result = AudioUnitInitialize (mAudioUnit);
179 if (noErr != result)
180 handleError(result);
181 // AU open
182 AUIO::open();
183 }
184
185 void CAIO :: start() throw(CException) {
186 OSStatus result = AudioOutputUnitStart(mAudioUnit); // Start 'er up!
187 if (noErr != result)
188 handleError(result);
189 }
190
191 void CAIO :: stop() throw(CException) {
192 OSStatus result = AudioOutputUnitStop(mAudioUnit);
193 if (noErr != result)
194 handleError(result);
195 }
196
197 void CAIO :: close() throw(CException) {
198 AudioUnitUninitialize(mAudioUnit);
199 CloseComponent(mAudioUnit);
200 }