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>
46 #define CYCLE_POINTS 500000
49 jack_time_t fBeforeRead
;
50 jack_time_t fAfterRead
;
51 jack_time_t fAfterReadConvert
;
52 jack_time_t fBeforeWrite
;
53 jack_time_t fAfterWrite
;
54 jack_time_t fBeforeWriteConvert
;
57 struct OSSCycleTable
{
58 jack_time_t fBeforeFirstWrite
;
59 jack_time_t fAfterFirstWrite
;
60 OSSCycle fTable
[CYCLE_POINTS
];
63 OSSCycleTable gCycleTable
;
68 inline int int2pow2(int x
) { int r
= 0; while ((1 << r
) < x
) r
++; return r
; }
70 static inline void CopyAndConvertIn(jack_sample_t
*dst
, void *src
, size_t nframes
, int channel
, int chcount
, int bits
)
75 signed short *s16src
= (signed short*)src
;
77 sample_move_dS_s16(dst
, (char*)s16src
, nframes
, chcount
<<1);
81 signed int *s32src
= (signed int*)src
;
83 sample_move_dS_s24(dst
, (char*)s32src
, nframes
, chcount
<<2);
87 signed int *s32src
= (signed int*)src
;
89 sample_move_dS_s32u24(dst
, (char*)s32src
, nframes
, chcount
<<2);
95 static inline void CopyAndConvertOut(void *dst
, jack_sample_t
*src
, size_t nframes
, int channel
, int chcount
, int bits
)
100 signed short *s16dst
= (signed short*)dst
;
102 sample_move_d16_sS((char*)s16dst
, src
, nframes
, chcount
<<1, NULL
); // No dithering for now...
106 signed int *s32dst
= (signed int*)dst
;
108 sample_move_d24_sS((char*)s32dst
, src
, nframes
, chcount
<<2, NULL
); // No dithering for now...
112 signed int *s32dst
= (signed int*)dst
;
114 sample_move_d32u24_sS((char*)s32dst
, src
, nframes
, chcount
<<2, NULL
);
120 void JackOSSDriver::SetSampleFormat()
124 case 24: /* native-endian LSB aligned 24-bits in 32-bits integer */
125 fSampleFormat
= AFMT_S24_NE
;
126 fSampleSize
= sizeof(int);
128 case 32: /* native-endian 32-bit integer */
129 fSampleFormat
= AFMT_S32_NE
;
130 fSampleSize
= sizeof(int);
132 case 16: /* native-endian 16-bit integer */
134 fSampleFormat
= AFMT_S16_NE
;
135 fSampleSize
= sizeof(short);
140 void JackOSSDriver::DisplayDeviceInfo()
143 oss_audioinfo ai_in
, ai_out
;
144 memset(&info
, 0, sizeof(audio_buf_info
));
147 // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html
148 jack_info("Audio Interface Description :");
149 jack_info("Sampling Frequency : %d, Sample Format : %d, Mode : %d", fEngineControl
->fSampleRate
, fSampleFormat
, fRWMode
);
151 if (fRWMode
& kWrite
) {
154 if (ioctl(fOutFD
, OSS_SYSINFO
, &si
) == -1) {
155 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
157 jack_info("OSS product %s", si
.product
);
158 jack_info("OSS version %s", si
.version
);
159 jack_info("OSS version num %d", si
.versionnum
);
160 jack_info("OSS numaudios %d", si
.numaudios
);
161 jack_info("OSS numaudioengines %d", si
.numaudioengines
);
162 jack_info("OSS numcards %d", si
.numcards
);
165 jack_info("Output capabilities - %d channels : ", fPlaybackChannels
);
166 jack_info("Output block size = %d", fOutputBufferSize
);
168 if (ioctl(fOutFD
, SNDCTL_DSP_GETOSPACE
, &info
) == -1) {
169 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
171 jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
172 info
.fragments
, info
.fragstotal
, info
.fragsize
, info
.bytes
);
175 if (ioctl(fOutFD
, SNDCTL_DSP_GETCAPS
, &cap
) == -1) {
176 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
178 if (cap
& DSP_CAP_DUPLEX
) jack_info(" DSP_CAP_DUPLEX");
179 if (cap
& DSP_CAP_REALTIME
) jack_info(" DSP_CAP_REALTIME");
180 if (cap
& DSP_CAP_BATCH
) jack_info(" DSP_CAP_BATCH");
181 if (cap
& DSP_CAP_COPROC
) jack_info(" DSP_CAP_COPROC");
182 if (cap
& DSP_CAP_TRIGGER
) jack_info(" DSP_CAP_TRIGGER");
183 if (cap
& DSP_CAP_MMAP
) jack_info(" DSP_CAP_MMAP");
184 if (cap
& DSP_CAP_MULTI
) jack_info(" DSP_CAP_MULTI");
185 if (cap
& DSP_CAP_BIND
) jack_info(" DSP_CAP_BIND");
189 if (fRWMode
& kRead
) {
192 if (ioctl(fInFD
, OSS_SYSINFO
, &si
) == -1) {
193 jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
195 jack_info("OSS product %s", si
.product
);
196 jack_info("OSS version %s", si
.version
);
197 jack_info("OSS version num %d", si
.versionnum
);
198 jack_info("OSS numaudios %d", si
.numaudios
);
199 jack_info("OSS numaudioengines %d", si
.numaudioengines
);
200 jack_info("OSS numcards %d", si
.numcards
);
203 jack_info("Input capabilities - %d channels : ", fCaptureChannels
);
204 jack_info("Input block size = %d", fInputBufferSize
);
206 if (ioctl(fInFD
, SNDCTL_DSP_GETISPACE
, &info
) == -1) {
207 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
209 jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d",
210 info
.fragments
, info
.fragstotal
, info
.fragsize
, info
.bytes
);
213 if (ioctl(fInFD
, SNDCTL_DSP_GETCAPS
, &cap
) == -1) {
214 jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
216 if (cap
& DSP_CAP_DUPLEX
) jack_info(" DSP_CAP_DUPLEX");
217 if (cap
& DSP_CAP_REALTIME
) jack_info(" DSP_CAP_REALTIME");
218 if (cap
& DSP_CAP_BATCH
) jack_info(" DSP_CAP_BATCH");
219 if (cap
& DSP_CAP_COPROC
) jack_info(" DSP_CAP_COPROC");
220 if (cap
& DSP_CAP_TRIGGER
) jack_info(" DSP_CAP_TRIGGER");
221 if (cap
& DSP_CAP_MMAP
) jack_info(" DSP_CAP_MMAP");
222 if (cap
& DSP_CAP_MULTI
) jack_info(" DSP_CAP_MULTI");
223 if (cap
& DSP_CAP_BIND
) jack_info(" DSP_CAP_BIND");
227 if (ai_in
.rate_source
!= ai_out
.rate_source
) {
228 jack_info("Warning : input and output are not necessarily driven by the same clock!");
232 int JackOSSDriver::OpenInput()
236 int cur_capture_channels
;
237 int cur_sample_format
;
238 jack_nframes_t cur_sample_rate
;
240 if (fCaptureChannels
== 0) fCaptureChannels
= 2;
242 if ((fInFD
= open(fCaptureDriverName
, O_RDONLY
| ((fExcl
) ? O_EXCL
: 0))) < 0) {
243 jack_error("JackOSSDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
247 jack_log("JackOSSDriver::OpenInput input fInFD = %d", fInFD
);
250 if (ioctl(fInFD
, SNDCTL_DSP_COOKEDMODE
, &flags
) == -1) {
251 jack_error("JackOSSDriver::OpenInput failed to set cooked mode : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
256 gFragFormat
= (2 << 16) + int2pow2(fEngineControl
->fBufferSize
* fSampleSize
* fCaptureChannels
);
257 if (ioctl(fInFD
, SNDCTL_DSP_SETFRAGMENT
, &gFragFormat
) == -1) {
258 jack_error("JackOSSDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
262 cur_sample_format
= fSampleFormat
;
263 if (ioctl(fInFD
, SNDCTL_DSP_SETFMT
, &fSampleFormat
) == -1) {
264 jack_error("JackOSSDriver::OpenInput failed to set format : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
267 if (cur_sample_format
!= fSampleFormat
) {
268 jack_info("JackOSSDriver::OpenInput driver forced the sample format %ld", fSampleFormat
);
271 cur_capture_channels
= fCaptureChannels
;
272 if (ioctl(fInFD
, SNDCTL_DSP_CHANNELS
, &fCaptureChannels
) == -1) {
273 jack_error("JackOSSDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
276 if (cur_capture_channels
!= fCaptureChannels
) {
277 jack_info("JackOSSDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels
);
280 cur_sample_rate
= fEngineControl
->fSampleRate
;
281 if (ioctl(fInFD
, SNDCTL_DSP_SPEED
, &fEngineControl
->fSampleRate
) == -1) {
282 jack_error("JackOSSDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
285 if (cur_sample_rate
!= fEngineControl
->fSampleRate
) {
286 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl
->fSampleRate
);
289 fInputBufferSize
= 0;
290 if (ioctl(fInFD
, SNDCTL_DSP_GETBLKSIZE
, &fInputBufferSize
) == -1) {
291 jack_error("JackOSSDriver::OpenInput failed to get fragments : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
295 if (fInputBufferSize
!= fEngineControl
->fBufferSize
* fSampleSize
* fCaptureChannels
) {
297 int new_buffer_size
= fInputBufferSize
/ (fSampleSize
* fCaptureChannels
);
298 jack_info("JackOSSDriver::OpenInput driver forced buffer size %ld", new_buffer_size
);
299 JackAudioDriver::SetBufferSize(new_buffer_size
); // never fails
301 jack_error("JackOSSDriver::OpenInput wanted buffer size cannot be obtained");
306 fInputBuffer
= (void*)calloc(fInputBufferSize
, 1);
307 assert(fInputBuffer
);
315 int JackOSSDriver::OpenOutput()
319 int cur_sample_format
;
320 int cur_playback_channels
;
321 jack_nframes_t cur_sample_rate
;
323 if (fPlaybackChannels
== 0) fPlaybackChannels
= 2;
325 if ((fOutFD
= open(fPlaybackDriverName
, O_WRONLY
| ((fExcl
) ? O_EXCL
: 0))) < 0) {
326 jack_error("JackOSSDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
330 jack_log("JackOSSDriver::OpenOutput output fOutFD = %d", fOutFD
);
333 if (ioctl(fOutFD
, SNDCTL_DSP_COOKEDMODE
, &flags
) == -1) {
334 jack_error("JackOSSDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
339 gFragFormat
= (2 << 16) + int2pow2(fEngineControl
->fBufferSize
* fSampleSize
* fPlaybackChannels
);
340 if (ioctl(fOutFD
, SNDCTL_DSP_SETFRAGMENT
, &gFragFormat
) == -1) {
341 jack_error("JackOSSDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
345 cur_sample_format
= fSampleFormat
;
346 if (ioctl(fOutFD
, SNDCTL_DSP_SETFMT
, &fSampleFormat
) == -1) {
347 jack_error("JackOSSDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
350 if (cur_sample_format
!= fSampleFormat
) {
351 jack_info("JackOSSDriver::OpenOutput driver forced the sample format %ld", fSampleFormat
);
354 cur_playback_channels
= fPlaybackChannels
;
355 if (ioctl(fOutFD
, SNDCTL_DSP_CHANNELS
, &fPlaybackChannels
) == -1) {
356 jack_error("JackOSSDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
359 if (cur_playback_channels
!= fPlaybackChannels
) {
360 jack_info("JackOSSDriver::OpenOutput driver forced the number of playback channels %ld", fPlaybackChannels
);
363 cur_sample_rate
= fEngineControl
->fSampleRate
;
364 if (ioctl(fOutFD
, SNDCTL_DSP_SPEED
, &fEngineControl
->fSampleRate
) == -1) {
365 jack_error("JackOSSDriver::OpenOutput failed to set sample rate : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
368 if (cur_sample_rate
!= fEngineControl
->fSampleRate
) {
369 jack_info("JackOSSDriver::OpenInput driver forced the sample rate %ld", fEngineControl
->fSampleRate
);
372 fOutputBufferSize
= 0;
373 if (ioctl(fOutFD
, SNDCTL_DSP_GETBLKSIZE
, &fOutputBufferSize
) == -1) {
374 jack_error("JackOSSDriver::OpenOutput failed to get fragments : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
378 if (fOutputBufferSize
!= fEngineControl
->fBufferSize
* fSampleSize
* fPlaybackChannels
) {
380 int new_buffer_size
= fOutputBufferSize
/ (fSampleSize
* fPlaybackChannels
);
381 jack_info("JackOSSDriver::OpenOutput driver forced buffer size %ld", new_buffer_size
);
382 JackAudioDriver::SetBufferSize(new_buffer_size
); // never fails
384 jack_error("JackOSSDriver::OpenInput wanted buffer size cannot be obtained");
389 fOutputBuffer
= (void*)calloc(fOutputBufferSize
, 1);
391 assert(fOutputBuffer
);
399 int JackOSSDriver::Open(jack_nframes_t nframes
,
401 jack_nframes_t samplerate
,
408 const char* capture_driver_uid
,
409 const char* playback_driver_uid
,
410 jack_nframes_t capture_latency
,
411 jack_nframes_t playback_latency
,
415 // Generic JackAudioDriver Open
416 if (JackAudioDriver::Open(nframes
, samplerate
, capturing
, playing
, inchannels
, outchannels
, monitor
,
417 capture_driver_uid
, playback_driver_uid
, capture_latency
, playback_latency
) != 0) {
421 if (!fEngineControl
->fSyncMode
) {
422 jack_error("Cannot run in asynchronous mode, use the -S parameter for jackd");
426 fRWMode
|= ((capturing
) ? kRead
: 0);
427 fRWMode
|= ((playing
) ? kWrite
: 0);
429 fIgnoreHW
= ignorehwbuf
;
430 fNperiods
= user_nperiods
;
434 // Force memory page in
435 memset(&gCycleTable
, 0, sizeof(gCycleTable
));
447 int JackOSSDriver::Close()
450 FILE* file
= fopen("OSSProfiling.log", "w");
453 jack_info("Writing OSS driver timing data....");
454 for (int i
= 1; i
< gCycleCount
; i
++) {
455 int d1
= gCycleTable
.fTable
[i
].fAfterRead
- gCycleTable
.fTable
[i
].fBeforeRead
;
456 int d2
= gCycleTable
.fTable
[i
].fAfterReadConvert
- gCycleTable
.fTable
[i
].fAfterRead
;
457 int d3
= gCycleTable
.fTable
[i
].fAfterWrite
- gCycleTable
.fTable
[i
].fBeforeWrite
;
458 int d4
= gCycleTable
.fTable
[i
].fBeforeWrite
- gCycleTable
.fTable
[i
].fBeforeWriteConvert
;
459 fprintf(file
, "%d \t %d \t %d \t %d \t \n", d1
, d2
, d3
, d4
);
463 jack_error("JackOSSDriver::Close : cannot open OSSProfiling.log file");
466 file
= fopen("TimingOSS.plot", "w");
469 jack_error("JackOSSDriver::Close cannot open TimingOSS.plot file");
472 fprintf(file
, "set grid\n");
473 fprintf(file
, "set title \"OSS audio driver timing\"\n");
474 fprintf(file
, "set xlabel \"audio cycles\"\n");
475 fprintf(file
, "set ylabel \"usec\"\n");
476 fprintf(file
, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
477 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
478 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
479 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
481 fprintf(file
, "set output 'TimingOSS.pdf\n");
482 fprintf(file
, "set terminal pdf\n");
484 fprintf(file
, "set grid\n");
485 fprintf(file
, "set title \"OSS audio driver timing\"\n");
486 fprintf(file
, "set xlabel \"audio cycles\"\n");
487 fprintf(file
, "set ylabel \"usec\"\n");
488 fprintf(file
, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
489 \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
490 \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
491 \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
496 int res
= JackAudioDriver::Close();
502 int JackOSSDriver::OpenAux()
506 if ((fRWMode
& kRead
) && (OpenInput() < 0)) {
510 if ((fRWMode
& kWrite
) && (OpenOutput() < 0)) {
514 // In duplex mode, check that input and output use the same buffer size
517 10/02/09 : desactivated for now, needs more check (only needed when *same* device is used for input and output ??)
519 if ((fRWMode & kRead) && (fRWMode & kWrite) && (fInputBufferSize != fOutputBufferSize)) {
520 jack_error("JackOSSDriver::OpenAux input and output buffer size are not the same!!");
529 void JackOSSDriver::CloseAux()
531 if (fRWMode
& kRead
&& fInFD
> 0) {
536 if (fRWMode
& kWrite
&& fOutFD
> 0) {
547 fOutputBuffer
= NULL
;
550 int JackOSSDriver::Read()
553 // Keep begin cycle time
554 JackDriver::CycleTakeBeginTime();
561 gCycleTable
.fTable
[gCycleCount
].fBeforeRead
= GetMicroSeconds();
565 count
= ::read(fInFD
, fInputBuffer
, fInputBufferSize
);
568 if (count
> 0 && count
!= (int)fInputBufferSize
)
569 jack_log("JackOSSDriver::Read count = %ld", count
/ (fSampleSize
* fCaptureChannels
));
570 gCycleTable
.fTable
[gCycleCount
].fAfterRead
= GetMicroSeconds();
574 if (ioctl(fInFD
, SNDCTL_DSP_GETERROR
, &ei_in
) == 0) {
576 if (ei_in
.rec_overruns
> 0 ) {
577 jack_error("JackOSSDriver::Read overruns");
578 jack_time_t cur_time
= GetMicroSeconds();
579 NotifyXRun(cur_time
, float(cur_time
- fBeginDateUst
)); // Better this value than nothing...
582 if (ei_in
.rec_errorcount
> 0 && ei_in
.rec_lasterror
!= 0) {
583 jack_error("%d OSS rec event(s), last=%05d:%d", ei_in
.rec_errorcount
, ei_in
.rec_lasterror
, ei_in
.rec_errorparm
);
588 jack_log("JackOSSDriver::Read error = %s", strerror(errno
));
590 } else if (count
< (int)fInputBufferSize
) {
591 jack_error("JackOSSDriver::Read error bytes read = %ld", count
);
595 // Keep begin cycle time
596 JackDriver::CycleTakeBeginTime();
597 for (int i
= 0; i
< fCaptureChannels
; i
++) {
598 if (fGraphManager
->GetConnectionsNum(fCapturePortList
[i
]) > 0) {
599 CopyAndConvertIn(GetInputBuffer(i
), fInputBuffer
, fEngineControl
->fBufferSize
, i
, fCaptureChannels
, fBits
);
604 gCycleTable
.fTable
[gCycleCount
].fAfterReadConvert
= GetMicroSeconds();
611 int JackOSSDriver::Write()
614 // Keep end cycle time
615 JackDriver::CycleTakeEndTime();
620 audio_errinfo ei_out
;
622 // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html
626 memset(fOutputBuffer
, 0, fOutputBufferSize
);
628 // Prefill ouput buffer
629 for (int i
= 0; i
< fNperiods
; i
++) {
630 count
= ::write(fOutFD
, fOutputBuffer
, fOutputBufferSize
);
631 if (count
< (int)fOutputBufferSize
) {
632 jack_error("JackOSSDriver::Write error bytes written = %ld", count
);
638 if (ioctl(fOutFD
, SNDCTL_DSP_GETODELAY
, &delay
) == -1) {
639 jack_error("JackOSSDriver::Write error get out delay : %s@%i, errno = %d", __FILE__
, __LINE__
, errno
);
643 delay
/= fSampleSize
* fPlaybackChannels
;
644 jack_info("JackOSSDriver::Write output latency frames = %ld", delay
);
648 gCycleTable
.fTable
[gCycleCount
].fBeforeWriteConvert
= GetMicroSeconds();
651 memset(fOutputBuffer
, 0, fOutputBufferSize
);
652 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
653 if (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[i
]) > 0) {
654 CopyAndConvertOut(fOutputBuffer
, GetOutputBuffer(i
), fEngineControl
->fBufferSize
, i
, fPlaybackChannels
, fBits
);
659 gCycleTable
.fTable
[gCycleCount
].fBeforeWrite
= GetMicroSeconds();
662 // Keep end cycle time
663 JackDriver::CycleTakeEndTime();
664 count
= ::write(fOutFD
, fOutputBuffer
, fOutputBufferSize
);
667 if (count
> 0 && count
!= (int)fOutputBufferSize
)
668 jack_log("JackOSSDriver::Write count = %ld", count
/ (fSampleSize
* fPlaybackChannels
));
669 gCycleTable
.fTable
[gCycleCount
].fAfterWrite
= GetMicroSeconds();
670 gCycleCount
= (gCycleCount
== CYCLE_POINTS
- 1) ? gCycleCount
: gCycleCount
+ 1;
674 if (ioctl(fOutFD
, SNDCTL_DSP_GETERROR
, &ei_out
) == 0) {
676 if (ei_out
.play_underruns
> 0) {
677 jack_error("JackOSSDriver::Write underruns");
678 jack_time_t cur_time
= GetMicroSeconds();
679 NotifyXRun(cur_time
, float(cur_time
- fBeginDateUst
)); // Better this value than nothing...
682 if (ei_out
.play_errorcount
> 0 && ei_out
.play_lasterror
!= 0) {
683 jack_error("%d OSS play event(s), last=%05d:%d",ei_out
.play_errorcount
, ei_out
.play_lasterror
, ei_out
.play_errorparm
);
688 jack_log("JackOSSDriver::Write error = %s", strerror(errno
));
690 } else if (count
< (int)fOutputBufferSize
) {
691 jack_error("JackOSSDriver::Write error bytes written = %ld", count
);
698 int JackOSSDriver::SetBufferSize(jack_nframes_t buffer_size
)
701 JackAudioDriver::SetBufferSize(buffer_size
); // Generic change, never fails
705 int JackOSSDriver::ProcessSync()
707 // Read input buffers for the current cycle
709 jack_error("ProcessSync: read error, skip cycle");
710 return 0; // Non fatal error here, skip cycle, but continue processing...
719 // Write output buffers for the current cycle
721 jack_error("JackAudioDriver::ProcessSync: write error, skip cycle");
722 return 0; // Non fatal error here, skip cycle, but continue processing...
728 } // end of namespace
735 SERVER_EXPORT jack_driver_desc_t
* driver_get_descriptor()
737 jack_driver_desc_t
* desc
;
738 jack_driver_desc_filler_t filler
;
739 jack_driver_param_value_t value
;
741 desc
= jack_driver_descriptor_construct("oss", JackDriverMaster
, "OSS API based audio backend", &filler
);
743 value
.ui
= OSS_DRIVER_DEF_FS
;
744 jack_driver_descriptor_add_parameter(desc
, &filler
, "rate", 'r', JackDriverParamUInt
, &value
, NULL
, "Sample rate", NULL
);
746 value
.ui
= OSS_DRIVER_DEF_BLKSIZE
;
747 jack_driver_descriptor_add_parameter(desc
, &filler
, "period", 'p', JackDriverParamUInt
, &value
, NULL
, "Frames per period", NULL
);
749 value
.ui
= OSS_DRIVER_DEF_NPERIODS
;
750 jack_driver_descriptor_add_parameter(desc
, &filler
, "nperiods", 'n', JackDriverParamUInt
, &value
, NULL
, "Number of periods to prefill output buffer", NULL
);
752 value
.i
= OSS_DRIVER_DEF_BITS
;
753 jack_driver_descriptor_add_parameter(desc
, &filler
, "wordlength", 'w', JackDriverParamInt
, &value
, NULL
, "Word length", NULL
);
755 value
.ui
= OSS_DRIVER_DEF_INS
;
756 jack_driver_descriptor_add_parameter(desc
, &filler
, "inchannels", 'i', JackDriverParamUInt
, &value
, NULL
, "Capture channels", NULL
);
758 value
.ui
= OSS_DRIVER_DEF_OUTS
;
759 jack_driver_descriptor_add_parameter(desc
, &filler
, "outchannels", 'o', JackDriverParamUInt
, &value
, NULL
, "Playback channels", NULL
);
762 jack_driver_descriptor_add_parameter(desc
, &filler
, "excl", 'e', JackDriverParamBool
, &value
, NULL
, "Exclusif (O_EXCL) access mode", NULL
);
764 strcpy(value
.str
, OSS_DRIVER_DEF_DEV
);
765 jack_driver_descriptor_add_parameter(desc
, &filler
, "capture", 'C', JackDriverParamString
, &value
, NULL
, "Input device", NULL
);
766 jack_driver_descriptor_add_parameter(desc
, &filler
, "playback", 'P', JackDriverParamString
, &value
, NULL
, "Output device", NULL
);
767 jack_driver_descriptor_add_parameter(desc
, &filler
, "device", 'd', JackDriverParamString
, &value
, NULL
, "OSS device name", NULL
);
770 jack_driver_descriptor_add_parameter(desc
, &filler
, "ignorehwbuf", 'b', JackDriverParamBool
, &value
, NULL
, "Ignore hardware period size", NULL
);
773 jack_driver_descriptor_add_parameter(desc
, &filler
, "input-latency", 'I', JackDriverParamUInt
, &value
, NULL
, "Extra input latency", NULL
);
774 jack_driver_descriptor_add_parameter(desc
, &filler
, "output-latency", 'O', JackDriverParamUInt
, &value
, NULL
, "Extra output latency", NULL
);
779 EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackLockedEngine
* engine
, Jack::JackSynchro
* table
, const JSList
* params
)
781 int bits
= OSS_DRIVER_DEF_BITS
;
782 jack_nframes_t srate
= OSS_DRIVER_DEF_FS
;
783 jack_nframes_t frames_per_interrupt
= OSS_DRIVER_DEF_BLKSIZE
;
784 const char* capture_pcm_name
= OSS_DRIVER_DEF_DEV
;
785 const char* playback_pcm_name
= OSS_DRIVER_DEF_DEV
;
786 bool capture
= false;
787 bool playback
= false;
790 bool monitor
= false;
792 unsigned int nperiods
= OSS_DRIVER_DEF_NPERIODS
;
794 const jack_driver_param_t
*param
;
795 bool ignorehwbuf
= false;
796 jack_nframes_t systemic_input_latency
= 0;
797 jack_nframes_t systemic_output_latency
= 0;
799 for (node
= params
; node
; node
= jack_slist_next(node
)) {
801 param
= (const jack_driver_param_t
*)node
->data
;
803 switch (param
->character
) {
806 srate
= param
->value
.ui
;
810 frames_per_interrupt
= (unsigned int)param
->value
.ui
;
814 nperiods
= (unsigned int)param
->value
.ui
;
818 bits
= param
->value
.i
;
822 chan_in
= (int)param
->value
.ui
;
826 chan_out
= (int)param
->value
.ui
;
831 if (strcmp(param
->value
.str
, "none") != 0) {
832 capture_pcm_name
= param
->value
.str
;
838 if (strcmp(param
->value
.str
, "none") != 0) {
839 playback_pcm_name
= param
->value
.str
;
844 playback_pcm_name
= param
->value
.str
;
845 capture_pcm_name
= param
->value
.str
;
857 systemic_input_latency
= param
->value
.ui
;
861 systemic_output_latency
= param
->value
.ui
;
866 // duplex is the default
867 if (!capture
&& !playback
) {
872 Jack::JackOSSDriver
* oss_driver
= new Jack::JackOSSDriver("system", "oss", engine
, table
);
873 Jack::JackDriverClientInterface
* threaded_driver
= new Jack::JackThreadedDriver(oss_driver
);
875 // Special open for OSS driver...
876 if (oss_driver
->Open(frames_per_interrupt
, nperiods
, srate
, capture
, playback
, chan_in
, chan_out
,
877 excl
, monitor
, capture_pcm_name
, playback_pcm_name
, systemic_input_latency
, systemic_output_latency
, bits
, ignorehwbuf
) == 0) {
878 return threaded_driver
;
880 delete threaded_driver
; // Delete the decorated driver