Browse Source

wasapi: new API PaWasapi_SetStreamStateHandler() to be able to catch WASAPI error inside the rendering thread loop (and handle it gracefully, for example restart the stream), protect from dangling pointer during device list update, cleanup header

mr/7129721/83ab55b62d707c11d18238b1928e0297d67e4767
dmitrykos 6 months ago
parent
commit
83ab55b62d
3 changed files with 362 additions and 203 deletions
  1. 9
    7
      build/msvc/portaudio.def
  2. 198
    114
      include/pa_win_wasapi.h
  3. 155
    82
      src/hostapi/wasapi/pa_win_wasapi.c

+ 9
- 7
build/msvc/portaudio.def View File

@@ -45,10 +45,12 @@ PaWasapi_GetAudioClient             @56
45 45
 PaWasapi_UpdateDeviceList           @57
46 46
 PaWasapi_GetDeviceCurrentFormat     @58
47 47
 PaWasapi_GetDeviceDefaultFormat     @59
48
-PaWasapi_GetDeviceRole              @60
49
-PaWasapi_ThreadPriorityBoost        @61
50
-PaWasapi_ThreadPriorityRevert       @62
51
-PaWasapi_GetFramesPerHostBuffer     @63
52
-PaWasapi_GetJackCount               @64
53
-PaWasapi_GetJackDescription         @65
54
-PaWasapi_SetDefaultInterfaceId      @66
48
+PaWasapi_GetDeviceMixFormat         @60
49
+PaWasapi_GetDeviceRole              @61
50
+PaWasapi_ThreadPriorityBoost        @62
51
+PaWasapi_ThreadPriorityRevert       @63
52
+PaWasapi_GetFramesPerHostBuffer     @64
53
+PaWasapi_GetJackCount               @65
54
+PaWasapi_GetJackDescription         @66
55
+PaWasapi_SetDefaultInterfaceId      @67
56
+PaWasapi_SetStreamStateHandler      @68

+ 198
- 114
include/pa_win_wasapi.h View File

@@ -3,9 +3,11 @@
3 3
 /*
4 4
  * $Id:  $
5 5
  * PortAudio Portable Real-Time Audio Library
6
- * DirectSound specific extensions
6
+ * WASAPI specific extensions
7 7
  *
8
- * Copyright (c) 1999-2007 Ross Bencina and Phil Burk
8
+ * Copyright (c) 1999-2018 Ross Bencina and Phil Burk
9
+ * Copyright (c) 2006-2010 David Viens
10
+ * Copyright (c) 2010-2018 Dmitry Kostjuchenko
9 11
  *
10 12
  * Permission is hereby granted, free of charge, to any person obtaining
11 13
  * a copy of this software and associated documentation files
@@ -28,13 +30,13 @@
28 30
  */
29 31
 
30 32
 /*
31
- * The text above constitutes the entire PortAudio license; however, 
33
+ * The text above constitutes the entire PortAudio license; however,
32 34
  * the PortAudio community also makes the following non-binding requests:
33 35
  *
34 36
  * Any person wishing to distribute modifications to the Software is
35 37
  * requested to send the modifications to the original developer so that
36
- * they can be incorporated into the canonical version. It is also 
37
- * requested that these non-binding requests be included along with the 
38
+ * they can be incorporated into the canonical version. It is also
39
+ * requested that these non-binding requests be included along with the
38 40
  * license above.
39 41
  */
40 42
 
@@ -52,7 +54,7 @@ extern "C"
52 54
 #endif /* __cplusplus */
53 55
 
54 56
 
55
-/* Setup flags */
57
+/* Stream setup flags. */
56 58
 typedef enum PaWasapiFlags
57 59
 {
58 60
     /* put WASAPI into exclusive mode */
@@ -69,12 +71,12 @@ typedef enum PaWasapiFlags
69 71
              method can only provide 15-20ms latency. */
70 72
     paWinWasapiPolling                  = (1 << 3),
71 73
 
72
-    /* force custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority 
74
+    /* force custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority
73 75
        is set to a custom value */
74 76
     paWinWasapiThreadPriority           = (1 << 4),
75 77
 
76
-    /* force explicit sample format and do not allow PA to select suitable working format, API will 
77
-       fail if provided sample format is not supported by audio hardware in Exclusive mode 
78
+    /* force explicit sample format and do not allow PA to select suitable working format, API will
79
+       fail if provided sample format is not supported by audio hardware in Exclusive mode
78 80
        or system mixer in Shared mode */
79 81
     paWinWasapiExplicitSampleFormat     = (1 << 5)
80 82
 }
@@ -87,15 +89,62 @@ PaWasapiFlags;
87 89
 #define paWinWasapiExplicitSampleFormat  (paWinWasapiExplicitSampleFormat)
88 90
 
89 91
 
90
-/* Host processor. Allows to skip internal PA processing completely. 
91
-   You must set paWinWasapiRedirectHostProcessor flag to PaWasapiStreamInfo::flags member
92
-   in order to have host processor redirected to your callback.
92
+/* Stream state.
93
+
94
+ @note Multiple states can be united into a bitmask.
95
+ @see  PaWasapiStreamStateCallback, PaWasapi_SetStreamStateHandler
96
+*/
97
+typedef enum PaWasapiStreamState
98
+{
99
+    /* state change was caused by the error:
100
+
101
+       Example:
102
+       1) If thread execution stopped due to AUDCLNT_E_RESOURCES_INVALIDATED then state
103
+          value will contain paWasapiStreamStateError|paWasapiStreamStateThreadStop.
104
+    */
105
+    paWasapiStreamStateError         = (1 << 0),
106
+
107
+    /* processing thread is preparing to start execution */
108
+    paWasapiStreamStateThreadPrepare = (1 << 1),
109
+
110
+    /* processing thread started execution (enters its loop) */
111
+    paWasapiStreamStateThreadStart   = (1 << 2),
112
+
113
+    /* processing thread stopped execution */
114
+    paWasapiStreamStateThreadStop    = (1 << 3)
115
+}
116
+PaWasapiStreamState;
117
+#define paWasapiStreamStateError         (paWasapiStreamStateError)
118
+#define paWasapiStreamStateThreadPrepare (paWasapiStreamStateThreadPrepare)
119
+#define paWasapiStreamStateThreadStart   (paWasapiStreamStateThreadStart)
120
+#define paWasapiStreamStateThreadStop    (paWasapiStreamStateThreadStop)
121
+
122
+
123
+/* Host processor.
124
+
125
+   Allows to skip internal PA processing completely. paWinWasapiRedirectHostProcessor flag
126
+   must be set to the PaWasapiStreamInfo::flags member in order to have host processor
127
+   redirected to this callback.
128
+
93 129
    Use with caution! inputFrames and outputFrames depend solely on final device setup.
94
-   To query maximal values of inputFrames/outputFrames use PaWasapi_GetFramesPerHostBuffer.
130
+   To query max values of inputFrames/outputFrames use PaWasapi_GetFramesPerHostBuffer.
95 131
 */
96
-typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer,  long inputFrames,
97
-                                               void *outputBuffer, long outputFrames,
98
-                                               void *userData);
132
+typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFrames,
133
+    void *outputBuffer, long outputFrames, void *userData);
134
+
135
+
136
+/* Stream state handler.
137
+
138
+ @param pStream    Pointer to PaStream object.
139
+ @param stateFlags State flags, a collection of values from PaWasapiStreamState enum.
140
+ @param errorId    Error id provided by system API (HRESULT).
141
+ @param userData   Pointer to user data.
142
+
143
+ @see   PaWasapiStreamState
144
+*/
145
+typedef void (*PaWasapiStreamStateCallback) (PaStream *pStream, unsigned int stateFlags,
146
+    unsigned int errorId, void *pUserData);
147
+
99 148
 
