]> code.delx.au - pulseaudio/blob - src/modules/module-waveout.c
Merge remote branch 'origin/master-tx'
[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/mainloop-api.h>
31
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34
35 #include <pulsecore/sink.h>
36 #include <pulsecore/source.h>
37 #include <pulsecore/module.h>
38 #include <pulsecore/modargs.h>
39 #include <pulsecore/sample-util.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/log.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 "record=<enable source?> "
53 "playback=<enable sink?> "
54 "format=<sample format> "
55 "channels=<number of channels> "
56 "rate=<sample rate> "
57 "fragments=<number of fragments> "
58 "fragment_size=<fragment size> "
59 "channel_map=<channel map>")
60
61 #define DEFAULT_SINK_NAME "wave_output"
62 #define DEFAULT_SOURCE_NAME "wave_input"
63
64 #define WAVEOUT_MAX_VOLUME 0xFFFF
65
66 struct userdata {
67 pa_sink *sink;
68 pa_source *source;
69 pa_core *core;
70 pa_time_event *event;
71 pa_defer_event *defer;
72 pa_usec_t poll_timeout;
73
74 uint32_t fragments, fragment_size;
75
76 uint32_t free_ofrags, free_ifrags;
77
78 DWORD written_bytes;
79 int sink_underflow;
80
81 int cur_ohdr, cur_ihdr;
82 WAVEHDR *ohdrs, *ihdrs;
83
84 HWAVEOUT hwo;
85 HWAVEIN hwi;
86 pa_module *module;
87
88 CRITICAL_SECTION crit;
89 };
90
91 static const char* const valid_modargs[] = {
92 "sink_name",
93 "source_name",
94 "device",
95 "record",
96 "playback",
97 "fragments",
98 "fragment_size",
99 "format",
100 "rate",
101 "channels",
102 "channel_map",
103 NULL
104 };
105
106 static void update_usage(struct userdata *u) {
107 pa_module_set_used(u->module,
108 (u->sink ? pa_sink_used_by(u->sink) : 0) +
109 (u->source ? pa_source_used_by(u->source) : 0));
110 }
111
112 static void do_write(struct userdata *u)
113 {
114 uint32_t free_frags;
115 pa_memchunk memchunk;
116 WAVEHDR *hdr;
117 MMRESULT res;
118
119 if (!u->sink)
120 return;
121
122 EnterCriticalSection(&u->crit);
123 free_frags = u->free_ofrags;
124 LeaveCriticalSection(&u->crit);
125
126 if (!u->sink_underflow && (free_frags == u->fragments))
127 pa_log_debug("WaveOut underflow!");
128
129 while (free_frags) {
130 hdr = &u->ohdrs[u->cur_ohdr];
131 if (hdr->dwFlags & WHDR_PREPARED)
132 waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
133
134 hdr->dwBufferLength = 0;
135 while (hdr->dwBufferLength < u->fragment_size) {
136 size_t len;
137
138 len = u->fragment_size - hdr->dwBufferLength;
139
140 if (pa_sink_render(u->sink, len, &memchunk) < 0)
141 break;
142
143 assert(memchunk.memblock);
144 assert(memchunk.memblock->data);
145 assert(memchunk.length);
146
147 if (memchunk.length < len)
148 len = memchunk.length;
149
150 memcpy(hdr->lpData + hdr->dwBufferLength,
151 (char*)memchunk.memblock->data + memchunk.index, len);
152
153 hdr->dwBufferLength += len;
154
155 pa_memblock_unref(memchunk.memblock);
156 memchunk.memblock = NULL;
157 }
158
159 /* Insufficient data in sink buffer? */
160 if (hdr->dwBufferLength == 0) {
161 u->sink_underflow = 1;
162 break;
163 }
164
165 u->sink_underflow = 0;
166
167 res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
168 if (res != MMSYSERR_NOERROR) {
169 pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d",
170 res);
171 }
172 res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR));
173 if (res != MMSYSERR_NOERROR) {
174 pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d",
175 res);
176 }
177
178 u->written_bytes += hdr->dwBufferLength;
179
180 EnterCriticalSection(&u->crit);
181 u->free_ofrags--;
182 LeaveCriticalSection(&u->crit);
183
184 free_frags--;
185 u->cur_ohdr++;
186 u->cur_ohdr %= u->fragments;
187 }
188 }
189
190 static void do_read(struct userdata *u)
191 {
192 uint32_t free_frags;
193 pa_memchunk memchunk;
194 WAVEHDR *hdr;
195 MMRESULT res;
196
197 if (!u->source)
198 return;
199
200 EnterCriticalSection(&u->crit);
201
202 free_frags = u->free_ifrags;
203 u->free_ifrags = 0;
204
205 LeaveCriticalSection(&u->crit);
206
207 if (free_frags == u->fragments)
208 pa_log_debug("WaveIn overflow!");
209
210 while (free_frags) {
211 hdr = &u->ihdrs[u->cur_ihdr];
212 if (hdr->dwFlags & WHDR_PREPARED)
213 waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
214
215 if (hdr->dwBytesRecorded) {
216 memchunk.memblock = pa_memblock_new(u->core->mempool, hdr->dwBytesRecorded);
217 assert(memchunk.memblock);
218
219 memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded);
220
221 memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded;
222 memchunk.index = 0;
223
224 pa_source_post(u->source, &memchunk);
225 pa_memblock_unref(memchunk.memblock);
226 }
227
228 res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
229 if (res != MMSYSERR_NOERROR) {
230 pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d",
231 res);
232 }
233 res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR));
234 if (res != MMSYSERR_NOERROR) {
235 pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d",
236 res);
237 }
238
239 free_frags--;
240 u->cur_ihdr++;
241 u->cur_ihdr %= u->fragments;
242 }
243 }
244
245 static void poll_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) {
246 struct userdata *u = userdata;
247 struct timeval ntv;
248
249 assert(u);
250
251 update_usage(u);
252
253 do_write(u);
254 do_read(u);
255
256 pa_gettimeofday(&ntv);
257 pa_timeval_add(&ntv, u->poll_timeout);
258
259 a->rtclock_time_restart(e, &ntv);
260 }
261
262 static void defer_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) {
263 struct userdata *u = userdata;
264
265 assert(u);
266
267 a->defer_enable(e, 0);
268
269 do_write(u);
270 do_read(u);
271 }
272
273 static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
274 struct userdata *u = (struct userdata *)inst;
275
276 if (msg != WOM_DONE)
277 return;
278
279 EnterCriticalSection(&u->crit);
280
281 u->free_ofrags++;
282 assert(u->free_ofrags <= u->fragments);
283
284 LeaveCriticalSection(&u->crit);
285 }
286
287 static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
288 struct userdata *u = (struct userdata *)inst;
289
290 if (msg != WIM_DATA)
291 return;
292
293 EnterCriticalSection(&u->crit);
294
295 u->free_ifrags++;
296 assert(u->free_ifrags <= u->fragments);
297
298 LeaveCriticalSection(&u->crit);
299 }
300
301 static pa_usec_t sink_get_latency_cb(pa_sink *s) {
302 struct userdata *u = s->userdata;
303 uint32_t free_frags;
304 MMTIME mmt;
305 assert(s && u && u->sink);
306
307 memset(&mmt, 0, sizeof(mmt));
308 mmt.wType = TIME_BYTES;
309 if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR)
310 return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &s->sample_spec);
311 else {
312 EnterCriticalSection(&u->crit);
313
314 free_frags = u->free_ofrags;
315
316 LeaveCriticalSection(&u->crit);
317
318 return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size,
319 &s->sample_spec);
320 }
321 }
322
323 static pa_usec_t source_get_latency_cb(pa_source *s) {
324 pa_usec_t r = 0;
325 struct userdata *u = s->userdata;
326 uint32_t free_frags;
327 assert(s && u && u->sink);
328
329 EnterCriticalSection(&u->crit);
330
331 free_frags = u->free_ifrags;
332
333 LeaveCriticalSection(&u->crit);
334
335 r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec);
336
337 return r;
338 }
339
340 static void notify_sink_cb(pa_sink *s) {
341 struct userdata *u = s->userdata;
342 assert(u);
343
344 u->core->mainloop->defer_enable(u->defer, 1);
345 }
346
347 static void notify_source_cb(pa_source *s) {
348 struct userdata *u = s->userdata;
349 assert(u);
350
351 u->core->mainloop->defer_enable(u->defer, 1);
352 }
353
354 static int sink_get_hw_volume_cb(pa_sink *s) {
355 struct userdata *u = s->userdata;
356 DWORD vol;
357 pa_volume_t left, right;
358
359 if (waveOutGetVolume(u->hwo, &vol) != MMSYSERR_NOERROR)
360 return -1;
361
362 left = (vol & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME;
363 right = ((vol >> 16) & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME;
364
365 /* Windows supports > 2 channels, except for volume control */
366 if (s->hw_volume.channels > 2)
367 pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, (left + right)/2);
368
369 s->hw_volume.values[0] = left;
370 if (s->hw_volume.channels > 1)
371 s->hw_volume.values[1] = right;
372
373 return 0;
374 }
375
376 static int sink_set_hw_volume_cb(pa_sink *s) {
377 struct userdata *u = s->userdata;
378 DWORD vol;
379
380 vol = s->hw_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM;
381 if (s->hw_volume.channels > 1)
382 vol |= (s->hw_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
383
384 if (waveOutSetVolume(u->hwo, vol) != MMSYSERR_NOERROR)
385 return -1;
386
387 return 0;
388 }
389
390 static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) {
391 wf->wFormatTag = WAVE_FORMAT_PCM;
392
393 if (ss->channels > 2) {
394 pa_log_error("ERROR: More than two channels not supported.");
395 return -1;
396 }
397
398 wf->nChannels = ss->channels;
399
400 switch (ss->rate) {
401 case 8000:
402 case 11025:
403 case 22005:
404 case 44100:
405 break;
406 default:
407 pa_log_error("ERROR: Unsupported sample rate.");
408 return -1;
409 }
410
411 wf->nSamplesPerSec = ss->rate;
412
413 if (ss->format == PA_SAMPLE_U8)
414 wf->wBitsPerSample = 8;
415 else if (ss->format == PA_SAMPLE_S16NE)
416 wf->wBitsPerSample = 16;
417 else {
418 pa_log_error("ERROR: Unsupported sample format.");
419 return -1;
420 }
421
422 wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8;
423 wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign;
424
425 wf->cbSize = 0;
426
427 return 0;
428 }
429
430 int pa__init(pa_core *c, pa_module*m) {
431 struct userdata *u = NULL;
432 HWAVEOUT hwo = INVALID_HANDLE_VALUE;
433 HWAVEIN hwi = INVALID_HANDLE_VALUE;
434 WAVEFORMATEX wf;
435 int nfrags, frag_size;
436 int record = 1, playback = 1;
437 unsigned int device;
438 pa_sample_spec ss;
439 pa_channel_map map;
440 pa_modargs *ma = NULL;
441 unsigned int i;
442 struct timeval tv;
443
444 assert(c && m);
445
446 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
447 pa_log("failed to parse module arguments.");
448 goto fail;
449 }
450
451 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
452 pa_log("record= and playback= expect boolean argument.");
453 goto fail;
454 }
455
456 if (!playback && !record) {
457 pa_log("neither playback nor record enabled for device.");
458 goto fail;
459 }
460
461 device = WAVE_MAPPER;
462 if (pa_modargs_get_value_u32(ma, "device", &device) < 0) {
463 pa_log("failed to parse device argument");
464 goto fail;
465 }
466
467 nfrags = 5;
468 frag_size = 8192;
469 if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
470 pa_log("failed to parse fragments arguments");
471 goto fail;
472 }
473
474 ss = c->default_sample_spec;
475 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_WAVEEX) < 0) {
476 pa_log("failed to parse sample specification");
477 goto fail;
478 }
479
480 if (ss_to_waveformat(&ss, &wf) < 0)
481 goto fail;
482
483 u = pa_xmalloc(sizeof(struct userdata));
484
485 if (record) {
486 if (waveInOpen(&hwi, device, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
487 pa_log("failed to open waveIn");
488 goto fail;
489 }
490 if (waveInStart(hwi) != MMSYSERR_NOERROR) {
491 pa_log("failed to start waveIn");
492 goto fail;
493 }
494 pa_log_debug("Opened waveIn subsystem.");
495 }
496
497 if (playback) {
498 if (waveOutOpen(&hwo, device, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
499 pa_log("failed to open waveOut");
500 goto fail;
501 }
502 pa_log_debug("Opened waveOut subsystem.");
503 }
504
505 InitializeCriticalSection(&u->crit);
506
507 if (hwi != INVALID_HANDLE_VALUE) {
508 u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
509 assert(u->source);
510 u->source->userdata = u;
511 u->source->notify = notify_source_cb;
512 u->source->get_latency = source_get_latency_cb;
513 pa_source_set_owner(u->source, m);
514 pa_source_set_description(u->source, "Windows waveIn PCM");
515 u->source->is_hardware = 1;
516 } else
517 u->source = NULL;
518
519 if (hwo != INVALID_HANDLE_VALUE) {
520 u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
521 assert(u->sink);
522 u->sink->notify = notify_sink_cb;
523 u->sink->get_latency = sink_get_latency_cb;
524 u->sink->get_hw_volume = sink_get_hw_volume_cb;
525 u->sink->set_hw_volume = sink_set_hw_volume_cb;
526 u->sink->userdata = u;
527 pa_sink_set_owner(u->sink, m);
528 pa_sink_set_description(u->sink, "Windows waveOut PCM");
529 u->sink->is_hardware = 1;
530 } else
531 u->sink = NULL;
532
533 assert(u->source || u->sink);
534
535 u->core = c;
536 u->hwi = hwi;
537 u->hwo = hwo;
538
539 u->fragments = nfrags;
540 u->free_ifrags = u->fragments;
541 u->free_ofrags = u->fragments;
542 u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss));
543
544 u->written_bytes = 0;
545 u->sink_underflow = 1;
546
547 u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 10, &ss);
548
549 pa_gettimeofday(&tv);
550 pa_timeval_add(&tv, u->poll_timeout);
551
552 u->event = c->mainloop->rtclock_time_new(c->mainloop, &tv, poll_cb, u);
553 assert(u->event);
554
555 u->defer = c->mainloop->defer_new(c->mainloop, defer_cb, u);
556 assert(u->defer);
557 c->mainloop->defer_enable(u->defer, 0);
558
559 u->cur_ihdr = 0;
560 u->cur_ohdr = 0;
561 u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
562 assert(u->ihdrs);
563 u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
564 assert(u->ohdrs);
565 for (i = 0;i < u->fragments;i++) {
566 u->ihdrs[i].dwBufferLength = u->fragment_size;
567 u->ohdrs[i].dwBufferLength = u->fragment_size;
568 u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size);
569 assert(u->ihdrs);
570 u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size);
571 assert(u->ohdrs);
572 }
573
574 u->module = m;
575 m->userdata = u;
576
577 pa_modargs_free(ma);
578
579 /* Read mixer settings */
580 if (u->sink)
581 sink_get_hw_volume_cb(u->sink);
582
583 return 0;
584
585 fail:
586 if (hwi != INVALID_HANDLE_VALUE)
587 waveInClose(hwi);
588
589 if (hwo != INVALID_HANDLE_VALUE)
590 waveOutClose(hwo);
591
592 if (u)
593 pa_xfree(u);
594
595 if (ma)
596 pa_modargs_free(ma);
597
598 return -1;
599 }
600
601 void pa__done(pa_core *c, pa_module*m) {
602 struct userdata *u;
603 unsigned int i;
604
605 assert(c && m);
606
607 if (!(u = m->userdata))
608 return;
609
610 if (u->event)
611 c->mainloop->time_free(u->event);
612
613 if (u->defer)
614 c->mainloop->defer_free(u->defer);
615
616 if (u->sink) {
617 pa_sink_disconnect(u->sink);
618 pa_sink_unref(u->sink);
619 }
620
621 if (u->source) {
622 pa_source_disconnect(u->source);
623 pa_source_unref(u->source);
624 }
625
626 if (u->hwi != INVALID_HANDLE_VALUE) {
627 waveInReset(u->hwi);
628 waveInClose(u->hwi);
629 }
630
631 if (u->hwo != INVALID_HANDLE_VALUE) {
632 waveOutReset(u->hwo);
633 waveOutClose(u->hwo);
634 }
635
636 for (i = 0;i < u->fragments;i++) {
637 pa_xfree(u->ihdrs[i].lpData);
638 pa_xfree(u->ohdrs[i].lpData);
639 }
640
641 pa_xfree(u->ihdrs);
642 pa_xfree(u->ohdrs);
643
644 DeleteCriticalSection(&u->crit);
645
646 pa_xfree(u);
647 }