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