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