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