100 149
 /* Device role. */
101 150
 typedef enum PaWasapiDeviceRole
@@ -130,7 +179,7 @@ typedef enum PaWasapiJackConnectionType
130 179
     eJackConnTypeXlrProfessional,
131 180
     eJackConnTypeRJ11Modem,
132 181
     eJackConnTypeCombination
133
-} 
182
+}
134 183
 PaWasapiJackConnectionType;
135 184
 
136 185
 
@@ -153,7 +202,7 @@ typedef enum PaWasapiJackGeoLocation
153 202
     eJackGeoLocATAPI,
154 203
     eJackGeoLocReserved5,
155 204
     eJackGeoLocReserved6,
156
-} 
205
+}
157 206
 PaWasapiJackGeoLocation;
158 207
 
159 208
 
@@ -164,7 +213,7 @@ typedef enum PaWasapiJackGenLocation
164 213
     eJackGenLocInternal,
165 214
     eJackGenLocSeparate,
166 215
     eJackGenLocOther
167
-} 
216
+}
168 217
 PaWasapiJackGenLocation;
169 218
 
170 219
 
@@ -175,7 +224,7 @@ typedef enum PaWasapiJackPortConnection
175 224
     eJackPortConnIntegratedDevice,
176 225
     eJackPortConnBothIntegratedAndJack,
177 226
     eJackPortConnUnknown
178
-} 
227
+}
179 228
 PaWasapiJackPortConnection;
180 229
 
181 230
 
@@ -195,7 +244,7 @@ PaWasapiThreadPriority;
195 244
 
196 245
 
197 246
 /* Stream descriptor. */
198
-typedef struct PaWasapiJackDescription 
247
+typedef struct PaWasapiJackDescription
199 248
 {
200 249
     unsigned long              channelMapping;
201 250
     unsigned long              color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */
@@ -249,7 +298,7 @@ PaWasapiStreamOption;
249 298
 
250 299
 
251 300
 /* Stream descriptor. */
252
-typedef struct PaWasapiStreamInfo 
301
+typedef struct PaWasapiStreamInfo
253 302
 {
254 303
     unsigned long size;             /**< sizeof(PaWasapiStreamInfo) */
255 304
     PaHostApiTypeId hostApiType;    /**< paWASAPI */
@@ -258,16 +307,16 @@ typedef struct PaWasapiStreamInfo
258 307
     unsigned long flags;            /**< collection of PaWasapiFlags */
259 308
 
260 309
     /** Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains
261
-       paWinWasapiUseChannelMask this allows you to specify which speakers 
310
+       paWinWasapiUseChannelMask this allows you to specify which speakers
262 311
        to address in a multichannel stream. Constants for channelMask
263
-       are specified in pa_win_waveformat.h. Will be used only if 
312
+       are specified in pa_win_waveformat.h. Will be used only if
264 313
        paWinWasapiUseChannelMask flag is specified.
265 314
     */
266 315
     PaWinWaveFormatChannelMask channelMask;
267 316
 
268 317
     /** Delivers raw data to callback obtained from GetBuffer() methods skipping
269
-       internal PortAudio processing inventory completely. userData parameter will 
270
-       be the same that was passed to Pa_OpenStream method. Will be used only if 
318
+       internal PortAudio processing inventory completely. userData parameter will
319
+       be the same that was passed to Pa_OpenStream method. Will be used only if
271 320
        paWinWasapiRedirectHostProcessor flag is specified.
272 321
     */
273 322
     PaWasapiHostProcessorCallback hostProcessorOutput;
@@ -293,13 +342,13 @@ typedef struct PaWasapiStreamInfo
293 342
      @version Available as of 19.6.0
294 343
     */
295 344
     PaWasapiStreamOption streamOption;
296
-} 
345
+}
297 346
 PaWasapiStreamInfo;
298 347
 
299 348
 
300 349
 /** Returns pointer to WASAPI's IAudioClient object of the stream.
301 350
 
302
- @param pStream      Pointer to PaStream.
351
+ @param pStream      Pointer to PaStream object.
303 352
  @param pAudioClient Pointer to pointer of IAudioClient.
304 353
  @param bOutput      TRUE (1) for output stream, FALSE (0) for input stream.
305 354
 
@@ -308,10 +357,11 @@ PaWasapiStreamInfo;
308 357
 PaError PaWasapi_GetAudioClient( PaStream *pStream, void **pAudioClient, int bOutput );
309 358
 
310 359
 
311
-/** Update device list. 
312
-    This function is available if PA_WASAPI_MAX_CONST_DEVICE_COUNT is defined during compile time 
313
-    with maximum constant WASAPI device count (recommended value - 32). 
314
-    If PA_WASAPI_MAX_CONST_DEVICE_COUNT is set to 0 (or not defined) during compile time the implementation 
360
+/** Update device list.
361
+
362
+    This function is available if PA_WASAPI_MAX_CONST_DEVICE_COUNT is defined during compile time
363
+    with maximum constant WASAPI device count (recommended value - 32).
364
+    If PA_WASAPI_MAX_CONST_DEVICE_COUNT is set to 0 (or not defined) during compile time the implementation
315 365
     will not define PaWasapi_UpdateDeviceList() and thus updating device list can only be possible by calling
316 366
     Pa_Terminate() and then Pa_Initialize().
317 367
 
@@ -320,115 +370,128 @@ PaError PaWasapi_GetAudioClient( PaStream *pStream, void **pAudioClient, int bOu
320 370
 PaError PaWasapi_UpdateDeviceList();
321 371
 
322 372
 
323
-/** Returns current audio format of the device assigned to the opened stream. Format is represented by 
324
-    PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. Use this function to reconfirm format if 
325
-    PA's processor is overriden and paWinWasapiRedirectHostProcessor flag is specified.
373
+/** Get current audio format of the device assigned to the opened stream.
374
+
375
+    Format is represented by PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
376
+    Use this function to reconfirm format if PA's processor is overriden and
377
+    paWinWasapiRedirectHostProcessor flag is specified.
326 378
 
327
- @param pStream     Pointer to PaStream.
328
- @param pFormat     Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
329
- @param nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
330
- @param bOutput     TRUE (1) for output stream, FALSE (0) for input stream.
379
+ @param pStream    Pointer to PaStream object.
380
+ @param pFormat    Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
381
+ @param formatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
382
+ @param bOutput    TRUE (1) for output stream, FALSE (0) for input stream.
331 383
 
332 384
  @return Non-negative value indicating the number of bytes copied into format decriptor
333
-         or, a PaErrorCode (which are always negative) if PortAudio is not initialized
385
+         or, a PaErrorCode (which is always negative) if PortAudio is not initialized
334 386
          or an error is encountered.
335 387
 */
336
-int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int nFormatSize, int bOutput );
388
+int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int formatSize, int bOutput );
337 389
 
338 390
 
339
-/** Returns default audio format for device in Shared Mode. Format is represented by
340
-    PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure and obtained by getting
341
-    the device property with a PKEY_AudioEngine_DeviceFormat key.
391
+/** Get default audio format for the device in Shared Mode.
342 392
 
343
- @param  pFormat     Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
344
- @param  nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
345
- @param  nDevice     Device index.
393
+    Format is represented by PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure and obtained
394
+    by getting the device property with a PKEY_AudioEngine_DeviceFormat key.
395
+
396
+ @param  pFormat    Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
397
+ @param  formatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
398
+ @param  device     Device index.
346 399
 
347 400
  @return Non-negative value indicating the number of bytes copied into format decriptor
348
-         or, a PaErrorCode (which are always negative) if PortAudio is not initialized
401
+         or, a PaErrorCode (which is always negative) if PortAudio is not initialized
349 402
          or an error is encountered.
350 403
 */
351
-int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice );
404
+int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device );
405
+
352 406
 
