~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/wasapi/pa_win_wasapi.cpp

  • 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
 * Portable Audio I/O Library WASAPI implementation
 
3
 * Copyright (c) 2006-2007 David Viens
 
4
 *
 
5
 * Based on the Open Source API proposed by Ross Bencina
 
6
 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
 
7
 *
 
8
 * Permission is hereby granted, free of charge, to any person obtaining
 
9
 * a copy of this software and associated documentation files
 
10
 * (the "Software"), to deal in the Software without restriction,
 
11
 * including without limitation the rights to use, copy, modify, merge,
 
12
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
13
 * and to permit persons to whom the Software is furnished to do so,
 
14
 * subject to the following conditions:
 
15
 *
 
16
 * The above copyright notice and this permission notice shall be
 
17
 * included in all copies or substantial portions of the Software.
 
18
 *
 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
20
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
21
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
22
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 
23
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 
24
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
25
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
26
 */
 
27
 
 
28
/*
 
29
 * The text above constitutes the entire PortAudio license; however, 
 
30
 * the PortAudio community also makes the following non-binding requests:
 
31
 *
 
32
 * Any person wishing to distribute modifications to the Software is
 
33
 * requested to send the modifications to the original developer so that
 
34
 * they can be incorporated into the canonical version. It is also 
 
35
 * requested that these non-binding requests be included along with the 
 
36
 * license above.
 
37
 */
 
38
 
 
39
/** @file
 
40
 @ingroup hostapi_src
 
41
 @brief WASAPI implementation of support for a host API.
 
42
 
 
43
 @note pa_wasapi currently requires VC 2005, and the latest Vista SDK
 
44
*/
 
45
 
 
46
#if _MSC_VER >= 1400
 
47
#include <windows.h>
 
48
#include <MMReg.h>  //must be before other Wasapi headers
 
49
#include <strsafe.h>
 
50
#include <mmdeviceapi.h>
 
51
#include <Avrt.h>
 
52
#include <audioclient.h>
 
53
#include <Endpointvolume.h>
 
54
 
 
55
#include <KsMedia.h>
 
56
#include <functiondiscoverykeys.h>  // PKEY_Device_FriendlyName
 
57
#endif
 
58
 
 
59
#include <process.h>
 
60
 
 
61
#include "pa_util.h"
 
62
#include "pa_allocation.h"
 
63
#include "pa_hostapi.h"
 
64
#include "pa_stream.h"
 
65
#include "pa_cpuload.h"
 
66
#include "pa_process.h"
 
67
#include "pa_debugprint.h"
 
68
 
 
69
 
 
70
/*
 
71
  davidv : work in progress. try using with 48000 , then 44100
 
72
  and shared mode FIRST.
 
73
 */
 
74
 
 
75
#define PORTAUDIO_SHAREMODE     AUDCLNT_SHAREMODE_SHARED
 
76
//#define PORTAUDIO_SHAREMODE   AUDCLNT_SHAREMODE_EXCLUSIVE
 
77
 
 
78
/* use CreateThread for CYGWIN, _beginthreadex for all others */
 
79
#ifndef __CYGWIN__
 
80
#define CREATE_THREAD (HANDLE) _beginthreadex(NULL, 0, (unsigned (_stdcall *)(void *))ProcThread, (LPVOID) stream, 0, (unsigned *)&stream->dwThreadId)
 
81
#else
 
82
#define CREATE_THREAD CreateThread(NULL, 0, ProcThread, (LPVOID) stream, 0, &stream->dwThreadId)
 
83
#endif
 
84
 
 
85
/* prototypes for functions declared in this file */
 
86
 
 
87
#ifdef __cplusplus
 
88
extern "C"
 
89
{
 
90
#endif /* __cplusplus */
 
91
 
 
92
PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
 
93
 
 
94
#ifdef __cplusplus
 
95
}
 
96
#endif /* __cplusplus */
 
97
 
 
98
 
 
99
 
 
100
 
 
101
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
 
102
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
 
103
                                  const PaStreamParameters *inputParameters,
 
104
                                  const PaStreamParameters *outputParameters,
 
105
                                  double sampleRate );
 
106
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 
107
                           PaStream** s,
 
108
                           const PaStreamParameters *inputParameters,
 
109
                           const PaStreamParameters *outputParameters,
 
110
                           double sampleRate,
 
111
                           unsigned long framesPerBuffer,
 
112
                           PaStreamFlags streamFlags,
 
113
                           PaStreamCallback *streamCallback,
 
114
                           void *userData );
 
115
static PaError CloseStream( PaStream* stream );
 
116
static PaError StartStream( PaStream *stream );
 
117
static PaError StopStream( PaStream *stream );
 
118
static PaError AbortStream( PaStream *stream );
 
119
static PaError IsStreamStopped( PaStream *s );
 
120
static PaError IsStreamActive( PaStream *stream );
 
121
static PaTime GetStreamTime( PaStream *stream );
 
122
static double GetStreamCpuLoad( PaStream* stream );
 
123
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
 
124
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
 
125
static signed long GetStreamReadAvailable( PaStream* stream );
 
126
static signed long GetStreamWriteAvailable( PaStream* stream );
 
127
 
 
128
 
 
129
/* IMPLEMENT ME: a macro like the following one should be used for reporting
 
130
 host errors */
 
131
#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
 
132
    PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
 
133
 
 
134
/* PaWinWasapiHostApiRepresentation - host api datastructure specific to this implementation */
 
135
 
 
136
 
 
137
 
 
138
//dummy entry point for other compilers and sdks
 
139
//currently built using RC1 SDK (5600)
 
140
#if _MSC_VER < 1400
 
141
 
 
142
PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){
 
143
    return paNoError;
 
144
}
 
145
 
 
146
#else
 
147
 
 
148
 
 
149
 
 
150
 
 
151
#define MAX_STR_LEN 512
 
152
 
 
153
/*
 
154
 These are fields that can be gathered from IDevice
 
155
 and IAudioDevice PRIOR to Initialize, and done in first pass
 
156
 i assume that neither of these will cause the Driver to "load",
 
157
 but again, who knows how they implement their stuff
 
158
 */
 
159
typedef struct PaWinWasapiDeviceInfo
 
160
{
 
161
    //hmm is it wise to keep a reference until Terminate?
 
162
    //TODO Check if that interface requires the driver to be loaded!
 
163
    IMMDevice * device;
 
164
 
 
165
    //Fields filled from IDevice
 
166
    //from GetId
 
167
    WCHAR szDeviceID[MAX_STR_LEN];
 
168
    //from GetState
 
169
    DWORD state;
 
170
 
 
171
    //Fields filled from IMMEndpoint'sGetDataFlow
 
172
    EDataFlow  flow;
 
173
 
 
174
    //Fields filled from IAudioDevice (_prior_ to Initialize)
 
175
    //from GetDevicePeriod(
 
176
    REFERENCE_TIME  DefaultDevicePeriod;
 
177
    REFERENCE_TIME  MinimumDevicePeriod;
 
178
    //from GetMixFormat
 
179
    WAVEFORMATEX   *MixFormat;//needs to be CoTaskMemFree'd after use!
 
180
 
 
181
} PaWinWasapiDeviceInfo;
 
182
 
 
183
 
 
184
typedef struct
 
185
{
 
186
    PaUtilHostApiRepresentation inheritedHostApiRep;
 
187
    PaUtilStreamInterface callbackStreamInterface;
 
188
    PaUtilStreamInterface blockingStreamInterface;
 
189
 
 
190
    PaUtilAllocationGroup *allocations;
 
191
 
 
192
    /* implementation specific data goes here */
 
193
 
 
194
    //in case we later need the synch
 
195
    IMMDeviceEnumerator * enumerator;
 
196
 
 
197
    //this is the REAL number of devices, whether they are usefull to PA or not!
 
198
    UINT deviceCount;
 
199
 
 
200
    WCHAR defaultRenderer [MAX_STR_LEN];
 
201
    WCHAR defaultCapturer [MAX_STR_LEN];
 
202
 
 
203
    PaWinWasapiDeviceInfo   *devInfo;
 
204
}PaWinWasapiHostApiRepresentation;
 
205
 
 
206
 
 
207
/* PaWinWasapiStream - a stream data structure specifically for this implementation */
 
208
 
 
209
typedef struct PaWinWasapiSubStream{
 
210
    IAudioClient        *client;
 
211
    WAVEFORMATEXTENSIBLE wavex;
 
212
    UINT32               bufferSize;
 
213
    REFERENCE_TIME       latency;
 
214
    REFERENCE_TIME       period;
 
215
    unsigned long framesPerHostCallback; /* just an example */
 
216
}PaWinWasapiSubStream;
 
217
 
 
218
typedef struct PaWinWasapiStream
 
219
{ /* IMPLEMENT ME: rename this */
 
220
    PaUtilStreamRepresentation streamRepresentation;
 
221
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
 
222
    PaUtilBufferProcessor bufferProcessor;
 
223
 
 
224
    /* IMPLEMENT ME:
 
225
            - implementation specific data goes here
 
226
    */
 
227
 
 
228
 
 
229
    //input
 
230
        PaWinWasapiSubStream in;
 
231
    IAudioCaptureClient *cclient;
 
232
    IAudioEndpointVolume *inVol;
 
233
        //output
 
234
        PaWinWasapiSubStream out;
 
235
    IAudioRenderClient  *rclient;
 
236
        IAudioEndpointVolume *outVol;
 
237
 
 
238
    bool running;
 
239
    bool closeRequest;
 
240
 
 
241
    DWORD dwThreadId;
 
242
    HANDLE hThread;
 
243
        HANDLE hNotificationEvent; 
 
244
 
 
245
    GUID  session;
 
246
 
 
247
}PaWinWasapiStream;
 
