r689: Fixed that changes made by dragging a control would often store each
[cinelerra_cv.git] / cinelerra / audiooss.C
blobb4aeb961270add0ef44989f7f20f985bb2306eda
1 #include "audioconfig.h"
2 #include "audiodevice.h"
3 #include "audiooss.h"
4 #include "clip.h"
5 #include "condition.h"
6 #include "errno.h"
7 #include "playbackconfig.h"
8 #include "preferences.h"
9 #include "recordconfig.h"
11 #include <string.h>
13 #ifdef HAVE_OSS
15 // These are only available in commercial OSS
17 #ifndef AFMT_S32_LE
18 #define AFMT_S32_LE      0x00001000
19 #define AFMT_S32_BE      0x00002000
20 #endif
23 // Synchronie multiple devices by using threads
25 OSSThread::OSSThread(AudioOSS *device)
26  : Thread(1, 0, 0)
28         rd = 0;
29         wr = 0;
30         done = 0;
31         this->device = device;
32         input_lock = new Condition(0, "OSSThread::input_lock");
33         output_lock = new Condition(1, "OSSThread::output_lock");
34         read_lock = new Condition(0, "OSSThread::read_lock");
35         write_lock = new Condition(0, "OSSThread::write_lock");
38 OSSThread::~OSSThread()
40         done = 1;
41         input_lock->unlock();
42         Thread::join();
43         delete input_lock;
44         delete output_lock;
45         delete read_lock;
46         delete write_lock;
49 void OSSThread::run()
51         while(!done)
52         {
53                 input_lock->lock("OSSThread::run 1");
54                 if(rd)
55                 {
56                         int result = read(fd, data, bytes);
57                         read_lock->unlock();
58                 }
59                 else
60                 if(wr)
61                 {
62                         if(done) return;
65                         Thread::enable_cancel();
66                         write(fd, data, bytes);
67                         Thread::disable_cancel();
70                         if(done) return;
71                         write_lock->unlock();
72                 }
73                 output_lock->unlock();
74         }
77 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
79         output_lock->lock("OSSThread::write_data");
80         wr = 1;
81         rd = 0;
82         this->data = data;
83         this->bytes = bytes;
84         this->fd = fd;
85         input_lock->unlock();
88 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
90         output_lock->lock("OSSThread::read_data");
91         wr = 0;
92         rd = 1;
93         this->data = data;
94         this->bytes = bytes;
95         this->fd = fd;
96         input_lock->unlock();
99 void OSSThread::wait_read()
101         read_lock->lock("OSSThread::wait_read");
104 void OSSThread::wait_write()
106         write_lock->lock("OSSThread::wait_write");
119 AudioOSS::AudioOSS(AudioDevice *device)
120  : AudioLowLevel(device)
122         for(int i = 0; i < MAXDEVICES; i++)
123         {
124                 dsp_in[i] = dsp_out[i] = dsp_duplex[i] = 0;
125                 thread[i] = 0;
126                 data[i] = 0;
127                 data_allocated[i] = 0;
128         }
131 AudioOSS::~AudioOSS()
135 int AudioOSS::open_input()
137         device->in_channels = 0;
138         for(int i = 0; i < MAXDEVICES; i++)
139         {
140                 if(device->in_config->oss_enable[i])
141                         device->in_channels += device->in_config->oss_in_channels[i];
142         }
143         device->in_bits = device->in_config->oss_in_bits;
144 // 24 bits not available in OSS
145         if(device->in_bits == 24) device->in_bits = 32;
147         for(int i = 0; i < MAXDEVICES; i++)
148         {
149                 if(device->in_config->oss_enable[i])
150                 {
151 //printf("AudioOSS::open_input 10\n");
152                         dsp_in[i] = open(device->in_config->oss_in_device[i], O_RDONLY/* | O_NDELAY*/);
153 //printf("AudioOSS::open_input 20\n");
154                         if(dsp_in[i] < 0) fprintf(stderr, "AudioOSS::open_input %s: %s\n", 
155                                 device->in_config->oss_in_device[i], 
156                                 strerror(errno));
158                         int format = get_fmt(device->in_config->oss_in_bits);
159                         int buffer_info = sizetofrag(device->in_samples, 
160                                 device->in_config->oss_in_channels[i], 
161                                 device->in_config->oss_in_bits);
163                         set_cloexec_flag(dsp_in[i], 1);
165 //printf("AudioOSS::open_input %d %d %d\n", device->in_samples, device->in_config->oss_in_channels[i], device->in_config->oss_in_bits);
166 // For the ice1712 the buffer must be maximum or no space will be allocated.
167                         if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
168                         if(ioctl(dsp_in[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
169                         if(ioctl(dsp_in[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
170                         if(ioctl(dsp_in[i], SNDCTL_DSP_CHANNELS, &device->in_config->oss_in_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
171                         if(ioctl(dsp_in[i], SNDCTL_DSP_SPEED, &device->in_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
173                         audio_buf_info recinfo;
174                         ioctl(dsp_in[i], SNDCTL_DSP_GETISPACE, &recinfo);
176 //printf("AudioOSS::open_input fragments=%d fragstotal=%d fragsize=%d bytes=%d\n", 
177 //      recinfo.fragments, recinfo.fragstotal, recinfo.fragsize, recinfo.bytes);
179                         thread[i] = new OSSThread(this);
180                         thread[i]->start();
181                 }
182         }
183         return 0;
186 int AudioOSS::open_output()
188 //printf("AudioOSS::open_output 1\n");
189         device->out_channels = 0;
190         
191         for(int i = 0; i < MAXDEVICES; i++)
192         {
193                 if(device->out_config->oss_enable[i])
194                         device->out_channels += device->out_config->oss_out_channels[i];
195         }
196         device->out_bits = device->out_config->oss_out_bits;
197 // OSS only supports 8, 16, and 32
198         if(device->out_bits == 24) device->out_bits = 32;
200         for(int i = 0; i < MAXDEVICES; i++)
201         {
202                 if(device->out_config->oss_enable[i])
203                 {
204 // Linux 2.4.18 no longer supports allocating the maximum buffer size.
205 // Need the shrink fragment size in preferences until it works.
206                         dsp_out[i] = 
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->out_config->oss_out_channels[i], 
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->driver == 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                         if(ioctl(dsp_out[i], SNDCTL_DSP_CHANNELS, &device->out_config->oss_out_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS 2 failed\n");
224                         if(ioctl(dsp_out[i], SNDCTL_DSP_SPEED, &device->out_samplerate) < 0) printf("SNDCTL_DSP_SPEED 2 failed\n");
225                         ioctl(dsp_out[i], SNDCTL_DSP_GETOSPACE, &playinfo);
226 // printf("AudioOSS::open_output fragments=%d fragstotal=%d fragsize=%d bytes=%d\n", 
227 // playinfo.fragments, playinfo.fragstotal, playinfo.fragsize, playinfo.bytes);
228                         device->device_buffer = playinfo.bytes;
229                         thread[i] = new OSSThread(this);
230                         thread[i]->start();
231                 }
232         }
233         return 0;
236 int AudioOSS::open_duplex()
238         device->duplex_channels = 0;
239         for(int i = 0; i < MAXDEVICES; i++)
240         {
241                 if(device->out_config->oss_enable[i])
242                         device->duplex_channels += device->out_config->oss_out_channels[i];
243         }
244         device->duplex_bits = device->out_config->oss_out_bits;
245         if(device->duplex_bits == 24) device->duplex_bits = 32;
247         for(int i = 0; i < MAXDEVICES; i++)
248         {
249                 if(device->out_config->oss_enable[i])
250                 {
251                         dsp_duplex[i] = open(device->out_config->oss_out_device[i], O_RDWR/* | O_NDELAY*/);
252                         if(dsp_duplex[i] < 0) perror("AudioOSS::open_duplex");
254                         int format = get_fmt(device->out_config->oss_out_bits);
255                         int buffer_info = sizetofrag(device->duplex_samples, 
256                                 device->out_config->oss_out_channels[i], 
257                                 device->out_config->oss_out_bits);
258                         audio_buf_info playinfo;
260                         set_cloexec_flag(dsp_duplex[i], 1);
262 // For the ice1712 the buffer must be maximum or no space will be allocated.
263                         if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
264                         if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
265                         if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETDUPLEX, 1) == -1) printf("SNDCTL_DSP_SETDUPLEX failed\n");
266                         if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
267                         if(ioctl(dsp_duplex[i], SNDCTL_DSP_CHANNELS, &device->out_config->oss_out_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
268                         if(ioctl(dsp_duplex[i], SNDCTL_DSP_SPEED, &device->duplex_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
269                         ioctl(dsp_duplex[i], SNDCTL_DSP_GETOSPACE, &playinfo);
270                         device->device_buffer = playinfo.bytes;
271                         thread[i] = new OSSThread(this);
272                         thread[i]->start();
273                 }
274         }
275         return 0;
278 int AudioOSS::sizetofrag(int samples, int channels, int bits)
280         int testfrag = 2, fragsize = 1;
281         samples *= channels * bits / 8;
282         while(testfrag < samples)
283         {
284                 fragsize++;
285                 testfrag *= 2;
286         }
287 //printf("AudioOSS::sizetofrag %d\n", fragsize);
288         return (4 << 16) | fragsize;
291 int AudioOSS::get_fmt(int bits)
293         switch(bits)
294         {
295                 case 32: return AFMT_S32_LE; break;
296                 case 16: return AFMT_S16_LE; break;
297                 case 8:  return AFMT_S8;  break;
298         }
299         return AFMT_S16_LE;
303 int AudioOSS::close_all()
305 //printf("AudioOSS::close_all 1\n");
306         for(int i = 0; i < MAXDEVICES; i++)
307         {
308                 if(dsp_in[i]) 
309                 {
310                         ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);         
311                         close(dsp_in[i]);      
312                 }
314                 if(dsp_out[i]) 
315                 {
316 //printf("AudioOSS::close_all 2\n");
317                         ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);        
318                         close(dsp_out[i]);     
319                 }
321                 if(dsp_duplex[i]) 
322                 {
323                         ioctl(dsp_duplex[i], SNDCTL_DSP_RESET, 0);     
324                         close(dsp_duplex[i]);  
325                 }
326                 
327                 if(thread[i]) delete thread[i];
328                 if(data[i]) delete [] data[i];
329         }
330         return 0;
333 int AudioOSS::set_cloexec_flag(int desc, int value)
335         int oldflags = fcntl (desc, F_GETFD, 0);
336         if (oldflags < 0) return oldflags;
337         if(value != 0) 
338                 oldflags |= FD_CLOEXEC;
339         else
340                 oldflags &= ~FD_CLOEXEC;
341         return fcntl(desc, F_SETFD, oldflags);
344 int64_t AudioOSS::device_position()
346         count_info info;
347         if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
348         {
349 //printf("AudioOSS::device_position %d %d %d\n", info.bytes, device->get_obits(), device->get_ochannels());
350 // workaround for ALSA OSS emulation driver's bug
351 // the problem is that if the first write to sound device was not full lenght fragment then 
352 // _GETOPTR returns insanely large numbers at first moments of play
353                 if (info.bytes > 2100000000) 
354                         return 0;
355                 else
356                         return info.bytes / 
357                                 (device->get_obits() / 8) / 
358                                 device->get_ochannels();
359         }
360         return 0;
363 int AudioOSS::interrupt_playback()
365 //printf("AudioOSS::interrupt_playback 1\n");
366         for(int i = 0; i < MAXDEVICES; i++)
367         {
368                 if(thread[i])
369                 {
370                         thread[i]->cancel();
371                         thread[i]->write_lock->unlock();
372                 }
373         }
374 //printf("AudioOSS::interrupt_playback 100\n");
375         return 0;
378 int AudioOSS::read_buffer(char *buffer, int bytes)
380         int sample_size = device->get_ibits() / 8;
381         int out_frame_size = device->get_ichannels() * sample_size;
382         int samples = bytes / out_frame_size;
384 //printf("AudioOSS::read_buffer 1 %d\n", bytes);
385 // Fill temp buffers
386         for(int i = 0; i < MAXDEVICES; i++)
387         {
388                 if(thread[i])
389                 {
390                         int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
392                         if(data[i] && data_allocated[i] < bytes)
393                         {
394                                 delete [] data[i];
395                                 data[i] = 0;
396                         }
397                         if(!data[i])
398                         {
399                                 data[i] = new unsigned char[bytes];
400                                 data_allocated[i] = bytes;
401                         }
403                         thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
404                 }
405         }
407 //printf("AudioOSS::read_buffer 1 %d\n", device->get_ibits());
408         for(int i = 0, out_channel = 0; i < MAXDEVICES; i++)
409         {
410                 if(thread[i])
411                 {
412                         thread[i]->wait_read();
414                         for(int in_channel = 0; 
415                                 in_channel < device->in_config->oss_in_channels[i]; 
416                                 in_channel++)
417                         {
418                                 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
420                                 for(int k = 0; k < samples; k++)
421                                 {
422                                         for(int l = 0; 
423                                                 l < sample_size;
424                                                 l++)
425                                         {
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;
438 int AudioOSS::write_buffer(char *buffer, int bytes)
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;
444         for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
445         {
446                 if(thread[i])
447                 {
448                         int out_frame_size = device->out_config->oss_out_channels[i] * sample_size;
449                         if(data[i] && data_allocated[i] < bytes)
450                         {
451                                 delete [] data[i];
452                                 data[i] = 0;
453                         }
454                         if(!data[i])
455                         {
456                                 data[i] = new unsigned char[bytes];
457                                 data_allocated[i] = bytes;
458                         }
459                         
460                         for(int out_channel = 0;
461                                 out_channel < device->out_config->oss_out_channels[i];
462                                 out_channel++)
463                         {
464                                 
465                                 for(int k = 0; k < samples; k++)
466                                 {
467                                         for(int l = 0; l < sample_size; l++)
468                                         {
469                                                 data[i][out_channel * sample_size + k * out_frame_size + l] = 
470                                                         buffer[in_channel * sample_size + k * in_frame_size + l];
471                                         }
472                                 }
473                                 in_channel++;
474                         }
475                         
476                         thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
477                 }
478         }
479         for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
480         {
481                 if(thread[i])
482                 {
483                         thread[i]->wait_write();
484                 }
485         }
486         return 0;
489 int AudioOSS::flush_device()
491         for(int i = 0; i < MAXDEVICES; i++)
492                 if(thread[i]) ioctl(get_output(i), SNDCTL_DSP_SYNC, 0);
493         return 0;
496 int AudioOSS::get_output(int number)
498         if(device->w) return dsp_out[number];
499         else if(device->d) return dsp_duplex[number];
500         return 0;
503 int AudioOSS::get_input(int number)
505         if(device->r) return dsp_in[number];
506         else if(device->d) return dsp_duplex[number];
507         return 0;
510 #endif // HAVE_OSS