add missing GPL information in guicast program files
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / audiooss.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "audioconfig.h"
23 #include "audiodevice.h"
24 #include "audiooss.h"
25 #include "clip.h"
26 #include "condition.h"
27 #include "errno.h"
28 #include "language.h"
29 #include "playbackconfig.h"
30 #include "preferences.h"
31 #include "recordconfig.h"
32 #include "mutex.h"
33
34 #include <string.h>
35
36 #ifdef HAVE_OSS
37
38 // These are only available in commercial OSS
39
40 #ifndef AFMT_S32_LE
41 #define AFMT_S32_LE      0x00001000
42 #define AFMT_S32_BE      0x00002000
43 #endif
44
45
46 // Synchronie multiple devices by using threads
47
48 OSSThread::OSSThread(AudioOSS *device)
49  : Thread(1, 0, 0)
50 {
51         rd = 0;
52         wr = 0;
53         done = 0;
54         this->device = device;
55         input_lock = new Condition(0, "OSSThread::input_lock");
56         output_lock = new Condition(1, "OSSThread::output_lock");
57         read_lock = new Condition(0, "OSSThread::read_lock");
58         write_lock = new Condition(0, "OSSThread::write_lock");
59
60         // delay / timing
61         bytes_written = 0;
62         timer = new Timer;
63         delay = 0;
64         timer_lock = new Mutex("OSSThread::timer_lock");
65         timer->update();
66 }
67
68 OSSThread::~OSSThread()
69 {
70         done = 1;
71         input_lock->unlock();
72         Thread::join();
73         delete input_lock;
74         delete output_lock;
75         delete read_lock;
76         delete write_lock;
77         delete timer_lock;
78         delete timer;
79 }
80
81 void OSSThread::run()
82 {
83 // this makes the longest (blocking) write 1024 samples
84 //  if this is not done, the video can be jerky
85         AudioDevice *audio_device = device->device;
86         int frame_size = audio_device->get_ochannels() * audio_device->get_obits()/8;
87         int maxsz = 1024*frame_size, blksz = maxsz;
88         ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blksz);
89         if( blksz > maxsz ) blksz = maxsz;
90
91         while(!done) {
92                 input_lock->lock("OSSThread::run 1");
93                 if(done) return;
94                 if(rd) {
95                         read(fd, data, bytes);
96                         read_lock->unlock();
97                 }
98                 else if(wr) {
99                         if( !bytes_written )
100                                 timer->update();
101                         int count = bytes;
102                         unsigned char *bp = data;
103                         while( count > 0 && !done ) {
104                                 Thread::enable_cancel();
105                                 int len = count>blksz ? blksz : count;
106                                 int ret = write(fd, bp, len);
107                                 Thread::disable_cancel();
108                                 if( ret < 0 ) break;
109                                 bp += ret;
110                                 count -= ret;
111                                 int delay = 0;
112                                 timer_lock->lock("OSSThread::run");
113                                 if( !ioctl(fd, SNDCTL_DSP_GETODELAY, &delay) )
114                                         this->delay = delay;
115                                 bytes_written += ret;
116                                 timer->update();
117                                 timer_lock->unlock();
118                         }
119                         write_lock->unlock();
120                 }
121                 output_lock->unlock();
122         }
123 }
124
125 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
126 {
127         output_lock->lock("OSSThread::write_data");
128         wr = 1;
129         rd = 0;
130         this->data = data;
131         this->bytes = bytes;
132         this->fd = fd;
133         input_lock->unlock();
134 }
135
136 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
137 {
138         output_lock->lock("OSSThread::read_data");
139         wr = 0;
140         rd = 1;
141         this->data = data;
142         this->bytes = bytes;
143         this->fd = fd;
144         input_lock->unlock();
145 }
146
147 void OSSThread::wait_read()
148 {
149         read_lock->lock("OSSThread::wait_read");
150 }
151
152 void OSSThread::wait_write()
153 {
154         write_lock->lock("OSSThread::wait_write");
155 }
156
157
158 // bytes not samples
159 int64_t OSSThread::device_position()
160 {
161         timer_lock->lock("OSSThread::device_position");
162         int64_t ret = bytes_written - delay;
163         timer_lock->unlock();
164         return ret;
165 }
166
167
168 AudioOSS::AudioOSS(AudioDevice *device)
169  : AudioLowLevel(device)
170 {
171         for(int i = 0; i < MAXDEVICES; i++) {
172                 dsp_in[i] = dsp_out[i] = -1;
173                 thread[i] = 0;
174                 data[i] = 0;
175                 data_allocated[i] = 0;
176         }
177 }
178
179 AudioOSS::~AudioOSS()
180 {
181 }
182
183 int AudioOSS::open_input()
184 {
185         device->in_bits = device->in_config->oss_in_bits;
186 // 24 bits not available in OSS
187         if(device->in_bits == 24) device->in_bits = 32;
188
189         for(int i = 0; i < MAXDEVICES; i++) {
190                 if(device->in_config->oss_enable[i]) {
191 //printf("AudioOSS::open_input 10\n");
192                         dsp_in[i] = open(device->in_config->oss_in_device[i], O_RDONLY/* | O_NDELAY*/);
193 //printf("AudioOSS::open_input 20\n");
194                         if(dsp_in[i] < 0) {
195                                 fprintf(stderr, "AudioOSS::open_input %s: %s\n",
196                                         device->in_config->oss_in_device[i], strerror(errno));
197                                 close_all();
198                                 return 1;
199                         }
200
201                         int format = get_fmt(device->in_config->oss_in_bits);
202                         int buffer_info = sizetofrag(device->in_samples,
203                                 device->get_ichannels(),
204                                 device->in_config->oss_in_bits);
205
206                         set_cloexec_flag(dsp_in[i], 1);
207
208 // For the ice1712 the buffer must be maximum or no space will be allocated.
209                         if(device->idriver == AUDIO_OSS_ENVY24)
210                                 buffer_info = 0x7fff000f;
211                         int ret = 1;
212                         if(ioctl(dsp_in[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info))
213                                 fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_SETFRAGMENT");
214                         else if(ioctl(dsp_in[i], SNDCTL_DSP_SETFMT, &format) < 0)
215                                 fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_SETFMT");
216                         else {
217                                 int channels = device->get_ichannels();
218                                 if(ioctl(dsp_in[i], SNDCTL_DSP_CHANNELS, &channels) < 0)
219                                         fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_CHANNELS");
220                                 else if(ioctl(dsp_in[i], SNDCTL_DSP_SPEED, &device->in_samplerate) < 0)
221                                         fprintf(stderr, _("%s failed\n"), "SNDCTL_DSP_SPEED");
222                                 else
223                                         ret = 0;
224                         }
225                         if( ret ) {
226                                 close_all();
227                                 return ret;
228                         }
229
230                         audio_buf_info recinfo;
231                         ioctl(dsp_in[i], SNDCTL_DSP_GETISPACE, &recinfo);
232
233 //printf("AudioOSS::open_input fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
234 //      recinfo.fragments, recinfo.fragstotal, recinfo.fragsize, recinfo.bytes);
235
236                         thread[i] = new OSSThread(this);
237                         thread[i]->start();
238                 }
239         }
240         return 0;
241 }
242
243 int AudioOSS::open_output()
244 {
245         device->out_bits = device->out_config->oss_out_bits;
246 // OSS only supports 8, 16, and 32
247         if(device->out_bits == 24) device->out_bits = 32;
248
249         for(int i = 0; i < MAXDEVICES; i++) {
250                 if(device->out_config->oss_enable[i]) {
251 // Linux 2.4.18 no longer supports allocating the maximum buffer size.
252 // Need the shrink fragment size in preferences until it works.
253                         dsp_out[i] =
254                                 open(device->out_config->oss_out_device[i],
255                                         O_WRONLY /*| O_NDELAY*/);
256                         if(dsp_out[i] < 0) {
257                                 perror("AudioOSS::open_output");
258                                 close_all();
259                                 return 1;
260                         }
261
262                         int format = get_fmt(device->out_config->oss_out_bits);
263                         int buffer_info = sizetofrag(device->out_samples,
264                                 device->get_ochannels(),
265                                 device->out_config->oss_out_bits);
266
267                         set_cloexec_flag(dsp_out[i], 1);
268
269 // For the ice1712 the buffer must be maximum or no space will be allocated.
270                         if(device->odriver == AUDIO_OSS_ENVY24)
271                                 buffer_info = 0x7fff000f;
272                         int ret = 1;
273                         if(ioctl(dsp_out[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info))
274                                 fprintf(stderr,"SNDCTL_DSP_SETFRAGMENT 2 failed.\n");
275                         else if(ioctl(dsp_out[i], SNDCTL_DSP_SETFMT, &format) < 0)
276                                 fprintf(stderr,"SNDCTL_DSP_SETFMT 2 failed\n");
277                         else {
278                                 int channels = device->get_ochannels();
279                                 if(ioctl(dsp_out[i], SNDCTL_DSP_CHANNELS, &channels) < 0)
280                                         fprintf(stderr,"SNDCTL_DSP_CHANNELS 2 failed\n");
281                                 else if(ioctl(dsp_out[i], SNDCTL_DSP_SPEED, &device->out_samplerate) < 0)
282                                         fprintf(stderr,"SNDCTL_DSP_SPEED 2 failed\n");
283                                 else
284                                         ret = 0;
285                         }
286                         if( ret ) {
287                                 close_all();
288                                 return ret;
289                         }
290
291                         audio_buf_info playinfo;
292                         ioctl(dsp_out[i], SNDCTL_DSP_GETOSPACE, &playinfo);
293 // printf("AudioOSS::open_output fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
294 // playinfo.fragments, playinfo.fragstotal, playinfo.fragsize, playinfo.bytes);
295                         device->device_buffer = playinfo.bytes;
296                         thread[i] = new OSSThread(this);
297                         thread[i]->start();
298                 }
299         }
300         return 0;
301 }
302
303 int AudioOSS::sizetofrag(int samples, int channels, int bits)
304 {
305         int testfrag = 2, fragsize = 1, grain = 4;
306         samples *= channels * bits / (8 * grain);
307         while(testfrag < samples) {
308                 fragsize++;
309                 testfrag *= 2;
310         }
311 //printf("AudioOSS::sizetofrag %d\n", fragsize);
312         return (grain << 16) | fragsize;
313 }
314
315 int AudioOSS::get_fmt(int bits)
316 {
317         switch(bits) {
318         case 32: return AFMT_S32_LE; break;
319         case 16: return AFMT_S16_LE; break;
320         case 8:  return AFMT_S8;  break;
321         }
322         return AFMT_S16_LE;
323 }
324
325
326 int AudioOSS::close_all()
327 {
328 //printf("AudioOSS::close_all 1\n");
329         for(int i = 0; i < MAXDEVICES; i++) {
330                 if(dsp_in[i] >= 0) {
331                         ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);
332                         close(dsp_in[i]);
333                         dsp_in[i] = -1;
334                 }
335
336                 if(dsp_out[i] >= 0) {
337 //printf("AudioOSS::close_all 2\n");
338                         ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);
339                         close(dsp_out[i]);
340                         dsp_out[i] = -1;
341                 }
342
343                 if(thread[i]) delete thread[i];
344                 if(data[i]) delete [] data[i];
345         }
346         return 0;
347 }
348
349 int AudioOSS::set_cloexec_flag(int desc, int value)
350 {
351         int oldflags = fcntl (desc, F_GETFD, 0);
352         if (oldflags < 0) return oldflags;
353         if(value != 0)
354                 oldflags |= FD_CLOEXEC;
355         else
356                 oldflags &= ~FD_CLOEXEC;
357         return fcntl(desc, F_SETFD, oldflags);
358 }
359
360 int64_t AudioOSS::device_position()
361 {
362         for (int i = 0; i < MAXDEVICES; i++) {
363                 if( thread[i] ) {
364                         int frame_size = device->get_ochannels() * device->get_obits()/8;
365                         int64_t pos = thread[i]->device_position() / frame_size;
366                         int64_t tmr = thread[i]->timer->get_scaled_difference(device->out_samplerate);
367                         return pos + tmr;
368                 }
369         }
370         count_info info;
371         if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
372         {
373 //printf("AudioOSS::device_position %d %d %d\n", info.bytes, device->get_obits(), device->get_ochannels());
374 // workaround for ALSA OSS emulation driver's bug
375 // the problem is that if the first write to sound device was not full lenght fragment then
376 // _GETOPTR returns insanely large numbers at first moments of play
377                 if (info.bytes > 2100000000) return 0;
378                 int frame_size = device->get_ochannels() * device->get_obits()/8;
379                 return info.bytes / frame_size;
380         }
381         return 0;
382 }
383
384 int AudioOSS::interrupt_playback()
385 {
386 //printf("AudioOSS::interrupt_playback 1\n");
387         for(int i = 0; i < MAXDEVICES; i++) {
388                 if(thread[i]) {
389                         thread[i]->done = 1;
390                         thread[i]->input_lock->unlock();
391                         thread[i]->write_lock->unlock();
392                         thread[i]->cancel();
393                 }
394         }
395 //printf("AudioOSS::interrupt_playback 100\n");
396         return 0;
397 }
398
399 int64_t AudioOSS::samples_output()
400 {
401         for( int i=0; i<MAXDEVICES; ++i ) {
402                 if( thread[i] ) {
403                         int frame_size = device->get_ochannels() * device->get_obits()/8;
404                         return thread[i]->bytes_written / frame_size;
405                 }
406         }
407         return 0;
408 }
409
410 int AudioOSS::read_buffer(char *buffer, int bytes)
411 {
412         int sample_size = device->get_ibits() / 8;
413         int out_frame_size = device->get_ichannels() * sample_size;
414         int samples = bytes / out_frame_size;
415
416 //printf("AudioOSS::read_buffer 1 %d\n", bytes);
417 // Fill temp buffers
418         for(int i = 0; i < MAXDEVICES; i++) {
419                 if(thread[i]) {
420                         int in_frame_size = device->get_ichannels() * sample_size;
421
422                         if(data[i] && data_allocated[i] < bytes) {
423                                 delete [] data[i];
424                                 data[i] = 0;
425                         }
426                         if(!data[i]) {
427                                 data[i] = new unsigned char[bytes];
428                                 data_allocated[i] = bytes;
429                         }
430
431                         thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
432                 }
433         }
434
435 //printf("AudioOSS::read_buffer 1 %d\n", device->get_ibits());
436         for(int i = 0, out_channel = 0; i < MAXDEVICES; i++) {
437                 if(thread[i]) {
438                         thread[i]->wait_read();
439
440                         for(int in_channel = 0;
441                                 in_channel < device->get_ichannels();
442                                 in_channel++) {
443                                 int in_frame_size = device->get_ichannels() * sample_size;
444
445                                 for(int k = 0; k < samples; k++) {
446                                         for(int l = 0;
447                                                 l < sample_size;
448                                                 l++) {
449                                                 buffer[out_channel * sample_size + k * out_frame_size + l] =
450                                                         data[i][in_channel * sample_size + k * in_frame_size + l];
451                                         }
452                                 }
453                                 out_channel++;
454                         }
455                 }
456         }
457 //printf("AudioOSS::read_buffer 2\n");
458         return 0;
459 }
460
461 int AudioOSS::write_buffer(char *buffer, int bytes)
462 {
463         int sample_size = device->get_obits() / 8;
464         int in_frame_size = device->get_ochannels() * sample_size;
465         int samples = bytes / in_frame_size;
466
467         for(int i = 0, in_channel = 0; i < MAXDEVICES; i++) {
468                 if( thread[i] ) {
469                         int out_frame_size = device->get_ochannels() * sample_size;
470                         if(data[i] && data_allocated[i] < bytes) {
471                                 delete [] data[i];
472                                 data[i] = 0;
473                         }
474                         if(!data[i]) {
475                                 data[i] = new unsigned char[bytes];
476                                 data_allocated[i] = bytes;
477                         }
478
479                         for(int out_channel = 0;
480                                 out_channel < device->get_ochannels();
481                                 out_channel++) {
482
483                                 for(int k = 0; k < samples; k++) {
484                                         for(int l = 0; l < sample_size; l++) {
485                                                 data[i][out_channel * sample_size + k * out_frame_size + l] =
486                                                         buffer[in_channel * sample_size + k * in_frame_size + l];
487                                         }
488                                 }
489                                 in_channel++;
490                         }
491
492                         thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
493                 }
494         }
495         for(int i = 0; i < MAXDEVICES; i++) {
496                 if( thread[i] ) thread[i]->wait_write();
497         }
498         return 0;
499 }
500
501 int AudioOSS::flush_device()
502 {
503         for(int i = 0; i < MAXDEVICES; i++)
504                 if(thread[i]) ioctl(get_output(i), SNDCTL_DSP_SYNC, 0);
505         return 0;
506 }
507
508 int AudioOSS::get_output(int number)
509 {
510         return device->w ? dsp_out[number] : -1;
511 }
512
513 int AudioOSS::get_input(int number)
514 {
515         return device->r ? dsp_in[number] : -1;
516 }
517
518 #endif // HAVE_OSS