~ubuntu-branches/ubuntu/saucy/sflphone/saucy

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/third_party/portaudio/src/hostapi/wasapi/pa_win_wasapi.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Francois Marier
  • Date: 2010-12-24 16:33:55 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20101224163355-tkvvikqxbrbav6up
Tags: 0.9.11-1
* New upstream release
* Add new build dependencies on libwebkit-dev and libyaml-dev

* Bump Standards-Version up to 3.9.1
* Bump debhelper compatibility to 8
* Patch another typo in the upstream code (lintian notice)

Show diffs side-by-side

added added

removed removed

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