2 * Wine Driver for PulseAudio
3 * http://pulseaudio.org/
5 * Copyright 2009 Arthur Taylor <theycallhimart@gmail.com>
7 * Contains code from other wine sound drivers.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
44 #ifdef HAVE_PULSEAUDIO
46 #include "wine/unicode.h"
47 #include "wine/debug.h"
48 #include "wine/library.h"
50 #include <winepulse.h>
51 #include <pulse/pulseaudio.h>
52 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
54 /* These strings used only for tracing */
55 const char * PULSE_getCmdString(enum win_wm_message msg
) {
56 static char unknown
[32];
57 #define MSG_TO_STR(x) case x: return #x
59 MSG_TO_STR(WINE_WM_PAUSING
);
60 MSG_TO_STR(WINE_WM_RESTARTING
);
61 MSG_TO_STR(WINE_WM_RESETTING
);
62 MSG_TO_STR(WINE_WM_HEADER
);
63 MSG_TO_STR(WINE_WM_BREAKLOOP
);
64 MSG_TO_STR(WINE_WM_CLOSING
);
65 MSG_TO_STR(WINE_WM_STARTING
);
66 MSG_TO_STR(WINE_WM_STOPPING
);
67 MSG_TO_STR(WINE_WM_XRUN
);
68 MSG_TO_STR(WINE_WM_FEED
);
71 sprintf(unknown
, "UNKNOWN(0x%08x)", msg
);
75 /*======================================================================*
76 * Ring Buffer Functions - copied from winealsa.drv *
77 *======================================================================*/
79 /* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
83 #define INIT_OMR(omr) do { if (pipe(omr->msg_pipe) < 0) { omr->msg_pipe[0] = omr->msg_pipe[1] = -1; } } while (0)
84 #define CLOSE_OMR(omr) do { close(omr->msg_pipe[0]); close(omr->msg_pipe[1]); } while (0)
85 #define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
86 #define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
87 #define RESET_OMR(omr) do { } while (0)
88 #define WAIT_OMR(omr, sleep) \
89 do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
90 pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
92 #define INIT_OMR(omr) do { omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
93 #define CLOSE_OMR(omr) do { CloseHandle(omr->msg_event); } while (0)
94 #define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
95 #define CLEAR_OMR(omr) do { } while (0)
96 #define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
97 #define WAIT_OMR(omr, sleep) \
98 do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
101 #define PULSE_RING_BUFFER_INCREMENT 64
103 /******************************************************************
104 * PULSE_InitRingMessage
106 * Initialize the ring of messages for passing between driver's caller
107 * and playback/record thread
109 int PULSE_InitRingMessage(PULSE_MSG_RING
* omr
)
114 omr
->ring_buffer_size
= PULSE_RING_BUFFER_INCREMENT
;
115 omr
->messages
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,omr
->ring_buffer_size
* sizeof(PULSE_MSG
));
117 InitializeCriticalSection(&omr
->msg_crst
);
118 omr
->msg_crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PULSE_MSG_RING.msg_crst");
122 /******************************************************************
123 * PULSE_DestroyRingMessage
126 int PULSE_DestroyRingMessage(PULSE_MSG_RING
* omr
)
129 HeapFree(GetProcessHeap(),0,omr
->messages
);
130 omr
->messages
= NULL
;
131 omr
->ring_buffer_size
= PULSE_RING_BUFFER_INCREMENT
;
132 omr
->msg_crst
.DebugInfo
->Spare
[0] = 0;
133 DeleteCriticalSection(&omr
->msg_crst
);
136 /******************************************************************
137 * PULSE_ResetRingMessage
140 void PULSE_ResetRingMessage(PULSE_MSG_RING
* omr
)
145 /******************************************************************
146 * PULSE_WaitRingMessage
149 void PULSE_WaitRingMessage(PULSE_MSG_RING
* omr
, DWORD sleep
)
151 WAIT_OMR(omr
, sleep
);
154 /******************************************************************
155 * PULSE_AddRingMessage
157 * Inserts a new message into the ring (should be called from DriverProc derived routines)
159 int PULSE_AddRingMessage(PULSE_MSG_RING
* omr
, enum win_wm_message msg
, DWORD param
, BOOL wait
)
161 HANDLE hEvent
= INVALID_HANDLE_VALUE
;
163 EnterCriticalSection(&omr
->msg_crst
);
164 if ((omr
->msg_toget
== ((omr
->msg_tosave
+ 1) % omr
->ring_buffer_size
)))
166 int old_ring_buffer_size
= omr
->ring_buffer_size
;
167 omr
->ring_buffer_size
+= PULSE_RING_BUFFER_INCREMENT
;
168 omr
->messages
= HeapReAlloc(GetProcessHeap(),0,omr
->messages
, omr
->ring_buffer_size
* sizeof(PULSE_MSG
));
169 /* Now we need to rearrange the ring buffer so that the new
170 buffers just allocated are in between omr->msg_tosave and
173 if (omr
->msg_tosave
< omr
->msg_toget
)
175 memmove(&(omr
->messages
[omr
->msg_toget
+ PULSE_RING_BUFFER_INCREMENT
]),
176 &(omr
->messages
[omr
->msg_toget
]),
177 sizeof(PULSE_MSG
)*(old_ring_buffer_size
- omr
->msg_toget
)
179 omr
->msg_toget
+= PULSE_RING_BUFFER_INCREMENT
;
184 hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
185 if (hEvent
== INVALID_HANDLE_VALUE
)
187 ERR("can't create event !?\n");
188 LeaveCriticalSection(&omr
->msg_crst
);
191 /* fast messages have to be added at the start of the queue */
192 omr
->msg_toget
= (omr
->msg_toget
+ omr
->ring_buffer_size
- 1) % omr
->ring_buffer_size
;
194 omr
->messages
[omr
->msg_toget
].msg
= msg
;
195 omr
->messages
[omr
->msg_toget
].param
= param
;
196 omr
->messages
[omr
->msg_toget
].hEvent
= hEvent
;
200 omr
->messages
[omr
->msg_tosave
].msg
= msg
;
201 omr
->messages
[omr
->msg_tosave
].param
= param
;
202 omr
->messages
[omr
->msg_tosave
].hEvent
= INVALID_HANDLE_VALUE
;
203 omr
->msg_tosave
= (omr
->msg_tosave
+ 1) % omr
->ring_buffer_size
;
205 LeaveCriticalSection(&omr
->msg_crst
);
206 /* signal a new message */
210 /* wait for playback/record thread to have processed the message */
211 WaitForSingleObject(hEvent
, INFINITE
);
217 /******************************************************************
218 * PULSE_RetrieveRingMessage
220 * Get a message from the ring. Should be called by the playback/record thread.
222 int PULSE_RetrieveRingMessage(PULSE_MSG_RING
* omr
,
223 enum win_wm_message
*msg
, DWORD
*param
, HANDLE
*hEvent
)
225 EnterCriticalSection(&omr
->msg_crst
);
227 if (omr
->msg_toget
== omr
->msg_tosave
) /* buffer empty ? */
229 LeaveCriticalSection(&omr
->msg_crst
);
233 *msg
= omr
->messages
[omr
->msg_toget
].msg
;
234 omr
->messages
[omr
->msg_toget
].msg
= 0;
235 *param
= omr
->messages
[omr
->msg_toget
].param
;
236 *hEvent
= omr
->messages
[omr
->msg_toget
].hEvent
;
237 omr
->msg_toget
= (omr
->msg_toget
+ 1) % omr
->ring_buffer_size
;
239 LeaveCriticalSection(&omr
->msg_crst
);
243 /**************************************************************************
245 *************************************************************************/
247 /******************************************************************
250 * Checks to see if the audio format in wf is supported, and if so set up the
251 * pa_sample_spec at ss to that format.
253 BOOL
PULSE_SetupFormat(LPWAVEFORMATEX wf
, pa_sample_spec
*ss
) {
254 WAVEFORMATEXTENSIBLE
*wfex
;
256 ss
->channels
= wf
->nChannels
;
257 ss
->rate
= wf
->nSamplesPerSec
;
258 ss
->format
= PA_SAMPLE_INVALID
;
260 if (ss
->rate
< DSBFREQUENCY_MIN
|| ss
->rate
> DSBFREQUENCY_MAX
) return FALSE
;
262 switch (wf
->wFormatTag
) {
263 case WAVE_FORMAT_PCM
:
264 /* MSDN says that for WAVE_FORMAT_PCM, nChannels must be 1 or 2 and
265 * wBitsPerSample must be 8 or 16, yet other values are used by some
266 * applications in the wild for surround. */
267 if (ss
->channels
> 6 || ss
->channels
< 1) return FALSE
;
268 ss
->format
= wf
->wBitsPerSample
== 8 ? PA_SAMPLE_U8
269 : wf
->wBitsPerSample
== 16 ? PA_SAMPLE_S16NE
270 : wf
->wBitsPerSample
== 32 ? PA_SAMPLE_S32NE
274 case WAVE_FORMAT_MULAW
:
275 if (wf
->wBitsPerSample
== 8) ss
->format
= PA_SAMPLE_ULAW
;
278 case WAVE_FORMAT_ALAW
:
279 if (wf
->wBitsPerSample
== 8) ss
->format
= PA_SAMPLE_ALAW
;
282 case WAVE_FORMAT_EXTENSIBLE
:
283 if (wf
->cbSize
> 22) return FALSE
;
284 if (ss
->channels
< 1 || ss
->channels
> 6) return FALSE
;
285 wfex
= (WAVEFORMATEXTENSIBLE
*)wf
;
286 if (IsEqualGUID(&wfex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
287 if (wf
->wBitsPerSample
== wfex
->Samples
.wValidBitsPerSample
) {
288 ss
->format
= wf
->wBitsPerSample
== 8 ? PA_SAMPLE_U8
289 : wf
->wBitsPerSample
== 16 ? PA_SAMPLE_S16NE
290 : wf
->wBitsPerSample
== 32 ? PA_SAMPLE_S32NE
295 } else if (wf
->wBitsPerSample
!= wfex
->Samples
.wValidBitsPerSample
) {
297 } else if ((IsEqualGUID(&wfex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))) {
298 ss
->format
= PA_SAMPLE_FLOAT32NE
;
300 WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT of WAVE_FORMAT_EXTENSIBLE supported\n");
306 WARN("only WAVE_FORMAT_PCM, WAVE_FORMAT_MULAW, WAVE_FORMAT_ALAW and WAVE_FORMAT_EXTENSIBLE supported\n");
310 if (!pa_sample_spec_valid(ss
)) return FALSE
;
311 if (wf
->nBlockAlign
!= pa_frame_size(ss
)) {
312 ERR("wf->nBlockAlign != the format frame size!\n");
319 /******************************************************************
322 * Converts the current time to a MMTIME structure. lpTime shold be validated
325 HRESULT
PULSE_UsecToMMTime(pa_usec_t time
, LPMMTIME lpTime
, const pa_sample_spec
*ss
) {
329 /* Convert to milliseconds */
332 bytes
= time
* pa_bytes_per_second(ss
) / 1000;
333 /* Align to frame size */
334 bytes
-= bytes
% pa_frame_size(ss
);
336 switch (lpTime
->wType
) {
338 lpTime
->u
.sample
= bytes
/ pa_frame_size(ss
);
339 TRACE("TIME_SAMPLES=%u\n", lpTime
->u
.sample
);
343 TRACE("TIME_MS=%u\n", lpTime
->u
.ms
);
346 lpTime
->u
.smpte
.fps
= 30;
347 temp
= bytes
/ pa_frame_size(ss
);
348 temp
+= ss
->rate
/ lpTime
->u
.smpte
.fps
- 1;
349 lpTime
->u
.smpte
.sec
= time
/1000;
350 temp
-= lpTime
->u
.smpte
.sec
* ss
->rate
;
351 lpTime
->u
.smpte
.min
= lpTime
->u
.smpte
.sec
/ 60;
352 lpTime
->u
.smpte
.sec
-= 60 * lpTime
->u
.smpte
.min
;
353 lpTime
->u
.smpte
.hour
= lpTime
->u
.smpte
.min
/ 60;
354 lpTime
->u
.smpte
.min
-= 60 * lpTime
->u
.smpte
.hour
;
355 lpTime
->u
.smpte
.frame
= temp
* lpTime
->u
.smpte
.fps
/ ss
->rate
;
356 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
357 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
358 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
361 WARN("Format %d not supported, using TIME_BYTES !\n", lpTime
->wType
);
362 lpTime
->wType
= TIME_BYTES
;
365 lpTime
->u
.cb
= bytes
;
366 TRACE("TIME_BYTES=%u\n", lpTime
->u
.cb
);
370 return MMSYSERR_NOERROR
;
373 /**************************************************************************
374 * PULSE_WaitForOperation
376 * Waits for pa operations to complete, and dereferences the operation.
378 void PULSE_WaitForOperation(pa_operation
*o
) {
382 if (pa_operation_get_state(o
) != PA_OPERATION_RUNNING
)
384 pa_threaded_mainloop_wait(PULSE_ml
);
386 pa_operation_unref(o
);
389 /**************************************************************************
393 /**************************************************************************
394 * PULSE_StreamRequestCallback
396 * Called by the pulse mainloop whenever it wants/has audio data.
398 void PULSE_StreamRequestCallback(pa_stream
*s
, size_t nbytes
, void *userdata
) {
399 WINE_WAVEINST
*ww
= (WINE_WAVEINST
*)userdata
;
401 TRACE("Server has %u bytes\n", nbytes
);
403 /* Make sure that the player/recorder is running */
404 if (ww
->hThread
!= INVALID_HANDLE_VALUE
&& ww
->msgRing
.messages
) {
405 PULSE_AddRingMessage(&ww
->msgRing
, WINE_WM_FEED
, (DWORD
)nbytes
, FALSE
);
410 /**************************************************************************
411 * PULSE_StreamSuspendedCallback [internal]
413 * Called by the pulse mainloop any time stream playback is intentionally
414 * suspended or resumed from being suspended.
416 void PULSE_StreamSuspendedCallback(pa_stream
*s
, void *userdata
) {
417 WINE_WAVEINST
*wwo
= (WINE_WAVEINST
*)userdata
;
420 /* Currently we handle this kinda like an underrun. Perhaps we should
421 * tell the client somehow so it doesn't just hang? */
423 if (!pa_stream_is_suspended(s
) && wwo
->hThread
!= INVALID_HANDLE_VALUE
&& wwo
->msgRing
.ring_buffer_size
> 0)
424 PULSE_AddRingMessage(&wwo
->msgRing
, WINE_WM_XRUN
, 0, FALSE
);
427 /**************************************************************************
428 * PULSE_StreamUnderflowCallback [internal]
430 * Called by the pulse mainloop when the prebuf runs out of data.
432 void PULSE_StreamUnderflowCallback(pa_stream
*s
, void *userdata
) {
433 WINE_WAVEINST
*wwo
= (WINE_WAVEINST
*)userdata
;
436 /* If we aren't playing, don't care ^_^ */
437 if (wwo
->state
!= WINE_WS_PLAYING
) return;
439 TRACE("Underrun occurred.\n");
441 if (wwo
->hThread
!= INVALID_HANDLE_VALUE
&& wwo
->msgRing
.ring_buffer_size
> 0);
442 PULSE_AddRingMessage(&wwo
->msgRing
, WINE_WM_XRUN
, 0, FALSE
);
445 /**************************************************************************
446 * PULSE_StreamMovedCallback [internal]
448 * Called by the pulse mainloop when the stream gets moved, resulting in
449 * possibly different metrics.
451 void PULSE_StreamMovedCallback(pa_stream
*s
, void *userdata
) {
456 /******************************************************************
457 * PULSE_StreamStateCallback
459 * Called by pulse whenever the state of the stream changes.
461 void PULSE_StreamStateCallback(pa_stream
*s
, void *userdata
) {
464 switch (pa_stream_get_state(s
)) {
465 case PA_STREAM_READY
:
466 TRACE("Stream %p ready\n", userdata
);
469 case PA_STREAM_TERMINATED
: /* Stream closed normally */
470 TRACE("Stream %p terminated\n", userdata
);
473 case PA_STREAM_FAILED
: /* Stream closed not-normally */
474 ERR("Stream %p failed!\n", userdata
);
477 case PA_STREAM_UNCONNECTED
:
478 case PA_STREAM_CREATING
:
481 pa_threaded_mainloop_signal(PULSE_ml
, 0);
484 /**************************************************************************
485 * PULSE_StreamSucessCallback
487 void PULSE_StreamSuccessCallback(pa_stream
*s
, int success
, void *userdata
) {
489 WARN("Stream %p operation failed: %s\n", userdata
, pa_strerror(pa_context_errno(PULSE_context
)));
491 pa_threaded_mainloop_signal(PULSE_ml
, 0);
494 /**************************************************************************
495 * PULSE_ContextSuccessCallback
497 void PULSE_ContextSuccessCallback(pa_context
*c
, int success
, void *userdata
) {
498 if (!success
) ERR("Context operation failed: %s\n", pa_strerror(pa_context_errno(c
)));
499 pa_threaded_mainloop_signal(PULSE_ml
, 0);
502 /**************************************************************************
503 * Connection management and sink / source management.
506 /**************************************************************************
507 * PULSE_ContextStateCallback [internal]
509 static void PULSE_ContextStateCallback(pa_context
*c
, void *userdata
) {
512 switch (pa_context_get_state(c
)) {
513 case PA_CONTEXT_CONNECTING
:
514 case PA_CONTEXT_UNCONNECTED
:
515 case PA_CONTEXT_AUTHORIZING
:
516 case PA_CONTEXT_SETTING_NAME
:
519 case PA_CONTEXT_READY
:
520 case PA_CONTEXT_TERMINATED
:
521 pa_threaded_mainloop_signal(PULSE_ml
, 0);
524 case PA_CONTEXT_FAILED
:
525 ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c
)));
526 pa_threaded_mainloop_signal(PULSE_ml
, 0);
531 /**************************************************************************
532 * PULSE_AllocateWaveinDevice [internal]
534 * Creates or adds a device to WInDev based on the pa_source_info.
536 static void PULSE_AllocateWaveinDevice(const char *name
, const char *device
, const char *description
, const pa_cvolume
*v
) {
540 wdi
= HeapReAlloc(GetProcessHeap(), 0, WInDev
, sizeof(WINE_WAVEDEV
) * (PULSE_WidNumDevs
+ 1));
542 wdi
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV
));
547 wdi
= &WInDev
[PULSE_WidNumDevs
++];
548 memset(wdi
, 0, sizeof(WINE_WAVEDEV
));
549 memset(&(wdi
->caps
.in
), 0, sizeof(wdi
->caps
.in
));
550 snprintf(wdi
->interface_name
, MAXPNAMELEN
* 2, "winepulse: %s", name
);
551 wdi
->device_name
= pa_xstrdup(device
);
552 MultiByteToWideChar(CP_UTF8
, 0, description
, -1, wdi
->caps
.in
.szPname
, sizeof(wdi
->caps
.in
.szPname
)/sizeof(WCHAR
));
553 wdi
->caps
.in
.szPname
[sizeof(wdi
->caps
.in
.szPname
)/sizeof(WCHAR
) - 1] = '\0';
554 wdi
->caps
.in
.wMid
= MM_CREATIVE
;
555 wdi
->caps
.in
.wPid
= MM_CREATIVE_SBP16_WAVEOUT
;
556 wdi
->caps
.in
.vDriverVersion
= 0x0100;
557 wdi
->caps
.in
.wChannels
= v
->channels
== 1 ? 1 : 2;
558 wdi
->caps
.in
.dwFormats
= PULSE_ALL_FORMATS
;
559 memset(&wdi
->ds_desc
, 0, sizeof(DSDRIVERDESC
));
560 memcpy(wdi
->ds_desc
.szDesc
, description
, min(sizeof(wdi
->ds_desc
.szDesc
) - 1, strlen(description
)));
561 memcpy(wdi
->ds_desc
.szDrvname
, "winepulse.drv", 14);
562 wdi
->ds_caps
.dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
563 wdi
->ds_caps
.dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
564 wdi
->ds_caps
.dwPrimaryBuffers
= 1;
565 wdi
->ds_caps
.dwFlags
= \
567 DSCAPS_PRIMARYSTEREO
|
569 DSCAPS_PRIMARY16BIT
|
570 DSCAPS_SECONDARYMONO
|
571 DSCAPS_SECONDARYSTEREO
|
572 DSCAPS_SECONDARY8BIT
|
573 DSCAPS_SECONDARY16BIT
|
574 DSCCAPS_MULTIPLECAPTURE
;
577 /**************************************************************************
578 * PULSE_AllocateWaveoutDevice [internal]
580 * Creates or adds a sink to the WOutDev array.
582 static void PULSE_AllocateWaveoutDevice(const char *name
, const char *device
, const char *description
, const pa_cvolume
*v
) {
587 wdo
= HeapReAlloc(GetProcessHeap(), 0, WOutDev
, sizeof(WINE_WAVEDEV
) * (PULSE_WodNumDevs
+ 1));
589 wdo
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV
));
594 wdo
= &WOutDev
[PULSE_WodNumDevs
++];
595 memset(wdo
, 0, sizeof(WINE_WAVEDEV
));
597 wdo
->device_name
= pa_xstrdup(device
);
598 wdo
->volume
.channels
= v
->channels
;
599 for (x
= 0; x
< v
->channels
; x
++) wdo
->volume
.values
[x
] = v
->values
[x
];
600 snprintf(wdo
->interface_name
, MAXPNAMELEN
* 2, "winepulse: %s", name
);
601 MultiByteToWideChar(CP_UTF8
, 0, description
, -1, wdo
->caps
.out
.szPname
, sizeof(wdo
->caps
.out
.szPname
)/sizeof(WCHAR
));
602 wdo
->caps
.out
.szPname
[sizeof(wdo
->caps
.out
.szPname
)/sizeof(WCHAR
) - 1] = '\0';
603 wdo
->caps
.out
.wMid
= MM_CREATIVE
;
604 wdo
->caps
.out
.wPid
= MM_CREATIVE_SBP16_WAVEOUT
;
605 wdo
->caps
.out
.vDriverVersion
= 0x0100;
606 wdo
->caps
.out
.dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_SAMPLEACCURATE
;// | WAVECAPS_DIRECTSOUND;
607 if (v
->channels
>= 2) {
608 wdo
->caps
.out
.wChannels
= 2;
609 wdo
->caps
.out
.dwSupport
|= WAVECAPS_LRVOLUME
;
611 wdo
->caps
.out
.wChannels
= 1;
612 wdo
->caps
.out
.dwFormats
= PULSE_ALL_FORMATS
;
613 memset(&wdo
->ds_desc
, 0, sizeof(DSDRIVERDESC
));
614 memcpy(wdo
->ds_desc
.szDesc
, description
, min(sizeof(wdo
->ds_desc
.szDesc
) - 1, strlen(description
)));
615 memcpy(wdo
->ds_desc
.szDrvname
, "winepulse.drv", 14);
616 wdo
->ds_caps
.dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
617 wdo
->ds_caps
.dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
618 wdo
->ds_caps
.dwPrimaryBuffers
= 1;
619 wdo
->ds_caps
.dwFlags
= \
621 DSCAPS_PRIMARYSTEREO
|
623 DSCAPS_PRIMARY16BIT
|
624 DSCAPS_SECONDARYMONO
|
625 DSCAPS_SECONDARYSTEREO
|
626 DSCAPS_SECONDARY8BIT
|
627 DSCAPS_SECONDARY16BIT
|
628 DSCAPS_CONTINUOUSRATE
;
631 /**************************************************************************
632 * PULSE_SourceInfoCallback [internal]
634 static void PULSE_SourceInfoCallback(pa_context
*c
, const pa_source_info
*i
, int eol
, void *userdata
) {
637 PULSE_AllocateWaveinDevice(i
->name
, i
->name
, i
->description
, &i
->volume
);
639 pa_threaded_mainloop_signal(PULSE_ml
, 0);
642 /**************************************************************************
643 * PULSE_SinkInfoCallback [internal]
645 static void PULSE_SinkInfoCallback(pa_context
*c
, const pa_sink_info
*i
, int eol
, void *userdata
) {
648 PULSE_AllocateWaveoutDevice(i
->name
, i
->name
, i
->description
, &i
->volume
);
650 pa_threaded_mainloop_signal(PULSE_ml
, 0);
653 /**************************************************************************
654 * PULSE_ContextNotifyCallback [internal]
656 static void PULSE_ContextNotifyCallback(pa_context
*c
, void *userdata
) {
657 pa_threaded_mainloop_signal(PULSE_ml
, 0);
660 /**************************************************************************
661 * PULSE_WaveClose [internal]
663 * Disconnect from the server, deallocated the WaveIn/WaveOut devices, stop and
666 static LONG
PULSE_WaveClose(void) {
669 if (!PULSE_ml
) return DRV_FAILURE
;
671 pa_threaded_mainloop_lock(PULSE_ml
);
672 /* device_name is allocated with pa_xstrdup, free with pa_xfree */
673 for (x
= 0; x
< PULSE_WodNumDevs
; x
++) pa_xfree(WOutDev
[x
].device_name
);
674 for (x
= 0; x
< PULSE_WidNumDevs
; x
++) pa_xfree(WInDev
[x
].device_name
);
675 HeapFree(GetProcessHeap(), 0, WOutDev
);
676 HeapFree(GetProcessHeap(), 0, WInDev
);
678 PULSE_WaitForOperation(pa_context_drain(PULSE_context
, PULSE_ContextNotifyCallback
, NULL
));
679 pa_context_disconnect(PULSE_context
);
680 pa_context_unref(PULSE_context
);
681 PULSE_context
= NULL
;
684 pa_threaded_mainloop_unlock(PULSE_ml
);
685 pa_threaded_mainloop_stop(PULSE_ml
);
686 pa_threaded_mainloop_free(PULSE_ml
);
692 /**************************************************************************
693 * PULSE_WaveInit [internal]
695 * Connects to the pulseaudio server, tries to discover sinks and sources and
696 * allocates the WaveIn/WaveOut devices.
698 static LONG
PULSE_WaveInit(void) {
702 pa_cvolume fake_cvolume
;
706 PULSE_WodNumDevs
= 0;
707 PULSE_WidNumDevs
= 0;
708 PULSE_context
= NULL
;
711 if (!(PULSE_ml
= pa_threaded_mainloop_new())) {
712 ERR("Failed to create mainloop object.");
716 /* Application name giving to pulse should be unique to the binary so that
717 * pulse-*-restore can be useful */
719 /* Get binary path, and remove path a-la strrchr */
720 if (GetModuleFileNameA(NULL
, path
, PATH_MAX
))
721 offset
= strrchr(path
, '\\');
723 if (offset
&& ++offset
&& offset
< path
+ PATH_MAX
) {
724 app_name
= pa_xmalloc(strlen(offset
) + 8);
725 snprintf(app_name
, strlen(offset
) + 8, "WINE [%s]", offset
);
727 app_name
= pa_xstrdup("WINE Application");
729 TRACE("App name is \"%s\"\n", app_name
);
731 pa_threaded_mainloop_start(PULSE_ml
);
732 PULSE_context
= pa_context_new(pa_threaded_mainloop_get_api(PULSE_ml
), app_name
);
733 assert(PULSE_context
);
736 pa_context_set_state_callback(PULSE_context
, PULSE_ContextStateCallback
, NULL
);
738 pa_threaded_mainloop_lock(PULSE_ml
);
740 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(PULSE_context
), PA_API_VERSION
);
741 if (pa_context_connect(PULSE_context
, NULL
, 0, NULL
) < 0)
744 /* Wait for connection */
746 pa_context_state_t state
= pa_context_get_state(PULSE_context
);
748 if (state
== PA_CONTEXT_FAILED
|| state
== PA_CONTEXT_TERMINATED
)
751 if (state
== PA_CONTEXT_READY
)
754 pa_threaded_mainloop_wait(PULSE_ml
);
757 TRACE("Connected to server %s with protocol version: %i.\n",
758 pa_context_get_server(PULSE_context
),
759 pa_context_get_server_protocol_version(PULSE_context
));
761 fake_cvolume
.channels
= 2;
762 pa_cvolume_reset(&fake_cvolume
, 2);
763 /* FIXME Translations? */
764 PULSE_AllocateWaveoutDevice("default", NULL
, "Default", &fake_cvolume
);
765 PULSE_AllocateWaveinDevice("default", NULL
, "Default", &fake_cvolume
);
766 PULSE_WaitForOperation(pa_context_get_sink_info_list(PULSE_context
, PULSE_SinkInfoCallback
, &PULSE_WodNumDevs
));
767 PULSE_WaitForOperation(pa_context_get_source_info_list(PULSE_context
, PULSE_SourceInfoCallback
, &PULSE_WidNumDevs
));
768 TRACE("Found %u output and %u input device(s).\n", PULSE_WodNumDevs
- 1, PULSE_WidNumDevs
- 1);
770 pa_threaded_mainloop_unlock(PULSE_ml
);
775 pa_threaded_mainloop_unlock(PULSE_ml
);
776 /* Only warn, because if we failed wine may still choose the next driver */
777 WARN("Failed to connect to server\n");
781 #endif /* HAVE_PULSEAUDIO */
783 /**************************************************************************
784 * DriverProc (WINEPULSE.@)
786 LRESULT CALLBACK
PULSE_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
787 LPARAM dwParam1
, LPARAM dwParam2
) {
790 #ifdef HAVE_PULSEAUDIO
791 case DRV_LOAD
: return PULSE_WaveInit();
792 case DRV_FREE
: return PULSE_WaveClose();
793 case DRV_OPEN
: return 1;
794 case DRV_CLOSE
: return 1;
795 case DRV_ENABLE
: return 1;
796 case DRV_DISABLE
: return 1;
797 case DRV_QUERYCONFIGURE
: return 1;
798 case DRV_CONFIGURE
: MessageBoxA(0, "PulseAudio MultiMedia Driver !", "PulseAudio Driver", MB_OK
); return 1;
799 case DRV_INSTALL
: return DRVCNF_RESTART
;
800 case DRV_REMOVE
: return DRVCNF_RESTART
;
803 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);