1 #include "audioconfig.h"
2 #include "audiodevice.h"
7 #include "playbackconfig.h"
8 #include "preferences.h"
9 #include "recordconfig.h"
15 // These are only available in commercial OSS
18 #define AFMT_S32_LE 0x00001000
19 #define AFMT_S32_BE 0x00002000
23 // Synchronie multiple devices by using threads
25 OSSThread::OSSThread(AudioOSS *device)
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()
53 input_lock->lock("OSSThread::run 1");
56 int result = read(fd, data, bytes);
65 Thread::enable_cancel();
66 write(fd, data, bytes);
67 Thread::disable_cancel();
73 output_lock->unlock();
77 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
79 output_lock->lock("OSSThread::write_data");
88 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
90 output_lock->lock("OSSThread::read_data");
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++)
124 dsp_in[i] = dsp_out[i] = dsp_duplex[i] = 0;
127 data_allocated[i] = 0;
131 AudioOSS::~AudioOSS()
135 int AudioOSS::open_input()
137 device->in_channels = 0;
138 for(int i = 0; i < MAXDEVICES; i++)
140 if(device->in_config->oss_enable[i])
141 device->in_channels += device->in_config->oss_in_channels[i];
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++)
149 if(device->in_config->oss_enable[i])
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],
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);
186 int AudioOSS::open_output()
188 //printf("AudioOSS::open_output 1\n");
189 device->out_channels = 0;
191 for(int i = 0; i < MAXDEVICES; i++)
193 if(device->out_config->oss_enable[i])
194 device->out_channels += device->out_config->oss_out_channels[i];
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++)
202 if(device->out_config->oss_enable[i])
204 // Linux 2.4.18 no longer supports allocating the maximum buffer size.
205 // Need the shrink fragment size in preferences until it works.
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);
236 int AudioOSS::open_duplex()
238 device->duplex_channels = 0;
239 for(int i = 0; i < MAXDEVICES; i++)
241 if(device->out_config->oss_enable[i])
242 device->duplex_channels += device->out_config->oss_out_channels[i];
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++)
249 if(device->out_config->oss_enable[i])
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);
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)
287 //printf("AudioOSS::sizetofrag %d\n", fragsize);
288 return (4 << 16) | fragsize;
291 int AudioOSS::get_fmt(int bits)
295 case 32: return AFMT_S32_LE; break;
296 case 16: return AFMT_S16_LE; break;
297 case 8: return AFMT_S8; break;
303 int AudioOSS::close_all()
305 //printf("AudioOSS::close_all 1\n");
306 for(int i = 0; i < MAXDEVICES; i++)
310 ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);
316 //printf("AudioOSS::close_all 2\n");
317 ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);
323 ioctl(dsp_duplex[i], SNDCTL_DSP_RESET, 0);
324 close(dsp_duplex[i]);
327 if(thread[i]) delete thread[i];
328 if(data[i]) delete [] data[i];
333 int AudioOSS::set_cloexec_flag(int desc, int value)
335 int oldflags = fcntl (desc, F_GETFD, 0);
336 if (oldflags < 0) return oldflags;
338 oldflags |= FD_CLOEXEC;
340 oldflags &= ~FD_CLOEXEC;
341 return fcntl(desc, F_SETFD, oldflags);
344 int64_t AudioOSS::device_position()
347 if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
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)
357 (device->get_obits() / 8) /
358 device->get_ochannels();
363 int AudioOSS::interrupt_playback()
365 //printf("AudioOSS::interrupt_playback 1\n");
366 for(int i = 0; i < MAXDEVICES; i++)
371 thread[i]->write_lock->unlock();
374 //printf("AudioOSS::interrupt_playback 100\n");
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);
386 for(int i = 0; i < MAXDEVICES; i++)
390 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
392 if(data[i] && data_allocated[i] < bytes)
399 data[i] = new unsigned char[bytes];
400 data_allocated[i] = bytes;
403 thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
407 //printf("AudioOSS::read_buffer 1 %d\n", device->get_ibits());
408 for(int i = 0, out_channel = 0; i < MAXDEVICES; i++)
412 thread[i]->wait_read();
414 for(int in_channel = 0;
415 in_channel < device->in_config->oss_in_channels[i];
418 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
420 for(int k = 0; k < samples; k++)
426 buffer[out_channel * sample_size + k * out_frame_size + l] =
427 data[i][in_channel * sample_size + k * in_frame_size + l];
434 //printf("AudioOSS::read_buffer 2\n");
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++)
448 int out_frame_size = device->out_config->oss_out_channels[i] * sample_size;
449 if(data[i] && data_allocated[i] < bytes)
456 data[i] = new unsigned char[bytes];
457 data_allocated[i] = bytes;
460 for(int out_channel = 0;
461 out_channel < device->out_config->oss_out_channels[i];
465 for(int k = 0; k < samples; k++)
467 for(int l = 0; l < sample_size; l++)
469 data[i][out_channel * sample_size + k * out_frame_size + l] =
470 buffer[in_channel * sample_size + k * in_frame_size + l];
476 thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
479 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
483 thread[i]->wait_write();
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);
496 int AudioOSS::get_output(int number)
498 if(device->w) return dsp_out[number];
499 else if(device->d) return dsp_duplex[number];
503 int AudioOSS::get_input(int number)
505 if(device->r) return dsp_in[number];
506 else if(device->d) return dsp_duplex[number];