Issue 5-1, January 5, 2000

Be Engineering Insights: Multiaudio API

By Steven Olson

I'm in the family bunker deep in an Idaho hillside. Y2K is officially over but I'm still not sure if it's safe to come out yet. The only communication line I have is a fiber optic link to Be's world headquarters in Menlo Park. Because of some poor planning on my part, though, there's no gas for the electric generator. Instead, I have to use a candle (signal) and deck of playing cards (modulator) to send this article. Fiber optic cable was the right choice for the bunker because of its high speed and bandwidth capabilities. Coincidentally, BeOS is also known for high speed and bandwith capabilities. In particular, the new multiaudio driver API takes full advantage of BeOS's superior speed and bandwidth.

Multi

Not all of you may be familiar with the multiaudio API, as it's intended only for driver writers. User level add-ons and applications will talk to the multiaudio node, or "multinode" as it's called. The advantage of the multiaudio API over other APIs (such as legacy and game) is that it's ideally suited for professional and semiprofessional audio cards. These cards generally have more inputs and outputs, higher sampling rates (typically 48Khz or 96Khz), and greater bit depths (up to 32 bits per sample) than typical game sound cards. They may also have support for other audio formats such as S/PDIF and ADAT. The "complete" documentation for the driver API is included in three files: multi_audio.h, multi_audio.gb, and multi_audio.txt. To get these files, write to trinity@be.com. Without rehashing all the information in the files, I'd like to hit the highlights of the new API.

Highlights

The API is different from the other audio APIs in that read/write calls are combined into a single ioctl, B_MULTI_BUFFER_EXCHANGE. This call is synchronous—it returns after playback data has been transferred (or queued) and capture data (if any) is present in the capture buffer. A ping-pong type of buffer management normally used—one buffer is being played (or filled with capture data) while a second buffer is being prepared. In some cases, a ring buffer may be required.

Another area of interest is the mixer ioctls. Extensible mixer implementation is tricky, and this API is no exception. However, the burden is now off the driver writer and on the node and add-on writers instead. That's good news for us driver writers. (There should be example code in the future to make nodes and add-ons easier too.) The ioctls B_MULTI_LIST_MIX_CHANNELS, B_MULTI_LIST_MIX_CONTROLS, and B_MULTI_LIST_MIX_CONNECTIONS return mixer components associated with the device. This allows the mixer GUI and implementation to be handled by the user mode components.

Masters

One item that's slightly different from the documentation is the ganging together of controls. The multi mix control structure has a member named master. It is intended that this value be 0 if the control is not slaved. If it is ganged, then the ID of the master control goes here. In order to facilitate the implementation of parameter webs, I suggest that the master control use its own control ID here and not 0. This reduces to using 0 if the control is not ganged or slaved, and the master control ID if it is. The documentation will be updated to reflect these changes.

Complications

Some things are tricky. For example, say your card supports a 32Khz sampling rate, but only if you're sample-locked to an incoming 32Khz S/PDIF signal. You should report the actual sample rate (32 Khz) when requested (MULTI_GET_GLOBAL_FORMAT) but don't show 32 Khz in the B_MULTI_GET_DESCRIPTION ioctl. This will prevent users from manually trying to set the rate to 32 Khz.

Confusion

Some people have reported confusion over the terms "bus" and "channel" as used in the multiaudio API. Busses are the connectors to the world outside the computer, while channels carry audio data inside the computer. Busses may be digital (e.g., ADAT) or analog. Channels are what's "processed" by the computer. In a typical capture scenario, an analog signal is converted to digital PCM data by an ADC. The digital PCM data is associated with the input channel, while the analog signal is part of the input bus.

Latency

The purpose of the multiaudio API is create an environment in which high-performance audio cards can excel. So the question "How fast is it?" invariably arises. The answer is "It depends." How fast is your CPU? How fast is your hard disk? How fast is your memory bus? Do you want multitrack hard disk recording or are you more interested in "real time" (<10 ms) effects processing? In audio, the primary concern is latency. How long does it take to get an analog signal into the computer, process it, and then send it back out? What if you also wish to write processed data to disk? There are many items which contribute to the latency of the entire system, including the OS, the API, A/D D/A converter latency, buffer size, etc... (If the OS is not designed properly, you may be able to get two channels of audio in and out fairly quickly, but you may not be able to access the disk simultaneously.) So how fast is the new API? The only way to know is to test your machine and card.