407
+/** Get mix audio format for the device in Shared Mode.
353 408
 
354
-/** Returns mix audio format for device in Shared Mode. Format is represented by
355
-    PaWinWaveFormat or WAVEFORMATEXTENSIBLE structureand obtained by
409
+    Format is represented by PaWinWaveFormat or WAVEFORMATEXTENSIBLE structureand obtained by
356 410
     IAudioClient::GetMixFormat.
357 411
 
358
- @param  pFormat     Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
359
- @param  nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
360
- @param  nDevice     Device index.
412
+ @param  pFormat    Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
413
+ @param  formatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
414
+ @param  device     Device index.
361 415
 
362 416
  @return Non-negative value indicating the number of bytes copied into format decriptor
363
-         or, a PaErrorCode (which are always negative) if PortAudio is not initialized
417
+         or, a PaErrorCode (which is always negative) if PortAudio is not initialized
364 418
          or an error is encountered.
365 419
 */
366
-int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice );
420
+int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device );
367 421
 
368 422
 
369
-/** Returns device role (PaWasapiDeviceRole enum).
423
+/** Get device role (PaWasapiDeviceRole enum).
370 424
 
371
- @param  nDevice Device index.
425
+ @param  device Device index.
372 426
 
373
- @return Non-negative value indicating device role or, a PaErrorCode (which are always negative)
427
+ @return Non-negative value indicating device role or, a PaErrorCode (which is always negative)
374 428
          if PortAudio is not initialized or an error is encountered.
375 429
 */
376
-int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex nDevice );
430
+int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex device );
377 431
 
378 432
 
379
-/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
380
-    which makes calls to Pa_WriteStream/Pa_ReadStream.
433
+/** Boost thread priority of calling thread (MMCSS).
381 434
 
382
- @param  hTask Handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority
383
-               method to revert thread priority to initial state.
435
+    Use it for Blocking Interface only inside the thread which makes calls to Pa_WriteStream/Pa_ReadStream.
384 436
 
385
- @param  nPriorityClass Id of thread priority of PaWasapiThreadPriority type. Specifying 
437
+ @param  pTask          Handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority
438
+                        method to revert thread priority to initial state.
439
+
440
+ @param  priorityClass  Id of thread priority of PaWasapiThreadPriority type. Specifying
386 441
                         eThreadPriorityNone does nothing.
387 442
 
388 443
  @return Error code indicating success or failure.
389 444
  @see    PaWasapi_RevertThreadPriority
390 445
 */
391
-PaError PaWasapi_ThreadPriorityBoost( void **hTask, PaWasapiThreadPriority nPriorityClass );
446
+PaError PaWasapi_ThreadPriorityBoost( void **pTask, PaWasapiThreadPriority priorityClass );
447
+
392 448
 
449
+/** Boost thread priority of calling thread (MMCSS).
393 450
 
394
-/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
395
-    which makes calls to Pa_WriteStream/Pa_ReadStream.
451
+    Use it for Blocking Interface only inside the thread which makes calls to Pa_WriteStream/Pa_ReadStream.
452
+
453
+ @param  pTask Task handle obtained by PaWasapi_BoostThreadPriority method.
396 454
 
397
- @param  hTask Task handle obtained by PaWasapi_BoostThreadPriority method.
398 455
  @return Error code indicating success or failure.
399 456
  @see    PaWasapi_BoostThreadPriority
400 457
 */
401
-PaError PaWasapi_ThreadPriorityRevert( void *hTask );
458
+PaError PaWasapi_ThreadPriorityRevert( void *pTask );
459
+
460
+
461
+/** Get number of frames per host buffer.
402 462
 
463
+    It is max value of frames of WASAPI buffer which can be locked for operations.
464
+    Use this method as helper to findout max values of inputFrames/outputFrames
465
+    of PaWasapiHostProcessorCallback.
403 466
 
404
-/** Get number of frames per host buffer. This is maximal value of frames of WASAPI buffer which 
405
-    can be locked for operations. Use this method as helper to findout maximal values of 
406
-    inputFrames/outputFrames of PaWasapiHostProcessorCallback.
467
+ @param  pStream Pointer to PaStream object.
468
+ @param  pInput  Pointer to variable to receive number of input frames. Can be NULL.
469
+ @param  pOutput Pointer to variable to receive number of output frames. Can be NULL.
407 470
 
408
- @param  pStream Pointer to PaStream to query.
409
- @param  nInput  Pointer to variable to receive number of input frames. Can be NULL.
410
- @param  nOutput Pointer to variable to receive number of output frames. Can be NULL.
411 471
  @return Error code indicating success or failure.
412 472
  @see    PaWasapiHostProcessorCallback
413 473
 */
414
-PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput );
474
+PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *pInput, unsigned int *pOutput );
415 475
 
416 476
 
417
-/** Get number of jacks associated with a WASAPI device.  Use this method to determine if
418
-    there are any jacks associated with the provided WASAPI device.  Not all audio devices
419
-    will support this capability.  This is valid for both input and output devices.
477
+/** Get number of jacks associated with a WASAPI device.
478
+
479
+    Use this method to determine if there are any jacks associated with the provided WASAPI device.
480
+    Not all audio devices will support this capability. This is valid for both input and output devices.
420 481
 
421 482
  @note   Not available on UWP platform.
422 483
 
423
- @param  nDevice  device index.
424
- @param  jcount   Number of jacks is returned in this variable
425
- @return Error code indicating success or failure
484
+ @param  device     Device index.
485
+ @param  pJackCount Pointer to variable to receive number of jacks.
486
+
487
+ @return Error code indicating success or failure.
426 488
  @see    PaWasapi_GetJackDescription
427 489
  */
428
-PaError PaWasapi_GetJackCount( PaDeviceIndex nDevice, int *jcount );
490
+PaError PaWasapi_GetJackCount( PaDeviceIndex device, int *pJackCount );
429 491
 
430 492
 
431
-/** Get the jack description associated with a WASAPI device and jack number
493
+/** Get the jack description associated with a WASAPI device and jack number.
494
+
432 495
     Before this function is called, use PaWasapi_GetJackCount to determine the
433 496
     number of jacks associated with device.  If jcount is greater than zero, then
434 497
     each jack from 0 to jcount can be queried with this function to get the jack
@@ -436,19 +499,21 @@ PaError PaWasapi_GetJackCount( PaDeviceIndex nDevice, int *jcount );
436 499
 
437 500
  @note   Not available on UWP platform.
438 501
 
439
- @param  nDevice device index.
440
- @param  jindex  Which jack to return information
502
+ @param  device           Device index.
503
+ @param  jackIndex        Jack index.
441 504
  @param  pJackDescription Pointer to PaWasapiJackDescription.
442
- @return Error code indicating success or failure
505
+
506
+ @return Error code indicating success or failure.
443 507
  @see PaWasapi_GetJackCount
444 508
  */
445
-PaError PaWasapi_GetJackDescription( PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription );
509
+PaError PaWasapi_GetJackDescription( PaDeviceIndex device, int jackIndex, PaWasapiJackDescription *pJackDescription );
446 510
 
447 511
 
