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>
32 #include <arpa/inet.h>
38 #include "configuration.h"
40 static int oss_fd
= -1;
41 static pthread_t oss_thread
;
42 static uaudio_callback
*oss_callback
;
43 static int oss_started
;
44 static int oss_activated
;
46 static pthread_mutex_t oss_lock
= PTHREAD_MUTEX_INITIALIZER
;
47 static pthread_cond_t oss_cond
= PTHREAD_COND_INITIALIZER
;
49 /** @brief Buffer size in bytes */
50 static int oss_bufsize
;
52 static const char *const oss_options
[] = {
57 static void *oss_thread_fn(void *userdata
) {
59 pthread_mutex_lock(&oss_lock
);
60 buffer
= xmalloc(oss_bufsize
);
62 while(oss_started
&& !oss_activated
)
63 pthread_cond_wait(&oss_cond
, &oss_lock
);
66 /* We are definitely active now */
68 pthread_cond_signal(&oss_cond
);
69 while(oss_activated
) {
70 const int nsamples
= oss_callback(buffer
,
71 oss_bufsize
/ sizeof(int16_t),
73 const int nbytes
= nsamples
* sizeof(int16_t);
76 while(written
< nsamples
) {
77 const int rc
= write(oss_fd
, buffer
+ written
, nbytes
- written
);
79 fatal(errno
, "error playing audio");
84 pthread_cond_signal(&oss_cond
);
86 pthread_mutex_unlock(&oss_lock
);
90 static void oss_activate(void) {
91 pthread_mutex_lock(&oss_lock
);
93 const char *device
= uaudio_get("device");
96 if(!device
|| !*device
|| !strcmp(device
, "default")) {
99 if(!device
|| !*device
|| !strcmp(device
, "default")) {
100 if(access("/dev/dsp", W_OK
) == 0)
103 device
= "/dev/audio";
106 if((oss_fd
= open(device
, O_WRONLY
, 0)) < 0)
107 fatal(errno
, "error opening %s", device
);
109 /* empeg audio driver only knows /dev/audio, only supports the equivalent
110 * of AFMT_S16_NE, has a fixed buffer size, and does not support the
114 int stereo
= (config
->sample_format
.channels
== 2), format
, rate
;
115 if(ioctl(oss_fd
, SNDCTL_DSP_STEREO
, &stereo
) < 0)
116 fatal(errno
, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo
);
117 /* TODO we need to think about where we decide this */
118 if(config
->sample_format
.bits
== 8)
120 else if(config
->sample_format
.bits
== 16)
121 format
= (config
->sample_format
.endian
== ENDIAN_LITTLE
122 ? AFMT_S16_LE
: AFMT_S16_BE
);
124 fatal(0, "unsupported sample_format for oss backend");
125 if(ioctl(oss_fd
, SNDCTL_DSP_SETFMT
, &format
) < 0)
126 fatal(errno
, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format
);
127 rate
= config
->sample_format
.rate
;
128 if(ioctl(oss_fd
, SNDCTL_DSP_SPEED
, &rate
) < 0)
129 fatal(errno
, "error calling ioctl SNDCTL_DSP_SPEED %d", rate
);
130 if((unsigned)rate
!= config
->sample_format
.rate
)
131 error(0, "asked for %luHz, got %dHz",
132 (unsigned long)config
->sample_format
.rate
, rate
);
133 if(ioctl(oss_fd
, SNDCTL_DSP_GETBLKSIZE
, &oss_bufsize
) < 0) {
134 error(errno
, "ioctl SNDCTL_DSP_GETBLKSIZE");
135 oss_bufsize
= 2048; /* guess */
139 pthread_cond_signal(&oss_cond
);
141 pthread_cond_wait(&oss_cond
, &oss_lock
);
143 pthread_mutex_unlock(&oss_lock
);
146 static void oss_deactivate(void) {
147 pthread_mutex_lock(&oss_lock
);
150 pthread_cond_signal(&oss_cond
);
152 pthread_cond_wait(&oss_cond
, &oss_lock
);
156 pthread_mutex_unlock(&oss_lock
);
159 static void oss_start(uaudio_callback
*callback
,
162 oss_callback
= callback
;
163 if((e
= pthread_create(&oss_thread
,
167 fatal(e
, "pthread_create");
170 static void oss_stop(void) {
174 pthread_mutex_lock(&oss_lock
);
176 pthread_cond_signal(&oss_cond
);
177 pthread_mutex_unlock(&oss_lock
);
178 pthread_join(oss_thread
, &result
);
181 const struct uaudio uaudio_oss
= {
183 .options
= oss_options
,
186 .activate
= oss_activate
,
187 .deactivate
= oss_deactivate