xref: /freebsd/share/examples/sound/oss/README (revision cb00491fbc51751fe166056cc69e23beeb26fee4)
1*cb00491fSChristos MargiolisBriefly summarised, a general audio application will:
2*cb00491fSChristos Margiolis- open(2)
3*cb00491fSChristos Margiolis- ioctl(2)
4*cb00491fSChristos Margiolis- read(2)
5*cb00491fSChristos Margiolis- write(2)
6*cb00491fSChristos Margiolis- close(2)
7*cb00491fSChristos Margiolis
8*cb00491fSChristos MargiolisIn this example, read/write will be called in a loop for a duration of
9*cb00491fSChristos Margiolisrecord/playback. Usually, /dev/dsp is the device you want to open, but it can
10*cb00491fSChristos Margiolisbe any OSS compatible device, even user space one created with virtual_oss. For
11*cb00491fSChristos Margiolisconfiguring sample rate, bit depth and all other configuring of the device
12*cb00491fSChristos Margiolisioctl is used. As devices can support multiple sample rates and formats, what
13*cb00491fSChristos Margiolisspecific application should do in case there's an error issuing ioctl, as not
14*cb00491fSChristos Margiolisall errors are fatal, is upon the developer to decide. As a general guideline
15*cb00491fSChristos MargiolisOfficial OSS development howto should be used. FreeBSD OSS and virtual_oss are
16*cb00491fSChristos Margiolisdifferent to a small degree.
17*cb00491fSChristos Margiolis
18*cb00491fSChristos MargiolisFor more advanced OSS and real-time applications, developers need to handle
19*cb00491fSChristos Margiolisbuffers more carefully. The size of the buffer in OSS is selected using fragment
20*cb00491fSChristos Margiolissize size_selector and the buffer size is 2^size_selector for values between 4
21*cb00491fSChristos Margiolisand 16. The formula on the official site is:
22*cb00491fSChristos Margiolis
23*cb00491fSChristos Margiolisint frag = (max_fragments << 16) | (size_selector);
24*cb00491fSChristos Margiolisioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
25*cb00491fSChristos Margiolis
26*cb00491fSChristos MargiolisThe max_fragments determines in how many fragments the buffer will be, hence if
27*cb00491fSChristos Margiolisthe size_selector is 4, the requested size is 2^4 = 16 and for the
28*cb00491fSChristos Margiolismax_fragments of 2, the total buffer size will be
29*cb00491fSChristos Margiolis
30*cb00491fSChristos Margiolis(2 ^ size_selector) * max_fragments
31*cb00491fSChristos Margiolis
32*cb00491fSChristos Margiolisor in this case 32 bytes. Please note that size of buffer is in bytes not
33*cb00491fSChristos Margiolissamples. For example, 24bit sample will be represented with 3 bytes. If you're
34*cb00491fSChristos Margiolisporting audio app from Linux, you should be aware that 24 bit samples are
35*cb00491fSChristos Margiolisrepresented with 4 bytes (usually int).
36*cb00491fSChristos Margiolis
37*cb00491fSChristos MargiolisFreeBSD kernel will round up max_fragments and size of fragment/buffer, so the
38*cb00491fSChristos Margiolislast thing any OSS code should do is get info about buffer with audio_buf_info
39*cb00491fSChristos Margiolisand SNDCTL_DSP_GETOSPACE. That also means that not all values of max_fragments
40*cb00491fSChristos Margiolisare permitted.
41*cb00491fSChristos Margiolis
42*cb00491fSChristos MargiolisFrom kernel perspective, there are few points OSS developers should be aware of:
43*cb00491fSChristos Margiolis- There is a software facing buffer (bs) and a hardware driver buffer (b)
44*cb00491fSChristos Margiolis- The sizes can be seen with cat /dev/sndstat as [b:_/_/_] [bs:_/_/_] (needed:
45*cb00491fSChristos Margiolis  sysctl hw.snd.verbose=2)
46*cb00491fSChristos Margiolis- OSS ioctl only concern software buffer fragments, not hardware
47*cb00491fSChristos Margiolis
48*cb00491fSChristos MargiolisFor USB the block size is according to hw.usb.uaudio.buffer_ms sysctl, meaning
49*cb00491fSChristos Margiolis2ms at 48kHz gives 0.002 * 48000 = 96 samples per block, all multiples of this
50*cb00491fSChristos Margioliswork well. Block size for virtual_oss, if used, should be set accordingly.
51*cb00491fSChristos Margiolis
52*cb00491fSChristos MargiolisOSS driver insists on reading / writing a certain number of samples at a time,
53*cb00491fSChristos Margiolisone fragment full of samples. It is bound to do so in a fixed time frame, to
54*cb00491fSChristos Margiolisavoid under- and overruns in communication with the hardware.
55*cb00491fSChristos Margiolis
56*cb00491fSChristos MargiolisThe idea of a total buffer size that holds max_fragments fragments is to give
57*cb00491fSChristos Margiolissome slack and allow application to be about max_fragments - 1 fragments late.
58*cb00491fSChristos MargiolisLet's call this the jitter tolerance. The jitter tolerance may be much less if
59*cb00491fSChristos Margiolisthere is a slight mismatch between the period and the samples per fragment.
60*cb00491fSChristos Margiolis
61*cb00491fSChristos MargiolisJitter tolerance gets better if we can make either the period or the samples
62*cb00491fSChristos Margiolisper fragment considerably smaller than the other. In our case that means we
63*cb00491fSChristos Margiolisdivide the total buffer size into smaller fragments, keeping overall latency at
64*cb00491fSChristos Margiolisthe same level.
65*cb00491fSChristos Margiolis
66*cb00491fSChristos MargiolisOfficial OSS development howto: http://manuals.opensound.com/developer/DSP.html
67