448 512
 /** Set default interface Id.
449
-    By default PA implementation will use DEVINTERFACE_AUDIO_RENDER and 
450
-    DEVINTERFACE_AUDIO_CAPTURE if device Id is not provided explicitly. These default Ids 
451
-    will not allow to use Exclusive mode on UWP platform and thus you must provide 
513
+
514
+    By default PA implementation will use DEVINTERFACE_AUDIO_RENDER and
515
+    DEVINTERFACE_AUDIO_CAPTURE if device Id is not provided explicitly. These default Ids
516
+    will not allow to use Exclusive mode on UWP platform and thus you must provide
452 517
     device Id explicitly via this API before calling Pa_OpenStream().
453 518
     Device Ids on UWP platform are obtainable via
454 519
     Windows::Media::Devices::MediaDevice::GetDefaultAudioRenderId() or
@@ -459,18 +524,30 @@ PaError PaWasapi_GetJackDescription( PaDeviceIndex nDevice, int jindex, PaWasapi
459 524
  @param  pId     Interface Id, pointer to the 16-bit Unicode string (WCHAR). If NULL then device Id
460 525
                  will be reset to the default, e.g. DEVINTERFACE_AUDIO_RENDER or DEVINTERFACE_AUDIO_CAPTURE.
461 526
  @param  bOutput TRUE (1) for output (render), FALSE (0) for input (capture).
527
+
462 528
  @return Error code indicating success or failure. Will return paIncompatibleStreamHostApi if PA is not compiled
463 529
          for UWP platform. If Id is longer than 4096 characters paBufferTooBig will be returned.
464 530
 */
465 531
 PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput );
466 532
 
467 533
 
534
+/** Set stream state handler.
535
+
536
+ @param  pStream        Pointer to PaStream object.
537
+ @param  fnStateHandler Pointer to state handling function.
538
+ @param  pUserData      Pointer to user data.
539
+
540
+ @return Error code indicating success or failure.
541
+*/
542
+PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCallback fnStateHandler, void *pUserData );
543
+
544
+
468 545
 /*
469 546
     IMPORTANT:
470 547
 
471 548
     WASAPI is implemented for Callback and Blocking interfaces. It supports Shared and Exclusive
472
-    share modes. 
473
-    
549
+    share modes.
550
+
474 551
     Exclusive Mode:
475 552
 
476 553
         Exclusive mode allows to deliver audio data directly to hardware bypassing
@@ -479,20 +556,20 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput );
479 556
 
480 557
     Callback Interface:
481 558
 
482
-        Provides best audio quality with low latency. Callback interface is implemented in 
559
+        Provides best audio quality with low latency. Callback interface is implemented in
483 560
         two versions:
484 561
 
485 562
         1) Event-Driven:
486 563
         This is the most powerful WASAPI implementation which provides glitch-free
487
-        audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is 
488
-        3 ms for HD Audio class audio chips. For the Shared mode latency can not be 
564
+        audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is
565
+        3 ms for HD Audio class audio chips. For the Shared mode latency can not be
489 566
         lower than 20 ms.
490 567
 
491 568
         2) Poll-Driven:
492 569
         Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven
493 570
         and provides latency at around 10-13ms. Polling must be used to overcome a system bug
494
-        under Windows Vista x64 when application is WOW64(32-bit) and Event-Driven method simply 
495
-        times out (event handle is never signalled on buffer completion). Please note, such WOW64 bug 
571
+        under Windows Vista x64 when application is WOW64(32-bit) and Event-Driven method simply
572
+        times out (event handle is never signalled on buffer completion). Please note, such WOW64 bug
496 573
         does not exist in Vista x86 or Windows 7.
497 574
         Polling can be setup by speciying 'paWinWasapiPolling' flag. Our WASAPI implementation detects
498 575
         WOW64 bug and sets 'paWinWasapiPolling' automatically.
@@ -501,44 +578,51 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput );
501 578
 
502 579
         Normally thread priority is set automatically and does not require modification. Although
503 580
         if user wants some tweaking thread priority can be modified by setting 'paWinWasapiThreadPriority'
504
-        flag and specifying 'PaWasapiStreamInfo::threadPriority' with value from PaWasapiThreadPriority 
581
+        flag and specifying 'PaWasapiStreamInfo::threadPriority' with value from PaWasapiThreadPriority
505 582
         enum.
506 583
 
507 584
     Blocking Interface:
508 585
 
509 586
         Blocking interface is implemented but due to above described Poll-Driven method can not
510
-        deliver lowest possible latency. Specifying too low latency in Shared mode will result in 
587
+        deliver lowest possible latency. Specifying too low latency in Shared mode will result in
511 588
         distorted audio although Exclusive mode adds stability.
512 589
 
513 590
     8.24 format:
514 591
 
515
-        If paCustomFormat is specified as sample format then the implementation will understand it 
592
+        If paCustomFormat is specified as sample format then the implementation will understand it
516 593
         as valid 24-bits inside 32-bit container (e.g. wBitsPerSample = 32, Samples.wValidBitsPerSample = 24).
517
-        
518
-        By using paCustomFormat there will be small optimization when samples are be copied 
519
-        with Copy_24_To_24 by PA processor instead of conversion from packed 3-byte (24-bit) data 
594
+
595
+        By using paCustomFormat there will be small optimization when samples are be copied
596
+        with Copy_24_To_24 by PA processor instead of conversion from packed 3-byte (24-bit) data
520 597
         with Int24_To_Int32.
521 598
 
522 599
     Pa_IsFormatSupported:
523 600
 
524
-        To check format with correct Share Mode (Exclusive/Shared) you must supply PaWasapiStreamInfo 
525
-        with flags paWinWasapiExclusive set through member of PaStreamParameters::hostApiSpecificStreamInfo 
526
-        structure. 
527
-        
528
-        If paWinWasapiExplicitSampleFormat flag is provided then implementation will not try to select 
529
-        suitable close format and will return an error instead of paFormatIsSupported. By specifying 
530
-        paWinWasapiExplicitSampleFormat flag it is possible to find out what sample formats are 
601
+        To check format with correct Share Mode (Exclusive/Shared) you must supply PaWasapiStreamInfo
602
+        with flags paWinWasapiExclusive set through member of PaStreamParameters::hostApiSpecificStreamInfo
603
+        structure.
604
+
605
+        If paWinWasapiExplicitSampleFormat flag is provided then implementation will not try to select
606
+        suitable close format and will return an error instead of paFormatIsSupported. By specifying
607
+        paWinWasapiExplicitSampleFormat flag it is possible to find out what sample formats are
531 608
         supported by Exclusive or Shared modes.
532 609
 
533 610
     Pa_OpenStream:
534 611
 
535 612
         To set desired Share Mode (Exclusive/Shared) you must supply
536
-        PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of 
613
+        PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of
537 614
         PaStreamParameters::hostApiSpecificStreamInfo structure.
615
+
616
+    Coding style for parameters and structure members of the public API:
617
+
618
+        1) bXXX - boolean, [1 (TRUE), 0 (FALSE)]
619
+        2) pXXX - pointer
620
+        3) fnXXX - pointer to function
621
+        4) structure members are never prefixed with a type distinguisher
538 622
 */
539 623
 
540 624
 #ifdef __cplusplus
541 625
 }
542 626
 #endif /* __cplusplus */
543 627
 
544
-#endif /* PA_WIN_WASAPI_H */                                  
628
+#endif /* PA_WIN_WASAPI_H */

+ 155
- 82
src/hostapi/wasapi/pa_win_wasapi.c View File

