]> code.delx.au - pulseaudio/blob - src/modules/module-waveout.c
alsa-mixer: Add surround 2.1 profile
[pulseaudio] / src / modules / module-waveout.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <windows.h>
28 #include <mmsystem.h>
29
30 #include <pulse/xmalloc.h>
31 #include <pulse/timeval.h>
32
33 #include <pulsecore/sink.h>
34 #include <pulsecore/source.h>
35 #include <pulsecore/module.h>
36 #include <pulsecore/modargs.h>
37 #include <pulsecore/sample-util.h>
38 #include <pulsecore/core-util.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/thread.h>
41 #include <pulsecore/thread-mq.h>
42
43 #include "module-waveout-symdef.h"
44
45 PA_MODULE_AUTHOR("Pierre Ossman");
46 PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source");
47 PA_MODULE_VERSION(PACKAGE_VERSION);
48 PA_MODULE_USAGE(
49 "sink_name=<name for the sink> "
50 "source_name=<name for the source> "
51 "device=<device number> "
52 "device_name=<name of the device> "
53 "record=<enable source?> "
54 "playback=<enable sink?> "
55 "format=<sample format> "
56 "rate=<sample rate> "
57 "channels=<number of channels> "
58 "channel_map=<channel map> "
59 "fragments=<number of fragments> "
60 "fragment_size=<fragment size>");
61
62 #define DEFAULT_SINK_NAME "wave_output"
63 #define DEFAULT_SOURCE_NAME "wave_input"
64
65 #define WAVEOUT_MAX_VOLUME 0xFFFF
66
67 struct userdata {
68 pa_sink *sink;
69 pa_source *source;
70 pa_core *core;
71 pa_usec_t poll_timeout;
72
73 pa_thread *thread;
74 pa_thread_mq thread_mq;
75 pa_rtpoll *rtpoll;
76
77 uint32_t fragments, fragment_size;
78
79 uint32_t free_ofrags, free_ifrags;
80
81 DWORD written_bytes;
82 int sink_underflow;
83
84 int cur_ohdr, cur_ihdr;
85 WAVEHDR *ohdrs, *ihdrs;
86
87 HWAVEOUT hwo;
88 HWAVEIN hwi;
89 pa_module *module;
90
91 CRITICAL_SECTION crit;
92 };
93
94 static const char* const valid_modargs[] = {
95 "sink_name",
96 "source_name",
97 "device",
98 "device_name",
99 "record",
100 "playback",
101 "fragments",
102 "fragment_size",
103 "format",
104 "rate",
105 "channels",
106 "channel_map",
107 NULL
108 };
109
110 static void do_write(struct userdata *u) {
111 uint32_t free_frags;
112 pa_memchunk memchunk;
113 WAVEHDR *hdr;
114 MMRESULT res;
115 void *p;
116
117 if (!u->sink)
118 return;
119
120 if (!PA_SINK_IS_LINKED(u->sink->state))
121 return;
122
123 EnterCriticalSection(&u->crit);
124 free_frags = u->free_ofrags;
125 LeaveCriticalSection(&u->crit);
126
127 if (!u->sink_underflow && (free_frags == u->fragments))
128 pa_log_debug("WaveOut underflow!");
129
130 while (free_frags) {
131 hdr = &u->ohdrs[u->cur_ohdr];
132 if (hdr->dwFlags & WHDR_PREPARED)
133 waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
134
135 hdr->dwBufferLength = 0;
136 while (hdr->dwBufferLength < u->fragment_size) {
137 size_t len;
138
139 len = u->fragment_size - hdr->dwBufferLength;
140
141 pa_sink_render(u->sink, len, &memchunk);
142
143 pa_assert(memchunk.memblock);
144 pa_assert(memchunk.length);
145
146 if (memchunk.length < len)
147 len = memchunk.length;
148
149 p = pa_memblock_acquire(memchunk.memblock);
150 memcpy(hdr->lpData + hdr->dwBufferLength, (char*) p + memchunk.index, len);
151 pa_memblock_release(memchunk.memblock);
152
153 hdr->dwBufferLength += len;
154
155 pa_memblock_unref(memchunk.memblock);
156 memchunk.memblock = NULL;
157 }
158
159 /* Underflow detection */
160 if (hdr->dwBufferLength == 0) {
161 u->sink_underflow = 1;
162 break;
163 }
164 u->sink_underflow = 0;
165
166 res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
167 if (res != MMSYSERR_NOERROR)
168 pa_log_error("Unable to prepare waveOut block: %d", res);
169
170 res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR));
171 if (res != MMSYSERR_NOERROR)
172 pa_log_error("Unable to write waveOut block: %d", res);
173
174 u->written_bytes += hdr->dwBufferLength;
175
176 EnterCriticalSection(&u->crit);
177 u->free_ofrags--;
178 LeaveCriticalSection(&u->crit);
179
180 free_frags--;
181 u->cur_ohdr++;
182 u->cur_ohdr %= u->fragments;
183 }
184 }
185
186 static void do_read(struct userdata *u) {
187 uint32_t free_frags;
188 pa_memchunk memchunk;
189 WAVEHDR *hdr;
190 MMRESULT res;
191 void *p;
192
193 if (!u->source)
194 return;
195
196 if (!PA_SOURCE_IS_LINKED(u->source->state))
197 return;
198
199 EnterCriticalSection(&u->crit);
200 free_frags = u->free_ifrags;
201 u->free_ifrags = 0;
202 LeaveCriticalSection(&u->crit);
203
204 if (free_frags == u->fragments)
205 pa_log_debug("WaveIn overflow!");
206
207 while (free_frags) {
208 hdr = &u->ihdrs[u->cur_ihdr];
209 if (hdr->dwFlags & WHDR_PREPARED)
210 waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
211
212 if (hdr->dwBytesRecorded) {
213 memchunk.memblock = pa_memblock_new(u->core->mempool, hdr->dwBytesRecorded);
214 pa_assert(memchunk.memblock);
215
216 p = pa_memblock_acquire(memchunk.memblock);
217 memcpy((char*) p, hdr->lpData, hdr->dwBytesRecorded);
218 pa_memblock_release(memchunk.memblock);
219
220 memchunk.length = hdr->dwBytesRecorded;
221 memchunk.index = 0;
222
223 pa_source_post(u->source, &memchunk);
224 pa_memblock_unref(memchunk.memblock);
225 }
226
227 res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
228 if (res != MMSYSERR_NOERROR)
229 pa_log_error("Unable to prepare waveIn block: %d", res);
230
231 res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR));
232 if (res != MMSYSERR_NOERROR)
233 pa_log_error("Unable to add waveIn block: %d", res);
234
235 free_frags--;
236 u->cur_ihdr++;
237 u->cur_ihdr %= u->fragments;
238 }
239 }
240
241 static void thread_func(void *userdata) {
242 struct userdata *u = userdata;
243
244 pa_assert(u);
245 pa_assert(u->sink || u->source);
246
247 pa_log_debug("Thread starting up");
248
249 if (u->core->realtime_scheduling)
250 pa_make_realtime(u->core->realtime_priority);
251
252 pa_thread_mq_install(&u->thread_mq);
253
254 for (;;) {
255 int ret;
256 bool need_timer = false;
257
258 if (u->sink) {
259 if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
260 pa_sink_process_rewind(u->sink, 0);
261
262 if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
263 do_write(u);
264 need_timer = true;
265 }
266 }
267
268 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
269 do_read(u);
270 need_timer = true;
271 }
272
273 if (need_timer)
274 pa_rtpoll_set_timer_relative(u->rtpoll, u->poll_timeout);
275 else
276 pa_rtpoll_set_timer_disabled(u->rtpoll);
277
278 /* Hmm, nothing to do. Let's sleep */
279 if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0)
280 goto fail;
281
282 if (ret == 0)
283 goto finish;
284 }
285
286 fail:
287 /* If this was no regular exit from the loop we have to continue
288 * processing messages until we received PA_MESSAGE_SHUTDOWN */
289 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
290 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
291
292 finish:
293 pa_log_debug("Thread shutting down");
294 }
295
296 static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
297 struct userdata *u = (struct userdata*) inst;
298
299 if (msg == WOM_OPEN)
300 pa_log_debug("WaveOut subsystem opened.");
301 if (msg == WOM_CLOSE)
302 pa_log_debug("WaveOut subsystem closed.");
303 if (msg != WOM_DONE)
304 return;
305
306 EnterCriticalSection(&u->crit);
307 u->free_ofrags++;
308 pa_assert(u->free_ofrags <= u->fragments);
309 LeaveCriticalSection(&u->crit);
310 }
311
312 static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
313 struct userdata *u = (struct userdata*) inst;
314
315 if (msg == WIM_OPEN)
316 pa_log_debug("WaveIn subsystem opened.");
317 if (msg == WIM_CLOSE)
318 pa_log_debug("WaveIn subsystem closed.");
319 if (msg != WIM_DATA)
320 return;
321
322 EnterCriticalSection(&u->crit);
323 u->free_ifrags++;
324 pa_assert(u->free_ifrags <= u->fragments);
325 LeaveCriticalSection(&u->crit);
326 }
327
328 static pa_usec_t sink_get_latency(struct userdata *u) {
329 uint32_t free_frags;
330 MMTIME mmt;
331 pa_assert(u);
332 pa_assert(u->sink);
333
334 memset(&mmt, 0, sizeof(mmt));
335 mmt.wType = TIME_BYTES;
336 if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR)
337 return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &u->sink->sample_spec);
338 else {
339 EnterCriticalSection(&u->crit);
340 free_frags = u->free_ofrags;
341 LeaveCriticalSection(&u->crit);
342
343 return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size, &u->sink->sample_spec);
344 }
345 }
346
347 static pa_usec_t source_get_latency(struct userdata *u) {
348 pa_usec_t r = 0;
349 uint32_t free_frags;
350 pa_assert(u);
351 pa_assert(u->source);
352
353 EnterCriticalSection(&u->crit);
354 free_frags = u->free_ifrags;
355 LeaveCriticalSection(&u->crit);
356
357 r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &u->source->sample_spec);
358
359 return r;
360 }
361
362 static int process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
363 struct userdata *u;
364
365 if (pa_sink_isinstance(o)) {
366 u = PA_SINK(o)->userdata;
367
368 switch (code) {
369
370 case PA_SINK_MESSAGE_GET_LATENCY: {
371 pa_usec_t r = 0;
372 if (u->hwo)
373 r = sink_get_latency(u);
374 *((pa_usec_t*) data) = r;
375 return 0;
376 }
377
378 }
379
380 return pa_sink_process_msg(o, code, data, offset, chunk);
381 }
382
383 if (pa_source_isinstance(o)) {
384 u = PA_SOURCE(o)->userdata;
385
386 switch (code) {
387
388 case PA_SOURCE_MESSAGE_GET_LATENCY: {
389 pa_usec_t r = 0;
390 if (u->hwi)
391 r = source_get_latency(u);
392 *((pa_usec_t*) data) = r;
393 return 0;
394 }
395
396 }
397
398 return pa_source_process_msg(o, code, data, offset, chunk);
399 }
400
401 return -1;
402 }
403
404 static void sink_get_volume_cb(pa_sink *s) {
405 struct userdata *u = s->userdata;
406 WAVEOUTCAPS caps;
407 DWORD vol;
408 pa_volume_t left, right;
409
410 if (waveOutGetDevCaps(u->hwo, &caps, sizeof(caps)) != MMSYSERR_NOERROR)
411 return;
412 if (!(caps.dwSupport & WAVECAPS_VOLUME))
413 return;
414
415 if (waveOutGetVolume(u->hwo, &vol) != MMSYSERR_NOERROR)
416 return;
417
418 left = PA_CLAMP_VOLUME((vol & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
419 if (caps.dwSupport & WAVECAPS_LRVOLUME)
420 right = PA_CLAMP_VOLUME(((vol >> 16) & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
421 else
422 right = left;
423
424 /* Windows supports > 2 channels, except for volume control */
425 if (s->real_volume.channels > 2)
426 pa_cvolume_set(&s->real_volume, s->real_volume.channels, (left + right)/2);
427
428 s->real_volume.values[0] = left;
429 if (s->real_volume.channels > 1)
430 s->real_volume.values[1] = right;
431 }
432
433 static void sink_set_volume_cb(pa_sink *s) {
434 struct userdata *u = s->userdata;
435 WAVEOUTCAPS caps;
436 DWORD vol;
437
438 if (waveOutGetDevCaps(u->hwo, &caps, sizeof(caps)) != MMSYSERR_NOERROR)
439 return;
440 if (!(caps.dwSupport & WAVECAPS_VOLUME))
441 return;
442
443 if (s->real_volume.channels == 2 && caps.dwSupport & WAVECAPS_LRVOLUME) {
444 vol = (s->real_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM)
445 | (s->real_volume.values[1] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
446 } else {
447 vol = (pa_cvolume_avg(&(s->real_volume)) * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM)
448 | (pa_cvolume_avg(&(s->real_volume)) * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
449 }
450
451 if (waveOutSetVolume(u->hwo, vol) != MMSYSERR_NOERROR)
452 return;
453 }
454
455 static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) {
456 wf->wFormatTag = WAVE_FORMAT_PCM;
457
458 if (ss->channels > 2) {
459 pa_log_error("More than two channels not supported.");
460 return -1;
461 }
462
463 wf->nChannels = ss->channels;
464
465 wf->nSamplesPerSec = ss->rate;
466
467 if (ss->format == PA_SAMPLE_U8)
468 wf->wBitsPerSample = 8;
469 else if (ss->format == PA_SAMPLE_S16NE)
470 wf->wBitsPerSample = 16;
471 else {
472 pa_log_error("Unsupported sample format, only u8 and s16 are supported.");
473 return -1;
474 }
475
476 wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8;
477 wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign;
478
479 wf->cbSize = 0;
480
481 return 0;
482 }
483
484 int pa__get_n_used(pa_module *m) {
485 struct userdata *u;
486 pa_assert(m);
487 pa_assert(m->userdata);
488 u = (struct userdata*) m->userdata;
489
490 return (u->sink ? pa_sink_used_by(u->sink) : 0) +
491 (u->source ? pa_source_used_by(u->source) : 0);
492 }
493
494 int pa__init(pa_module *m) {
495 struct userdata *u = NULL;
496 HWAVEOUT hwo = INVALID_HANDLE_VALUE;
497 HWAVEIN hwi = INVALID_HANDLE_VALUE;
498 WAVEFORMATEX wf;
499 WAVEOUTCAPS pwoc;
500 MMRESULT result;
501 int nfrags, frag_size;
502 bool record = true, playback = true;
503 unsigned int device;
504 pa_sample_spec ss;
505 pa_channel_map map;
506 pa_modargs *ma = NULL;
507 const char *device_name = NULL;
508 unsigned int i;
509
510 pa_assert(m);
511 pa_assert(m->core);
512
513 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
514 pa_log("failed to parse module arguments.");
515 goto fail;
516 }
517
518 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
519 pa_log("record= and playback= expect boolean argument.");
520 goto fail;
521 }
522
523 if (!playback && !record) {
524 pa_log("neither playback nor record enabled for device.");
525 goto fail;
526 }
527
528 /* Set the device to be opened. If set device_name is used,
529 * else device if set and lastly WAVE_MAPPER is the default */
530 device = WAVE_MAPPER;
531 if (pa_modargs_get_value_u32(ma, "device", &device) < 0) {
532 pa_log("failed to parse device argument");
533 goto fail;
534 }
535 if ((device_name = pa_modargs_get_value(ma, "device_name", NULL)) != NULL) {
536 unsigned int num_devices = waveOutGetNumDevs();
537 for (i = 0; i < num_devices; i++) {
538 if (waveOutGetDevCaps(i, &pwoc, sizeof(pwoc)) == MMSYSERR_NOERROR)
539 if (_stricmp(device_name, pwoc.szPname) == 0)
540 break;
541 }
542 if (i < num_devices)
543 device = i;
544 else {
545 pa_log("device not found: %s", device_name);
546 goto fail;
547 }
548 }
549 if (waveOutGetDevCaps(device, &pwoc, sizeof(pwoc)) == MMSYSERR_NOERROR)
550 device_name = pwoc.szPname;
551 else
552 device_name = "unknown";
553
554 nfrags = 5;
555 frag_size = 8192;
556 if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
557 pa_log("failed to parse fragments arguments");
558 goto fail;
559 }
560
561 ss = m->core->default_sample_spec;
562 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_WAVEEX) < 0) {
563 pa_log("failed to parse sample specification");
564 goto fail;
565 }
566
567 if (ss_to_waveformat(&ss, &wf) < 0)
568 goto fail;
569
570 u = pa_xmalloc(sizeof(struct userdata));
571
572 if (record) {
573 result = waveInOpen(&hwi, device, &wf, 0, 0, WAVE_FORMAT_DIRECT | WAVE_FORMAT_QUERY);
574 if (result != MMSYSERR_NOERROR) {
575 pa_log_warn("Sample spec not supported by WaveIn, falling back to default sample rate.");
576 ss.rate = wf.nSamplesPerSec = m->core->default_sample_spec.rate;
577 }
578 result = waveInOpen(&hwi, device, &wf, (DWORD_PTR) chunk_ready_cb, (DWORD_PTR) u, CALLBACK_FUNCTION);
579 if (result != MMSYSERR_NOERROR) {
580 char errortext[MAXERRORLENGTH];
581 pa_log("Failed to open WaveIn.");
582 if (waveInGetErrorText(result, errortext, sizeof(errortext)) == MMSYSERR_NOERROR)
583 pa_log("Error: %s", errortext);
584 goto fail;
585 }
586 if (waveInStart(hwi) != MMSYSERR_NOERROR) {
587 pa_log("failed to start waveIn");
588 goto fail;
589 }
590 }
591
592 if (playback) {
593 result = waveOutOpen(&hwo, device, &wf, 0, 0, WAVE_FORMAT_DIRECT | WAVE_FORMAT_QUERY);
594 if (result != MMSYSERR_NOERROR) {
595 pa_log_warn("Sample spec not supported by WaveOut, falling back to default sample rate.");
596 ss.rate = wf.nSamplesPerSec = m->core->default_sample_spec.rate;
597 }
598 result = waveOutOpen(&hwo, device, &wf, (DWORD_PTR) chunk_done_cb, (DWORD_PTR) u, CALLBACK_FUNCTION);
599 if (result != MMSYSERR_NOERROR) {
600 char errortext[MAXERRORLENGTH];
601 pa_log("Failed to open WaveOut.");
602 if (waveOutGetErrorText(result, errortext, sizeof(errortext)) == MMSYSERR_NOERROR)
603 pa_log("Error: %s", errortext);
604 goto fail;
605 }
606 }
607
608 InitializeCriticalSection(&u->crit);
609
610 if (hwi != INVALID_HANDLE_VALUE) {
611 pa_source_new_data data;
612 pa_source_new_data_init(&data);
613 data.driver = __FILE__;
614 data.module = m;
615 pa_source_new_data_set_sample_spec(&data, &ss);
616 pa_source_new_data_set_channel_map(&data, &map);
617 pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
618 pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "WaveIn on %s", device_name);
619 u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
620 pa_source_new_data_done(&data);
621
622 pa_assert(u->source);
623 u->source->userdata = u;
624 u->source->parent.process_msg = process_msg;
625 } else
626 u->source = NULL;
627
628 if (hwo != INVALID_HANDLE_VALUE) {
629 pa_sink_new_data data;
630 pa_sink_new_data_init(&data);
631 data.driver = __FILE__;
632 data.module = m;
633 pa_sink_new_data_set_sample_spec(&data, &ss);
634 pa_sink_new_data_set_channel_map(&data, &map);
635 pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
636 pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "WaveOut on %s", device_name);
637 u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
638 pa_sink_new_data_done(&data);
639
640 pa_assert(u->sink);
641 pa_sink_set_get_volume_callback(u->sink, sink_get_volume_cb);
642 pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
643 u->sink->userdata = u;
644 u->sink->parent.process_msg = process_msg;
645 } else
646 u->sink = NULL;
647
648 pa_assert(u->source || u->sink);
649 pa_modargs_free(ma);
650
651 u->core = m->core;
652 u->hwi = hwi;
653 u->hwo = hwo;
654
655 u->fragments = nfrags;
656 u->free_ifrags = u->fragments;
657 u->free_ofrags = u->fragments;
658 u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss));
659
660 u->written_bytes = 0;
661 u->sink_underflow = 1;
662
663 u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 10, &ss);
664 pa_log_debug("Poll timeout = %.1f ms", (double) u->poll_timeout / PA_USEC_PER_MSEC);
665
666 u->cur_ihdr = 0;
667 u->cur_ohdr = 0;
668 u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
669 pa_assert(u->ihdrs);
670 u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
671 pa_assert(u->ohdrs);
672 for (i = 0; i < u->fragments; i++) {
673 u->ihdrs[i].dwBufferLength = u->fragment_size;
674 u->ohdrs[i].dwBufferLength = u->fragment_size;
675 u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size);
676 pa_assert(u->ihdrs);
677 u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size);
678 pa_assert(u->ohdrs);
679 }
680
681 u->module = m;
682 m->userdata = u;
683
684 /* Read mixer settings */
685 if (u->sink)
686 sink_get_volume_cb(u->sink);
687
688 u->rtpoll = pa_rtpoll_new();
689 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
690
691 if (u->sink) {
692 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
693 pa_sink_set_rtpoll(u->sink, u->rtpoll);
694 }
695 if (u->source) {
696 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
697 pa_source_set_rtpoll(u->source, u->rtpoll);
698 }
699
700 if (!(u->thread = pa_thread_new("waveout", thread_func, u))) {
701 pa_log("Failed to create thread.");
702 goto fail;
703 }
704
705 if (u->sink)
706 pa_sink_put(u->sink);
707 if (u->source)
708 pa_source_put(u->source);
709
710 return 0;
711
712 fail:
713 if (ma)
714 pa_modargs_free(ma);
715
716 pa__done(m);
717
718 return -1;
719 }
720
721 void pa__done(pa_module *m) {
722 struct userdata *u;
723 unsigned int i;
724
725 pa_assert(m);
726 pa_assert(m->core);
727
728 if (!(u = m->userdata))
729 return;
730
731 if (u->sink)
732 pa_sink_unlink(u->sink);
733 if (u->source)
734 pa_source_unlink(u->source);
735
736 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
737 if (u->thread)
738 pa_thread_free(u->thread);
739 pa_thread_mq_done(&u->thread_mq);
740
741 if (u->sink)
742 pa_sink_unref(u->sink);
743 if (u->source)
744 pa_source_unref(u->source);
745
746 if (u->rtpoll)
747 pa_rtpoll_free(u->rtpoll);
748
749 if (u->hwi != INVALID_HANDLE_VALUE) {
750 waveInReset(u->hwi);
751 waveInClose(u->hwi);
752 }
753
754 if (u->hwo != INVALID_HANDLE_VALUE) {
755 waveOutReset(u->hwo);
756 waveOutClose(u->hwo);
757 }
758
759 for (i = 0; i < u->fragments; i++) {
760 pa_xfree(u->ihdrs[i].lpData);
761 pa_xfree(u->ohdrs[i].lpData);
762 }
763
764 pa_xfree(u->ihdrs);
765 pa_xfree(u->ohdrs);
766
767 DeleteCriticalSection(&u->crit);
768
769 pa_xfree(u);
770 }