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