@@ -1,9 +1,10 @@
1 1
 /*
2 2
  * Portable Audio I/O Library WASAPI implementation
3
- * Copyright (c) 2006-2010 David Viens, Dmitry Kostjuchenko
3
+ * Copyright (c) 2006-2010 David Viens
4
+ * Copyright (c) 2010-2018 Dmitry Kostjuchenko
4 5
  *
5 6
  * Based on the Open Source API proposed by Ross Bencina
6
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
7
+ * Copyright (c) 1999-2018 Ross Bencina, Phil Burk
7 8
  *
8 9
  * Permission is hereby granted, free of charge, to any person obtaining
9 10
  * a copy of this software and associated documentation files
@@ -287,6 +288,10 @@ PA_THREAD_FUNC ProcThreadPoll(void *param);
287 288
 
288 289
 #define MAX_STR_LEN 512
289 290
 
291
+#ifdef PA_WINRT
292
+	#define PA_WASAPI_DEVICE_ID_LEN 4096
293
+#endif
294
+
290 295
 enum { S_INPUT = 0, S_OUTPUT = 1, S_COUNT = 2, S_FULLDUPLEX = 0 };
291 296
 
292 297
 // Number of packets which compose single contignous buffer. With trial and error it was calculated
@@ -334,12 +339,6 @@ FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
334 339
 FAvSetMmThreadPriority           pAvSetMmThreadPriority = NULL;
335 340
 #endif
336 341
 
337
-#ifdef PA_WINRT
338
-#define PA_WASAPI_DEVICE_ID_LEN 4096
339
-static OLECHAR g_DefaultRenderId[PA_WASAPI_DEVICE_ID_LEN] = { 0 };
340
-static OLECHAR g_DefaultCaptureId[PA_WASAPI_DEVICE_ID_LEN] = { 0 };
341
-#endif
342
-
343 342
 #define _GetProc(fun, type, name)  {                                                        \
344 343
                                         fun = (type) GetProcAddress(hDInputDLL,name);       \
345 344
                                         if (fun == NULL) {                                  \
@@ -447,15 +446,15 @@ typedef struct
447 446
 
448 447
     PaWinUtilComInitializationResult comInitializationResult;
449 448
 
450
-    //this is the REAL number of devices, whether they are usefull to PA or not!
449
+    // this is the REAL number of devices, whether they are usefull to PA or not!
451 450
     UINT32 deviceCount;
452 451
 
453
-    WCHAR defaultRenderer [MAX_STR_LEN];
454
-    WCHAR defaultCapturer [MAX_STR_LEN];
452
+    WCHAR defaultRenderer[MAX_STR_LEN];
453
+    WCHAR defaultCapturer[MAX_STR_LEN];
455 454
 
456 455
     PaWasapiDeviceInfo *devInfo;
457 456
 
458
-	// Is true when WOW64 Vista/7 Workaround is needed
457
+	// is TRUE when WOW64 Vista/7 Workaround is needed
459 458
 	BOOL useWOW64Workaround;
460 459
 }
461 460
 PaWasapiHostApiRepresentation;
@@ -579,6 +578,10 @@ typedef struct PaWasapiStream
579 578
 
580 579
 	// Thread priority level
581 580
 	PaWasapiThreadPriority nThreadPriority;
581
+
582
+	// State handler
583
+	PaWasapiStreamStateCallback fnStateHandler;
584
+	void *pStateHandlerUserData;
582 585
 }
583 586
 PaWasapiStream;
584 587
 
@@ -601,6 +604,10 @@ static void PaWasapi_FreeMemory(void *ptr);
601 604
 static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *fmtext);
602 605
 
603 606
 // Local statics
607
+#ifdef PA_WINRT
608
+static OLECHAR g_DefaultRenderId[PA_WASAPI_DEVICE_ID_LEN] = { 0 };
609
+static OLECHAR g_DefaultCaptureId[PA_WASAPI_DEVICE_ID_LEN] = { 0 };
610
+#endif
604 611
 
605 612
 // ------------------------------------------------------------------------------------------
606 613
 #define LogHostError(HRES) __LogHostError(HRES, __FUNCTION__, __FILE__, __LINE__)
@@ -846,7 +853,7 @@ static UINT32 ALIGN_FWD(UINT32 v, UINT32 align)
846 853
 
847 854
 // ------------------------------------------------------------------------------------------
848 855
 // Get next value power of 2
849
-UINT32 ALIGN_NEXT_POW2(UINT32 v)
856
+static UINT32 ALIGN_NEXT_POW2(UINT32 v)
850 857
 {
851 858
 	UINT32 v2 = 1;
852 859
 	while (v > (v2 <<= 1)) { }
@@ -1579,6 +1586,18 @@ static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn,
1579 1586
 #endif
1580 1587
 
1581 1588
 // ------------------------------------------------------------------------------------------
1589
+static void NotifyStateChanged(PaWasapiStream *stream, UINT32 flags, HRESULT hr)
1590
+{
1591
+	if (stream->fnStateHandler == NULL)
1592
+		return;
1593
+
1594
+	if (FAILED(hr))
1595
+		flags |= paWasapiStreamStateError;
1596
+	
1597
+	stream->fnStateHandler((PaStream *)stream, flags, hr, stream->pStateHandlerUserData);
1598
+}
1599
+
1600
+// ------------------------------------------------------------------------------------------
1582 1601
 static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostApiIndex hostApiIndex)
1583 1602
 {
1584 1603
 	PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
@@ -1679,7 +1698,8 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
1679 1698
 	}
1680 1699
 #endif
1681 1700
 
1682
-    paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_AllocateMemory(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);
1701
+    paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(
1702
+		paWasapi->allocations, sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);
1683 1703
     if (paWasapi->devInfo == NULL)
1684 1704
 	{
1685 1705
         result = paInsufficientMemory;
@@ -2008,7 +2028,7 @@ error:
2008 2028
 // ------------------------------------------------------------------------------------------
2009 2029
 PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
2010 2030
 {
2011
-    PaError result = paInternalError;
2031
+    PaError result;
2012 2032
     PaWasapiHostApiRepresentation *paWasapi;
2013 2033
 
2014 2034
 #ifndef PA_WINRT
@@ -2027,10 +2047,12 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
2027 2047
     }	
2028 2048
     memset(paWasapi, 0, sizeof(PaWasapiHostApiRepresentation)); /* ensure all fields are zeroed. especially paWasapi->allocations */
2029 2049
 
2050
+	// Initialize COM subsystem
2030 2051
     result = PaWinUtil_CoInitialize(paWASAPI, &paWasapi->comInitializationResult);
2031 2052
     if (result != paNoError)
2032 2053
         goto error;
2033 2054
 
2055
+	// Create memory group
2034 2056
     paWasapi->allocations = PaUtil_CreateAllocationGroup();
2035 2057
     if (paWasapi->allocations == NULL)
