00001 #include "audioconfig.h"
00002 #include "audiodevice.h"
00003 #include "audiooss.h"
00004 #include "clip.h"
00005 #include "condition.h"
00006 #include "errno.h"
00007 #include "playbackconfig.h"
00008 #include "preferences.h"
00009 #include "recordconfig.h"
00010
00011 #include <string.h>
00012
00013 #ifdef HAVE_OSS
00014
00015
00016
00017 #ifndef AFMT_S32_LE
00018 #define AFMT_S32_LE 0x00001000
00019 #define AFMT_S32_BE 0x00002000
00020 #endif
00021
00022
00023
00024
00025 OSSThread::OSSThread(AudioOSS *device)
00026 : Thread(1, 0, 0)
00027 {
00028 rd = 0;
00029 wr = 0;
00030 done = 0;
00031 this->device = device;
00032 input_lock = new Condition(0, "OSSThread::input_lock");
00033 output_lock = new Condition(1, "OSSThread::output_lock");
00034 read_lock = new Condition(0, "OSSThread::read_lock");
00035 write_lock = new Condition(0, "OSSThread::write_lock");
00036 }
00037
00038 OSSThread::~OSSThread()
00039 {
00040 done = 1;
00041 input_lock->unlock();
00042 Thread::join();
00043 delete input_lock;
00044 delete output_lock;
00045 delete read_lock;
00046 delete write_lock;
00047 }
00048
00049 void OSSThread::run()
00050 {
00051 while(!done)
00052 {
00053 input_lock->lock("OSSThread::run 1");
00054 if(rd)
00055 {
00056 int result = read(fd, data, bytes);
00057 read_lock->unlock();
00058 }
00059 else
00060 if(wr)
00061 {
00062 if(done) return;
00063
00064
00065 Thread::enable_cancel();
00066 write(fd, data, bytes);
00067 Thread::disable_cancel();
00068
00069
00070 if(done) return;
00071 write_lock->unlock();
00072 }
00073 output_lock->unlock();
00074 }
00075 }
00076
00077 void OSSThread::write_data(int fd, unsigned char *data, int bytes)
00078 {
00079 output_lock->lock("OSSThread::write_data");
00080 wr = 1;
00081 rd = 0;
00082 this->data = data;
00083 this->bytes = bytes;
00084 this->fd = fd;
00085 input_lock->unlock();
00086 }
00087
00088 void OSSThread::read_data(int fd, unsigned char *data, int bytes)
00089 {
00090 output_lock->lock("OSSThread::read_data");
00091 wr = 0;
00092 rd = 1;
00093 this->data = data;
00094 this->bytes = bytes;
00095 this->fd = fd;
00096 input_lock->unlock();
00097 }
00098
00099 void OSSThread::wait_read()
00100 {
00101 read_lock->lock("OSSThread::wait_read");
00102 }
00103
00104 void OSSThread::wait_write()
00105 {
00106 write_lock->lock("OSSThread::wait_write");
00107 }
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 AudioOSS::AudioOSS(AudioDevice *device)
00120 : AudioLowLevel(device)
00121 {
00122 for(int i = 0; i < MAXDEVICES; i++)
00123 {
00124 dsp_in[i] = dsp_out[i] = dsp_duplex[i] = 0;
00125 thread[i] = 0;
00126 data[i] = 0;
00127 data_allocated[i] = 0;
00128 }
00129 }
00130
00131 AudioOSS::~AudioOSS()
00132 {
00133 }
00134
00135 int AudioOSS::open_input()
00136 {
00137 device->in_channels = 0;
00138 for(int i = 0; i < MAXDEVICES; i++)
00139 {
00140 if(device->in_config->oss_enable[i])
00141 device->in_channels += device->in_config->oss_in_channels[i];
00142 }
00143 device->in_bits = device->in_config->oss_in_bits;
00144
00145 if(device->in_bits == 24) device->in_bits = 32;
00146
00147 for(int i = 0; i < MAXDEVICES; i++)
00148 {
00149 if(device->in_config->oss_enable[i])
00150 {
00151
00152 dsp_in[i] = open(device->in_config->oss_in_device[i], O_RDONLY);
00153
00154 if(dsp_in[i] < 0) fprintf(stderr, "AudioOSS::open_input %s: %s\n",
00155 device->in_config->oss_in_device[i],
00156 strerror(errno));
00157
00158 int format = get_fmt(device->in_config->oss_in_bits);
00159 int buffer_info = sizetofrag(device->in_samples,
00160 device->in_config->oss_in_channels[i],
00161 device->in_config->oss_in_bits);
00162
00163 set_cloexec_flag(dsp_in[i], 1);
00164
00165
00166
00167 if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
00168 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
00169 if(ioctl(dsp_in[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
00170 if(ioctl(dsp_in[i], SNDCTL_DSP_CHANNELS, &device->in_config->oss_in_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
00171 if(ioctl(dsp_in[i], SNDCTL_DSP_SPEED, &device->in_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
00172
00173 audio_buf_info recinfo;
00174 ioctl(dsp_in[i], SNDCTL_DSP_GETISPACE, &recinfo);
00175
00176
00177
00178
00179 thread[i] = new OSSThread(this);
00180 thread[i]->start();
00181 }
00182 }
00183 return 0;
00184 }
00185
00186 int AudioOSS::open_output()
00187 {
00188
00189 device->out_channels = 0;
00190
00191 for(int i = 0; i < MAXDEVICES; i++)
00192 {
00193 if(device->out_config->oss_enable[i])
00194 device->out_channels += device->out_config->oss_out_channels[i];
00195 }
00196 device->out_bits = device->out_config->oss_out_bits;
00197
00198 if(device->out_bits == 24) device->out_bits = 32;
00199
00200 for(int i = 0; i < MAXDEVICES; i++)
00201 {
00202 if(device->out_config->oss_enable[i])
00203 {
00204
00205
00206 dsp_out[i] =
00207 open(device->out_config->oss_out_device[i],
00208 O_WRONLY );
00209 if(dsp_out[i] < 0) perror("AudioOSS::open_output");
00210
00211 int format = get_fmt(device->out_config->oss_out_bits);
00212 int buffer_info = sizetofrag(device->out_samples,
00213 device->out_config->oss_out_channels[i],
00214 device->out_config->oss_out_bits);
00215 audio_buf_info playinfo;
00216
00217 set_cloexec_flag(dsp_out[i], 1);
00218
00219
00220 if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
00221 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT 2 failed.\n");
00222 if(ioctl(dsp_out[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT 2 failed\n");
00223 if(ioctl(dsp_out[i], SNDCTL_DSP_CHANNELS, &device->out_config->oss_out_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS 2 failed\n");
00224 if(ioctl(dsp_out[i], SNDCTL_DSP_SPEED, &device->out_samplerate) < 0) printf("SNDCTL_DSP_SPEED 2 failed\n");
00225 ioctl(dsp_out[i], SNDCTL_DSP_GETOSPACE, &playinfo);
00226
00227
00228 device->device_buffer = playinfo.bytes;
00229 thread[i] = new OSSThread(this);
00230 thread[i]->start();
00231 }
00232 }
00233 return 0;
00234 }
00235
00236 int AudioOSS::open_duplex()
00237 {
00238 device->duplex_channels = 0;
00239 for(int i = 0; i < MAXDEVICES; i++)
00240 {
00241 if(device->out_config->oss_enable[i])
00242 device->duplex_channels += device->out_config->oss_out_channels[i];
00243 }
00244 device->duplex_bits = device->out_config->oss_out_bits;
00245 if(device->duplex_bits == 24) device->duplex_bits = 32;
00246
00247 for(int i = 0; i < MAXDEVICES; i++)
00248 {
00249 if(device->out_config->oss_enable[i])
00250 {
00251 dsp_duplex[i] = open(device->out_config->oss_out_device[i], O_RDWR);
00252 if(dsp_duplex[i] < 0) perror("AudioOSS::open_duplex");
00253
00254 int format = get_fmt(device->out_config->oss_out_bits);
00255 int buffer_info = sizetofrag(device->duplex_samples,
00256 device->out_config->oss_out_channels[i],
00257 device->out_config->oss_out_bits);
00258 audio_buf_info playinfo;
00259
00260 set_cloexec_flag(dsp_duplex[i], 1);
00261
00262
00263 if(device->driver == AUDIO_OSS_ENVY24) buffer_info = 0x7fff000f;
00264 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETFRAGMENT, &buffer_info)) printf("SNDCTL_DSP_SETFRAGMENT failed.\n");
00265 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETDUPLEX, 1) == -1) printf("SNDCTL_DSP_SETDUPLEX failed\n");
00266 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SETFMT, &format) < 0) printf("SNDCTL_DSP_SETFMT failed\n");
00267 if(ioctl(dsp_duplex[i], SNDCTL_DSP_CHANNELS, &device->out_config->oss_out_channels[i]) < 0) printf("SNDCTL_DSP_CHANNELS failed\n");
00268 if(ioctl(dsp_duplex[i], SNDCTL_DSP_SPEED, &device->duplex_samplerate) < 0) printf("SNDCTL_DSP_SPEED failed\n");
00269 ioctl(dsp_duplex[i], SNDCTL_DSP_GETOSPACE, &playinfo);
00270 device->device_buffer = playinfo.bytes;
00271 thread[i] = new OSSThread(this);
00272 thread[i]->start();
00273 }
00274 }
00275 return 0;
00276 }
00277
00278 int AudioOSS::sizetofrag(int samples, int channels, int bits)
00279 {
00280 int testfrag = 2, fragsize = 1;
00281 samples *= channels * bits / 8;
00282 while(testfrag < samples)
00283 {
00284 fragsize++;
00285 testfrag *= 2;
00286 }
00287
00288 return (4 << 16) | fragsize;
00289 }
00290
00291 int AudioOSS::get_fmt(int bits)
00292 {
00293 switch(bits)
00294 {
00295 case 32: return AFMT_S32_LE; break;
00296 case 16: return AFMT_S16_LE; break;
00297 case 8: return AFMT_S8; break;
00298 }
00299 return AFMT_S16_LE;
00300 }
00301
00302
00303 int AudioOSS::close_all()
00304 {
00305
00306 for(int i = 0; i < MAXDEVICES; i++)
00307 {
00308 if(dsp_in[i])
00309 {
00310 ioctl(dsp_in[i], SNDCTL_DSP_RESET, 0);
00311 close(dsp_in[i]);
00312 }
00313
00314 if(dsp_out[i])
00315 {
00316
00317 ioctl(dsp_out[i], SNDCTL_DSP_RESET, 0);
00318 close(dsp_out[i]);
00319 }
00320
00321 if(dsp_duplex[i])
00322 {
00323 ioctl(dsp_duplex[i], SNDCTL_DSP_RESET, 0);
00324 close(dsp_duplex[i]);
00325 }
00326
00327 if(thread[i]) delete thread[i];
00328 if(data[i]) delete [] data[i];
00329 }
00330 return 0;
00331 }
00332
00333 int AudioOSS::set_cloexec_flag(int desc, int value)
00334 {
00335 int oldflags = fcntl (desc, F_GETFD, 0);
00336 if (oldflags < 0) return oldflags;
00337 if(value != 0)
00338 oldflags |= FD_CLOEXEC;
00339 else
00340 oldflags &= ~FD_CLOEXEC;
00341 return fcntl(desc, F_SETFD, oldflags);
00342 }
00343
00344 int64_t AudioOSS::device_position()
00345 {
00346 count_info info;
00347 if(!ioctl(get_output(0), SNDCTL_DSP_GETOPTR, &info))
00348 {
00349
00350
00351
00352
00353 if (info.bytes > 2100000000)
00354 return 0;
00355 else
00356 return info.bytes /
00357 (device->get_obits() / 8) /
00358 device->get_ochannels();
00359 }
00360 return 0;
00361 }
00362
00363 int AudioOSS::interrupt_playback()
00364 {
00365
00366 for(int i = 0; i < MAXDEVICES; i++)
00367 {
00368 if(thread[i])
00369 {
00370 thread[i]->cancel();
00371 thread[i]->write_lock->unlock();
00372 }
00373 }
00374
00375 return 0;
00376 }
00377
00378 int AudioOSS::read_buffer(char *buffer, int bytes)
00379 {
00380 int sample_size = device->get_ibits() / 8;
00381 int out_frame_size = device->get_ichannels() * sample_size;
00382 int samples = bytes / out_frame_size;
00383
00384
00385
00386 for(int i = 0; i < MAXDEVICES; i++)
00387 {
00388 if(thread[i])
00389 {
00390 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
00391
00392 if(data[i] && data_allocated[i] < bytes)
00393 {
00394 delete [] data[i];
00395 data[i] = 0;
00396 }
00397 if(!data[i])
00398 {
00399 data[i] = new unsigned char[bytes];
00400 data_allocated[i] = bytes;
00401 }
00402
00403 thread[i]->read_data(get_input(i), data[i], samples * in_frame_size);
00404 }
00405 }
00406
00407
00408 for(int i = 0, out_channel = 0; i < MAXDEVICES; i++)
00409 {
00410 if(thread[i])
00411 {
00412 thread[i]->wait_read();
00413
00414 for(int in_channel = 0;
00415 in_channel < device->in_config->oss_in_channels[i];
00416 in_channel++)
00417 {
00418 int in_frame_size = device->in_config->oss_in_channels[i] * sample_size;
00419
00420 for(int k = 0; k < samples; k++)
00421 {
00422 for(int l = 0;
00423 l < sample_size;
00424 l++)
00425 {
00426 buffer[out_channel * sample_size + k * out_frame_size + l] =
00427 data[i][in_channel * sample_size + k * in_frame_size + l];
00428 }
00429 }
00430 out_channel++;
00431 }
00432 }
00433 }
00434
00435 return 0;
00436 }
00437
00438 int AudioOSS::write_buffer(char *buffer, int bytes)
00439 {
00440 int sample_size = device->get_obits() / 8;
00441 int in_frame_size = device->get_ochannels() * sample_size;
00442 int samples = bytes / in_frame_size;
00443
00444 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
00445 {
00446 if(thread[i])
00447 {
00448 int out_frame_size = device->out_config->oss_out_channels[i] * sample_size;
00449 if(data[i] && data_allocated[i] < bytes)
00450 {
00451 delete [] data[i];
00452 data[i] = 0;
00453 }
00454 if(!data[i])
00455 {
00456 data[i] = new unsigned char[bytes];
00457 data_allocated[i] = bytes;
00458 }
00459
00460 for(int out_channel = 0;
00461 out_channel < device->out_config->oss_out_channels[i];
00462 out_channel++)
00463 {
00464
00465 for(int k = 0; k < samples; k++)
00466 {
00467 for(int l = 0; l < sample_size; l++)
00468 {
00469 data[i][out_channel * sample_size + k * out_frame_size + l] =
00470 buffer[in_channel * sample_size + k * in_frame_size + l];
00471 }
00472 }
00473 in_channel++;
00474 }
00475
00476 thread[i]->write_data(get_output(i), data[i], samples * out_frame_size);
00477 }
00478 }
00479 for(int i = 0, in_channel = 0; i < MAXDEVICES; i++)
00480 {
00481 if(thread[i])
00482 {
00483 thread[i]->wait_write();
00484 }
00485 }
00486 return 0;
00487 }
00488
00489 int AudioOSS::flush_device()
00490 {
00491 for(int i = 0; i < MAXDEVICES; i++)
00492 if(thread[i]) ioctl(get_output(i), SNDCTL_DSP_SYNC, 0);
00493 return 0;
00494 }
00495
00496 int AudioOSS::get_output(int number)
00497 {
00498 if(device->w) return dsp_out[number];
00499 else if(device->d) return dsp_duplex[number];
00500 return 0;
00501 }
00502
00503 int AudioOSS::get_input(int number)
00504 {
00505 if(device->r) return dsp_in[number];
00506 else if(device->d) return dsp_duplex[number];
00507 return 0;
00508 }
00509
00510 #endif // HAVE_OSS