00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "driver_interface.h"
00021 #include "JackThreadedDriver.h"
00022 #include "JackDriverLoader.h"
00023 #include "JackBoomerDriver.h"
00024 #include "JackEngineControl.h"
00025 #include "JackGraphManager.h"
00026 #include "JackError.h"
00027 #include "JackTime.h"
00028 #include "JackShmMem.h"
00029 #include "JackGlobals.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 gCycleReadCount = 0;
00065 int gCycleWriteCount = 0;
00066
00067 #endif
00068
00069 inline int int2pow2(int x) { int r = 0; while ((1 << r) < x) r++; return r; }
00070
00071 static inline void CopyAndConvertIn(jack_sample_t *dst, void *src, size_t nframes, int channel, int byte_skip, int bits)
00072 {
00073 switch (bits) {
00074
00075 case 16: {
00076 signed short *s16src = (signed short*)src;
00077 s16src += channel;
00078 sample_move_dS_s16(dst, (char*)s16src, nframes, byte_skip);
00079 break;
00080 }
00081 case 24: {
00082 signed int *s32src = (signed int*)src;
00083 s32src += channel;
00084 sample_move_dS_s24(dst, (char*)s32src, nframes, byte_skip);
00085 break;
00086 }
00087 case 32: {
00088 signed int *s32src = (signed int*)src;
00089 s32src += channel;
00090 sample_move_dS_s32u24(dst, (char*)s32src, nframes, byte_skip);
00091 break;
00092 }
00093 }
00094 }
00095
00096 static inline void CopyAndConvertOut(void *dst, jack_sample_t *src, size_t nframes, int channel, int byte_skip, int bits)
00097 {
00098 switch (bits) {
00099
00100 case 16: {
00101 signed short *s16dst = (signed short*)dst;
00102 s16dst += channel;
00103 sample_move_d16_sS((char*)s16dst, src, nframes, byte_skip, NULL);
00104 break;
00105 }
00106 case 24: {
00107 signed int *s32dst = (signed int*)dst;
00108 s32dst += channel;
00109 sample_move_d24_sS((char*)s32dst, src, nframes, byte_skip, NULL);
00110 break;
00111 }
00112 case 32: {
00113 signed int *s32dst = (signed int*)dst;
00114 s32dst += channel;
00115 sample_move_d32u24_sS((char*)s32dst, src, nframes, byte_skip, NULL);
00116 break;
00117 }
00118 }
00119 }
00120
00121 void JackBoomerDriver::SetSampleFormat()
00122 {
00123 switch (fBits) {
00124
00125 case 24:
00126 fSampleFormat = AFMT_S24_NE;
00127 fSampleSize = 4;
00128 break;
00129 case 32:
00130 fSampleFormat = AFMT_S32_NE;
00131 fSampleSize = 4;
00132 break;
00133 case 16:
00134 default:
00135 fSampleFormat = AFMT_S16_NE;
00136 fSampleSize = 2;
00137 break;
00138 }
00139 }
00140
00141 void JackBoomerDriver::DisplayDeviceInfo()
00142 {
00143 audio_buf_info info;
00144 oss_audioinfo ai_in, ai_out;
00145 memset(&info, 0, sizeof(audio_buf_info));
00146 int cap = 0;
00147
00148
00149 jack_info("Audio Interface Description :");
00150 jack_info("Sampling Frequency : %d, Sample Format : %d, Mode : %d", fEngineControl->fSampleRate, fSampleFormat, fRWMode);
00151
00152 if (fRWMode & kWrite) {
00153
00154 oss_sysinfo si;
00155 if (ioctl(fOutFD, OSS_SYSINFO, &si) == -1) {
00156 jack_error("JackBoomerDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00157 } else {
00158 jack_info("OSS product %s", si.product);
00159 jack_info("OSS version %s", si.version);
00160 jack_info("OSS version num %d", si.versionnum);
00161 jack_info("OSS numaudios %d", si.numaudios);
00162 jack_info("OSS numaudioengines %d", si.numaudioengines);
00163 jack_info("OSS numcards %d", si.numcards);
00164 }
00165
00166 jack_info("Output capabilities - %d channels : ", fPlaybackChannels);
00167 jack_info("Output block size = %d", fOutputBufferSize);
00168
00169 if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1) {
00170 jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00171 } else {
00172 jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
00173 info.fragments, info.fragstotal, info.fragsize, info.bytes);
00174 fFragmentSize = info.fragsize;
00175 }
00176
00177 if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) {
00178 jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00179 } else {
00180 if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX");
00181 if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME");
00182 if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH");
00183 if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC");
00184 if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER");
00185 if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP");
00186 if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI");
00187 if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND");
00188 }
00189 }
00190
00191 if (fRWMode & kRead) {
00192
00193 oss_sysinfo si;
00194 if (ioctl(fInFD, OSS_SYSINFO, &si) == -1) {
00195 jack_error("JackBoomerDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00196 } else {
00197 jack_info("OSS product %s", si.product);
00198 jack_info("OSS version %s", si.version);
00199 jack_info("OSS version num %d", si.versionnum);
00200 jack_info("OSS numaudios %d", si.numaudios);
00201 jack_info("OSS numaudioengines %d", si.numaudioengines);
00202 jack_info("OSS numcards %d", si.numcards);
00203 }
00204
00205 jack_info("Input capabilities - %d channels : ", fCaptureChannels);
00206 jack_info("Input block size = %d", fInputBufferSize);
00207
00208 if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) {
00209 jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00210 } else {
00211 jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
00212 info.fragments, info.fragstotal, info.fragsize, info.bytes);
00213 }
00214
00215 if (ioctl(fInFD, SNDCTL_DSP_GETCAPS, &cap) == -1) {
00216 jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00217 } else {
00218 if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX");
00219 if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME");
00220 if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH");
00221 if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC");
00222 if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER");
00223 if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP");
00224 if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI");
00225 if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND");
00226 }
00227 }
00228
00229 if (ai_in.rate_source != ai_out.rate_source) {
00230 jack_info("Warning : input and output are not necessarily driven by the same clock!");
00231 }
00232 }
00233
00234 JackBoomerDriver::JackBoomerDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
00235 : JackAudioDriver(name, alias, engine, table),
00236 fInFD(-1), fOutFD(-1), fBits(0),
00237 fSampleFormat(0), fNperiods(0), fSampleSize(0), fFragmentSize(0),
00238 fRWMode(0), fExcl(false), fSyncIO(false),
00239 fInputBufferSize(0), fOutputBufferSize(0),
00240 fInputBuffer(NULL), fOutputBuffer(NULL),
00241 fInputThread(&fInputHandler), fOutputThread(&fOutputHandler),
00242 fInputHandler(this), fOutputHandler(this)
00243 {
00244 sem_init(&fReadSema, 0, 0);
00245 sem_init(&fWriteSema, 0, 0);
00246 }
00247
00248 JackBoomerDriver::~JackBoomerDriver()
00249 {
00250 sem_destroy(&fReadSema);
00251 sem_destroy(&fWriteSema);
00252 }
00253
00254 int JackBoomerDriver::OpenInput()
00255 {
00256 int flags = 0;
00257 int gFragFormat;
00258 int cur_capture_channels;
00259 int cur_sample_format;
00260 jack_nframes_t cur_sample_rate;
00261
00262 if (fCaptureChannels == 0)
00263 fCaptureChannels = 2;
00264
00265 if ((fInFD = open(fCaptureDriverName, O_RDONLY | ((fExcl) ? O_EXCL : 0))) < 0) {
00266 jack_error("JackBoomerDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00267 return -1;
00268 }
00269
00270 jack_log("JackBoomerDriver::OpenInput input fInFD = %d", fInFD);
00271
00272 if (fExcl) {
00273 if (ioctl(fInFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) {
00274 jack_error("JackBoomerDriver::OpenInput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00275 goto error;
00276 }
00277 }
00278
00279 gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels);
00280 if (ioctl(fInFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) {
00281 jack_error("JackBoomerDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00282 goto error;
00283 }
00284
00285 cur_sample_format = fSampleFormat;
00286 if (ioctl(fInFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) {
00287 jack_error("JackBoomerDriver::OpenInput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00288 goto error;
00289 }
00290 if (cur_sample_format != fSampleFormat) {
00291 jack_info("JackBoomerDriver::OpenInput driver forced the sample format %ld", fSampleFormat);
00292 }
00293
00294 cur_capture_channels = fCaptureChannels;
00295 if (ioctl(fInFD, SNDCTL_DSP_CHANNELS, &fCaptureChannels) == -1) {
00296 jack_error("JackBoomerDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00297 goto error;
00298 }
00299 if (cur_capture_channels != fCaptureChannels) {
00300 jack_info("JackBoomerDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels);
00301 }
00302
00303 cur_sample_rate = fEngineControl->fSampleRate;
00304 if (ioctl(fInFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) {
00305 jack_error("JackBoomerDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00306 goto error;
00307 }
00308 if (cur_sample_rate != fEngineControl->fSampleRate) {
00309 jack_info("JackBoomerDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate);
00310 }
00311
00312
00313 fInputBufferSize = fEngineControl->fBufferSize * fSampleSize * fCaptureChannels;
00314
00315 fInputBuffer = (void*)calloc(fInputBufferSize, 1);
00316 assert(fInputBuffer);
00317 return 0;
00318
00319 error:
00320 ::close(fInFD);
00321 return -1;
00322 }
00323
00324 int JackBoomerDriver::OpenOutput()
00325 {
00326 int flags = 0;
00327 int gFragFormat;
00328 int cur_sample_format;
00329 int cur_playback_channels;
00330 jack_nframes_t cur_sample_rate;
00331
00332 if (fPlaybackChannels == 0)
00333 fPlaybackChannels = 2;
00334
00335 if ((fOutFD = open(fPlaybackDriverName, O_WRONLY | ((fExcl) ? O_EXCL : 0))) < 0) {
00336 jack_error("JackBoomerDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00337 return -1;
00338 }
00339
00340 jack_log("JackBoomerDriver::OpenOutput output fOutFD = %d", fOutFD);
00341
00342 if (fExcl) {
00343 if (ioctl(fOutFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) {
00344 jack_error("JackBoomerDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00345 goto error;
00346 }
00347 }
00348
00349 gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels);
00350 if (ioctl(fOutFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) {
00351 jack_error("JackBoomerDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00352 goto error;
00353 }
00354
00355 cur_sample_format = fSampleFormat;
00356 if (ioctl(fOutFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) {
00357 jack_error("JackBoomerDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00358 goto error;
00359 }
00360 if (cur_sample_format != fSampleFormat) {
00361 jack_info("JackBoomerDriver::OpenOutput driver forced the sample format %ld", fSampleFormat);
00362 }
00363
00364 cur_playback_channels = fPlaybackChannels;
00365 if (ioctl(fOutFD, SNDCTL_DSP_CHANNELS, &fPlaybackChannels) == -1) {
00366 jack_error("JackBoomerDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00367 goto error;
00368 }
00369 if (cur_playback_channels != fPlaybackChannels) {
00370 jack_info("JackBoomerDriver::OpenOutput driver forced the number of playback channels %ld", fPlaybackChannels);
00371 }
00372
00373 cur_sample_rate = fEngineControl->fSampleRate;
00374 if (ioctl(fOutFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) {
00375 jack_error("JackBoomerDriver::OpenOutput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00376 goto error;
00377 }
00378 if (cur_sample_rate != fEngineControl->fSampleRate) {
00379 jack_info("JackBoomerDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate);
00380 }
00381
00382
00383 fOutputBufferSize = fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels;
00384
00385 fOutputBuffer = (void*)calloc(fOutputBufferSize, 1);
00386 assert(fOutputBuffer);
00387 return 0;
00388
00389 error:
00390 ::close(fOutFD);
00391 return -1;
00392 }
00393
00394 int JackBoomerDriver::Open(jack_nframes_t nframes,
00395 int user_nperiods,
00396 jack_nframes_t samplerate,
00397 bool capturing,
00398 bool playing,
00399 int inchannels,
00400 int outchannels,
00401 bool excl,
00402 bool monitor,
00403 const char* capture_driver_uid,
00404 const char* playback_driver_uid,
00405 jack_nframes_t capture_latency,
00406 jack_nframes_t playback_latency,
00407 int bits, bool syncio)
00408 {
00409
00410 if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor,
00411 capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) {
00412 return -1;
00413 } else {
00414
00415 if (!fEngineControl->fSyncMode) {
00416 jack_error("Cannot run in asynchronous mode, use the -S parameter for jackd");
00417 return -1;
00418 }
00419
00420 fRWMode |= ((capturing) ? kRead : 0);
00421 fRWMode |= ((playing) ? kWrite : 0);
00422 fBits = bits;
00423 fExcl = excl;
00424 fNperiods = (user_nperiods == 0) ? 1 : user_nperiods ;
00425 fSyncIO = syncio;
00426
00427 #ifdef JACK_MONITOR
00428
00429 memset(&gCycleTable, 0, sizeof(gCycleTable));
00430 #endif
00431
00432 if (OpenAux() < 0) {
00433 Close();
00434 return -1;
00435 } else {
00436 return 0;
00437 }
00438 }
00439 }
00440
00441 int JackBoomerDriver::Close()
00442 {
00443 #ifdef JACK_MONITOR
00444 FILE* file = fopen("OSSProfiling.log", "w");
00445
00446 if (file) {
00447 jack_info("Writing OSS driver timing data....");
00448 for (int i = 1; i < std::min(gCycleReadCount, gCycleWriteCount); i++) {
00449 int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead;
00450 int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead;
00451 int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite;
00452 int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert;
00453 fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4);
00454 }
00455 fclose(file);
00456 } else {
00457 jack_error("JackBoomerDriver::Close : cannot open OSSProfiling.log file");
00458 }
00459
00460 file = fopen("TimingOSS.plot", "w");
00461
00462 if (file == NULL) {
00463 jack_error("JackBoomerDriver::Close cannot open TimingOSS.plot file");
00464 } else {
00465
00466 fprintf(file, "set grid\n");
00467 fprintf(file, "set title \"OSS audio driver timing\"\n");
00468 fprintf(file, "set xlabel \"audio cycles\"\n");
00469 fprintf(file, "set ylabel \"usec\"\n");
00470 fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
00471 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
00472 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
00473 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
00474
00475 fprintf(file, "set output 'TimingOSS.pdf\n");
00476 fprintf(file, "set terminal pdf\n");
00477
00478 fprintf(file, "set grid\n");
00479 fprintf(file, "set title \"OSS audio driver timing\"\n");
00480 fprintf(file, "set xlabel \"audio cycles\"\n");
00481 fprintf(file, "set ylabel \"usec\"\n");
00482 fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
00483 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
00484 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
00485 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
00486
00487 fclose(file);
00488 }
00489 #endif
00490 int res = JackAudioDriver::Close();
00491 CloseAux();
00492 return res;
00493 }
00494
00495 int JackBoomerDriver::OpenAux()
00496 {
00497 SetSampleFormat();
00498
00499 if ((fRWMode & kRead) && (OpenInput() < 0)) {
00500 return -1;
00501 }
00502
00503 if ((fRWMode & kWrite) && (OpenOutput() < 0)) {
00504 return -1;
00505 }
00506
00507 DisplayDeviceInfo();
00508 return 0;
00509 }
00510
00511 void JackBoomerDriver::CloseAux()
00512 {
00513 if (fRWMode & kRead && fInFD >= 0) {
00514 close(fInFD);
00515 fInFD = -1;
00516 }
00517
00518 if (fRWMode & kWrite && fOutFD >= 0) {
00519 close(fOutFD);
00520 fOutFD = -1;
00521 }
00522
00523 if (fInputBuffer)
00524 free(fInputBuffer);
00525 fInputBuffer = NULL;
00526
00527 if (fOutputBuffer)
00528 free(fOutputBuffer);
00529 fOutputBuffer = NULL;
00530 }
00531
00532 int JackBoomerDriver::Start()
00533 {
00534 jack_log("JackBoomerDriver::Start");
00535 JackAudioDriver::Start();
00536
00537
00538 if (fInFD >= 0 && fOutFD >= 0 && fSyncIO) {
00539
00540 jack_log("JackBoomerDriver::Start sync input/output");
00541
00542
00543 int id;
00544 oss_syncgroup group;
00545 group.id = 0;
00546
00547 group.mode = PCM_ENABLE_INPUT;
00548 if (ioctl(fInFD, SNDCTL_DSP_SYNCGROUP, &group) == -1)
00549 jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCGROUP : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00550
00551 group.mode = PCM_ENABLE_OUTPUT;
00552 if (ioctl(fOutFD, SNDCTL_DSP_SYNCGROUP, &group) == -1)
00553 jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCGROUP : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00554
00555
00556 char* silence_buf = (char*)malloc(fFragmentSize);
00557 memset(silence_buf, 0, fFragmentSize);
00558
00559 jack_log ("JackBoomerDriver::Start prefill size = %d", fFragmentSize);
00560
00561 for (int i = 0; i < 2; i++) {
00562 ssize_t count = ::write(fOutFD, silence_buf, fFragmentSize);
00563 if (count < (int)fFragmentSize) {
00564 jack_error("JackBoomerDriver::Start error bytes written = %ld", count);
00565 }
00566 }
00567
00568 free(silence_buf);
00569
00570
00571 id = group.id;
00572
00573 if (ioctl(fInFD, SNDCTL_DSP_SYNCSTART, &id) == -1)
00574 jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCSTART : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00575
00576 } else if (fOutFD >= 0) {
00577
00578
00579 memset(fOutputBuffer, 0, fOutputBufferSize);
00580
00581
00582 for (int i = 0; i < fNperiods; i++) {
00583 ssize_t count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize);
00584 if (count < (int)fOutputBufferSize) {
00585 jack_error("JackBoomerDriver::Start error bytes written = %ld", count);
00586 }
00587 }
00588 }
00589
00590
00591 if (fInFD >= 0) {
00592 if (fInputThread.StartSync() < 0) {
00593 jack_error("Cannot start input thread");
00594 return -1;
00595 }
00596 }
00597
00598
00599 if (fOutFD >= 0) {
00600 if (fOutputThread.StartSync() < 0) {
00601 jack_error("Cannot start output thread");
00602 return -1;
00603 }
00604 }
00605
00606 return 0;
00607 }
00608
00609 int JackBoomerDriver::Stop()
00610 {
00611
00612 if (fInFD >= 0) {
00613 fInputThread.Kill();
00614 }
00615
00616
00617 if (fOutFD >= 0) {
00618 fOutputThread.Kill();
00619 }
00620
00621 return 0;
00622 }
00623
00624 bool JackBoomerDriver::JackBoomerDriverInput::Init()
00625 {
00626 if (fDriver->IsRealTime()) {
00627 jack_log("JackBoomerDriverInput::Init IsRealTime");
00628 if (fDriver->fInputThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) {
00629 jack_error("AcquireRealTime error");
00630 } else {
00631 set_threaded_log_function();
00632 }
00633 }
00634
00635 return true;
00636 }
00637
00638
00639 bool JackBoomerDriver::JackBoomerDriverInput::Execute()
00640 {
00641
00642 #ifdef JACK_MONITOR
00643 gCycleTable.fTable[gCycleReadCount].fBeforeRead = GetMicroSeconds();
00644 #endif
00645
00646 audio_errinfo ei_in;
00647 ssize_t count = ::read(fDriver->fInFD, fDriver->fInputBuffer, fDriver->fInputBufferSize);
00648
00649 #ifdef JACK_MONITOR
00650 if (count > 0 && count != (int)fDriver->fInputBufferSize)
00651 jack_log("JackBoomerDriverInput::Execute count = %ld", count / (fDriver->fSampleSize * fDriver->fCaptureChannels));
00652 gCycleTable.fTable[gCycleReadCount].fAfterRead = GetMicroSeconds();
00653 #endif
00654
00655
00656 if (ioctl(fDriver->fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) {
00657
00658 if (ei_in.rec_overruns > 0 ) {
00659 jack_error("JackBoomerDriverInput::Execute overruns");
00660 jack_time_t cur_time = GetMicroSeconds();
00661 fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst));
00662 }
00663
00664 if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) {
00665 jack_error("%d OSS rec event(s), last=%05d:%d", ei_in.rec_errorcount, ei_in.rec_lasterror, ei_in.rec_errorparm);
00666 }
00667 }
00668
00669 if (count < 0) {
00670 jack_log("JackBoomerDriverInput::Execute error = %s", strerror(errno));
00671 } else if (count < (int)fDriver->fInputBufferSize) {
00672 jack_error("JackBoomerDriverInput::Execute error bytes read = %ld", count);
00673 } else {
00674
00675
00676 fDriver->CycleTakeBeginTime();
00677 for (int i = 0; i < fDriver->fCaptureChannels; i++) {
00678 if (fDriver->fGraphManager->GetConnectionsNum(fDriver->fCapturePortList[i]) > 0) {
00679 CopyAndConvertIn(fDriver->GetInputBuffer(i),
00680 fDriver->fInputBuffer,
00681 fDriver->fEngineControl->fBufferSize,
00682 i,
00683 fDriver->fCaptureChannels * fDriver->fSampleSize,
00684 fDriver->fBits);
00685 }
00686 }
00687
00688 #ifdef JACK_MONITOR
00689 gCycleTable.fTable[gCycleReadCount].fAfterReadConvert = GetMicroSeconds();
00690 gCycleReadCount = (gCycleReadCount == CYCLE_POINTS - 1) ? gCycleReadCount: gCycleReadCount + 1;
00691 #endif
00692 }
00693
00694
00695 if (fDriver->fInFD >= 0 && fDriver->fOutFD >= 0) {
00696 fDriver->SynchronizeRead();
00697 } else {
00698
00699 fDriver->Process();
00700 }
00701 return true;
00702 }
00703
00704 bool JackBoomerDriver::JackBoomerDriverOutput::Init()
00705 {
00706 if (fDriver->IsRealTime()) {
00707 jack_log("JackBoomerDriverOutput::Init IsRealTime");
00708 if (fDriver->fOutputThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) {
00709 jack_error("AcquireRealTime error");
00710 } else {
00711 set_threaded_log_function();
00712 }
00713 }
00714
00715 int delay;
00716 if (ioctl(fDriver->fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) {
00717 jack_error("JackBoomerDriverOutput::Init error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno);
00718 }
00719
00720 delay /= fDriver->fSampleSize * fDriver->fPlaybackChannels;
00721 jack_info("JackBoomerDriverOutput::Init output latency frames = %ld", delay);
00722
00723 return true;
00724 }
00725
00726
00727 bool JackBoomerDriver::JackBoomerDriverOutput::Execute()
00728 {
00729 memset(fDriver->fOutputBuffer, 0, fDriver->fOutputBufferSize);
00730
00731 #ifdef JACK_MONITOR
00732 gCycleTable.fTable[gCycleWriteCount].fBeforeWriteConvert = GetMicroSeconds();
00733 #endif
00734
00735 for (int i = 0; i < fDriver->fPlaybackChannels; i++) {
00736 if (fDriver->fGraphManager->GetConnectionsNum(fDriver->fPlaybackPortList[i]) > 0) {
00737 CopyAndConvertOut(fDriver->fOutputBuffer,
00738 fDriver->GetOutputBuffer(i),
00739 fDriver->fEngineControl->fBufferSize,
00740 i,
00741 fDriver->fPlaybackChannels * fDriver->fSampleSize,
00742 fDriver->fBits);
00743 }
00744 }
00745
00746 #ifdef JACK_MONITOR
00747 gCycleTable.fTable[gCycleWriteCount].fBeforeWrite = GetMicroSeconds();
00748 #endif
00749
00750 ssize_t count = ::write(fDriver->fOutFD, fDriver->fOutputBuffer, fDriver->fOutputBufferSize);
00751
00752 #ifdef JACK_MONITOR
00753 if (count > 0 && count != (int)fDriver->fOutputBufferSize)
00754 jack_log("JackBoomerDriverOutput::Execute count = %ld", count / (fDriver->fSampleSize * fDriver->fPlaybackChannels));
00755 gCycleTable.fTable[gCycleWriteCount].fAfterWrite = GetMicroSeconds();
00756 gCycleWriteCount = (gCycleWriteCount == CYCLE_POINTS - 1) ? gCycleWriteCount: gCycleWriteCount + 1;
00757 #endif
00758
00759
00760 audio_errinfo ei_out;
00761 if (ioctl(fDriver->fOutFD, SNDCTL_DSP_GETERROR, &ei_out) == 0) {
00762
00763 if (ei_out.play_underruns > 0) {
00764 jack_error("JackBoomerDriverOutput::Execute underruns");
00765 jack_time_t cur_time = GetMicroSeconds();
00766 fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst));
00767 }
00768
00769 if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) {
00770 jack_error("%d OSS play event(s), last=%05d:%d",ei_out.play_errorcount, ei_out.play_lasterror, ei_out.play_errorparm);
00771 }
00772 }
00773
00774 if (count < 0) {
00775 jack_log("JackBoomerDriverOutput::Execute error = %s", strerror(errno));
00776 } else if (count < (int)fDriver->fOutputBufferSize) {
00777 jack_error("JackBoomerDriverOutput::Execute error bytes written = %ld", count);
00778 }
00779
00780
00781 if (fDriver->fInFD >= 0 && fDriver->fOutFD >= 0) {
00782 fDriver->SynchronizeWrite();
00783 } else {
00784
00785 fDriver->CycleTakeBeginTime();
00786 fDriver->Process();
00787 }
00788 return true;
00789 }
00790
00791 void JackBoomerDriver::SynchronizeRead()
00792 {
00793 sem_wait(&fWriteSema);
00794 Process();
00795 sem_post(&fReadSema);
00796 }
00797
00798 void JackBoomerDriver::SynchronizeWrite()
00799 {
00800 sem_post(&fWriteSema);
00801 sem_wait(&fReadSema);
00802 }
00803
00804 int JackBoomerDriver::SetBufferSize(jack_nframes_t buffer_size)
00805 {
00806 CloseAux();
00807 JackAudioDriver::SetBufferSize(buffer_size);
00808 return OpenAux();
00809 }
00810
00811 }
00812
00813 #ifdef __cplusplus
00814 extern "C"
00815 {
00816 #endif
00817
00818 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
00819 {
00820 jack_driver_desc_t * desc;
00821 jack_driver_desc_filler_t filler;
00822 jack_driver_param_value_t value;
00823
00824 desc = jack_driver_descriptor_construct("boomer", JackDriverMaster, "Boomer/OSS API based audio backend", &filler);
00825
00826 value.ui = OSS_DRIVER_DEF_FS;
00827 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
00828
00829 value.ui = OSS_DRIVER_DEF_BLKSIZE;
00830 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
00831
00832 value.ui = OSS_DRIVER_DEF_NPERIODS;
00833 jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods to prefill output buffer", NULL);
00834
00835 value.i = OSS_DRIVER_DEF_BITS;
00836 jack_driver_descriptor_add_parameter(desc, &filler, "wordlength", 'w', JackDriverParamInt, &value, NULL, "Word length", NULL);
00837
00838 value.ui = OSS_DRIVER_DEF_INS;
00839 jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Capture channels", NULL);
00840
00841 value.ui = OSS_DRIVER_DEF_OUTS;
00842 jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Playback channels", NULL);
00843
00844 value.i = false;
00845 jack_driver_descriptor_add_parameter(desc, &filler, "excl", 'e', JackDriverParamBool, &value, NULL, "Exclusif (O_EXCL) access mode", NULL);
00846
00847 strcpy(value.str, OSS_DRIVER_DEF_DEV);
00848 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input device", NULL);
00849 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output device", NULL);
00850 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "OSS device name", NULL);
00851
00852 value.ui = 0;
00853 jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency", NULL);
00854 jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency", NULL);
00855
00856 value.i = false;
00857 jack_driver_descriptor_add_parameter(desc, &filler, "sync-io", 'S', JackDriverParamBool, &value, NULL, "In duplex mode, synchronize input and output", NULL);
00858
00859 return desc;
00860 }
00861
00862 EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
00863 {
00864 int bits = OSS_DRIVER_DEF_BITS;
00865 jack_nframes_t srate = OSS_DRIVER_DEF_FS;
00866 jack_nframes_t frames_per_interrupt = OSS_DRIVER_DEF_BLKSIZE;
00867 const char* capture_pcm_name = OSS_DRIVER_DEF_DEV;
00868 const char* playback_pcm_name = OSS_DRIVER_DEF_DEV;
00869 bool capture = false;
00870 bool playback = false;
00871 int chan_in = 0;
00872 int chan_out = 0;
00873 bool monitor = false;
00874 bool excl = false;
00875 bool syncio = false;
00876 unsigned int nperiods = OSS_DRIVER_DEF_NPERIODS;
00877 const JSList *node;
00878 const jack_driver_param_t *param;
00879 jack_nframes_t systemic_input_latency = 0;
00880 jack_nframes_t systemic_output_latency = 0;
00881
00882 for (node = params; node; node = jack_slist_next(node)) {
00883
00884 param = (const jack_driver_param_t *)node->data;
00885
00886 switch (param->character) {
00887
00888 case 'r':
00889 srate = param->value.ui;
00890 break;
00891
00892 case 'p':
00893 frames_per_interrupt = (unsigned int)param->value.ui;
00894 break;
00895
00896 case 'n':
00897 nperiods = (unsigned int)param->value.ui;
00898 break;
00899
00900 case 'w':
00901 bits = param->value.i;
00902 break;
00903
00904 case 'i':
00905 chan_in = (int)param->value.ui;
00906 break;
00907
00908 case 'o':
00909 chan_out = (int)param->value.ui;
00910 break;
00911
00912 case 'C':
00913 capture = true;
00914 if (strcmp(param->value.str, "none") != 0) {
00915 capture_pcm_name = param->value.str;
00916 }
00917 break;
00918
00919 case 'P':
00920 playback = true;
00921 if (strcmp(param->value.str, "none") != 0) {
00922 playback_pcm_name = param->value.str;
00923 }
00924 break;
00925
00926 case 'd':
00927 playback_pcm_name = param->value.str;
00928 capture_pcm_name = param->value.str;
00929 break;
00930
00931 case 'e':
00932 excl = true;
00933 break;
00934
00935 case 'I':
00936 systemic_input_latency = param->value.ui;
00937 break;
00938
00939 case 'O':
00940 systemic_output_latency = param->value.ui;
00941 break;
00942
00943 case 'S':
00944 syncio = true;
00945 break;
00946 }
00947 }
00948
00949
00950 if (!capture && !playback) {
00951 capture = true;
00952 playback = true;
00953 }
00954
00955 Jack::JackBoomerDriver* boomer_driver = new Jack::JackBoomerDriver("system", "boomer", engine, table);
00956
00957
00958 if (boomer_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, excl,
00959 monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, syncio) == 0) {
00960 return boomer_driver;
00961 } else {
00962 delete boomer_driver;
00963 return NULL;
00964 }
00965 }
00966
00967 #ifdef __cplusplus
00968 }
00969 #endif