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