2036 2058
 	{
@@ -2086,15 +2108,20 @@ static void ReleaseWasapiDeviceInfoList( PaWasapiHostApiRepresentation *paWasapi
2086 2108
 {
2087 2109
 	UINT32 i;
2088 2110
 
2089
-	// Release device info bound objects and device info itself
2111
+	// Release device info bound objects
2090 2112
     for (i = 0; i < paWasapi->deviceCount; ++i)
2091 2113
 	{
2092 2114
 	#ifndef PA_WINRT
2093 2115
         SAFE_RELEASE(paWasapi->devInfo[i].device);
2094 2116
 	#endif
2095 2117
     }
2096
-    PaUtil_FreeMemory(paWasapi->devInfo);
2097 2118
 
2119
+	// Free device info
2120
+	if (paWasapi->allocations != NULL)
2121
+		PaUtil_GroupFreeMemory(paWasapi->allocations, paWasapi->devInfo);
2122
+
2123
+	// Be ready for a device list reinitialization and if its creation is failed pointers must not be dangling
2124
+	paWasapi->devInfo = NULL;
2098 2125
 	paWasapi->deviceCount = 0;
2099 2126
 }
2100 2127
 
@@ -2105,16 +2132,20 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
2105 2132
 	if (paWasapi == NULL)
2106 2133
 		return;
2107 2134
 
2135
+	// Release device list
2108 2136
 	ReleaseWasapiDeviceInfoList(paWasapi);
2109 2137
 
2138
+	// Free allocations and memory group itself
2110 2139
     if (paWasapi->allocations != NULL)
2111 2140
 	{
2112 2141
         PaUtil_FreeAllAllocations(paWasapi->allocations);
2113 2142
         PaUtil_DestroyAllocationGroup(paWasapi->allocations);
2114 2143
     }
2115 2144
 
2116
-    PaWinUtil_CoUninitialize( paWASAPI, &paWasapi->comInitializationResult );
2145
+	// Release COM subsystem
2146
+    PaWinUtil_CoUninitialize(paWASAPI, &paWasapi->comInitializationResult);
2117 2147
 
2148
+	// Free API representation
2118 2149
     PaUtil_FreeMemory(paWasapi);
2119 2150
 
2120 2151
 	// Close AVRT
@@ -2122,18 +2153,19 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
2122 2153
 }
2123 2154
 
2124 2155
 // ------------------------------------------------------------------------------------------
2125
-static PaWasapiHostApiRepresentation *_GetHostApi(PaError *_error)
2156
+static PaWasapiHostApiRepresentation *_GetHostApi(PaError *ret)
2126 2157
 {
2127 2158
 	PaError error;
2128
-
2129 2159
 	PaUtilHostApiRepresentation *pApi;
2160
+
2130 2161
 	if ((error = PaUtil_GetHostApiRepresentation(&pApi, paWASAPI)) != paNoError)
2131 2162
 	{
2132
-		if (_error != NULL)
2133
-			(*_error) = error;
2163
+		if (ret != NULL)
2164
+			(*ret) = error;
2134 2165
 
2135 2166
 		return NULL;
2136 2167
 	}
2168
+
2137 2169
 	return (PaWasapiHostApiRepresentation *)pApi;
2138 2170
 }
2139 2171
 
@@ -2148,7 +2180,11 @@ static PaError UpdateDeviceList()
2148 2180
 	// Get API
2149 2181
 	hostApi = (PaUtilHostApiRepresentation *)(paWasapi = _GetHostApi(&ret));
2150 2182
 	if (paWasapi == NULL)
2151
-		return ret;
2183
+		return paNotInitialized;
2184
+
2185
+	// Make sure initialized properly
2186
+	if (paWasapi->allocations == NULL)
2187
+		return paNotInitialized;
2152 2188
 
2153 2189
 	// Release WASAPI internal device info list
2154 2190
 	ReleaseWasapiDeviceInfoList(paWasapi);
@@ -2163,6 +2199,8 @@ static PaError UpdateDeviceList()
2163 2199
 		PaUtil_GroupFreeMemory(paWasapi->allocations, hostApi->deviceInfos[0]);
2164 2200
 		PaUtil_GroupFreeMemory(paWasapi->allocations, hostApi->deviceInfos);
2165 2201
 
2202
+		// Be ready for a device list reinitialization and if its creation is failed pointers must not be dangling
2203
+		hostApi->deviceInfos = NULL;
2166 2204
 		hostApi->info.deviceCount = 0;
2167 2205
 		hostApi->info.defaultInputDevice = paNoDevice;
2168 2206
 		hostApi->info.defaultOutputDevice = paNoDevice;
@@ -2184,7 +2222,7 @@ PaError PaWasapi_UpdateDeviceList()
2184 2222
 #endif
2185 2223
 
2186 2224
 // ------------------------------------------------------------------------------------------
2187
-int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int nFormatSize, int bOutput )
2225
+int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int formatSize, int bOutput )
2188 2226
 {
2189 2227
 	UINT32 size;
2190 2228
 	WAVEFORMATEXTENSIBLE *format;
@@ -2195,14 +2233,14 @@ int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned
2195 2233
 	
2196 2234
 	format = (bOutput == TRUE ? &stream->out.wavex : &stream->in.wavex);
2197 2235
 
2198
-	size = min(nFormatSize, (UINT32)sizeof(*format));
2236
+	size = min(formatSize, (UINT32)sizeof(*format));
2199 2237
 	memcpy(pFormat, format, size);
2200 2238
 
2201 2239
 	return size;
2202 2240
 }
2203 2241
 
2204 2242
 // ------------------------------------------------------------------------------------------
2205
-int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice )
2243
+int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device )
2206 2244
 {
2207 2245
 	PaError ret;
2208 2246
 	PaWasapiHostApiRepresentation *paWasapi;
@@ -2211,7 +2249,7 @@ int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, Pa
2211 2249
 
2212 2250
 	if (pFormat == NULL)
2213 2251
 		return paBadBufferPtr;
2214
-	if (nFormatSize <= 0)
2252
+	if (formatSize <= 0)
2215 2253
 		return paBufferTooSmall;
2216 2254
 
2217 2255
 	// Get API
@@ -2220,7 +2258,7 @@ int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, Pa
2220 2258
 		return ret;
2221 2259
 
2222 2260
 	// Get device index
2223
-	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
2261
+	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep);
2224 2262
     if (ret != paNoError)
2225 2263
         return ret;
2226 2264
 
@@ -2228,14 +2266,14 @@ int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, Pa
2228 2266
 	if ((UINT32)index >= paWasapi->deviceCount)
2229 2267
 		return paInvalidDevice;
2230 2268
 	
2231
-	size = min(nFormatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].DefaultFormat));
2269
+	size = min(formatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].DefaultFormat));
2232 2270
 	memcpy(pFormat, &paWasapi->devInfo[ index ].DefaultFormat, size);
2233 2271
 
2234 2272
 	return size;
2235 2273
 }
2236 2274
 
2237 2275
 // ------------------------------------------------------------------------------------------
2238
-int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice )
2276
+int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device )
2239 2277
 {
2240 2278
 	PaError ret;
2241 2279
 	PaWasapiHostApiRepresentation *paWasapi;
@@ -2244,7 +2282,7 @@ int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDevi
2244 2282
 
2245 2283
 	if (pFormat == NULL)
2246 2284
 		return paBadBufferPtr;
2247
-	if (nFormatSize <= 0)
2285
+	if (formatSize <= 0)
2248 2286
 		return paBufferTooSmall;
2249 2287
 
2250 2288
 	// Get API
@@ -2253,7 +2291,7 @@ int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDevi
2253 2291
 		return ret;
2254 2292
 
2255 2293
 	// Get device index
2256
-	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
2294
+	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep);
2257 2295
     if (ret != paNoError)
2258 2296
         return ret;
2259 2297
 
@@ -2261,14 +2299,14 @@ int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDevi
2261 2299
 	if ((UINT32)index >= paWasapi->deviceCount)
2262 2300
 		return paInvalidDevice;
2263 2301
 	
2264
-	size = min(nFormatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].MixFormat));
2302
+	size = min(formatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].MixFormat));
2265 2303
 	memcpy(pFormat, &paWasapi->devInfo[ index ].MixFormat, size);
2266 2304
 
2267 2305
 	return size;
2268 2306
 }
2269 2307
 
2270 2308
 // ------------------------------------------------------------------------------------------
2271
-int PaWasapi_GetDeviceRole( PaDeviceIndex nDevice )
2309
+int PaWasapi_GetDeviceRole( PaDeviceIndex device )
2272 2310
 {
2273 2311
 	PaError ret;
2274 2312
 	PaDeviceIndex index;
@@ -2279,7 +2317,7 @@ int PaWasapi_GetDeviceRole( PaDeviceIndex nDevice )
2279 2317
 		return paNotInitialized;
2280 2318
 
2281 2319
 	// Get device index
2282
-	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
2320
+	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep);
2283 2321
     if (ret != paNoError)
2284 2322
         return ret;
2285 2323
 
@@ -2291,17 +2329,17 @@ int PaWasapi_GetDeviceRole( PaDeviceIndex nDevice )
2291 2329
 }
2292 2330
 
2293 2331
 // ------------------------------------------------------------------------------------------
2294
-PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput )
2332
+PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *pInput, unsigned int *pOutput )
2295 2333
 {
2296 2334
     PaWasapiStream *stream = (PaWasapiStream *)pStream;
2297 2335
 	if (stream == NULL)
2298 2336
 		return paBadStreamPtr;
2299 2337
 
2300
-	if (nInput != NULL)
2301
-		(*nInput) = stream->in.framesPerHostCallback;
2338
+	if (pInput != NULL)
2339
+		(*pInput) = stream->in.framesPerHostCallback;
2302 2340
 
2303
-	if (nOutput != NULL)
2304
-		(*nOutput) = stream->out.framesPerHostCallback;
2341
+	if (pOutput != NULL)
2342
+		(*pOutput) = stream->out.framesPerHostCallback;
2305 2343
 
2306 2344
 	return paNoError;
2307 2345
 }
