~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): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

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
 
}