4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "audioconfig.h"
24 #include "audiodevice.h"
27 #include "condition.h"
30 #include "playbackconfig.h"
31 #include "preferences.h"
32 #include "recordconfig.h"
39 // These are only available in commercial OSS
42 #define AFMT_S32_LE 0x00001000
43 #define AFMT_S32_BE 0x00002000
47 // Synchronie multiple devices by using threads
49 OSSThread::OSSThread(AudioOSS *device)
55 this->device = device;
56 input_lock = new Condition(0, "OSSThread::input_lock");
57 output_lock = new Condition(1, "OSSThread::output_lock");
58 read_lock = new Condition(0, "OSSThread::read_lock");
59 write_lock = new Condition(0, "OSSThread::write_lock");
65 timer_lock = new Mutex("OSSThread::timer_lock");
69 OSSThread::~OSSThread()
84 // this makes the longest (blocking) write 1024 samples
85 // if this is not done, the video can be jerky
86 AudioDevice *audio_device = device->device;
87 int frame_size = audio_device->get_ochannels() * audio_device->get_obits()/8;
88 int maxsz = 1024*frame_size, blksz = maxsz;
89 ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blksz);
90 if( blksz > maxsz ) blksz = maxsz;
93 input_lock->lock("OSSThread::run 1");
96 read(fd, data, bytes);
103 unsigned char *bp = data;
104 while( count > 0 && !done ) {
105 Thread::enable_cancel();
106 int len = count>blksz ? blksz : count;
107 int ret = write(fd, bp, len);
108 Thread::disable_cancel();
113 timer_lock->lock("OSSThread::run");
114 if( !ioctl(fd, SNDCTL_DSP_GETODELAY, &delay) )
116 bytes_written += ret;
118 timer_lock->unlock();
120 write_lock->unlock();
122 output_lock->unlock();
126 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
128 output_lock->lock("OSSThread::write_data");
134 input_lock->unlock();
137 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
139 output_lock->lock("OSSThread::read_data");
145 input_lock->unlock();
148 void OSSThread::wait_read()
150 read_lock->lock("OSSThread::wait_read");
153 void OSSThread::wait_write()
155 write_lock->lock("OSSThread::wait_write");
160 int64_t OSSThread::device_position()
162 timer_lock->lock("OSSThread::device_position");
163 int64_t ret = bytes_written - delay;
164 timer_lock->unlock();
169 AudioOSS::AudioOSS(AudioDevice *device)
170 : AudioLowLevel(device)
172 for(int i = 0; i < MAXDEVICES; i++) {
173 dsp_in[i] = dsp_out[i] = -1;
176 data_allocated[i] = 0;
180 AudioOSS::~AudioOSS()
184 int AudioOSS::open_input()
186 device->in_bits = device->in_config->oss_in_bits;
187 // 24 bits not available in OSS
188 if(device->in_bits == 24) device->in_bits = 32;
190 for(int i = 0; i < MAXDEVICES; i++) {
191 if(device->in_config->oss_enable[i]) {
192 //printf("AudioOSS::open_input 10\n");
193 dsp_in[i] = open(device->in_config->oss_in_device[i], O_RDONLY/* | O_NDELAY*/);
194 //printf("AudioOSS::open_input 20\n");
196 fprintf(stderr, "AudioOSS::open_input %s: %s\n",
197 device->in_config->oss_in_device[i], strerror(errno));
202 int format = get_fmt(device->in_config->oss_in_bits);
203 int buffer_info = sizetofrag(device->in_samples,
204 device->get_ichannels(),
205 device->in_config->oss_in_bits);
207 set_cloexec_flag(dsp_in[i], 1);
209 // For the ice1712 the buffer must be maximum or no space will be allocated.
210 if(device->idriver == AUDIO_OSS_ENVY24)
211 buffer_info = 0x7fff000f;
213 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info))
214 fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_SETFRAGMENT");
215 else if(ioctl(dsp_in[i], SNDCTL_DSP_SETFMT, &format) < 0)
216 fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_SETFMT");
218 int channels = device->get_ichannels();
219 if(ioctl(dsp_in[i], SNDCTL_DSP_CHANNELS, &channels) < 0)
220 fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_CHANNELS");
221 else if(ioctl(dsp_in[i], SNDCTL_DSP_SPEED, &device->in_samplerate) < 0)
222 fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_SPEED");
231 audio_buf_info recinfo;
232 ioctl(dsp_in[i], SNDCTL_DSP_GETISPACE, &recinfo);
234 //printf("AudioOSS::open_input fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
235 // recinfo.fragments, recinfo.fragstotal, recinfo.fragsize, recinfo.bytes);
237 thread[i] = new OSSThread(this);
244 int AudioOSS::open_output()
246 device->out_bits = device->out_config->oss_out_bits;
247 // OSS only supports 8, 16, and 32
248 if(device->out_bits == 24) device->out_bits = 32;
250 for(int i = 0; i < MAXDEVICES; i++) {
251 if(device->out_config->oss_enable[i]) {
252 // Linux 2.4.18 no longer supports allocating the maximum buffer size.
253 // Need the shrink fragment size in preferences until it works.
255 open(device->out_config->oss_out_device[i],
256 O_WRONLY /*| O_NDELAY*/);
258 perror("AudioOSS::open_output");
263 int format = get_fmt(device->out_config->oss_out_bits);
264 int buffer_info = sizetofrag(device->out_samples,
265 device->get_ochannels(),
266 device->out_config->oss_out_bits);
268 set_cloexec_flag(dsp_out[i], 1);
270 // For the ice1712 the buffer must be maximum or no space will be allocated.
271 if(device->odriver == AUDIO_OSS_ENVY24)
272 buffer_info = 0x7fff000f;
274 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info))
275 fprintf(stderr,"SNDCTL_DSP_SETFRAGMENT 2 failed.\n");
276 else if(ioctl(dsp_out[i], SNDCTL_DSP_SETFMT, &format) < 0)
277 fprintf(stderr,"SNDCTL_DSP_SETFMT 2 failed\n");
279 int channels = device->get_ochannels();
280 if(ioctl(dsp_out[i], SNDCTL_DSP_CHANNELS, &channels) < 0)
281 fprintf(stderr,"SNDCTL_DSP_CHANNELS 2 failed\n");
282 else if(ioctl(dsp_out[i], SNDCTL_DSP_SPEED, &device->out_samplerate) < 0)
283 fprintf(stderr,"SNDCTL_DSP_SPEED 2 failed\n");
292 audio_buf_info playinfo;
293 ioctl(dsp_out[i], SNDCTL_DSP_GETOSPACE, &playinfo);
294 // printf("AudioOSS::open_output fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
295 // playinfo.fragments, playinfo.fragstotal, playinfo.fragsize, playinfo.bytes);
296 device->device_buffer = playinfo.bytes;
297 thread[i] = new OSSThread(this);
304 int AudioOSS::sizetofrag(int samples, int channels, int bits)
306 int testfrag = 2, fragsize = 1, grain = 4;
307 samples *= channels * bits / (8 * grain);
308 while(testfrag < samples) {
312 //printf("AudioOSS::sizetofrag %d\n", fragsize);
313 return (grain << 16) | fragsize;
316 int AudioOSS::get_fmt(int bits)
319 case 32: return AFMT_S32_LE; break;
320 case 16: return AFMT_S16_LE; break;
321 case 8: return AFMT_S8; break;
327 int AudioOSS::close_all()
329 //printf("AudioOSS::close_all 1\n");
330 for(int i = 0; i < MAXDEVICES; i++) {
332 ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);
337 if(dsp_out[i] >= 0) {
338 //printf("AudioOSS::close_all 2\n");
339 ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);
344 if(thread[i]) delete thread[i];
345 if(data[i]) delete [] data[i];
350 int AudioOSS::set_cloexec_flag(int desc, int value)
352 int oldflags = fcntl (desc, F_GETFD, 0);
353 if (oldflags < 0) return oldflags;
355 oldflags |= FD_CLOEXEC;
357 oldflags &= ~FD_CLOEXEC;
358 return fcntl(desc, F_SETFD, oldflags);
361 int64_t AudioOSS::device_position()
363 for (int i = 0; i < MAXDEVICES; i++) {
365 int frame_size = device->get_ochannels() * device->get_obits()/8;
366 int64_t pos = thread[i]->device_position() / frame_size;
367 int64_t tmr = thread[i]->timer->get_scaled_difference(device->out_samplerate);
372 if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
374 //printf("AudioOSS::device_position %d %d %d\n", info.bytes, device->get_obits(), device->get_ochannels());
375 // workaround for ALSA OSS emulation driver's bug
376 // the problem is that if the first write to sound device was not full lenght fragment then
377 // _GETOPTR returns insanely large numbers at first moments of play
378 if (info.bytes > 2100000000) return 0;
379 int frame_size = device->get_ochannels() * device->get_obits()/8;
380 return info.bytes / frame_size;
385 int AudioOSS::interrupt_playback()
387 //printf("AudioOSS::interrupt_playback 1\n");
388 for(int i = 0; i < MAXDEVICES; i++) {
391 thread[i]->input_lock->unlock();
392 thread[i]->write_lock->unlock();
396 //printf("AudioOSS::interrupt_playback 100\n");
400 int64_t AudioOSS::samples_output()
402 for( int i=0; i<MAXDEVICES; ++i ) {
404 int frame_size = device->get_ochannels() * device->get_obits()/8;
405 return thread[i]->bytes_written / frame_size;
411 int AudioOSS::read_buffer(char *buffer, int bytes)
413 int sample_size = device->get_ibits() / 8;
414 int out_frame_size = device->get_ichannels() * sample_size;
415 int samples = bytes / out_frame_size;
417 //printf("AudioOSS::read_buffer 1 %d\n", bytes);
419 for(int i = 0; i < MAXDEVICES; i++) {
421 int in_frame_size = device->get_ichannels() * sample_size;
423 if(data[i] && data_allocated[i] < bytes) {
428 data[i] = new unsigned char[bytes];
429 data_allocated[i] = bytes;
432 thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
436 //printf("AudioOSS::read_buffer 1 %d\n", device->get_ibits());
437 for(int i = 0, out_channel = 0; i < MAXDEVICES; i++) {
439 thread[i]->wait_read();
441 for(int in_channel = 0;
442 in_channel < device->get_ichannels();
444 int in_frame_size = device->get_ichannels() * sample_size;
446 for(int k = 0; k < samples; k++) {
450 buffer[out_channel * sample_size + k * out_frame_size + l] =
451 data[i][in_channel * sample_size + k * in_frame_size + l];
458 //printf("AudioOSS::read_buffer 2\n");
462 int AudioOSS::write_buffer(char *buffer, int bytes)
464 int sample_size = device->get_obits() / 8;
465 int in_frame_size = device->get_ochannels() * sample_size;
466 int samples = bytes / in_frame_size;
468 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++) {
470 int out_frame_size = device->get_ochannels() * sample_size;
471 if(data[i] && data_allocated[i] < bytes) {
476 data[i] = new unsigned char[bytes];
477 data_allocated[i] = bytes;
480 for(int out_channel = 0;
481 out_channel < device->get_ochannels();
484 for(int k = 0; k < samples; k++) {
485 for(int l = 0; l < sample_size; l++) {
486 data[i][out_channel * sample_size + k * out_frame_size + l] =
487 buffer[in_channel * sample_size + k * in_frame_size + l];
493 thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
496 for(int i = 0; i < MAXDEVICES; i++) {
497 if( thread[i] ) thread[i]->wait_write();
502 int AudioOSS::flush_device()
504 for(int i = 0; i < MAXDEVICES; i++)
505 if(thread[i]) ioctl(get_output(i), SNDCTL_DSP_SYNC, 0);
509 int AudioOSS::get_output(int number)
511 return device->w ? dsp_out[number] : -1;
514 int AudioOSS::get_input(int number)
516 return device->r ? dsp_in[number] : -1;