248
 
 
249
#define PRINT(x) PA_DEBUG(x);
 
250
 
 
251
void
 
252
logAUDCLNT_E(HRESULT res){
 
253
 
 
254
    char *text = 0;
 
255
    switch(res){
 
256
        case S_OK: return; break;
 
257
        case E_POINTER                              :text ="E_POINTER"; break;
 
258
        case E_INVALIDARG                           :text ="E_INVALIDARG"; break;
 
259
 
 
260
        case AUDCLNT_E_NOT_INITIALIZED              :text ="AUDCLNT_E_NOT_INITIALIZED"; break;
 
261
        case AUDCLNT_E_ALREADY_INITIALIZED          :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break;
 
262
        case AUDCLNT_E_WRONG_ENDPOINT_TYPE          :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break;
 
263
        case AUDCLNT_E_DEVICE_INVALIDATED           :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break;
 
264
        case AUDCLNT_E_NOT_STOPPED                  :text ="AUDCLNT_E_NOT_STOPPED"; break;
 
265
        case AUDCLNT_E_BUFFER_TOO_LARGE             :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break;
 
266
        case AUDCLNT_E_OUT_OF_ORDER                 :text ="AUDCLNT_E_OUT_OF_ORDER"; break;
 
267
        case AUDCLNT_E_UNSUPPORTED_FORMAT           :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break;
 
268
        case AUDCLNT_E_INVALID_SIZE                 :text ="AUDCLNT_E_INVALID_SIZE"; break;
 
269
        case AUDCLNT_E_DEVICE_IN_USE                :text ="AUDCLNT_E_DEVICE_IN_USE"; break;
 
270
        case AUDCLNT_E_BUFFER_OPERATION_PENDING     :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break;
 
271
        case AUDCLNT_E_THREAD_NOT_REGISTERED        :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break;      
 
272
                case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED   :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break;
 
273
        case AUDCLNT_E_ENDPOINT_CREATE_FAILED       :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break;
 
274
        case AUDCLNT_E_SERVICE_NOT_RUNNING          :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break;
 
275
     //  case AUDCLNT_E_CPUUSAGE_EXCEEDED            :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break;
 
276
     //Header error?
 
277
        case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED     :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break;
 
278
        case AUDCLNT_E_EXCLUSIVE_MODE_ONLY          :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break;
 
279
        case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break;
 
280
        case AUDCLNT_E_EVENTHANDLE_NOT_SET          :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break;
 
281
        case AUDCLNT_E_INCORRECT_BUFFER_SIZE        :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break;
 
282
        case AUDCLNT_E_BUFFER_SIZE_ERROR            :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break;
 
283
        case AUDCLNT_S_BUFFER_EMPTY                 :text ="AUDCLNT_S_BUFFER_EMPTY"; break;
 
284
        case AUDCLNT_S_THREAD_ALREADY_REGISTERED    :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break;
 
285
        default:
 
286
            text =" dunno!";
 
287
            return ;
 
288
        break;
 
289
 
 
290
    }
 
291
    PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n",res,text));
 
292
}
 
293
 
 
294
inline double
 
295
nano100ToMillis(const REFERENCE_TIME &ref){
 
296
    //  1 nano = 0.000000001 seconds
 
297
    //100 nano = 0.0000001   seconds
 
298
    //100 nano = 0.0001   milliseconds
 
299
    return ((double)ref)*0.0001;
 
300
}
 
301
 
 
302
inline double
 
303
nano100ToSeconds(const REFERENCE_TIME &ref){
 
304
    //  1 nano = 0.000000001 seconds
 
305
    //100 nano = 0.0000001   seconds
 
306
    //100 nano = 0.0001   milliseconds
 
307
    return ((double)ref)*0.0000001;
 
308
}
 
309
 
 
310
#ifndef IF_FAILED_JUMP
 
311
#define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label;
 
312
#endif
 
313
 
 
314
 
 
315
 
 
316
//AVRT is the new "multimedia schedulling stuff"
 
317
 
 
318
typedef BOOL   (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER);
 
319
typedef BOOL   (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE);
 
320
typedef BOOL   (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE);
 
321
typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics)  (LPCTSTR,LPDWORD);
 
322
typedef BOOL   (WINAPI *FAvSetMmThreadPriority)         (HANDLE,AVRT_PRIORITY);
 
323
 
 
324
HMODULE  hDInputDLL = 0;
 
325
FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup=0;
 
326
FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup=0;
 
327
FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup=0;
 
328
FAvSetMmThreadCharacteristics  pAvSetMmThreadCharacteristics=0;
 
329
FAvSetMmThreadPriority         pAvSetMmThreadPriority=0;
 
330
 
 
331
 
 
332
 
 
333
#define setupPTR(fun, type, name)  {                                                        \
 
334
                                        fun = (type) GetProcAddress(hDInputDLL,name);       \
 
335
                                        if(fun == NULL) {                                   \
 
336
                                            PRINT(("GetProcAddr failed for %s" ,name));     \
 
337
                                            return false;                                   \
 
338
                                        }                                                   \
 
339
                                    }                                                       \
 
340
 
 
341
bool
 
342
setupAVRT(){
 
343
 
 
344
    hDInputDLL = LoadLibraryA("avrt.dll");
 
345
    if(hDInputDLL == NULL)
 
346
        return false;
 
347
 
 
348
    setupPTR(pAvRtCreateThreadOrderingGroup, FAvRtCreateThreadOrderingGroup, "AvRtCreateThreadOrderingGroup");
 
349
    setupPTR(pAvRtDeleteThreadOrderingGroup, FAvRtDeleteThreadOrderingGroup, "AvRtDeleteThreadOrderingGroup");
 
350
    setupPTR(pAvRtWaitOnThreadOrderingGroup, FAvRtWaitOnThreadOrderingGroup, "AvRtWaitOnThreadOrderingGroup");
 
351
    setupPTR(pAvSetMmThreadCharacteristics,  FAvSetMmThreadCharacteristics,  "AvSetMmThreadCharacteristicsA");
 
352
    setupPTR(pAvSetMmThreadPriority,         FAvSetMmThreadPriority,         "AvSetMmThreadPriority");
 
353
 
 
354
    return true;
 
355
}
 
356
 
 
357
 
 
358
 
 
359
PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
 
360
{
 
361
    if (!setupAVRT()){
 
362
        PRINT(("Windows WASAPI : No AVRT! (not VISTA?)"));
 
363
        return paNoError;
 
364
    }
 
365
 
 
366
    CoInitialize(NULL);
 
367
 
 
368
    PaError result = paNoError;
 
369
    PaWinWasapiHostApiRepresentation *paWasapi;
 
370
    PaDeviceInfo *deviceInfoArray;
 
371
 
 
372
    paWasapi = (PaWinWasapiHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWasapiHostApiRepresentation) );
 
373
    if( !paWasapi ){
 
374
        result = paInsufficientMemory;
 
375
        goto error;
 
376
    }
 
377
 
 
378
    paWasapi->allocations = PaUtil_CreateAllocationGroup();
 
379
    if( !paWasapi->allocations ){
 
380
        result = paInsufficientMemory;
 
381
        goto error;
 
382
    }
 
383
 
 
384
    *hostApi = &paWasapi->inheritedHostApiRep;
 
385
    (*hostApi)->info.structVersion = 1;
 
386
    (*hostApi)->info.type = paWASAPI;
 
387
    (*hostApi)->info.name = "Windows WASAPI";
 
388
    (*hostApi)->info.deviceCount = 0;   //so far, we must investigate each
 
389
    (*hostApi)->info.defaultInputDevice  = paNoDevice;  /* IMPLEMENT ME */
 
390
    (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
 
391
 
 
392
 
 
393
    HRESULT hResult = S_OK;
 
394
    IMMDeviceCollection* spEndpoints=0;
 
395
    paWasapi->enumerator = 0;
 
396
 
 
397
    hResult = CoCreateInstance(
 
398
             __uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER,
 
399
             __uuidof(IMMDeviceEnumerator),
 
400
             (void**)&paWasapi->enumerator);
 
401
 
 
402
    IF_FAILED_JUMP(hResult, error);
 
403
 
 
404
    //getting default device ids in the eMultimedia "role"
 
405
    {
 
406
        {
 
407
            IMMDevice* defaultRenderer=0;
 
408
            hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer);
 
409
            IF_FAILED_JUMP(hResult, error);
 
410
            WCHAR* pszDeviceId = NULL;
 
411
            hResult = defaultRenderer->GetId(&pszDeviceId);
 
412
            IF_FAILED_JUMP(hResult, error);
 
413
            StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId);
 
414
            CoTaskMemFree(pszDeviceId);
 
415
            defaultRenderer->Release();
 
416
        }
 
417
 
 
418
        {
 
419
            IMMDevice* defaultCapturer=0;
 
420
            hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer);
 
421
            IF_FAILED_JUMP(hResult, error);
 
422
            WCHAR* pszDeviceId = NULL;
 
423
            hResult = defaultCapturer->GetId(&pszDeviceId);
 
424
            IF_FAILED_JUMP(hResult, error);
 
425
            StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId);
 
426
            CoTaskMemFree(pszDeviceId);
 
427
            defaultCapturer->Release();
 
428
        }
 
429
    }
 
430
 
 
431
 
 
432
    hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints);
 
