winepulse.drv: add a pulseaudio driver
[wine/hacks.git] / dlls / winepulse.drv / pulse.c
blob9dd1f803737855a5078850872f52b509d2cb6b65
1 /*
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
24 #include "config.h"
26 #include <stdarg.h>
27 #include <stdio.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winreg.h"
34 #include "mmddk.h"
35 #include "ks.h"
36 #include "ksguid.h"
37 #include "ksmedia.h"
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #include <poll.h>
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
58 switch(msg) {
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);
70 #undef MSG_TO_STR
71 sprintf(unknown, "UNKNOWN(0x%08x)", msg);
72 return unknown;
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 */
80 #define USE_PIPE_SYNC
82 #ifdef USE_PIPE_SYNC
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)
91 #else
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)
99 #endif
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)
111 omr->msg_toget = 0;
112 omr->msg_tosave = 0;
113 INIT_OMR(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");
119 return 0;
122 /******************************************************************
123 * PULSE_DestroyRingMessage
126 int PULSE_DestroyRingMessage(PULSE_MSG_RING* omr)
128 CLOSE_OMR(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);
134 return 0;
136 /******************************************************************
137 * PULSE_ResetRingMessage
140 void PULSE_ResetRingMessage(PULSE_MSG_RING* omr)
142 RESET_OMR(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
171 omr->msg_toget.
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;
182 if (wait)
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);
189 return 0;
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;
198 else
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 */
207 SIGNAL_OMR(omr);
208 if (wait)
210 /* wait for playback/record thread to have processed the message */
211 WaitForSingleObject(hEvent, INFINITE);
212 CloseHandle(hEvent);
214 return 1;
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);
230 return 0;
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;
238 CLEAR_OMR(omr);
239 LeaveCriticalSection(&omr->msg_crst);
240 return 1;
243 /**************************************************************************
244 * Utility Functions
245 *************************************************************************/
247 /******************************************************************
248 * PULSE_SetupFormat
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
271 : PA_SAMPLE_INVALID;
272 break;
274 case WAVE_FORMAT_MULAW:
275 if (wf->wBitsPerSample == 8) ss->format = PA_SAMPLE_ULAW;
276 break;
278 case WAVE_FORMAT_ALAW:
279 if (wf->wBitsPerSample == 8) ss->format = PA_SAMPLE_ALAW;
280 break;
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
291 : PA_SAMPLE_INVALID;
292 } else {
293 return FALSE;
295 } else if (wf->wBitsPerSample != wfex->Samples.wValidBitsPerSample) {
296 return FALSE;
297 } else if ((IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) {
298 ss->format = PA_SAMPLE_FLOAT32NE;
299 } else {
300 WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT of WAVE_FORMAT_EXTENSIBLE supported\n");
301 return FALSE;
303 break;
305 default:
306 WARN("only WAVE_FORMAT_PCM, WAVE_FORMAT_MULAW, WAVE_FORMAT_ALAW and WAVE_FORMAT_EXTENSIBLE supported\n");
307 return FALSE;
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");
313 return FALSE;
316 return TRUE;
319 /******************************************************************
320 * PULSE_SetupFormat
322 * Converts the current time to a MMTIME structure. lpTime shold be validated
323 * before calling.
325 HRESULT PULSE_UsecToMMTime(pa_usec_t time, LPMMTIME lpTime, const pa_sample_spec *ss) {
326 pa_usec_t temp;
327 size_t bytes;
329 /* Convert to milliseconds */
330 time /= 1000;
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) {
337 case TIME_SAMPLES:
338 lpTime->u.sample = bytes / pa_frame_size(ss);
339 TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
340 break;
341 case TIME_MS:
342 lpTime->u.ms = time;
343 TRACE("TIME_MS=%u\n", lpTime->u.ms);
344 break;
345 case TIME_SMPTE:
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);
359 break;
360 default:
361 WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
362 lpTime->wType = TIME_BYTES;
363 /* fall through */
364 case TIME_BYTES:
365 lpTime->u.cb = bytes;
366 TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
367 break;
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) {
379 if (!o) return;
381 for (;;) {
382 if (pa_operation_get_state(o) != PA_OPERATION_RUNNING)
383 break;
384 pa_threaded_mainloop_wait(PULSE_ml);
386 pa_operation_unref(o);
389 /**************************************************************************
390 * Common Callbacks
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;
418 assert(s && wwo);
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;
434 assert(s && wwo);
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) {
452 FIXME("stub");
456 /******************************************************************
457 * PULSE_StreamStateCallback
459 * Called by pulse whenever the state of the stream changes.
461 void PULSE_StreamStateCallback(pa_stream *s, void *userdata) {
462 assert(s);
464 switch (pa_stream_get_state(s)) {
465 case PA_STREAM_READY:
466 TRACE("Stream %p ready\n", userdata);
467 break;
469 case PA_STREAM_TERMINATED: /* Stream closed normally */
470 TRACE("Stream %p terminated\n", userdata);
471 break;
473 case PA_STREAM_FAILED: /* Stream closed not-normally */
474 ERR("Stream %p failed!\n", userdata);
475 break;
477 case PA_STREAM_UNCONNECTED:
478 case PA_STREAM_CREATING:
479 return;
481 pa_threaded_mainloop_signal(PULSE_ml, 0);
484 /**************************************************************************
485 * PULSE_StreamSucessCallback
487 void PULSE_StreamSuccessCallback(pa_stream *s, int success, void *userdata) {
488 if (!success)
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) {
510 assert(c);
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:
517 break;
519 case PA_CONTEXT_READY:
520 case PA_CONTEXT_TERMINATED:
521 pa_threaded_mainloop_signal(PULSE_ml, 0);
522 break;
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);
527 break;
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) {
537 WINE_WAVEDEV *wdi;
539 if (WInDev)
540 wdi = HeapReAlloc(GetProcessHeap(), 0, WInDev, sizeof(WINE_WAVEDEV) * (PULSE_WidNumDevs + 1));
541 else
542 wdi = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV));
544 if (!wdi) return;
546 WInDev = wdi;
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 = \
566 DSCAPS_PRIMARYMONO |
567 DSCAPS_PRIMARYSTEREO |
568 DSCAPS_PRIMARY8BIT |
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) {
583 WINE_WAVEDEV *wdo;
584 int x;
586 if (WOutDev)
587 wdo = HeapReAlloc(GetProcessHeap(), 0, WOutDev, sizeof(WINE_WAVEDEV) * (PULSE_WodNumDevs + 1));
588 else
589 wdo = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV));
591 if (!wdo) return;
593 WOutDev = wdo;
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;
610 } else
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 = \
620 DSCAPS_PRIMARYMONO |
621 DSCAPS_PRIMARYSTEREO |
622 DSCAPS_PRIMARY8BIT |
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) {
636 if (!eol && i)
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) {
647 if (!eol && i)
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
664 * free the mainloop.
666 static LONG PULSE_WaveClose(void) {
667 int x;
668 TRACE("()\n");
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);
677 if (PULSE_context) {
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);
687 PULSE_ml = NULL;
689 return DRV_SUCCESS;
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) {
699 char *app_name;
700 char path[PATH_MAX];
701 char *offset = NULL;
702 pa_cvolume fake_cvolume;
704 WOutDev = NULL;
705 WInDev = NULL;
706 PULSE_WodNumDevs = 0;
707 PULSE_WidNumDevs = 0;
708 PULSE_context = NULL;
709 PULSE_ml = NULL;
711 if (!(PULSE_ml = pa_threaded_mainloop_new())) {
712 ERR("Failed to create mainloop object.");
713 return DRV_FAILURE;
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);
726 } else
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);
734 pa_xfree(app_name);
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)
742 goto fail;
744 /* Wait for connection */
745 for (;;) {
746 pa_context_state_t state = pa_context_get_state(PULSE_context);
748 if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
749 goto fail;
751 if (state == PA_CONTEXT_READY)
752 break;
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);
772 return DRV_SUCCESS;
774 fail:
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");
778 return DRV_FAILURE;
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) {
789 switch(wMsg) {
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;
801 #endif
802 default:
803 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);