]> code.delx.au - pulseaudio/blob - src/modules/module-solaris.c
Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
[pulseaudio] / src / modules / module-solaris.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 Copyright 2009 Finn Thain
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <limits.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38
39 #include <signal.h>
40 #include <stropts.h>
41 #include <sys/conf.h>
42 #include <sys/audio.h>
43
44 #include <pulse/error.h>
45 #include <pulse/mainloop-signal.h>
46 #include <pulse/xmalloc.h>
47 #include <pulse/timeval.h>
48 #include <pulse/util.h>
49
50 #include <pulsecore/iochannel.h>
51 #include <pulsecore/sink.h>
52 #include <pulsecore/source.h>
53 #include <pulsecore/module.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/modargs.h>
57 #include <pulsecore/log.h>
58 #include <pulsecore/core-error.h>
59 #include <pulsecore/thread-mq.h>
60 #include <pulsecore/rtpoll.h>
61 #include <pulsecore/thread.h>
62 #include <pulsecore/rtclock.h>
63
64 #include "module-solaris-symdef.h"
65
66 PA_MODULE_AUTHOR("Pierre Ossman");
67 PA_MODULE_DESCRIPTION("Solaris Sink/Source");
68 PA_MODULE_VERSION(PACKAGE_VERSION);
69 PA_MODULE_USAGE(
70 "sink_name=<name for the sink> "
71 "source_name=<name for the source> "
72 "device=<audio device file name> "
73 "record=<enable source?> "
74 "playback=<enable sink?> "
75 "format=<sample format> "
76 "channels=<number of channels> "
77 "rate=<sample rate> "
78 "buffer_size=<record buffer size> "
79 "channel_map=<channel map>");
80 PA_MODULE_LOAD_ONCE(FALSE);
81
82 struct userdata {
83 pa_core *core;
84 pa_sink *sink;
85 pa_source *source;
86
87 pa_thread *thread;
88 pa_thread_mq thread_mq;
89 pa_rtpoll *rtpoll;
90
91 pa_signal_event *sig;
92
93 pa_memchunk memchunk;
94
95 uint32_t frame_size;
96 int32_t buffer_size;
97 volatile uint64_t written_bytes, read_bytes;
98 pa_mutex *written_bytes_lock;
99
100 char *device_name;
101 int mode;
102 int fd;
103 pa_rtpoll_item *rtpoll_item;
104 pa_module *module;
105
106 pa_bool_t sink_suspended, source_suspended;
107
108 uint32_t play_samples_msw, record_samples_msw;
109 uint32_t prev_playback_samples, prev_record_samples;
110 pa_mutex *sample_counter_lock;
111
112 size_t min_request;
113 };
114
115 static const char* const valid_modargs[] = {
116 "sink_name",
117 "source_name",
118 "device",
119 "record",
120 "playback",
121 "buffer_size",
122 "format",
123 "rate",
124 "channels",
125 "channel_map",
126 NULL
127 };
128
129 #define DEFAULT_DEVICE "/dev/audio"
130 #define MIN_BUFFER_SIZE (640)
131 #define MAX_RENDER_HZ (300)
132
133 /* This render rate limit implies a minimum latency, but without it we waste too much CPU time in the
134 * IO thread. The maximum render rate and minimum latency (or minimum buffer size) are unachievable on
135 * common hardware anyway. Note that MIN_BUFFER_SIZE * MAX_RENDER_HZ >= 4 * 48000 Bps.
136 */
137
138 static uint64_t get_playback_buffered_bytes(struct userdata *u) {
139 audio_info_t info;
140 uint64_t played_bytes;
141 int err;
142
143 pa_assert(u->sink);
144
145 pa_mutex_lock(u->sample_counter_lock);
146
147 err = ioctl(u->fd, AUDIO_GETINFO, &info);
148 pa_assert(err >= 0);
149
150 /* Handle wrap-around of the device's sample counter, which is a uint_32. */
151 if (u->prev_playback_samples > info.play.samples) {
152 /* Unfortunately info.play.samples can sometimes go backwards, even before it wraps! */
153 if (u->prev_playback_samples + info.play.samples < 240000) {
154 ++u->play_samples_msw;
155 } else {
156 pa_log_debug("play.samples went backwards %d bytes", u->prev_playback_samples - info.play.samples);
157 }
158 }
159 u->prev_playback_samples = info.play.samples;
160 played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size;
161
162 pa_mutex_unlock(u->sample_counter_lock);
163
164 return u->written_bytes - played_bytes;
165 }
166
167 static pa_usec_t sink_get_latency(struct userdata *u, pa_sample_spec *ss) {
168 pa_usec_t r = 0;
169
170 pa_assert(u);
171 pa_assert(ss);
172
173 if (u->fd >= 0) {
174 pa_mutex_lock(u->written_bytes_lock);
175 r = pa_bytes_to_usec(get_playback_buffered_bytes(u), ss);
176 if (u->memchunk.memblock)
177 r += pa_bytes_to_usec(u->memchunk.length, ss);
178 pa_mutex_unlock(u->written_bytes_lock);
179 }
180 return r;
181 }
182
183 static uint64_t get_recorded_bytes(struct userdata *u) {
184 audio_info_t info;
185 uint64_t result;
186 int err;
187
188 pa_assert(u->source);
189
190 err = ioctl(u->fd, AUDIO_GETINFO, &info);
191 pa_assert(err >= 0);
192
193 if (u->prev_record_samples > info.record.samples)
194 ++u->record_samples_msw;
195 u->prev_record_samples = info.record.samples;
196 result = (((uint64_t)u->record_samples_msw << 32) + info.record.samples) * u->frame_size;
197
198 return result;
199 }
200
201 static pa_usec_t source_get_latency(struct userdata *u, pa_sample_spec *ss) {
202 pa_usec_t r = 0;
203 audio_info_t info;
204
205 pa_assert(u);
206 pa_assert(ss);
207
208 if (u->fd) {
209 int err = ioctl(u->fd, AUDIO_GETINFO, &info);
210 pa_assert(err >= 0);
211
212 r = pa_bytes_to_usec(get_recorded_bytes(u), ss) - pa_bytes_to_usec(u->read_bytes, ss);
213 }
214 return r;
215 }
216
217 static void build_pollfd(struct userdata *u) {
218 struct pollfd *pollfd;
219
220 pa_assert(u);
221 pa_assert(!u->rtpoll_item);
222 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
223
224 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
225 pollfd->fd = u->fd;
226 pollfd->events = 0;
227 pollfd->revents = 0;
228 }
229
230 static int set_buffer(int fd, int buffer_size) {
231 audio_info_t info;
232
233 pa_assert(fd >= 0);
234
235 AUDIO_INITINFO(&info);
236 info.play.buffer_size = buffer_size;
237 info.record.buffer_size = buffer_size;
238
239 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
240 if (errno == EINVAL)
241 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
242 else
243 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
244 return -1;
245 }
246
247 return 0;
248 }
249
250 static int auto_format(int fd, int mode, pa_sample_spec *ss) {
251 audio_info_t info;
252
253 pa_assert(fd >= 0);
254 pa_assert(ss);
255
256 AUDIO_INITINFO(&info);
257
258 if (mode != O_RDONLY) {
259 info.play.sample_rate = ss->rate;
260 info.play.channels = ss->channels;
261 switch (ss->format) {
262 case PA_SAMPLE_U8:
263 info.play.precision = 8;
264 info.play.encoding = AUDIO_ENCODING_LINEAR;
265 break;
266 case PA_SAMPLE_ALAW:
267 info.play.precision = 8;
268 info.play.encoding = AUDIO_ENCODING_ALAW;
269 break;
270 case PA_SAMPLE_ULAW:
271 info.play.precision = 8;
272 info.play.encoding = AUDIO_ENCODING_ULAW;
273 break;
274 case PA_SAMPLE_S16NE:
275 info.play.precision = 16;
276 info.play.encoding = AUDIO_ENCODING_LINEAR;
277 break;
278 default:
279 pa_log("AUDIO_SETINFO: Unsupported sample format.");
280 return -1;
281 }
282 }
283
284 if (mode != O_WRONLY) {
285 info.record.sample_rate = ss->rate;
286 info.record.channels = ss->channels;
287 switch (ss->format) {
288 case PA_SAMPLE_U8:
289 info.record.precision = 8;
290 info.record.encoding = AUDIO_ENCODING_LINEAR;
291 break;
292 case PA_SAMPLE_ALAW:
293 info.record.precision = 8;
294 info.record.encoding = AUDIO_ENCODING_ALAW;
295 break;
296 case PA_SAMPLE_ULAW:
297 info.record.precision = 8;
298 info.record.encoding = AUDIO_ENCODING_ULAW;
299 break;
300 case PA_SAMPLE_S16NE:
301 info.record.precision = 16;
302 info.record.encoding = AUDIO_ENCODING_LINEAR;
303 break;
304 default:
305 pa_log("AUDIO_SETINFO: Unsupported sample format.");
306 return -1;
307 }
308 }
309
310 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
311 if (errno == EINVAL)
312 pa_log("AUDIO_SETINFO: Failed to set sample format.");
313 else
314 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
315 return -1;
316 }
317
318 return 0;
319 }
320
321 static int open_audio_device(struct userdata *u, pa_sample_spec *ss) {
322 pa_assert(u);
323 pa_assert(ss);
324
325 if ((u->fd = open(u->device_name, u->mode | O_NONBLOCK)) < 0) {
326 pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno));
327 return -1;
328 }
329
330 pa_log_info("device opened in %s mode.", u->mode == O_WRONLY ? "O_WRONLY" : (u->mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
331
332 if (auto_format(u->fd, u->mode, ss) < 0)
333 return -1;
334
335 if (set_buffer(u->fd, u->buffer_size) < 0)
336 return -1;
337
338 u->written_bytes = u->read_bytes = 0;
339 u->play_samples_msw = u->record_samples_msw = 0;
340 u->prev_playback_samples = u->prev_record_samples = 0;
341
342 return u->fd;
343 }
344
345 static int suspend(struct userdata *u) {
346 pa_assert(u);
347 pa_assert(u->fd >= 0);
348
349 pa_log_info("Suspending...");
350
351 ioctl(u->fd, AUDIO_DRAIN, NULL);
352 pa_close(u->fd);
353 u->fd = -1;
354
355 if (u->rtpoll_item) {
356 pa_rtpoll_item_free(u->rtpoll_item);
357 u->rtpoll_item = NULL;
358 }
359
360 pa_log_info("Device suspended.");
361
362 return 0;
363 }
364
365 static int unsuspend(struct userdata *u) {
366 pa_assert(u);
367 pa_assert(u->fd < 0);
368
369 pa_log_info("Resuming...");
370
371 if (open_audio_device(u, u->sink ? &u->sink->sample_spec : &u->source->sample_spec) < 0)
372 return -1;
373
374 build_pollfd(u);
375
376 pa_log_info("Device resumed.");
377
378 return 0;
379 }
380
381 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
382 struct userdata *u = PA_SINK(o)->userdata;
383
384 switch (code) {
385
386 case PA_SINK_MESSAGE_GET_LATENCY:
387 *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec);
388 return 0;
389
390 case PA_SINK_MESSAGE_SET_STATE:
391
392 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
393
394 case PA_SINK_SUSPENDED:
395
396 pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
397
398 if (!u->source || u->source_suspended) {
399 if (suspend(u) < 0)
400 return -1;
401 }
402 u->sink_suspended = TRUE;
403 break;
404
405 case PA_SINK_IDLE:
406 case PA_SINK_RUNNING:
407
408 if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
409 if (!u->source || u->source_suspended) {
410 if (unsuspend(u) < 0)
411 return -1;
412 u->sink->get_volume(u->sink);
413 u->sink->get_mute(u->sink);
414 }
415 u->sink_suspended = FALSE;
416 }
417 break;
418
419 case PA_SINK_INVALID_STATE:
420 case PA_SINK_UNLINKED:
421 case PA_SINK_INIT:
422 ;
423 }
424
425 break;
426 }
427
428 return pa_sink_process_msg(o, code, data, offset, chunk);
429 }
430
431 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
432 struct userdata *u = PA_SOURCE(o)->userdata;
433
434 switch (code) {
435
436 case PA_SOURCE_MESSAGE_GET_LATENCY:
437 *((pa_usec_t*) data) = source_get_latency(u, &PA_SOURCE(o)->sample_spec);
438 return 0;
439
440 case PA_SOURCE_MESSAGE_SET_STATE:
441
442 switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
443
444 case PA_SOURCE_SUSPENDED:
445
446 pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
447
448 if (!u->sink || u->sink_suspended) {
449 if (suspend(u) < 0)
450 return -1;
451 }
452 u->source_suspended = TRUE;
453 break;
454
455 case PA_SOURCE_IDLE:
456 case PA_SOURCE_RUNNING:
457
458 if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
459 if (!u->sink || u->sink_suspended) {
460 if (unsuspend(u) < 0)
461 return -1;
462 u->source->get_volume(u->source);
463 }
464 u->source_suspended = FALSE;
465 }
466 break;
467
468 case PA_SOURCE_UNLINKED:
469 case PA_SOURCE_INIT:
470 case PA_SOURCE_INVALID_STATE:
471 ;
472
473 }
474 break;
475
476 }
477
478 return pa_source_process_msg(o, code, data, offset, chunk);
479 }
480
481 static void sink_set_volume(pa_sink *s) {
482 struct userdata *u;
483 audio_info_t info;
484
485 pa_assert_se(u = s->userdata);
486
487 if (u->fd >= 0) {
488 AUDIO_INITINFO(&info);
489
490 info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
491 assert(info.play.gain <= AUDIO_MAX_GAIN);
492
493 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
494 if (errno == EINVAL)
495 pa_log("AUDIO_SETINFO: Unsupported volume.");
496 else
497 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
498 }
499 }
500 }
501
502 static void sink_get_volume(pa_sink *s) {
503 struct userdata *u;
504 audio_info_t info;
505
506 pa_assert_se(u = s->userdata);
507
508 if (u->fd >= 0) {
509 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
510 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
511 else
512 pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels,
513 info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
514 }
515 }
516
517 static void source_set_volume(pa_source *s) {
518 struct userdata *u;
519 audio_info_t info;
520
521 pa_assert_se(u = s->userdata);
522
523 if (u->fd >= 0) {
524 AUDIO_INITINFO(&info);
525
526 info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
527 assert(info.play.gain <= AUDIO_MAX_GAIN);
528
529 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
530 if (errno == EINVAL)
531 pa_log("AUDIO_SETINFO: Unsupported volume.");
532 else
533 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
534 }
535 }
536 }
537
538 static void source_get_volume(pa_source *s) {
539 struct userdata *u;
540 audio_info_t info;
541
542 pa_assert_se(u = s->userdata);
543
544 if (u->fd >= 0) {
545 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
546 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
547 else
548 pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels,
549 info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
550 }
551 }
552
553 static void sink_set_mute(pa_sink *s) {
554 struct userdata *u = s->userdata;
555 audio_info_t info;
556
557 pa_assert(u);
558
559 if (u->fd >= 0) {
560 AUDIO_INITINFO(&info);
561
562 info.output_muted = !!s->muted;
563
564 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
565 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
566 }
567 }
568
569 static void sink_get_mute(pa_sink *s) {
570 struct userdata *u = s->userdata;
571 audio_info_t info;
572
573 pa_assert(u);
574
575 if (u->fd >= 0) {
576 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
577 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
578 else
579 s->muted = !!info.output_muted;
580 }
581 }
582
583 static void thread_func(void *userdata) {
584 struct userdata *u = userdata;
585 unsigned short revents = 0;
586 int ret, err;
587 audio_info_t info;
588
589 pa_assert(u);
590
591 pa_log_debug("Thread starting up");
592
593 if (u->core->realtime_scheduling)
594 pa_make_realtime(u->core->realtime_priority);
595
596 pa_thread_mq_install(&u->thread_mq);
597 pa_rtpoll_install(u->rtpoll);
598
599 for (;;) {
600 /* Render some data and write it to the dsp */
601
602 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
603 pa_usec_t xtime0;
604 uint64_t buffered_bytes;
605
606 if (u->sink->thread_info.rewind_requested)
607 pa_sink_process_rewind(u->sink, 0);
608
609 err = ioctl(u->fd, AUDIO_GETINFO, &info);
610 pa_assert(err >= 0);
611
612 if (info.play.error) {
613 pa_log_debug("buffer under-run!");
614
615 AUDIO_INITINFO(&info);
616 info.play.error = 0;
617 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
618 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
619 }
620
621 for (;;) {
622 void *p;
623 ssize_t w;
624 size_t len;
625
626 /*
627 * Since we cannot modify the size of the output buffer we fake it
628 * by not filling it more than u->buffer_size.
629 */
630 xtime0 = pa_rtclock_usec();
631 buffered_bytes = get_playback_buffered_bytes(u);
632 if (buffered_bytes >= (uint64_t)u->buffer_size)
633 break;
634
635 len = u->buffer_size - buffered_bytes;
636 len -= len % u->frame_size;
637
638 if (len < u->min_request)
639 break;
640
641 if (u->memchunk.length < len)
642 pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk);
643
644 p = pa_memblock_acquire(u->memchunk.memblock);
645 w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL);
646 pa_memblock_release(u->memchunk.memblock);
647
648 if (w <= 0) {
649 switch (errno) {
650 case EINTR:
651 break;
652 case EAGAIN:
653 u->buffer_size = u->buffer_size * 18 / 25;
654 u->buffer_size -= u->buffer_size % u->frame_size;
655 u->buffer_size = PA_MAX(u->buffer_size, (int32_t)MIN_BUFFER_SIZE);
656 pa_sink_set_max_request(u->sink, u->buffer_size);
657 pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u->buffer_size, buffered_bytes);
658 break;
659 default:
660 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
661 goto fail;
662 }
663 } else {
664 pa_assert(w % u->frame_size == 0);
665
666 pa_mutex_lock(u->written_bytes_lock);
667 u->written_bytes += w;
668 u->memchunk.length -= w;
669 pa_mutex_unlock(u->written_bytes_lock);
670
671 u->memchunk.index += w;
672 if (u->memchunk.length <= 0) {
673 pa_memblock_unref(u->memchunk.memblock);
674 pa_memchunk_reset(&u->memchunk);
675 }
676 }
677 }
678
679 pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec));
680 } else {
681 pa_rtpoll_set_timer_disabled(u->rtpoll);
682 }
683
684 /* Try to read some data and pass it on to the source driver */
685
686 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && (revents & POLLIN)) {
687 pa_memchunk memchunk;
688 void *p;
689 ssize_t r;
690 size_t len;
691
692 err = ioctl(u->fd, AUDIO_GETINFO, &info);
693 pa_assert(err >= 0);
694
695 if (info.record.error) {
696 pa_log_debug("buffer overflow!");
697
698 AUDIO_INITINFO(&info);
699 info.record.error = 0;
700 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
701 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
702 }
703
704 err = ioctl(u->fd, I_NREAD, &len);
705 pa_assert(err >= 0);
706
707 if (len > 0) {
708 memchunk.memblock = pa_memblock_new(u->core->mempool, len);
709 pa_assert(memchunk.memblock);
710
711 p = pa_memblock_acquire(memchunk.memblock);
712 r = pa_read(u->fd, p, len, NULL);
713 pa_memblock_release(memchunk.memblock);
714
715 if (r < 0) {
716 pa_memblock_unref(memchunk.memblock);
717 if (errno == EAGAIN)
718 break;
719 else {
720 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
721 goto fail;
722 }
723 } else {
724 u->read_bytes += r;
725
726 memchunk.index = 0;
727 memchunk.length = r;
728
729 pa_source_post(u->source, &memchunk);
730 pa_memblock_unref(memchunk.memblock);
731
732 revents &= ~POLLIN;
733 }
734 }
735 }
736
737 if (u->rtpoll_item) {
738 struct pollfd *pollfd;
739
740 pa_assert(u->fd >= 0);
741
742 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
743 pollfd->events = (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0;
744 }
745
746 /* Hmm, nothing to do. Let's sleep */
747 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
748 goto fail;
749
750 if (ret == 0)
751 goto finish;
752
753 if (u->rtpoll_item) {
754 struct pollfd *pollfd;
755
756 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
757
758 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
759 pa_log("DSP shutdown.");
760 goto fail;
761 }
762
763 revents = pollfd->revents;
764 } else
765 revents = 0;
766 }
767
768 fail:
769 /* We have to continue processing messages until we receive the
770 * SHUTDOWN message */
771 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
772 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
773
774 finish:
775 pa_log_debug("Thread shutting down");
776 }
777
778 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
779 struct userdata *u = userdata;
780
781 assert(u);
782
783 pa_log_debug("caught signal");
784
785 if (u->sink) {
786 pa_sink_get_volume(u->sink, TRUE);
787 pa_sink_get_mute(u->sink, TRUE);
788 }
789
790 if (u->source)
791 pa_source_get_volume(u->source, TRUE);
792 }
793
794 int pa__init(pa_module *m) {
795 struct userdata *u = NULL;
796 pa_bool_t record = TRUE, playback = TRUE;
797 pa_sample_spec ss;
798 pa_channel_map map;
799 pa_modargs *ma = NULL;
800 int fd;
801 pa_sink_new_data sink_new_data;
802 pa_source_new_data source_new_data;
803 char const *name;
804 char *name_buf;
805 pa_bool_t namereg_fail;
806
807 pa_assert(m);
808
809 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
810 pa_log("failed to parse module arguments.");
811 goto fail;
812 }
813
814 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
815 pa_log("record= and playback= expect a boolean argument.");
816 goto fail;
817 }
818
819 if (!playback && !record) {
820 pa_log("neither playback nor record enabled for device.");
821 goto fail;
822 }
823
824 u = pa_xnew0(struct userdata, 1);
825 u->sample_counter_lock = pa_mutex_new(FALSE, FALSE);
826 u->written_bytes_lock = pa_mutex_new(FALSE, FALSE);
827
828 /*
829 * For a process (or several processes) to use the same audio device for both
830 * record and playback at the same time, the device's mixer must be enabled.
831 * See mixerctl(1). It may be turned off for playback only or record only.
832 */
833 u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
834
835 ss = m->core->default_sample_spec;
836 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
837 pa_log("failed to parse sample specification");
838 goto fail;
839 }
840 u->frame_size = pa_frame_size(&ss);
841
842 u->buffer_size = 16384;
843 if (pa_modargs_get_value_s32(ma, "buffer_size", &u->buffer_size) < 0) {
844 pa_log("failed to parse buffer size argument");
845 goto fail;
846 }
847 u->buffer_size -= u->buffer_size % u->frame_size;
848 if (u->buffer_size < (int32_t)MIN_BUFFER_SIZE) {
849 pa_log("supplied buffer size argument is too small");
850 goto fail;
851 }
852
853 u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
854
855 if ((fd = open_audio_device(u, &ss)) < 0)
856 goto fail;
857
858 u->core = m->core;
859 u->module = m;
860 m->userdata = u;
861
862 pa_memchunk_reset(&u->memchunk);
863
864 u->rtpoll = pa_rtpoll_new();
865 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
866
867 u->rtpoll_item = NULL;
868 build_pollfd(u);
869
870 if (u->mode != O_WRONLY) {
871 name_buf = NULL;
872 namereg_fail = TRUE;
873
874 if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) {
875 name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name));
876 namereg_fail = FALSE;
877 }
878
879 pa_source_new_data_init(&source_new_data);
880 source_new_data.driver = __FILE__;
881 source_new_data.module = m;
882 pa_source_new_data_set_name(&source_new_data, name);
883 source_new_data.namereg_fail = namereg_fail;
884 pa_source_new_data_set_sample_spec(&source_new_data, &ss);
885 pa_source_new_data_set_channel_map(&source_new_data, &map);
886 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
887 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
888 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source");
889 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
890 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size);
891
892 u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL);
893 pa_source_new_data_done(&source_new_data);
894 pa_xfree(name_buf);
895
896 if (!u->source) {
897 pa_log("Failed to create source object");
898 goto fail;
899 }
900
901 u->source->userdata = u;
902 u->source->parent.process_msg = source_process_msg;
903
904 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
905 pa_source_set_rtpoll(u->source, u->rtpoll);
906
907 u->source->get_volume = source_get_volume;
908 u->source->set_volume = source_set_volume;
909 u->source->refresh_volume = TRUE;
910 } else
911 u->source = NULL;
912
913 if (u->mode != O_RDONLY) {
914 name_buf = NULL;
915 namereg_fail = TRUE;
916 if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) {
917 name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name));
918 namereg_fail = FALSE;
919 }
920
921 pa_sink_new_data_init(&sink_new_data);
922 sink_new_data.driver = __FILE__;
923 sink_new_data.module = m;
924 pa_sink_new_data_set_name(&sink_new_data, name);
925 sink_new_data.namereg_fail = namereg_fail;
926 pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
927 pa_sink_new_data_set_channel_map(&sink_new_data, &map);
928 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
929 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
930 pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink");
931 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
932
933 u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL);
934 pa_sink_new_data_done(&sink_new_data);
935
936 pa_assert(u->sink);
937 u->sink->userdata = u;
938 u->sink->parent.process_msg = sink_process_msg;
939
940 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
941 pa_sink_set_rtpoll(u->sink, u->rtpoll);
942
943 u->sink->get_volume = sink_get_volume;
944 u->sink->set_volume = sink_set_volume;
945 u->sink->get_mute = sink_get_mute;
946 u->sink->set_mute = sink_set_mute;
947 u->sink->refresh_volume = u->sink->refresh_muted = TRUE;
948
949 u->sink->thread_info.max_request = u->buffer_size;
950 u->min_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
951 } else
952 u->sink = NULL;
953
954 pa_assert(u->source || u->sink);
955
956 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
957 pa_assert(u->sig);
958 ioctl(u->fd, I_SETSIG, S_MSG);
959
960 if (!(u->thread = pa_thread_new(thread_func, u))) {
961 pa_log("Failed to create thread.");
962 goto fail;
963 }
964
965 /* Read mixer settings */
966 if (u->sink) {
967 if (sink_new_data.volume_is_set)
968 u->sink->set_volume(u->sink);
969 else
970 u->sink->get_volume(u->sink);
971
972 if (sink_new_data.muted_is_set)
973 u->sink->set_mute(u->sink);
974 else
975 u->sink->get_mute(u->sink);
976
977 pa_sink_put(u->sink);
978 }
979
980 if (u->source) {
981 if (source_new_data.volume_is_set)
982 u->source->set_volume(u->source);
983 else
984 u->source->get_volume(u->source);
985
986 pa_source_put(u->source);
987 }
988
989 pa_modargs_free(ma);
990
991 return 0;
992
993 fail:
994 if (u)
995 pa__done(m);
996 else if (fd >= 0)
997 close(fd);
998
999 if (ma)
1000 pa_modargs_free(ma);
1001
1002 return -1;
1003 }
1004
1005 void pa__done(pa_module *m) {
1006 struct userdata *u;
1007
1008 pa_assert(m);
1009
1010 if (!(u = m->userdata))
1011 return;
1012
1013 ioctl(u->fd, I_SETSIG, 0);
1014 pa_signal_free(u->sig);
1015
1016 if (u->sink)
1017 pa_sink_unlink(u->sink);
1018
1019 if (u->source)
1020 pa_source_unlink(u->source);
1021
1022 if (u->thread) {
1023 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1024 pa_thread_free(u->thread);
1025 }
1026
1027 pa_thread_mq_done(&u->thread_mq);
1028
1029 if (u->sink)
1030 pa_sink_unref(u->sink);
1031
1032 if (u->source)
1033 pa_source_unref(u->source);
1034
1035 if (u->memchunk.memblock)
1036 pa_memblock_unref(u->memchunk.memblock);
1037
1038 if (u->rtpoll_item)
1039 pa_rtpoll_item_free(u->rtpoll_item);
1040
1041 if (u->rtpoll)
1042 pa_rtpoll_free(u->rtpoll);
1043
1044 if (u->fd >= 0)
1045 close(u->fd);
1046
1047 pa_mutex_free(u->written_bytes_lock);
1048 pa_mutex_free(u->sample_counter_lock);
1049
1050 pa_xfree(u->device_name);
1051
1052 pa_xfree(u);
1053 }