433
    IF_FAILED_JUMP(hResult, error);
 
434
 
 
435
    hResult = spEndpoints->GetCount(&paWasapi->deviceCount);
 
436
    IF_FAILED_JUMP(hResult, error);
 
437
 
 
438
    paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount];
 
439
    {
 
440
        for (size_t step=0;step<paWasapi->deviceCount;++step)
 
441
            memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo));
 
442
    }
 
443
 
 
444
 
 
445
 
 
446
    if( paWasapi->deviceCount > 0 )
 
447
    {
 
448
        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
 
449
                paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount );
 
450
        if( !(*hostApi)->deviceInfos ){
 
451
            result = paInsufficientMemory;
 
452
            goto error;
 
453
        }
 
454
 
 
455
        /* allocate all device info structs in a contiguous block */
 
456
        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
 
457
                paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount );
 
458
        if( !deviceInfoArray ){
 
459
            result = paInsufficientMemory;
 
460
            goto error;
 
461
        }
 
462
 
 
463
        for( UINT i=0; i < paWasapi->deviceCount; ++i ){
 
464
 
 
465
                        PA_DEBUG(("i:%d\n",i));
 
466
            PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
 
467
            deviceInfo->structVersion = 2;
 
468
            deviceInfo->hostApi = hostApiIndex;
 
469
 
 
470
            hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device);
 
471
            IF_FAILED_JUMP(hResult, error);
 
472
 
 
473
            //getting ID
 
474
            {
 
475
                WCHAR* pszDeviceId = NULL;
 
476
                hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId);
 
477
                IF_FAILED_JUMP(hResult, error);
 
478
                StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId);
 
479
                CoTaskMemFree(pszDeviceId);
 
480
 
 
481
                if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){
 
482
                    //we found the default input!
 
483
                    (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
 
484
                }
 
485
                if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){
 
486
                    //we found the default output!
 
487
                    (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
 
488
                }
 
489
            }
 
490
 
 
491
            DWORD state=0;
 
492
            hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state);
 
493
            IF_FAILED_JUMP(hResult, error);
 
494
 
 
495
            if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){
 
496
                PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state));
 
497
                //spDevice->Release();
 
498
                //continue;
 
499
            }
 
500
 
 
501
            {
 
502
                IPropertyStore* spProperties;
 
503
                hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties);
 
504
                IF_FAILED_JUMP(hResult, error);
 
505
 
 
506
                //getting "Friendly" Name
 
507
                {
 
508
                    PROPVARIANT value;
 
509
                    PropVariantInit(&value);
 
510
                    hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value);
 
511
                    IF_FAILED_JUMP(hResult, error);
 
512
                    deviceInfo->name = 0;
 
513
                    char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 );
 
514
                    if( !deviceName ){
 
515
                        result = paInsufficientMemory;
 
516
                        goto error;
 
517
                    }
 
518
                                        if (value.pwszVal)
 
519
                                                wcstombs(deviceName,   value.pwszVal,MAX_STR_LEN-1); //todo proper size 
 
520
                                        else{
 
521
                                                _snprintf_s(deviceName,MAX_STR_LEN-1,MAX_STR_LEN-1,"baddev%d",i);
 
522
                                        }
 
523
 
 
524
                    deviceInfo->name = deviceName;
 
525
                    PropVariantClear(&value);
 
526
                }
 
527
 
 
528
#if 0
 
529
                DWORD numProps = 0;
 
530
                hResult = spProperties->GetCount(&numProps);
 
531
                IF_FAILED_JUMP(hResult, error);
 
532
                {
 
533
                    for (DWORD i=0;i<numProps;++i){
 
534
                        PROPERTYKEY pkey;
 
535
                        hResult = spProperties->GetAt(i,&pkey);
 
536
 
 
537
                        PROPVARIANT value;
 
538
                        PropVariantInit(&value);
 
539
                        hResult = spProperties->GetValue(pkey, &value);
 
540
 
 
541
                        switch(value.vt){
 
542
                            case 11:
 
543
                                PRINT(("property*%u*\n",value.ulVal));
 
544
                            break;
 
545
                            case 19:
 
546
                                PRINT(("property*%d*\n",value.boolVal));
 
547
                            break;
 
548
                            case 31:
 
549
                            {
 
550
                                char temp[512];
 
551
                                wcstombs(temp,    value.pwszVal,MAX_STR_LEN-1);
 
552
                                PRINT(("property*%s*\n",temp));
 
553
                            }
 
554
                            break;
 
555
                            default:break;
 
556
                        }
 
557
 
 
558
                        PropVariantClear(&value);
 
559
                    }
 
560
                }
 
561
#endif
 
562
 
 
563
                /*  These look interresting... but they are undocumented
 
564
                PKEY_AudioEndpoint_FormFactor
 
565
                PKEY_AudioEndpoint_ControlPanelPageProvider
 
566
                PKEY_AudioEndpoint_Association
 
567
                PKEY_AudioEndpoint_PhysicalSpeakerConfig
 
568
                PKEY_AudioEngine_DeviceFormat
 
569
                */
 
570
                spProperties->Release();
 
571
            }
 
572
 
 
573
 
 
574
            //getting the Endpoint data
 
575
            {
 
576
                IMMEndpoint *endpoint=0;
 
577
                hResult = paWasapi->devInfo[i].device->QueryInterface(__uuidof(IMMEndpoint),(void **)&endpoint);
 
578
                if (SUCCEEDED(hResult)){
 
579
                    hResult = endpoint->GetDataFlow(&paWasapi->devInfo[i].flow);
 
580
                    endpoint->Release();
 
581
                }
 
582
            }
 
583
 
 
584
            //Getting a temporary IAudioDevice for more fields
 
585
            //we make sure NOT to call Initialize yet!
 
586
            {
 
587
                IAudioClient *myClient=0;
 
588
 
 
589
                hResult = paWasapi->devInfo[i].device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
 
590
                IF_FAILED_JUMP(hResult, error);
 
591
 
 
592
                hResult = myClient->GetDevicePeriod(
 
593
                    &paWasapi->devInfo[i].DefaultDevicePeriod,
 
594
                    &paWasapi->devInfo[i].MinimumDevicePeriod);
 
595
                IF_FAILED_JUMP(hResult, error);
 
596
 
 
597
                hResult = myClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat);
 
598
 
 
599
                                if (hResult != S_OK){
 
600
                                        /*davidv: this happened with my hardware, previously for that same device in DirectSound:
 
601
                                          Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f} 
 
602
                                          so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat*/
 
603
                                        logAUDCLNT_E(hResult);
 
604
                                        goto error;
 
605
                                }
 
606
 
 
607
                myClient->Release();
 
608
            }
 
609
 
 
610
            //we can now fill in portaudio device data
 
611
            deviceInfo->maxInputChannels  = 0;  //for now
 
612
            deviceInfo->maxOutputChannels = 0;  //for now
 
613
 
 
614
            switch(paWasapi->devInfo[i].flow){
 
615
                case eRender:
 
616
                    //hum not exaclty maximum, more like "default"
 
617
                    deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat->nChannels;
 
618
 
 
619
                    deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
 
620
                    deviceInfo->defaultLowOutputLatency  = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
 
621
                break;
 
622
                case eCapture:
 
623
                    //hum not exaclty maximum, more like "default"
 
624
                    deviceInfo->maxInputChannels  = paWasapi->devInfo[i].MixFormat->nChannels;
 
625
 
 
626
                    deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
 
627
                    deviceInfo->defaultLowInputLatency  = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
 
628
                break;
 
629
                default:
 
630
                    PRINT(("WASAPI device:%d bad Data FLow! \n",i));
 
631
                    goto error;
 
632
                break;
 
633
            }
 
634
 
 
635
            deviceInfo->defaultSampleRate = (double)paWasapi->devInfo[i].MixFormat->nSamplesPerSec;
 
636
 
 
637
            (*hostApi)->deviceInfos[i] = deviceInfo;
 
638
            ++(*hostApi)->info.deviceCount;
 
639
        }
 
640
    }
 
641
 
 
642
    spEndpoints->Release();
 
643
 
 
644
    (*hostApi)->Terminate = Terminate;
 
645
    (*hostApi)->OpenStream = OpenStream;
 
646
    (*hostApi)->IsFormatSupported = IsFormatSupported;
 
647
 
 
648
    PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
 
649
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
 
650
                                      GetStreamTime, GetStreamCpuLoad,
 
651
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
 
652
                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
 
653
 
 
654
    PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream,
 
655
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
 
656
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
 
657
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
 
658
 
 
659
    return result;
 
660
 
 
661
error:
 
662
 
 
663
    if (spEndpoints)
 
664
        spEndpoints->Release();
 
665
 
 
666
    if (paWasapi->enumerator)
 
667
        paWasapi->enumerator->Release();
 
668
 
 
669
    if( paWasapi )
 
670
    {
 
671
        if( paWasapi->allocations )
 
672
        {
 
673
            PaUtil_FreeAllAllocations( paWasapi->allocations );
 
674
            PaUtil_DestroyAllocationGroup( paWasapi->allocations );
 
675
        }
 
676
 
 
677
        PaUtil_FreeMemory( paWasapi );
 
678
    }
 
679
    return result;
 
680
}
 
681
 
 
682
 
 
683
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
 
