/[pcsx2_0.9.7]/trunk/3rdparty/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c
ViewVC logotype

Contents of /trunk/3rdparty/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations) (download)
Mon Sep 6 11:40:06 2010 UTC (9 years, 5 months ago) by william
File MIME type: text/plain
File size: 35776 byte(s)
exported r3113 from ./upstream/trunk
1 /*
2 * $Id: pa_mac_core_old.c 1083 2006-08-23 07:30:49Z rossb $
3 * pa_mac_core.c
4 * Implementation of PortAudio for Mac OS X CoreAudio
5 *
6 * PortAudio Portable Real-Time Audio Library
7 * Latest Version at: http://www.portaudio.com
8 *
9 * Authors: Ross Bencina and Phil Burk
10 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining
13 * a copy of this software and associated documentation files
14 * (the "Software"), to deal in the Software without restriction,
15 * including without limitation the rights to use, copy, modify, merge,
16 * publish, distribute, sublicense, and/or sell copies of the Software,
17 * and to permit persons to whom the Software is furnished to do so,
18 * subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be
21 * included in all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
27 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
28 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 */
31
32 /*
33 * The text above constitutes the entire PortAudio license; however,
34 * the PortAudio community also makes the following non-binding requests:
35 *
36 * Any person wishing to distribute modifications to the Software is
37 * requested to send the modifications to the original developer so that
38 * they can be incorporated into the canonical version. It is also
39 * requested that these non-binding requests be included along with the
40 * license above.
41 */
42
43 #include <CoreAudio/CoreAudio.h>
44 #include <AudioToolbox/AudioToolbox.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <math.h>
48 #include <assert.h>
49
50 #include "portaudio.h"
51 #include "pa_trace.h"
52 #include "pa_util.h"
53 #include "pa_allocation.h"
54 #include "pa_hostapi.h"
55 #include "pa_stream.h"
56 #include "pa_cpuload.h"
57 #include "pa_process.h"
58
59 // ===== constants =====
60
61 // ===== structs =====
62 #pragma mark structs
63
64 // PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation
65 typedef struct PaMacCore_HAR
66 {
67 PaUtilHostApiRepresentation inheritedHostApiRep;
68 PaUtilStreamInterface callbackStreamInterface;
69 PaUtilStreamInterface blockingStreamInterface;
70
71 PaUtilAllocationGroup *allocations;
72 AudioDeviceID *macCoreDeviceIds;
73 }
74 PaMacCoreHostApiRepresentation;
75
76 typedef struct PaMacCore_DI
77 {
78 PaDeviceInfo inheritedDeviceInfo;
79 }
80 PaMacCoreDeviceInfo;
81
82 // PaMacCoreStream - a stream data structure specifically for this implementation
83 typedef struct PaMacCore_S
84 {
85 PaUtilStreamRepresentation streamRepresentation;
86 PaUtilCpuLoadMeasurer cpuLoadMeasurer;
87 PaUtilBufferProcessor bufferProcessor;
88
89 int primeStreamUsingCallback;
90
91 AudioDeviceID inputDevice;
92 AudioDeviceID outputDevice;
93
94 // Processing thread management --------------
95 // HANDLE abortEvent;
96 // HANDLE processingThread;
97 // DWORD processingThreadId;
98
99 char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle
100 int processingThreadPriority;
101 int highThreadPriority;
102 int throttledThreadPriority;
103 unsigned long throttledSleepMsecs;
104
105 int isStopped;
106 volatile int isActive;
107 volatile int stopProcessing; // stop thread once existing buffers have been returned
108 volatile int abortProcessing; // stop thread immediately
109
110 // DWORD allBuffersDurationMs; // used to calculate timeouts
111 }
112 PaMacCoreStream;
113
114 // Data needed by the CoreAudio callback functions
115 typedef struct PaMacCore_CD
116 {
117 PaMacCoreStream *stream;
118 PaStreamCallback *callback;
119 void *userData;
120 PaUtilConverter *inputConverter;
121 PaUtilConverter *outputConverter;
122 void *inputBuffer;
123 void *outputBuffer;
124 int inputChannelCount;
125 int outputChannelCount;
126 PaSampleFormat inputSampleFormat;
127 PaSampleFormat outputSampleFormat;
128 PaUtilTriangularDitherGenerator *ditherGenerator;
129 }
130 PaMacClientData;
131
132 // ===== CoreAudio-PortAudio bridge functions =====
133 #pragma mark CoreAudio-PortAudio bridge functions
134
135 // Maps CoreAudio OSStatus codes to PortAudio PaError codes
136 static PaError conv_err(OSStatus error)
137 {
138 PaError result;
139
140 switch (error) {
141 case kAudioHardwareNoError:
142 result = paNoError; break;
143 case kAudioHardwareNotRunningError:
144 result = paInternalError; break;
145 case kAudioHardwareUnspecifiedError:
146 result = paInternalError; break;
147 case kAudioHardwareUnknownPropertyError:
148 result = paInternalError; break;
149 case kAudioHardwareBadPropertySizeError:
150 result = paInternalError; break;
151 case kAudioHardwareIllegalOperationError:
152 result = paInternalError; break;
153 case kAudioHardwareBadDeviceError:
154 result = paInvalidDevice; break;
155 case kAudioHardwareBadStreamError:
156 result = paBadStreamPtr; break;
157 case kAudioHardwareUnsupportedOperationError:
158 result = paInternalError; break;
159 case kAudioDeviceUnsupportedFormatError:
160 result = paSampleFormatNotSupported; break;
161 case kAudioDevicePermissionsError:
162 result = paDeviceUnavailable; break;
163 default:
164 result = paInternalError;
165 }
166
167 return result;
168 }
169
170 /* This function is unused
171 static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate)
172 {
173 struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription));
174 streamDescription->mSampleRate = sampleRate;
175 streamDescription->mFormatID = kAudioFormatLinearPCM;
176 streamDescription->mFormatFlags = 0;
177 streamDescription->mFramesPerPacket = 1;
178
179 if (parameters->sampleFormat & paNonInterleaved) {
180 streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved;
181 streamDescription->mChannelsPerFrame = 1;
182 streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat);
183 streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat);
184 }
185 else {
186 streamDescription->mChannelsPerFrame = parameters->channelCount;
187 }
188
189 streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame;
190 streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket;
191
192 if (parameters->sampleFormat & paFloat32) {
193 streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
194 streamDescription->mBitsPerChannel = 32;
195 }
196 else if (parameters->sampleFormat & paInt32) {
197 streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
198 streamDescription->mBitsPerChannel = 32;
199 }
200 else if (parameters->sampleFormat & paInt24) {
201 streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
202 streamDescription->mBitsPerChannel = 24;
203 }
204 else if (parameters->sampleFormat & paInt16) {
205 streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
206 streamDescription->mBitsPerChannel = 16;
207 }
208 else if (parameters->sampleFormat & paInt8) {
209 streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
210 streamDescription->mBitsPerChannel = 8;
211 }
212 else if (parameters->sampleFormat & paInt32) {
213 streamDescription->mBitsPerChannel = 8;
214 }
215
216 return streamDescription;
217 }
218 */
219
220 static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime)
221 {
222 PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo));
223
224 timeInfo->inputBufferAdcTime = inputTime->mSampleTime;
225 timeInfo->currentTime = now->mSampleTime;
226 timeInfo->outputBufferDacTime = outputTime->mSampleTime;
227
228 return timeInfo;
229 }
230
231 // ===== support functions =====
232 #pragma mark support functions
233
234 static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi)
235 {
236 if( macCoreHostApi->allocations )
237 {
238 PaUtil_FreeAllAllocations( macCoreHostApi->allocations );
239 PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations );
240 }
241
242 PaUtil_FreeMemory( macCoreHostApi );
243 }
244
245 static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput)
246 {
247 UInt32 propSize;
248 PaError err = paNoError;
249 UInt32 i;
250 int numChannels = 0;
251 AudioBufferList *buflist;
252
253 err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
254 buflist = PaUtil_AllocateMemory(propSize);
255 err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
256 if (!err) {
257 for (i = 0; i < buflist->mNumberBuffers; ++i) {
258 numChannels += buflist->mBuffers[i].mNumberChannels;
259 }
260
261 if (isInput)
262 deviceInfo->maxInputChannels = numChannels;
263 else
264 deviceInfo->maxOutputChannels = numChannels;
265
266 int frameLatency;
267 propSize = sizeof(UInt32);
268 err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
269 if (!err) {
270 double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
271 if (isInput) {
272 deviceInfo->defaultLowInputLatency = secondLatency;
273 deviceInfo->defaultHighInputLatency = secondLatency;
274 }
275 else {
276 deviceInfo->defaultLowOutputLatency = secondLatency;
277 deviceInfo->defaultHighOutputLatency = secondLatency;
278 }
279 }
280 }
281 PaUtil_FreeMemory(buflist);
282
283 return err;
284 }
285
286 static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex )
287 {
288 PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo;
289 deviceInfo->structVersion = 2;
290 deviceInfo->hostApi = hostApiIndex;
291
292 PaError err = paNoError;
293 UInt32 propSize;
294
295 err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
296 // FIXME: this allocation should be part of the allocations group
297 char *name = PaUtil_AllocateMemory(propSize);
298 err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
299 if (!err) {
300 deviceInfo->name = name;
301 }
302
303 Float64 sampleRate;
304 propSize = sizeof(Float64);
305 err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
306 if (!err) {
307 deviceInfo->defaultSampleRate = sampleRate;
308 }
309
310
311 // Get channel info
312 err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1);
313 err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0);
314
315 return err;
316 }
317
318 static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex )
319 {
320 PaError result = paNoError;
321 PaUtilHostApiRepresentation *hostApi;
322 PaMacCoreDeviceInfo *deviceInfoArray;
323
324 // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized.
325 hostApi = &macCoreHostApi->inheritedHostApiRep;
326 hostApi->info.deviceCount = 0;
327 hostApi->info.defaultInputDevice = paNoDevice;
328 hostApi->info.defaultOutputDevice = paNoDevice;
329
330 UInt32 propsize;
331 AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL);
332 int numDevices = propsize / sizeof(AudioDeviceID);
333 hostApi->info.deviceCount = numDevices;
334 if (numDevices > 0) {
335 hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
336 macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
337 if( !hostApi->deviceInfos )
338 {
339 return paInsufficientMemory;
340 }
341
342 // allocate all device info structs in a contiguous block
343 deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory(
344 macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices );
345 if( !deviceInfoArray )
346 {
347 return paInsufficientMemory;
348 }
349
350 macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize);
351 AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds);
352
353 AudioDeviceID defaultInputDevice, defaultOutputDevice;
354 propsize = sizeof(AudioDeviceID);
355 AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice);
356 AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice);
357
358 UInt32 i;
359 for (i = 0; i < numDevices; ++i) {
360 if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) {
361 hostApi->info.defaultInputDevice = i;
362 }
363 if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) {
364 hostApi->info.defaultOutputDevice = i;
365 }
366 InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex);
367 hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);
368 }
369 }
370
371 return result;
372 }
373
374 static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput)
375 {
376 UInt32 propSize = sizeof(AudioStreamBasicDescription);
377 AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize);
378
379 streamDescription->mSampleRate = sampleRate;
380 streamDescription->mFormatID = 0;
381 streamDescription->mFormatFlags = 0;
382 streamDescription->mBytesPerPacket = 0;
383 streamDescription->mFramesPerPacket = 0;
384 streamDescription->mBytesPerFrame = 0;
385 streamDescription->mChannelsPerFrame = 0;
386 streamDescription->mBitsPerChannel = 0;
387 streamDescription->mReserved = 0;
388
389 OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription);
390 PaUtil_FreeMemory(streamDescription);
391 return result;
392 }
393
394 static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount)
395 {
396 int frameSpacing, channelSpacing;
397 if (destination->inputSampleFormat & paNonInterleaved) {
398 frameSpacing = 1;
399 channelSpacing = destination->inputChannelCount;
400 }
401 else {
402 frameSpacing = destination->inputChannelCount;
403 channelSpacing = 1;
404 }
405
406 AudioBuffer const *inputBuffer = &source->mBuffers[0];
407 void *coreAudioBuffer = inputBuffer->mData;
408 void *portAudioBuffer = destination->inputBuffer;
409 UInt32 i, streamNumber, streamChannel;
410 for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) {
411 if (streamChannel >= inputBuffer->mNumberChannels) {
412 ++streamNumber;
413 inputBuffer = &source->mBuffers[streamNumber];
414 coreAudioBuffer = inputBuffer->mData;
415 streamChannel = 0;
416 }
417 destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator);
418 coreAudioBuffer += sizeof(Float32);
419 portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing;
420 }
421 return noErr;
422 }
423
424 static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount)
425 {
426 int frameSpacing, channelSpacing;
427 if (source->outputSampleFormat & paNonInterleaved) {
428 frameSpacing = 1;
429 channelSpacing = source->outputChannelCount;
430 }
431 else {
432 frameSpacing = source->outputChannelCount;
433 channelSpacing = 1;
434 }
435
436 AudioBuffer *outputBuffer = &destination->mBuffers[0];
437 void *coreAudioBuffer = outputBuffer->mData;
438 void *portAudioBuffer = source->outputBuffer;
439 UInt32 i, streamNumber, streamChannel;
440 for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) {
441 if (streamChannel >= outputBuffer->mNumberChannels) {
442 ++streamNumber;
443 outputBuffer = &destination->mBuffers[streamNumber];
444 coreAudioBuffer = outputBuffer->mData;
445 streamChannel = 0;
446 }
447 source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL);
448 coreAudioBuffer += sizeof(Float32);
449 portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing;
450 }
451 return noErr;
452 }
453
454 static OSStatus AudioIOProc( AudioDeviceID inDevice,
455 const AudioTimeStamp* inNow,
456 const AudioBufferList* inInputData,
457 const AudioTimeStamp* inInputTime,
458 AudioBufferList* outOutputData,
459 const AudioTimeStamp* inOutputTime,
460 void* inClientData)
461 {
462 PaMacClientData *clientData = (PaMacClientData *)inClientData;
463 PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
464
465 PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
466
467 AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
468 unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
469
470 if (clientData->inputBuffer) {
471 CopyInputData(clientData, inInputData, frameCount);
472 }
473 PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
474 if (clientData->outputBuffer) {
475 CopyOutputData(outOutputData, clientData, frameCount);
476 }
477
478 PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
479
480 if (result == paComplete || result == paAbort) {
481 Pa_StopStream(clientData->stream);
482 }
483
484 PaUtil_FreeMemory( timeInfo );
485 return noErr;
486 }
487
488 // This is not for input-only streams, this is for streams where the input device is different from the output device
489 static OSStatus AudioInputProc( AudioDeviceID inDevice,
490 const AudioTimeStamp* inNow,
491 const AudioBufferList* inInputData,
492 const AudioTimeStamp* inInputTime,
493 AudioBufferList* outOutputData,
494 const AudioTimeStamp* inOutputTime,
495 void* inClientData)
496 {
497 PaMacClientData *clientData = (PaMacClientData *)inClientData;
498 PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
499
500 PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
501
502 AudioBuffer const *inputBuffer = &inInputData->mBuffers[0];
503 unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32));
504
505 CopyInputData(clientData, inInputData, frameCount);
506 PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
507
508 PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
509 if( result == paComplete || result == paAbort )
510 Pa_StopStream(clientData->stream);
511 PaUtil_FreeMemory( timeInfo );
512 return noErr;
513 }
514
515 // This is not for output-only streams, this is for streams where the input device is different from the output device
516 static OSStatus AudioOutputProc( AudioDeviceID inDevice,
517 const AudioTimeStamp* inNow,
518 const AudioBufferList* inInputData,
519 const AudioTimeStamp* inInputTime,
520 AudioBufferList* outOutputData,
521 const AudioTimeStamp* inOutputTime,
522 void* inClientData)
523 {
524 PaMacClientData *clientData = (PaMacClientData *)inClientData;
525 //PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
526
527 PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
528
529 AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
530 unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
531
532 //clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
533
534 CopyOutputData(outOutputData, clientData, frameCount);
535
536 PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
537 return noErr;
538 }
539
540 static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput)
541 {
542 PaError result = paNoError;
543
544 double actualSampleRate;
545 UInt32 propSize = sizeof(double);
546 result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate));
547
548 result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate));
549
550 if (result == paNoError && actualSampleRate != sampleRate) {
551 result = paInvalidSampleRate;
552 }
553
554 return result;
555 }
556
557 static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput)
558 {
559 PaError result = paNoError;
560 UInt32 preferredFramesPerBuffer = framesPerBuffer;
561 // while (preferredFramesPerBuffer > UINT32_MAX) {
562 // preferredFramesPerBuffer /= 2;
563 // }
564
565 UInt32 actualFramesPerBuffer;
566 UInt32 propSize = sizeof(UInt32);
567 result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer));
568
569 result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer));
570
571 if (result != paNoError) {
572 // do nothing
573 }
574 else if (actualFramesPerBuffer > framesPerBuffer) {
575 result = paBufferTooSmall;
576 }
577 else if (actualFramesPerBuffer < framesPerBuffer) {
578 result = paBufferTooBig;
579 }
580
581 return result;
582 }
583
584 static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput)
585 {
586 PaError err = paNoError;
587 err = SetSampleRate(device, sampleRate, isInput);
588 if( err == paNoError )
589 err = SetFramesPerBuffer(device, framesPerBuffer, isInput);
590 return err;
591 }
592
593 // ===== PortAudio functions =====
594 #pragma mark PortAudio functions
595
596 #ifdef __cplusplus
597 extern "C"
598 {
599 #endif // __cplusplus
600
601 PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
602
603 #ifdef __cplusplus
604 }
605 #endif // __cplusplus
606
607 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
608 {
609 PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
610
611 CleanUp(macCoreHostApi);
612 }
613
614 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
615 const PaStreamParameters *inputParameters,
616 const PaStreamParameters *outputParameters,
617 double sampleRate )
618 {
619 PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
620 PaDeviceInfo *deviceInfo;
621
622 PaError result = paNoError;
623 if (inputParameters) {
624 deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
625 if (inputParameters->channelCount > deviceInfo->maxInputChannels)
626 result = paInvalidChannelCount;
627 else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) {
628 result = paInvalidSampleRate;
629 }
630 }
631 if (outputParameters && result == paNoError) {
632 deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
633 if (outputParameters->channelCount > deviceInfo->maxOutputChannels)
634 result = paInvalidChannelCount;
635 else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) {
636 result = paInvalidSampleRate;
637 }
638 }
639
640 return result;
641 }
642
643 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
644 PaStream** s,
645 const PaStreamParameters *inputParameters,
646 const PaStreamParameters *outputParameters,
647 double sampleRate,
648 unsigned long framesPerBuffer,
649 PaStreamFlags streamFlags,
650 PaStreamCallback *streamCallback,
651 void *userData )
652 {
653 PaError err = paNoError;
654 PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi;
655 PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream));
656 stream->isActive = 0;
657 stream->isStopped = 1;
658 stream->inputDevice = kAudioDeviceUnknown;
659 stream->outputDevice = kAudioDeviceUnknown;
660
661 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
662 ( (streamCallback)
663 ? &macCoreHostApi->callbackStreamInterface
664 : &macCoreHostApi->blockingStreamInterface ),
665 streamCallback, userData );
666 PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
667
668 *s = (PaStream*)stream;
669 PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData));
670 clientData->stream = stream;
671 clientData->callback = streamCallback;
672 clientData->userData = userData;
673 clientData->inputBuffer = 0;
674 clientData->outputBuffer = 0;
675 clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator));
676 PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator);
677
678 if (inputParameters != NULL) {
679 stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device];
680 clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags);
681 clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount);
682 clientData->inputChannelCount = inputParameters->channelCount;
683 clientData->inputSampleFormat = inputParameters->sampleFormat;
684 err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1);
685 }
686
687 if (err == paNoError && outputParameters != NULL) {
688 stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device];
689 clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags);
690 clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount);
691 clientData->outputChannelCount = outputParameters->channelCount;
692 clientData->outputSampleFormat = outputParameters->sampleFormat;
693 err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0);
694 }
695
696 if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) {
697 AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice;
698
699 AudioDeviceAddIOProc(device, AudioIOProc, clientData);
700 }
701 else {
702 // using different devices for input and output
703 AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData);
704 AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData);
705 }
706
707 return err;
708 }
709
710 // Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.
711 static PaError CloseStream( PaStream* s )
712 {
713 PaError err = paNoError;
714 PaMacCoreStream *stream = (PaMacCoreStream*)s;
715
716 PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
717
718 if (stream->inputDevice != kAudioDeviceUnknown) {
719 if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
720 err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc));
721 }
722 else {
723 err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc));
724 err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc));
725 }
726 }
727 else {
728 err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc));
729 }
730
731 return err;
732 }
733
734
735 static PaError StartStream( PaStream *s )
736 {
737 PaError err = paNoError;
738 PaMacCoreStream *stream = (PaMacCoreStream*)s;
739
740 if (stream->inputDevice != kAudioDeviceUnknown) {
741 if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
742 err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc));
743 }
744 else {
745 err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc));
746 err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc));
747 }
748 }
749 else {
750 err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc));
751 }
752
753 stream->isActive = 1;
754 stream->isStopped = 0;
755 return err;
756 }
757
758 static PaError AbortStream( PaStream *s )
759 {
760 PaError err = paNoError;
761 PaMacCoreStream *stream = (PaMacCoreStream*)s;
762
763 if (stream->inputDevice != kAudioDeviceUnknown) {
764 if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
765 err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc));
766 }
767 else {
768 err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc));
769 err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc));
770 }
771 }
772 else {
773 err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc));
774 }
775
776 stream->isActive = 0;
777 stream->isStopped = 1;
778 return err;
779 }
780
781 static PaError StopStream( PaStream *s )
782 {
783 // TODO: this should be nicer than abort
784 return AbortStream(s);
785 }
786
787 static PaError IsStreamStopped( PaStream *s )
788 {
789 PaMacCoreStream *stream = (PaMacCoreStream*)s;
790
791 return stream->isStopped;
792 }
793
794
795 static PaError IsStreamActive( PaStream *s )
796 {
797 PaMacCoreStream *stream = (PaMacCoreStream*)s;
798
799 return stream->isActive;
800 }
801
802
803 static PaTime GetStreamTime( PaStream *s )
804 {
805 OSStatus err;
806 PaTime result;
807 PaMacCoreStream *stream = (PaMacCoreStream*)s;
808
809 AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp));
810 if (stream->inputDevice != kAudioDeviceUnknown) {
811 err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp);
812 }
813 else {
814 err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp);
815 }
816
817 result = err ? 0 : timeStamp->mSampleTime;
818 PaUtil_FreeMemory(timeStamp);
819
820 return result;
821 }
822
823
824 static double GetStreamCpuLoad( PaStream* s )
825 {
826 PaMacCoreStream *stream = (PaMacCoreStream*)s;
827
828 return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
829 }
830
831
832 // As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams.
833
834 static PaError ReadStream( PaStream* s,
835 void *buffer,
836 unsigned long frames )
837 {
838 return paInternalError;
839 }
840
841
842 static PaError WriteStream( PaStream* s,
843 const void *buffer,
844 unsigned long frames )
845 {
846 return paInternalError;
847 }
848
849
850 static signed long GetStreamReadAvailable( PaStream* s )
851 {
852 return paInternalError;
853 }
854
855
856 static signed long GetStreamWriteAvailable( PaStream* s )
857 {
858 return paInternalError;
859 }
860
861 // HostAPI-specific initialization function
862 PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
863 {
864 PaError result = paNoError;
865 PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) );
866 if( !macCoreHostApi )
867 {
868 result = paInsufficientMemory;
869 goto error;
870 }
871
872 macCoreHostApi->allocations = PaUtil_CreateAllocationGroup();
873 if( !macCoreHostApi->allocations )
874 {
875 result = paInsufficientMemory;
876 goto error;
877 }
878
879 *hostApi = &macCoreHostApi->inheritedHostApiRep;
880 (*hostApi)->info.structVersion = 1;
881 (*hostApi)->info.type = paCoreAudio;
882 (*hostApi)->info.name = "CoreAudio";
883
884 result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex);
885 if (result != paNoError) {
886 goto error;
887 }
888
889 // Set up the proper callbacks to this HostApi's functions
890 (*hostApi)->Terminate = Terminate;
891 (*hostApi)->OpenStream = OpenStream;
892 (*hostApi)->IsFormatSupported = IsFormatSupported;
893
894 PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream,
895 StopStream, AbortStream, IsStreamStopped, IsStreamActive,
896 GetStreamTime, GetStreamCpuLoad,
897 PaUtil_DummyRead, PaUtil_DummyWrite,
898 PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
899
900 PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream,
901 StopStream, AbortStream, IsStreamStopped, IsStreamActive,
902 GetStreamTime, PaUtil_DummyGetCpuLoad,
903 ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
904
905 return result;
906
907 error:
908 if( macCoreHostApi ) {
909 CleanUp(macCoreHostApi);
910 }
911
912 return result;
913 }

  ViewVC Help
Powered by ViewVC 1.1.22