Test

Everyone has a preferred method for testing audio latency and I'm no exception. I recommend the following: input a sine wave from a signal generator to the sound card, run a loopback program that doesn't bypass the converters, then measure the phase difference with an oscilloscope. Make sure that the period of the input signal is greater than the buffer playback time. A very simple loopback program is available at <ftp://ftp.be.com/pub/samples /drivers/multiaudio_test.zip


Developers' Workshop: BeOS Driver FAQs (Part 2)

By Michael Morrissey

You can find the first part of this article here: Developers' Workshop: BeOS Driver FAQs (Part 1)

BeOS Driver FAQs Continued

1. How do I write a driver for:

Q:

a sound card?

A:

You need to write a kernel driver that implements one of Be's audio device ioctl opcode protocols. The protocol used up through R4.5.x is deprecated, but the preferred multichannel protocol (defined in multi_audio.h) is not yet finalized. If you are now beginning development of a sound card driver, contact trinity@be.com for preliminary multichannel audio headers and docs.

Q:

a SCSI card?

A:

Specific SCSI controller chipsets are supported via modules that are loaded by the SCSI bus manager module. Consult the Buslogic or Symbios bus module sample code at <ftp://ftp.be.com/pub/samples/add-ons/ (or in /boot/optional/sample-code if you installed the optional sample code from the BeOS CD.

Q:

a graphics card?

A:

Graphics card support in R4 and beyond HAS two software components: a kernel driver as described in this FAQ, and a user space add-on to the App Server called an accelerant. Detailed discussion of the BeOS graphics driver model in general and accelerant development in particular is available in the document R4 Graphics Driver Docs, found in /boot/optional/sample-code/drivers/graphics/ (if you installed the optional sample code from the BeOS CD) or in <ftp://ftp.be.com/pub/samples/drivers/graphics.zip>.

Q:

a USB device?

A:

Write a kernel driver that uses the services of the USB manager module declared in drivers/USB.h; that way, your driver will work with any USB host controller supported by BeOS.

Q:

a printer?

A:

You're in luck! Printer drivers live entirely within the velvety-soft cuddliness of user space. They are add-ons to the Print server that implement several hook functions. However, this API is not yet set in stone. For more information on writing printer drivers, contact mathias@be.com.

Q:

a network interface card?

A:

Network interface card support consists of a kernel driver (as described in this FAQ) and a user space add-on to the Net Server. Consult the EtherPCI sample code <ftp://ftp.be.com/pub/samples/drivers/EtherPCI.zip>, or /boot/optional/sample-code/drivers/EtherPCI/ if you installed the optional sample code from the BeOS CD.

2. File Systems

Q:

What is a file system?

A:

A good general definition of a file system is found in Dominic's book "Practical File System Design With the Be File System," on pg. 7:

A file system is a way to organize, store, retrieve, and manage information on a permanent storage medium such as a disk.

In BeOS parlance, a file system is a kernel add-on that can translate between the kernel's abstract notion of a file system and the implementation details of a particular concrete file system (such as BFS or ISO 9660).

For more information on writing a file system for BeOS, see George Hoffman's article, "Be Engineering Insights: Chelsea 'n' Me" ), and Alfred's article, "Be Engineering Insights: Network File Systems for BeOS—The Art of Being Paranoid".

Q:

Where do file systems live?

A:

File systems that ship with BeOS live in /boot/beos/system/add-ons/kernel/file_systems/. File systems users add after installing BeOS should be placed in /boot/home/config/add-ons/kernel/drivers/bin/ because the /boot/beos/system/ hierarchy should not be modified.

Q:

Where can I find file system sample code?

A:

In optional/sample-code/add-ons/ if installed, or at <ftp://ftp.be.com/pub/samples/add-ons/>.

3. Life in Kernel Space

Q:

What is kernel space vs. user space?

A:

Kernel space refers to the runtime environment of the kernel, particularly the fact that the CPU is in supervisor mode. Code running in supervisor mode can do things that can't be done from user mode, such as manage interrupts or access any virtual address. Since drivers, modules, and filesystems are add-ons loaded by the kernel, they also enjoy the privileges and suffer the perils of running in kernel space.

Similarly, user space refers to the runtime environment of user programs, in which the CPU is not running in supervisor mode but rather in user mode.

Q:

What is a kernel add-on?

A:

