To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / hostapi / coreaudio / pa_mac_core_old.c @ 162:d43aab368df9

History | View | Annotate | Download (34.4 KB)

1
/*
2
 * $Id$
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
}