@@ -4844,19 +4882,19 @@ static void MMCSS_deactivate(HANDLE hTask)
4844 4882
 #endif
4845 4883
 
4846 4884
 // ------------------------------------------------------------------------------------------
4847
-PaError PaWasapi_ThreadPriorityBoost(void **hTask, PaWasapiThreadPriority nPriorityClass)
4885
+PaError PaWasapi_ThreadPriorityBoost(void **pTask, PaWasapiThreadPriority priorityClass)
4848 4886
 {
4849 4887
 	HANDLE task;
4850 4888
 	PaError ret;
4851 4889
 
4852
-	if (hTask == NULL)
4890
+	if (pTask == NULL)
4853 4891
 		return paUnanticipatedHostError;
4854 4892
 
4855 4893
 #ifndef PA_WINRT
4856
-	if ((ret = MMCSS_activate(nPriorityClass, &task)) != paNoError)
4894
+	if ((ret = MMCSS_activate(priorityClass, &task)) != paNoError)
4857 4895
 		return ret;
4858 4896
 #else
4859
-	switch (nPriorityClass)
4897
+	switch (priorityClass)
4860 4898
 	{
4861 4899
 	case eThreadPriorityAudio:
4862 4900
 	case eThreadPriorityProAudio: {
@@ -4880,21 +4918,21 @@ PaError PaWasapi_ThreadPriorityBoost(void **hTask, PaWasapiThreadPriority nPrior
4880 4918
 	}
4881 4919
 #endif
4882 4920
 
4883
-	(*hTask) = task;
4921
+	(*pTask) = task;
4884 4922
 	return ret;
4885 4923
 }
4886 4924
 
4887 4925
 // ------------------------------------------------------------------------------------------
4888
-PaError PaWasapi_ThreadPriorityRevert(void *hTask)
4926
+PaError PaWasapi_ThreadPriorityRevert(void *pTask)
4889 4927
 {
4890
-	if (hTask == NULL)
4928
+	if (pTask == NULL)
4891 4929
 		return paUnanticipatedHostError;
4892 4930
 
4893 4931
 #ifndef PA_WINRT
4894
-	MMCSS_deactivate((HANDLE)hTask);
4932
+	MMCSS_deactivate((HANDLE)pTask);
4895 4933
 #else
4896 4934
 	// Revert previous priority by removing 0x80000000 mask
4897
-	if (SetThreadPriority(GetCurrentThread(), (int)((intptr_t)hTask & ~0x80000000)) == FALSE)
4935
+	if (SetThreadPriority(GetCurrentThread(), (int)((intptr_t)pTask & ~0x80000000)) == FALSE)
4898 4936
 		return paUnanticipatedHostError;
4899 4937
 #endif
4900 4938
 
@@ -4905,7 +4943,7 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask)
4905 4943
 // Described at:
4906 4944
 // http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx
4907 4945
 
4908
-PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount)
4946
+PaError PaWasapi_GetJackCount(PaDeviceIndex device, int *pJackCount)
4909 4947
 {
4910 4948
 #ifndef PA_WINRT
4911 4949
 	PaError ret;
@@ -4922,47 +4960,50 @@ PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount)
4922 4960
 	if (paWasapi == NULL)
4923 4961
 		return paNotInitialized;
4924 4962
 
4925
-	// Get device index.
4926
-	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
4963
+	if (pJackCount == NULL)
4964
+		return paUnanticipatedHostError;
4965
+
4966
+	// Get device index
4967
+	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep);
4927 4968
     if (ret != paNoError)
4928 4969
         return ret;
4929 4970
 
4930
-	// Validate index.
4971
+	// Validate index
4931 4972
 	if ((UINT32)index >= paWasapi->deviceCount)
4932 4973
 		return paInvalidDevice;
4933 4974
 
4934
-	// Get the endpoint device's IDeviceTopology interface.
4975
+	// Get the endpoint device's IDeviceTopology interface
4935 4976
 	hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology,
4936 4977
 		CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology);
4937 4978
 	IF_FAILED_JUMP(hr, error);
4938 4979
 
4939
-    // The device topology for an endpoint device always contains just one connector (connector number 0).
4980
+    // The device topology for an endpoint device always contains just one connector (connector number 0)
4940 4981
 	hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom);
4941 4982
 	IF_FAILED_JUMP(hr, error);
4942 4983
 
4943
-    // Step across the connection to the jack on the adapter.
4984
+    // Step across the connection to the jack on the adapter
4944 4985
 	hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo);
4945 4986
     if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
4946 4987
     {
4947
-        // The adapter device is not currently active.
4988
+        // The adapter device is not currently active
4948 4989
         hr = E_NOINTERFACE;
4949 4990
     }
4950 4991
 	IF_FAILED_JUMP(hr, error);
4951 4992
 
4952
-	// Get the connector's IPart interface.
4993
+	// Get the connector's IPart interface
4953 4994
 	hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart);
4954 4995
 	IF_FAILED_JUMP(hr, error);
4955 4996
 
4956
-	// Activate the connector's IKsJackDescription interface.
4997
+	// Activate the connector's IKsJackDescription interface
4957 4998
 	hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc);
4958 4999
 	IF_FAILED_JUMP(hr, error);
4959 5000
 
4960
-	// Return jack count for this device.
5001
+	// Return jack count for this device
4961 5002
 	hr = IKsJackDescription_GetJackCount(pJackDesc, &jackCount);
4962 5003
 	IF_FAILED_JUMP(hr, error);
4963 5004
 
4964 5005
 	// Set.
4965
-	(*jcount) = jackCount;
5006
+	(*pJackCount) = jackCount;
4966 5007
 
4967 5008
 	// Ok.
4968 5009
 	ret = paNoError;
@@ -4978,8 +5019,8 @@ error:
4978 5019
 	LogHostError(hr);
4979 5020
 	return paNoError;
4980 5021
 #else
4981
-	(void)nDevice;
4982
-	(void)jcount;
5022
+	(void)device;
5023
+	(void)pJackCount;
4983 5024
 	return paUnanticipatedHostError;
4984 5025
 #endif
4985 5026
 }
@@ -5077,7 +5118,7 @@ static PaWasapiJackPortConnection _ConvertJackPortConnectionWASAPIToPA(int portC
5077 5118
 // Described at:
5078 5119
 // http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx
5079 5120
 
5080
-PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription)
5121
+PaError PaWasapi_GetJackDescription(PaDeviceIndex device, int jackIndex, PaWasapiJackDescription *pJackDescription)
5081 5122
 {
5082 5123
 #ifndef PA_WINRT
5083 5124
 	PaError ret;
@@ -5094,46 +5135,46 @@ PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJ
5094 5135
 	if (paWasapi == NULL)
5095 5136
 		return paNotInitialized;
5096 5137
 
5097
-	// Get device index.
5098
-	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
5138
+	// Get device index
5139
+	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep);
5099 5140
     if (ret != paNoError)
5100 5141
         return ret;
5101 5142
 
5102
-	// Validate index.
5143
+	// Validate index
5103 5144
 	if ((UINT32)index >= paWasapi->deviceCount)
5104 5145
 		return paInvalidDevice;
5105 5146
 
5106
-	// Get the endpoint device's IDeviceTopology interface.
5147
+	// Get the endpoint device's IDeviceTopology interface
5107 5148
 	hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology,
5108 5149
 		CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology);
5109 5150
 	IF_FAILED_JUMP(hr, error);