684
{
 
685
    PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
 
686
 
 
687
    paWasapi->enumerator->Release();
 
688
 
 
689
    for (UINT i=0;i<paWasapi->deviceCount;++i){
 
690
        PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i];
 
691
 
 
692
        if (info->device)
 
693
            info->device->Release();
 
694
 
 
695
        if (info->MixFormat)
 
696
            CoTaskMemFree(info->MixFormat);
 
697
    }
 
698
    delete [] paWasapi->devInfo;
 
699
 
 
700
    CoUninitialize();
 
701
 
 
702
    if( paWasapi->allocations ){
 
703
        PaUtil_FreeAllAllocations( paWasapi->allocations );
 
704
        PaUtil_DestroyAllocationGroup( paWasapi->allocations );
 
705
    }
 
706
 
 
707
    PaUtil_FreeMemory( paWasapi );
 
708
}
 
709
 
 
710
static void
 
711
LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in){
 
712
 
 
713
    const WAVEFORMATEX *old = (WAVEFORMATEX *)in;
 
714
 
 
715
        switch (old->wFormatTag){
 
716
                case WAVE_FORMAT_EXTENSIBLE:{
 
717
 
 
718
                        PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n"));
 
719
 
 
720
                        if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){
 
721
                                PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
 
722
                        }
 
723
                        else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){
 
724
                                PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n"));
 
725
                        }
 
726
                        else{
 
727
                                PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",    
 
728
                                                                                        in->SubFormat.Data1,
 
729
                                                                                        in->SubFormat.Data2,
 
730
                                                                                        in->SubFormat.Data3,
 
731
                                                                                        (int)in->SubFormat.Data4[0],
 
732
                                                                                        (int)in->SubFormat.Data4[1],
 
733
                                                                                        (int)in->SubFormat.Data4[2],
 
734
                                                                                        (int)in->SubFormat.Data4[3],
 
735
                                                                                        (int)in->SubFormat.Data4[4],
 
736
                                                                                        (int)in->SubFormat.Data4[5],
 
737
                                                                                        (int)in->SubFormat.Data4[6],
 
738
                                                                                        (int)in->SubFormat.Data4[7]));
 
739
                        }
 
740
                        PRINT(("Samples.wValidBitsPerSample=%d\n",  in->Samples.wValidBitsPerSample));
 
741
                        PRINT(("dwChannelMask=0x%X\n",in->dwChannelMask));
 
742
                }break;
 
743
                
 
744
                case WAVE_FORMAT_PCM:        PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break;
 
745
                case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break;
 
746
                default : PRINT(("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag)); break;
 
747
        }
 
748
 
 
749
        PRINT(("nChannels      =%d\n",old->nChannels)); 
 
750
        PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec));  
 
751
        PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec));  
 
752
        PRINT(("nBlockAlign    =%d\n",old->nBlockAlign));  
 
753
        PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample));  
 
754
        PRINT(("cbSize         =%d\n",old->cbSize));  
 
755
}
 
756
 
 
757
 
 
758
 
 
759
/*
 
760
 WAVEFORMATXXX is always interleaved
 
761
 */
 
762
static PaSampleFormat
 
763
waveformatToPaFormat(const WAVEFORMATEXTENSIBLE *in){
 
764
 
 
765
    const WAVEFORMATEX *old = (WAVEFORMATEX*)in;
 
766
 
 
767
    switch (old->wFormatTag){
 
768
 
 
769
        case WAVE_FORMAT_EXTENSIBLE:
 
770
        {
 
771
            if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){
 
772
                if (in->Samples.wValidBitsPerSample == 32)
 
773
                    return paFloat32;
 
774
                else
 
775
                    return paCustomFormat;
 
776
            }
 
777
            else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){
 
778
                switch (old->wBitsPerSample){
 
779
                    case 32: return paInt32; break;
 
780
                    case 24: return paInt24;break;
 
781
                    case  8: return paUInt8;break;
 
782
                    case 16: return paInt16;break;
 
783
                    default: return paCustomFormat;break;
 
784
                }
 
785
            }
 
786
            else
 
787
                return paCustomFormat;
 
788
        }
 
789
        break;
 
790
 
 
791
        case WAVE_FORMAT_IEEE_FLOAT:
 
792
            return paFloat32;
 
793
        break;
 
794
 
 
795
        case WAVE_FORMAT_PCM:
 
796
        {
 
797
            switch (old->wBitsPerSample){
 
798
                case 32: return paInt32; break;
 
799
                case 24: return paInt24;break;
 
800
                case  8: return paUInt8;break;
 
801
                case 16: return paInt16;break;
 
802
                default: return paCustomFormat;break;
 
803
            }
 
804
        }
 
805
        break;
 
806
 
 
807
        default:
 
808
            return paCustomFormat;
 
809
        break;
 
810
    }
 
811
 
 
812
    return paCustomFormat;
 
813
}
 
814
 
 
815
 
 
816
 
 
817
static PaError
 
818
waveformatFromParams(WAVEFORMATEXTENSIBLE*wavex,
 
819
                          const PaStreamParameters * params,
 
820
                          double sampleRate){
 
821
 
 
822
    size_t bytesPerSample = 0;
 
823
    switch( params->sampleFormat & ~paNonInterleaved ){
 
824
        case paFloat32:
 
825
        case paInt32: bytesPerSample=4;break;
 
826
        case paInt16: bytesPerSample=2;break;
 
827
        case paInt24: bytesPerSample=3;break;
 
828
        case paInt8:
 
829
        case paUInt8: bytesPerSample=1;break;
 
830
        case paCustomFormat:
 
831
        default: return paSampleFormatNotSupported;break;
 
832
    }
 
833
 
 
834
    memset(wavex,0,sizeof(WAVEFORMATEXTENSIBLE));
 
835
 
 
836
    WAVEFORMATEX *old    = (WAVEFORMATEX *)wavex;
 
837
    old->nChannels       = (WORD)params->channelCount;
 
838
    old->nSamplesPerSec  = (DWORD)sampleRate;
 
839
    old->wBitsPerSample  = (WORD)(bytesPerSample*8);
 
840
    old->nAvgBytesPerSec = (DWORD)(old->nSamplesPerSec * old->nChannels * bytesPerSample);
 
841
    old->nBlockAlign     = (WORD)(old->nChannels * bytesPerSample);
 
842
 
 
843
    //WAVEFORMATEX
 
844
    if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)){
 
845
        old->cbSize          = 0;
 
846
        old->wFormatTag      = WAVE_FORMAT_PCM;
 
847
    }
 
848
    //WAVEFORMATEXTENSIBLE
 
849
    else{
 
850
        old->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
 
851
 
 
852
        old->cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
 
853
 
 
854
        if ((params->sampleFormat & ~paNonInterleaved) == paFloat32)
 
855
            wavex->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
 
856
        else
 
857
            wavex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
858
 
 
859
        wavex->Samples.wValidBitsPerSample = old->wBitsPerSample; //no extra padding!
 
860
 
 
861
        switch(params->channelCount){
 
862
            case 1:  wavex->dwChannelMask = SPEAKER_FRONT_CENTER; break;
 
863
            case 2:  wavex->dwChannelMask = 0x1 | 0x2; break;
 
864
            case 4:  wavex->dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20; break;
 
865
            case 6:  wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20; break;
 
866
            case 8:  wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80; break;
 
867
            default: wavex->dwChannelMask = 0; break;
 
868
        }
 
869
    }
 
870
 
 
871
    return paNoError;
 
872
}
 
873
 
 
874
 
 
875
 
 
876
 
 
877
 
 
878
 
 
879
/*
 
880
#define paFloat32        ((PaSampleFormat) 0x00000001) 
 
881
#define paInt32          ((PaSampleFormat) 0x00000002)
 
882
#define paInt24          ((PaSampleFormat) 0x00000004) 
 
883
#define paInt16          ((PaSampleFormat) 0x00000008) 
 
884
*/
 
885
//lifted from pa_wdmks
 
886
static void wasapiFillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount)
 
887
{
 
888
    PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat ));
 
889
    PA_DEBUG(( "sampleRate = %f\n" , sampleRate ));
 
890
    PA_DEBUG(( "chanelCount = %d\n", channelCount ));
 
891
 
 
892
    pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
 
893
    pwfext->Format.nChannels = channelCount;
 
894
    pwfext->Format.nSamplesPerSec = (int)sampleRate;
 
895
    if(channelCount == 1)
 
896
        pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
 
897
    else
 
898
        pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
 
899
    if(sampleFormat == paFloat32)
 
900
    {
 
901
        pwfext->Format.nBlockAlign = channelCount * 4;
 
902
        pwfext->Format.wBitsPerSample = 32;
 
903
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
904
        pwfext->Samples.wValidBitsPerSample = 32;
 
905
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
 
906
    }
 
907
    else if(sampleFormat == paInt32)
 
908
    {
 
909
        pwfext->Format.nBlockAlign = channelCount * 4;
 
910
        pwfext->Format.wBitsPerSample = 32;
 
911
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
912
        pwfext->Samples.wValidBitsPerSample = 32;
 
913
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
914
    }
 
915
    else if(sampleFormat == paInt24)
 
916
    {
 
917
        pwfext->Format.nBlockAlign = channelCount * 3;
 
918
        pwfext->Format.wBitsPerSample = 24;
 
919
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
920
        pwfext->Samples.wValidBitsPerSample = 24;
 
921
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
922
    }
 
923
    else if(sampleFormat == paInt16)
 
924
    {
 
925
        pwfext->Format.nBlockAlign = channelCount * 2;
 
926
        pwfext->Format.wBitsPerSample = 16;
 
927
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
928
        pwfext->Samples.wValidBitsPerSample = 16;
 
929
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
930
    }
 
