1 /*
2  * Internal interfaces for PortAudio Apple AUHAL implementation
3  *
4  * PortAudio Portable Real-Time Audio Library
5  * Latest Version at: http://www.portaudio.com
6  *
7  * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
8  * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
9  *
10  * Dominic's code was based on code by Phil Burk, Darren Gibbs,
11  * Gord Peters, Stephane Letz, and Greg Pfiel.
12  *
13  * The following people also deserve acknowledgements:
14  *
15  * Olivier Tristan for feedback and testing
16  * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
17  * interface.
18  *
19  *
20  * Based on the Open Source API proposed by Ross Bencina
21  * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
22  *
23  * Permission is hereby granted, free of charge, to any person obtaining
24  * a copy of this software and associated documentation files
25  * (the "Software"), to deal in the Software without restriction,
26  * including without limitation the rights to use, copy, modify, merge,
27  * publish, distribute, sublicense, and/or sell copies of the Software,
28  * and to permit persons to whom the Software is furnished to do so,
29  * subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be
32  * included in all copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
38  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
39  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
40  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41  */
42 
43 /*
44  * The text above constitutes the entire PortAudio license; however,
45  * the PortAudio community also makes the following non-binding requests:
46  *
47  * Any person wishing to distribute modifications to the Software is
48  * requested to send the modifications to the original developer so that
49  * they can be incorporated into the canonical version. It is also
50  * requested that these non-binding requests be included along with the
51  * license above.
52  */
53 
54 /**
55  @file pa_mac_core
56  @ingroup hostapi_src
57  @author Bjorn Roche
58  @brief AUHAL implementation of PortAudio
59 */
60 
61 #ifndef PA_MAC_CORE_INTERNAL_H__
62 #define PA_MAC_CORE_INTERNAL_H__
63 
64 #include <CoreAudio/CoreAudio.h>
65 #include <CoreServices/CoreServices.h>
66 #include <AudioUnit/AudioUnit.h>
67 #include <AudioToolbox/AudioToolbox.h>
68 
69 #include "portaudio.h"
70 #include "pa_util.h"
71 #include "pa_hostapi.h"
72 #include "pa_stream.h"
73 #include "pa_allocation.h"
74 #include "pa_cpuload.h"
75 #include "pa_process.h"
76 #include "pa_ringbuffer.h"
77 
78 #include "pa_mac_core_blocking.h"
79 
80 /* function prototypes */
81 
82 #ifdef __cplusplus
83 extern "C"
84 {
85 #endif /* __cplusplus */
86 
87 PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
88 
89 #ifdef __cplusplus
90 }
91 #endif /* __cplusplus */
92 
93 #define RING_BUFFER_ADVANCE_DENOMINATOR (4)
94 
95 PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
96 PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
97 signed long GetStreamReadAvailable( PaStream* stream );
98 signed long GetStreamWriteAvailable( PaStream* stream );
99 /* PaMacAUHAL - host api datastructure specific to this implementation */
100 typedef struct
101 {
102     PaUtilHostApiRepresentation inheritedHostApiRep;
103     PaUtilStreamInterface callbackStreamInterface;
104     PaUtilStreamInterface blockingStreamInterface;
105 
106     PaUtilAllocationGroup *allocations;
107 
108     /* implementation specific data goes here */
109     long devCount;
110     AudioDeviceID *devIds; /*array of all audio devices*/
111     AudioDeviceID defaultIn;
112     AudioDeviceID defaultOut;
113 }
114 PaMacAUHAL;
115 
116 typedef struct PaMacCoreDeviceProperties
117 {
118     /* Values in Frames from property queries. */
119     UInt32 safetyOffset;
120     UInt32 bufferFrameSize;
121     // UInt32 streamLatency; // Seems to be the same as deviceLatency!?
122     UInt32 deviceLatency;
123     /* Current device sample rate. May change! */
124     Float64 sampleRate;
125     Float64 samplePeriod; // reciprocal
126 }
127 PaMacCoreDeviceProperties;
128 
129 /* stream data structure specifically for this implementation */
130 typedef struct PaMacCoreStream
131 {
132     PaUtilStreamRepresentation streamRepresentation;
133     PaUtilCpuLoadMeasurer cpuLoadMeasurer;
134     PaUtilBufferProcessor bufferProcessor;
135 
136     /* implementation specific data goes here */
137     bool bufferProcessorIsInitialized;
138     AudioUnit inputUnit;
139     AudioUnit outputUnit;
140     AudioDeviceID inputDevice;
141     AudioDeviceID outputDevice;
142     size_t userInChan;
143     size_t userOutChan;
144     size_t inputFramesPerBuffer;
145     size_t outputFramesPerBuffer;
146     PaMacBlio blio;
147     /* We use this ring buffer when input and out devs are different. */
148     PaUtilRingBuffer inputRingBuffer;
149     /* We may need to do SR conversion on input. */
150     AudioConverterRef inputSRConverter;
151     /* We need to preallocate an inputBuffer for reading data. */
152     AudioBufferList inputAudioBufferList;
153     AudioTimeStamp startTime;
154     /* FIXME: instead of volatile, these should be properly memory barriered */
155     volatile uint32_t xrunFlags; /*PaStreamCallbackFlags*/
156     volatile enum {
157        STOPPED          = 0, /* playback is completely stopped,
158                                 and the user has called StopStream(). */
159        CALLBACK_STOPPED = 1, /* callback has requested stop,
160                                 but user has not yet called StopStream(). */
161        STOPPING         = 2, /* The stream is in the process of closing
162                                 because the user has called StopStream.
163                                 This state is just used internally;
164                                 externally it is indistinguishable from
165                                 ACTIVE.*/
166        ACTIVE           = 3  /* The stream is active and running. */
167     } state;
168     double sampleRate;
169     //these may be different from the stream sample rate due to SR conversion:
170     double outDeviceSampleRate;
171     double inDeviceSampleRate;
172 
173     PaMacCoreDeviceProperties  inputProperties;
174     PaMacCoreDeviceProperties  outputProperties;
175 
176 	/* data updated by main thread and notifications, protected by timingInformationMutex */
177 	int timingInformationMutexIsInitialized;
178 	pthread_mutex_t timingInformationMutex;
179 
180     /* These are written by the PA thread or from CoreAudio callbacks. Protected by the mutex. */
181     Float64 timestampOffsetCombined;
182     Float64 timestampOffsetInputDevice;
183     Float64 timestampOffsetOutputDevice;
184 
185 	/* Offsets in seconds to be applied to Apple timestamps to convert them to PA timestamps.
186      * While the io proc is active, the following values are only accessed and manipulated by the ioproc */
187     Float64 timestampOffsetCombined_ioProcCopy;
188     Float64 timestampOffsetInputDevice_ioProcCopy;
189     Float64 timestampOffsetOutputDevice_ioProcCopy;
190 
191 }
192 PaMacCoreStream;
193 
194 #endif /* PA_MAC_CORE_INTERNAL_H__ */
195