summaryrefslogtreecommitdiff
path: root/portaudio/src/hostapi/asio/iasiothiscallresolver.h
blob: 21d53b3206babad3f48165529e100ad53c686f6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// ****************************************************************************
// File:			IASIOThiscallResolver.h
// Description:     The IASIOThiscallResolver class implements the IASIO
//					interface and acts as a proxy to the real IASIO interface by
//                  calling through its vptr table using the thiscall calling
//                  convention. To put it another way, we interpose
//                  IASIOThiscallResolver between ASIO SDK code and the driver.
//                  This is necessary because most non-Microsoft compilers don't
//                  implement the thiscall calling convention used by IASIO.
//
//					iasiothiscallresolver.cpp contains the background of this
//					problem plus a technical description of the vptr
//                  manipulations.
//
//					In order to use this mechanism one simply has to add
//					iasiothiscallresolver.cpp to the list of files to compile
//                  and #include <iasiothiscallresolver.h>
//
//					Note that this #include must come after the other ASIO SDK
//                  #includes, for example:
//
//					#include <windows.h>
//					#include <asiosys.h>
//					#include <asio.h>
//					#include <asiodrivers.h>
//					#include <iasiothiscallresolver.h>
//
//					Actually the important thing is to #include
//                  <iasiothiscallresolver.h> after <asio.h>. We have
//                  incorporated a test to enforce this ordering.
//
//					The code transparently takes care of the interposition by
//                  using macro substitution to intercept calls to ASIOInit()
//                  and ASIOExit(). We save the original ASIO global
//                  "theAsioDriver" in our "that" variable, and then set
//                  "theAsioDriver" to equal our IASIOThiscallResolver instance.
//
// 					Whilst this method of resolving the thiscall problem requires
//					the addition of #include <iasiothiscallresolver.h> to client
//                  code it has the advantage that it does not break the terms
//                  of the ASIO licence by publishing it. We are NOT modifying
//                  any Steinberg code here, we are merely implementing the IASIO
//					interface in the same way that we would need to do if we
//					wished to provide an open source ASIO driver.
//
//					For compilation with MinGW -lole32 needs to be added to the
//                  linker options. For BORLAND, linking with Import32.lib is
//                  sufficient.
//
//					The dependencies are with: CoInitialize, CoUninitialize,
//					CoCreateInstance, CLSIDFromString - used by asiolist.cpp
//					and are required on Windows whether ThiscallResolver is used
//					or not.
//
//					Searching for the above strings in the root library path
//					of your compiler should enable the correct libraries to be
//					identified if they aren't immediately obvious.
//
//                  Note that the current implementation of IASIOThiscallResolver
//                  is not COM compliant - it does not correctly implement the
//                  IUnknown interface. Implementing it is not necessary because
//                  it is not called by parts of the ASIO SDK which call through
//                  theAsioDriver ptr. The IUnknown methods are implemented as
//                  assert(false) to ensure that the code fails if they are
//                  ever called.
// Restrictions:	None. Public Domain & Open Source distribute freely
//					You may use IASIOThiscallResolver commercially as well as
//                  privately.
//					You the user assume the responsibility for the use of the
//					files, binary or text, and there is no guarantee or warranty,
//					expressed or implied, including but not limited to the
//					implied warranties of merchantability and fitness for a
//					particular purpose. You assume all responsibility and agree
//					to hold no entity, copyright holder or distributors liable
//					for any loss of data or inaccurate representations of data
//					as a result of using IASIOThiscallResolver.
// Version:         1.4 Added separate macro CALL_THISCALL_1_DOUBLE from
//                  Andrew Baldwin, and volatile for whole gcc asm blocks,
//                  both for compatibility with newer gcc versions. Cleaned up
//                  Borland asm to use one less register.
//                  1.3 Switched to including assert.h for better compatibility.
//                  Wrapped entire .h and .cpp contents with a check for
//                  _MSC_VER to provide better compatibility with MS compilers.
//                  Changed Singleton implementation to use static instance
//                  instead of freestore allocated instance. Removed ASIOExit
//                  macro as it is no longer needed.
//                  1.2 Removed semicolons from ASIOInit and ASIOExit macros to
//                  allow them to be embedded in expressions (if statements).
//                  Cleaned up some comments. Removed combase.c dependency (it
//                  doesn't compile with BCB anyway) by stubbing IUnknown.
//                  1.1 Incorporated comments from Ross Bencina including things
//					such as changing name from ThiscallResolver to
//					IASIOThiscallResolver, tidying up the constructor, fixing
//					a bug in IASIOThiscallResolver::ASIOExit() and improving
//					portability through the use of conditional compilation
//					1.0 Initial working version.
// Created:			6/09/2003
// Authors:         Fraser Adams
//                  Ross Bencina
//                  Rene G. Ceballos
//                  Martin Fay
//                  Antti Silvast
//                  Andrew Baldwin
//
// ****************************************************************************


#ifndef included_iasiothiscallresolver_h
#define included_iasiothiscallresolver_h

// We only need IASIOThiscallResolver at all if we are on Win32. For other
// platforms we simply bypass the IASIOThiscallResolver definition to allow us
// to be safely #include'd whatever the platform to keep client code portable
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64)


// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
// is not used.
#if !defined(_MSC_VER)


// The following is in order to ensure that this header is only included after
// the other ASIO headers (except for the case of iasiothiscallresolver.cpp).
// We need to do this because IASIOThiscallResolver works by eclipsing the
// original definition of ASIOInit() with a macro (see below).
#if !defined(iasiothiscallresolver_sourcefile)
	#if !defined(__ASIO_H)
	#error iasiothiscallresolver.h must be included AFTER asio.h
	#endif
#endif

#include <windows.h>
#include <asiodrvr.h> /* From ASIO SDK */


class IASIOThiscallResolver : public IASIO {
private:
	IASIO* that_; // Points to the real IASIO

	static IASIOThiscallResolver instance; // Singleton instance

	// Constructors - declared private so construction is limited to
    // our Singleton instance
    IASIOThiscallResolver();
	IASIOThiscallResolver(IASIO* that);
public:

    // Methods from the IUnknown interface. We don't fully implement IUnknown
    // because the ASIO SDK never calls these methods through theAsioDriver ptr.
    // These methods are implemented as assert(false).
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
    virtual ULONG STDMETHODCALLTYPE AddRef();
    virtual ULONG STDMETHODCALLTYPE Release();

    // Methods from the IASIO interface, implemented as forwarning calls to that.
	virtual ASIOBool init(void *sysHandle);
	virtual void getDriverName(char *name);
	virtual long getDriverVersion();
	virtual void getErrorMessage(char *string);
	virtual ASIOError start();
	virtual ASIOError stop();
	virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
	virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
	virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
	virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
	virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
	virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
	virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
	virtual ASIOError setClockSource(long reference);
	virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
	virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
	virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);
	virtual ASIOError disposeBuffers();
	virtual ASIOError controlPanel();
	virtual ASIOError future(long selector,void *opt);
	virtual ASIOError outputReady();

    // Class method, see ASIOInit() macro below.
    static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit
};


// Replace calls to ASIOInit with our interposing version.
// This macro enables us to perform thiscall resolution simply by #including
// <iasiothiscallresolver.h> after the asio #includes (this file _must_ be
// included _after_ the asio #includes)

#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name))


#endif /* !defined(_MSC_VER) */

#endif /* Win32 */

#endif /* included_iasiothiscallresolver_h */