pop 2aca846ce15eecb13ed27a247389e46952e6fa4a
[wine/hacks.git] / dlls / winepulse.drv / pulse.c
blob3dcb08605c825b4b5dba826fb9073a75a8c60326
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_StreamSuspendedCallback [internal]
396 * Called by the pulse mainloop any time stream playback is intentionally
397 * suspended or resumed from being suspended.
399 void PULSE_StreamSuspendedCallback(pa_stream *s, void *userdata) {
400 WINE_WAVEINST *wwo = (WINE_WAVEINST*)userdata;
401 assert(s && wwo);
403 /* Currently we handle this kinda like an underrun. Perhaps we should
404 * tell the client somehow so it doesn't just hang? */
406 if (!pa_stream_is_suspended(s) && wwo->hThread != INVALID_HANDLE_VALUE && wwo->msgRing.ring_buffer_size > 0)
407 PULSE_AddRingMessage(&wwo->msgRing, WINE_WM_XRUN, 0, FALSE);
410 /**************************************************************************
411 * PULSE_StreamUnderflowCallback [internal]
413 * Called by the pulse mainloop when the prebuf runs out of data.
415 void PULSE_StreamUnderflowCallback(pa_stream *s, void *userdata) {
416 WINE_WAVEINST *wwo = (WINE_WAVEINST*)userdata;
417 assert(s && wwo);
419 /* If we aren't playing, don't care ^_^ */
420 if (wwo->state != WINE_WS_PLAYING) return;
422 TRACE("Underrun occurred.\n");
424 if (wwo->hThread != INVALID_HANDLE_VALUE && wwo->msgRing.ring_buffer_size > 0);
425 PULSE_AddRingMessage(&wwo->msgRing, WINE_WM_XRUN, 0, FALSE);
428 /**************************************************************************
429 * PULSE_StreamMovedCallback [internal]
431 * Called by the pulse mainloop when the stream gets moved, resulting in
432 * possibly different metrics.
434 void PULSE_StreamMovedCallback(pa_stream *s, void *userdata) {
435 FIXME("stub");
439 /******************************************************************
440 * PULSE_StreamStateCallback
442 * Called by pulse whenever the state of the stream changes.
444 void PULSE_StreamStateCallback(pa_stream *s, void *userdata) {
445 assert(s);
447 switch (pa_stream_get_state(s)) {
448 case PA_STREAM_READY:
449 TRACE("Stream %p ready\n", userdata);
450 break;
452 case PA_STREAM_TERMINATED:
453 TRACE("Stream %p terminated\n", userdata);
454 break;
456 case PA_STREAM_FAILED:
457 ERR("Stream %p failed!\n", userdata);
458 break;
460 case PA_STREAM_UNCONNECTED:
461 case PA_STREAM_CREATING:
462 return;
464 pa_threaded_mainloop_signal(PULSE_ml, 0);
467 /**************************************************************************
468 * PULSE_StreamSucessCallback
470 void PULSE_StreamSuccessCallback(pa_stream *s, int success, void *userdata) {
471 if (!success)
472 WARN("Stream %p operation failed: %s\n", userdata, pa_strerror(pa_context_errno(PULSE_context)));
474 pa_threaded_mainloop_signal(PULSE_ml, 0);
477 /**************************************************************************
478 * PULSE_ContextSuccessCallback
480 void PULSE_ContextSuccessCallback(pa_context *c, int success, void *userdata) {
481 if (!success) ERR("Context operation failed: %s\n", pa_strerror(pa_context_errno(c)));
482 pa_threaded_mainloop_signal(PULSE_ml, 0);
485 /**************************************************************************
486 * Connection management and sink / source management.
489 /**************************************************************************
490 * PULSE_ContextStateCallback [internal]
492 static void PULSE_ContextStateCallback(pa_context *c, void *userdata) {
493 assert(c);
495 switch (pa_context_get_state(c)) {
496 case PA_CONTEXT_CONNECTING:
497 case PA_CONTEXT_UNCONNECTED:
498 case PA_CONTEXT_AUTHORIZING:
499 case PA_CONTEXT_SETTING_NAME:
500 break;
502 case PA_CONTEXT_READY:
503 case PA_CONTEXT_TERMINATED:
504 pa_threaded_mainloop_signal(PULSE_ml, 0);
505 break;
507 case PA_CONTEXT_FAILED:
508 ERR("Context failure: %s\n", pa_strerror(pa_context_errno(c)));
509 pa_threaded_mainloop_signal(PULSE_ml, 0);
510 break;
514 /**************************************************************************
515 * PULSE_AllocateWaveinDevice [internal]
517 * Creates or adds a device to WInDev based on the pa_source_info.
519 static void PULSE_AllocateWaveinDevice(const char *name, const char *device, const char *description, const pa_cvolume *v) {
520 WINE_WAVEDEV *wdi;
522 if (WInDev)
523 wdi = HeapReAlloc(GetProcessHeap(), 0, WInDev, sizeof(WINE_WAVEDEV) * (PULSE_WidNumDevs + 1));
524 else
525 wdi = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV));
527 if (!wdi) return;
529 WInDev = wdi;
530 wdi = &WInDev[PULSE_WidNumDevs++];
531 memset(wdi, 0, sizeof(WINE_WAVEDEV));
532 memset(&(wdi->caps.in), 0, sizeof(wdi->caps.in));
533 snprintf(wdi->interface_name, MAXPNAMELEN * 2, "winepulse: %s", name);
534 wdi->device_name = pa_xstrdup(device);
535 MultiByteToWideChar(CP_ACP, 0, description, -1, wdi->caps.in.szPname, sizeof(wdi->caps.in.szPname)/sizeof(WCHAR));
536 wdi->caps.in.szPname[sizeof(wdi->caps.in.szPname)/sizeof(WCHAR) - 1] = '\0';
537 wdi->caps.in.wMid = MM_CREATIVE;
538 wdi->caps.in.wPid = MM_CREATIVE_SBP16_WAVEOUT;
539 wdi->caps.in.vDriverVersion = 0x0100;
540 wdi->caps.in.wChannels = v->channels == 1 ? 1 : 2;
541 wdi->caps.in.dwFormats = PULSE_ALL_FORMATS;
542 memset(&wdi->ds_desc, 0, sizeof(DSDRIVERDESC));
543 memcpy(wdi->ds_desc.szDesc, description, min(sizeof(wdi->ds_desc.szDesc) - 1, strlen(description)));
544 memcpy(wdi->ds_desc.szDrvname, "winepulse.drv", 14);
545 wdi->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
546 wdi->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
547 wdi->ds_caps.dwPrimaryBuffers = 1;
548 wdi->ds_caps.dwFlags = \
549 DSCAPS_PRIMARYMONO |
550 DSCAPS_PRIMARYSTEREO |
551 DSCAPS_PRIMARY8BIT |
552 DSCAPS_PRIMARY16BIT |
553 DSCAPS_SECONDARYMONO |
554 DSCAPS_SECONDARYSTEREO |
555 DSCAPS_SECONDARY8BIT |
556 DSCAPS_SECONDARY16BIT |
557 DSCCAPS_MULTIPLECAPTURE;
560 /**************************************************************************
561 * PULSE_AllocateWaveoutDevice [internal]
563 * Creates or adds a sink to the WOutDev array.
565 static void PULSE_AllocateWaveoutDevice(const char *name, const char *device, const char *description, const pa_cvolume *v) {
566 WINE_WAVEDEV *wdo;
567 int x;
569 if (WOutDev)
570 wdo = HeapReAlloc(GetProcessHeap(), 0, WOutDev, sizeof(WINE_WAVEDEV) * (PULSE_WodNumDevs + 1));
571 else
572 wdo = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV));
574 if (!wdo) return;
576 WOutDev = wdo;
577 wdo = &WOutDev[PULSE_WodNumDevs++];
578 memset(wdo, 0, sizeof(WINE_WAVEDEV));
580 wdo->device_name = pa_xstrdup(device);
581 wdo->volume.channels = v->channels;
582 for (x = 0; x < v->channels; x++) wdo->volume.values[x] = v->values[x];
583 snprintf(wdo->interface_name, MAXPNAMELEN * 2, "winepulse: %s", name);
584 MultiByteToWideChar(CP_ACP, 0, description, -1, wdo->caps.out.szPname, sizeof(wdo->caps.out.szPname)/sizeof(WCHAR));
585 wdo->caps.out.szPname[sizeof(wdo->caps.out.szPname)/sizeof(WCHAR) - 1] = '\0';
586 wdo->caps.out.wMid = MM_CREATIVE;
587 wdo->caps.out.wPid = MM_CREATIVE_SBP16_WAVEOUT;
588 wdo->caps.out.vDriverVersion = 0x0100;
589 wdo->caps.out.dwSupport = WAVECAPS_VOLUME | WAVECAPS_SAMPLEACCURATE;// | WAVECAPS_DIRECTSOUND;
590 if (v->channels >= 2) {
591 wdo->caps.out.wChannels = 2;
592 wdo->caps.out.dwSupport |= WAVECAPS_LRVOLUME;
593 } else
594 wdo->caps.out.wChannels = 1;
595 wdo->caps.out.dwFormats = PULSE_ALL_FORMATS;
596 memset(&wdo->ds_desc, 0, sizeof(DSDRIVERDESC));
597 memcpy(wdo->ds_desc.szDesc, description, min(sizeof(wdo->ds_desc.szDesc) - 1, strlen(description)));
598 memcpy(wdo->ds_desc.szDrvname, "winepulse.drv", 14);
599 wdo->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
600 wdo->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
601 wdo->ds_caps.dwPrimaryBuffers = 1;
602 wdo->ds_caps.dwFlags = \
603 DSCAPS_PRIMARYMONO |
604 DSCAPS_PRIMARYSTEREO |
605 DSCAPS_PRIMARY8BIT |
606 DSCAPS_PRIMARY16BIT |
607 DSCAPS_SECONDARYMONO |
608 DSCAPS_SECONDARYSTEREO |
609 DSCAPS_SECONDARY8BIT |
610 DSCAPS_SECONDARY16BIT |
611 DSCAPS_CONTINUOUSRATE;
614 /**************************************************************************
615 * PULSE_SourceInfoCallback [internal]
617 static void PULSE_SourceInfoCallback(pa_context *c, const pa_source_info *i, int eol, void *userdata) {
619 if (!eol && i)
620 PULSE_AllocateWaveinDevice(i->name, i->name, i->description, &i->volume);
622 pa_threaded_mainloop_signal(PULSE_ml, 0);
625 /**************************************************************************
626 * PULSE_SinkInfoCallback [internal]
628 static void PULSE_SinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) {
630 if (!eol && i)
631 PULSE_AllocateWaveoutDevice(i->name, i->name, i->description, &i->volume);
633 pa_threaded_mainloop_signal(PULSE_ml, 0);
636 /**************************************************************************
637 * PULSE_ContextNotifyCallback [internal]
639 static void PULSE_ContextNotifyCallback(pa_context *c, void *userdata) {
640 pa_threaded_mainloop_signal(PULSE_ml, 0);
643 /**************************************************************************
644 * PULSE_WaveClose [internal]
646 * Disconnect from the server, deallocated the WaveIn/WaveOut devices, stop and
647 * free the mainloop.
649 static LONG PULSE_WaveClose(void) {
650 int x;
651 TRACE("()\n");
652 if (!PULSE_ml) return DRV_FAILURE;
654 pa_threaded_mainloop_lock(PULSE_ml);
655 /* device_name is allocated with pa_xstrdup, free with pa_xfree */
656 for (x = 0; x < PULSE_WodNumDevs; x++) pa_xfree(WOutDev[x].device_name);
657 for (x = 0; x < PULSE_WidNumDevs; x++) pa_xfree(WInDev[x].device_name);
658 HeapFree(GetProcessHeap(), 0, WOutDev);
659 HeapFree(GetProcessHeap(), 0, WInDev);
660 if (PULSE_context) {
661 PULSE_WaitForOperation(pa_context_drain(PULSE_context, PULSE_ContextNotifyCallback, NULL));
662 pa_context_disconnect(PULSE_context);
663 pa_context_unref(PULSE_context);
664 PULSE_context = NULL;
667 pa_threaded_mainloop_unlock(PULSE_ml);
668 pa_threaded_mainloop_stop(PULSE_ml);
669 pa_threaded_mainloop_free(PULSE_ml);
670 PULSE_ml = NULL;
672 return DRV_SUCCESS;
675 /**************************************************************************
676 * PULSE_WaveInit [internal]
678 * Connects to the pulseaudio server, tries to discover sinks and sources and
679 * allocates the WaveIn/WaveOut devices.
681 static LONG PULSE_WaveInit(void) {
682 char *app_name;
683 char path[PATH_MAX];
684 char *offset = NULL;
685 pa_cvolume fake_cvolume;
687 WOutDev = NULL;
688 WInDev = NULL;
689 PULSE_WodNumDevs = 0;
690 PULSE_WidNumDevs = 0;
691 PULSE_context = NULL;
692 PULSE_ml = NULL;
694 if (!(PULSE_ml = pa_threaded_mainloop_new())) {
695 WARN("Failed to create mainloop object.");
696 return DRV_FAILURE;
699 /* Application name giving to pulse should be unique to the binary so that
700 * pulse-*-restore can be useful */
702 /* Get binary path, and remove path a-la strrchr */
703 if (GetModuleFileNameA(NULL, path, PATH_MAX))
704 offset = strrchr(path, '\\');
706 if (offset && ++offset && offset < path + PATH_MAX) {
707 app_name = pa_xmalloc(strlen(offset) + 8);
708 snprintf(app_name, strlen(offset) + 8, "WINE [%s]", offset);
709 } else
710 app_name = pa_xstrdup("WINE Application");
712 TRACE("App name is \"%s\"\n", app_name);
714 pa_threaded_mainloop_start(PULSE_ml);
715 PULSE_context = pa_context_new(pa_threaded_mainloop_get_api(PULSE_ml), app_name);
716 assert(PULSE_context);
717 pa_xfree(app_name);
719 pa_context_set_state_callback(PULSE_context, PULSE_ContextStateCallback, NULL);
721 pa_threaded_mainloop_lock(PULSE_ml);
723 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(PULSE_context), PA_API_VERSION);
724 TRACE("Attempting to connect to pulseaudio server.\n");
725 if (pa_context_connect(PULSE_context, NULL, 0, NULL) < 0)
726 goto fail;
728 /* Wait for connection */
729 for (;;) {
730 pa_context_state_t state = pa_context_get_state(PULSE_context);
732 if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
733 goto fail;
735 if (state == PA_CONTEXT_READY)
736 break;
738 pa_threaded_mainloop_wait(PULSE_ml);
741 TRACE("Connected to server %s with protocol version: %i.\n",
742 pa_context_get_server(PULSE_context),
743 pa_context_get_server_protocol_version(PULSE_context));
745 fake_cvolume.channels = 2;
746 pa_cvolume_reset(&fake_cvolume, 2);
747 /* FIXME Translations? */
748 PULSE_AllocateWaveoutDevice("default", NULL, "Default", &fake_cvolume);
749 PULSE_AllocateWaveinDevice("default", NULL, "Default", &fake_cvolume);
750 PULSE_WaitForOperation(pa_context_get_sink_info_list(PULSE_context, PULSE_SinkInfoCallback, &PULSE_WodNumDevs));
751 PULSE_WaitForOperation(pa_context_get_source_info_list(PULSE_context, PULSE_SourceInfoCallback, &PULSE_WidNumDevs));
752 TRACE("Found %u output and %u input device(s).\n", PULSE_WodNumDevs - 1, PULSE_WidNumDevs - 1);
754 pa_threaded_mainloop_unlock(PULSE_ml);
756 return DRV_SUCCESS;
758 fail:
759 pa_threaded_mainloop_unlock(PULSE_ml);
760 ERR("Failed to connect to server\n");
761 return DRV_FAILURE;
764 #endif /* HAVE_PULSEAUDIO */
766 /**************************************************************************
767 * DriverProc (WINEPULSE.@)
769 LRESULT CALLBACK PULSE_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
770 LPARAM dwParam1, LPARAM dwParam2) {
772 switch(wMsg) {
773 #ifdef HAVE_PULSEAUDIO
774 case DRV_LOAD: return PULSE_WaveInit();
775 case DRV_FREE: return PULSE_WaveClose();
776 case DRV_OPEN: return 1;
777 case DRV_CLOSE: return 1;
778 case DRV_ENABLE: return 1;
779 case DRV_DISABLE: return 1;
780 case DRV_QUERYCONFIGURE: return 1;
781 case DRV_CONFIGURE: MessageBoxA(0, "PulseAudio MultiMedia Driver !", "PulseAudio Driver", MB_OK); return 1;
782 case DRV_INSTALL: return DRVCNF_RESTART;
783 case DRV_REMOVE: return DRVCNF_RESTART;
784 #endif
785 default:
786 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);