rawsontetley.org

Linux Intel iMac 17" iSight and Sound

As part of a project I’ve undertaken to build a video diary booth, I was given a shiny new Core-Duo Intel iMac 17" as the hardware platform. I’ve since had an absolute nightmare getting the sound and iSight camera to work properly with gstreamer (I built my application around the gstreamer libs), so I thought I’d share some of my experiences.

What I’m not covering

I’m not covering bootloading, rEfit, getting your Debian installed, X (which worked fine out of the box) as there are plenty of better guides out there for that.

iSight

I did get the internal iSight camera working well thanks to the work of Ronald S Bultje (one of the GNOME devs). Here’s how I did it:

  1. Make sure you have installed and are running with linux-image-2.6.18-1-686, with the headers installed (linux-headers-2-6.18-1-686). You’ll also need libusb-dev, in addition to the usual build tools (make, gcc, libc6-dev, etc). If a newer kernel is available in Debian by the time you read this, then use that instead (or pray that this stuff has been fixed :-)
apt-get install linux-image-2.6.18-1-686 linux-headers-2.6.18-1-686
apt-get install libusb-dev libc6-dev make gcc
  1. Download Ronald’s patched uvcvideo driver here (kept locally for posterity), and unpack it to your src directory. I’ve added an install script to it to put the module into the kernel tree, run depmod and copy the firmware extractor to your path. Note that this patched uvcvideo has support for the newer firmwares found in OSX 10.4.8
mv uvcvideo10d.tar.gz /usr/src
cd /usr/src
tar -zxvf uvcvideo10d.tar.gz
  1. Now, enter the directory and run the install.sh script. It will compile the new module and install it. It will also copy the firmware “extract” program to /usr/bin/isight-firmware-loader
cd /usr/src/uvcvideo
sh install.sh
  1. Next, mount your OSX partition (you only need one firmware file from it, but I can’t distribute it due to legal issues) and copy the firmware file onto your linux partition (saves you having to mount it within Linux again).
mkdir /mnt/mac
mount -t hfsplus /dev/sda2 /mnt/mac
cd /mnt/mac/System/Library
cd Extensions/IOUSBFamily.kext
cd Contents/PlugIns/AppleUSBVideoSupport.kext
cd Contents/MacOS
cp AppleUSBVideoSupport /lib/firmware
  1. You can now load the firmware and driver:
modprobe uvcvideo
isight-firmware-loader /lib/firmware/AppleUSBVideoSupport

If you’d like Debian to autoload the firmware every time you boot Linux, there’s an init.d script included in the tarball that I added, called isight.init_d - copy it to your init.d directory and symlink it in rc2.d (the default runlevel in Debian).

cp /usr/src/uvcvideo/isight.init_d /etc/init.d/isight
ln -sf /etc/init.d/isight /etc/rc2.d/S99isight

Testing the iSight

This driver is still relatively incomplete and only supplies v4l2 functionality, and then only a limited subset that seems to be just enough to work with gstreamer. This means you can only use it with programs that are utilising gstreamer for the backend!

I’m using gstreamer 0.10 with the python bindings and you can test it with a simple gst-launch command. Note the use of videorate - the driver doesn’t support a fixed fps, but you can use the gstreamer videorate plugin to limit the fps. Here’s an example launch/pipeline that I use to record video at 640x480 with sound capture from the card. It uses a tee to send output to both the video encoder (theora in this example, but you can substitute that for xvidenc/avimux or whatever you prefer) and an xvimagesink for display on the screen.

gst-launch-0.10 v4l2src name=source use-fixed-fps=false \
        ! videorate \
        ! video/x-raw-yuv,format=\(fourcc\)UYVY,width=640,height=480,framerate=10/1 \
        ! ffmpegcolorspace \
        ! tee name=screen \
        ! theoraenc \
        ! queue \
        ! oggmux name=mux \
        ! filesink location=video.ogg \
        { \
        screen. \
        ! xvimagesink \
        } \
        { alsasrc \
        ! audiorate \
        ! "audio/x-raw-int",rate=11025,depth=16,channels=1,width=16,sign=\(boolean\)TRUE,endianness=1234 \
        ! audioconvert \
        ! vorbisenc \
        ! queue \
        ! mux.

My application uses sink->window->xid to redirect the xv sink to a GTK drawable (in case you’re wondering how to do it). I hope to release it once I’ve got the rough edges knocked off.

Sound

Make sure you have the alsa-utils package installed before you start as we’re going to need arecord, alsamixer, alsaconf and amixer

I never did get the internal speakers working (although headphones works so you can use external speakers for now). My main problem was the microphone for audio capture.

Thankfully, the nice people at Mactel-Linux have the pinouts for the STAC9221 A1 chip inside the 17" iMac, so I took the ALSA 1.0.13 sources and modified them for the apple pinouts.

To install on Debian, first get the alsa sources (1.0.13 in unstable) and unpack them:

apt-get install alsa-source
cd /usr/src
tar -jxvf alsa-source.tar.bz2
cd modules/alsa-source

Now, replace alsa-kernel/pci/hda/patch_sigmatel.c with this patched version for the iMac pinouts (these also work with the Mac Mini and Macbook Pro).

In /usr/src/modules/alsa-source, build a replacementa driver for snd-hda-intel:

cd /usr/src/modules/alsa-source
./configure --with-cards=hda-intel
make
make install

The replacement driver will now be in your kernel tree, run “alsaconf” to reload the driver and you should have a fully working internal microphone!

The microphone doesn’t work immediately (some strange quirk), so you have to switch the input source to Line and then back to Mic again before it works. You’ll have to do this on every reboot - I’m not sure if it’s an alsa mixer restore issue or not. I also had to set the “Mux” capture level to 100% in alsamixer as well before it seemed to work (however this does get restored properly between reboots along with the capture level)

amixer set "Input Source" "Line"
amixer set "Input Source" "Mic"

I already had a master init.d script for the machine so I added these lines to that, but you could put it in /etc/rc.local (or in the /etc/init.d/isight script if you used that).

To verify the microphone is working, run:

arecord

You should ascii spewing out onto the screen (relatively similar stuff) and if you tap the microphone (it’s the little pin just to the left of the iSight lens) you should see noise appear on the screen to show it’s working.

If you want to hear the mic capture instead of see it, you can just run:

arecord | aplay

The internal mic is surprisingly good and seems to pick up even fairly quiet sounds at a distance. I could record myself speaking quietly a good 5 feet away and still understand it when played back.