Tuesday, January 4, 2011

AudioStreamer - CeltStreamer

I must admit that chosing the Edimax 6104 router wasn't the easiest path to OpenWRT hacking, but it was very rewarding in terms of the learning curve. After some minor tweaking I decided to dig deeper into the wonders of Embedded micro-architectures. One of the uses of the Openwrt system was to be able to distribute audio without the hassle of audio cables. But what about capturing and broadcasting audio directly from my router or similar machine ?

So a new project was born : audiostreamer

Objective : find the smallest, cheapest machine to capture 22Khz audio and broadcast it to a corresponding receiver. Budget : 50 €

After reading some forums, I stumbled on the Bifferboard (S3282@150Mhz, 8MB ROM, 32MB RAM).
It has sufficient space for all my programming needs and measures only 68x28x21 mm ! That's tiny !

  • Bifferboard : 35 GBP
  • Housing : 5 GBP
  • USB Soundcard : 1.8 GBP

Streaming PCM from and to the device didn't pose any major difficulty :
[Streaming] arecord -D plughw:0,0 -r 48000 -c 2 -f S16_LE | nc 192.168.2.10 6666
[Receiving] nc 192.168.2.9 6666 | aplay -D plughw:0,0

Playing some MP3 audio worked too, using mpc and mpd, combined with a shoutcast-server on my desktop.

The next hurdle was to produce compressed audio in order to minimize bandwidth use ...

  • LAME : failed (lack of FPU on the S3282)
  • IVORBIS (Fixed Point version of Vorbis) : failed

Then I did some research and found another Fixed Point codec .... CELT - Constrained Energy Lapped Transform.

After some fiddling with the 'tools' sources, I managed to compile the celtencoder and celtdecoder.
They work fine ... but they don't seem to be compatible with the aplay / arecord PCM netcatting.
The result is a working encoding/decoding environment, but unfortunately not realtime !

Nicely tucked away in the GIT-repository, I found the celtclient demo and tried to implement it.
I stripped out the streaming part and reduced the main loop to the following activities :



do { alsa_read(pcm1) ; celt_encode(pcm1,celt) ; celt_decode(celt,pcm2) ; alsa_write(pcm2) } loop

Massive overruns and underruns in the ALSA part ....

My Bifferboard running at approximately 50 BogoMips could only handle following testcase @ 8Khz, mono:
do { alsa_read(pcm) ; celt_encode(pcm,celt) ; alsa_write(pcm) } loop

In order to estimate the needed processing power for celt_encode@22Khz I ported the sources to my Edimax environment.
The Adm5120 runs at approx 170BogoMips and should at least on paper provide 3x more processing power.

After implementing the ALSA-sound subsystem I couldn't get the USB Audio to play a standard WAV-file without being completely choppy and slowed down.
Turns out the USB-host on the ADM5120 isn't completely following the USB specifications and is lacking Isochronuous transfer mode.

I'm left no other solution than to get myself a different board to test on. I'm not sure if I would strip down one of the latest routers (TP-LINK 1043 - Atheros AR9132@400Mhz - 266 BogoMips) or maybe look at one of the Marvel boards.

2 comments:

  1. Greetings, — one of the CELT developers here.

    Did you try using the _ctl call to change the encoder complexity? The encoder does a fair amount of non-essential analysis, some of which can be deactivated to lower the complexity.

    A 150MHz "486" running the encoder in realtime seems quite reasonable, so unless it's surprisingly slow. I'm certainly interested in seeing CELT running on hardware like this.

    Just to be sure— you're compiling in fixed point mode, right? (There are several defines that need to be set if you're not using autoconf to build the config.h) It sounds like from your lame comment that you don't even have emulation, but I figure that it's better to ask the silly questions than to be surprised later.

    ReplyDelete
  2. Gregory, the standard setting in the toolchain for the RDC is to activate FPU-emulation.
    I compiled lame and vorbis using these settings.
    In the CELT package I activated FIXED_POINT.
    The reason why lame and vorbis failed was the emulation slowness.
    I had the same experience with my initial testing on CELT, where the slowness and resulting overruns made me think the codec was malfunctioning.
    The reason for not investigating the lame/vorbis behaviour indepth, was my need for a low latency codec. If I wanted to do point to point streaming of audio, having a low latency codec would be a plus. In my second life as FM radio technician and internet DJ/broadcaster, there's one major letdown when streaming audio : latency.

    Thanks for the hint.

    I will give it another go on the Bifferboard. I must admit I didn't try to optimize the encoder behaviour, so I'll drop a note in the celt-dev mailinglist in case I'm stuck here.

    Greetz

    ReplyDelete