4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "audioconfig.h"
23 #include "audiodevice.h"
26 #include "condition.h"
28 #include "playbackconfig.h"
29 #include "preferences.h"
30 #include "recordconfig.h"
36 // These are only available in commercial OSS
39 #define AFMT_S32_LE 0x00001000
40 #define AFMT_S32_BE 0x00002000
44 // Synchronie multiple devices by using threads
46 OSSThread::OSSThread(AudioOSS *device)
52 this->device = device;
53 input_lock = new Condition(0, "OSSThread::input_lock");
54 output_lock = new Condition(1, "OSSThread::output_lock");
55 read_lock = new Condition(0, "OSSThread::read_lock");
56 write_lock = new Condition(0, "OSSThread::write_lock");
59 OSSThread::~OSSThread()
73 input_lock->lock("OSSThread::run 1");
76 read(fd, data, bytes);
81 unsigned char *bp = data;
83 Thread::enable_cancel();
84 int ret = write(fd, bp, bytes);
85 Thread::disable_cancel();
92 output_lock->unlock();
96 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
98 output_lock->lock("OSSThread::write_data");
104 input_lock->unlock();
107 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
109 output_lock->lock("OSSThread::read_data");
115 input_lock->unlock();
118 void OSSThread::wait_read()
120 read_lock->lock("OSSThread::wait_read");
123 void OSSThread::wait_write()
125 write_lock->lock("OSSThread::wait_write");
138 AudioOSS::AudioOSS(AudioDevice *device)
139 : AudioLowLevel(device)
141 for(int i = 0; i < MAXDEVICES; i++) {
142 dsp_in[i] = dsp_out[i] = -1;
145 data_allocated[i] = 0;
149 AudioOSS::~AudioOSS()
153 int AudioOSS::open_input()
155 device->in_bits = device->in_config->oss_in_bits;
156 // 24 bits not available in OSS
157 if(device->in_bits == 24) device->in_bits = 32;
159 for(int i = 0; i < MAXDEVICES; i++) {
160 if(device->in_config->oss_enable[i]) {
161 //printf("AudioOSS::open_input 10\n");
162 dsp_in[i] = open(device->in_config->oss_in_device[i], O_RDONLY/* | O_NDELAY*/);
163 //printf("AudioOSS::open_input 20\n");
164 if(dsp_in[i] < 0) fprintf(stderr, "AudioOSS::open_input %s: %s\n",
165 device->in_config->oss_in_device[i],
168 int format = get_fmt(device->in_config->oss_in_bits);
169 int buffer_info = sizetofrag(device->in_samples,
170 device->get_ichannels(),
171 device->in_config->oss_in_bits);
173 set_cloexec_flag(dsp_in[i], 1);
175 // For the ice1712 the buffer must be maximum or no space will be allocated.
176 if(device->idriver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
177 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
178 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
179 int channels = device->get_ichannels();
180 if(ioctl(dsp_in[i], SNDCTL_DSP_CHANNELS, &channels) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
181 if(ioctl(dsp_in[i], SNDCTL_DSP_SPEED, &device->in_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
183 audio_buf_info recinfo;
184 ioctl(dsp_in[i], SNDCTL_DSP_GETISPACE, &recinfo);
186 //printf("AudioOSS::open_input fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
187 // recinfo.fragments, recinfo.fragstotal, recinfo.fragsize, recinfo.bytes);
189 thread[i] = new OSSThread(this);
196 int AudioOSS::open_output()
198 device->out_bits = device->out_config->oss_out_bits;
199 // OSS only supports 8, 16, and 32
200 if(device->out_bits == 24) device->out_bits = 32;
202 for(int i = 0; i < MAXDEVICES; i++) {
203 if(device->out_config->oss_enable[i]) {
204 // Linux 2.4.18 no longer supports allocating the maximum buffer size.
205 // Need the shrink fragment size in preferences until it works.
207 open(device->out_config->oss_out_device[i],
208 O_WRONLY /*| O_NDELAY*/);
209 if(dsp_out[i] < 0) perror("AudioOSS::open_output");
211 int format = get_fmt(device->out_config->oss_out_bits);
212 int buffer_info = sizetofrag(device->out_samples,
213 device->get_ochannels(),
214 device->out_config->oss_out_bits);
215 audio_buf_info playinfo;
217 set_cloexec_flag(dsp_out[i], 1);
219 // For the ice1712 the buffer must be maximum or no space will be allocated.
220 if(device->odriver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
221 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT 2 failed.\n");
222 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT 2 failed\n");
223 int channels = device->get_ochannels();
224 if(ioctl(dsp_out[i], SNDCTL_DSP_CHANNELS, &channels) < 0) printf("SNDCTL_DSP_CHANNELS 2 failed\n");
225 if(ioctl(dsp_out[i], SNDCTL_DSP_SPEED, &device->out_samplerate) < 0) printf("SNDCTL_DSP_SPEED 2 failed\n");
226 ioctl(dsp_out[i], SNDCTL_DSP_GETOSPACE, &playinfo);
227 // printf("AudioOSS::open_output fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
228 // playinfo.fragments, playinfo.fragstotal, playinfo.fragsize, playinfo.bytes);
229 device->device_buffer = playinfo.bytes;
230 thread[i] = new OSSThread(this);
237 int AudioOSS::sizetofrag(int samples, int channels, int bits)
239 int testfrag = 2, fragsize = 1;
240 samples *= channels * bits / 8;
241 while(testfrag < samples) {
245 //printf("AudioOSS::sizetofrag %d\n", fragsize);
246 return (4 << 16) | fragsize;
249 int AudioOSS::get_fmt(int bits)
252 case 32: return AFMT_S32_LE; break;
253 case 16: return AFMT_S16_LE; break;
254 case 8: return AFMT_S8; break;
260 int AudioOSS::close_all()
262 //printf("AudioOSS::close_all 1\n");
263 for(int i = 0; i < MAXDEVICES; i++) {
265 ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);
270 if(dsp_out[i] >= 0) {
271 //printf("AudioOSS::close_all 2\n");
272 ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);
277 if(thread[i]) delete thread[i];
278 if(data[i]) delete [] data[i];
283 int AudioOSS::set_cloexec_flag(int desc, int value)
285 int oldflags = fcntl (desc, F_GETFD, 0);
286 if (oldflags < 0) return oldflags;
288 oldflags |= FD_CLOEXEC;
290 oldflags &= ~FD_CLOEXEC;
291 return fcntl(desc, F_SETFD, oldflags);
294 int64_t AudioOSS::device_position()
297 if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
299 //printf("AudioOSS::device_position %d %d %d\n", info.bytes, device->get_obits(), device->get_ochannels());
300 // workaround for ALSA OSS emulation driver's bug
301 // the problem is that if the first write to sound device was not full lenght fragment then
302 // _GETOPTR returns insanely large numbers at first moments of play
303 if (info.bytes > 2100000000) return 0;
304 int frame = device->get_ochannels() * device->get_obits()/8;
305 return info.bytes / frame;
310 int AudioOSS::interrupt_playback()
312 //printf("AudioOSS::interrupt_playback 1\n");
313 for(int i = 0; i < MAXDEVICES; i++) {
316 thread[i]->input_lock->unlock();
317 thread[i]->write_lock->unlock();
321 //printf("AudioOSS::interrupt_playback 100\n");
325 int AudioOSS::read_buffer(char *buffer, int bytes)
327 int sample_size = device->get_ibits() / 8;
328 int out_frame_size = device->get_ichannels() * sample_size;
329 int samples = bytes / out_frame_size;
331 //printf("AudioOSS::read_buffer 1 %d\n", bytes);
333 for(int i = 0; i < MAXDEVICES; i++) {
335 int in_frame_size = device->get_ichannels() * sample_size;
337 if(data[i] && data_allocated[i] < bytes) {
342 data[i] = new unsigned char[bytes];
343 data_allocated[i] = bytes;
346 thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
350 //printf("AudioOSS::read_buffer 1 %d\n", device->get_ibits());
351 for(int i = 0, out_channel = 0; i < MAXDEVICES; i++) {
353 thread[i]->wait_read();
355 for(int in_channel = 0;
356 in_channel < device->get_ichannels();
358 int in_frame_size = device->get_ichannels() * sample_size;
360 for(int k = 0; k < samples; k++) {
364 buffer[out_channel * sample_size + k * out_frame_size + l] =
365 data[i][in_channel * sample_size + k * in_frame_size + l];
372 //printf("AudioOSS::read_buffer 2\n");
376 int AudioOSS::write_buffer(char *buffer, int bytes)
378 int sample_size = device->get_obits() / 8;
379 int in_frame_size = device->get_ochannels() * sample_size;
380 int samples = bytes / in_frame_size;
382 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++) {
384 int out_frame_size = device->get_ochannels() * sample_size;
385 if(data[i] && data_allocated[i] < bytes) {
390 data[i] = new unsigned char[bytes];
391 data_allocated[i] = bytes;
394 for(int out_channel = 0;
395 out_channel < device->get_ochannels();
398 for(int k = 0; k < samples; k++) {
399 for(int l = 0; l < sample_size; l++) {
400 data[i][out_channel * sample_size + k * out_frame_size + l] =
401 buffer[in_channel * sample_size + k * in_frame_size + l];
407 thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
410 for(int i = 0; i < MAXDEVICES; i++) {
411 if( thread[i] ) thread[i]->wait_write();
416 int AudioOSS::flush_device()
418 for(int i = 0; i < MAXDEVICES; i++)
419 if(thread[i]) ioctl(get_output(i), SNDCTL_DSP_SYNC, 0);
423 int AudioOSS::get_output(int number)
425 return dsp_out[number];
428 int AudioOSS::get_input(int number)
430 return dsp_in[number];