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