mmap support for Raspberry Pi bcm2835 ALSA driver

Because I work on an awesome company I spent last week improving the Raspberry Pi ALSA driver.

A long standing issue was that the driver did not support memory-mapped I/O mode for audio stream transfers.

ALSA supports two transfers methods for PCM playback: Read/Write transfer where samples are written to the device using standard read and write functions and Direct Read/Write transfers where samples can be written directly to a mapped memory area and the driver is signaled once this has been done.

ALSA provides an API for both cases and each application using ALSA to access the audio device can choose which API to use. But since mmap was not supported by the bcm2835 driver, applications using the mmap API did not work on the Raspberry Pi.

To bypass hardware limitation such as the lack of mmap support, ALSA provides a set of PCM plug-ins that can be used to extend functionality and features of PCM devices.

These plug-ins are used by defining a custom /etc/asound.conf or .asoundrc and one of them is the mmap emulation plug-in (mmap_emul) which emulates mmap access using a set of read/write transfers. This plug-in was needed on the Raspberry Pi to allow applications using ALSA mmap API to work. But of course it introduces some latency and requires a custom configuration to enable it.

So, the best approach was to just add mmap support to the ALSA driver and get rid of the mmap emulation plug-in. Normally this is straightforward since the kernel allows memory areas to be mapped to user-space address space so applications can have direct access to device memory.

This was not the case on the Raspberry Pi since the PCM samples are processed by its VideoCore IVI GPU. The ARM11 CPU communicates with the VideoCore co-processor using a message passing interface (vchiq) which means that the CPU is not able to directly address the audio device hardware buffers and audio samples have to be sent to the device using vchiq messages.

Since hardware buffers can’t be directly mapped to user-space memory, an intermediate buffer is needed. This intermediate buffer is mapped to user-space so applications can store the audio samples there. Once user-space has finished writing the PCM samples they are pushed to VideoCore as vchiq messages.

Fortunately, the kernel ALSA subsystem provides a PCM indirect API which are a set of helper functions and a data structure to manage the intermediate and hardware buffers. It is really helpful so you don’t have to write all the buffer management.

So, after figuring out all of this I wrote a patch to add mmap support to the Raspberry Pi ALSA driver and send a pull request that also contained other improvements to the driver.

Since it has been merged on the Raspberry Pi kernel, this feature will be available on the next raspbian release but if you want to use it now you can do the following:

$ git clone git://github.com/raspberrypi/tools.git
$ git clone git://github.com/raspberrypi/linux.git
$ cd linux
$ git checkoub -b rpi-3.6.y origin/rpi-3.6.y
$ export ARCH=arm
$ export CROSS_COMPILE=../tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
$ make bcmrpi_defconfig
$ make prepare modules_prepare
$ make M=sound/arm
$ sudo cp sound/arm/snd-bcm2835.ko /media/rootfs/lib/modules/3.6.11+/kernel/sound/arm/
$ sudo rm /media/rootfs/etc/asound.conf

The last step is very important since using both a mmap capable ALSA driver and the PCM mmap emulation plug-in does not work.

I want to thank my employer Collabora for allowing me to work on this:

About these ads
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

7 Responses to mmap support for Raspberry Pi bcm2835 ALSA driver

  1. Wolfgang Koop says:

    What shoud I copy in step 10?
    Where is the result after step 9?

  2. Javier Martinez Canillas says:

    Hello Wolfgang,

    The result of step 9 is a compiled kernel module of the ALSA bcm2835 driver (sound/arm/snd-bcm2835.ko). That is what you have to copy to the rpi rootfs.

    I just added to the cp command on step 10 too. I somehow forgot when writing the post.

    Thanks a lot for pointing out this!

    • Bud says:

      Hi Javier, I am trying to record using my Pi using a USB audio input device with microphone. Works fine on other machines. Does your ALSA driver support sound recording via USB or am I missing something? Thx, Bud

  3. Wolfgang Koop says:

    After two efforts no chance to win
    Do you have tested it?
    Is there somewhere a binary for the driver?

  4. Javier Martinez Canillas says:

    What specific problem do you have?

    The commands (although can be used verbatim) are just a reference, basically you need to compile the module and copy it to the rootfs.

    Anyway, here is a pre-built kernel module for the 3.6.y kernel branch: http://people.collabora.com/~javier/rpi/snd-bcm2835.ko

    Also, you can use the rpi-update update to get the latest firmware and remove /etc/sound.conf

  5. Javier, this update has broken text-to-speech. Using espeak to get tts long utteances are now very stuttery and slow down from the preset speech speed.

    Also, does the update mean that vchiq is not used after /etc/asound.conf has been removed? I am trying to get the SpeakUp console-mode screen-reader to work and it causes a kernel oops in VCHIQ-0 process. If this update worked with espeak and removed the need for vchiq this would work. Mike

    • Javier Martinez Canillas says:

      Hi Mike,

      Yes I saw that there are two open issues on the Raspberry Pi github issue tracker (#304 and #305). I’ll take a look at why text-to-speech is broken.

      Best regards,
      Javier

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s