~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}