931
    pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign;
 
932
}
 
933
 
 
934
 
 
935
 
 
936
/*
 
937
#define FORMATTESTS 4
 
938
const int BestToWorst[FORMATTESTS]={paFloat32,paInt32,paInt24,paInt16};
 
939
*/
 
940
 
 
941
#define FORMATTESTS 3
 
942
const int BestToWorst[FORMATTESTS]={paFloat32,paInt24,paInt16};
 
943
 
 
944
 
 
945
static PaError
 
946
GetClosestFormat(IAudioClient * myClient, double sampleRate,const  PaStreamParameters * params, 
 
947
                                 AUDCLNT_SHAREMODE *shareMode, WAVEFORMATEXTENSIBLE *outWavex)
 
948
{
 
949
        //TODO we should try exclusive first and shared after
 
950
        *shareMode = PORTAUDIO_SHAREMODE;
 
951
 
 
952
        PaError answer = paInvalidSampleRate;
 
953
 
 
954
    waveformatFromParams(outWavex,params,sampleRate);
 
955
        WAVEFORMATEX *sharedClosestMatch=0;
 
956
        HRESULT hResult=!S_OK;
 
957
 
 
958
        if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
 
959
                hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&outWavex->Format,NULL);
 
960
        else
 
961
                hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,   &outWavex->Format,&sharedClosestMatch);
 
962
 
 
963
        if (hResult == S_OK)
 
964
                answer = paFormatIsSupported;
 
965
    else if (sharedClosestMatch){
 
966
        WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*)sharedClosestMatch;
 
967
                
 
968
                int closestMatchSR = (int)sharedClosestMatch->nSamplesPerSec;
 
969
 
 
970
                if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
 
971
                        memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEXTENSIBLE));
 
972
                else
 
973
                        memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEX));
 
974
 
 
975
        CoTaskMemFree(sharedClosestMatch);
 
976
 
 
977
                if ((int)sampleRate == closestMatchSR)
 
978
                answer = paFormatIsSupported;
 
979
                else
 
980
                        answer = paInvalidSampleRate;
 
981
        
 
982
        }else {
 
983
 
 
984
                //it doesnt suggest anything?? ok lets show it the MENU!
 
985
 
 
986
                //ok fun time as with pa_win_mme, we know only a refusal of the user-requested
 
987
                //sampleRate+num Channel is disastrous, as the portaudio buffer processor converts between anything
 
988
                //so lets only use the number 
 
989
                for (int i=0;i<FORMATTESTS;++i){
 
990
                        WAVEFORMATEXTENSIBLE ext;
 
991
                        wasapiFillWFEXT(&ext,BestToWorst[i],sampleRate,params->channelCount);           
 
992
                        if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
 
993
                                hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&ext.Format,NULL);
 
994
                        else
 
995
                                hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,   &ext.Format,&sharedClosestMatch);
 
996
 
 
997
                        if (hResult == S_OK){
 
998
                                memcpy(outWavex,&ext,sizeof(WAVEFORMATEXTENSIBLE));
 
999
                                answer = paFormatIsSupported;
 
1000
                                break;
 
1001
                        }
 
1002
                }
 
1003
 
 
1004
                if (answer!=paFormatIsSupported) {
 
1005
                        //try MIX format?
 
1006
                        //why did it HAVE to come to this ....
 
1007
                        WAVEFORMATEX pcm16WaveFormat;
 
1008
                        memset(&pcm16WaveFormat,0,sizeof(WAVEFORMATEX));
 
1009
                        pcm16WaveFormat.wFormatTag = WAVE_FORMAT_PCM; 
 
1010
                        pcm16WaveFormat.nChannels = 2; 
 
1011
                        pcm16WaveFormat.nSamplesPerSec = (DWORD)sampleRate; 
 
1012
                        pcm16WaveFormat.nBlockAlign = 4; 
 
1013
                        pcm16WaveFormat.nAvgBytesPerSec = pcm16WaveFormat.nSamplesPerSec*pcm16WaveFormat.nBlockAlign; 
 
1014
                        pcm16WaveFormat.wBitsPerSample = 16; 
 
1015
                        pcm16WaveFormat.cbSize = 0;
 
1016
 
 
1017
                        if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
 
1018
                                hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&pcm16WaveFormat,NULL);
 
1019
                        else
 
1020
                                hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,   &pcm16WaveFormat,&sharedClosestMatch);
 
1021
 
 
1022
                        if (hResult == S_OK){
 
1023
                                memcpy(outWavex,&pcm16WaveFormat,sizeof(WAVEFORMATEX));
 
1024
                                answer = paFormatIsSupported;
 
1025
                        }
 
1026
                }
 
1027
 
 
1028
                logAUDCLNT_E(hResult);
 
1029
        }
 
1030
 
 
1031
        return answer;
 
1032
}
 
1033
 
 
1034
 
 
1035
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
 
1036
                                  const  PaStreamParameters *inputParameters,
 
1037
                                  const  PaStreamParameters *outputParameters,
 
1038
                                  double sampleRate )
 
