Jack2
1.9.8
|
00001 /* 00002 Copyright (C) 2003-2007 Jussi Laako <jussi@sonarnerd.net> 00003 Copyright (C) 2008 Grame & RTL 2008 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 00019 */ 00020 00021 #include "driver_interface.h" 00022 #include "JackThreadedDriver.h" 00023 #include "JackDriverLoader.h" 00024 #include "JackOSSDriver.h" 00025 #include "JackEngineControl.h" 00026 #include "JackGraphManager.h" 00027 #include "JackError.h" 00028 #include "JackTime.h" 00029 #include "JackShmMem.h" 00030 #include "memops.h" 00031 00032 #include <sys/ioctl.h> 00033 #include <sys/soundcard.h> 00034 #include <fcntl.h> 00035 #include <iostream> 00036 #include <assert.h> 00037 #include <stdio.h> 00038 00039 using namespace std; 00040 00041 namespace Jack 00042 { 00043 00044 #ifdef JACK_MONITOR 00045 00046 #define CYCLE_POINTS 500000 00047 00048 struct OSSCycle { 00049 jack_time_t fBeforeRead; 00050 jack_time_t fAfterRead; 00051 jack_time_t fAfterReadConvert; 00052 jack_time_t fBeforeWrite; 00053 jack_time_t fAfterWrite; 00054 jack_time_t fBeforeWriteConvert; 00055 }; 00056 00057 struct OSSCycleTable { 00058 jack_time_t fBeforeFirstWrite; 00059 jack_time_t fAfterFirstWrite; 00060 OSSCycle fTable[CYCLE_POINTS]; 00061 }; 00062 00063 OSSCycleTable gCycleTable; 00064 int gCycleCount = 0; 00065 00066 #endif 00067 00068 inline int int2pow2(int x) { int r = 0; while ((1 << r) < x) r++; return r; } 00069 00070 static inline void CopyAndConvertIn(jack_sample_t *dst, void *src, size_t nframes, int channel, int chcount, int bits) 00071 { 00072 switch (bits) { 00073 00074 case 16: { 00075 signed short *s16src = (signed short*)src; 00076 s16src += channel; 00077 sample_move_dS_s16(dst, (char*)s16src, nframes, chcount<<1); 00078 break; 00079 } 00080 case 24: { 00081 signed int *s32src = (signed int*)src; 00082 s32src += channel; 00083 sample_move_dS_s24(dst, (char*)s32src, nframes, chcount<<2); 00084 break; 00085 } 00086 case 32: { 00087 signed int *s32src = (signed int*)src; 00088 s32src += channel; 00089 sample_move_dS_s32u24(dst, (char*)s32src, nframes, chcount<<2); 00090 break; 00091 } 00092 } 00093 } 00094 00095 static inline void CopyAndConvertOut(void *dst, jack_sample_t *src, size_t nframes, int channel, int chcount, int bits) 00096 { 00097 switch (bits) { 00098 00099 case 16: { 00100 signed short *s16dst = (signed short*)dst; 00101 s16dst += channel; 00102 sample_move_d16_sS((char*)s16dst, src, nframes, chcount<<1, NULL); // No dithering for now... 00103 break; 00104 } 00105 case 24: { 00106 signed int *s32dst = (signed int*)dst; 00107 s32dst += channel; 00108 sample_move_d24_sS((char*)s32dst, src, nframes, chcount<<2, NULL); // No dithering for now... 00109 break; 00110 } 00111 case 32: { 00112 signed int *s32dst = (signed int*)dst; 00113 s32dst += channel; 00114 sample_move_d32u24_sS((char*)s32dst, src, nframes, chcount<<2, NULL); 00115 break; 00116 } 00117 } 00118 } 00119 00120 void JackOSSDriver::SetSampleFormat() 00121 { 00122 switch (fBits) { 00123 00124 case 24: /* native-endian LSB aligned 24-bits in 32-bits integer */ 00125 fSampleFormat = AFMT_S24_NE; 00126 fSampleSize = sizeof(int); 00127 break; 00128 case 32: /* native-endian 32-bit integer */ 00129 fSampleFormat = AFMT_S32_NE; 00130 fSampleSize = sizeof(int); 00131 break; 00132 case 16: /* native-endian 16-bit integer */ 00133 default: 00134 fSampleFormat = AFMT_S16_NE; 00135 fSampleSize = sizeof(short); 00136 break; 00137 } 00138 } 00139 00140 void JackOSSDriver::DisplayDeviceInfo() 00141 { 00142 audio_buf_info info; 00143 oss_audioinfo ai_in, ai_out; 00144 memset(&info, 0, sizeof(audio_buf_info)); 00145 int cap = 0; 00146 00147 // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html 00148 jack_info("Audio Interface Description :"); 00149 jack_info("Sampling Frequency : %d, Sample Format : %d, Mode : %d", fEngineControl->fSampleRate, fSampleFormat, fRWMode); 00150 00151 if (fRWMode & kWrite) { 00152 00153 oss_sysinfo si; 00154 if (ioctl(fOutFD, OSS_SYSINFO, &si) == -1) { 00155 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00156 } else { 00157 jack_info("OSS product %s", si.product); 00158 jack_info("OSS version %s", si.version); 00159 jack_info("OSS version num %d", si.versionnum); 00160 jack_info("OSS numaudios %d", si.numaudios); 00161 jack_info("OSS numaudioengines %d", si.numaudioengines); 00162 jack_info("OSS numcards %d", si.numcards); 00163 } 00164 00165 jack_info("Output capabilities - %d channels : ", fPlaybackChannels); 00166 jack_info("Output block size = %d", fOutputBufferSize); 00167 00168 if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1) { 00169 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00170 } else { 00171 jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", 00172 info.fragments, info.fragstotal, info.fragsize, info.bytes); 00173 } 00174 00175 if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { 00176 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00177 } else { 00178 if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX"); 00179 if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME"); 00180 if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH"); 00181 if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC"); 00182 if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER"); 00183 if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP"); 00184 if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI"); 00185 if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); 00186 } 00187 } 00188 00189 if (fRWMode & kRead) { 00190 00191 oss_sysinfo si; 00192 if (ioctl(fInFD, OSS_SYSINFO, &si) == -1) { 00193 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00194 } else { 00195 jack_info("OSS product %s", si.product); 00196 jack_info("OSS version %s", si.version); 00197 jack_info("OSS version num %d", si.versionnum); 00198 jack_info("OSS numaudios %d", si.numaudios); 00199 jack_info("OSS numaudioengines %d", si.numaudioengines); 00200 jack_info("OSS numcards %d", si.numcards); 00201 } 00202 00203 jack_info("Input capabilities - %d channels : ", fCaptureChannels); 00204 jack_info("Input block size = %d", fInputBufferSize); 00205 00206 if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) { 00207 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00208 } else { 00209 jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", 00210 info.fragments, info.fragstotal, info.fragsize, info.bytes); 00211 } 00212 00213 if (ioctl(fInFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { 00214 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00215 } else { 00216 if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX"); 00217 if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME"); 00218 if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH"); 00219 if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC"); 00220 if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER"); 00221 if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP"); 00222 if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI"); 00223 if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); 00224 } 00225 } 00226 00227 if (ai_in.rate_source != ai_out.rate_source) { 00228 jack_info("Warning : input and output are not necessarily driven by the same clock!"); 00229 } 00230 } 00231 00232 int JackOSSDriver::OpenInput() 00233 { 00234 int flags = 0; 00235 int gFragFormat; 00236 int cur_capture_channels; 00237 int cur_sample_format; 00238 jack_nframes_t cur_sample_rate; 00239 00240 if (fCaptureChannels == 0) fCaptureChannels = 2; 00241 00242 if ((fInFD = open(fCaptureDriverName, O_RDONLY | ((fExcl) ? O_EXCL : 0))) < 0) { 00243 jack_error("JackOSSDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00244 return -1; 00245 } 00246 00247 jack_log("JackOSSDriver::OpenInput input fInFD = %d", fInFD); 00248 00249 if (fExcl) { 00250 if (ioctl(fInFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) { 00251 jack_error("JackOSSDriver::OpenInput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00252 goto error; 00253 } 00254 } 00255 00256 gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels); 00257 if (ioctl(fInFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { 00258 jack_error("JackOSSDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00259 goto error; 00260 } 00261 00262 cur_sample_format = fSampleFormat; 00263 if (ioctl(fInFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) { 00264 jack_error("JackOSSDriver::OpenInput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00265 goto error; 00266 } 00267 if (cur_sample_format != fSampleFormat) { 00268 jack_info("JackOSSDriver::OpenInput driver forced the sample format %ld", fSampleFormat); 00269 } 00270 00271 cur_capture_channels = fCaptureChannels; 00272 if (ioctl(fInFD, SNDCTL_DSP_CHANNELS, &fCaptureChannels) == -1) { 00273 jack_error("JackOSSDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00274 goto error; 00275 } 00276 if (cur_capture_channels != fCaptureChannels) { 00277 jack_info("JackOSSDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels); 00278 } 00279 00280 cur_sample_rate = fEngineControl->fSampleRate; 00281 if (ioctl(fInFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) { 00282 jack_error("JackOSSDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00283 goto error; 00284 } 00285 if (cur_sample_rate != fEngineControl->fSampleRate) { 00286 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate); 00287 } 00288 00289 fInputBufferSize = 0; 00290 if (ioctl(fInFD, SNDCTL_DSP_GETBLKSIZE, &fInputBufferSize) == -1) { 00291 jack_error("JackOSSDriver::OpenInput failed to get fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00292 goto error; 00293 } 00294 00295 if (fInputBufferSize != fEngineControl->fBufferSize * fSampleSize * fCaptureChannels) { 00296 if (fIgnoreHW) { 00297 int new_buffer_size = fInputBufferSize / (fSampleSize * fCaptureChannels); 00298 jack_info("JackOSSDriver::OpenInput driver forced buffer size %ld", new_buffer_size); 00299 JackAudioDriver::SetBufferSize(new_buffer_size); // never fails 00300 } else { 00301 jack_error("JackOSSDriver::OpenInput wanted buffer size cannot be obtained"); 00302 goto error; 00303 } 00304 } 00305 00306 fInputBuffer = (void*)calloc(fInputBufferSize, 1); 00307 assert(fInputBuffer); 00308 return 0; 00309 00310 error: 00311 ::close(fInFD); 00312 return -1; 00313 } 00314 00315 int JackOSSDriver::OpenOutput() 00316 { 00317 int flags = 0; 00318 int gFragFormat; 00319 int cur_sample_format; 00320 int cur_playback_channels; 00321 jack_nframes_t cur_sample_rate; 00322 00323 if (fPlaybackChannels == 0) fPlaybackChannels = 2; 00324 00325 if ((fOutFD = open(fPlaybackDriverName, O_WRONLY | ((fExcl) ? O_EXCL : 0))) < 0) { 00326 jack_error("JackOSSDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00327 return -1; 00328 } 00329 00330 jack_log("JackOSSDriver::OpenOutput output fOutFD = %d", fOutFD); 00331 00332 if (fExcl) { 00333 if (ioctl(fOutFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) { 00334 jack_error("JackOSSDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00335 goto error; 00336 } 00337 } 00338 00339 gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels); 00340 if (ioctl(fOutFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { 00341 jack_error("JackOSSDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00342 goto error; 00343 } 00344 00345 cur_sample_format = fSampleFormat; 00346 if (ioctl(fOutFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) { 00347 jack_error("JackOSSDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00348 goto error; 00349 } 00350 if (cur_sample_format != fSampleFormat) { 00351 jack_info("JackOSSDriver::OpenOutput driver forced the sample format %ld", fSampleFormat); 00352 } 00353 00354 cur_playback_channels = fPlaybackChannels; 00355 if (ioctl(fOutFD, SNDCTL_DSP_CHANNELS, &fPlaybackChannels) == -1) { 00356 jack_error("JackOSSDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00357 goto error; 00358 } 00359 if (cur_playback_channels != fPlaybackChannels) { 00360 jack_info("JackOSSDriver::OpenOutput driver forced the number of playback channels %ld", fPlaybackChannels); 00361 } 00362 00363 cur_sample_rate = fEngineControl->fSampleRate; 00364 if (ioctl(fOutFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) { 00365 jack_error("JackOSSDriver::OpenOutput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00366 goto error; 00367 } 00368 if (cur_sample_rate != fEngineControl->fSampleRate) { 00369 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate); 00370 } 00371 00372 fOutputBufferSize = 0; 00373 if (ioctl(fOutFD, SNDCTL_DSP_GETBLKSIZE, &fOutputBufferSize) == -1) { 00374 jack_error("JackOSSDriver::OpenOutput failed to get fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00375 goto error; 00376 } 00377 00378 if (fOutputBufferSize != fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels) { 00379 if (fIgnoreHW) { 00380 int new_buffer_size = fOutputBufferSize / (fSampleSize * fPlaybackChannels); 00381 jack_info("JackOSSDriver::OpenOutput driver forced buffer size %ld", new_buffer_size); 00382 JackAudioDriver::SetBufferSize(new_buffer_size); // never fails 00383 } else { 00384 jack_error("JackOSSDriver::OpenInput wanted buffer size cannot be obtained"); 00385 goto error; 00386 } 00387 } 00388 00389 fOutputBuffer = (void*)calloc(fOutputBufferSize, 1); 00390 fFirstCycle = true; 00391 assert(fOutputBuffer); 00392 return 0; 00393 00394 error: 00395 ::close(fOutFD); 00396 return -1; 00397 } 00398 00399 int JackOSSDriver::Open(jack_nframes_t nframes, 00400 int user_nperiods, 00401 jack_nframes_t samplerate, 00402 bool capturing, 00403 bool playing, 00404 int inchannels, 00405 int outchannels, 00406 bool excl, 00407 bool monitor, 00408 const char* capture_driver_uid, 00409 const char* playback_driver_uid, 00410 jack_nframes_t capture_latency, 00411 jack_nframes_t playback_latency, 00412 int bits, 00413 bool ignorehwbuf) 00414 { 00415 // Generic JackAudioDriver Open 00416 if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, 00417 capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { 00418 return -1; 00419 } else { 00420 00421 if (!fEngineControl->fSyncMode) { 00422 jack_error("Cannot run in asynchronous mode, use the -S parameter for jackd"); 00423 return -1; 00424 } 00425 00426 fRWMode |= ((capturing) ? kRead : 0); 00427 fRWMode |= ((playing) ? kWrite : 0); 00428 fBits = bits; 00429 fIgnoreHW = ignorehwbuf; 00430 fNperiods = user_nperiods; 00431 fExcl = excl; 00432 00433 #ifdef JACK_MONITOR 00434 // Force memory page in 00435 memset(&gCycleTable, 0, sizeof(gCycleTable)); 00436 #endif 00437 00438 if (OpenAux() < 0) { 00439 Close(); 00440 return -1; 00441 } else { 00442 return 0; 00443 } 00444 } 00445 } 00446 00447 int JackOSSDriver::Close() 00448 { 00449 #ifdef JACK_MONITOR 00450 FILE* file = fopen("OSSProfiling.log", "w"); 00451 00452 if (file) { 00453 jack_info("Writing OSS driver timing data...."); 00454 for (int i = 1; i < gCycleCount; i++) { 00455 int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead; 00456 int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead; 00457 int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite; 00458 int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert; 00459 fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4); 00460 } 00461 fclose(file); 00462 } else { 00463 jack_error("JackOSSDriver::Close : cannot open OSSProfiling.log file"); 00464 } 00465 00466 file = fopen("TimingOSS.plot", "w"); 00467 00468 if (file == NULL) { 00469 jack_error("JackOSSDriver::Close cannot open TimingOSS.plot file"); 00470 } else { 00471 00472 fprintf(file, "set grid\n"); 00473 fprintf(file, "set title \"OSS audio driver timing\"\n"); 00474 fprintf(file, "set xlabel \"audio cycles\"\n"); 00475 fprintf(file, "set ylabel \"usec\"\n"); 00476 fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \ 00477 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ 00478 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ 00479 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); 00480 00481 fprintf(file, "set output 'TimingOSS.pdf\n"); 00482 fprintf(file, "set terminal pdf\n"); 00483 00484 fprintf(file, "set grid\n"); 00485 fprintf(file, "set title \"OSS audio driver timing\"\n"); 00486 fprintf(file, "set xlabel \"audio cycles\"\n"); 00487 fprintf(file, "set ylabel \"usec\"\n"); 00488 fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \ 00489 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ 00490 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ 00491 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); 00492 00493 fclose(file); 00494 } 00495 #endif 00496 int res = JackAudioDriver::Close(); 00497 CloseAux(); 00498 return res; 00499 } 00500 00501 00502 int JackOSSDriver::OpenAux() 00503 { 00504 SetSampleFormat(); 00505 00506 if ((fRWMode & kRead) && (OpenInput() < 0)) { 00507 return -1; 00508 } 00509 00510 if ((fRWMode & kWrite) && (OpenOutput() < 0)) { 00511 return -1; 00512 } 00513 00514 // In duplex mode, check that input and output use the same buffer size 00515 /* 00516 00517 10/02/09 : desactivated for now, needs more check (only needed when *same* device is used for input and output ??) 00518 00519 if ((fRWMode & kRead) && (fRWMode & kWrite) && (fInputBufferSize != fOutputBufferSize)) { 00520 jack_error("JackOSSDriver::OpenAux input and output buffer size are not the same!!"); 00521 return -1; 00522 } 00523 */ 00524 00525 DisplayDeviceInfo(); 00526 return 0; 00527 } 00528 00529 void JackOSSDriver::CloseAux() 00530 { 00531 if (fRWMode & kRead && fInFD > 0) { 00532 close(fInFD); 00533 fInFD = -1; 00534 } 00535 00536 if (fRWMode & kWrite && fOutFD > 0) { 00537 close(fOutFD); 00538 fOutFD = -1; 00539 } 00540 00541 if (fInputBuffer) 00542 free(fInputBuffer); 00543 fInputBuffer = NULL; 00544 00545 if (fOutputBuffer) 00546 free(fOutputBuffer); 00547 fOutputBuffer = NULL; 00548 } 00549 00550 int JackOSSDriver::Read() 00551 { 00552 if (fInFD < 0) { 00553 // Keep begin cycle time 00554 JackDriver::CycleTakeBeginTime(); 00555 return 0; 00556 } 00557 00558 ssize_t count; 00559 00560 #ifdef JACK_MONITOR 00561 gCycleTable.fTable[gCycleCount].fBeforeRead = GetMicroSeconds(); 00562 #endif 00563 00564 audio_errinfo ei_in; 00565 count = ::read(fInFD, fInputBuffer, fInputBufferSize); 00566 00567 #ifdef JACK_MONITOR 00568 if (count > 0 && count != (int)fInputBufferSize) 00569 jack_log("JackOSSDriver::Read count = %ld", count / (fSampleSize * fCaptureChannels)); 00570 gCycleTable.fTable[gCycleCount].fAfterRead = GetMicroSeconds(); 00571 #endif 00572 00573 // XRun detection 00574 if (ioctl(fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) { 00575 00576 if (ei_in.rec_overruns > 0 ) { 00577 jack_error("JackOSSDriver::Read overruns"); 00578 jack_time_t cur_time = GetMicroSeconds(); 00579 NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... 00580 } 00581 00582 if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) { 00583 jack_error("%d OSS rec event(s), last=%05d:%d", ei_in.rec_errorcount, ei_in.rec_lasterror, ei_in.rec_errorparm); 00584 } 00585 } 00586 00587 if (count < 0) { 00588 jack_log("JackOSSDriver::Read error = %s", strerror(errno)); 00589 return -1; 00590 } else if (count < (int)fInputBufferSize) { 00591 jack_error("JackOSSDriver::Read error bytes read = %ld", count); 00592 return -1; 00593 } else { 00594 00595 // Keep begin cycle time 00596 JackDriver::CycleTakeBeginTime(); 00597 for (int i = 0; i < fCaptureChannels; i++) { 00598 if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) { 00599 CopyAndConvertIn(GetInputBuffer(i), fInputBuffer, fEngineControl->fBufferSize, i, fCaptureChannels, fBits); 00600 } 00601 } 00602 00603 #ifdef JACK_MONITOR 00604 gCycleTable.fTable[gCycleCount].fAfterReadConvert = GetMicroSeconds(); 00605 #endif 00606 00607 return 0; 00608 } 00609 } 00610 00611 int JackOSSDriver::Write() 00612 { 00613 if (fOutFD < 0) { 00614 // Keep end cycle time 00615 JackDriver::CycleTakeEndTime(); 00616 return 0; 00617 } 00618 00619 ssize_t count; 00620 audio_errinfo ei_out; 00621 00622 // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html 00623 if (fFirstCycle) { 00624 00625 fFirstCycle = false; 00626 memset(fOutputBuffer, 0, fOutputBufferSize); 00627 00628 // Prefill ouput buffer 00629 for (int i = 0; i < fNperiods; i++) { 00630 count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize); 00631 if (count < (int)fOutputBufferSize) { 00632 jack_error("JackOSSDriver::Write error bytes written = %ld", count); 00633 return -1; 00634 } 00635 } 00636 00637 int delay; 00638 if (ioctl(fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) { 00639 jack_error("JackOSSDriver::Write error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno); 00640 return -1; 00641 } 00642 00643 delay /= fSampleSize * fPlaybackChannels; 00644 jack_info("JackOSSDriver::Write output latency frames = %ld", delay); 00645 } 00646 00647 #ifdef JACK_MONITOR 00648 gCycleTable.fTable[gCycleCount].fBeforeWriteConvert = GetMicroSeconds(); 00649 #endif 00650 00651 memset(fOutputBuffer, 0, fOutputBufferSize); 00652 for (int i = 0; i < fPlaybackChannels; i++) { 00653 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { 00654 CopyAndConvertOut(fOutputBuffer, GetOutputBuffer(i), fEngineControl->fBufferSize, i, fPlaybackChannels, fBits); 00655 } 00656 } 00657 00658 #ifdef JACK_MONITOR 00659 gCycleTable.fTable[gCycleCount].fBeforeWrite = GetMicroSeconds(); 00660 #endif 00661 00662 // Keep end cycle time 00663 JackDriver::CycleTakeEndTime(); 00664 count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize); 00665 00666 #ifdef JACK_MONITOR 00667 if (count > 0 && count != (int)fOutputBufferSize) 00668 jack_log("JackOSSDriver::Write count = %ld", count / (fSampleSize * fPlaybackChannels)); 00669 gCycleTable.fTable[gCycleCount].fAfterWrite = GetMicroSeconds(); 00670 gCycleCount = (gCycleCount == CYCLE_POINTS - 1) ? gCycleCount: gCycleCount + 1; 00671 #endif 00672 00673 // XRun detection 00674 if (ioctl(fOutFD, SNDCTL_DSP_GETERROR, &ei_out) == 0) { 00675 00676 if (ei_out.play_underruns > 0) { 00677 jack_error("JackOSSDriver::Write underruns"); 00678 jack_time_t cur_time = GetMicroSeconds(); 00679 NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... 00680 } 00681 00682 if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) { 00683 jack_error("%d OSS play event(s), last=%05d:%d",ei_out.play_errorcount, ei_out.play_lasterror, ei_out.play_errorparm); 00684 } 00685 } 00686 00687 if (count < 0) { 00688 jack_log("JackOSSDriver::Write error = %s", strerror(errno)); 00689 return -1; 00690 } else if (count < (int)fOutputBufferSize) { 00691 jack_error("JackOSSDriver::Write error bytes written = %ld", count); 00692 return -1; 00693 } else { 00694 return 0; 00695 } 00696 } 00697 00698 int JackOSSDriver::SetBufferSize(jack_nframes_t buffer_size) 00699 { 00700 CloseAux(); 00701 JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails 00702 return OpenAux(); 00703 } 00704 00705 int JackOSSDriver::ProcessSync() 00706 { 00707 // Read input buffers for the current cycle 00708 if (Read() < 0) { 00709 jack_error("ProcessSync: read error, skip cycle"); 00710 return 0; // Non fatal error here, skip cycle, but continue processing... 00711 } 00712 00713 if (fIsMaster) { 00714 ProcessGraphSync(); 00715 } else { 00716 ResumeRefNum(); 00717 } 00718 00719 // Write output buffers for the current cycle 00720 if (Write() < 0) { 00721 jack_error("JackAudioDriver::ProcessSync: write error, skip cycle"); 00722 return 0; // Non fatal error here, skip cycle, but continue processing... 00723 } 00724 00725 return 0; 00726 } 00727 00728 } // end of namespace 00729 00730 #ifdef __cplusplus 00731 extern "C" 00732 { 00733 #endif 00734 00735 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() 00736 { 00737 jack_driver_desc_t * desc; 00738 jack_driver_desc_filler_t filler; 00739 jack_driver_param_value_t value; 00740 00741 desc = jack_driver_descriptor_construct("oss", JackDriverMaster, "OSS API based audio backend", &filler); 00742 00743 value.ui = OSS_DRIVER_DEF_FS; 00744 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); 00745 00746 value.ui = OSS_DRIVER_DEF_BLKSIZE; 00747 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL); 00748 00749 value.ui = OSS_DRIVER_DEF_NPERIODS; 00750 jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods to prefill output buffer", NULL); 00751 00752 value.i = OSS_DRIVER_DEF_BITS; 00753 jack_driver_descriptor_add_parameter(desc, &filler, "wordlength", 'w', JackDriverParamInt, &value, NULL, "Word length", NULL); 00754 00755 value.ui = OSS_DRIVER_DEF_INS; 00756 jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Capture channels", NULL); 00757 00758 value.ui = OSS_DRIVER_DEF_OUTS; 00759 jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Playback channels", NULL); 00760 00761 value.i = false; 00762 jack_driver_descriptor_add_parameter(desc, &filler, "excl", 'e', JackDriverParamBool, &value, NULL, "Exclusif (O_EXCL) access mode", NULL); 00763 00764 strcpy(value.str, OSS_DRIVER_DEF_DEV); 00765 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input device", NULL); 00766 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output device", NULL); 00767 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "OSS device name", NULL); 00768 00769 value.i = false; 00770 jack_driver_descriptor_add_parameter(desc, &filler, "ignorehwbuf", 'b', JackDriverParamBool, &value, NULL, "Ignore hardware period size", NULL); 00771 00772 value.ui = 0; 00773 jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency", NULL); 00774 jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency", NULL); 00775 00776 return desc; 00777 } 00778 00779 EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) 00780 { 00781 int bits = OSS_DRIVER_DEF_BITS; 00782 jack_nframes_t srate = OSS_DRIVER_DEF_FS; 00783 jack_nframes_t frames_per_interrupt = OSS_DRIVER_DEF_BLKSIZE; 00784 const char* capture_pcm_name = OSS_DRIVER_DEF_DEV; 00785 const char* playback_pcm_name = OSS_DRIVER_DEF_DEV; 00786 bool capture = false; 00787 bool playback = false; 00788 int chan_in = 0; 00789 int chan_out = 0; 00790 bool monitor = false; 00791 bool excl = false; 00792 unsigned int nperiods = OSS_DRIVER_DEF_NPERIODS; 00793 const JSList *node; 00794 const jack_driver_param_t *param; 00795 bool ignorehwbuf = false; 00796 jack_nframes_t systemic_input_latency = 0; 00797 jack_nframes_t systemic_output_latency = 0; 00798 00799 for (node = params; node; node = jack_slist_next(node)) { 00800 00801 param = (const jack_driver_param_t *)node->data; 00802 00803 switch (param->character) { 00804 00805 case 'r': 00806 srate = param->value.ui; 00807 break; 00808 00809 case 'p': 00810 frames_per_interrupt = (unsigned int)param->value.ui; 00811 break; 00812 00813 case 'n': 00814 nperiods = (unsigned int)param->value.ui; 00815 break; 00816 00817 case 'w': 00818 bits = param->value.i; 00819 break; 00820 00821 case 'i': 00822 chan_in = (int)param->value.ui; 00823 break; 00824 00825 case 'o': 00826 chan_out = (int)param->value.ui; 00827 break; 00828 00829 case 'C': 00830 capture = true; 00831 if (strcmp(param->value.str, "none") != 0) { 00832 capture_pcm_name = param->value.str; 00833 } 00834 break; 00835 00836 case 'P': 00837 playback = true; 00838 if (strcmp(param->value.str, "none") != 0) { 00839 playback_pcm_name = param->value.str; 00840 } 00841 break; 00842 00843 case 'd': 00844 playback_pcm_name = param->value.str; 00845 capture_pcm_name = param->value.str; 00846 break; 00847 00848 case 'b': 00849 ignorehwbuf = true; 00850 break; 00851 00852 case 'e': 00853 excl = true; 00854 break; 00855 00856 case 'I': 00857 systemic_input_latency = param->value.ui; 00858 break; 00859 00860 case 'O': 00861 systemic_output_latency = param->value.ui; 00862 break; 00863 } 00864 } 00865 00866 // duplex is the default 00867 if (!capture && !playback) { 00868 capture = true; 00869 playback = true; 00870 } 00871 00872 Jack::JackOSSDriver* oss_driver = new Jack::JackOSSDriver("system", "oss", engine, table); 00873 Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(oss_driver); 00874 00875 // Special open for OSS driver... 00876 if (oss_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, 00877 excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, ignorehwbuf) == 0) { 00878 return threaded_driver; 00879 } else { 00880 delete threaded_driver; // Delete the decorated driver 00881 return NULL; 00882 } 00883 } 00884 00885 #ifdef __cplusplus 00886 } 00887 #endif