]> code.delx.au - pulseaudio/blob - src/modules/module-solaris.c
Remove silence generation in solaris module.
[pulseaudio] / src / modules / module-solaris.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <limits.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37
38 #include <signal.h>
39 #include <stropts.h>
40 #include <sys/conf.h>
41 #include <sys/audio.h>
42
43 #include <pulse/error.h>
44 #include <pulse/mainloop-signal.h>
45 #include <pulse/xmalloc.h>
46 #include <pulse/timeval.h>
47
48 #include <pulsecore/iochannel.h>
49 #include <pulsecore/sink.h>
50 #include <pulsecore/source.h>
51 #include <pulsecore/module.h>
52 #include <pulsecore/sample-util.h>
53 #include <pulsecore/core-util.h>
54 #include <pulsecore/modargs.h>
55 #include <pulsecore/log.h>
56 #include <pulsecore/core-error.h>
57
58 #include "module-solaris-symdef.h"
59
60 PA_MODULE_AUTHOR("Pierre Ossman")
61 PA_MODULE_DESCRIPTION("Solaris Sink/Source")
62 PA_MODULE_VERSION(PACKAGE_VERSION)
63 PA_MODULE_USAGE(
64 "sink_name=<name for the sink> "
65 "source_name=<name for the source> "
66 "device=<OSS device> record=<enable source?> "
67 "playback=<enable sink?> "
68 "format=<sample format> "
69 "channels=<number of channels> "
70 "rate=<sample rate> "
71 "buffer_size=<record buffer size> "
72 "channel_map=<channel map>")
73
74 struct userdata {
75 pa_sink *sink;
76 pa_source *source;
77 pa_iochannel *io;
78 pa_core *core;
79 pa_time_event *timer;
80 pa_usec_t poll_timeout;
81 pa_signal_event *sig;
82
83 pa_memchunk memchunk;
84
85 uint32_t frame_size;
86 uint32_t buffer_size;
87 unsigned int written_bytes, read_bytes;
88 int sink_underflow;
89
90 int fd;
91 pa_module *module;
92 };
93
94 static const char* const valid_modargs[] = {
95 "sink_name",
96 "source_name",
97 "device",
98 "record",
99 "playback",
100 "buffer_size",
101 "format",
102 "rate",
103 "channels",
104 "channel_map",
105 NULL
106 };
107
108 #define DEFAULT_SINK_NAME "solaris_output"
109 #define DEFAULT_SOURCE_NAME "solaris_input"
110 #define DEFAULT_DEVICE "/dev/audio"
111
112 #define CHUNK_SIZE 2048
113
114 static void update_usage(struct userdata *u) {
115 pa_module_set_used(u->module,
116 (u->sink ? pa_sink_used_by(u->sink) : 0) +
117 (u->source ? pa_source_used_by(u->source) : 0));
118 }
119
120 static void do_write(struct userdata *u) {
121 audio_info_t info;
122 int err;
123 size_t len;
124 ssize_t r;
125
126 assert(u);
127
128 /* We cannot check pa_iochannel_is_writable() because of our buffer hack */
129 if (!u->sink)
130 return;
131
132 update_usage(u);
133
134 err = ioctl(u->fd, AUDIO_GETINFO, &info);
135 assert(err >= 0);
136
137 /*
138 * Since we cannot modify the size of the output buffer we fake it
139 * by not filling it more than u->buffer_size.
140 */
141 len = u->buffer_size;
142 len -= u->written_bytes - (info.play.samples * u->frame_size);
143
144 /* The sample counter can sometimes go backwards :( */
145 if (len > u->buffer_size)
146 len = 0;
147
148 if (!u->sink_underflow && (len == u->buffer_size))
149 pa_log_debug("Solaris buffer underflow!");
150
151 len -= len % u->frame_size;
152
153 if (len == 0)
154 return;
155
156 if (!u->memchunk.length) {
157 if (pa_sink_render(u->sink, len, &u->memchunk) < 0) {
158 u->sink_underflow = 1;
159 return;
160 }
161 }
162
163 u->sink_underflow = 0;
164
165 assert(u->memchunk.memblock);
166 assert(u->memchunk.memblock->data);
167 assert(u->memchunk.length);
168
169 if (u->memchunk.length < len) {
170 len = u->memchunk.length;
171 len -= len % u->frame_size;
172 assert(len);
173 }
174
175 if ((r = pa_iochannel_write(u->io,
176 (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, len)) < 0) {
177 pa_log("write() failed: %s", pa_cstrerror(errno));
178 return;
179 }
180
181 assert(r % u->frame_size == 0);
182
183 u->memchunk.index += r;
184 u->memchunk.length -= r;
185
186 if (u->memchunk.length <= 0) {
187 pa_memblock_unref(u->memchunk.memblock);
188 u->memchunk.memblock = NULL;
189 }
190
191 u->written_bytes += r;
192 }
193
194 static void do_read(struct userdata *u) {
195 pa_memchunk memchunk;
196 int err, l;
197 ssize_t r;
198 assert(u);
199
200 if (!u->source || !pa_iochannel_is_readable(u->io))
201 return;
202
203 update_usage(u);
204
205 err = ioctl(u->fd, I_NREAD, &l);
206 assert(err >= 0);
207
208 memchunk.memblock = pa_memblock_new(u->core->mempool, l);
209 assert(memchunk.memblock);
210 if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
211 pa_memblock_unref(memchunk.memblock);
212 if (errno != EAGAIN)
213 pa_log("read() failed: %s", pa_cstrerror(errno));
214 return;
215 }
216
217 assert(r <= (ssize_t) memchunk.memblock->length);
218 memchunk.length = memchunk.memblock->length = r;
219 memchunk.index = 0;
220
221 pa_source_post(u->source, &memchunk);
222 pa_memblock_unref(memchunk.memblock);
223
224 u->read_bytes += r;
225 }
226
227 static void io_callback(pa_iochannel *io, void*userdata) {
228 struct userdata *u = userdata;
229 assert(u);
230 do_write(u);
231 do_read(u);
232 }
233
234 static void timer_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) {
235 struct userdata *u = userdata;
236 struct timeval ntv;
237
238 assert(u);
239
240 do_write(u);
241
242 pa_gettimeofday(&ntv);
243 pa_timeval_add(&ntv, u->poll_timeout);
244
245 a->time_restart(e, &ntv);
246 }
247
248 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
249 struct userdata *u = userdata;
250 pa_cvolume old_vol;
251
252 assert(u);
253
254 if (u->sink) {
255 assert(u->sink->get_hw_volume);
256 memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume));
257 if (u->sink->get_hw_volume(u->sink) < 0)
258 return;
259 if (memcmp(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)) != 0) {
260 pa_subscription_post(u->sink->core,
261 PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE,
262 u->sink->index);
263 }
264 }
265
266 if (u->source) {
267 assert(u->source->get_hw_volume);
268 memcpy(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume));
269 if (u->source->get_hw_volume(u->source) < 0)
270 return;
271 if (memcmp(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume)) != 0) {
272 pa_subscription_post(u->source->core,
273 PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE,
274 u->source->index);
275 }
276 }
277 }
278
279 static pa_usec_t sink_get_latency_cb(pa_sink *s) {
280 pa_usec_t r = 0;
281 audio_info_t info;
282 int err;
283 struct userdata *u = s->userdata;
284 assert(s && u && u->sink);
285
286 err = ioctl(u->fd, AUDIO_GETINFO, &info);
287 assert(err >= 0);
288
289 r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec);
290 r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &s->sample_spec);
291
292 if (u->memchunk.memblock)
293 r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec);
294
295 return r;
296 }
297
298 static pa_usec_t source_get_latency_cb(pa_source *s) {
299 pa_usec_t r = 0;
300 struct userdata *u = s->userdata;
301 audio_info_t info;
302 int err;
303 assert(s && u && u->source);
304
305 err = ioctl(u->fd, AUDIO_GETINFO, &info);
306 assert(err >= 0);
307
308 r += pa_bytes_to_usec(info.record.samples * u->frame_size, &s->sample_spec);
309 r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec);
310
311 return r;
312 }
313
314 static int sink_get_hw_volume_cb(pa_sink *s) {
315 struct userdata *u = s->userdata;
316 audio_info_t info;
317 int err;
318
319 err = ioctl(u->fd, AUDIO_GETINFO, &info);
320 assert(err >= 0);
321
322 pa_cvolume_set(&s->hw_volume, s->hw_volume.channels,
323 info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
324
325 return 0;
326 }
327
328 static int sink_set_hw_volume_cb(pa_sink *s) {
329 struct userdata *u = s->userdata;
330 audio_info_t info;
331
332 AUDIO_INITINFO(&info);
333
334 info.play.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
335 assert(info.play.gain <= AUDIO_MAX_GAIN);
336
337 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
338 if (errno == EINVAL)
339 pa_log("AUDIO_SETINFO: Unsupported volume.");
340 else
341 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
342 return -1;
343 }
344
345 return 0;
346 }
347
348 static int sink_get_hw_mute_cb(pa_sink *s) {
349 struct userdata *u = s->userdata;
350 audio_info_t info;
351 int err;
352
353 err = ioctl(u->fd, AUDIO_GETINFO, &info);
354 assert(err >= 0);
355
356 s->hw_muted = !!info.output_muted;
357
358 return 0;
359 }
360
361 static int sink_set_hw_mute_cb(pa_sink *s) {
362 struct userdata *u = s->userdata;
363 audio_info_t info;
364
365 AUDIO_INITINFO(&info);
366
367 info.output_muted = !!s->hw_muted;
368
369 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
370 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
371 return -1;
372 }
373
374 return 0;
375 }
376
377 static int source_get_hw_volume_cb(pa_source *s) {
378 struct userdata *u = s->userdata;
379 audio_info_t info;
380 int err;
381
382 err = ioctl(u->fd, AUDIO_GETINFO, &info);
383 assert(err >= 0);
384
385 pa_cvolume_set(&s->hw_volume, s->hw_volume.channels,
386 info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
387
388 return 0;
389 }
390
391 static int source_set_hw_volume_cb(pa_source *s) {
392 struct userdata *u = s->userdata;
393 audio_info_t info;
394
395 AUDIO_INITINFO(&info);
396
397 info.record.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
398 assert(info.record.gain <= AUDIO_MAX_GAIN);
399
400 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
401 if (errno == EINVAL)
402 pa_log("AUDIO_SETINFO: Unsupported volume.");
403 else
404 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
405 return -1;
406 }
407
408 return 0;
409 }
410
411 static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) {
412 audio_info_t info;
413
414 AUDIO_INITINFO(&info);
415
416 if (mode != O_RDONLY) {
417 info.play.sample_rate = ss->rate;
418 info.play.channels = ss->channels;
419 switch (ss->format) {
420 case PA_SAMPLE_U8:
421 info.play.precision = 8;
422 info.play.encoding = AUDIO_ENCODING_LINEAR;
423 break;
424 case PA_SAMPLE_ALAW:
425 info.play.precision = 8;
426 info.play.encoding = AUDIO_ENCODING_ALAW;
427 break;
428 case PA_SAMPLE_ULAW:
429 info.play.precision = 8;
430 info.play.encoding = AUDIO_ENCODING_ULAW;
431 break;
432 case PA_SAMPLE_S16NE:
433 info.play.precision = 16;
434 info.play.encoding = AUDIO_ENCODING_LINEAR;
435 break;
436 default:
437 return -1;
438 }
439 }
440
441 if (mode != O_WRONLY) {
442 info.record.sample_rate = ss->rate;
443 info.record.channels = ss->channels;
444 switch (ss->format) {
445 case PA_SAMPLE_U8:
446 info.record.precision = 8;
447 info.record.encoding = AUDIO_ENCODING_LINEAR;
448 break;
449 case PA_SAMPLE_ALAW:
450 info.record.precision = 8;
451 info.record.encoding = AUDIO_ENCODING_ALAW;
452 break;
453 case PA_SAMPLE_ULAW:
454 info.record.precision = 8;
455 info.record.encoding = AUDIO_ENCODING_ULAW;
456 break;
457 case PA_SAMPLE_S16NE:
458 info.record.precision = 16;
459 info.record.encoding = AUDIO_ENCODING_LINEAR;
460 break;
461 default:
462 return -1;
463 }
464 }
465
466 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
467 if (errno == EINVAL)
468 pa_log("AUDIO_SETINFO: Unsupported sample format.");
469 else
470 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
471 return -1;
472 }
473
474 return 0;
475 }
476
477 static int pa_solaris_set_buffer(int fd, int buffer_size) {
478 audio_info_t info;
479
480 AUDIO_INITINFO(&info);
481
482 info.record.buffer_size = buffer_size;
483
484 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
485 if (errno == EINVAL)
486 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
487 else
488 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
489 return -1;
490 }
491
492 return 0;
493 }
494
495 int pa__init(pa_core *c, pa_module*m) {
496 struct userdata *u = NULL;
497 const char *p;
498 int fd = -1;
499 int buffer_size;
500 int mode;
501 int record = 1, playback = 1;
502 pa_sample_spec ss;
503 pa_channel_map map;
504 pa_modargs *ma = NULL;
505 struct timeval tv;
506 char *t;
507 assert(c && m);
508
509 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
510 pa_log("failed to parse module arguments.");
511 goto fail;
512 }
513
514 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
515 pa_log("record= and playback= expect numeric argument.");
516 goto fail;
517 }
518
519 if (!playback && !record) {
520 pa_log("neither playback nor record enabled for device.");
521 goto fail;
522 }
523
524 mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
525
526 buffer_size = 16384;
527 if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
528 pa_log("failed to parse buffer size argument");
529 goto fail;
530 }
531
532 ss = c->default_sample_spec;
533 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
534 pa_log("failed to parse sample specification");
535 goto fail;
536 }
537
538 if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0)
539 goto fail;
540
541 pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
542
543 if (pa_solaris_auto_format(fd, mode, &ss) < 0)
544 goto fail;
545
546 if ((mode != O_WRONLY) && (buffer_size >= 1))
547 if (pa_solaris_set_buffer(fd, buffer_size) < 0)
548 goto fail;
549
550 u = pa_xmalloc(sizeof(struct userdata));
551 u->core = c;
552
553 if (mode != O_WRONLY) {
554 u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
555 assert(u->source);
556 u->source->userdata = u;
557 u->source->get_latency = source_get_latency_cb;
558 u->source->get_hw_volume = source_get_hw_volume_cb;
559 u->source->set_hw_volume = source_set_hw_volume_cb;
560 pa_source_set_owner(u->source, m);
561 pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
562 pa_xfree(t);
563 u->source->is_hardware = 1;
564 } else
565 u->source = NULL;
566
567 if (mode != O_RDONLY) {
568 u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
569 assert(u->sink);
570 u->sink->get_latency = sink_get_latency_cb;
571 u->sink->get_hw_volume = sink_get_hw_volume_cb;
572 u->sink->set_hw_volume = sink_set_hw_volume_cb;
573 u->sink->get_hw_mute = sink_get_hw_mute_cb;
574 u->sink->set_hw_mute = sink_set_hw_mute_cb;
575 u->sink->userdata = u;
576 pa_sink_set_owner(u->sink, m);
577 pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
578 pa_xfree(t);
579 u->sink->is_hardware = 1;
580 } else
581 u->sink = NULL;
582
583 assert(u->source || u->sink);
584
585 u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0);
586 assert(u->io);
587 pa_iochannel_set_callback(u->io, io_callback, u);
588 u->fd = fd;
589
590 u->memchunk.memblock = NULL;
591 u->memchunk.length = 0;
592 u->frame_size = pa_frame_size(&ss);
593 u->buffer_size = buffer_size;
594
595 u->written_bytes = 0;
596 u->read_bytes = 0;
597
598 u->sink_underflow = 1;
599
600 u->module = m;
601 m->userdata = u;
602
603 u->poll_timeout = pa_bytes_to_usec(u->buffer_size / 10, &ss);
604
605 pa_gettimeofday(&tv);
606 pa_timeval_add(&tv, u->poll_timeout);
607
608 u->timer = c->mainloop->time_new(c->mainloop, &tv, timer_cb, u);
609 assert(u->timer);
610
611 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
612 assert(u->sig);
613 ioctl(u->fd, I_SETSIG, S_MSG);
614
615 pa_modargs_free(ma);
616
617 /* Read mixer settings */
618 if (u->source)
619 source_get_hw_volume_cb(u->source);
620 if (u->sink) {
621 sink_get_hw_volume_cb(u->sink);
622 sink_get_hw_mute_cb(u->sink);
623 }
624
625 return 0;
626
627 fail:
628 if (fd >= 0)
629 close(fd);
630
631 if (ma)
632 pa_modargs_free(ma);
633
634 return -1;
635 }
636
637 void pa__done(pa_core *c, pa_module*m) {
638 struct userdata *u;
639 assert(c && m);
640
641 if (!(u = m->userdata))
642 return;
643
644 if (u->timer)
645 c->mainloop->time_free(u->timer);
646 ioctl(u->fd, I_SETSIG, 0);
647 pa_signal_free(u->sig);
648
649 if (u->memchunk.memblock)
650 pa_memblock_unref(u->memchunk.memblock);
651
652 if (u->sink) {
653 pa_sink_disconnect(u->sink);
654 pa_sink_unref(u->sink);
655 }
656
657 if (u->source) {
658 pa_source_disconnect(u->source);
659 pa_source_unref(u->source);
660 }
661
662 pa_iochannel_free(u->io);
663 pa_xfree(u);
664 }