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