5110 5151
 
5111
-    // The device topology for an endpoint device always contains just one connector (connector number 0).
5152
+    // The device topology for an endpoint device always contains just one connector (connector number 0)
5112 5153
 	hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom);
5113 5154
 	IF_FAILED_JUMP(hr, error);
5114 5155
 
5115
-    // Step across the connection to the jack on the adapter.
5156
+    // Step across the connection to the jack on the adapter
5116 5157
 	hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo);
5117 5158
     if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
5118 5159
     {
5119
-        // The adapter device is not currently active.
5160
+        // The adapter device is not currently active
5120 5161
         hr = E_NOINTERFACE;
5121 5162
     }
5122 5163
 	IF_FAILED_JUMP(hr, error);
5123 5164
 
5124
-	// Get the connector's IPart interface.
5165
+	// Get the connector's IPart interface
5125 5166
 	hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart);
5126 5167
 	IF_FAILED_JUMP(hr, error);
5127 5168
 
5128
-	// Activate the connector's IKsJackDescription interface.
5169
+	// Activate the connector's IKsJackDescription interface
5129 5170
 	hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc);
5130 5171
 	IF_FAILED_JUMP(hr, error);
5131 5172
 
5132
-	// Test to return jack description struct for index 0.
5133
-	hr = IKsJackDescription_GetJackDescription(pJackDesc, jindex, &jack);
5173
+	// Test to return jack description struct for index 0
5174
+	hr = IKsJackDescription_GetJackDescription(pJackDesc, jackIndex, &jack);
5134 5175
 	IF_FAILED_JUMP(hr, error);
5135 5176
 
5136
-	// Convert WASAPI values to PA format.
5177
+	// Convert WASAPI values to PA format
5137 5178
 	pJackDescription->channelMapping = jack.ChannelMapping;
5138 5179
 	pJackDescription->color          = jack.Color;
5139 5180
 	pJackDescription->connectionType = _ConvertJackConnectionTypeWASAPIToPA(jack.ConnectionType);
@@ -5142,7 +5183,7 @@ PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJ
5142 5183
 	pJackDescription->isConnected    = jack.IsConnected;
5143 5184
 	pJackDescription->portConnection = _ConvertJackPortConnectionWASAPIToPA(jack.PortConnection);
5144 5185
 
5145
-	// Ok.
5186
+	// Ok
5146 5187
 	ret = paNoError;
5147 5188
 
5148 5189
 error:
@@ -5157,8 +5198,8 @@ error:
5157 5198
 	return ret;
5158 5199
 
5159 5200
 #else
5160
-	(void)nDevice;
5161
-	(void)jindex;
5201
+	(void)device;
5202
+	(void)jackIndex;
5162 5203
 	(void)pJackDescription;
5163 5204
 	return paUnanticipatedHostError;
5164 5205
 #endif
@@ -5183,11 +5224,12 @@ PaError PaWasapi_GetAudioClient(PaStream *pStream, void **pAudioClient, int bOut
5183 5224
 PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput )
5184 5225
 {
5185 5226
 #ifdef PA_WINRT
5227
+	int i;
5186 5228
 
5187 5229
 	// Validate Id length
5188 5230
 	if (pId != NULL)
5189 5231
 	{
5190
-		for (int i = 0; pId[i] != 0; ++i)
5232
+		for (i = 0; pId[i] != 0; ++i)
5191 5233
 		{
5192 5234
 			if (i >= PA_WASAPI_DEVICE_ID_LEN)
5193 5235
 				return paBufferTooBig;
@@ -5200,7 +5242,7 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput )
5200 5242
 		memset(g_DefaultRenderId, 0, sizeof(g_DefaultRenderId));
5201 5243
 		if (pId != NULL)
5202 5244
 		{
5203
-			for (int i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultRenderId)); ++i)
5245
+			for (i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultRenderId)); ++i)
5204 5246
 				g_DefaultRenderId[i] = pId[i];
5205 5247
 		}
5206 5248
 	}
@@ -5209,7 +5251,7 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput )
5209 5251
 		memset(g_DefaultCaptureId, 0, sizeof(g_DefaultCaptureId));
5210 5252
 		if (pId != NULL)
5211 5253
 		{
5212
-			for (int i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultCaptureId)); ++i)
5254
+			for (i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultCaptureId)); ++i)
5213 5255
 				g_DefaultCaptureId[i] = pId[i];
5214 5256
 		}
5215 5257
 	}
@@ -5222,6 +5264,19 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput )
5222 5264
 }
5223 5265
 
5224 5266
 // ------------------------------------------------------------------------------------------
5267
+PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCallback fnStateHandler, void *pUserData )
5268
+{
5269
+	PaWasapiStream *stream = (PaWasapiStream *)pStream;
5270
+	if (stream == NULL)
5271
+		return paBadStreamPtr;
5272
+
5273
+	stream->fnStateHandler        = fnStateHandler;
5274
+	stream->pStateHandlerUserData = pUserData;
5275
+
5276
+	return paNoError;
5277
+}
5278
+
5279
+// ------------------------------------------------------------------------------------------
5225 5280
 HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available)
5226 5281
 {
5227 5282
 	HRESULT hr;
@@ -5448,6 +5503,9 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
5448 5503
 	BOOL bWaitAllEvents = FALSE;
5449 5504
 	BOOL bThreadComInitialized = FALSE;
5450 5505
 
5506
+	// Notify: state
5507
+	NotifyStateChanged(stream, paWasapiStreamStateThreadPrepare, ERROR_SUCCESS);
5508
+
5451 5509
 	/*
5452 5510
 	If COM is already initialized CoInitialize will either return
5453 5511
 	FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different
@@ -5560,6 +5618,9 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
5560 5618
 	// Notify: thread started
5561 5619
 	SetEvent(stream->hThreadStart);
5562 5620
 
5621
+	// Notify: state
5622
+	NotifyStateChanged(stream, paWasapiStreamStateThreadStart, ERROR_SUCCESS);
5623
+
5563 5624
 	// Processing Loop
5564 5625
 	for (;;)
5565 5626
     {
@@ -5627,6 +5688,9 @@ thread_end:
5627 5688
 	// Notify: thread exited
5628 5689
 	SetEvent(stream->hThreadExit);
5629 5690
 
5691
+	// Notify: state
5692
+	NotifyStateChanged(stream, paWasapiStreamStateThreadStop, hr);
5693
+
5630 5694
 	return 0;
5631 5695
 
5632 5696
 thread_error:
@@ -5655,6 +5719,9 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
5655 5719
 
5656 5720
 	BOOL bThreadComInitialized = FALSE;
5657 5721
 
5722
+	// Notify: state
5723
+	NotifyStateChanged(stream, paWasapiStreamStateThreadPrepare, ERROR_SUCCESS);
5724
+
5658 5725
 	/*
5659 5726
 	If COM is already initialized CoInitialize will either return
5660 5727
 	FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different
@@ -5797,6 +5864,9 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
5797 5864
 	// Notify: thread started
5798 5865
 	SetEvent(stream->hThreadStart);
5799 5866
 
5867
+	// Notify: state
5868
+	NotifyStateChanged(stream, paWasapiStreamStateThreadStart, ERROR_SUCCESS);
5869
+
5800 5870
 	if (!PA_WASAPI__IS_FULLDUPLEX(stream))
5801 5871
 	{
5802 5872
 		// Processing Loop
@@ -6152,6 +6222,9 @@ thread_end:
6152 6222
 	// Notify: thread exited
6153 6223
 	SetEvent(stream->hThreadExit);
6154 6224
 
6225
+	// Notify: state
6226
+	NotifyStateChanged(stream, paWasapiStreamStateThreadStop, hr);
6227
+
6155 6228
 	return 0;
6156 6229
 
6157 6230
 thread_error:

Loading…
Cancel
Save