1 #include "audioconfig.h"
2 #include "audiodevice.h"
6 #include "playbackconfig.h"
7 #include "preferences.h"
8 #include "recordconfig.h"
14 // These are only available in commercial OSS
17 #define AFMT_S32_LE 0x00001000
18 #define AFMT_S32_BE 0x00002000
22 // Synchronie multiple devices by using threads
24 OSSThread::OSSThread(AudioOSS *device)
30 this->device = device;
34 OSSThread::~OSSThread()
48 int result = read(fd, data, bytes);
54 //fwrite(data, bytes, 1, stdout);
55 //printf("OSSThread::run %d %d\n", bytes, device->device->get_device_buffer());
57 //printf("OSSThread::run 1\n");
58 Thread::enable_cancel();
59 write(fd, data, bytes);
60 Thread::disable_cancel();
61 //printf("OSSThread::run 10\n");
69 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
81 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
93 void OSSThread::wait_read()
99 void OSSThread::wait_write()
115 AudioOSS::AudioOSS(AudioDevice *device)
116 : AudioLowLevel(device)
118 for(int i = 0; i < MAXDEVICES; i++)
120 dsp_in[i] = dsp_out[i] = dsp_duplex[i] = 0;
123 data_allocated[i] = 0;
127 AudioOSS::~AudioOSS()
131 int AudioOSS::open_input()
133 device->in_channels = 0;
134 for(int i = 0; i < MAXDEVICES; i++)
136 if(device->in_config->oss_enable[i])
137 device->in_channels += device->in_config->oss_in_channels[i];
139 device->in_bits = device->in_config->oss_in_bits;
140 // 24 bits not available in OSS
141 if(device->in_bits == 24) device->in_bits = 32;
143 for(int i = 0; i < MAXDEVICES; i++)
145 if(device->in_config->oss_enable[i])
147 dsp_in[i] = open(device->in_config->oss_in_device[i], O_RDONLY/* | O_NDELAY*/);
148 if(dsp_in[i] < 0) fprintf(stderr, "AudioOSS::open_input %s: %s\n",
149 device->in_config->oss_in_device[i],
152 int format = get_fmt(device->in_config->oss_in_bits);
153 int buffer_info = sizetofrag(device->in_samples,
154 device->in_config->oss_in_channels[i],
155 device->in_config->oss_in_bits);
157 set_cloexec_flag(dsp_in[i], 1);
159 //printf("AudioOSS::open_input %d %d %d\n", device->in_samples, device->in_config->oss_in_channels[i], device->in_config->oss_in_bits);
160 // For the ice1712 the buffer must be maximum or no space will be allocated.
161 if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
162 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
163 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
164 if(ioctl(dsp_in[i], SNDCTL_DSP_CHANNELS, &device->in_config->oss_in_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
165 if(ioctl(dsp_in[i], SNDCTL_DSP_SPEED, &device->in_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
167 audio_buf_info recinfo;
168 ioctl(dsp_in[i], SNDCTL_DSP_GETISPACE, &recinfo);
170 //printf("AudioOSS::open_input fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
171 // recinfo.fragments, recinfo.fragstotal, recinfo.fragsize, recinfo.bytes);
173 thread[i] = new OSSThread(this);
180 int AudioOSS::open_output()
182 //printf("AudioOSS::open_output 1\n");
183 device->out_channels = 0;
185 for(int i = 0; i < MAXDEVICES; i++)
187 if(device->out_config->oss_enable[i])
188 device->out_channels += device->out_config->oss_out_channels[i];
190 device->out_bits = device->out_config->oss_out_bits;
191 // OSS only supports 8, 16, and 32
192 if(device->out_bits == 24) device->out_bits = 32;
194 for(int i = 0; i < MAXDEVICES; i++)
196 if(device->out_config->oss_enable[i])
198 // Linux 2.4.18 no longer supports allocating the maximum buffer size.
199 // Need the shrink fragment size in preferences until it works.
201 open(device->out_config->oss_out_device[i],
202 O_WRONLY /*| O_NDELAY*/);
203 if(dsp_out[i] < 0) perror("AudioOSS::open_output");
205 int format = get_fmt(device->out_config->oss_out_bits);
206 int buffer_info = sizetofrag(device->out_samples,
207 device->out_config->oss_out_channels[i],
208 device->out_config->oss_out_bits);
209 audio_buf_info playinfo;
211 set_cloexec_flag(dsp_out[i], 1);
213 // For the ice1712 the buffer must be maximum or no space will be allocated.
214 if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
215 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT 2 failed.\n");
216 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT 2 failed\n");
217 if(ioctl(dsp_out[i], SNDCTL_DSP_CHANNELS, &device->out_config->oss_out_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS 2 failed\n");
218 if(ioctl(dsp_out[i], SNDCTL_DSP_SPEED, &device->out_samplerate) < 0) printf("SNDCTL_DSP_SPEED 2 failed\n");
219 ioctl(dsp_out[i], SNDCTL_DSP_GETOSPACE, &playinfo);
220 // printf("AudioOSS::open_output fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
221 // playinfo.fragments, playinfo.fragstotal, playinfo.fragsize, playinfo.bytes);
222 device->device_buffer = playinfo.bytes;
223 thread[i] = new OSSThread(this);
230 int AudioOSS::open_duplex()
232 device->duplex_channels = 0;
233 for(int i = 0; i < MAXDEVICES; i++)
235 if(device->out_config->oss_enable[i])
236 device->duplex_channels += device->out_config->oss_out_channels[i];
238 device->duplex_bits = device->out_config->oss_out_bits;
239 if(device->duplex_bits == 24) device->duplex_bits = 32;
241 for(int i = 0; i < MAXDEVICES; i++)
243 if(device->out_config->oss_enable[i])
245 dsp_duplex[i] = open(device->out_config->oss_out_device[i], O_RDWR/* | O_NDELAY*/);
246 if(dsp_duplex[i] < 0) perror("AudioOSS::open_duplex");
248 int format = get_fmt(device->out_config->oss_out_bits);
249 int buffer_info = sizetofrag(device->duplex_samples,
250 device->out_config->oss_out_channels[i],
251 device->out_config->oss_out_bits);
252 audio_buf_info playinfo;
254 set_cloexec_flag(dsp_duplex[i], 1);
256 // For the ice1712 the buffer must be maximum or no space will be allocated.
257 if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
258 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
259 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETDUPLEX, 1) == -1) printf("SNDCTL_DSP_SETDUPLEX failed\n");
260 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
261 if(ioctl(dsp_duplex[i], SNDCTL_DSP_CHANNELS, &device->out_config->oss_out_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
262 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SPEED, &device->duplex_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
263 ioctl(dsp_duplex[i], SNDCTL_DSP_GETOSPACE, &playinfo);
264 device->device_buffer = playinfo.bytes;
265 thread[i] = new OSSThread(this);
272 int AudioOSS::sizetofrag(int samples, int channels, int bits)
274 int testfrag = 2, fragsize = 1;
275 samples *= channels * bits / 8;
276 while(testfrag < samples)
281 //printf("AudioOSS::sizetofrag %d\n", fragsize);
282 return (4 << 16) | fragsize;
285 int AudioOSS::get_fmt(int bits)
289 case 32: return AFMT_S32_LE; break;
290 case 16: return AFMT_S16_LE; break;
291 case 8: return AFMT_S8; break;
297 int AudioOSS::close_all()
299 //printf("AudioOSS::close_all 1\n");
300 for(int i = 0; i < MAXDEVICES; i++)
304 ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);
310 //printf("AudioOSS::close_all 2\n");
311 ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);
317 ioctl(dsp_duplex[i], SNDCTL_DSP_RESET, 0);
318 close(dsp_duplex[i]);
321 if(thread[i]) delete thread[i];
322 if(data[i]) delete data[i];
327 int AudioOSS::set_cloexec_flag(int desc, int value)
329 int oldflags = fcntl (desc, F_GETFD, 0);
330 if (oldflags < 0) return oldflags;
332 oldflags |= FD_CLOEXEC;
334 oldflags &= ~FD_CLOEXEC;
335 return fcntl(desc, F_SETFD, oldflags);
338 int64_t AudioOSS::device_position()
341 if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
343 //printf("AudioOSS::device_position %d %d %d\n", info.bytes, device->get_obits(), device->get_ochannels());
345 (device->get_obits() / 8) /
346 device->get_ochannels();
351 int AudioOSS::interrupt_playback()
353 //printf("AudioOSS::interrupt_playback 1\n");
354 for(int i = 0; i < MAXDEVICES; i++)
359 thread[i]->write_lock.unlock();
362 //printf("AudioOSS::interrupt_playback 100\n");
366 int AudioOSS::read_buffer(char *buffer, int bytes)
368 int sample_size = device->get_ibits() / 8;
369 int out_frame_size = device->get_ichannels() * sample_size;
370 int samples = bytes / out_frame_size;
372 //printf("AudioOSS::read_buffer 1 %d\n", bytes);
374 for(int i = 0; i < MAXDEVICES; i++)
378 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
380 if(data[i] && data_allocated[i] < bytes)
387 data[i] = new unsigned char[bytes];
388 data_allocated[i] = bytes;
391 thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
395 //printf("AudioOSS::read_buffer 1 %d\n", device->get_ibits());
396 for(int i = 0, out_channel = 0; i < MAXDEVICES; i++)
400 thread[i]->wait_read();
402 for(int in_channel = 0;
403 in_channel < device->in_config->oss_in_channels[i];
406 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
408 for(int k = 0; k < samples; k++)
414 buffer[out_channel * sample_size + k * out_frame_size + l] =
415 data[i][in_channel * sample_size + k * in_frame_size + l];
422 //printf("AudioOSS::read_buffer 2\n");
426 int AudioOSS::write_buffer(char *buffer, int bytes)
428 int sample_size = device->get_obits() / 8;
429 int in_frame_size = device->get_ochannels() * sample_size;
430 int samples = bytes / in_frame_size;
432 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
436 int out_frame_size = device->out_config->oss_out_channels[i] * sample_size;
437 if(data[i] && data_allocated[i] < bytes)
444 data[i] = new unsigned char[bytes];
445 data_allocated[i] = bytes;
448 for(int out_channel = 0;
449 out_channel < device->out_config->oss_out_channels[i];
453 for(int k = 0; k < samples; k++)
455 for(int l = 0; l < sample_size; l++)
457 data[i][out_channel * sample_size + k * out_frame_size + l] =
458 buffer[in_channel * sample_size + k * in_frame_size + l];
464 thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
467 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
471 thread[i]->wait_write();
477 int AudioOSS::flush_device(int number)
479 printf("AudioOSS::flush_device 1 %d\n", number);
480 ioctl(get_output(number), SNDCTL_DSP_SYNC, 0);
484 int AudioOSS::get_output(int number)
486 if(device->w) return dsp_out[number];
487 else if(device->d) return dsp_duplex[number];
491 int AudioOSS::get_input(int number)
493 if(device->r) return dsp_in[number];
494 else if(device->d) return dsp_duplex[number];