1 /* Copyright (C) 2009 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /** \file oss_write.c Paraslash's oss output plugin. */
7 #include <sys/soundcard.h>
10 #include "write_cmd.lsg.h"
16 #include "buffer_tree.h"
20 /** Data specific to the oss writer. */
21 struct private_oss_write_data
{
22 /** The file handle of the device. */
24 /** Four bytes for stereo streams, two bytes for mono streams. */
29 * We keep one bit of static storage to make sure only one instance of the oss
30 * writer is running at any given time.
32 static bool sound_device_busy
;
34 static bool sound_device_is_busy(void)
36 return sound_device_busy
;
39 static void set_sound_device_busy(void)
41 assert(!sound_device_busy
);
42 sound_device_busy
= true;
45 static void set_sound_device_idle(void)
47 assert(sound_device_busy
);
48 sound_device_busy
= false;
51 static int get_oss_format(enum sample_format sf
)
54 case SF_S8
: return AFMT_S8
;
55 case SF_U8
: return AFMT_U8
;
56 case SF_S16_LE
: return AFMT_S16_LE
;
57 case SF_S16_BE
: return AFMT_S16_BE
;
58 case SF_U16_LE
: return AFMT_U16_LE
;
59 case SF_U16_BE
: return AFMT_U16_BE
;
60 default: return -E_BAD_SAMPLE_FORMAT
;
64 static void oss_pre_select(struct sched
*s
, void *context
)
66 struct writer_node
*wn
= context
;
67 struct private_oss_write_data
*powd
= wn
->private_data
;
68 int ret
= btr_node_status(wn
->btrn
, wn
->min_iqs
, BTR_NT_LEAF
);
70 if (ret
== 0 || (sound_device_is_busy() && !powd
))
73 return sched_min_delay(s
);
74 para_fd_set(powd
->fd
, &s
->wfds
, &s
->max_fileno
);
77 static void oss_close(struct writer_node
*wn
)
79 struct private_oss_write_data
*powd
= wn
->private_data
;
85 set_sound_device_idle();
89 * The Open Sound System Programmer's Guide sayeth:
91 * Set sampling parameters always so that number of channels (mono/stereo) is
92 * set before selecting sampling rate (speed). Failing to do this will make
93 * your program incompatible with cards such as the SoundBlaster Pro which
94 * supports 44.1 kHz in mono but just 22.05 kHz in stereo. A program which
95 * selects 44.1 kHz speed and then sets the device to stereo mode will
96 * incorrectly believe that the device is still in 44.1 kHz mode when actually
97 * the speed is decreased to 22.05 kHz.
99 static int oss_init(struct writer_node
*wn
, unsigned sample_rate
,
100 unsigned channels
, int sample_format
)
104 struct private_oss_write_data
*powd
= para_calloc(sizeof(*powd
));
105 const char *dev
= WRITE_CMD_OPT_STRING_VAL(OSS
, DEVICE
, wn
->lpr
);
107 PARA_INFO_LOG("opening %s\n", dev
);
108 ret
= para_open(dev
, O_WRONLY
, 0);
112 ret
= mark_fd_nonblocking(powd
->fd
);
116 ret
= get_oss_format(sample_format
);
119 sample_format
= format
= ret
;
120 ret
= ioctl(powd
->fd
, SNDCTL_DSP_SETFMT
, &format
);
122 ret
= -ERRNO_TO_PARA_ERROR(errno
);
123 PARA_ERROR_LOG("could not set sample format\n");
126 ret
= -E_BAD_SAMPLE_FORMAT
;
127 if (format
!= sample_format
)
129 /* set number of channels */
131 ret
= ioctl(powd
->fd
, SNDCTL_DSP_CHANNELS
, &ch
);
133 ret
= -ERRNO_TO_PARA_ERROR(errno
);
136 ret
= -E_BAD_CHANNEL_COUNT
;
139 if (format
== SF_U8
|| format
== SF_S8
)
140 powd
->bytes_per_frame
= ch
;
142 powd
->bytes_per_frame
= ch
* 2;
147 * If we request a higher sampling rate than is supported by the
148 * device, the highest possible speed is automatically used. The
149 * value actually used is returned as the new value of the argument.
152 ret
= ioctl(powd
->fd
, SNDCTL_DSP_SPEED
, &rate
);
154 ret
= -ERRNO_TO_PARA_ERROR(errno
);
157 if (rate
!= sample_rate
) {
158 unsigned min
= PARA_MIN(rate
, sample_rate
),
159 max
= PARA_MAX(rate
, sample_rate
);
161 * Check whether the returned sample rate differs significantly
162 * from the requested one.
164 ret
= -E_BAD_SAMPLERATE
;
165 if (100 * max
> 110 * min
) /* more than 10% deviation */
167 PARA_NOTICE_LOG("using %uHz rather than %uHz\n", rate
,
170 wn
->min_iqs
= powd
->bytes_per_frame
;
171 wn
->private_data
= powd
;
177 PARA_ERROR_LOG("failed to init %s: %s\n", dev
, para_strerror(-ret
));
181 static int oss_post_select(__a_unused
struct sched
*s
, void *context
)
183 struct writer_node
*wn
= context
;
184 struct private_oss_write_data
*powd
= wn
->private_data
;
185 struct btr_node
*btrn
= wn
->btrn
;
186 size_t frames
, bytes
;
191 ret
= task_get_notification(wn
->task
);
194 ret
= btr_node_status(btrn
, wn
->min_iqs
, BTR_NT_LEAF
);
198 int32_t rate
, ch
, format
;
200 if (sound_device_is_busy())
202 get_btr_sample_rate(btrn
, &rate
);
203 get_btr_channels(btrn
, &ch
);
204 get_btr_sample_format(btrn
, &format
);
205 ret
= oss_init(wn
, rate
, ch
, format
);
208 set_sound_device_busy();
211 btr_merge(btrn
, wn
->min_iqs
);
212 bytes
= btr_next_buffer(btrn
, &data
);
213 frames
= bytes
/ powd
->bytes_per_frame
;
214 if (!frames
) { /* eof and less than a single frame available */
215 ret
= -E_WRITE_COMMON_EOF
;
219 if (!FD_ISSET(powd
->fd
, &s
->wfds
))
221 /* get maximal number of bytes that can be written */
222 ret
= ioctl(powd
->fd
, SNDCTL_DSP_GETOSPACE
, &abi
);
224 size_t max_frames
= abi
.bytes
/ powd
->bytes_per_frame
;
227 /* cap number of frames to avoid sound artefacts */
228 frames
= PARA_MIN(frames
, max_frames
);
230 ret
= xwrite(powd
->fd
, data
, frames
* powd
->bytes_per_frame
);
233 btr_consume(btrn
, ret
);
237 btr_remove_node(&wn
->btrn
);
241 const struct writer lsg_write_cmd_com_oss_user_data
= {
242 .pre_select
= oss_pre_select
,
243 .post_select
= oss_post_select
,