2 * Copyright (C) 2008 Mark Hills <mark@pogo.org.uk>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * version 2, as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License version 2 for more details.
13 * You should have received a copy of the GNU General Public License
14 * version 2 along with this program; if not, write to the Free
15 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 #include <sys/ioctl.h>
27 #include <sys/soundcard.h>
30 #include "timecoder.h"
33 #define DEFAULT_OSS_BUFFERS 8
34 #define DEFAULT_OSS_FRAGMENT 7
36 static guint oss_fragment
= DEFAULT_OSS_FRAGMENT
;
37 static guint oss_buffers
= DEFAULT_OSS_BUFFERS
;
45 static int clear(struct device_t
*dv
)
48 struct oss_t
*oss
= (struct oss_t
*)dv
->local
;
60 /* Push audio into the device's buffer, for playback */
62 static int push(int fd
, signed short *pcm
, int samples
)
66 bytes
= samples
* DEVICE_CHANNELS
* sizeof(short);
68 r
= write(fd
, pcm
, bytes
);
76 fprintf(stderr
, "Device output overrun.\n");
78 return r
/ DEVICE_CHANNELS
/ sizeof(short);
82 /* Pull audio from the device, for recording */
84 static int pull(int fd
, signed short *pcm
, int samples
)
88 bytes
= samples
* DEVICE_CHANNELS
* sizeof(short);
90 r
= read(fd
, pcm
, bytes
);
98 fprintf(stderr
, "Device input underrun.\n");
100 return r
/ DEVICE_CHANNELS
/ sizeof(short);
104 static int handle(struct device_t
*dv
)
106 signed short pcm
[DEVICE_FRAME
* DEVICE_CHANNELS
];
108 struct oss_t
*oss
= (struct oss_t
*)dv
->local
;
110 /* Check input buffer for recording */
112 if(oss
->pe
->revents
& POLLIN
) {
113 samples
= pull(oss
->fd
, pcm
, DEVICE_FRAME
);
118 timecoder_submit(dv
->timecoder
, pcm
, samples
);
121 /* Check the output buffer for playback */
123 if(oss
->pe
->revents
& POLLOUT
) {
125 /* Always push some audio to the soundcard, even if it means
126 * silence. This has shown itself to be much more reliable
127 * than starting and stopping -- which can affect other
128 * devices in the system. */
131 player_collect(dv
->player
, pcm
, DEVICE_FRAME
);
133 memset(pcm
, 0, DEVICE_FRAME
* DEVICE_CHANNELS
* sizeof(short));
135 samples
= push(oss
->fd
, pcm
, DEVICE_FRAME
);
145 int pollfds(struct device_t
*dv
, struct pollfd
*pe
, int n
)
147 struct oss_t
*oss
= (struct oss_t
*)dv
->local
;
153 pe
->events
= POLLIN
| POLLOUT
| POLLHUP
;
161 int oss_init(struct device_t
*dv
, const char *filename
,
162 unsigned short buffers
, unsigned short fragment
)
167 fd
= open(filename
, O_RDWR
, 0);
173 /* Ideally would set independent settings for the record and
174 * playback buffers. Recording needs to buffer where necessary, as
175 * lost audio results in zero-crossings which corrupt the
176 * timecode. Playback buffer neews to be short to avoid high
179 p
= (buffers
<< 16) | fragment
;
180 if(ioctl(fd
, SNDCTL_DSP_SETFRAGMENT
, &p
) == -1) {
181 perror("SNDCTL_DSP_SETFRAGMENT");
186 if(ioctl(fd
, SNDCTL_DSP_SETFMT
, &p
) == -1) {
187 perror("SNDCTL_DSP_SETFMT");
192 if(ioctl(fd
, SNDCTL_DSP_CHANNELS
, &p
) == -1) {
193 perror("SNDCTL_DSP_CHANNELS");
198 if(ioctl(fd
, SNDCTL_DSP_SPEED
, &p
) == -1) {
199 perror("SNDCTL_DSP_SPEED");
203 if(fcntl(fd
, F_SETFL
, O_NONBLOCK
) == -1) {
208 dv
->local
= malloc(sizeof(struct oss_t
));
214 oss
= (struct oss_t
*)dv
->local
;
219 dv
->pollfds
= pollfds
;
232 static gboolean
parse_oss_device(const gchar
*option_name
, const gchar
*value
, gpointer data
, GError
**error
)
234 struct device_t
* device
= createDevice(error
);
239 return connectAudio(device
, oss_init(device
, value
, oss_buffers
, oss_fragment
));
242 static GOptionEntry ossOptions
[] =
244 { "oss_device", 'o', 0, G_OPTION_ARG_CALLBACK
, &parse_oss_device
, "Build a deck connected to OSS audio device", "/dev/dsp"},
245 // Set number of buffers for subsequent devices
246 { "buffer_count", 'b', 0, G_OPTION_ARG_INT
, &oss_buffers
, "Number of buffers", NULL
},
247 { "buffer_size", 'f', 0, G_OPTION_ARG_INT
, &oss_fragment
, "Buffer size to request (2^n bytes)", NULL
},
251 GOptionGroup
* get_oss_option_group()
253 GOptionGroup
* group
= g_option_group_new
256 "OSS device options",
257 "Show OSS help options",
262 if(ossOptions
[1].arg_description
== NULL
)
263 ossOptions
[1].arg_description
= g_strdup_printf("%u", DEFAULT_OSS_BUFFERS
);
265 if(ossOptions
[2].arg_description
== NULL
)
266 ossOptions
[2].arg_description
= g_strdup_printf("%u", DEFAULT_OSS_FRAGMENT
);
268 g_option_group_add_entries(group
, ossOptions
);