PortAudio 2.0
iasiothiscallresolver.h
Go to the documentation of this file.
1// ****************************************************************************
2// File: IASIOThiscallResolver.h
3// Description: The IASIOThiscallResolver class implements the IASIO
4// interface and acts as a proxy to the real IASIO interface by
5// calling through its vptr table using the thiscall calling
6// convention. To put it another way, we interpose
7// IASIOThiscallResolver between ASIO SDK code and the driver.
8// This is necessary because most non-Microsoft compilers don't
9// implement the thiscall calling convention used by IASIO.
10//
11// iasiothiscallresolver.cpp contains the background of this
12// problem plus a technical description of the vptr
13// manipulations.
14//
15// In order to use this mechanism one simply has to add
16// iasiothiscallresolver.cpp to the list of files to compile
17// and #include <iasiothiscallresolver.h>
18//
19// Note that this #include must come after the other ASIO SDK
20// #includes, for example:
21//
22// #include <windows.h>
23// #include <asiosys.h>
24// #include <asio.h>
25// #include <asiodrivers.h>
26// #include <iasiothiscallresolver.h>
27//
28// Actually the important thing is to #include
29// <iasiothiscallresolver.h> after <asio.h>. We have
30// incorporated a test to enforce this ordering.
31//
32// The code transparently takes care of the interposition by
33// using macro substitution to intercept calls to ASIOInit()
34// and ASIOExit(). We save the original ASIO global
35// "theAsioDriver" in our "that" variable, and then set
36// "theAsioDriver" to equal our IASIOThiscallResolver instance.
37//
38// Whilst this method of resolving the thiscall problem requires
39// the addition of #include <iasiothiscallresolver.h> to client
40// code it has the advantage that it does not break the terms
41// of the ASIO licence by publishing it. We are NOT modifying
42// any Steinberg code here, we are merely implementing the IASIO
43// interface in the same way that we would need to do if we
44// wished to provide an open source ASIO driver.
45//
46// For compilation with MinGW -lole32 needs to be added to the
47// linker options. For BORLAND, linking with Import32.lib is
48// sufficient.
49//
50// The dependencies are with: CoInitialize, CoUninitialize,
51// CoCreateInstance, CLSIDFromString - used by asiolist.cpp
52// and are required on Windows whether ThiscallResolver is used
53// or not.
54//
55// Searching for the above strings in the root library path
56// of your compiler should enable the correct libraries to be
57// identified if they aren't immediately obvious.
58//
59// Note that the current implementation of IASIOThiscallResolver
60// is not COM compliant - it does not correctly implement the
61// IUnknown interface. Implementing it is not necessary because
62// it is not called by parts of the ASIO SDK which call through
63// theAsioDriver ptr. The IUnknown methods are implemented as
64// assert(false) to ensure that the code fails if they are
65// ever called.
66// Restrictions: None. Public Domain & Open Source distribute freely
67// You may use IASIOThiscallResolver commercially as well as
68// privately.
69// You the user assume the responsibility for the use of the
70// files, binary or text, and there is no guarantee or warranty,
71// expressed or implied, including but not limited to the
72// implied warranties of merchantability and fitness for a
73// particular purpose. You assume all responsibility and agree
74// to hold no entity, copyright holder or distributors liable
75// for any loss of data or inaccurate representations of data
76// as a result of using IASIOThiscallResolver.
77// Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from
78// Andrew Baldwin, and volatile for whole gcc asm blocks,
79// both for compatibility with newer gcc versions. Cleaned up
80// Borland asm to use one less register.
81// 1.3 Switched to including assert.h for better compatibility.
82// Wrapped entire .h and .cpp contents with a check for
83// _MSC_VER to provide better compatibility with MS compilers.
84// Changed Singleton implementation to use static instance
85// instead of freestore allocated instance. Removed ASIOExit
86// macro as it is no longer needed.
87// 1.2 Removed semicolons from ASIOInit and ASIOExit macros to
88// allow them to be embedded in expressions (if statements).
89// Cleaned up some comments. Removed combase.c dependency (it
90// doesn't compile with BCB anyway) by stubbing IUnknown.
91// 1.1 Incorporated comments from Ross Bencina including things
92// such as changing name from ThiscallResolver to
93// IASIOThiscallResolver, tidying up the constructor, fixing
94// a bug in IASIOThiscallResolver::ASIOExit() and improving
95// portability through the use of conditional compilation
96// 1.0 Initial working version.
97// Created: 6/09/2003
98// Authors: Fraser Adams
99// Ross Bencina
100// Rene G. Ceballos
101// Martin Fay
102// Antti Silvast
103// Andrew Baldwin
104//
105// ****************************************************************************
106
107
108#ifndef included_iasiothiscallresolver_h
109#define included_iasiothiscallresolver_h
110
111// We only need IASIOThiscallResolver at all if we are on Win32. For other
112// platforms we simply bypass the IASIOThiscallResolver definition to allow us
113// to be safely #include'd whatever the platform to keep client code portable
114#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64)
115
116
117// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
118// is not used.
119#if !defined(_MSC_VER)
120
121
122// The following is in order to ensure that this header is only included after
123// the other ASIO headers (except for the case of iasiothiscallresolver.cpp).
124// We need to do this because IASIOThiscallResolver works by eclipsing the
125// original definition of ASIOInit() with a macro (see below).
126#if !defined(iasiothiscallresolver_sourcefile)
127 #if !defined(__ASIO_H)
128 #error iasiothiscallresolver.h must be included AFTER asio.h
129 #endif
130#endif
131
132#include <windows.h>
133#include <asiodrvr.h> /* From ASIO SDK */
134
135
136class IASIOThiscallResolver : public IASIO {
137private:
138 IASIO* that_; // Points to the real IASIO
139
140 static IASIOThiscallResolver instance; // Singleton instance
141
142 // Constructors - declared private so construction is limited to
143 // our Singleton instance
144 IASIOThiscallResolver();
145 IASIOThiscallResolver(IASIO* that);
146public:
147
148 // Methods from the IUnknown interface. We don't fully implement IUnknown
149 // because the ASIO SDK never calls these methods through theAsioDriver ptr.
150 // These methods are implemented as assert(false).
151 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
152 virtual ULONG STDMETHODCALLTYPE AddRef();
153 virtual ULONG STDMETHODCALLTYPE Release();
154
155 // Methods from the IASIO interface, implemented as forwarning calls to that.
156 virtual ASIOBool init(void *sysHandle);
157 virtual void getDriverName(char *name);
158 virtual long getDriverVersion();
159 virtual void getErrorMessage(char *string);
160 virtual ASIOError start();
161 virtual ASIOError stop();
162 virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
163 virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
164 virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
165 virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
166 virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
167 virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
168 virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
169 virtual ASIOError setClockSource(long reference);
170 virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
171 virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
172 virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);
173 virtual ASIOError disposeBuffers();
174 virtual ASIOError controlPanel();
175 virtual ASIOError future(long selector,void *opt);
176 virtual ASIOError outputReady();
177
178 // Class method, see ASIOInit() macro below.
179 static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit
180};
181
182
183// Replace calls to ASIOInit with our interposing version.
184// This macro enables us to perform thiscall resolution simply by #including
185// <iasiothiscallresolver.h> after the asio #includes (this file _must_ be
186// included _after_ the asio #includes)
187
188#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name))
189
190
191#endif /* !defined(_MSC_VER) */
192
193#endif /* Win32 */
194
195#endif /* included_iasiothiscallresolver_h */
196
197