1039
{
 
1040
 
 
1041
    int inputChannelCount, outputChannelCount;
 
1042
    PaSampleFormat inputSampleFormat, outputSampleFormat;
 
1043
 
 
1044
    if( inputParameters )
 
1045
    {
 
1046
        inputChannelCount = inputParameters->channelCount;
 
1047
        inputSampleFormat = inputParameters->sampleFormat;
 
1048
 
 
1049
        /* all standard sample formats are supported by the buffer adapter,
 
1050
            this implementation doesn't support any custom sample formats */
 
1051
        if( inputSampleFormat & paCustomFormat )
 
1052
            return paSampleFormatNotSupported;
 
1053
 
 
1054
        /* unless alternate device specification is supported, reject the use of
 
1055
            paUseHostApiSpecificDeviceSpecification */
 
1056
 
 
1057
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1058
            return paInvalidDevice;
 
1059
 
 
1060
        /* check that input device can support inputChannelCount */
 
1061
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
 
1062
            return paInvalidChannelCount;
 
1063
 
 
1064
        /* validate inputStreamInfo */
 
1065
        if( inputParameters->hostApiSpecificStreamInfo )
 
1066
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
1067
 
 
1068
 
 
1069
        PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
 
1070
 
 
1071
 
 
1072
                IAudioClient *myClient=0;
 
1073
                HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate(
 
1074
                        __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
 
1075
                if (hResult != S_OK){
 
1076
                        logAUDCLNT_E(hResult);
 
1077
                        return paInvalidDevice;
 
1078
                }
 
1079
 
 
1080
        WAVEFORMATEXTENSIBLE wavex;
 
1081
                AUDCLNT_SHAREMODE shareMode;
 
1082
                PaError answer = GetClosestFormat(myClient,sampleRate,inputParameters,&shareMode,&wavex);
 
1083
                myClient->Release();
 
1084
 
 
1085
                if (answer !=paFormatIsSupported)
 
1086
                        return answer;
 
1087
    }
 
1088
    else
 
1089
    {
 
1090
        inputChannelCount = 0;
 
1091
    }
 
1092
 
 
1093
    if( outputParameters )
 
1094
    {
 
1095
        outputChannelCount = outputParameters->channelCount;
 
1096
        outputSampleFormat = outputParameters->sampleFormat;
 
1097
 
 
1098
        /* all standard sample formats are supported by the buffer adapter,
 
1099
            this implementation doesn't support any custom sample formats */
 
1100
        if( outputSampleFormat & paCustomFormat )
 
1101
            return paSampleFormatNotSupported;
 
1102
 
 
1103
        /* unless alternate device specification is supported, reject the use of
 
1104
            paUseHostApiSpecificDeviceSpecification */
 
1105
 
 
1106
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1107
            return paInvalidDevice;
 
1108
 
 
1109
        /* check that output device can support outputChannelCount */
 
1110
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
 
1111
            return paInvalidChannelCount;
 
1112
 
 
1113
        /* validate outputStreamInfo */
 
1114
        if( outputParameters->hostApiSpecificStreamInfo )
 
1115
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
1116
 
 
1117
 
 
1118
        PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
 
1119
 
 
1120
                IAudioClient *myClient=0;
 
1121
                HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate(
 
1122
                        __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
 
1123
                if (hResult != S_OK){
 
1124
                        logAUDCLNT_E(hResult);
 
1125
                        return paInvalidDevice;
 
1126
                }
 
1127
 
 
1128
        WAVEFORMATEXTENSIBLE wavex;
 
1129
                AUDCLNT_SHAREMODE shareMode;
 
1130
                PaError answer = GetClosestFormat(myClient,sampleRate,outputParameters,&shareMode,&wavex);
 
1131
                myClient->Release();
 
1132
 
 
1133
                if (answer !=paFormatIsSupported)
 
1134
                        return answer;          
 
1135
    }
 
1136
    else
 
1137
    {
 
1138
        outputChannelCount = 0;
 
1139
    }
 
1140
 
 
1141
 
 
1142
    return paFormatIsSupported;
 
1143
}
 
1144
 
 
1145
 
 
1146
 
 
1147
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
 
1148
 
 
1149
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 
1150
                           PaStream** s,
 
1151
                           const PaStreamParameters *inputParameters,
 
1152
                           const PaStreamParameters *outputParameters,
 
1153
                           double sampleRate,
 
1154
                           unsigned long framesPerBuffer,
 
1155
                           PaStreamFlags streamFlags,
 
1156
                           PaStreamCallback *streamCallback,
 
1157
                           void *userData )
 
1158
{
 
1159
    PaError result = paNoError;
 
1160
    PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
 
1161
    PaWinWasapiStream *stream = 0;
 
1162
    int inputChannelCount, outputChannelCount;
 
1163
    PaSampleFormat inputSampleFormat, outputSampleFormat;
 
1164
    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
 
1165
 
 
1166
 
 
1167
    stream = (PaWinWasapiStream*)PaUtil_AllocateMemory( sizeof(PaWinWasapiStream) );
 
1168
    if( !stream ){
 
1169
        result = paInsufficientMemory;
 
1170
        goto error;
 
1171
    }
 
1172
 
 
1173
    if( inputParameters )
 
1174
    {
 
1175
        inputChannelCount = inputParameters->channelCount;
 
1176
        inputSampleFormat = inputParameters->sampleFormat;
 
1177
 
 
1178
        /* unless alternate device specification is supported, reject the use of
 
1179
            paUseHostApiSpecificDeviceSpecification */
 
1180
 
 
1181
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1182
            return paInvalidDevice;
 
1183
 
 
1184
        /* check that input device can support inputChannelCount */
 
1185
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
 
1186
            return paInvalidChannelCount;
 
1187
 
 
1188
        /* validate inputStreamInfo */
 
1189
        if( inputParameters->hostApiSpecificStreamInfo )
 
1190
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
1191
 
 
1192
 
 
1193
        PaWinWasapiDeviceInfo &info = paWasapi->devInfo[inputParameters->device];
 
1194
 
 
1195
        HRESULT hResult = info.device->Activate(
 
1196
            __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
 
1197
            (void**)&stream->in.client);
 
1198
 
 
1199
        if (hResult != S_OK)
 
1200
            return paInvalidDevice;
 
1201
 
 
1202
        hResult = info.device->Activate(
 
1203
            __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
 
1204
            (void**)&stream->inVol);
 
1205
 
 
1206
        if (hResult != S_OK)
 
1207
            return paInvalidDevice;
 
1208
        
 
1209
                AUDCLNT_SHAREMODE shareMode;
 
1210
                PaError answer = GetClosestFormat(stream->in.client,sampleRate,inputParameters,&shareMode,&stream->in.wavex);
 
1211
                
 
1212
                if (answer !=paFormatIsSupported)
 
1213
                        return answer;
 
1214
 
 
1215
        //stream->out.period = info.DefaultDevicePeriod;
 
1216
        stream->in.period = info.MinimumDevicePeriod;
 
1217
 
 
1218
        hResult = stream->in.client->Initialize(
 
1219
            shareMode,
 
1220
            0,  //no flags
 
1221
            stream->in.period,
 
1222
            0,//stream->out.period,
 
1223
            (WAVEFORMATEX*)&stream->in.wavex,
 
1224
            &stream->session
 
1225
            );
 
1226
 
 
1227
        if (hResult != S_OK){
 
1228
            logAUDCLNT_E(hResult);
 
1229
            return paInvalidDevice;
 
1230
        }
 
1231
 
 
1232
        hResult = stream->in.client->GetBufferSize(&stream->in.bufferSize);
 
1233
        if (hResult != S_OK)
 
1234
            return paInvalidDevice;
 
1235
 
 
1236
        hResult = stream->in.client->GetStreamLatency(&stream->in.latency);
 
1237
        if (hResult != S_OK)
 
1238
            return paInvalidDevice;
 
1239
 
 
1240
        double periodsPerSecond = 1.0/nano100ToSeconds(stream->in.period);
 
1241
        double samplesPerPeriod = (double)(stream->in.wavex.Format.nSamplesPerSec)/periodsPerSecond;
 
1242
 
 
1243
        //this is the number of samples that are required at each period
 
1244
        stream->in.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels
 
1245
 
 
1246
        /* IMPLEMENT ME - establish which  host formats are available */
 
1247
        hostInputSampleFormat =
 
1248
            PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );
 
1249
        }
 
1250
    else
 
1251
    {
 
1252
        inputChannelCount = 0;
 
1253
        inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
 
1254
    }
 
1255
 
 
1256
    if( outputParameters )
 
1257
    {
 
1258
        outputChannelCount = outputParameters->channelCount;
 
1259
        outputSampleFormat = outputParameters->sampleFormat;
 
1260
 
 
1261
        /* unless alternate device specification is supported, reject the use of
 
1262
            paUseHostApiSpecificDeviceSpecification */
 
1263
 
 
1264
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1265
            return paInvalidDevice;
 
1266
 
 
1267
        /* check that output device can support inputChannelCount */
 
1268
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
 
1269
            return paInvalidChannelCount;
 
1270
 
 
1271
        /* validate outputStreamInfo */
 
1272
        if( outputParameters->hostApiSpecificStreamInfo )
 
1273
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
1274
 
 
1275
 
 
1276
        PaWinWasapiDeviceInfo &info = paWasapi->devInfo[outputParameters->device];
 
1277
 
 
1278
        HRESULT hResult = info.device->Activate(
 
1279
            __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
 
1280
            (void**)&stream->out.client);
 
1281
 
 
1282
        if (hResult != S_OK)
 
1283
            return paInvalidDevice;
 
1284
 
 
1285
                AUDCLNT_SHAREMODE shareMode;
 
1286
                PaError answer = GetClosestFormat(stream->out.client,sampleRate,outputParameters,&shareMode,&stream->out.wavex);
 
1287
                
 
1288
                if (answer !=paFormatIsSupported)
 
1289
                        return answer;
 
1290
                LogWAVEFORMATEXTENSIBLE(&stream->out.wavex);
 
1291
 
 
1292
       // stream->out.period = info.DefaultDevicePeriod;
 
1293
        stream->out.period = info.MinimumDevicePeriod;
 
1294
 
 
1295
                /*For an exclusive-mode stream that uses event-driven buffering, 
 
1296
                the caller must specify nonzero values for hnsPeriodicity and hnsBufferDuration, 
 
1297
                and the values of these two parameters must be equal */
 
1298
                if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE){
 
1299
                        hResult = stream->out.client->Initialize(
 
1300
                                shareMode,
 
1301
                                AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 
 
1302
                                stream->out.period,
 
1303
                                stream->out.period,
 
1304
                                (WAVEFORMATEX*)&stream->out.wavex,
 
1305
                                &stream->session
 
1306
                                );
 
1307
                }
 
1308
                else{
 
1309
                        hResult = stream->out.client->Initialize(
 
1310
                                shareMode,
 
1311
                                AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 
 
1312
                                0,
 
1313
                                0,
 
1314
                                (WAVEFORMATEX*)&stream->out.wavex,
 
1315
                                &stream->session
 
1316
                                );
 
1317
                }
 
1318
        
 
1319
 
 
1320
        if (hResult != S_OK){
 
1321
            logAUDCLNT_E(hResult);
 
1322
            return paInvalidDevice;
 
1323
        }
 
1324
 
 
1325
        hResult = info.device->Activate(
 
1326
            __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
 
1327
            (void**)&stream->outVol);
 
1328
 
 
1329
        if (hResult != S_OK)
 
1330
            return paInvalidDevice;
 
1331
 
 
1332
        hResult = stream->out.client->GetBufferSize(&stream->out.bufferSize);
 
1333
        if (hResult != S_OK)
 
1334
            return paInvalidDevice;
 
1335
 
 
1336
        hResult = stream->out.client->GetStreamLatency(&stream->out.latency);
 
1337
        if (hResult != S_OK)
 
1338
            return paInvalidDevice;
 
1339
                
 
1340
        double periodsPerSecond = 1.0/nano100ToSeconds(stream->out.period);
 
1341
        double samplesPerPeriod = (double)(stream->out.wavex.Format.nSamplesPerSec)/periodsPerSecond;
 
1342
 
 
1343
        //this is the number of samples that are required at each period
 
1344
        stream->out.framesPerHostCallback = stream->out.bufferSize; //(unsigned long)samplesPerPeriod;//unrelated to channels
 
1345
 
 
1346
        /* IMPLEMENT ME - establish which  host formats are available */
 
1347
        hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );
 
1348
    }
 
1349
    else
 
1350
    {
 
1351
        outputChannelCount = 0;
 
1352
        outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
 
1353
    }
 
1354
 
 
1355
 
 
1356
 
 
1357
    /*
 
1358
        IMPLEMENT ME:
 
1359
 
 
1360
        ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
 
1361
 
 
1362
            - check that input device can support inputSampleFormat, or that
 
1363
                we have the capability to convert from outputSampleFormat to
 
1364
                a native format
 
1365
 
 
1366
            - check that output device can support outputSampleFormat, or that
 
1367
                we have the capability to convert from outputSampleFormat to
 
1368
                a native format
 
1369
 
 
1370
            - if a full duplex stream is requested, check that the combination
 
1371
                of input and output parameters is supported
 
1372
 
 
1373
            - check that the device supports sampleRate
 
1374
 
 
1375
            - alter sampleRate to a close allowable rate if possible / necessary
 
1376
 
 
1377
            - validate suggestedInputLatency and suggestedOutputLatency parameters,
 
1378
                use default values where necessary
 
1379
    */
 
1380
 
 
1381
 
 
1382
 
 
1383
    /* validate platform specific flags */
 
1384
    if( (streamFlags & paPlatformSpecificFlags) != 0 )
 
1385
        return paInvalidFlag; /* unexpected platform specific flag */
 
1386
 
 
1387
 
 
1388
 
 
1389
    if( streamCallback )
 
1390
    {
 
1391
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
 
1392
                                               &paWasapi->callbackStreamInterface, streamCallback, userData );
 
