2 * This file is part of DisOrder.
3 * Copyright (C) 2009 Richard Kettlewell
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.
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.
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/>.
18 /** @file lib/uaudio-oss.c
19 * @brief Support for OSS backend */
22 #if HAVE_SYS_SOUNDCARD_H || EMPEG_HOST
24 #if HAVE_SYS_SOUNDCARD_H
25 # include <sys/soundcard.h>
27 #include <sys/ioctl.h>
37 # if BYTE_ORDER == BIG_ENDIAN
38 # define AFMT_U16_NE AFMT_U16_BE
40 # define AFMT_U16_NE AFMT_U16_LE
44 static int oss_fd
= -1;
46 static const char *const oss_options
[] = {
51 /** @brief Actually play sound via OSS */
52 static 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
);
56 fatal(errno
, "error writing to sound device");
57 return rc
/ uaudio_sample_size
;
60 /** @brief Open the OSS sound device */
61 static void oss_open(void) {
62 const char *device
= uaudio_get("device");
65 if(!device
|| !*device
|| !strcmp(device
, "default"))
68 if(!device
|| !*device
|| !strcmp(device
, "default")) {
69 if(access("/dev/dsp", W_OK
) == 0)
72 device
= "/dev/audio";
75 if((oss_fd
= open(device
, O_WRONLY
, 0)) < 0)
76 fatal(errno
, "error opening %s", device
);
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
);
82 format
= uaudio_signed ? AFMT_S16_NE
: AFMT_U16_NE
;
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
);
95 static void oss_activate(void) {
97 uaudio_thread_activate();
100 static void oss_deactivate(void) {
101 uaudio_thread_deactivate();
106 static void oss_start(uaudio_callback
*callback
,
108 if(uaudio_channels
!= 1 && uaudio_channels
!= 2)
109 fatal(0, "asked for %d channels but only support 1 or 2",
111 if(uaudio_bits
!= 8 && uaudio_bits
!= 16)
112 fatal(0, "asked for %d bits/channel but only support 8 or 16",
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
);
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
);
128 static void oss_stop(void) {
129 uaudio_thread_stop();
132 const struct uaudio uaudio_oss
= {
134 .options
= oss_options
,
137 .activate
= oss_activate
,
138 .deactivate
= oss_deactivate