chiark / gitweb /
uaudio_apis[] is a constant
[disorder] / lib / uaudio-oss.c
... / ...
CommitLineData
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2009 Richard Kettlewell
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/** @file lib/uaudio-oss.c
19 * @brief Support for OSS backend */
20#include "common.h"
21
22#if HAVE_SYS_SOUNDCARD_H || EMPEG_HOST
23
24#if HAVE_SYS_SOUNDCARD_H
25# include <sys/soundcard.h>
26#endif
27#include <sys/ioctl.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <errno.h>
31
32#include "mem.h"
33#include "log.h"
34#include "uaudio.h"
35
36#ifndef AFMT_U16_NE
37# if BYTE_ORDER == BIG_ENDIAN
38# define AFMT_U16_NE AFMT_U16_BE
39# else
40# define AFMT_U16_NE AFMT_U16_LE
41# endif
42#endif
43
44static int oss_fd = -1;
45
46static const char *const oss_options[] = {
47 "device",
48 NULL
49};
50
51/** @brief Actually play sound via OSS */
52static size_t oss_play(void *buffer, size_t samples) {
53 const size_t bytes = samples * uaudio_sample_size;
54 int rc = write(oss_fd, buffer, bytes);
55 if(rc < 0)
56 fatal(errno, "error writing to sound device");
57 return rc / uaudio_sample_size;
58}
59
60/** @brief Open the OSS sound device */
61static void oss_open(void) {
62 const char *device = uaudio_get("device");
63
64#if EMPEG_HOST
65 if(!device || !*device || !strcmp(device, "default"))
66 device "/dev/audio";
67#else
68 if(!device || !*device || !strcmp(device, "default")) {
69 if(access("/dev/dsp", W_OK) == 0)
70 device = "/dev/dsp";
71 else
72 device = "/dev/audio";
73 }
74#endif
75 if((oss_fd = open(device, O_WRONLY, 0)) < 0)
76 fatal(errno, "error opening %s", device);
77#if !EMPEG_HOST
78 int stereo = (uaudio_channels == 2), format;
79 if(ioctl(oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
80 fatal(errno, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo);
81 if(uaudio_bits == 16)
82 format = uaudio_signed ? AFMT_S16_NE : AFMT_U16_NE;
83 else
84 format = uaudio_signed ? AFMT_S8 : AFMT_U8;
85 if(ioctl(oss_fd, SNDCTL_DSP_SETFMT, &format) < 0)
86 fatal(errno, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format);
87 int rate = uaudio_rate;
88 if(ioctl(oss_fd, SNDCTL_DSP_SPEED, &rate) < 0)
89 fatal(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate);
90 if(rate != uaudio_rate)
91 error(0, "asked for %dHz, got %dHz", uaudio_rate, rate);
92#endif
93}
94
95static void oss_activate(void) {
96 oss_open();
97 uaudio_thread_activate();
98}
99
100static void oss_deactivate(void) {
101 uaudio_thread_deactivate();
102 close(oss_fd);
103 oss_fd = -1;
104}
105
106static void oss_start(uaudio_callback *callback,
107 void *userdata) {
108 if(uaudio_channels != 1 && uaudio_channels != 2)
109 fatal(0, "asked for %d channels but only support 1 or 2",
110 uaudio_channels);
111 if(uaudio_bits != 8 && uaudio_bits != 16)
112 fatal(0, "asked for %d bits/channel but only support 8 or 16",
113 uaudio_bits);
114#if EMPEG_HOST
115 /* Very specific buffer size requirements here apparently */
116 uaudio_thread_start(callback, userdata, oss_play,
117 4608 / uaudio_sample_size,
118 4608 / uaudio_sample_size);
119#else
120 /* We could SNDCTL_DSP_GETBLKSIZE but only when the device is already open,
121 * which is kind of inconvenient. We go with 1-4Kbyte for now. */
122 uaudio_thread_start(callback, userdata, oss_play,
123 32 / uaudio_sample_size,
124 4096 / uaudio_sample_size);
125#endif
126}
127
128static void oss_stop(void) {
129 uaudio_thread_stop();
130}
131
132const struct uaudio uaudio_oss = {
133 .name = "oss",
134 .options = oss_options,
135 .start = oss_start,
136 .stop = oss_stop,
137 .activate = oss_activate,
138 .deactivate = oss_deactivate
139};
140
141#endif
142
143/*
144Local Variables:
145c-basic-offset:2
146comment-column:40
147fill-column:79
148indent-tabs-mode:nil
149End:
150*/