1393
    }
 
1394
    else
 
1395
    {
 
1396
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
 
1397
                                               &paWasapi->blockingStreamInterface, streamCallback, userData );
 
1398
    }
 
1399
 
 
1400
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
 
1401
 
 
1402
 
 
1403
        if (outputParameters && inputParameters){
 
1404
 
 
1405
                //serious problem #1
 
1406
                if (stream->in.period != stream->out.period){
 
1407
                        PRINT(("OpenStream: period discrepancy\n"));
 
1408
                        goto error;
 
1409
                }
 
1410
 
 
1411
                //serious problem #2
 
1412
                if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback){
 
1413
                        PRINT(("OpenStream: framesPerHostCallback discrepancy\n"));
 
1414
                        goto error;
 
1415
                }
 
1416
        }
 
1417
 
 
1418
        unsigned long framesPerHostCallback = (outputParameters)?
 
1419
                stream->out.framesPerHostCallback: 
 
1420
                stream->in.framesPerHostCallback;
 
1421
 
 
1422
    /* we assume a fixed host buffer size in this example, but the buffer processor
 
1423
        can also support bounded and unknown host buffer sizes by passing
 
1424
        paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
 
1425
        paUtilFixedHostBufferSize below. */
 
1426
 
 
1427
    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
 
1428
              inputChannelCount, inputSampleFormat, hostInputSampleFormat,
 
1429
              outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
 
1430
              sampleRate, streamFlags, framesPerBuffer,
 
1431
              framesPerHostCallback, paUtilFixedHostBufferSize,
 
1432
              streamCallback, userData );
 
1433
    if( result != paNoError )
 
1434
        goto error;
 
1435
 
 
1436
 
 
1437
    /*
 
1438
        IMPLEMENT ME: initialise the following fields with estimated or actual
 
1439
        values.
 
1440
    */
 
1441
    stream->streamRepresentation.streamInfo.inputLatency =
 
1442
            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
 
1443
                        + ((inputParameters)?nano100ToSeconds(stream->in.latency) :0);
 
1444
 
 
1445
    stream->streamRepresentation.streamInfo.outputLatency =
 
1446
            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
 
1447
                        + ((outputParameters)?nano100ToSeconds(stream->out.latency) :0);
 
1448
 
 
1449
    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
 
1450
 
 
1451
 
 
1452
    *s = (PaStream*)stream;
 
1453
 
 
1454
 
 
1455
    return result;
 
1456
 
 
1457
error:
 
1458
    if( stream )
 
1459
        PaUtil_FreeMemory( stream );
 
1460
 
 
1461
    return result;
 
1462
}
 
1463
 
 
1464
 
 
1465
 
 
1466
/*
 
1467
    When CloseStream() is called, the multi-api layer ensures that
 
1468
    the stream has already been stopped or aborted.
 
1469
*/
 
1470
 
 
1471
#define SAFE_RELEASE(punk)  \
 
1472
              if ((punk) != NULL)  \
 
1473
                { (punk)->Release(); (punk) = NULL; }
 
1474
 
 
1475
static PaError CloseStream( PaStream* s )
 
1476
{
 
1477
    PaError result = paNoError;
 
1478
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1479
 
 
1480
    /*
 
1481
        IMPLEMENT ME:
 
1482
            - additional stream closing + cleanup
 
1483
    */
 
1484
 
 
1485
    SAFE_RELEASE(stream->out.client);
 
1486
    SAFE_RELEASE(stream->in.client);
 
1487
    SAFE_RELEASE(stream->cclient);
 
1488
    SAFE_RELEASE(stream->rclient);
 
1489
        SAFE_RELEASE(stream->inVol);
 
1490
        SAFE_RELEASE(stream->outVol);
 
1491
    CloseHandle(stream->hThread);
 
1492
        CloseHandle(stream->hNotificationEvent);
 
1493
 
 
1494
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
 
1495
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
 
1496
    PaUtil_FreeMemory( stream );
 
1497
 
 
1498
    return result;
 
1499
}
 
1500
 
 
1501
DWORD WINAPI ProcThread(void *client);
 
1502
 
 
1503
static PaError StartStream( PaStream *s )
 
1504
{
 
1505
    PaError result = paNoError;
 
1506
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1507
 
 
1508
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
 
1509
        
 
1510
        HRESULT hResult=S_OK;
 
1511
 
 
1512
        if (stream->out.client){
 
1513
                hResult = stream->out.client->GetService(__uuidof(IAudioRenderClient),(void**)&stream->rclient);
 
1514
                logAUDCLNT_E(hResult);
 
1515
                if (hResult!=S_OK)
 
1516
                        return paUnanticipatedHostError;
 
1517
        }
 
1518
        
 
1519
        if (stream->in.client){
 
1520
         hResult = stream->in.client->GetService(__uuidof(IAudioCaptureClient),(void**)&stream->cclient);
 
1521
                logAUDCLNT_E(hResult);
 
1522
                if (hResult!=S_OK)
 
1523
                        return paUnanticipatedHostError;
 
1524
        }
 
1525
 
 
1526
    // Create a thread for this client.
 
1527
    stream->hThread = CREATE_THREAD;
 
1528
        
 
1529
    if (stream->hThread == NULL)
 
1530
        return paUnanticipatedHostError;
 
1531
 
 
1532
    return paNoError;
 
1533
}
 
1534
 
 
1535
 
 
1536
static PaError StopStream( PaStream *s )
 
1537
{
 
1538
    PaError result = paNoError;
 
1539
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1540
 
 
1541
    /* suppress unused variable warnings */
 
1542
    stream->closeRequest = true;
 
1543
    //todo something MUCH better than this
 
1544
    while(stream->closeRequest)
 
1545
        Sleep(100);
 
1546
 
 
1547
    /* IMPLEMENT ME, see portaudio.h for required behavior */
 
1548
 
 
1549
    stream->running = false;
 
1550
 
 
1551
    return result;
 
1552
}
 
1553
 
 
1554
 
 
1555
static PaError AbortStream( PaStream *s )
 
1556
{
 
1557
    PaError result = paNoError;
 
1558
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1559
 
 
1560
    /* suppress unused variable warnings */
 
1561
    stream->closeRequest = true;
 
1562
    //todo something MUCH better than this
 
1563
    while(stream->closeRequest)
 
1564
        Sleep(100);
 
1565
 
 
1566
    /* IMPLEMENT ME, see portaudio.h for required behavior */
 
1567
 
 
1568
    return result;
 
1569
}
 
1570
 
 
1571
 
 
1572
static PaError IsStreamStopped( PaStream *s )
 
1573
{
 
1574
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1575
 
 
1576
    return !stream->running;
 
1577
}
 
1578
 
 
1579
 
 
1580
static PaError IsStreamActive( PaStream *s )
 
1581
{
 
1582
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1583
    return stream->running;
 
1584
}
 
1585
 
 
1586
 
 
1587
static PaTime GetStreamTime( PaStream *s )
 
1588
{
 
1589
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1590
 
 
1591
    /* suppress unused variable warnings */
 
1592
    (void) stream;
 
1593
 
 
1594
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
1595
 
 
1596
        //this is lame ds and mme does the same thing, quite useless method imho
 
1597
        //why dont we fetch the time in the pa callbacks?
 
1598
        //at least its doing to be clocked to something
 
1599
    return PaUtil_GetTime();
 
1600
}
 
1601
 
 
1602
 
 
1603
static double GetStreamCpuLoad( PaStream* s )
 
1604
{
 
1605
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1606
 
 
1607
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
 
1608
}
 
1609
 
 
1610
 
 
1611
/*
 
1612
    As separate stream interfaces are used for blocking and callback
 
1613
    streams, the following functions can be guaranteed to only be called
 
1614
    for blocking streams.
 
1615
*/
 
1616
 
 
1617
static PaError ReadStream( PaStream* s,
 
1618
                           void *buffer,
 
1619
                           unsigned long frames )
 
1620
{
 
1621
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1622
 
 
1623
    /* suppress unused variable warnings */
 
1624
    (void) buffer;
 
1625
    (void) frames;
 
1626
    (void) stream;
 
1627
 
 
1628
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
1629
 
 
1630
    return paNoError;
 
1631
}
 
1632
 
 
1633
 
 
1634
static PaError WriteStream( PaStream* s,
 
1635
                            const void *buffer,
 
1636
                            unsigned long frames )
 
1637
{
 
1638
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1639
 
 
1640
    /* suppress unused variable warnings */
 
1641
    (void) buffer;
 
1642
    (void) frames;
 
1643
    (void) stream;
 
1644
 
 
1645
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
1646
 
 
1647
    return paNoError;
 
1648
}
 
1649
 
 
1650
 
 
1651
static signed long GetStreamReadAvailable( PaStream* s )
 
1652
{
 
1653
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1654
 
 
1655
    /* suppress unused variable warnings */
 
1656
    (void) stream;
 
1657
 
 
1658
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
1659
 
 
1660
    return 0;
 
1661
}
 
1662
 
 
1663
 
 
1664
static signed long GetStreamWriteAvailable( PaStream* s )
 
1665
{
 
1666
    PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
 
1667
 
 
1668
    /* suppress unused variable warnings */
 
1669
    (void) stream;
 
1670
 
 
1671
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
1672
 
 
1673
    return 0;
 
1674
}
 
1675
 
 
1676
 
 
1677
 
 
1678
/*
 
1679
    ExampleHostProcessingLoop() illustrates the kind of processing which may
 
1680
    occur in a host implementation.
 
1681
 
 
1682
*/
 
