2
* $Id: pa_mac_core_old.c 1083 2006-08-23 07:30:49Z rossb $
4
* Implementation of PortAudio for Mac OS X CoreAudio
6
* PortAudio Portable Real-Time Audio Library
7
* Latest Version at: http://www.portaudio.com
9
* Authors: Ross Bencina and Phil Burk
10
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
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:
20
* The above copyright notice and this permission notice shall be
21
* included in all copies or substantial portions of the Software.
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.
33
* The text above constitutes the entire PortAudio license; however,
34
* the PortAudio community also makes the following non-binding requests:
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
43
#include <CoreAudio/CoreAudio.h>
44
#include <AudioToolbox/AudioToolbox.h>
50
#include "portaudio.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"
59
// ===== constants =====
61
// ===== structs =====
64
// PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation
65
typedef struct PaMacCore_HAR
67
PaUtilHostApiRepresentation inheritedHostApiRep;
68
PaUtilStreamInterface callbackStreamInterface;
69
PaUtilStreamInterface blockingStreamInterface;
71
PaUtilAllocationGroup *allocations;
72
AudioDeviceID *macCoreDeviceIds;
74
PaMacCoreHostApiRepresentation;
76
typedef struct PaMacCore_DI
78
PaDeviceInfo inheritedDeviceInfo;
82
// PaMacCoreStream - a stream data structure specifically for this implementation
83
typedef struct PaMacCore_S
85
PaUtilStreamRepresentation streamRepresentation;
86
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
87
PaUtilBufferProcessor bufferProcessor;
89
int primeStreamUsingCallback;
91
AudioDeviceID inputDevice;
92
AudioDeviceID outputDevice;
94
// Processing thread management --------------
96
// HANDLE processingThread;
97
// DWORD processingThreadId;
99
char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle
100
int processingThreadPriority;
101
int highThreadPriority;
102
int throttledThreadPriority;
103
unsigned long throttledSleepMsecs;
106
volatile int isActive;
107
volatile int stopProcessing; // stop thread once existing buffers have been returned
108
volatile int abortProcessing; // stop thread immediately
110
// DWORD allBuffersDurationMs; // used to calculate timeouts
114
// Data needed by the CoreAudio callback functions
115
typedef struct PaMacCore_CD
117
PaMacCoreStream *stream;
118
PaStreamCallback *callback;
120
PaUtilConverter *inputConverter;
121
PaUtilConverter *outputConverter;
124
int inputChannelCount;
125
int outputChannelCount;
126
PaSampleFormat inputSampleFormat;
127
PaSampleFormat outputSampleFormat;
128
PaUtilTriangularDitherGenerator *ditherGenerator;
132
// ===== CoreAudio-PortAudio bridge functions =====
133
#pragma mark CoreAudio-PortAudio bridge functions
135
// Maps CoreAudio OSStatus codes to PortAudio PaError codes
136
static PaError conv_err(OSStatus 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;
164
result = paInternalError;
170
/* This function is unused
171
static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate)
173
struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription));
174
streamDescription->mSampleRate = sampleRate;
175
streamDescription->mFormatID = kAudioFormatLinearPCM;
176
streamDescription->mFormatFlags = 0;
177
streamDescription->mFramesPerPacket = 1;
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);
186
streamDescription->mChannelsPerFrame = parameters->channelCount;
189
streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame;
190
streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket;
192
if (parameters->sampleFormat & paFloat32) {
193
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
194
streamDescription->mBitsPerChannel = 32;
196
else if (parameters->sampleFormat & paInt32) {
197
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
198
streamDescription->mBitsPerChannel = 32;
200
else if (parameters->sampleFormat & paInt24) {
201
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
202
streamDescription->mBitsPerChannel = 24;
204
else if (parameters->sampleFormat & paInt16) {
205
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
206
streamDescription->mBitsPerChannel = 16;
208
else if (parameters->sampleFormat & paInt8) {
209
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
210
streamDescription->mBitsPerChannel = 8;
212
else if (parameters->sampleFormat & paInt32) {
213
streamDescription->mBitsPerChannel = 8;
216
return streamDescription;
220
static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime)
222
PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo));
224
timeInfo->inputBufferAdcTime = inputTime->mSampleTime;
225
timeInfo->currentTime = now->mSampleTime;
226
timeInfo->outputBufferDacTime = outputTime->mSampleTime;
231
// ===== support functions =====
232
#pragma mark support functions
234
static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi)
236
if( macCoreHostApi->allocations )
238
PaUtil_FreeAllAllocations( macCoreHostApi->allocations );
239
PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations );
242
PaUtil_FreeMemory( macCoreHostApi );
245
static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput)
248
PaError err = paNoError;
251
AudioBufferList *buflist;
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));
257
for (i = 0; i < buflist->mNumberBuffers; ++i) {
258
numChannels += buflist->mBuffers[i].mNumberChannels;
262
deviceInfo->maxInputChannels = numChannels;
264
deviceInfo->maxOutputChannels = numChannels;
267
propSize = sizeof(UInt32);
268
err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
270
double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
272
deviceInfo->defaultLowInputLatency = secondLatency;
273
deviceInfo->defaultHighInputLatency = secondLatency;
276
deviceInfo->defaultLowOutputLatency = secondLatency;
277
deviceInfo->defaultHighOutputLatency = secondLatency;
281
PaUtil_FreeMemory(buflist);
286
static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex )
288
PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo;
289
deviceInfo->structVersion = 2;
290
deviceInfo->hostApi = hostApiIndex;
292
PaError err = paNoError;
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));
300
deviceInfo->name = name;
304
propSize = sizeof(Float64);
305
err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
307
deviceInfo->defaultSampleRate = sampleRate;
312
err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1);
313
err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0);
318
static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex )
320
PaError result = paNoError;
321
PaUtilHostApiRepresentation *hostApi;
322
PaMacCoreDeviceInfo *deviceInfoArray;
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;
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 )
339
return paInsufficientMemory;
342
// allocate all device info structs in a contiguous block
343
deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory(
344
macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices );
345
if( !deviceInfoArray )
347
return paInsufficientMemory;
350
macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize);
351
AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds);
353
AudioDeviceID defaultInputDevice, defaultOutputDevice;
354
propsize = sizeof(AudioDeviceID);
355
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice);
356
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice);
359
for (i = 0; i < numDevices; ++i) {
360
if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) {
361
hostApi->info.defaultInputDevice = i;
363
if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) {
364
hostApi->info.defaultOutputDevice = i;
366
InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex);
367
hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);
374
static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput)
376
UInt32 propSize = sizeof(AudioStreamBasicDescription);
377
AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize);
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;
389
OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription);
390
PaUtil_FreeMemory(streamDescription);
394
static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount)
396
int frameSpacing, channelSpacing;
397
if (destination->inputSampleFormat & paNonInterleaved) {
399
channelSpacing = destination->inputChannelCount;
402
frameSpacing = destination->inputChannelCount;
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) {
413
inputBuffer = &source->mBuffers[streamNumber];
414
coreAudioBuffer = inputBuffer->mData;
417
destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator);
418
coreAudioBuffer += sizeof(Float32);
419
portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing;
424
static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount)
426
int frameSpacing, channelSpacing;
427
if (source->outputSampleFormat & paNonInterleaved) {
429
channelSpacing = source->outputChannelCount;
432
frameSpacing = source->outputChannelCount;
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) {
443
outputBuffer = &destination->mBuffers[streamNumber];
444
coreAudioBuffer = outputBuffer->mData;
447
source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL);
448
coreAudioBuffer += sizeof(Float32);
449
portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing;
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,
462
PaMacClientData *clientData = (PaMacClientData *)inClientData;
463
PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
465
PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
467
AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
468
unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
470
if (clientData->inputBuffer) {
471
CopyInputData(clientData, inInputData, frameCount);
473
PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
474
if (clientData->outputBuffer) {
475
CopyOutputData(outOutputData, clientData, frameCount);
478
PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
480
if (result == paComplete || result == paAbort) {
481
Pa_StopStream(clientData->stream);
484
PaUtil_FreeMemory( timeInfo );
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,
497
PaMacClientData *clientData = (PaMacClientData *)inClientData;
498
PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
500
PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
502
AudioBuffer const *inputBuffer = &inInputData->mBuffers[0];
503
unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32));
505
CopyInputData(clientData, inInputData, frameCount);
506
PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
508
PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
509
if( result == paComplete || result == paAbort )
510
Pa_StopStream(clientData->stream);
511
PaUtil_FreeMemory( timeInfo );
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,
524
PaMacClientData *clientData = (PaMacClientData *)inClientData;
525
//PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
527
PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
529
AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
530
unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
532
//clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
534
CopyOutputData(outOutputData, clientData, frameCount);
536
PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
540
static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput)
542
PaError result = paNoError;
544
double actualSampleRate;
545
UInt32 propSize = sizeof(double);
546
result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate));
548
result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate));
550
if (result == paNoError && actualSampleRate != sampleRate) {
551
result = paInvalidSampleRate;
557
static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput)
559
PaError result = paNoError;
560
UInt32 preferredFramesPerBuffer = framesPerBuffer;
561
// while (preferredFramesPerBuffer > UINT32_MAX) {
562
// preferredFramesPerBuffer /= 2;
565
UInt32 actualFramesPerBuffer;
566
UInt32 propSize = sizeof(UInt32);
567
result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer));
569
result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer));
571
if (result != paNoError) {
574
else if (actualFramesPerBuffer > framesPerBuffer) {
575
result = paBufferTooSmall;
577
else if (actualFramesPerBuffer < framesPerBuffer) {
578
result = paBufferTooBig;
584
static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput)
586
PaError err = paNoError;
587
err = SetSampleRate(device, sampleRate, isInput);
588
if( err == paNoError )
589
err = SetFramesPerBuffer(device, framesPerBuffer, isInput);
593
// ===== PortAudio functions =====
594
#pragma mark PortAudio functions
599
#endif // __cplusplus
601
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
605
#endif // __cplusplus
607
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
609
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
611
CleanUp(macCoreHostApi);
614
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
615
const PaStreamParameters *inputParameters,
616
const PaStreamParameters *outputParameters,
619
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
620
PaDeviceInfo *deviceInfo;
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;
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;
643
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
645
const PaStreamParameters *inputParameters,
646
const PaStreamParameters *outputParameters,
648
unsigned long framesPerBuffer,
649
PaStreamFlags streamFlags,
650
PaStreamCallback *streamCallback,
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;
661
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
663
? &macCoreHostApi->callbackStreamInterface
664
: &macCoreHostApi->blockingStreamInterface ),
665
streamCallback, userData );
666
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
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);
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);
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);
696
if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) {
697
AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice;
699
AudioDeviceAddIOProc(device, AudioIOProc, clientData);
702
// using different devices for input and output
703
AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData);
704
AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData);
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 )
713
PaError err = paNoError;
714
PaMacCoreStream *stream = (PaMacCoreStream*)s;
716
PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
718
if (stream->inputDevice != kAudioDeviceUnknown) {
719
if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
720
err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc));
723
err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc));
724
err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc));
728
err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc));
735
static PaError StartStream( PaStream *s )
737
PaError err = paNoError;
738
PaMacCoreStream *stream = (PaMacCoreStream*)s;
740
if (stream->inputDevice != kAudioDeviceUnknown) {
741
if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
742
err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc));
745
err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc));
746
err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc));
750
err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc));
753
stream->isActive = 1;
754
stream->isStopped = 0;
758
static PaError AbortStream( PaStream *s )
760
PaError err = paNoError;
761
PaMacCoreStream *stream = (PaMacCoreStream*)s;
763
if (stream->inputDevice != kAudioDeviceUnknown) {
764
if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
765
err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc));
768
err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc));
769
err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc));
773
err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc));
776
stream->isActive = 0;
777
stream->isStopped = 1;
781
static PaError StopStream( PaStream *s )
783
// TODO: this should be nicer than abort
784
return AbortStream(s);
787
static PaError IsStreamStopped( PaStream *s )
789
PaMacCoreStream *stream = (PaMacCoreStream*)s;
791
return stream->isStopped;
795
static PaError IsStreamActive( PaStream *s )
797
PaMacCoreStream *stream = (PaMacCoreStream*)s;
799
return stream->isActive;
803
static PaTime GetStreamTime( PaStream *s )
807
PaMacCoreStream *stream = (PaMacCoreStream*)s;
809
AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp));
810
if (stream->inputDevice != kAudioDeviceUnknown) {
811
err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp);
814
err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp);
817
result = err ? 0 : timeStamp->mSampleTime;
818
PaUtil_FreeMemory(timeStamp);
824
static double GetStreamCpuLoad( PaStream* s )
826
PaMacCoreStream *stream = (PaMacCoreStream*)s;
828
return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
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.
834
static PaError ReadStream( PaStream* s,
836
unsigned long frames )
838
return paInternalError;
842
static PaError WriteStream( PaStream* s,
844
unsigned long frames )
846
return paInternalError;
850
static signed long GetStreamReadAvailable( PaStream* s )
852
return paInternalError;
856
static signed long GetStreamWriteAvailable( PaStream* s )
858
return paInternalError;
861
// HostAPI-specific initialization function
862
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
864
PaError result = paNoError;
865
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) );
866
if( !macCoreHostApi )
868
result = paInsufficientMemory;
872
macCoreHostApi->allocations = PaUtil_CreateAllocationGroup();
873
if( !macCoreHostApi->allocations )
875
result = paInsufficientMemory;
879
*hostApi = &macCoreHostApi->inheritedHostApiRep;
880
(*hostApi)->info.structVersion = 1;
881
(*hostApi)->info.type = paCoreAudio;
882
(*hostApi)->info.name = "CoreAudio";
884
result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex);
885
if (result != paNoError) {
889
// Set up the proper callbacks to this HostApi's functions
890
(*hostApi)->Terminate = Terminate;
891
(*hostApi)->OpenStream = OpenStream;
892
(*hostApi)->IsFormatSupported = IsFormatSupported;
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 );
900
PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream,
901
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
902
GetStreamTime, PaUtil_DummyGetCpuLoad,
903
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
908
if( macCoreHostApi ) {
909
CleanUp(macCoreHostApi);