1 /*
2 Copyright (C) 2003-2007 Jussi Laako <jussi@sonarnerd.net>
3 Copyright (C) 2008 Grame & RTL 2008
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "driver_interface.h"
22 #include "JackThreadedDriver.h"
23 #include "JackDriverLoader.h"
24 #include "JackOSSDriver.h"
25 #include "JackEngineControl.h"
26 #include "JackGraphManager.h"
27 #include "JackError.h"
28 #include "JackTime.h"
29 #include "JackShmMem.h"
30 #include "memops.h"
31
32 #include <sys/ioctl.h>
33 #include <sys/soundcard.h>
34 #include <fcntl.h>
35 #include <iostream>
36 #include <assert.h>
37 #include <stdio.h>
38
39 using namespace std;
40
41 namespace
42 {
43
TimeToFrames(jack_time_t time,jack_nframes_t sample_rate)44 inline jack_nframes_t TimeToFrames(jack_time_t time, jack_nframes_t sample_rate) {
45 return ((time * sample_rate) + 500000ULL) / 1000000ULL;
46 }
47
TimeToOffset(jack_time_t time1,jack_time_t time2,jack_nframes_t sample_rate)48 inline long long TimeToOffset(jack_time_t time1, jack_time_t time2, jack_nframes_t sample_rate)
49 {
50 if (time2 > time1) {
51 return TimeToFrames(time2 - time1, sample_rate);
52 } else {
53 return 0LL - TimeToFrames(time1 - time2, sample_rate);
54 }
55 }
56
FramesToTime(jack_nframes_t frames,jack_nframes_t sample_rate)57 inline jack_time_t FramesToTime(jack_nframes_t frames, jack_nframes_t sample_rate) {
58 return ((frames * 1000000ULL) + (sample_rate / 2ULL)) / sample_rate;
59 }
60
RoundUp(jack_nframes_t frames,jack_nframes_t block)61 inline jack_nframes_t RoundUp(jack_nframes_t frames, jack_nframes_t block) {
62 if (block > 0) {
63 frames += (block - 1);
64 frames -= (frames % block);
65 }
66 return frames;
67 }
68
RoundDown(jack_time_t time,jack_time_t interval)69 inline jack_time_t RoundDown(jack_time_t time, jack_time_t interval) {
70 if (interval > 0) {
71 time -= (time % interval);
72 }
73 return time;
74 }
75
GetSampleFormat(int bits)76 int GetSampleFormat(int bits)
77 {
78 switch(bits) {
79 // Native-endian signed 32 bit samples.
80 case 32:
81 return AFMT_S32_NE;
82 // Native-endian signed 24 bit (packed) samples.
83 case 24:
84 return AFMT_S24_NE;
85 // Native-endian signed 16 bit samples, used by default.
86 case 16:
87 default:
88 return AFMT_S16_NE;
89 }
90 }
91
GetSampleSize(int format)92 unsigned int GetSampleSize(int format)
93 {
94 switch(format) {
95 // Native-endian signed 32 bit samples.
96 case AFMT_S32_NE:
97 return 4;
98 // Native-endian signed 24 bit (packed) samples.
99 case AFMT_S24_NE:
100 return 3;
101 // Native-endian signed 16 bit samples.
102 case AFMT_S16_NE:
103 return 2;
104 // Unsupported sample format.
105 default:
106 return 0;
107 }
108 }
109
UpToPower2(int x)110 inline int UpToPower2(int x)
111 {
112 int r = 0;
113 while ((1 << r) < x)
114 r++;
115 return r;
116 }
117
118 }
119
120 namespace Jack
121 {
122
123 #ifdef JACK_MONITOR
124
125 #define CYCLE_POINTS 500000
126
127 struct OSSCycle {
128 jack_time_t fBeforeRead;
129 jack_time_t fAfterRead;
130 jack_time_t fAfterReadConvert;
131 jack_time_t fBeforeWrite;
132 jack_time_t fAfterWrite;
133 jack_time_t fBeforeWriteConvert;
134 };
135
136 struct OSSCycleTable {
137 jack_time_t fBeforeFirstWrite;
138 jack_time_t fAfterFirstWrite;
139 OSSCycle fTable[CYCLE_POINTS];
140 };
141
142 OSSCycleTable gCycleTable;
143 int gCycleCount = 0;
144
145 #endif
146
CopyAndConvertIn(jack_sample_t * dst,void * src,size_t nframes,int channel,int chcount,int bits)147 static inline void CopyAndConvertIn(jack_sample_t *dst, void *src, size_t nframes, int channel, int chcount, int bits)
148 {
149 switch (bits) {
150
151 case 16: {
152 signed short *s16src = (signed short*)src;
153 s16src += channel;
154 sample_move_dS_s16(dst, (char*)s16src, nframes, chcount<<1);
155 break;
156 }
157 case 24: {
158 char *s24src = (char*)src;
159 s24src += channel * 3;
160 sample_move_dS_s24(dst, s24src, nframes, chcount*3);
161 break;
162 }
163 case 32: {
164 signed int *s32src = (signed int*)src;
165 s32src += channel;
166 sample_move_dS_s32u24(dst, (char*)s32src, nframes, chcount<<2);
167 break;
168 }
169 }
170 }
171
CopyAndConvertOut(void * dst,jack_sample_t * src,size_t nframes,int channel,int chcount,int bits)172 static inline void CopyAndConvertOut(void *dst, jack_sample_t *src, size_t nframes, int channel, int chcount, int bits)
173 {
174 switch (bits) {
175
176 case 16: {
177 signed short *s16dst = (signed short*)dst;
178 s16dst += channel;
179 sample_move_d16_sS((char*)s16dst, src, nframes, chcount<<1, NULL); // No dithering for now...
180 break;
181 }
182 case 24: {
183 char *s24dst = (char*)dst;
184 s24dst += channel * 3;
185 sample_move_d24_sS(s24dst, src, nframes, chcount*3, NULL);
186 break;
187 }
188 case 32: {
189 signed int *s32dst = (signed int*)dst;
190 s32dst += channel;
191 sample_move_d32u24_sS((char*)s32dst, src, nframes, chcount<<2, NULL);
192 break;
193 }
194 }
195 }
196
DisplayDeviceInfo()197 void JackOSSDriver::DisplayDeviceInfo()
198 {
199 audio_buf_info info;
200 oss_audioinfo ai_in, ai_out;
201 memset(&info, 0, sizeof(audio_buf_info));
202 int cap = 0;
203
204 // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html
205 jack_info("Audio Interface Description :");
206 jack_info("Sampling Frequency : %d, Sample Size : %d", fEngineControl->fSampleRate, fInSampleSize * 8);
207
208 if (fPlayback) {
209
210 oss_sysinfo si;
211 if (ioctl(fOutFD, OSS_SYSINFO, &si) == -1) {
212 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
213 } else {
214 jack_info("OSS product %s", si.product);
215 jack_info("OSS version %s", si.version);
216 jack_info("OSS version num %d", si.versionnum);
217 jack_info("OSS numaudios %d", si.numaudios);
218 jack_info("OSS numaudioengines %d", si.numaudioengines);
219 jack_info("OSS numcards %d", si.numcards);
220 }
221
222 jack_info("Output capabilities - %d channels : ", fPlaybackChannels);
223 jack_info("Output block size = %d", fOutputBufferSize);
224
225 if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1) {
226 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
227 } else {
228 jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
229 info.fragments, info.fragstotal, info.fragsize, info.bytes);
230 }
231
232 if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) {
233 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
234 } else {
235 if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX");
236 if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME");
237 if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH");
238 if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC");
239 if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER");
240 if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP");
241 if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI");
242 if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND");
243 }
244 }
245
246 if (fCapture) {
247
248 oss_sysinfo si;
249 if (ioctl(fInFD, OSS_SYSINFO, &si) == -1) {
250 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
251 } else {
252 jack_info("OSS product %s", si.product);
253 jack_info("OSS version %s", si.version);
254 jack_info("OSS version num %d", si.versionnum);
255 jack_info("OSS numaudios %d", si.numaudios);
256 jack_info("OSS numaudioengines %d", si.numaudioengines);
257 jack_info("OSS numcards %d", si.numcards);
258 }
259
260 jack_info("Input capabilities - %d channels : ", fCaptureChannels);
261 jack_info("Input block size = %d", fInputBufferSize);
262
263 if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) {
264 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
265 } else {
266 jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
267 info.fragments, info.fragstotal, info.fragsize, info.bytes);
268 }
269
270 if (ioctl(fInFD, SNDCTL_DSP_GETCAPS, &cap) == -1) {
271 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno);
272 } else {
273 if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX");
274 if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME");
275 if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH");
276 if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC");
277 if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER");
278 if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP");
279 if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI");
280 if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND");
281 }
282 }
283
284 if (ai_in.rate_source != ai_out.rate_source) {
285 jack_info("Warning : input and output are not necessarily driven by the same clock!");
286 }
287 }
288
ProbeInBlockSize()289 int JackOSSDriver::ProbeInBlockSize()
290 {
291 jack_nframes_t blocks[8] = {0, 0, 0, 0, 0, 0, 0, 0};
292 int probes = 0;
293 int ret = 0;
294 // Default values in case of an error.
295 fInMeanStep = fEngineControl->fBufferSize;
296 fInBlockSize = 1;
297
298 if (fInFD > 0) {
299 // Read one frame into a new hardware block so we can check its size.
300 // Repeat that for multiple probes, sometimes the first reads differ.
301 jack_nframes_t frames = 1;
302 for (int p = 0; p < 8 && frames > 0; ++p) {
303 ret = Discard(frames);
304 frames = 0;
305 if (ret == 0) {
306 oss_count_t ptr;
307 if (ioctl(fInFD, SNDCTL_DSP_CURRENT_IPTR, &ptr) == 0 && ptr.fifo_samples > 0) {
308 // Success, store probed hardware block size for later.
309 blocks[p] = 1U + ptr.fifo_samples;
310 ++probes;
311 // Proceed by reading one frame into the next hardware block.
312 frames = blocks[p];
313 }
314 } else {
315 // Read error - abort.
316 jack_error("JackOSSDriver::ProbeInBlockSize read failed with %d", ret);
317 }
318 }
319
320 // Stop recording.
321 ioctl(fInFD, SNDCTL_DSP_HALT_INPUT, NULL);
322 }
323
324 if (probes == 8) {
325 // Compute mean block size of the last six probes.
326 jack_nframes_t sum = 0;
327 for (int p = 2; p < 8; ++p) {
328 jack_info("JackOSSDriver::ProbeInBlockSize read hardware block of %d", blocks[p]);
329 sum += blocks[p];
330 }
331 fInMeanStep = sum / 6;
332
333 // Check that none of the probed block sizes deviates too much.
334 jack_nframes_t slack = fInMeanStep / 16;
335 bool strict = true;
336 for (int p = 2; p < 8; ++p) {
337 strict = strict && (blocks[p] > fInMeanStep - slack) && (blocks[p] < fInMeanStep + slack);
338 }
339
340 if (strict && fInMeanStep <= fEngineControl->fBufferSize) {
341 // Regular hardware block size, use it for rounding.
342 jack_info("JackOSSDriver::ProbeInBlockSize hardware blocks are %d frames", fInMeanStep);
343 fInBlockSize = fInMeanStep;
344 } else {
345 jack_info("JackOSSDriver::ProbeInBlockSize irregular hardware block sizes");
346 jack_info("JackOSSDriver::ProbeInBlockSize mean hardware block was %d frames", fInMeanStep);
347 }
348
349 if (fInBlockSize > fEngineControl->fBufferSize / 2) {
350 jack_info("JackOSSDriver::ProbeInBlockSize less than two hardware blocks per cycle");
351 jack_info("JackOSSDriver::ProbeInBlockSize for best results make period a multiple of %d", fInBlockSize);
352 }
353
354 if (fInMeanStep > fEngineControl->fBufferSize) {
355 jack_error("JackOSSDriver::ProbeInBlockSize period is too small, hardware blocks of %d frames", fInMeanStep);
356 return -1;
357 }
358 }
359
360 return ret;
361 }
362
ProbeOutBlockSize()363 int JackOSSDriver::ProbeOutBlockSize()
364 {
365 jack_nframes_t blocks[8] = {0, 0, 0, 0, 0, 0, 0, 0};
366 int probes = 0;
367 int ret = 0;
368 // Default values in case of an error.
369 fOutMeanStep = fEngineControl->fBufferSize;
370 fOutBlockSize = 1;
371
372 if (fOutFD) {
373 // Write one frame over the low water mark, then check the consumed block size.
374 // Repeat that for multiple probes, sometimes the initial ones differ.
375 jack_nframes_t mark = fNperiods * fEngineControl->fBufferSize;
376 WriteSilence(mark + 1);
377 for (int p = 0; p < 8 && ret >= 0; ++p) {
378 pollfd poll_fd;
379 poll_fd.fd = fOutFD;
380 poll_fd.events = POLLOUT;
381 ret = poll(&poll_fd, 1, 500);
382 if (ret < 0) {
383 jack_error("JackOSSDriver::ProbeOutBlockSize poll failed with %d", ret);
384 break;
385 }
386 if (poll_fd.revents & POLLOUT) {
387 oss_count_t ptr;
388 if (ioctl(fOutFD, SNDCTL_DSP_CURRENT_OPTR, &ptr) != -1 && ptr.fifo_samples >= 0) {
389 // Success, store probed hardware block size for later.
390 blocks[p] = mark + 1 - ptr.fifo_samples;
391 ++probes;
392 // Proceed by writing one frame over the low water mark.
393 WriteSilence(blocks[p]);
394 }
395 poll_fd.revents = 0;
396 }
397 }
398
399 // Stop playback.
400 ioctl(fOutFD, SNDCTL_DSP_HALT_INPUT, NULL);
401 }
402
403 if (probes == 8) {
404 // Compute mean and maximum block size of the last six probes.
405 jack_nframes_t sum = 0;
406 for (int p = 2; p < 8; ++p) {
407 jack_info("JackOSSDriver::ProbeOutBlockSize write hardware block of %d", blocks[p]);
408 sum += blocks[p];
409 }
410 fOutMeanStep = sum / 6;
411
412 // Check that none of the probed block sizes deviates too much.
413 jack_nframes_t slack = fOutMeanStep / 16;
414 bool strict = true;
415 for (int p = 2; p < 8; ++p) {
416 strict = strict && (blocks[p] > fOutMeanStep - slack) && (blocks[p] < fOutMeanStep + slack);
417 }
418
419 if (strict && fOutMeanStep <= fEngineControl->fBufferSize) {
420 // Regular hardware block size, use it for rounding.
421 jack_info("JackOSSDriver::ProbeOutBlockSize hardware blocks are %d frames", fOutMeanStep);
422 fOutBlockSize = fOutMeanStep;
423 } else {
424 jack_info("JackOSSDriver::ProbeOutBlockSize irregular hardware block sizes");
425 jack_info("JackOSSDriver::ProbeOutBlockSize mean hardware block was %d frames", fOutMeanStep);
426 }
427
428 if (fOutBlockSize > fEngineControl->fBufferSize / 2) {
429 jack_info("JackOSSDriver::ProbeOutBlockSize less than two hardware blocks per cycle");
430 jack_info("JackOSSDriver::ProbeOutBlockSize for best results make period a multiple of %d", fOutBlockSize);
431 }
432
433 if (fOutMeanStep > fEngineControl->fBufferSize) {
434 jack_error("JackOSSDriver::ProbeOutBlockSize period is too small, hardware blocks of %d frames", fOutMeanStep);
435 return -1;
436 }
437 }
438
439 return ret;
440 }
441
Discard(jack_nframes_t frames)442 int JackOSSDriver::Discard(jack_nframes_t frames)
443 {
444 if (fInFD < 0) {
445 return -1;
446 }
447
448 // Read frames from OSS capture buffer to be discarded.
449 ssize_t size = frames * fInSampleSize * fCaptureChannels;
450 while (size > 0) {
451 ssize_t chunk = (size > fInputBufferSize) ? fInputBufferSize : size;
452 ssize_t count = ::read(fInFD, fInputBuffer, chunk);
453 if (count <= 0) {
454 jack_error("JackOSSDriver::Discard error bytes read = %ld", count);
455 return -1;
456 }
457 fOSSReadOffset += count / (fInSampleSize * fCaptureChannels);
458 size -= count;
459 }
460 return 0;
461 }
462
WriteSilence(jack_nframes_t frames)463 int JackOSSDriver::WriteSilence(jack_nframes_t frames)
464 {
465 if (fOutFD < 0) {
466 return -1;
467 }
468
469 // Prefill OSS playback buffer, write some periods of silence.
470 memset(fOutputBuffer, 0, fOutputBufferSize);
471 ssize_t size = frames * fOutSampleSize * fPlaybackChannels;
472 while (size > 0) {
473 ssize_t chunk = (size > fOutputBufferSize) ? fOutputBufferSize : size;
474 ssize_t count = ::write(fOutFD, fOutputBuffer, chunk);
475 if (count <= 0) {
476 jack_error("JackOSSDriver::WriteSilence error bytes written = %ld", count);
477 return -1;
478 }
479 fOSSWriteOffset += (count / (fOutSampleSize * fPlaybackChannels));
480 size -= count;
481 }
482 return 0;
483 }
484
WaitAndSync()485 int JackOSSDriver::WaitAndSync()
486 {
487 oss_count_t ptr = {0, 0, {0}};
488 if (fInFD > 0 && fOSSReadSync != 0) {
489 // Predict time of next capture sync (poll() return).
490 if (fOSSReadOffset + fEngineControl->fBufferSize > 0) {
491 jack_nframes_t frames = fOSSReadOffset + fEngineControl->fBufferSize;
492 jack_nframes_t rounded = RoundUp(frames, fInBlockSize);
493 fOSSReadSync += FramesToTime(rounded, fEngineControl->fSampleRate);
494 fOSSReadOffset -= rounded;
495 }
496 }
497 if (fOutFD > 0 && fOSSWriteSync != 0) {
498 // Predict time of next playback sync (poll() return).
499 if (fOSSWriteOffset > fNperiods * fEngineControl->fBufferSize) {
500 jack_nframes_t frames = fOSSWriteOffset - fNperiods * fEngineControl->fBufferSize;
501 jack_nframes_t rounded = RoundUp(frames, fOutBlockSize);
502 fOSSWriteSync += FramesToTime(rounded, fEngineControl->fSampleRate);
503 fOSSWriteOffset -= rounded;
504 }
505 }
506 jack_time_t poll_start = GetMicroSeconds();
507 // Poll until recording and playback buffer are ready for this cycle.
508 pollfd poll_fd[2];
509 poll_fd[0].fd = fInFD;
510 if (fInFD > 0 && (fForceSync || poll_start < fOSSReadSync)) {
511 poll_fd[0].events = POLLIN;
512 } else {
513 poll_fd[0].events = 0;
514 }
515 poll_fd[1].fd = fOutFD;
516 if (fOutFD > 0 && (fForceSync || poll_start < fOSSWriteSync)) {
517 poll_fd[1].events = POLLOUT;
518 } else {
519 poll_fd[1].events = 0;
520 }
521 while (poll_fd[0].events != 0 || poll_fd[1].events != 0) {
522 poll_fd[0].revents = 0;
523 poll_fd[1].revents = 0;
524 int ret = poll(poll_fd, 2, 500);
525 jack_time_t now = GetMicroSeconds();
526 if (ret <= 0) {
527 jack_error("JackOSSDriver::WaitAndSync poll failed with %d after %ld us", ret, now - poll_start);
528 return ret;
529 }
530 if (poll_fd[0].revents & POLLIN) {
531 // Check the excess recording frames.
532 if (ioctl(fInFD, SNDCTL_DSP_CURRENT_IPTR, &ptr) != -1 && ptr.fifo_samples >= 0) {
533 if (fInBlockSize <= 1) {
534 // Irregular block size, let sync time converge slowly when late.
535 fOSSReadSync = min(fOSSReadSync, now) / 2 + now / 2;
536 fOSSReadOffset = -ptr.fifo_samples;
537 } else if (ptr.fifo_samples - fEngineControl->fBufferSize >= fInBlockSize) {
538 // Too late for a reliable sync, make sure sync time is not in the future.
539 if (now < fOSSReadSync) {
540 fOSSReadOffset = -ptr.fifo_samples;
541 jack_info("JackOSSDriver::WaitAndSync capture %ld sync %ld early", fOSSReadOffset, fOSSReadSync - now);
542 fOSSReadSync = now;
543 }
544 } else if (fForceSync) {
545 // Uncertain previous sync, just use sync time directly.
546 fOSSReadSync = now;
547 fOSSReadOffset = -ptr.fifo_samples;
548 } else {
549 // Adapt expected sync time when early or late - in whole block intervals.
550 // Account for some speed drift, but otherwise round down to earlier interval.
551 jack_time_t interval = FramesToTime(fInBlockSize, fEngineControl->fSampleRate);
552 jack_time_t remainder = fOSSReadSync % interval;
553 jack_time_t max_drift = interval / 4;
554 jack_time_t rounded = RoundDown((now - remainder) + max_drift, interval) + remainder;
555 // Let sync time converge slowly when late, prefer earlier sync times.
556 fOSSReadSync = min(rounded, now) / 2 + now / 2;
557 fOSSReadOffset = -ptr.fifo_samples;
558 }
559 }
560 poll_fd[0].events = 0;
561 }
562 if (poll_fd[1].revents & POLLOUT) {
563 // Check the remaining playback frames.
564 if (ioctl(fOutFD, SNDCTL_DSP_CURRENT_OPTR, &ptr) != -1 && ptr.fifo_samples >= 0) {
565 if (fOutBlockSize <= 1) {
566 // Irregular block size, let sync time converge slowly when late.
567 fOSSWriteSync = min(fOSSWriteSync, now) / 2 + now / 2;
568 fOSSWriteOffset = ptr.fifo_samples;
569 } else if (ptr.fifo_samples + fOutBlockSize <= fNperiods * fEngineControl->fBufferSize) {
570 // Too late for a reliable sync, make sure sync time is not in the future.
571 if (now < fOSSWriteSync) {
572 fOSSWriteOffset = ptr.fifo_samples;
573 jack_info("JackOSSDriver::WaitAndSync playback %ld sync %ld early", fOSSWriteOffset, fOSSWriteSync - now);
574 fOSSWriteSync = now;
575 }
576 } else if (fForceSync) {
577 // Uncertain previous sync, just use sync time directly.
578 fOSSWriteSync = now;
579 fOSSWriteOffset = ptr.fifo_samples;
580 } else {
581 // Adapt expected sync time when early or late - in whole block intervals.
582 // Account for some speed drift, but otherwise round down to earlier interval.
583 jack_time_t interval = FramesToTime(fOutBlockSize, fEngineControl->fSampleRate);
584 jack_time_t remainder = fOSSWriteSync % interval;
585 jack_time_t max_drift = interval / 4;
586 jack_time_t rounded = RoundDown((now - remainder) + max_drift, interval) + remainder;
587 // Let sync time converge slowly when late, prefer earlier sync times.
588 fOSSWriteSync = min(rounded, now) / 2 + now / 2;
589 fOSSWriteOffset = ptr.fifo_samples;
590 }
591 }
592 poll_fd[1].events = 0;
593 }
594 }
595
596 fForceSync = false;
597
598 // Compute balance of read and write buffers combined.
599 fBufferBalance = 0;
600 if (fInFD > 0 && fOutFD > 0) {
601 // Compare actual buffer content with target of (1 + n) * period.
602 fBufferBalance += ((1 + fNperiods) * fEngineControl->fBufferSize);
603 fBufferBalance -= (fOSSWriteOffset - fOSSReadOffset);
604 fBufferBalance += TimeToOffset(fOSSWriteSync, fOSSReadSync, fEngineControl->fSampleRate);
605
606 // Force balancing if sync times deviate too much.
607 jack_time_t slack = FramesToTime((fEngineControl->fBufferSize * 2) / 3, fEngineControl->fSampleRate);
608 fForceBalancing = fForceBalancing || (fOSSReadSync > fOSSWriteSync + slack);
609 fForceBalancing = fForceBalancing || (fOSSWriteSync > fOSSReadSync + slack);
610 // Force balancing if buffer is badly balanced.
611 fForceBalancing = fForceBalancing || (abs(fBufferBalance) > max(fInMeanStep, fOutMeanStep));
612 }
613
614 // Print debug info every 10 seconds.
615 if (ptr.samples > 0 && (ptr.samples % (10 * fEngineControl->fSampleRate)) < fEngineControl->fBufferSize) {
616 jack_info("JackOSSDriver::Read buffer balance is %ld", fBufferBalance);
617 jack_time_t now = GetMicroSeconds();
618 jack_info("JackOSSDriver::Read recording offset %ld sync %ld ago", fOSSReadOffset, now - fOSSReadSync);
619 jack_info("JackOSSDriver::Read playback offset %ld sync %ld ago", fOSSWriteOffset, now - fOSSWriteSync);
620 }
621
622 return 0;
623 }
624
OpenInput()625 int JackOSSDriver::OpenInput()
626 {
627 int flags = 0;
628 int gFragFormat;
629 int cur_capture_channels;
630 int cur_sample_format;
631 jack_nframes_t cur_sample_rate;
632 audio_buf_info info;
633
634 if (fCaptureChannels == 0) fCaptureChannels = 2;
635
636 if ((fInFD = open(fCaptureDriverName, O_RDONLY | ((fExcl) ? O_EXCL : 0))) < 0) {
637 jack_error("JackOSSDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno);
638 return -1;
639 }
640
641 jack_log("JackOSSDriver::OpenInput input fInFD = %d", fInFD);
642
643 if (fExcl) {
644 if (ioctl(fInFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) {
645 jack_error("JackOSSDriver::OpenInput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno);
646 goto error;
647 }
648 }
649
650 cur_sample_format = GetSampleFormat(fBits);
651 if (ioctl(fInFD, SNDCTL_DSP_SETFMT, &cur_sample_format) == -1) {
652 jack_error("JackOSSDriver::OpenInput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno);
653 goto error;
654 }
655 fInSampleSize = GetSampleSize(cur_sample_format);
656 if (cur_sample_format != GetSampleFormat(fBits)) {
657 if (fInSampleSize > 0) {
658 jack_info("JackOSSDriver::OpenInput driver forced %d bit sample format", fInSampleSize * 8);
659 } else {
660 jack_error("JackOSSDriver::OpenInput unsupported sample format %#x", cur_sample_format);
661 goto error;
662 }
663 }
664
665 cur_capture_channels = fCaptureChannels;
666 if (ioctl(fInFD, SNDCTL_DSP_CHANNELS, &fCaptureChannels) == -1) {
667 jack_error("JackOSSDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno);
668 goto error;
669 }
670 if (cur_capture_channels != fCaptureChannels) {
671 jack_info("JackOSSDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels);
672 }
673
674 cur_sample_rate = fEngineControl->fSampleRate;
675 if (ioctl(fInFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) {
676 jack_error("JackOSSDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno);
677 goto error;
678 }
679 if (cur_sample_rate != fEngineControl->fSampleRate) {
680 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate);
681 }
682
683 // Internal buffer size required for one period.
684 fInputBufferSize = fEngineControl->fBufferSize * fInSampleSize * fCaptureChannels;
685
686 // Get the total size of the OSS recording buffer, in sample frames.
687 info = {0, 0, 0, 0};
688 if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1 || info.fragsize <= 0 || info.fragstotal <= 0) {
689 jack_error("JackOSSDriver::OpenInput failed to get buffer info : %s@%i, errno = %d", __FILE__, __LINE__, errno);
690 goto error;
691 }
692 fOSSInBuffer = info.fragstotal * info.fragsize / (fInSampleSize * fCaptureChannels);
693
694 if (fOSSInBuffer < fEngineControl->fBufferSize * (1 + fNperiods)) {
695 // Total size of the OSS recording buffer is too small, resize it.
696 unsigned int buf_size = fInputBufferSize * (1 + fNperiods);
697 // Keep current fragment size if possible - respect OSS latency settings.
698 gFragFormat = UpToPower2(info.fragsize);
699 unsigned int frag_size = 1U << gFragFormat;
700 gFragFormat |= ((buf_size + frag_size - 1) / frag_size) << 16;
701 jack_info("JackOSSDriver::OpenInput request %d fragments of %d", (gFragFormat >> 16), frag_size);
702 if (ioctl(fInFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) {
703 jack_error("JackOSSDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno);
704 goto error;
705 }
706 // Check the new OSS recording buffer size.
707 info = {0, 0, 0, 0};
708 if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1 || info.fragsize <= 0 || info.fragstotal <= 0) {
709 jack_error("JackOSSDriver::OpenInput failed to get buffer info : %s@%i, errno = %d", __FILE__, __LINE__, errno);
710 goto error;
711 }
712 fOSSInBuffer = info.fragstotal * info.fragsize / (fInSampleSize * fCaptureChannels);
713 }
714
715 if (fOSSInBuffer > fEngineControl->fBufferSize) {
716 int mark = fInputBufferSize;
717 if (ioctl(fInFD, SNDCTL_DSP_LOW_WATER, &mark) != 0) {
718 jack_error("JackOSSDriver::OpenInput failed to set low water mark : %s@%i, errno = %d", __FILE__, __LINE__, errno);
719 goto error;
720 }
721 jack_info("JackOSSDriver::OpenInput set low water mark to %d", mark);
722 }
723
724 fInputBuffer = (void*)calloc(fInputBufferSize, 1);
725 assert(fInputBuffer);
726
727 if (ProbeInBlockSize() < 0) {
728 goto error;
729 }
730
731 return 0;
732
733 error:
734 ::close(fInFD);
735 return -1;
736 }
737
OpenOutput()738 int JackOSSDriver::OpenOutput()
739 {
740 int flags = 0;
741 int gFragFormat;
742 int cur_sample_format;
743 int cur_playback_channels;
744 jack_nframes_t cur_sample_rate;
745 audio_buf_info info;
746
747 if (fPlaybackChannels == 0) fPlaybackChannels = 2;
748
749 if ((fOutFD = open(fPlaybackDriverName, O_WRONLY | ((fExcl) ? O_EXCL : 0))) < 0) {
750 jack_error("JackOSSDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno);
751 return -1;
752 }
753
754 jack_log("JackOSSDriver::OpenOutput output fOutFD = %d", fOutFD);
755
756 if (fExcl) {
757 if (ioctl(fOutFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) {
758 jack_error("JackOSSDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno);
759 goto error;
760 }
761 }
762
763 cur_sample_format = GetSampleFormat(fBits);
764 if (ioctl(fOutFD, SNDCTL_DSP_SETFMT, &cur_sample_format) == -1) {
765 jack_error("JackOSSDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno);
766 goto error;
767 }
768 fOutSampleSize = GetSampleSize(cur_sample_format);
769 if (cur_sample_format != GetSampleFormat(fBits)) {
770 if (fOutSampleSize > 0) {
771 jack_info("JackOSSDriver::OpenOutput driver forced %d bit sample format", fOutSampleSize * 8);
772 } else {
773 jack_error("JackOSSDriver::OpenOutput unsupported sample format %#x", cur_sample_format);
774 goto error;
775 }
776 }
777
778 cur_playback_channels = fPlaybackChannels;
779 if (ioctl(fOutFD, SNDCTL_DSP_CHANNELS, &fPlaybackChannels) == -1) {
780 jack_error("JackOSSDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno);
781 goto error;
782 }
783 if (cur_playback_channels != fPlaybackChannels) {
784 jack_info("JackOSSDriver::OpenOutput driver forced the number of playback channels %ld", fPlaybackChannels);
785 }
786
787 cur_sample_rate = fEngineControl->fSampleRate;
788 if (ioctl(fOutFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) {
789 jack_error("JackOSSDriver::OpenOutput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno);
790 goto error;
791 }
792 if (cur_sample_rate != fEngineControl->fSampleRate) {
793 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate);
794 }
795
796 // Internal buffer size required for one period.
797 fOutputBufferSize = fEngineControl->fBufferSize * fOutSampleSize * fPlaybackChannels;
798
799 // Get the total size of the OSS playback buffer, in sample frames.
800 info = {0, 0, 0, 0};
801 if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1 || info.fragsize <= 0 || info.fragstotal <= 0) {
802 jack_error("JackOSSDriver::OpenOutput failed to get buffer info : %s@%i, errno = %d", __FILE__, __LINE__, errno);
803 goto error;
804 }
805 fOSSOutBuffer = info.fragstotal * info.fragsize / (fOutSampleSize * fPlaybackChannels);
806
807 if (fOSSOutBuffer < fEngineControl->fBufferSize * (1 + fNperiods)) {
808 // Total size of the OSS playback buffer is too small, resize it.
809 unsigned int buf_size = fOutputBufferSize * (1 + fNperiods);
810 // Keep current fragment size if possible - respect OSS latency settings.
811 // Some sound cards like Intel HDA may stutter when changing the fragment size.
812 gFragFormat = UpToPower2(info.fragsize);
813 unsigned int frag_size = 1U << gFragFormat;
814 gFragFormat |= ((buf_size + frag_size - 1) / frag_size) << 16;
815 jack_info("JackOSSDriver::OpenOutput request %d fragments of %d", (gFragFormat >> 16), frag_size);
816 if (ioctl(fOutFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) {
817 jack_error("JackOSSDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno);
818 goto error;
819 }
820 // Check the new OSS playback buffer size.
821 info = {0, 0, 0, 0};
822 if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1 || info.fragsize <= 0 || info.fragstotal <= 0) {
823 jack_error("JackOSSDriver::OpenOutput failed to get buffer info : %s@%i, errno = %d", __FILE__, __LINE__, errno);
824 goto error;
825 }
826 fOSSOutBuffer = info.fragstotal * info.fragsize / (fOutSampleSize * fPlaybackChannels);
827 }
828
829 if (fOSSOutBuffer > fEngineControl->fBufferSize * fNperiods) {
830 jack_nframes_t low = fOSSOutBuffer - (fNperiods * fEngineControl->fBufferSize);
831 int mark = low * fOutSampleSize * fPlaybackChannels;
832 if (ioctl(fOutFD, SNDCTL_DSP_LOW_WATER, &mark) != 0) {
833 jack_error("JackOSSDriver::OpenOutput failed to set low water mark : %s@%i, errno = %d", __FILE__, __LINE__, errno);
834 goto error;
835 }
836 jack_info("JackOSSDriver::OpenOutput set low water mark to %d", mark);
837 }
838
839 fOutputBuffer = (void*)calloc(fOutputBufferSize, 1);
840 assert(fOutputBuffer);
841
842 if (ProbeOutBlockSize() < 0) {
843 goto error;
844 }
845
846 return 0;
847
848 error:
849 ::close(fOutFD);
850 return -1;
851 }
852
Open(jack_nframes_t nframes,int user_nperiods,jack_nframes_t samplerate,bool capturing,bool playing,int inchannels,int outchannels,bool excl,bool monitor,const char * capture_driver_uid,const char * playback_driver_uid,jack_nframes_t capture_latency,jack_nframes_t playback_latency,int bits,bool ignorehwbuf)853 int JackOSSDriver::Open(jack_nframes_t nframes,
854 int user_nperiods,
855 jack_nframes_t samplerate,
856 bool capturing,
857 bool playing,
858 int inchannels,
859 int outchannels,
860 bool excl,
861 bool monitor,
862 const char* capture_driver_uid,
863 const char* playback_driver_uid,
864 jack_nframes_t capture_latency,
865 jack_nframes_t playback_latency,
866 int bits,
867 bool ignorehwbuf)
868 {
869 // Store local settings first.
870 fCapture = capturing;
871 fPlayback = playing;
872 fBits = bits;
873 fIgnoreHW = ignorehwbuf;
874 fNperiods = user_nperiods;
875 fExcl = excl;
876 fExtraCaptureLatency = capture_latency;
877 fExtraPlaybackLatency = playback_latency;
878
879 // Additional playback latency introduced by the OSS buffer. The extra hardware
880 // latency given by the user should then be symmetric as reported by jack_iodelay.
881 playback_latency += user_nperiods * nframes;
882 // Generic JackAudioDriver Open
883 if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor,
884 capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) {
885 return -1;
886 } else {
887
888 #ifdef JACK_MONITOR
889 // Force memory page in
890 memset(&gCycleTable, 0, sizeof(gCycleTable));
891 #endif
892
893 if (OpenAux() < 0) {
894 Close();
895 return -1;
896 } else {
897 return 0;
898 }
899 }
900 }
901
Close()902 int JackOSSDriver::Close()
903 {
904 #ifdef JACK_MONITOR
905 FILE* file = fopen("OSSProfiling.log", "w");
906
907 if (file) {
908 jack_info("Writing OSS driver timing data....");
909 for (int i = 1; i < gCycleCount; i++) {
910 int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead;
911 int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead;
912 int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite;
913 int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert;
914 fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4);
915 }
916 fclose(file);
917 } else {
918 jack_error("JackOSSDriver::Close : cannot open OSSProfiling.log file");
919 }
920
921 file = fopen("TimingOSS.plot", "w");
922
923 if (file == NULL) {
924 jack_error("JackOSSDriver::Close cannot open TimingOSS.plot file");
925 } else {
926
927 fprintf(file, "set grid\n");
928 fprintf(file, "set title \"OSS audio driver timing\"\n");
929 fprintf(file, "set xlabel \"audio cycles\"\n");
930 fprintf(file, "set ylabel \"usec\"\n");
931 fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
932 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
933 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
934 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
935
936 fprintf(file, "set output 'TimingOSS.pdf\n");
937 fprintf(file, "set terminal pdf\n");
938
939 fprintf(file, "set grid\n");
940 fprintf(file, "set title \"OSS audio driver timing\"\n");
941 fprintf(file, "set xlabel \"audio cycles\"\n");
942 fprintf(file, "set ylabel \"usec\"\n");
943 fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
944 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
945 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
946 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
947
948 fclose(file);
949 }
950 #endif
951 int res = JackAudioDriver::Close();
952 CloseAux();
953 return res;
954 }
955
956
OpenAux()957 int JackOSSDriver::OpenAux()
958 {
959 // (Re-)Initialize runtime variables.
960 fInSampleSize = fOutSampleSize = 0;
961 fInputBufferSize = fOutputBufferSize = 0;
962 fInBlockSize = fOutBlockSize = 1;
963 fInMeanStep = fOutMeanStep = 0;
964 fOSSInBuffer = fOSSOutBuffer = 0;
965 fOSSReadSync = fOSSWriteSync = 0;
966 fOSSReadOffset = fOSSWriteOffset = 0;
967 fBufferBalance = 0;
968 fForceBalancing = false;
969 fForceSync = false;
970
971 if (fCapture && (OpenInput() < 0)) {
972 return -1;
973 }
974
975 if (fPlayback && (OpenOutput() < 0)) {
976 return -1;
977 }
978
979 DisplayDeviceInfo();
980 return 0;
981 }
982
CloseAux()983 void JackOSSDriver::CloseAux()
984 {
985 if (fCapture && fInFD > 0) {
986 close(fInFD);
987 fInFD = -1;
988 }
989
990 if (fPlayback && fOutFD > 0) {
991 close(fOutFD);
992 fOutFD = -1;
993 }
994
995 if (fInputBuffer)
996 free(fInputBuffer);
997 fInputBuffer = NULL;
998
999 if (fOutputBuffer)
1000 free(fOutputBuffer);
1001 fOutputBuffer = NULL;
1002 }
1003
Read()1004 int JackOSSDriver::Read()
1005 {
1006 if (fInFD > 0 && fOSSReadSync == 0) {
1007 // First cycle, account for leftover samples from previous reads.
1008 fOSSReadOffset = 0;
1009 oss_count_t ptr;
1010 if (ioctl(fInFD, SNDCTL_DSP_CURRENT_IPTR, &ptr) == 0 && ptr.fifo_samples > 0) {
1011 jack_info("JackOSSDriver::Read pre recording samples = %ld, fifo_samples = %d", ptr.samples, ptr.fifo_samples);
1012 fOSSReadOffset = -ptr.fifo_samples;
1013 }
1014
1015 // Start capture by reading a new hardware block.,
1016 jack_nframes_t discard = fInMeanStep - fOSSReadOffset;
1017 // Let half a block or at most 1ms remain in buffer, avoid drift issues at start.
1018 discard -= min(TimeToFrames(1000, fEngineControl->fSampleRate), (fInMeanStep / 2));
1019 jack_info("JackOSSDriver::Read start recording discard %ld frames", discard);
1020 fOSSReadSync = GetMicroSeconds();
1021 Discard(discard);
1022
1023 fForceSync = true;
1024 fForceBalancing = true;
1025 }
1026
1027 if (fOutFD > 0 && fOSSWriteSync == 0) {
1028 // First cycle, account for leftover samples from previous writes.
1029 fOSSWriteOffset = 0;
1030 oss_count_t ptr;
1031 if (ioctl(fOutFD, SNDCTL_DSP_CURRENT_OPTR, &ptr) == 0 && ptr.fifo_samples > 0) {
1032 jack_info("JackOSSDriver::Read pre playback samples = %ld, fifo_samples = %d", ptr.samples, ptr.fifo_samples);
1033 fOSSWriteOffset = ptr.fifo_samples;
1034 }
1035
1036 // Start playback with silence, target latency as given by the user.
1037 jack_nframes_t silence = (fNperiods + 1) * fEngineControl->fBufferSize;
1038 // Minus half a block or at most 1ms of frames, avoid drift issues at start.
1039 silence -= min(TimeToFrames(1000, fEngineControl->fSampleRate), (fOutMeanStep / 2));
1040 silence = max(silence - fOSSWriteOffset, 1LL);
1041 jack_info("JackOSSDriver::Read start playback with %ld frames of silence", silence);
1042 fOSSWriteSync = GetMicroSeconds();
1043 WriteSilence(silence);
1044
1045 fForceSync = true;
1046 fForceBalancing = true;
1047 }
1048
1049 #ifdef JACK_MONITOR
1050 gCycleTable.fTable[gCycleCount].fBeforeRead = GetMicroSeconds();
1051 #endif
1052
1053 if (WaitAndSync() < 0) {
1054 return -1;
1055 }
1056
1057 // Keep begin cycle time
1058 JackDriver::CycleTakeBeginTime();
1059
1060 if (fInFD < 0) {
1061 return 0;
1062 }
1063
1064 // Try to read multiple times in case of short reads.
1065 size_t count = 0;
1066 for (int i = 0; i < 3 && count < fInputBufferSize; ++i) {
1067 ssize_t ret = ::read(fInFD, ((char*)fInputBuffer) + count, fInputBufferSize - count);
1068 if (ret < 0) {
1069 jack_error("JackOSSDriver::Read error = %s", strerror(errno));
1070 return -1;
1071 }
1072 count += ret;
1073 }
1074
1075 // Read offset accounting and overrun detection.
1076 if (count > 0) {
1077 jack_time_t now = GetMicroSeconds();
1078 jack_time_t sync = max(fOSSReadSync, fOSSWriteSync);
1079 if (now - sync > 1000) {
1080 // Blocking read() may indicate sample loss in OSS - force resync.
1081 jack_log("JackOSSDriver::Read long read duration of %ld us", now - sync);
1082 fForceSync = true;
1083 }
1084 long long passed = TimeToFrames(now - fOSSReadSync, fEngineControl->fSampleRate);
1085 passed -= (passed % fInBlockSize);
1086 if (passed > fOSSReadOffset + fOSSInBuffer) {
1087 // Overrun, adjust read and write position.
1088 long long missed = passed - (fOSSReadOffset + fOSSInBuffer);
1089 jack_error("JackOSSDriver::Read missed %ld frames by overrun, passed=%ld, sync=%ld, now=%ld", missed, passed, fOSSReadSync, now);
1090 fOSSReadOffset += missed;
1091 fOSSWriteOffset += missed;
1092 NotifyXRun(now, float(FramesToTime(missed, fEngineControl->fSampleRate)));
1093 }
1094 fOSSReadOffset += count / (fInSampleSize * fCaptureChannels);
1095 }
1096
1097 #ifdef JACK_MONITOR
1098 if (count > 0 && count != (int)fInputBufferSize)
1099 jack_log("JackOSSDriver::Read count = %ld", count / (fInSampleSize * fCaptureChannels));
1100 gCycleTable.fTable[gCycleCount].fAfterRead = GetMicroSeconds();
1101 #endif
1102
1103 // Check and clear OSS errors.
1104 audio_errinfo ei_in;
1105 if (ioctl(fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) {
1106
1107 // Not reliable for overrun detection, virtual_oss doesn't implement it.
1108 if (ei_in.rec_overruns > 0 ) {
1109 jack_error("JackOSSDriver::Read %d overrun events", ei_in.rec_overruns);
1110 }
1111
1112 if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) {
1113 jack_error("%d OSS rec event(s), last=%05d:%d", ei_in.rec_errorcount, ei_in.rec_lasterror, ei_in.rec_errorparm);
1114 }
1115 }
1116
1117 if (count < fInputBufferSize) {
1118 jack_error("JackOSSDriver::Read incomplete read of %ld bytes", count);
1119 return -1;
1120 }
1121
1122 for (int i = 0; i < fCaptureChannels; i++) {
1123 if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
1124 CopyAndConvertIn(GetInputBuffer(i), fInputBuffer, fEngineControl->fBufferSize, i, fCaptureChannels, fInSampleSize * 8);
1125 }
1126 }
1127
1128 #ifdef JACK_MONITOR
1129 gCycleTable.fTable[gCycleCount].fAfterReadConvert = GetMicroSeconds();
1130 #endif
1131
1132 return 0;
1133 }
1134
Write()1135 int JackOSSDriver::Write()
1136 {
1137 if (fOutFD < 0) {
1138 return 0;
1139 }
1140
1141 unsigned int skip = 0;
1142 jack_time_t start = GetMicroSeconds();
1143
1144 if (fOSSWriteSync > 0) {
1145 // Check for underruns, rounded to hardware block size if available.
1146 long long passed = TimeToFrames(start - fOSSWriteSync, fEngineControl->fSampleRate);
1147 long long consumed = passed - (passed % fOutBlockSize);
1148 long long tolerance = (fOutBlockSize > 1) ? 0 : fOutMeanStep;
1149 long long overdue = 0;
1150 if (consumed > fOSSWriteOffset + tolerance) {
1151 // Skip playback data that already passed.
1152 overdue = consumed - fOSSWriteOffset - tolerance;
1153 jack_error("JackOSSDriver::Write underrun, late by %ld, skip %ld frames", passed - fOSSWriteOffset, overdue);
1154 jack_error("JackOSSDriver::Write playback offset %ld frames synced %ld us ago", fOSSWriteOffset, start - fOSSWriteSync);
1155 // Also consider buffer balance, there was a gap in playback anyway.
1156 fForceBalancing = true;
1157 }
1158 // Account for buffer balance if needed.
1159 long long progress = fEngineControl->fBufferSize;
1160 if (fForceBalancing) {
1161 fForceBalancing = false;
1162 progress = max(progress + fBufferBalance, 0LL);
1163 jack_info("JackOSSDriver::Write recording offset %ld sync %ld ago", fOSSReadOffset, start - fOSSReadSync);
1164 jack_info("JackOSSDriver::Write playback offset %ld sync %ld ago", fOSSWriteOffset, start - fOSSWriteSync);
1165 jack_info("JackOSSDriver::Write buffer balancing %ld", fBufferBalance);
1166 }
1167 // How many samples to skip or prepend due to underrun and balancing.
1168 long long write_length = progress - overdue;
1169 if (write_length <= 0) {
1170 skip += fOutputBufferSize;
1171 fOSSWriteOffset += progress;
1172 } else if (write_length < fEngineControl->fBufferSize) {
1173 skip += (fEngineControl->fBufferSize - write_length) * fOutSampleSize * fPlaybackChannels;
1174 fOSSWriteOffset += overdue;
1175 } else if (write_length > fEngineControl->fBufferSize) {
1176 jack_nframes_t fill = write_length - fEngineControl->fBufferSize;
1177 WriteSilence(fill);
1178 }
1179 }
1180
1181 #ifdef JACK_MONITOR
1182 gCycleTable.fTable[gCycleCount].fBeforeWriteConvert = GetMicroSeconds();
1183 #endif
1184
1185 memset(fOutputBuffer, 0, fOutputBufferSize);
1186 for (int i = 0; i < fPlaybackChannels; i++) {
1187 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
1188 CopyAndConvertOut(fOutputBuffer, GetOutputBuffer(i), fEngineControl->fBufferSize, i, fPlaybackChannels, fOutSampleSize * 8);
1189 }
1190 }
1191
1192 #ifdef JACK_MONITOR
1193 gCycleTable.fTable[gCycleCount].fBeforeWrite = GetMicroSeconds();
1194 #endif
1195
1196 // Try multiple times in case of short writes.
1197 ssize_t count = skip;
1198 for (int i = 0; i < 3 && count < fOutputBufferSize; ++i) {
1199 ssize_t ret = ::write(fOutFD, ((char*)fOutputBuffer) + count, fOutputBufferSize - count);
1200 if (ret < 0) {
1201 jack_error("JackOSSDriver::Write error = %s", strerror(errno));
1202 return -1;
1203 }
1204 count += ret;
1205 }
1206
1207 fOSSWriteOffset += ((count - skip) / (fOutSampleSize * fPlaybackChannels));
1208
1209 jack_time_t duration = GetMicroSeconds() - start;
1210 if (duration > 1000) {
1211 // Blocking write() may indicate sample loss in OSS - force resync.
1212 jack_log("JackOSSDriver::Write long write duration of %ld us", duration);
1213 fForceSync = true;
1214 }
1215
1216 #ifdef JACK_MONITOR
1217 if (count > 0 && count != (int)fOutputBufferSize)
1218 jack_log("JackOSSDriver::Write count = %ld", (count - skip) / (fOutSampleSize * fPlaybackChannels));
1219 gCycleTable.fTable[gCycleCount].fAfterWrite = GetMicroSeconds();
1220 gCycleCount = (gCycleCount == CYCLE_POINTS - 1) ? gCycleCount: gCycleCount + 1;
1221 #endif
1222
1223 // Check and clear OSS errors.
1224 audio_errinfo ei_out;
1225 if (ioctl(fOutFD, SNDCTL_DSP_GETERROR, &ei_out) == 0) {
1226
1227 // Not reliable for underrun detection, virtual_oss does not implement it.
1228 if (ei_out.play_underruns > 0) {
1229 jack_error("JackOSSDriver::Write %d underrun events", ei_out.play_underruns);
1230 }
1231
1232 if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) {
1233 jack_error("%d OSS play event(s), last=%05d:%d",ei_out.play_errorcount, ei_out.play_lasterror, ei_out.play_errorparm);
1234 }
1235 }
1236
1237 if (count < (int)fOutputBufferSize) {
1238 jack_error("JackOSSDriver::Write incomplete write of %ld bytes", count - skip);
1239 return -1;
1240 }
1241
1242 return 0;
1243 }
1244
SetBufferSize(jack_nframes_t buffer_size)1245 int JackOSSDriver::SetBufferSize(jack_nframes_t buffer_size)
1246 {
1247 CloseAux();
1248
1249 // Additional latency introduced by the OSS buffer, depends on buffer size.
1250 fCaptureLatency = fExtraCaptureLatency;
1251 fPlaybackLatency = fExtraPlaybackLatency + fNperiods * buffer_size;
1252
1253 JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
1254 return OpenAux();
1255 }
1256
1257 } // end of namespace
1258
1259 #ifdef __cplusplus
1260 extern "C"
1261 {
1262 #endif
1263
driver_get_descriptor()1264 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
1265 {
1266 jack_driver_desc_t * desc;
1267 jack_driver_desc_filler_t filler;
1268 jack_driver_param_value_t value;
1269
1270 desc = jack_driver_descriptor_construct("oss", JackDriverMaster, "OSS API based audio backend", &filler);
1271
1272 value.ui = OSS_DRIVER_DEF_FS;
1273 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
1274
1275 value.ui = OSS_DRIVER_DEF_BLKSIZE;
1276 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
1277
1278 value.ui = OSS_DRIVER_DEF_NPERIODS;
1279 jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods to prefill output buffer", NULL);
1280
1281 value.i = OSS_DRIVER_DEF_BITS;
1282 jack_driver_descriptor_add_parameter(desc, &filler, "wordlength", 'w', JackDriverParamInt, &value, NULL, "Word length", NULL);
1283
1284 value.ui = OSS_DRIVER_DEF_INS;
1285 jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Capture channels", NULL);
1286
1287 value.ui = OSS_DRIVER_DEF_OUTS;
1288 jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Playback channels", NULL);
1289
1290 value.i = false;
1291 jack_driver_descriptor_add_parameter(desc, &filler, "excl", 'e', JackDriverParamBool, &value, NULL, "Exclusif (O_EXCL) access mode", NULL);
1292
1293 strcpy(value.str, OSS_DRIVER_DEF_DEV);
1294 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input device", NULL);
1295 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output device", NULL);
1296 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "OSS device name", NULL);
1297
1298 value.i = false;
1299 jack_driver_descriptor_add_parameter(desc, &filler, "ignorehwbuf", 'b', JackDriverParamBool, &value, NULL, "Ignore hardware period size", NULL);
1300
1301 value.ui = 0;
1302 jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency", NULL);
1303 jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency", NULL);
1304
1305 return desc;
1306 }
1307
driver_initialize(Jack::JackLockedEngine * engine,Jack::JackSynchro * table,const JSList * params)1308 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
1309 {
1310 int bits = OSS_DRIVER_DEF_BITS;
1311 jack_nframes_t srate = OSS_DRIVER_DEF_FS;
1312 jack_nframes_t frames_per_interrupt = OSS_DRIVER_DEF_BLKSIZE;
1313 const char* capture_pcm_name = OSS_DRIVER_DEF_DEV;
1314 const char* playback_pcm_name = OSS_DRIVER_DEF_DEV;
1315 bool capture = false;
1316 bool playback = false;
1317 int chan_in = 0;
1318 int chan_out = 0;
1319 bool monitor = false;
1320 bool excl = false;
1321 unsigned int nperiods = OSS_DRIVER_DEF_NPERIODS;
1322 const JSList *node;
1323 const jack_driver_param_t *param;
1324 bool ignorehwbuf = false;
1325 jack_nframes_t systemic_input_latency = 0;
1326 jack_nframes_t systemic_output_latency = 0;
1327
1328 for (node = params; node; node = jack_slist_next(node)) {
1329
1330 param = (const jack_driver_param_t *)node->data;
1331
1332 switch (param->character) {
1333
1334 case 'r':
1335 srate = param->value.ui;
1336 break;
1337
1338 case 'p':
1339 frames_per_interrupt = (unsigned int)param->value.ui;
1340 break;
1341
1342 case 'n':
1343 nperiods = (unsigned int)param->value.ui;
1344 break;
1345
1346 case 'w':
1347 bits = param->value.i;
1348 break;
1349
1350 case 'i':
1351 chan_in = (int)param->value.ui;
1352 break;
1353
1354 case 'o':
1355 chan_out = (int)param->value.ui;
1356 break;
1357
1358 case 'C':
1359 capture = true;
1360 if (strcmp(param->value.str, "none") != 0) {
1361 capture_pcm_name = param->value.str;
1362 }
1363 break;
1364
1365 case 'P':
1366 playback = true;
1367 if (strcmp(param->value.str, "none") != 0) {
1368 playback_pcm_name = param->value.str;
1369 }
1370 break;
1371
1372 case 'd':
1373 playback_pcm_name = param->value.str;
1374 capture_pcm_name = param->value.str;
1375 break;
1376
1377 case 'b':
1378 ignorehwbuf = true;
1379 break;
1380
1381 case 'e':
1382 excl = true;
1383 break;
1384
1385 case 'I':
1386 systemic_input_latency = param->value.ui;
1387 break;
1388
1389 case 'O':
1390 systemic_output_latency = param->value.ui;
1391 break;
1392 }
1393 }
1394
1395 // duplex is the default
1396 if (!capture && !playback) {
1397 capture = true;
1398 playback = true;
1399 }
1400
1401 Jack::JackOSSDriver* oss_driver = new Jack::JackOSSDriver("system", "oss", engine, table);
1402 Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(oss_driver);
1403
1404 // Special open for OSS driver...
1405 if (oss_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out,
1406 excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, ignorehwbuf) == 0) {
1407 return threaded_driver;
1408 } else {
1409 delete threaded_driver; // Delete the decorated driver
1410 return NULL;
1411 }
1412 }
1413
1414 #ifdef __cplusplus
1415 }
1416 #endif
1417