2 Copyright (C) 2003-2007 Jussi Laako <jussi@sonarnerd.net>
3 Copyright (C) 2008 Grame & RTL 2008
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.
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.
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.
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"
29 #include "JackShmMem.h"
32 #include <sys/ioctl.h>
33 #include <sys/soundcard.h>
44 inline jack_nframes_t
TimeToFrames(jack_time_t time
, jack_nframes_t sample_rate
) {
45 return ((time
* sample_rate
) + 500000ULL) / 1000000ULL;
48 inline long long TimeToOffset(jack_time_t time1
, jack_time_t time2
, jack_nframes_t sample_rate
)
51 return TimeToFrames(time2
- time1
, sample_rate
);
53 return 0LL - TimeToFrames(time1
- time2
, 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
;
61 inline jack_nframes_t
RoundUp(jack_nframes_t frames
, jack_nframes_t block
) {
63 frames
+= (block
- 1);
64 frames
-= (frames
% block
);
69 inline jack_time_t
RoundDown(jack_time_t time
, jack_time_t interval
) {
71 time
-= (time
% interval
);
76 int GetSampleFormat(int bits
)
79 // Native-endian signed 32 bit samples.
82 // Native-endian signed 24 bit (packed) samples.
85 // Native-endian signed 16 bit samples, used by default.
92 unsigned int GetSampleSize(int format
)
95 // Native-endian signed 32 bit samples.
98 // Native-endian signed 24 bit (packed) samples.
101 // Native-endian signed 16 bit samples.
104 // Unsupported sample format.
110 inline int UpToPower2(int x
)
125 #define CYCLE_POINTS 500000
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
;
136 struct OSSCycleTable
{
137 jack_time_t fBeforeFirstWrite
;
138 jack_time_t fAfterFirstWrite
;
139 OSSCycle fTable
[CYCLE_POINTS
];
142 OSSCycleTable gCycleTable
;
147 static inline void CopyAndConvertIn(jack_sample_t
*dst
, void *src
, size_t nframes
, int channel
, int chcount
, int bits
)
152 signed short *s16src
= (signed short*)src
;
154 sample_move_dS_s16(dst
, (char*)s16src
, nframes
, chcount
<<1);
158 char *s24src
= (char*)src
;
159 s24src
+= channel
* 3;
160 sample_move_dS_s24(dst
, s24src
, nframes
, chcount
*3);
164 signed int *s32src
= (signed int*)src
;
166 sample_move_dS_s32u24(dst
, (char*)s32src
, nframes
, chcount
<<2);
172 static inline void CopyAndConvertOut(void *dst
, jack_sample_t
*src
, size_t nframes
, int channel
, int chcount
, int bits
)
177 signed short *s16dst
= (signed short*)dst
;
179 sample_move_d16_sS((char*)s16dst
, src
, nframes
, chcount
<<1, NULL
); // No dithering for now...
183 char *s24dst
= (char*)dst
;
184 s24dst
+= channel
* 3;
185 sample_move_d24_sS(s24dst
, src
, nframes
, chcount
*3, NULL
);
189 signed int *s32dst
= (signed int*)dst
;
191 sample_move_d32u24_sS((char*)s32dst
, src
, nframes
, chcount
<<2, NULL
);
197 void JackOSSDriver::DisplayDeviceInfo()
200 memset(&info
, 0, sizeof(audio_buf_info
));
203 // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html
204 jack_info("Audio Interface Description :");
205 jack_info("Sampling Frequency : %d, Sample Size : %d", fEngineControl
->fSampleRate
, fInSampleSize
* 8);
210 if (ioctl(fOutFD
, OSS_SYSINFO
, &si
) == -1) {
211 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
213 jack_info("OSS product %s", si
.product
);
214 jack_info("OSS version %s", si
.version
);
215 jack_info("OSS version num %d", si
.versionnum
);
216 jack_info("OSS numaudios %d", si
.numaudios
);
217 jack_info("OSS numaudioengines %d", si
.numaudioengines
);
218 jack_info("OSS numcards %d", si
.numcards
);
221 jack_info("Output capabilities - %d channels : ", fPlaybackChannels
);
222 jack_info("Output block size = %d", fOutputBufferSize
);
224 if (ioctl(fOutFD
, SNDCTL_DSP_GETOSPACE
, &info
) == -1) {
225 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
227 jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
228 info
.fragments
, info
.fragstotal
, info
.fragsize
, info
.bytes
);
231 if (ioctl(fOutFD
, SNDCTL_DSP_GETCAPS
, &cap
) == -1) {
232 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
234 if (cap
& DSP_CAP_DUPLEX
) jack_info(" DSP_CAP_DUPLEX");
235 if (cap
& DSP_CAP_REALTIME
) jack_info(" DSP_CAP_REALTIME");
236 if (cap
& DSP_CAP_BATCH
) jack_info(" DSP_CAP_BATCH");
237 if (cap
& DSP_CAP_COPROC
) jack_info(" DSP_CAP_COPROC");
238 if (cap
& DSP_CAP_TRIGGER
) jack_info(" DSP_CAP_TRIGGER");
239 if (cap
& DSP_CAP_MMAP
) jack_info(" DSP_CAP_MMAP");
240 if (cap
& DSP_CAP_MULTI
) jack_info(" DSP_CAP_MULTI");
241 if (cap
& DSP_CAP_BIND
) jack_info(" DSP_CAP_BIND");
248 if (ioctl(fInFD
, OSS_SYSINFO
, &si
) == -1) {
249 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
251 jack_info("OSS product %s", si
.product
);
252 jack_info("OSS version %s", si
.version
);
253 jack_info("OSS version num %d", si
.versionnum
);
254 jack_info("OSS numaudios %d", si
.numaudios
);
255 jack_info("OSS numaudioengines %d", si
.numaudioengines
);
256 jack_info("OSS numcards %d", si
.numcards
);
259 jack_info("Input capabilities - %d channels : ", fCaptureChannels
);
260 jack_info("Input block size = %d", fInputBufferSize
);
262 if (ioctl(fInFD
, SNDCTL_DSP_GETISPACE
, &info
) == -1) {
263 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
265 jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
266 info
.fragments
, info
.fragstotal
, info
.fragsize
, info
.bytes
);
269 if (ioctl(fInFD
, SNDCTL_DSP_GETCAPS
, &cap
) == -1) {
270 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
272 if (cap
& DSP_CAP_DUPLEX
) jack_info(" DSP_CAP_DUPLEX");
273 if (cap
& DSP_CAP_REALTIME
) jack_info(" DSP_CAP_REALTIME");
274 if (cap
& DSP_CAP_BATCH
) jack_info(" DSP_CAP_BATCH");
275 if (cap
& DSP_CAP_COPROC
) jack_info(" DSP_CAP_COPROC");
276 if (cap
& DSP_CAP_TRIGGER
) jack_info(" DSP_CAP_TRIGGER");
277 if (cap
& DSP_CAP_MMAP
) jack_info(" DSP_CAP_MMAP");
278 if (cap
& DSP_CAP_MULTI
) jack_info(" DSP_CAP_MULTI");
279 if (cap
& DSP_CAP_BIND
) jack_info(" DSP_CAP_BIND");
284 int JackOSSDriver::ProbeInBlockSize()
286 jack_nframes_t blocks
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
289 // Default values in case of an error.
290 fInMeanStep
= fEngineControl
->fBufferSize
;
294 // Read one frame into a new hardware block so we can check its size.
295 // Repeat that for multiple probes, sometimes the first reads differ.
296 jack_nframes_t frames
= 1;
297 for (int p
= 0; p
< 8 && frames
> 0; ++p
) {
298 ret
= Discard(frames
);
302 if (ioctl(fInFD
, SNDCTL_DSP_CURRENT_IPTR
, &ptr
) == 0 && ptr
.fifo_samples
> 0) {
303 // Success, store probed hardware block size for later.
304 blocks
[p
] = 1U + ptr
.fifo_samples
;
306 // Proceed by reading one frame into the next hardware block.
310 // Read error - abort.
311 jack_error("JackOSSDriver::ProbeInBlockSize read failed with %d", ret
);
316 ioctl(fInFD
, SNDCTL_DSP_HALT_INPUT
, NULL
);
320 // Compute mean block size of the last six probes.
321 jack_nframes_t sum
= 0;
322 for (int p
= 2; p
< 8; ++p
) {
323 jack_log("JackOSSDriver::ProbeInBlockSize read block of %d frames", blocks
[p
]);
326 fInMeanStep
= sum
/ 6;
328 // Check that none of the probed block sizes deviates too much.
329 jack_nframes_t slack
= fInMeanStep
/ 16;
331 for (int p
= 2; p
< 8; ++p
) {
332 strict
= strict
&& (blocks
[p
] > fInMeanStep
- slack
) && (blocks
[p
] < fInMeanStep
+ slack
);
335 if (strict
&& fInMeanStep
<= fEngineControl
->fBufferSize
) {
336 // Regular hardware block size, use it for rounding.
337 jack_info("JackOSSDriver::ProbeInBlockSize read blocks are %d frames", fInMeanStep
);
338 fInBlockSize
= fInMeanStep
;
340 jack_info("JackOSSDriver::ProbeInBlockSize irregular read block sizes");
341 jack_info("JackOSSDriver::ProbeInBlockSize mean read block was %d frames", fInMeanStep
);
344 if (fInBlockSize
> fEngineControl
->fBufferSize
/ 2) {
345 jack_info("JackOSSDriver::ProbeInBlockSize less than two read blocks per cycle");
346 jack_info("JackOSSDriver::ProbeInBlockSize for best results make period a multiple of %d", fInBlockSize
);
349 if (fInMeanStep
> fEngineControl
->fBufferSize
) {
350 jack_error("JackOSSDriver::ProbeInBlockSize period is too small, minimum is %d frames", fInMeanStep
);
358 int JackOSSDriver::ProbeOutBlockSize()
360 jack_nframes_t blocks
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
363 // Default values in case of an error.
364 fOutMeanStep
= fEngineControl
->fBufferSize
;
368 // Write one frame over the low water mark, then check the consumed block size.
369 // Repeat that for multiple probes, sometimes the initial ones differ.
370 jack_nframes_t mark
= fNperiods
* fEngineControl
->fBufferSize
;
371 WriteSilence(mark
+ 1);
372 for (int p
= 0; p
< 8 && ret
>= 0; ++p
) {
375 poll_fd
.events
= POLLOUT
;
376 ret
= poll(&poll_fd
, 1, 500);
378 jack_error("JackOSSDriver::ProbeOutBlockSize poll failed with %d", ret
);
381 if (poll_fd
.revents
& POLLOUT
) {
383 if (ioctl(fOutFD
, SNDCTL_DSP_CURRENT_OPTR
, &ptr
) != -1 && ptr
.fifo_samples
>= 0) {
384 // Success, store probed hardware block size for later.
385 blocks
[p
] = mark
+ 1 - ptr
.fifo_samples
;
387 // Proceed by writing one frame over the low water mark.
388 WriteSilence(blocks
[p
]);
395 ioctl(fOutFD
, SNDCTL_DSP_HALT_INPUT
, NULL
);
399 // Compute mean and maximum block size of the last six probes.
400 jack_nframes_t sum
= 0;
401 for (int p
= 2; p
< 8; ++p
) {
402 jack_log("JackOSSDriver::ProbeOutBlockSize write block of %d frames", blocks
[p
]);
405 fOutMeanStep
= sum
/ 6;
407 // Check that none of the probed block sizes deviates too much.
408 jack_nframes_t slack
= fOutMeanStep
/ 16;
410 for (int p
= 2; p
< 8; ++p
) {
411 strict
= strict
&& (blocks
[p
] > fOutMeanStep
- slack
) && (blocks
[p
] < fOutMeanStep
+ slack
);
414 if (strict
&& fOutMeanStep
<= fEngineControl
->fBufferSize
) {
415 // Regular hardware block size, use it for rounding.
416 jack_info("JackOSSDriver::ProbeOutBlockSize write blocks are %d frames", fOutMeanStep
);
417 fOutBlockSize
= fOutMeanStep
;
419 jack_info("JackOSSDriver::ProbeOutBlockSize irregular write block sizes");
420 jack_info("JackOSSDriver::ProbeOutBlockSize mean write block was %d frames", fOutMeanStep
);
423 if (fOutBlockSize
> fEngineControl
->fBufferSize
/ 2) {
424 jack_info("JackOSSDriver::ProbeOutBlockSize less than two write blocks per cycle");
425 jack_info("JackOSSDriver::ProbeOutBlockSize for best results make period a multiple of %d", fOutBlockSize
);
428 if (fOutMeanStep
> fEngineControl
->fBufferSize
) {
429 jack_error("JackOSSDriver::ProbeOutBlockSize period is too small, minimum is %d frames", fOutMeanStep
);
437 int JackOSSDriver::Discard(jack_nframes_t frames
)
443 // Read frames from OSS capture buffer to be discarded.
444 ssize_t size
= frames
* fInSampleSize
* fCaptureChannels
;
446 ssize_t chunk
= (size
> fInputBufferSize
) ? fInputBufferSize
: size
;
447 ssize_t count
= ::read(fInFD
, fInputBuffer
, chunk
);
449 jack_error("JackOSSDriver::Discard error bytes read = %ld", count
);
452 fOSSReadOffset
+= count
/ (fInSampleSize
* fCaptureChannels
);
458 int JackOSSDriver::WriteSilence(jack_nframes_t frames
)
464 // Fill OSS playback buffer, write some periods of silence.
465 memset(fOutputBuffer
, 0, fOutputBufferSize
);
466 ssize_t size
= frames
* fOutSampleSize
* fPlaybackChannels
;
468 ssize_t chunk
= (size
> fOutputBufferSize
) ? fOutputBufferSize
: size
;
469 ssize_t count
= ::write(fOutFD
, fOutputBuffer
, chunk
);
471 jack_error("JackOSSDriver::WriteSilence error bytes written = %ld", count
);
474 fOSSWriteOffset
+= (count
/ (fOutSampleSize
* fPlaybackChannels
));
480 int JackOSSDriver::WaitAndSync()
482 oss_count_t ptr
= {0, 0, {0}};
483 if (fInFD
> 0 && fOSSReadSync
!= 0) {
484 // Predict time of next capture sync (poll() return).
485 if (fOSSReadOffset
+ fEngineControl
->fBufferSize
> 0) {
486 jack_nframes_t frames
= fOSSReadOffset
+ fEngineControl
->fBufferSize
;
487 jack_nframes_t rounded
= RoundUp(frames
, fInBlockSize
);
488 fOSSReadSync
+= FramesToTime(rounded
, fEngineControl
->fSampleRate
);
489 fOSSReadOffset
-= rounded
;
492 if (fOutFD
> 0 && fOSSWriteSync
!= 0) {
493 // Predict time of next playback sync (poll() return).
494 if (fOSSWriteOffset
> fNperiods
* fEngineControl
->fBufferSize
) {
495 jack_nframes_t frames
= fOSSWriteOffset
- fNperiods
* fEngineControl
->fBufferSize
;
496 jack_nframes_t rounded
= RoundUp(frames
, fOutBlockSize
);
497 fOSSWriteSync
+= FramesToTime(rounded
, fEngineControl
->fSampleRate
);
498 fOSSWriteOffset
-= rounded
;
501 jack_time_t poll_start
= GetMicroSeconds();
502 // Poll until recording and playback buffer are ready for this cycle.
504 poll_fd
[0].fd
= fInFD
;
505 if (fInFD
> 0 && (fForceSync
|| poll_start
< fOSSReadSync
)) {
506 poll_fd
[0].events
= POLLIN
;
508 poll_fd
[0].events
= 0;
510 poll_fd
[1].fd
= fOutFD
;
511 if (fOutFD
> 0 && (fForceSync
|| poll_start
< fOSSWriteSync
)) {
512 poll_fd
[1].events
= POLLOUT
;
514 poll_fd
[1].events
= 0;
516 while (poll_fd
[0].events
!= 0 || poll_fd
[1].events
!= 0) {
517 poll_fd
[0].revents
= 0;
518 poll_fd
[1].revents
= 0;
519 int ret
= poll(poll_fd
, 2, 500);
520 jack_time_t now
= GetMicroSeconds();
522 jack_error("JackOSSDriver::WaitAndSync poll failed with %d after %ld us", ret
, now
- poll_start
);
525 if (poll_fd
[0].revents
& POLLIN
) {
526 // Check the excess recording frames.
527 if (ioctl(fInFD
, SNDCTL_DSP_CURRENT_IPTR
, &ptr
) != -1 && ptr
.fifo_samples
>= 0) {
528 if (fInBlockSize
<= 1) {
529 // Irregular block size, let sync time converge slowly when late.
530 fOSSReadSync
= min(fOSSReadSync
, now
) / 2 + now
/ 2;
531 fOSSReadOffset
= -ptr
.fifo_samples
;
532 } else if (ptr
.fifo_samples
- fEngineControl
->fBufferSize
>= fInBlockSize
) {
533 // Too late for a reliable sync, make sure sync time is not in the future.
534 if (now
< fOSSReadSync
) {
535 fOSSReadOffset
= -ptr
.fifo_samples
;
536 jack_info("JackOSSDriver::WaitAndSync capture sync %ld us early, %ld frames", fOSSReadSync
- now
, fOSSReadOffset
);
539 } else if (fForceSync
) {
540 // Uncertain previous sync, just use sync time directly.
542 fOSSReadOffset
= -ptr
.fifo_samples
;
544 // Adapt expected sync time when early or late - in whole block intervals.
545 // Account for some speed drift, but otherwise round down to earlier interval.
546 jack_time_t interval
= FramesToTime(fInBlockSize
, fEngineControl
->fSampleRate
);
547 jack_time_t remainder
= fOSSReadSync
% interval
;
548 jack_time_t max_drift
= interval
/ 4;
549 jack_time_t rounded
= RoundDown((now
- remainder
) + max_drift
, interval
) + remainder
;
550 // Let sync time converge slowly when late, prefer earlier sync times.
551 fOSSReadSync
= min(rounded
, now
) / 2 + now
/ 2;
552 fOSSReadOffset
= -ptr
.fifo_samples
;
555 poll_fd
[0].events
= 0;
557 if (poll_fd
[1].revents
& POLLOUT
) {
558 // Check the remaining playback frames.
559 if (ioctl(fOutFD
, SNDCTL_DSP_CURRENT_OPTR
, &ptr
) != -1 && ptr
.fifo_samples
>= 0) {
560 if (fOutBlockSize
<= 1) {
561 // Irregular block size, let sync time converge slowly when late.
562 fOSSWriteSync
= min(fOSSWriteSync
, now
) / 2 + now
/ 2;
563 fOSSWriteOffset
= ptr
.fifo_samples
;
564 } else if (ptr
.fifo_samples
+ fOutBlockSize
<= fNperiods
* fEngineControl
->fBufferSize
) {
565 // Too late for a reliable sync, make sure sync time is not in the future.
566 if (now
< fOSSWriteSync
) {
567 fOSSWriteOffset
= ptr
.fifo_samples
;
568 jack_info("JackOSSDriver::WaitAndSync playback sync %ld us early, %ld frames", fOSSWriteSync
- now
, fOSSWriteOffset
);
571 } else if (fForceSync
) {
572 // Uncertain previous sync, just use sync time directly.
574 fOSSWriteOffset
= ptr
.fifo_samples
;
576 // Adapt expected sync time when early or late - in whole block intervals.
577 // Account for some speed drift, but otherwise round down to earlier interval.
578 jack_time_t interval
= FramesToTime(fOutBlockSize
, fEngineControl
->fSampleRate
);
579 jack_time_t remainder
= fOSSWriteSync
% interval
;
580 jack_time_t max_drift
= interval
/ 4;
581 jack_time_t rounded
= RoundDown((now
- remainder
) + max_drift
, interval
) + remainder
;
582 // Let sync time converge slowly when late, prefer earlier sync times.
583 fOSSWriteSync
= min(rounded
, now
) / 2 + now
/ 2;
584 fOSSWriteOffset
= ptr
.fifo_samples
;
587 poll_fd
[1].events
= 0;
593 // Compute balance of read and write buffers combined.
595 if (fInFD
> 0 && fOutFD
> 0) {
596 // Compare actual buffer content with target of (1 + n) * period.
597 fBufferBalance
+= ((1 + fNperiods
) * fEngineControl
->fBufferSize
);
598 fBufferBalance
-= (fOSSWriteOffset
- fOSSReadOffset
);
599 fBufferBalance
+= TimeToOffset(fOSSWriteSync
, fOSSReadSync
, fEngineControl
->fSampleRate
);
601 // Force balancing if sync times deviate too much.
602 jack_time_t slack
= FramesToTime((fEngineControl
->fBufferSize
* 2) / 3, fEngineControl
->fSampleRate
);
603 fForceBalancing
= fForceBalancing
|| (fOSSReadSync
> fOSSWriteSync
+ slack
);
604 fForceBalancing
= fForceBalancing
|| (fOSSWriteSync
> fOSSReadSync
+ slack
);
605 // Force balancing if buffer is badly balanced.
606 fForceBalancing
= fForceBalancing
|| (abs(fBufferBalance
) > max(fInMeanStep
, fOutMeanStep
));
609 // Print debug info every 10 seconds.
610 if (ptr
.samples
> 0 && (ptr
.samples
% (10 * fEngineControl
->fSampleRate
)) < fEngineControl
->fBufferSize
) {
611 jack_log("JackOSSDriver::Read buffer balance is %ld frames", fBufferBalance
);
612 jack_time_t now
= GetMicroSeconds();
613 jack_log("JackOSSDriver::Read recording sync %ld frames %ld us ago", fOSSReadOffset
, now
- fOSSReadSync
);
614 jack_log("JackOSSDriver::Read playback sync %ld frames %ld us ago", fOSSWriteOffset
, now
- fOSSWriteSync
);
620 int JackOSSDriver::OpenInput()
624 int cur_capture_channels
;
625 int cur_sample_format
;
626 jack_nframes_t cur_sample_rate
;
629 if (fCaptureChannels
== 0) fCaptureChannels
= 2;
631 if ((fInFD
= open(fCaptureDriverName
, O_RDONLY
| ((fExcl
) ? O_EXCL
: 0))) < 0) {
632 jack_error("JackOSSDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
636 jack_log("JackOSSDriver::OpenInput input fInFD = %d", fInFD
);
639 if (ioctl(fInFD
, SNDCTL_DSP_COOKEDMODE
, &flags
) == -1) {
640 jack_error("JackOSSDriver::OpenInput failed to set cooked mode : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
645 cur_sample_format
= GetSampleFormat(fBits
);
646 if (ioctl(fInFD
, SNDCTL_DSP_SETFMT
, &cur_sample_format
) == -1) {
647 jack_error("JackOSSDriver::OpenInput failed to set format : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
650 fInSampleSize
= GetSampleSize(cur_sample_format
);
651 if (cur_sample_format
!= GetSampleFormat(fBits
)) {
652 if (fInSampleSize
> 0) {
653 jack_info("JackOSSDriver::OpenInput driver forced %d bit sample format", fInSampleSize
* 8);
655 jack_error("JackOSSDriver::OpenInput unsupported sample format %#x", cur_sample_format
);
660 cur_capture_channels
= fCaptureChannels
;
661 if (ioctl(fInFD
, SNDCTL_DSP_CHANNELS
, &fCaptureChannels
) == -1) {
662 jack_error("JackOSSDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
665 if (cur_capture_channels
!= fCaptureChannels
) {
666 jack_info("JackOSSDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels
);
669 cur_sample_rate
= fEngineControl
->fSampleRate
;
670 if (ioctl(fInFD
, SNDCTL_DSP_SPEED
, &fEngineControl
->fSampleRate
) == -1) {
671 jack_error("JackOSSDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
674 if (cur_sample_rate
!= fEngineControl
->fSampleRate
) {
675 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl
->fSampleRate
);
678 // Internal buffer size required for one period.
679 fInputBufferSize
= fEngineControl
->fBufferSize
* fInSampleSize
* fCaptureChannels
;
681 // Get the total size of the OSS recording buffer, in sample frames.
683 if (ioctl(fInFD
, SNDCTL_DSP_GETISPACE
, &info
) == -1 || info
.fragsize
<= 0 || info
.fragstotal
<= 0) {
684 jack_error("JackOSSDriver::OpenInput failed to get buffer info : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
687 fOSSInBuffer
= info
.fragstotal
* info
.fragsize
/ (fInSampleSize
* fCaptureChannels
);
689 if (fOSSInBuffer
< fEngineControl
->fBufferSize
* (1 + fNperiods
)) {
690 // Total size of the OSS recording buffer is too small, resize it.
691 unsigned int buf_size
= fInputBufferSize
* (1 + fNperiods
);
692 // Keep current fragment size if possible - respect OSS latency settings.
693 gFragFormat
= UpToPower2(info
.fragsize
);
694 unsigned int frag_size
= 1U << gFragFormat
;
695 gFragFormat
|= ((buf_size
+ frag_size
- 1) / frag_size
) << 16;
696 jack_info("JackOSSDriver::OpenInput request %d fragments of %d", (gFragFormat
>> 16), frag_size
);
697 if (ioctl(fInFD
, SNDCTL_DSP_SETFRAGMENT
, &gFragFormat
) == -1) {
698 jack_error("JackOSSDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
701 // Check the new OSS recording buffer size.
703 if (ioctl(fInFD
, SNDCTL_DSP_GETISPACE
, &info
) == -1 || info
.fragsize
<= 0 || info
.fragstotal
<= 0) {
704 jack_error("JackOSSDriver::OpenInput failed to get buffer info : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
707 fOSSInBuffer
= info
.fragstotal
* info
.fragsize
/ (fInSampleSize
* fCaptureChannels
);
710 if (fOSSInBuffer
> fEngineControl
->fBufferSize
) {
711 int mark
= fInputBufferSize
;
712 if (ioctl(fInFD
, SNDCTL_DSP_LOW_WATER
, &mark
) != 0) {
713 jack_error("JackOSSDriver::OpenInput failed to set low water mark : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
716 jack_info("JackOSSDriver::OpenInput set low water mark to %d", mark
);
719 fInputBuffer
= (void*)calloc(fInputBufferSize
, 1);
720 assert(fInputBuffer
);
722 if (ProbeInBlockSize() < 0) {
733 int JackOSSDriver::OpenOutput()
737 int cur_sample_format
;
738 int cur_playback_channels
;
739 jack_nframes_t cur_sample_rate
;
742 if (fPlaybackChannels
== 0) fPlaybackChannels
= 2;
744 if ((fOutFD
= open(fPlaybackDriverName
, O_WRONLY
| ((fExcl
) ? O_EXCL
: 0))) < 0) {
745 jack_error("JackOSSDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
749 jack_log("JackOSSDriver::OpenOutput output fOutFD = %d", fOutFD
);
752 if (ioctl(fOutFD
, SNDCTL_DSP_COOKEDMODE
, &flags
) == -1) {
753 jack_error("JackOSSDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
758 cur_sample_format
= GetSampleFormat(fBits
);
759 if (ioctl(fOutFD
, SNDCTL_DSP_SETFMT
, &cur_sample_format
) == -1) {
760 jack_error("JackOSSDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
763 fOutSampleSize
= GetSampleSize(cur_sample_format
);
764 if (cur_sample_format
!= GetSampleFormat(fBits
)) {
765 if (fOutSampleSize
> 0) {
766 jack_info("JackOSSDriver::OpenOutput driver forced %d bit sample format", fOutSampleSize
* 8);
768 jack_error("JackOSSDriver::OpenOutput unsupported sample format %#x", cur_sample_format
);
773 cur_playback_channels
= fPlaybackChannels
;
774 if (ioctl(fOutFD
, SNDCTL_DSP_CHANNELS
, &fPlaybackChannels
) == -1) {
775 jack_error("JackOSSDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
778 if (cur_playback_channels
!= fPlaybackChannels
) {
779 jack_info("JackOSSDriver::OpenOutput driver forced the number of playback channels %ld", fPlaybackChannels
);
782 cur_sample_rate
= fEngineControl
->fSampleRate
;
783 if (ioctl(fOutFD
, SNDCTL_DSP_SPEED
, &fEngineControl
->fSampleRate
) == -1) {
784 jack_error("JackOSSDriver::OpenOutput failed to set sample rate : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
787 if (cur_sample_rate
!= fEngineControl
->fSampleRate
) {
788 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl
->fSampleRate
);
791 // Internal buffer size required for one period.
792 fOutputBufferSize
= fEngineControl
->fBufferSize
* fOutSampleSize
* fPlaybackChannels
;
794 // Get the total size of the OSS playback buffer, in sample frames.
796 if (ioctl(fOutFD
, SNDCTL_DSP_GETOSPACE
, &info
) == -1 || info
.fragsize
<= 0 || info
.fragstotal
<= 0) {
797 jack_error("JackOSSDriver::OpenOutput failed to get buffer info : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
800 fOSSOutBuffer
= info
.fragstotal
* info
.fragsize
/ (fOutSampleSize
* fPlaybackChannels
);
802 if (fOSSOutBuffer
< fEngineControl
->fBufferSize
* (1 + fNperiods
)) {
803 // Total size of the OSS playback buffer is too small, resize it.
804 unsigned int buf_size
= fOutputBufferSize
* (1 + fNperiods
);
805 // Keep current fragment size if possible - respect OSS latency settings.
806 // Some sound cards like Intel HDA may stutter when changing the fragment size.
807 gFragFormat
= UpToPower2(info
.fragsize
);
808 unsigned int frag_size
= 1U << gFragFormat
;
809 gFragFormat
|= ((buf_size
+ frag_size
- 1) / frag_size
) << 16;
810 jack_info("JackOSSDriver::OpenOutput request %d fragments of %d", (gFragFormat
>> 16), frag_size
);
811 if (ioctl(fOutFD
, SNDCTL_DSP_SETFRAGMENT
, &gFragFormat
) == -1) {
812 jack_error("JackOSSDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
815 // Check the new OSS playback buffer size.
817 if (ioctl(fOutFD
, SNDCTL_DSP_GETOSPACE
, &info
) == -1 || info
.fragsize
<= 0 || info
.fragstotal
<= 0) {
818 jack_error("JackOSSDriver::OpenOutput failed to get buffer info : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
821 fOSSOutBuffer
= info
.fragstotal
* info
.fragsize
/ (fOutSampleSize
* fPlaybackChannels
);
824 if (fOSSOutBuffer
> fEngineControl
->fBufferSize
* fNperiods
) {
825 jack_nframes_t low
= fOSSOutBuffer
- (fNperiods
* fEngineControl
->fBufferSize
);
826 int mark
= low
* fOutSampleSize
* fPlaybackChannels
;
827 if (ioctl(fOutFD
, SNDCTL_DSP_LOW_WATER
, &mark
) != 0) {
828 jack_error("JackOSSDriver::OpenOutput failed to set low water mark : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
831 jack_info("JackOSSDriver::OpenOutput set low water mark to %d", mark
);
834 fOutputBuffer
= (void*)calloc(fOutputBufferSize
, 1);
835 assert(fOutputBuffer
);
837 if (ProbeOutBlockSize() < 0) {
848 int JackOSSDriver::Open(jack_nframes_t nframes
,
850 jack_nframes_t samplerate
,
857 const char* capture_driver_uid
,
858 const char* playback_driver_uid
,
859 jack_nframes_t capture_latency
,
860 jack_nframes_t playback_latency
,
864 // Store local settings first.
865 fCapture
= capturing
;
868 fIgnoreHW
= ignorehwbuf
;
869 fNperiods
= user_nperiods
;
871 fExtraCaptureLatency
= capture_latency
;
872 fExtraPlaybackLatency
= playback_latency
;
874 // Additional playback latency introduced by the OSS buffer. The extra hardware
875 // latency given by the user should then be symmetric as reported by jack_iodelay.
876 playback_latency
+= user_nperiods
* nframes
;
877 // Generic JackAudioDriver Open
878 if (JackAudioDriver::Open(nframes
, samplerate
, capturing
, playing
, inchannels
, outchannels
, monitor
,
879 capture_driver_uid
, playback_driver_uid
, capture_latency
, playback_latency
) != 0) {
884 // Force memory page in
885 memset(&gCycleTable
, 0, sizeof(gCycleTable
));
897 int JackOSSDriver::Close()
900 FILE* file
= fopen("OSSProfiling.log", "w");
903 jack_info("Writing OSS driver timing data....");
904 for (int i
= 1; i
< gCycleCount
; i
++) {
905 int d1
= gCycleTable
.fTable
[i
].fAfterRead
- gCycleTable
.fTable
[i
].fBeforeRead
;
906 int d2
= gCycleTable
.fTable
[i
].fAfterReadConvert
- gCycleTable
.fTable
[i
].fAfterRead
;
907 int d3
= gCycleTable
.fTable
[i
].fAfterWrite
- gCycleTable
.fTable
[i
].fBeforeWrite
;
908 int d4
= gCycleTable
.fTable
[i
].fBeforeWrite
- gCycleTable
.fTable
[i
].fBeforeWriteConvert
;
909 fprintf(file
, "%d \t %d \t %d \t %d \t \n", d1
, d2
, d3
, d4
);
913 jack_error("JackOSSDriver::Close : cannot open OSSProfiling.log file");
916 file
= fopen("TimingOSS.plot", "w");
919 jack_error("JackOSSDriver::Close cannot open TimingOSS.plot file");
922 fprintf(file
, "set grid\n");
923 fprintf(file
, "set title \"OSS audio driver timing\"\n");
924 fprintf(file
, "set xlabel \"audio cycles\"\n");
925 fprintf(file
, "set ylabel \"usec\"\n");
926 fprintf(file
, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
927 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
928 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
929 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
931 fprintf(file
, "set output 'TimingOSS.pdf\n");
932 fprintf(file
, "set terminal pdf\n");
934 fprintf(file
, "set grid\n");
935 fprintf(file
, "set title \"OSS audio driver timing\"\n");
936 fprintf(file
, "set xlabel \"audio cycles\"\n");
937 fprintf(file
, "set ylabel \"usec\"\n");
938 fprintf(file
, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
939 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
940 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
941 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
946 int res
= JackAudioDriver::Close();
952 int JackOSSDriver::OpenAux()
954 // (Re-)Initialize runtime variables.
955 fInSampleSize
= fOutSampleSize
= 0;
956 fInputBufferSize
= fOutputBufferSize
= 0;
957 fInBlockSize
= fOutBlockSize
= 1;
958 fInMeanStep
= fOutMeanStep
= 0;
959 fOSSInBuffer
= fOSSOutBuffer
= 0;
960 fOSSReadSync
= fOSSWriteSync
= 0;
961 fOSSReadOffset
= fOSSWriteOffset
= 0;
963 fForceBalancing
= false;
966 if (fCapture
&& (OpenInput() < 0)) {
970 if (fPlayback
&& (OpenOutput() < 0)) {
978 void JackOSSDriver::CloseAux()
980 if (fCapture
&& fInFD
> 0) {
985 if (fPlayback
&& fOutFD
> 0) {
996 fOutputBuffer
= NULL
;
999 int JackOSSDriver::Read()
1001 if (fInFD
> 0 && fOSSReadSync
== 0) {
1002 // First cycle, account for leftover samples from previous reads.
1005 if (ioctl(fInFD
, SNDCTL_DSP_CURRENT_IPTR
, &ptr
) == 0 && ptr
.fifo_samples
> 0) {
1006 jack_log("JackOSSDriver::Read pre recording samples = %ld, fifo_samples = %d", ptr
.samples
, ptr
.fifo_samples
);
1007 fOSSReadOffset
= -ptr
.fifo_samples
;
1010 // Start capture by reading a new hardware block.,
1011 jack_nframes_t discard
= fInMeanStep
- fOSSReadOffset
;
1012 // Let half a block or at most 1ms remain in buffer, avoid drift issues at start.
1013 discard
-= min(TimeToFrames(1000, fEngineControl
->fSampleRate
), (fInMeanStep
/ 2));
1014 jack_log("JackOSSDriver::Read start recording discard %ld frames", discard
);
1015 fOSSReadSync
= GetMicroSeconds();
1019 fForceBalancing
= true;
1022 if (fOutFD
> 0 && fOSSWriteSync
== 0) {
1023 // First cycle, account for leftover samples from previous writes.
1024 fOSSWriteOffset
= 0;
1026 if (ioctl(fOutFD
, SNDCTL_DSP_CURRENT_OPTR
, &ptr
) == 0 && ptr
.fifo_samples
> 0) {
1027 jack_log("JackOSSDriver::Read pre playback samples = %ld, fifo_samples = %d", ptr
.samples
, ptr
.fifo_samples
);
1028 fOSSWriteOffset
= ptr
.fifo_samples
;
1031 // Start playback with silence, target latency as given by the user.
1032 jack_nframes_t silence
= (fNperiods
+ 1) * fEngineControl
->fBufferSize
;
1033 // Minus half a block or at most 1ms of frames, avoid drift issues at start.
1034 silence
-= min(TimeToFrames(1000, fEngineControl
->fSampleRate
), (fOutMeanStep
/ 2));
1035 silence
= max(silence
- fOSSWriteOffset
, 1LL);
1036 jack_log("JackOSSDriver::Read start playback with %ld frames of silence", silence
);
1037 fOSSWriteSync
= GetMicroSeconds();
1038 WriteSilence(silence
);
1041 fForceBalancing
= true;
1045 gCycleTable
.fTable
[gCycleCount
].fBeforeRead
= GetMicroSeconds();
1048 if (WaitAndSync() < 0) {
1052 // Keep begin cycle time
1053 JackDriver::CycleTakeBeginTime();
1059 // Try to read multiple times in case of short reads.
1061 for (int i
= 0; i
< 3 && count
< fInputBufferSize
; ++i
) {
1062 ssize_t ret
= ::read(fInFD
, ((char*)fInputBuffer
) + count
, fInputBufferSize
- count
);
1064 jack_error("JackOSSDriver::Read error = %s", strerror(errno
));
1070 // Read offset accounting and overrun detection.
1072 jack_time_t now
= GetMicroSeconds();
1073 jack_time_t sync
= max(fOSSReadSync
, fOSSWriteSync
);
1074 if (now
- sync
> 1000) {
1075 // Blocking read() may indicate sample loss in OSS - force resync.
1076 jack_log("JackOSSDriver::Read long read duration of %ld us", now
- sync
);
1079 long long passed
= TimeToFrames(now
- fOSSReadSync
, fEngineControl
->fSampleRate
);
1080 passed
-= (passed
% fInBlockSize
);
1081 if (passed
> fOSSReadOffset
+ fOSSInBuffer
) {
1082 // Overrun, adjust read and write position.
1083 long long missed
= passed
- (fOSSReadOffset
+ fOSSInBuffer
);
1084 jack_error("JackOSSDriver::Read missed %ld frames by overrun, passed=%ld, sync=%ld, now=%ld", missed
, passed
, fOSSReadSync
, now
);
1085 fOSSReadOffset
+= missed
;
1086 fOSSWriteOffset
+= missed
;
1087 NotifyXRun(now
, float(FramesToTime(missed
, fEngineControl
->fSampleRate
)));
1089 fOSSReadOffset
+= count
/ (fInSampleSize
* fCaptureChannels
);
1093 if (count
> 0 && count
!= (int)fInputBufferSize
)
1094 jack_log("JackOSSDriver::Read count = %ld", count
/ (fInSampleSize
* fCaptureChannels
));
1095 gCycleTable
.fTable
[gCycleCount
].fAfterRead
= GetMicroSeconds();
1098 // Check and clear OSS errors.
1099 audio_errinfo ei_in
;
1100 if (ioctl(fInFD
, SNDCTL_DSP_GETERROR
, &ei_in
) == 0) {
1102 // Not reliable for overrun detection, virtual_oss doesn't implement it.
1103 if (ei_in
.rec_overruns
> 0 ) {
1104 jack_error("JackOSSDriver::Read %d overrun events", ei_in
.rec_overruns
);
1107 if (ei_in
.rec_errorcount
> 0 && ei_in
.rec_lasterror
!= 0) {
1108 jack_error("%d OSS rec event(s), last=%05d:%d", ei_in
.rec_errorcount
, ei_in
.rec_lasterror
, ei_in
.rec_errorparm
);
1112 if (count
< fInputBufferSize
) {
1113 jack_error("JackOSSDriver::Read incomplete read of %ld bytes", count
);
1117 for (int i
= 0; i
< fCaptureChannels
; i
++) {
1118 if (fGraphManager
->GetConnectionsNum(fCapturePortList
[i
]) > 0) {
1119 CopyAndConvertIn(GetInputBuffer(i
), fInputBuffer
, fEngineControl
->fBufferSize
, i
, fCaptureChannels
, fInSampleSize
* 8);
1124 gCycleTable
.fTable
[gCycleCount
].fAfterReadConvert
= GetMicroSeconds();
1130 int JackOSSDriver::Write()
1136 unsigned int skip
= 0;
1137 jack_time_t start
= GetMicroSeconds();
1139 if (fOSSWriteSync
> 0) {
1140 // Check for underruns, rounded to hardware block size if available.
1141 long long passed
= TimeToFrames(start
- fOSSWriteSync
, fEngineControl
->fSampleRate
);
1142 long long consumed
= passed
- (passed
% fOutBlockSize
);
1143 long long tolerance
= (fOutBlockSize
> 1) ? 0 : fOutMeanStep
;
1144 long long overdue
= 0;
1145 if (consumed
> fOSSWriteOffset
+ tolerance
) {
1146 // Skip playback data that already passed.
1147 overdue
= consumed
- fOSSWriteOffset
- tolerance
;
1148 jack_error("JackOSSDriver::Write underrun, late by %ld, skip %ld frames", passed
- fOSSWriteOffset
, overdue
);
1149 jack_log("JackOSSDriver::Write playback offset %ld frames synced %ld us ago", fOSSWriteOffset
, start
- fOSSWriteSync
);
1150 // Also consider buffer balance, there was a gap in playback anyway.
1151 fForceBalancing
= true;
1153 // Account for buffer balance if needed.
1154 long long progress
= fEngineControl
->fBufferSize
;
1155 if (fForceBalancing
) {
1156 fForceBalancing
= false;
1157 progress
= max(progress
+ fBufferBalance
, 0LL);
1158 jack_info("JackOSSDriver::Write buffer balancing %ld frames", fBufferBalance
);
1159 jack_log("JackOSSDriver::Write recording sync %ld frames %ld us ago", fOSSReadOffset
, start
- fOSSReadSync
);
1160 jack_log("JackOSSDriver::Write playback sync %ld frames %ld us ago", fOSSWriteOffset
, start
- fOSSWriteSync
);
1162 // How many samples to skip or prepend due to underrun and balancing.
1163 long long write_length
= progress
- overdue
;
1164 if (write_length
<= 0) {
1165 skip
+= fOutputBufferSize
;
1166 fOSSWriteOffset
+= progress
;
1167 } else if (write_length
< fEngineControl
->fBufferSize
) {
1168 skip
+= (fEngineControl
->fBufferSize
- write_length
) * fOutSampleSize
* fPlaybackChannels
;
1169 fOSSWriteOffset
+= overdue
;
1170 } else if (write_length
> fEngineControl
->fBufferSize
) {
1171 jack_nframes_t fill
= write_length
- fEngineControl
->fBufferSize
;
1177 gCycleTable
.fTable
[gCycleCount
].fBeforeWriteConvert
= GetMicroSeconds();
1180 memset(fOutputBuffer
, 0, fOutputBufferSize
);
1181 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
1182 if (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[i
]) > 0) {
1183 CopyAndConvertOut(fOutputBuffer
, GetOutputBuffer(i
), fEngineControl
->fBufferSize
, i
, fPlaybackChannels
, fOutSampleSize
* 8);
1188 gCycleTable
.fTable
[gCycleCount
].fBeforeWrite
= GetMicroSeconds();
1191 // Try multiple times in case of short writes.
1192 ssize_t count
= skip
;
1193 for (int i
= 0; i
< 3 && count
< fOutputBufferSize
; ++i
) {
1194 ssize_t ret
= ::write(fOutFD
, ((char*)fOutputBuffer
) + count
, fOutputBufferSize
- count
);
1196 jack_error("JackOSSDriver::Write error = %s", strerror(errno
));
1202 fOSSWriteOffset
+= ((count
- skip
) / (fOutSampleSize
* fPlaybackChannels
));
1204 jack_time_t duration
= GetMicroSeconds() - start
;
1205 if (duration
> 1000) {
1206 // Blocking write() may indicate sample loss in OSS - force resync.
1207 jack_log("JackOSSDriver::Write long write duration of %ld us", duration
);
1212 if (count
> 0 && count
!= (int)fOutputBufferSize
)
1213 jack_log("JackOSSDriver::Write count = %ld", (count
- skip
) / (fOutSampleSize
* fPlaybackChannels
));
1214 gCycleTable
.fTable
[gCycleCount
].fAfterWrite
= GetMicroSeconds();
1215 gCycleCount
= (gCycleCount
== CYCLE_POINTS
- 1) ? gCycleCount
: gCycleCount
+ 1;
1218 // Check and clear OSS errors.
1219 audio_errinfo ei_out
;
1220 if (ioctl(fOutFD
, SNDCTL_DSP_GETERROR
, &ei_out
) == 0) {
1222 // Not reliable for underrun detection, virtual_oss does not implement it.
1223 if (ei_out
.play_underruns
> 0) {
1224 jack_error("JackOSSDriver::Write %d underrun events", ei_out
.play_underruns
);
1227 if (ei_out
.play_errorcount
> 0 && ei_out
.play_lasterror
!= 0) {
1228 jack_error("%d OSS play event(s), last=%05d:%d",ei_out
.play_errorcount
, ei_out
.play_lasterror
, ei_out
.play_errorparm
);
1232 if (count
< (int)fOutputBufferSize
) {
1233 jack_error("JackOSSDriver::Write incomplete write of %ld bytes", count
- skip
);
1240 int JackOSSDriver::SetBufferSize(jack_nframes_t buffer_size
)
1244 // Additional latency introduced by the OSS buffer, depends on buffer size.
1245 fCaptureLatency
= fExtraCaptureLatency
;
1246 fPlaybackLatency
= fExtraPlaybackLatency
+ fNperiods
* buffer_size
;
1248 JackAudioDriver::SetBufferSize(buffer_size
); // Generic change, never fails
1252 } // end of namespace
1259 SERVER_EXPORT jack_driver_desc_t
* driver_get_descriptor()
1261 jack_driver_desc_t
* desc
;
1262 jack_driver_desc_filler_t filler
;
1263 jack_driver_param_value_t value
;
1265 desc
= jack_driver_descriptor_construct("oss", JackDriverMaster
, "OSS API based audio backend", &filler
);
1267 value
.ui
= OSS_DRIVER_DEF_FS
;
1268 jack_driver_descriptor_add_parameter(desc
, &filler
, "rate", 'r', JackDriverParamUInt
, &value
, NULL
, "Sample rate", NULL
);
1270 value
.ui
= OSS_DRIVER_DEF_BLKSIZE
;
1271 jack_driver_descriptor_add_parameter(desc
, &filler
, "period", 'p', JackDriverParamUInt
, &value
, NULL
, "Frames per period", NULL
);
1273 value
.ui
= OSS_DRIVER_DEF_NPERIODS
;
1274 jack_driver_descriptor_add_parameter(desc
, &filler
, "nperiods", 'n', JackDriverParamUInt
, &value
, NULL
, "Number of periods to prefill output buffer", NULL
);
1276 value
.i
= OSS_DRIVER_DEF_BITS
;
1277 jack_driver_descriptor_add_parameter(desc
, &filler
, "wordlength", 'w', JackDriverParamInt
, &value
, NULL
, "Word length", NULL
);
1279 value
.ui
= OSS_DRIVER_DEF_INS
;
1280 jack_driver_descriptor_add_parameter(desc
, &filler
, "inchannels", 'i', JackDriverParamUInt
, &value
, NULL
, "Capture channels", NULL
);
1282 value
.ui
= OSS_DRIVER_DEF_OUTS
;
1283 jack_driver_descriptor_add_parameter(desc
, &filler
, "outchannels", 'o', JackDriverParamUInt
, &value
, NULL
, "Playback channels", NULL
);
1286 jack_driver_descriptor_add_parameter(desc
, &filler
, "excl", 'e', JackDriverParamBool
, &value
, NULL
, "Exclusive and direct device access", NULL
);
1288 strcpy(value
.str
, OSS_DRIVER_DEF_DEV
);
1289 jack_driver_descriptor_add_parameter(desc
, &filler
, "capture", 'C', JackDriverParamString
, &value
, NULL
, "Input device", NULL
);
1290 jack_driver_descriptor_add_parameter(desc
, &filler
, "playback", 'P', JackDriverParamString
, &value
, NULL
, "Output device", NULL
);
1291 jack_driver_descriptor_add_parameter(desc
, &filler
, "device", 'd', JackDriverParamString
, &value
, NULL
, "OSS device name", NULL
);
1294 jack_driver_descriptor_add_parameter(desc
, &filler
, "ignorehwbuf", 'b', JackDriverParamBool
, &value
, NULL
, "Ignore hardware period size", NULL
);
1297 jack_driver_descriptor_add_parameter(desc
, &filler
, "input-latency", 'I', JackDriverParamUInt
, &value
, NULL
, "Extra input latency", NULL
);
1298 jack_driver_descriptor_add_parameter(desc
, &filler
, "output-latency", 'O', JackDriverParamUInt
, &value
, NULL
, "Extra output latency", NULL
);
1303 SERVER_EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackLockedEngine
* engine
, Jack::JackSynchro
* table
, const JSList
* params
)
1305 int bits
= OSS_DRIVER_DEF_BITS
;
1306 jack_nframes_t srate
= OSS_DRIVER_DEF_FS
;
1307 jack_nframes_t frames_per_interrupt
= OSS_DRIVER_DEF_BLKSIZE
;
1308 const char* capture_pcm_name
= OSS_DRIVER_DEF_DEV
;
1309 const char* playback_pcm_name
= OSS_DRIVER_DEF_DEV
;
1310 bool capture
= false;
1311 bool playback
= false;
1314 bool monitor
= false;
1316 unsigned int nperiods
= OSS_DRIVER_DEF_NPERIODS
;
1318 const jack_driver_param_t
*param
;
1319 bool ignorehwbuf
= false;
1320 jack_nframes_t systemic_input_latency
= 0;
1321 jack_nframes_t systemic_output_latency
= 0;
1323 for (node
= params
; node
; node
= jack_slist_next(node
)) {
1325 param
= (const jack_driver_param_t
*)node
->data
;
1327 switch (param
->character
) {
1330 srate
= param
->value
.ui
;
1334 frames_per_interrupt
= (unsigned int)param
->value
.ui
;
1338 nperiods
= (unsigned int)param
->value
.ui
;
1342 bits
= param
->value
.i
;
1346 chan_in
= (int)param
->value
.ui
;
1350 chan_out
= (int)param
->value
.ui
;
1355 if (strcmp(param
->value
.str
, "none") != 0) {
1356 capture_pcm_name
= param
->value
.str
;
1362 if (strcmp(param
->value
.str
, "none") != 0) {
1363 playback_pcm_name
= param
->value
.str
;
1368 playback_pcm_name
= param
->value
.str
;
1369 capture_pcm_name
= param
->value
.str
;
1381 systemic_input_latency
= param
->value
.ui
;
1385 systemic_output_latency
= param
->value
.ui
;
1390 // duplex is the default
1391 if (!capture
&& !playback
) {
1396 Jack::JackOSSDriver
* oss_driver
= new Jack::JackOSSDriver("system", "oss", engine
, table
);
1397 Jack::JackDriverClientInterface
* threaded_driver
= new Jack::JackThreadedDriver(oss_driver
);
1399 // Special open for OSS driver...
1400 if (oss_driver
->Open(frames_per_interrupt
, nperiods
, srate
, capture
, playback
, chan_in
, chan_out
,
1401 excl
, monitor
, capture_pcm_name
, playback_pcm_name
, systemic_input_latency
, systemic_output_latency
, bits
, ignorehwbuf
) == 0) {
1402 return threaded_driver
;
1404 delete threaded_driver
; // Delete the decorated driver