2 * Wine Driver for PulseAudio
3 * http://pulseaudio.org/
5 * Copyright 2008 Arthur Taylor <art@ified.ca>
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
40 #ifdef HAVE_PULSEAUDIO
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44 #include "wine/library.h"
46 #include <winepulse.h>
47 #include <pulse/pulseaudio.h>
48 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
51 * - Need to subscribe to sink/source events and keep the WInDev and WOutDev
55 /* These strings used only for tracing */
56 const char * PULSE_getCmdString(enum win_wm_message msg
) {
57 static char unknown
[32];
58 #define MSG_TO_STR(x) case x: return #x
60 MSG_TO_STR(WINE_WM_PAUSING
);
61 MSG_TO_STR(WINE_WM_RESTARTING
);
62 MSG_TO_STR(WINE_WM_RESETTING
);
63 MSG_TO_STR(WINE_WM_HEADER
);
64 MSG_TO_STR(WINE_WM_BREAKLOOP
);
65 MSG_TO_STR(WINE_WM_CLOSING
);
66 MSG_TO_STR(WINE_WM_STARTING
);
67 MSG_TO_STR(WINE_WM_STOPPING
);
68 MSG_TO_STR(WINE_WM_XRUN
);
69 MSG_TO_STR(WINE_WM_FEED
);
72 sprintf(unknown
, "UNKNOWN(0x%08x)", msg
);
76 /*======================================================================*
77 * Ring Buffer Functions - copied from winealsa.drv *
78 *======================================================================*/
80 /* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
84 #define INIT_OMR(omr) do { if (pipe(omr->msg_pipe) < 0) { omr->msg_pipe[0] = omr->msg_pipe[1] = -1; } } while (0)
85 #define CLOSE_OMR(omr) do { close(omr->msg_pipe[0]); close(omr->msg_pipe[1]); } while (0)
86 #define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
87 #define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
88 #define RESET_OMR(omr) do { } while (0)
89 #define WAIT_OMR(omr, sleep) \
90 do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
91 pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
93 #define INIT_OMR(omr) do { omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
94 #define CLOSE_OMR(omr) do { CloseHandle(omr->msg_event); } while (0)
95 #define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
96 #define CLEAR_OMR(omr) do { } while (0)
97 #define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
98 #define WAIT_OMR(omr, sleep) \
99 do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
102 #define PULSE_RING_BUFFER_INCREMENT 64
104 /******************************************************************
105 * PULSE_InitRingMessage
107 * Initialize the ring of messages for passing between driver's caller
108 * and playback/record thread
110 int PULSE_InitRingMessage(PULSE_MSG_RING
* omr
)
115 omr
->ring_buffer_size
= PULSE_RING_BUFFER_INCREMENT
;
116 omr
->messages
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,omr
->ring_buffer_size
* sizeof(PULSE_MSG
));
118 InitializeCriticalSection(&omr
->msg_crst
);
119 omr
->msg_crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PULSE_MSG_RING.msg_crst");
123 /******************************************************************
124 * PULSE_DestroyRingMessage
127 int PULSE_DestroyRingMessage(PULSE_MSG_RING
* omr
)
130 HeapFree(GetProcessHeap(),0,omr
->messages
);
131 omr
->messages
= NULL
;
132 omr
->ring_buffer_size
= PULSE_RING_BUFFER_INCREMENT
;
133 omr
->msg_crst
.DebugInfo
->Spare
[0] = 0;
134 DeleteCriticalSection(&omr
->msg_crst
);
137 /******************************************************************
138 * PULSE_ResetRingMessage
141 void PULSE_ResetRingMessage(PULSE_MSG_RING
* omr
)
146 /******************************************************************
147 * PULSE_WaitRingMessage
150 void PULSE_WaitRingMessage(PULSE_MSG_RING
* omr
, DWORD sleep
)
152 WAIT_OMR(omr
, sleep
);
155 /******************************************************************
156 * PULSE_AddRingMessage
158 * Inserts a new message into the ring (should be called from DriverProc derived routines)
160 int PULSE_AddRingMessage(PULSE_MSG_RING
* omr
, enum win_wm_message msg
, DWORD param
, BOOL wait
)
162 HANDLE hEvent
= INVALID_HANDLE_VALUE
;
164 EnterCriticalSection(&omr
->msg_crst
);
165 if ((omr
->msg_toget
== ((omr
->msg_tosave
+ 1) % omr
->ring_buffer_size
)))
167 int old_ring_buffer_size
= omr
->ring_buffer_size
;
168 omr
->ring_buffer_size
+= PULSE_RING_BUFFER_INCREMENT
;
169 omr
->messages
= HeapReAlloc(GetProcessHeap(),0,omr
->messages
, omr
->ring_buffer_size
* sizeof(PULSE_MSG
));
170 /* Now we need to rearrange the ring buffer so that the new
171 buffers just allocated are in between omr->msg_tosave and
174 if (omr
->msg_tosave
< omr
->msg_toget
)
176 memmove(&(omr
->messages
[omr
->msg_toget
+ PULSE_RING_BUFFER_INCREMENT
]),
177 &(omr
->messages
[omr
->msg_toget
]),
178 sizeof(PULSE_MSG
)*(old_ring_buffer_size
- omr
->msg_toget
)
180 omr
->msg_toget
+= PULSE_RING_BUFFER_INCREMENT
;
185 hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
186 if (hEvent
== INVALID_HANDLE_VALUE
)
188 ERR("can't create event !?\n");
189 LeaveCriticalSection(&omr
->msg_crst
);
192 if (omr
->msg_toget
!= omr
->msg_tosave
&& omr
->messages
[omr
->msg_toget
].msg
!= WINE_WM_HEADER
)
193 FIXME("two fast messages in the queue!!!!\n"); /* toget = %d(%s), tosave=%d(%s)\n",
194 omr->msg_toget,ALSA_getCmdString(omr->messages[omr->msg_toget].msg),
195 omr->msg_tosave,ALSA_getCmdString(omr->messages[omr->msg_tosave].msg)); */
197 /* fast messages have to be added at the start of the queue */
198 omr
->msg_toget
= (omr
->msg_toget
+ omr
->ring_buffer_size
- 1) % omr
->ring_buffer_size
;
200 omr
->messages
[omr
->msg_toget
].msg
= msg
;
201 omr
->messages
[omr
->msg_toget
].param
= param
;
202 omr
->messages
[omr
->msg_toget
].hEvent
= hEvent
;
206 omr
->messages
[omr
->msg_tosave
].msg
= msg
;
207 omr
->messages
[omr
->msg_tosave
].param
= param
;
208 omr
->messages
[omr
->msg_tosave
].hEvent
= INVALID_HANDLE_VALUE
;
209 omr
->msg_tosave
= (omr
->msg_tosave
+ 1) % omr
->ring_buffer_size
;
211 LeaveCriticalSection(&omr
->msg_crst
);
212 /* signal a new message */
216 /* wait for playback/record thread to have processed the message */
217 WaitForSingleObject(hEvent
, INFINITE
);
223 /******************************************************************
224 * PULSE_RetrieveRingMessage
226 * Get a message from the ring. Should be called by the playback/record thread.
228 int PULSE_RetrieveRingMessage(PULSE_MSG_RING
* omr
,
229 enum win_wm_message
*msg
, DWORD
*param
, HANDLE
*hEvent
)
231 EnterCriticalSection(&omr
->msg_crst
);
233 if (omr
->msg_toget
== omr
->msg_tosave
) /* buffer empty ? */
235 LeaveCriticalSection(&omr
->msg_crst
);
239 *msg
= omr
->messages
[omr
->msg_toget
].msg
;
240 omr
->messages
[omr
->msg_toget
].msg
= 0;
241 *param
= omr
->messages
[omr
->msg_toget
].param
;
242 *hEvent
= omr
->messages
[omr
->msg_toget
].hEvent
;
243 omr
->msg_toget
= (omr
->msg_toget
+ 1) % omr
->ring_buffer_size
;
245 LeaveCriticalSection(&omr
->msg_crst
);
249 /**************************************************************************
253 /******************************************************************
256 * Checks to see if the audio format in wf is supported, and if so set up the
257 * pa_sample_spec at ss to that format.
259 BOOL
PULSE_setupFormat(LPWAVEFORMATEX wf
, pa_sample_spec
*ss
) {
261 if (wf
->nSamplesPerSec
<DSBFREQUENCY_MIN
||wf
->nSamplesPerSec
>DSBFREQUENCY_MAX
)
264 ss
->channels
=wf
->nChannels
;
265 ss
->rate
=wf
->nSamplesPerSec
;
267 if (wf
->wFormatTag
== WAVE_FORMAT_PCM
) {
268 if (ss
->channels
==1 || ss
->channels
==2) {
269 switch (wf
->wBitsPerSample
) {
271 ss
->format
= PA_SAMPLE_U8
;
274 ss
->format
= PA_SAMPLE_S16NE
;
278 } else if (wf
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
279 WAVEFORMATEXTENSIBLE
* wfex
= (WAVEFORMATEXTENSIBLE
*)wf
;
281 if (wf
->cbSize
== 22 &&
282 (IsEqualGUID(&wfex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))) {
283 if (ss
->channels
>=1 && ss
->channels
<=6) {
284 if (wf
->wBitsPerSample
==wfex
->Samples
.wValidBitsPerSample
) {
285 switch (wf
->wBitsPerSample
) {
287 ss
->format
=PA_SAMPLE_U8
;
290 ss
->format
=PA_SAMPLE_S16NE
;
293 ss
->format
=PA_SAMPLE_S32NE
;
297 WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
299 } else if (wf
->cbSize
== 22 &&
300 (IsEqualGUID(&wfex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))) {
301 if (ss
->channels
>=1 && ss
->channels
<=6) {
302 if (wf
->wBitsPerSample
==wfex
->Samples
.wValidBitsPerSample
&& wf
->wBitsPerSample
== 32) {
303 ss
->format
=PA_SAMPLE_FLOAT32NE
;
308 WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT "
310 } else if (wf
->wFormatTag
== WAVE_FORMAT_MULAW
|| wf
->wFormatTag
== WAVE_FORMAT_ALAW
) {
311 if (wf
->wBitsPerSample
==8) {
312 ss
->format
= (wf
->wFormatTag
==WAVE_FORMAT_MULAW
) ? PA_SAMPLE_ULAW
: PA_SAMPLE_ALAW
;
315 ERR("WAVE_FORMAT_MULAW and WAVE_FORMAT_ALAW wBitsPerSample must = 8\n");
317 WARN("only WAVE_FORMAT_PCM, WAVE_FORMAT_MULAW, WAVE_FORMAT_ALAW and WAVE_FORMAT_EXTENSIBLE supported\n");
322 /******************************************************************
323 * PULSE_free_wavedevs [internal]
325 * Free and deallocated all the wavedevs in the array of size allocated
327 static void PULSE_free_wavedevs(WINE_WAVEDEV
*wd
, DWORD
*allocated
) {
328 DWORD y
, x
= *allocated
;
329 WINE_WAVEDEV
*current_device
;
330 WINE_WAVEINST
*current_instance
;
332 TRACE("%i\n", *allocated
);
335 current_device
= &wd
[--x
];
337 pa_xfree(current_device
->device_name
);
339 for (y
= 0; y
< PULSE_MAX_STREAM_INSTANCES
; y
++) {
340 if ((current_instance
= current_device
->instance
[y
])) {
341 if (current_instance
->hThread
!= INVALID_HANDLE_VALUE
&& current_instance
->msgRing
.messages
) {
342 PULSE_AddRingMessage(¤t_instance
->msgRing
, WINE_WM_CLOSING
, 1, TRUE
);
343 if (current_instance
->hThread
!= INVALID_HANDLE_VALUE
) {
345 TerminateThread(current_instance
->hThread
, 1);
346 current_instance
->hThread
= INVALID_HANDLE_VALUE
;
348 if (current_instance
->stream
)
349 pa_stream_unref(current_instance
->stream
);
350 PULSE_DestroyRingMessage(¤t_instance
->msgRing
);
351 current_device
->instance
[current_instance
->instance_ref
] = NULL
;
352 if (current_instance
->buffer_attr
)
353 pa_xfree(current_instance
->buffer_attr
);
354 HeapFree(GetProcessHeap(), 0, current_instance
);
360 HeapFree(GetProcessHeap(), 0, wd
);
364 /******************************************************************
365 * PULSE_wait_for_operation
367 * Waits for pa operations to complete, ensures success and dereferences the
370 void PULSE_wait_for_operation(pa_operation
*o
, WINE_WAVEINST
*wd
) {
379 pa_context_get_state(PULSE_context
) != PA_CONTEXT_READY
||
380 pa_stream_get_state(wd
->stream
) != PA_STREAM_READY
) {
381 wd
->state
= WINE_WS_FAILED
;
382 if (wd
->hThread
!= INVALID_HANDLE_VALUE
&& wd
->msgRing
.messages
)
383 PULSE_AddRingMessage(&wd
->msgRing
, WINE_WM_CLOSING
, 1, FALSE
);
387 if (pa_operation_get_state(o
) != PA_OPERATION_RUNNING
)
390 pa_threaded_mainloop_wait(PULSE_ml
);
393 pa_operation_unref(o
);
396 /**************************************************************************
400 /**************************************************************************
401 * PULSE_stream_request_callback
403 * Called by the pulse mainloop whenever it wants or has audio data.
405 void PULSE_stream_request_callback(pa_stream
*s
, size_t nbytes
, void *userdata
) {
406 WINE_WAVEINST
*ww
= (WINE_WAVEINST
*)userdata
;
409 TRACE("Asking to feed.\n");
411 /* Make sure that the player is running */
412 if (ww
->hThread
!= INVALID_HANDLE_VALUE
&& ww
->msgRing
.messages
) {
413 PULSE_AddRingMessage(&ww
->msgRing
, WINE_WM_FEED
, (DWORD
)nbytes
, FALSE
);
417 /******************************************************************
418 * PULSE_stream_state_callback
420 * Called by pulse whenever the state of the stream changes.
422 void PULSE_stream_state_callback(pa_stream
*s
, void *userdata
) {
423 WINE_WAVEINST
*wd
= (WINE_WAVEINST
*)userdata
;
426 switch (pa_stream_get_state(s
)) {
428 case PA_STREAM_READY
:
429 TRACE("Stream ready\n");
431 case PA_STREAM_TERMINATED
:
432 TRACE("Stream terminated\n");
434 case PA_STREAM_FAILED
:
435 WARN("Stream failed!\n");
436 wd
->state
= WINE_WS_FAILED
;
437 if (wd
->hThread
!= INVALID_HANDLE_VALUE
&& wd
->msgRing
.messages
)
438 PULSE_AddRingMessage(&wd
->msgRing
, WINE_WM_CLOSING
, 1, FALSE
);
440 case PA_STREAM_UNCONNECTED
:
441 case PA_STREAM_CREATING
:
444 pa_threaded_mainloop_signal(PULSE_ml
, 0);
447 /**************************************************************************
448 * PULSE_stream_sucess_callback
450 void PULSE_stream_success_callback(pa_stream
*s
, int success
, void *userdata
) {
452 WARN("Stream operation failed: %s\n", pa_strerror(pa_context_errno(PULSE_context
)));
454 pa_threaded_mainloop_signal(PULSE_ml
, 0);
457 /**************************************************************************
458 * PULSE_context_success_callback
460 void PULSE_context_success_callback(pa_context
*c
, int success
, void *userdata
) {
462 WARN("Context operation failed: %s\n", pa_strerror(pa_context_errno(c
)));
464 pa_threaded_mainloop_signal(PULSE_ml
, 0);
467 /**************************************************************************
468 * Connection management and sink / source management.
471 /**************************************************************************
472 * PULSE_context_state_callback [internal]
474 static void PULSE_context_state_callback(pa_context
*c
, void *userdata
) {
477 switch (pa_context_get_state(c
)) {
478 case PA_CONTEXT_CONNECTING
:
479 case PA_CONTEXT_AUTHORIZING
:
480 case PA_CONTEXT_SETTING_NAME
:
483 case PA_CONTEXT_READY
:
484 case PA_CONTEXT_TERMINATED
:
485 pa_threaded_mainloop_signal(PULSE_ml
, 0);
488 case PA_CONTEXT_FAILED
:
490 ERR("Conneciton failure: %s\n", pa_strerror(pa_context_errno(c
)));
493 pa_context_disconnect(PULSE_context
);
496 PULSE_free_wavedevs(WOutDev
, &PULSE_WodNumDevs
);
497 PULSE_free_wavedevs(WInDev
, &PULSE_WidNumDevs
);
499 pa_threaded_mainloop_signal(PULSE_ml
, 0);
503 /**************************************************************************
504 * PULSE_add_input_device [internal]
506 * Creates or adds a device to WInDev based on the pa_source_info, or if
507 * pa_source_info is null, a default.
509 static void PULSE_add_input_device(pa_source_info
*i
, DWORD
*allocated
) {
511 const char *description
;
515 wwi
= HeapReAlloc(GetProcessHeap(), 0, WInDev
, sizeof(WINE_WAVEDEV
) * ((*allocated
)+1));
517 wwi
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV
));
523 wwi
= &WInDev
[(*allocated
)++];
526 description
= i
->description
;
527 wwi
->device_name
= pa_xstrdup(i
->name
);
528 strcpy(wwi
->interface_name
, "winepulse: ");
529 memcpy(wwi
->interface_name
+ strlen(wwi
->interface_name
),
530 i
->name
, min(strlen(i
->name
),
531 sizeof(wwi
->interface_name
) - strlen("winepulse: ")));
533 description
= pa_xstrdup("PulseAudio Server Default");
534 wwi
->device_name
= NULL
;
535 strcpy(wwi
->interface_name
, "winepulse: default");
538 memset(wwi
, 0, sizeof(WINE_WAVEDEV
));
539 memset(&(wwi
->caps
.in
), 0, sizeof(wwi
->caps
.in
));
540 MultiByteToWideChar(CP_ACP
, 0, description
, -1, wwi
->caps
.in
.szPname
, sizeof(wwi
->caps
.in
.szPname
)/sizeof(WCHAR
));
541 wwi
->caps
.in
.szPname
[sizeof(wwi
->caps
.in
.szPname
)/sizeof(WCHAR
) - 1] = '\0';
542 wwi
->caps
.in
.wMid
= MM_CREATIVE
;
543 wwi
->caps
.in
.wPid
= MM_CREATIVE_SBP16_WAVEOUT
;
544 wwi
->caps
.in
.vDriverVersion
= 0x0100;
545 wwi
->caps
.in
.wChannels
= 2;
546 wwi
->caps
.in
.dwFormats
|=
547 WAVE_FORMAT_1M08
| /* Mono 11025Hz 8-bit */
548 WAVE_FORMAT_1M16
| /* Mono 11025Hz 16-bit */
549 WAVE_FORMAT_1S08
| /* Stereo 11025Hz 8-bit */
550 WAVE_FORMAT_1S16
| /* Stereo 11025Hz 16-bit */
551 WAVE_FORMAT_2M08
| /* Mono 22050Hz 8-bit */
552 WAVE_FORMAT_2M16
| /* Mono 22050Hz 16-bit */
553 WAVE_FORMAT_2S08
| /* Stereo 22050Hz 8-bit */
554 WAVE_FORMAT_2S16
| /* Stereo 22050Hz 16-bit */
555 WAVE_FORMAT_4M08
| /* Mono 44100Hz 8-bit */
556 WAVE_FORMAT_4M16
| /* Mono 44100Hz 16-bit */
557 WAVE_FORMAT_4S08
| /* Stereo 44100Hz 8-bit */
558 WAVE_FORMAT_4S16
| /* Stereo 44100Hz 16-bit */
559 WAVE_FORMAT_48M08
| /* Mono 48000Hz 8-bit */
560 WAVE_FORMAT_48S08
| /* Stereo 48000Hz 8-bit */
561 WAVE_FORMAT_48M16
| /* Mono 48000Hz 16-bit */
562 WAVE_FORMAT_48S16
| /* Stereo 48000Hz 16-bit */
563 WAVE_FORMAT_96M08
| /* Mono 96000Hz 8-bit */
564 WAVE_FORMAT_96S08
| /* Stereo 96000Hz 8-bit */
565 WAVE_FORMAT_96M16
| /* Mono 96000Hz 16-bit */
566 WAVE_FORMAT_96S16
; /* Stereo 96000Hz 16-bit */
568 /* NULL out the instance pointers */
569 for (x
= 0; x
< PULSE_MAX_STREAM_INSTANCES
; x
++) wwi
->instance
[x
] = NULL
;
572 /**************************************************************************
573 * PULSE_add_output_device [internal]
575 * Creates or adds a device to WOutDev based on the pa_sinl_info, or if
576 * pa_sink_info is null, a default.
578 static void PULSE_add_output_device(pa_sink_info
*i
, DWORD
*allocated
) {
580 const char *description
;
584 wwo
= HeapReAlloc(GetProcessHeap(), 0, WOutDev
, sizeof(WINE_WAVEDEV
) * ((*allocated
)+1));
586 wwo
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV
));
592 wwo
= &WOutDev
[(*allocated
)++];
595 description
= i
->description
;
596 wwo
->device_name
= pa_xstrdup(i
->name
);
597 strcpy(wwo
->interface_name
, "winepulse: ");
598 memcpy(wwo
->interface_name
+ strlen(wwo
->interface_name
),
599 wwo
->device_name
, min(strlen(wwo
->device_name
),
600 sizeof(wwo
->interface_name
) - strlen("winepulse: ")));
602 description
= pa_xstrdup("PulseAudio Server Default");
603 wwo
->device_name
= NULL
;
604 strcpy(wwo
->interface_name
, "winepulse: default");
607 memset(wwo
, 0, sizeof(WINE_WAVEDEV
));
608 memset(&(wwo
->caps
.out
), 0, sizeof(wwo
->caps
.out
));
609 MultiByteToWideChar(CP_ACP
, 0, description
, -1, wwo
->caps
.out
.szPname
, sizeof(wwo
->caps
.out
.szPname
)/sizeof(WCHAR
));
610 wwo
->caps
.out
.szPname
[sizeof(wwo
->caps
.out
.szPname
)/sizeof(WCHAR
) - 1] = '\0';
611 wwo
->caps
.out
.wMid
= MM_CREATIVE
;
612 wwo
->caps
.out
.wPid
= MM_CREATIVE_SBP16_WAVEOUT
;
613 wwo
->caps
.out
.vDriverVersion
= 0x0100;
614 wwo
->caps
.out
.dwSupport
|= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
615 wwo
->caps
.out
.wChannels
= 2;
616 wwo
->caps
.out
.dwFormats
|=
617 WAVE_FORMAT_1M08
| /* Mono 11025Hz 8-bit */
618 WAVE_FORMAT_1M16
| /* Mono 11025Hz 16-bit */
619 WAVE_FORMAT_1S08
| /* Stereo 11025Hz 8-bit */
620 WAVE_FORMAT_1S16
| /* Stereo 11025Hz 16-bit */
621 WAVE_FORMAT_2M08
| /* Mono 22050Hz 8-bit */
622 WAVE_FORMAT_2M16
| /* Mono 22050Hz 16-bit */
623 WAVE_FORMAT_2S08
| /* Stereo 22050Hz 8-bit */
624 WAVE_FORMAT_2S16
| /* Stereo 22050Hz 16-bit */
625 WAVE_FORMAT_4M08
| /* Mono 44100Hz 8-bit */
626 WAVE_FORMAT_4M16
| /* Mono 44100Hz 16-bit */
627 WAVE_FORMAT_4S08
| /* Stereo 44100Hz 8-bit */
628 WAVE_FORMAT_4S16
| /* Stereo 44100Hz 16-bit */
629 WAVE_FORMAT_48M08
| /* Mono 48000Hz 8-bit */
630 WAVE_FORMAT_48S08
| /* Stereo 48000Hz 8-bit */
631 WAVE_FORMAT_48M16
| /* Mono 48000Hz 16-bit */
632 WAVE_FORMAT_48S16
| /* Stereo 48000Hz 16-bit */
633 WAVE_FORMAT_96M08
| /* Mono 96000Hz 8-bit */
634 WAVE_FORMAT_96S08
| /* Stereo 96000Hz 8-bit */
635 WAVE_FORMAT_96M16
| /* Mono 96000HZ 16-bit */
636 WAVE_FORMAT_96S16
; /* Stereo 96000Hz 16-bit */
638 wwo
->left_vol
= PA_VOLUME_NORM
;
639 wwo
->right_vol
= PA_VOLUME_NORM
;
641 /* NULL out the instance pointers */
642 for (x
= 0; x
< PULSE_MAX_STREAM_INSTANCES
; x
++) wwo
->instance
[x
] = NULL
;
645 /**************************************************************************
646 * PULSE_source_info_callback [internal]
648 * Calls PULSE_add_input_device to add the source to the list of devices
650 static void PULSE_source_info_callback(pa_context
*c
, pa_source_info
*i
, int eol
, void *userdata
) {
653 if (i
->monitor_of_sink
== PA_INVALID_INDEX
) /* For now only add non-montior sources */
654 PULSE_add_input_device(i
, (DWORD
*)userdata
);
656 pa_threaded_mainloop_signal(PULSE_ml
, 0);
659 /**************************************************************************
660 * PULSE_sink_info_callback [internal]
662 * Calls PULSE_add_output_device to add the sink to the list of devices
664 static void PULSE_sink_info_callback(pa_context
*c
, pa_sink_info
*i
, int eol
, void *userdata
) {
667 PULSE_add_output_device(i
, (DWORD
*)userdata
);
669 pa_threaded_mainloop_signal(PULSE_ml
, 0);
672 /**************************************************************************
673 * PULSE_WaveInit [internal]
675 * Connects to the pulseaudio server, tries to discover sinks and sources and
676 * allocates the WaveIn/WaveOut devices.
678 LONG
PULSE_WaveInit(void) {
679 pa_operation
*o
= NULL
;
684 PULSE_WodNumDevs
= 0;
685 PULSE_WidNumDevs
= 0;
686 PULSE_context
= NULL
;
689 if (!(PULSE_ml
= pa_threaded_mainloop_new())) {
690 WARN("Failed to create mainloop object.");
694 pa_threaded_mainloop_start(PULSE_ml
);
696 /* FIXME: better name? */
697 PULSE_context
= pa_context_new(pa_threaded_mainloop_get_api(PULSE_ml
), "Wine Application");
698 assert(PULSE_context
);
700 pa_context_set_state_callback(PULSE_context
, PULSE_context_state_callback
, NULL
);
702 if (pa_context_get_state(PULSE_context
) != PA_CONTEXT_UNCONNECTED
)
705 pa_threaded_mainloop_lock(PULSE_ml
);
707 TRACE("Attempting to connect to pulseaudio server.\n");
708 if (pa_context_connect(PULSE_context
, NULL
, 0, NULL
) < 0) {
709 WARN("failed to connect context object %s\n", pa_strerror(pa_context_errno(PULSE_context
)));
713 /* Wait for connection */
715 pa_context_state_t state
= pa_context_get_state(PULSE_context
);
717 if (state
== PA_CONTEXT_FAILED
|| state
== PA_CONTEXT_TERMINATED
) {
718 ERR("Failed to connect to pulseaudio server.\n");
719 pa_context_unref(PULSE_context
);
720 pa_threaded_mainloop_unlock(PULSE_ml
);
721 pa_threaded_mainloop_stop(PULSE_ml
);
722 pa_threaded_mainloop_free(PULSE_ml
);
726 if (state
== PA_CONTEXT_READY
) {
727 TRACE("Connection succeeded!\n");
731 pa_threaded_mainloop_wait(PULSE_ml
);
734 /* Ask for all the sinks and create objects in the WOutDev array */
736 /* add a fake output (server default sink) */
737 PULSE_add_output_device(NULL
, &allocated
);
738 o
= pa_context_get_sink_info_list(PULSE_context
, (pa_sink_info_cb_t
)PULSE_sink_info_callback
, &allocated
);
740 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
)
741 pa_threaded_mainloop_wait(PULSE_ml
);
742 pa_operation_unref(o
);
743 pa_threaded_mainloop_unlock(PULSE_ml
);
744 TRACE("Allocated %i output device(s).\n",allocated
);
745 PULSE_WodNumDevs
=allocated
;
746 if (PULSE_WodNumDevs
== 1) /* Only the fake sink exists */
747 PULSE_free_wavedevs(WOutDev
, &PULSE_WodNumDevs
);
749 /* Repeate for all the sources */
751 /* add a fake input (server default source) */
752 PULSE_add_input_device(NULL
, &allocated
);
753 pa_threaded_mainloop_lock(PULSE_ml
);
754 o
= pa_context_get_source_info_list(PULSE_context
, (pa_source_info_cb_t
)PULSE_source_info_callback
, &allocated
);
756 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
)
757 pa_threaded_mainloop_wait(PULSE_ml
);
758 pa_operation_unref(o
);
759 pa_threaded_mainloop_unlock(PULSE_ml
);
760 TRACE("Allocated %i input device(s).\n", allocated
);
761 PULSE_WidNumDevs
=allocated
;
762 if (PULSE_WidNumDevs
== 1) /* Only the fake source exists */
763 PULSE_free_wavedevs(WInDev
, &PULSE_WidNumDevs
);
768 /**************************************************************************
769 * PULSE_WaveClose [internal]
771 * Disconnect from the server, deallocated the WaveIn/WaveOut devices, stop and
775 LONG
PULSE_WaveClose(void) {
776 pa_threaded_mainloop_lock(PULSE_ml
);
778 pa_context_disconnect(PULSE_context
);
779 pa_context_unref(PULSE_context
);
780 PULSE_context
= NULL
;
783 PULSE_free_wavedevs(WOutDev
, &PULSE_WodNumDevs
);
784 PULSE_free_wavedevs(WInDev
, &PULSE_WidNumDevs
);
786 pa_threaded_mainloop_unlock(PULSE_ml
);
787 pa_threaded_mainloop_stop(PULSE_ml
);
788 pa_threaded_mainloop_free(PULSE_ml
);
793 #endif /* HAVE_PULSEAUDIO */
795 /**************************************************************************
796 * DriverProc (WINEPULSE.@)
798 LRESULT CALLBACK
PULSE_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
799 LPARAM dwParam1
, LPARAM dwParam2
) {
802 #ifdef HAVE_PULSEAUDIO
803 case DRV_LOAD
: PULSE_WaveInit();
805 case DRV_FREE
: return PULSE_WaveClose();
806 case DRV_OPEN
: return 1;
807 case DRV_CLOSE
: return 1;
808 case DRV_ENABLE
: return 1;
809 case DRV_DISABLE
: return 1;
810 case DRV_QUERYCONFIGURE
: return 1;
811 case DRV_CONFIGURE
: MessageBoxA(0, "PulseAudio MultiMedia Driver !", "PulseAudio Driver", MB_OK
); return 1;
812 case DRV_INSTALL
: return DRVCNF_RESTART
;
813 case DRV_REMOVE
: return DRVCNF_RESTART
;
816 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);