]> code.delx.au - pulseaudio/blob - src/modules/module-solaris.c
revive solaris module
[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 if (!(u = pa_xnew0(struct userdata, 1)))
825 goto fail;
826
827 u->sample_counter_lock = pa_mutex_new(FALSE, FALSE);
828 u->written_bytes_lock = pa_mutex_new(FALSE, FALSE);
829
830 /*
831 * For a process (or several processes) to use the same audio device for both
832 * record and playback at the same time, the device's mixer must be enabled.
833 * See mixerctl(1). It may be turned off for playback only or record only.
834 */
835 u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
836
837 ss = m->core->default_sample_spec;
838 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
839 pa_log("failed to parse sample specification");
840 goto fail;
841 }
842 u->frame_size = pa_frame_size(&ss);
843
844 u->buffer_size = 16384;
845 if (pa_modargs_get_value_s32(ma, "buffer_size", &u->buffer_size) < 0) {
846 pa_log("failed to parse buffer size argument");
847 goto fail;
848 }
849 u->buffer_size -= u->buffer_size % u->frame_size;
850 if (u->buffer_size < (int32_t)MIN_BUFFER_SIZE) {
851 pa_log("supplied buffer size argument is too small");
852 goto fail;
853 }
854
855 u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
856
857 if ((fd = open_audio_device(u, &ss)) < 0)
858 goto fail;
859
860 u->core = m->core;
861 u->module = m;
862 m->userdata = u;
863
864 pa_memchunk_reset(&u->memchunk);
865
866 u->rtpoll = pa_rtpoll_new();
867 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
868
869 u->rtpoll_item = NULL;
870 build_pollfd(u);
871
872 if (u->mode != O_WRONLY) {
873 name_buf = NULL;
874 namereg_fail = TRUE;
875
876 if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) {
877 name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name));
878 namereg_fail = FALSE;
879 }
880
881 pa_source_new_data_init(&source_new_data);
882 source_new_data.driver = __FILE__;
883 source_new_data.module = m;
884 pa_source_new_data_set_name(&source_new_data, name);
885 source_new_data.namereg_fail = namereg_fail;
886 pa_source_new_data_set_sample_spec(&source_new_data, &ss);
887 pa_source_new_data_set_channel_map(&source_new_data, &map);
888 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
889 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
890 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source");
891 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
892 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size);
893
894 u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL);
895 pa_source_new_data_done(&source_new_data);
896 pa_xfree(name_buf);
897
898 if (!u->source) {
899 pa_log("Failed to create source object");
900 goto fail;
901 }
902
903 u->source->userdata = u;
904 u->source->parent.process_msg = source_process_msg;
905
906 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
907 pa_source_set_rtpoll(u->source, u->rtpoll);
908
909 u->source->get_volume = source_get_volume;
910 u->source->set_volume = source_set_volume;
911 u->source->refresh_volume = TRUE;
912 } else
913 u->source = NULL;
914
915 if (u->mode != O_RDONLY) {
916 name_buf = NULL;
917 namereg_fail = TRUE;
918 if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) {
919 name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name));
920 namereg_fail = FALSE;
921 }
922
923 pa_sink_new_data_init(&sink_new_data);
924 sink_new_data.driver = __FILE__;
925 sink_new_data.module = m;
926 pa_sink_new_data_set_name(&sink_new_data, name);
927 sink_new_data.namereg_fail = namereg_fail;
928 pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
929 pa_sink_new_data_set_channel_map(&sink_new_data, &map);
930 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
931 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
932 pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink");
933 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
934
935 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);
936 pa_sink_new_data_done(&sink_new_data);
937
938 pa_assert(u->sink);
939 u->sink->userdata = u;
940 u->sink->parent.process_msg = sink_process_msg;
941
942 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
943 pa_sink_set_rtpoll(u->sink, u->rtpoll);
944
945 u->sink->get_volume = sink_get_volume;
946 u->sink->set_volume = sink_set_volume;
947 u->sink->get_mute = sink_get_mute;
948 u->sink->set_mute = sink_set_mute;
949 u->sink->refresh_volume = u->sink->refresh_muted = TRUE;
950
951 u->sink->thread_info.max_request = u->buffer_size;
952 u->min_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
953 } else
954 u->sink = NULL;
955
956 pa_assert(u->source || u->sink);
957
958 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
959 pa_assert(u->sig);
960 ioctl(u->fd, I_SETSIG, S_MSG);
961
962 if (!(u->thread = pa_thread_new(thread_func, u))) {
963 pa_log("Failed to create thread.");
964 goto fail;
965 }
966
967 /* Read mixer settings */
968 if (u->sink) {
969 if (sink_new_data.volume_is_set)
970 u->sink->set_volume(u->sink);
971 else
972 u->sink->get_volume(u->sink);
973
974 if (sink_new_data.muted_is_set)
975 u->sink->set_mute(u->sink);
976 else
977 u->sink->get_mute(u->sink);
978
979 pa_sink_put(u->sink);
980 }
981
982 if (u->source) {
983 if (source_new_data.volume_is_set)
984 u->source->set_volume(u->source);
985 else
986 u->source->get_volume(u->source);
987
988 pa_source_put(u->source);
989 }
990
991 pa_modargs_free(ma);
992
993 return 0;
994
995 fail:
996 if (u)
997 pa__done(m);
998 else if (fd >= 0)
999 close(fd);
1000
1001 if (ma)
1002 pa_modargs_free(ma);
1003
1004 return -1;
1005 }
1006
1007 void pa__done(pa_module *m) {
1008 struct userdata *u;
1009
1010 pa_assert(m);
1011
1012 if (!(u = m->userdata))
1013 return;
1014
1015 ioctl(u->fd, I_SETSIG, 0);
1016 pa_signal_free(u->sig);
1017
1018 if (u->sink)
1019 pa_sink_unlink(u->sink);
1020
1021 if (u->source)
1022 pa_source_unlink(u->source);
1023
1024 if (u->thread) {
1025 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1026 pa_thread_free(u->thread);
1027 }
1028
1029 pa_thread_mq_done(&u->thread_mq);
1030
1031 if (u->sink)
1032 pa_sink_unref(u->sink);
1033
1034 if (u->source)
1035 pa_source_unref(u->source);
1036
1037 if (u->memchunk.memblock)
1038 pa_memblock_unref(u->memchunk.memblock);
1039
1040 if (u->rtpoll_item)
1041 pa_rtpoll_item_free(u->rtpoll_item);
1042
1043 if (u->rtpoll)
1044 pa_rtpoll_free(u->rtpoll);
1045
1046 if (u->fd >= 0)
1047 close(u->fd);
1048
1049 pa_mutex_free(u->written_bytes_lock);
1050 pa_mutex_free(u->sample_counter_lock);
1051
1052 pa_xfree(u->device_name);
1053
1054 pa_xfree(u);
1055 }