push 9eb9af089d68d39110a91889d3a673043db63c4b
[wine/hacks.git] / dlls / winepulse.drv / pulse.c
blob64274d4809225cd979590cd4e2b00b6cbd2e034f
1 /*
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
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 "mmddk.h"
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <poll.h>
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
52 * structures updated
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
59 switch(msg) {
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);
71 #undef MSG_TO_STR
72 sprintf(unknown, "UNKNOWN(0x%08x)", msg);
73 return unknown;
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 */
81 #define USE_PIPE_SYNC
83 #ifdef USE_PIPE_SYNC
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)
92 #else
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)
100 #endif
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)
112 omr->msg_toget = 0;
113 omr->msg_tosave = 0;
114 INIT_OMR(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");
120 return 0;
123 /******************************************************************
124 * PULSE_DestroyRingMessage
127 int PULSE_DestroyRingMessage(PULSE_MSG_RING* omr)
129 CLOSE_OMR(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);
135 return 0;
137 /******************************************************************
138 * PULSE_ResetRingMessage
141 void PULSE_ResetRingMessage(PULSE_MSG_RING* omr)
143 RESET_OMR(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
172 omr->msg_toget.
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;
183 if (wait)
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);
190 return 0;
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;
204 else
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 */
213 SIGNAL_OMR(omr);
214 if (wait)
216 /* wait for playback/record thread to have processed the message */
217 WaitForSingleObject(hEvent, INFINITE);
218 CloseHandle(hEvent);
220 return 1;
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);
236 return 0;
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;
244 CLEAR_OMR(omr);
245 LeaveCriticalSection(&omr->msg_crst);
246 return 1;
249 /**************************************************************************
250 * Utility Functions
253 /******************************************************************
254 * PULSE_setupFormat
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)
262 return FALSE;
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) {
270 case 8:
271 ss->format = PA_SAMPLE_U8;
272 return TRUE;
273 case 16:
274 ss->format = PA_SAMPLE_S16NE;
275 return TRUE;
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) {
286 case 8:
287 ss->format=PA_SAMPLE_U8;
288 return TRUE;
289 case 16:
290 ss->format=PA_SAMPLE_S16NE;
291 return TRUE;
292 case 43:
293 ss->format=PA_SAMPLE_S32NE;
294 return TRUE;
296 } else
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;
304 return TRUE;
307 } else
308 WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT "
309 "supported\n");
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;
313 return TRUE;
314 } else
315 ERR("WAVE_FORMAT_MULAW and WAVE_FORMAT_ALAW wBitsPerSample must = 8\n");
316 } else
317 WARN("only WAVE_FORMAT_PCM, WAVE_FORMAT_MULAW, WAVE_FORMAT_ALAW and WAVE_FORMAT_EXTENSIBLE supported\n");
319 return FALSE;
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);
334 for (; x>0; ) {
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(&current_instance->msgRing, WINE_WM_CLOSING, 1, TRUE);
343 if (current_instance->hThread != INVALID_HANDLE_VALUE) {
344 /* Overkill? */
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(&current_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);
361 *allocated = 0;
364 /******************************************************************
365 * PULSE_wait_for_operation
367 * Waits for pa operations to complete, ensures success and dereferences the
368 * operations.
370 void PULSE_wait_for_operation(pa_operation *o, WINE_WAVEINST *wd) {
371 assert(o && wd);
373 TRACE("Waiting...");
375 for (;;) {
377 if (!wd->stream ||
378 !PULSE_context ||
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);
384 break;
387 if (pa_operation_get_state(o) != PA_OPERATION_RUNNING)
388 break;
390 pa_threaded_mainloop_wait(PULSE_ml);
392 TRACE(" done\n");
393 pa_operation_unref(o);
396 /**************************************************************************
397 * Common Callbacks
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;
407 assert(s && ww);
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;
424 assert(s && wd);
426 switch (pa_stream_get_state(s)) {
428 case PA_STREAM_READY:
429 TRACE("Stream ready\n");
430 break;
431 case PA_STREAM_TERMINATED:
432 TRACE("Stream terminated\n");
433 break;
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);
439 break;
440 case PA_STREAM_UNCONNECTED:
441 case PA_STREAM_CREATING:
442 return;
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) {
451 if (!success)
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) {
461 if (!success)
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) {
475 assert(c);
477 switch (pa_context_get_state(c)) {
478 case PA_CONTEXT_CONNECTING:
479 case PA_CONTEXT_AUTHORIZING:
480 case PA_CONTEXT_SETTING_NAME:
481 break;
483 case PA_CONTEXT_READY:
484 case PA_CONTEXT_TERMINATED:
485 pa_threaded_mainloop_signal(PULSE_ml, 0);
486 break;
488 case PA_CONTEXT_FAILED:
489 default:
490 ERR("Conneciton failure: %s\n", pa_strerror(pa_context_errno(c)));
492 if (PULSE_context) {
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) {
510 WINE_WAVEDEV *wwi;
511 const char *description;
512 int x;
514 if (WInDev)
515 wwi = HeapReAlloc(GetProcessHeap(), 0, WInDev, sizeof(WINE_WAVEDEV) * ((*allocated)+1));
516 else
517 wwi = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV));
519 if (!wwi)
520 return;
522 WInDev = wwi;
523 wwi = &WInDev[(*allocated)++];
525 if (i) {
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: ")));
532 } else {
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) {
579 WINE_WAVEDEV *wwo;
580 const char *description;
581 int x;
583 if (WOutDev)
584 wwo = HeapReAlloc(GetProcessHeap(), 0, WOutDev, sizeof(WINE_WAVEDEV) * ((*allocated)+1));
585 else
586 wwo = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_WAVEDEV));
588 if (!wwo)
589 return;
591 WOutDev = wwo;
592 wwo = &WOutDev[(*allocated)++];
594 if (i) {
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: ")));
601 } else {
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) {
651 assert(c);
652 if (!eol && i)
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) {
665 assert(c);
666 if (!eol && i)
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;
680 DWORD allocated;
682 WOutDev = NULL;
683 WInDev = NULL;
684 PULSE_WodNumDevs = 0;
685 PULSE_WidNumDevs = 0;
686 PULSE_context = NULL;
687 PULSE_ml = NULL;
689 if (!(PULSE_ml = pa_threaded_mainloop_new())) {
690 WARN("Failed to create mainloop object.");
691 return -1;
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)
703 return 0;
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)));
710 return -1;
713 /* Wait for connection */
714 for (;;) {
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);
723 return -1;
726 if (state == PA_CONTEXT_READY) {
727 TRACE("Connection succeeded!\n");
728 break;
731 pa_threaded_mainloop_wait(PULSE_ml);
734 /* Ask for all the sinks and create objects in the WOutDev array */
735 allocated=0;
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);
739 assert(o);
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 */
750 allocated=0;
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);
755 assert(o);
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);
765 return 1;
768 /**************************************************************************
769 * PULSE_WaveClose [internal]
771 * Disconnect from the server, deallocated the WaveIn/WaveOut devices, stop and
772 * free the mainloop.
775 LONG PULSE_WaveClose(void) {
776 pa_threaded_mainloop_lock(PULSE_ml);
777 if (PULSE_context) {
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);
790 return 1;
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) {
801 switch(wMsg) {
802 #ifdef HAVE_PULSEAUDIO
803 case DRV_LOAD: PULSE_WaveInit();
804 return 1;
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;
814 #endif
815 default:
816 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);