A kernel add-on is compiled code (also known as an image) that the kernel can load and unload as it is running. Indeed, any BeOS application can be designed to use add-ons to extend its functionality; examples of applications that do this include the Tracker and the ScreenSaver.

Structurally, an add-on is no different from a shared library, but instead of being dynamically linked to the host by the loader before the host's main() is called, an add-on is explicitly loaded and unloaded as needed by the host using the API declared in kernel/image.h.

For more information on creating and using add-ons, see "Image Concepts" TheKernelKit_ImagesOverview.html in the Be Book.

Q:

What musn't I do in a kernel add-on?

A:

You must not leave interrupts disabled for longer than 50 microseconds. If you're inside a spinlock-protected critical section, you must never block. Prevent these tragedies by following the rules set forth in the next answer.

Q:

What can I do in a kernel add-on?

A:

If interrupts are disabled and you are inside a spinlock- protected critical section, you may:

  • touch hardware registers (through bus manager hooks).

  • touch memory that's locked down.

  • call the following functions:

    kernel: system_time(), atomic_add(), atomic_or(), and atomic_and()

    bus managers: read_io<size>() and write_io<size>()

and that's it. To quote Cyril Meurillon, EVERYTHING ELSE IS FORBIDDEN.

If interrupts are disabled and you are NOT inside a spinlock, you may do the following in addition to the above list:

  • release_sem_etc() with B_DO_NOT_RESCHEDULE as flags

  • get_sem_count()

  • add_timer()

  • cancel_timer()

  • dprintf()

For further discussion of the rules of kernel space, consult Cyril's articles on the subject: "Be Engineering Insights: Attention Driver Writers!" and "Be Engineering Insights: The Kernel Programming Model Revisited"

Q:

Got any general tips for writing kernel space code?

A:

You betcha. Dominic discusses some common constructs found in kernel space code in his article, "Be Engineering Insights: Device Driver Idioms". And Trey Boudreau's "Be Engineering Insights: Kernel Driver Tips and Traps" is aptly named, though it predates R4, so read carefully.

Q:

How do I debug drivers (and other kernel space code)?

A:

To debug kernel space code on BeOS, you have to leave the cushy world of source level debugging behind. Your main debugging tools will be dprintf() and kprintf(), which let you dump text to a serial port, and the assembly level kernel debugger.

There are two Newsletter on this subject. "Developers' Workshop: Welcome to the Cow...Debugging Device Drivers", by Victor Tsou, discusses your best friends dprintf() and kprintf(), and has some info about the less fully featured kernel debugger that existed in the R3.x days. "Be Engineering Insights: Welcome to Kernel Debugging Land", by Dominic, is a more recent article that discusses the R4.x kernel debugger in detail and gives tips for debugging common problems such as deadlocks.

Q:

How do I get additional debugging information, particularly for device driver crashes?

A:

You can add your own kernel debugger command to make it easier to view your driver-internal structures. Victor's article "Be Engineering Insights: Windows 95 Experience on BeOS—Or How to Hack on BeOS" has more on this

Q:

How do I use floating-point in kernel space?

A:

Please don't. Read Steven Olson's "Developers' Workshop: BeOS Programming Basics, Part 2"

Q:

How do I use functors and vectors and deques (oh my!) in kernel space?

A:

You should not use C++ in kernel space. There is not runtime support in the kernel for it, and there are a number of subtle issues involved with doing it.

Learning More

Wouldn't it be cool if there was, like, a web page with links to all sorts of Be developer resources grouped by topic? Yes, it is cool (how do you think I researched this FAQ?), and it's called the Be Developer Library <http://www.be.com/developers/developer_library/index.html>. It has links to Be Book documentation, Be Newsletter articles, sample code, and much more. You'll find resources pertaining to drivers and modules in the Drivers section <http://www.be.com/developers/developer_library/drivers.html>, and file systems are covered in the Add-ons section <http://www.be.com/developers/developer_library/add-ons.html>.

So that's the FAQs as they currently exist. But they don't have to end this way. Could they be better organized? Is there another question you'd like to see answered? I intend the FAQs to evolve as you need them to. Send questions, comments, corrections, etc. to tt@be.com. Really. Also, about that Developer Library thing I mentioned at the end there: I realize some of its content has grown a bit stale. The PR2 headers, for example. I hope to address that as soon as possible, although it might take awhile because the machinery that drives the Library is a rusty and should be updated. Stay tuned.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.