1683
static void WaspiHostProcessingLoop( void *inputBuffer,  long inputFrames,
 
1684
                                     void *outputBuffer, long outputFrames,
 
1685
                                     void *userData )
 
1686
{
 
1687
    PaWinWasapiStream *stream = (PaWinWasapiStream*)userData;
 
1688
    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
 
1689
    int callbackResult;
 
1690
    unsigned long framesProcessed;
 
1691
 
 
1692
    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
 
1693
 
 
1694
 
 
1695
    /*
 
1696
        IMPLEMENT ME:
 
1697
            - generate timing information
 
1698
            - handle buffer slips
 
1699
    */
 
1700
 
 
1701
    /*
 
1702
        If you need to byte swap or shift inputBuffer to convert it into a
 
1703
        portaudio format, do it here.
 
1704
    */
 
1705
 
 
1706
 
 
1707
 
 
1708
    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
 
1709
 
 
1710
    /*
 
1711
        depending on whether the host buffers are interleaved, non-interleaved
 
1712
        or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
 
1713
        PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
 
1714
    */
 
1715
 
 
1716
    if( stream->bufferProcessor.inputChannelCount > 0 )
 
1717
    {
 
1718
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, inputFrames );
 
1719
        PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
 
1720
            0, /* first channel of inputBuffer is channel 0 */
 
1721
            inputBuffer,
 
1722
            0 ); /* 0 - use inputChannelCount passed to init buffer processor */
 
1723
    }
 
1724
 
 
1725
    if( stream->bufferProcessor.outputChannelCount > 0 )
 
1726
    {
 
1727
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, outputFrames);
 
1728
        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
 
1729
            0, /* first channel of outputBuffer is channel 0 */
 
1730
            outputBuffer,
 
1731
            0 ); /* 0 - use outputChannelCount passed to init buffer processor */
 
1732
    }
 
1733
 
 
1734
    /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
 
1735
        in general you would pass paContinue for normal operation, and
 
1736
        paComplete to drain the buffer processor's internal output buffer.
 
1737
        You can check whether the buffer processor's output buffer is empty
 
1738
        using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
 
1739
    */
 
1740
    callbackResult = paContinue;
 
1741
    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
 
1742
 
 
1743
 
 
1744
    /*
 
1745
        If you need to byte swap or shift outputBuffer to convert it to
 
1746
        host format, do it here.
 
1747
    */
 
1748
 
 
1749
    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
 
1750
 
 
1751
 
 
1752
    if( callbackResult == paContinue )
 
1753
    {
 
1754
        /* nothing special to do */
 
1755
    }
 
1756
    else if( callbackResult == paAbort )
 
1757
    {
 
1758
        /* IMPLEMENT ME - finish playback immediately  */
 
1759
 
 
1760
        /* once finished, call the finished callback */
 
1761
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
1762
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
1763
    }
 
1764
    else
 
1765
    {
 
1766
        /* User callback has asked us to stop with paComplete or other non-zero value */
 
1767
 
 
1768
        /* IMPLEMENT ME - finish playback once currently queued audio has completed  */
 
1769
 
 
1770
        /* once finished, call the finished callback */
 
1771
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
1772
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
1773
    }
 
1774
}
 
1775
 
 
1776
 
 
1777
void 
 
1778
MMCSS_activate(){
 
1779
 
 
1780
    DWORD stuff=0;
 
1781
    HANDLE thCarac = pAvSetMmThreadCharacteristics("Pro Audio",&stuff);
 
1782
    if (!thCarac){
 
1783
        PRINT(("AvSetMmThreadCharacteristics failed!\n"));
 
1784
    }
 
1785
 
 
1786
    BOOL prio = pAvSetMmThreadPriority(thCarac,AVRT_PRIORITY_NORMAL);
 
1787
    if (!prio){
 
1788
        PRINT(("AvSetMmThreadPriority failed!\n"));
 
1789
    }
 
1790
 
 
1791
        //debug
 
1792
    {
 
1793
        HANDLE hh       = GetCurrentThread();
 
1794
        int  currprio   = GetThreadPriority(hh);
 
1795
        DWORD currclass = GetPriorityClass(GetCurrentProcess());
 
1796
        PRINT(("currprio 0x%X currclass 0x%X\n",currprio,currclass));
 
1797
    }
 
1798
}
 
1799
 
 
1800
 
 
1801
DWORD WINAPI
 
1802
ProcThread(void* param){
 
1803
        HRESULT hResult;
 
1804
        MMCSS_activate();
 
1805
 
 
1806
    PaWinWasapiStream *stream = (PaWinWasapiStream*)param;
 
1807
 
 
1808
        stream->hNotificationEvent = CreateEvent(NULL, 
 
1809
                                                 FALSE,  //bManualReset are we sure??
 
1810
                                                                                         FALSE, 
 
1811
                                                                                         "PAWASA");
 
1812
        hResult = stream->out.client->SetEventHandle(stream->hNotificationEvent);
 
1813
        if (hResult != S_OK)
 
1814
                logAUDCLNT_E(hResult);
 
1815
 
 
1816
        if (stream->out.client){
 
1817
                hResult = stream->out.client->Start();
 
1818
                if (hResult != S_OK)
 
1819
                        logAUDCLNT_E(hResult);
 
1820
        }
 
1821
 
 
1822
        stream->running = true;
 
1823
        bool bOne = false;
 
1824
 
 
1825
        while( !stream->closeRequest ) 
 
1826
    { 
 
1827
            //lets wait but have a 1 second timeout
 
1828
        DWORD dwResult = WaitForSingleObject(stream->hNotificationEvent, 1000);
 
1829
        switch( dwResult ) {
 
1830
                case WAIT_OBJECT_0: {
 
1831
 
 
1832
                        unsigned long usingBS = stream->out.framesPerHostCallback;
 
1833
 
 
1834
                        BYTE* indata  = 0;
 
1835
                        BYTE* outdata = 0;
 
1836
 
 
1837
                        hResult = stream->rclient->GetBuffer(usingBS, &outdata);
 
1838
 
 
1839
                        if (hResult != S_OK || !outdata) {
 
1840
                                //logAUDCLNT_E(hResult);
 
1841
                                //most probably shared mode and hResult=AUDCLNT_E_BUFFER_TOO_LARGE
 
1842
                                UINT32 padding = 0;
 
1843
                                hResult = stream->out.client->GetCurrentPadding(&padding);
 
1844
                                if (padding == 0)
 
1845
                                        break;  
 
1846
                                usingBS = usingBS-padding;
 
1847
                                if (usingBS == 0)
 
1848
                                        break;//huh?
 
1849
                                hResult = stream->rclient->GetBuffer(usingBS, &outdata);
 
1850
                                if (hResult != S_OK)//what can we do NOW??
 
1851
                                        break;
 
1852
                                //logAUDCLNT_E(hResult);                        
 
1853
                        }
 
1854
        
 
1855
                        WaspiHostProcessingLoop(indata, usingBS ,outdata, usingBS, stream);
 
1856
 
 
1857
                        hResult = stream->rclient->ReleaseBuffer(usingBS, 0);
 
1858
                        if (hResult != S_OK)
 
1859
                                logAUDCLNT_E(hResult);
 
1860
 
 
1861
                         /*     This was suggested, but in my tests it doesnt seem to improve the 
 
1862
                locking behaviour some drivers have running in exclusive mode.
 
1863
                if(!ResetEvent(stream->hNotificationEvent)){
 
1864
                                        logAUDCLNT_E(hResult);
 
1865
                                }
 
1866
             */
 
1867
 
 
1868
                } 
 
1869
                break;
 
1870
 
 
1871
        }
 
1872
    }
 
1873
        stream->out.client->Stop();
 
1874
    stream->closeRequest = false;
 
1875
    
 
1876
        return 0; 
 
1877
}
 
1878
 
 
1879
 
 
1880
 
 
1881
 
 
1882
#endif //VC 2005
 
1883
 
 
1884
 
 
1885
 
 
1886
 
 
1887
#if 0
 
1888
                        if(bFirst) {                    
 
1889
                                float masteur;
 
1890
                                hResult = stream->outVol->GetMasterVolumeLevelScalar(&masteur);
 
1891
                                if (hResult != S_OK)
 
1892
                                        logAUDCLNT_E(hResult);
 
1893
                                float chan1, chan2;
 
1894
                                hResult = stream->outVol->GetChannelVolumeLevelScalar(0, &chan1);
 
1895
                                if (hResult != S_OK)
 
1896
                                        logAUDCLNT_E(hResult);
 
1897
                                hResult = stream->outVol->GetChannelVolumeLevelScalar(1, &chan2);
 
1898
                                if (hResult != S_OK)
 
1899
                                        logAUDCLNT_E(hResult);
 
1900
 
 
1901
                                BOOL bMute;
 
1902
                                hResult = stream->outVol->GetMute(&bMute);
 
1903
                                if (hResult != S_OK)
 
1904
                                        logAUDCLNT_E(hResult);
 
1905
 
 
1906
                                stream->outVol->SetMasterVolumeLevelScalar(0.5, NULL);
 
1907
                                stream->outVol->SetChannelVolumeLevelScalar(0, 0.5, NULL);
 
1908
                                stream->outVol->SetChannelVolumeLevelScalar(1, 0.5, NULL);
 
1909
                                stream->outVol->SetMute(FALSE, NULL);
 
1910
                                bFirst = false;
 
1911
                        }
 
1912
#endif
 
 
b'\\ No newline at end of file'