RSS ugliness
I find it ironical to post a criticism of RSS through a medium where RSS is so dominant itself but here it goes anyways
RSS is mainly used for communicating news (more often breaking news than editorials). Hence, timeliness of getting a news item through RSS is important. The mechanism by which RSS works is pretty simple itself. An RSS feed is a simple text file served by a web server. News readers keep ‘polling’ the subscribed feeds at regular time intervals to get updates. In general, news readers set their polling rate at highly aggressive levels to ensure timeliness of news delivery.
Many sites complain that RSS feeds on their sites get ‘polled’ at such high rates that the amount of bandwidth they consume is significant compared to the traffic to their main website. This is obviously not a good trend as bandwidth is scarce and expensive. Also, most of the transfers are just for the news readers to check if there was a news update or not, so its quite likely that a significant fraction of RSS hits aren’t even viewed. Some analysis on this can be found at Robert Scoble’s blog and Internetnews. The general workaround against the problem is to limit the size of RSS items or use an RSS distribution service.
It is amusing to note that RSS appeared and became successful at a time when well engineered and time tested alternatives already existed. The most prominent is e-mail. Its well tested, robust and most importantly a notification medium by design. Instead of messy polling, it is based on one time reliable delivery of the message directly to the interested party (I am talking about the SMTP protocol for mail delivery). There is no scarcity of email clients on all kinds of platforms and they have umpteen number of ways to automatically filter and organize one’s mail. Email has also evolved significantly over the years. Problems like duplicate delivery and authentication have been taken care of. Its sad to see the powerful and efficient system of email newsletters being abandoned in favor of RSS feeds.
Please note that the IMAP protocol for accessing is mail is a client protocol and does use polling. However, it sensibly restricts polling to a very small transaction with the client asking the server for a count of unread messages. This is way better than fetching the whole feed again as done by RSS. Having said that, it is known that IMAP can be pretty resource hogging itself. It is very much possible for a thin client interface for mail (webmail, remote login) to actually be more efficient than IMAP itself.
RSS is evolving too. There are services which allow you to cache your website’s feed on their servers. The service takes over the subsequent distribution load. This reminds me a lot about how DNS works. DNS is probably one of the most heavily used, scalable and design-wise underestimated protocols on the Internet. It also works by having (a big number of) distributed caches between authoritative content (in case of DNS, the host-name to IP address mappings; the feed content in RSS’ case). However, there are enough differences between the two to point out the problems with RSS’ general design. DNS data is reused (a lot). Hence caching it at a local server makes sense. Updates are infrequent and often non-critical making an elaborate delivery mechanism (like Email for instance) an overkill. DNS hence resolves to simple expiration of cache entries to refresh DNS data in the caches. In contrast, RSS data is discarded the moment it has been used hence polling and caching at a ‘blog service’ site makes little architectural sense other than offloading bandwidth usage. We already touched upon the timeliness and frequency of update aspects of RSS which is in stark contrast with DNS.
Overall, a step backwards in technology…
Pulseaudio + ALSA Configuration
Okay… if you have read my previous post on ALSA Configuration you will know that I am trying to solve my sound setup problem in linux. The basic problem can be summarized as:
- Use the sound cards at their native sample-rate to improve over their rather poor hardware re-samplers.
- Mix audio from multiple applications on the cards.
- Be able to easily designate audio cards on a per application basis at application launch time.
I had commented earlier that I decided against pulseaudio because of its lack of 32 bit signed integer audio support. I realized after some general use of my previous alsa configuration that even though some applications use 32 bit audio well, most other applications have problems. Typically mplayer and ut2004 (through aoss) couldn’t correctly figure out that the device was running at 32 bit precision and sent it 16 bit audio data. This caused both the applications to run audio at half the speed with the audio crackling all over. The fix was simple: change S32_LE in .asoundrc to S16_LE. However, that would be the end of any 32 bit audio on my system. I also realized that the only application which I used (heavily) with 32 bit audio was madplay (piped through aplay; madplay directly outputs to hardware alone). I grudgingly agreed to sacrifice that
.
Pulseaudio configuration is pretty straight forward. I configured the /etc/pulse/default.pa for the two cards in the following way. I happily noticed that pulseaudio used a good resampler by default (speex-float-3 which has similar CPU usage as alsa’s plugin speexrate).
/etc/pulse/default.pa
#!/usr/bin/pulseaudio -nF .nofail ### Load something into the sample cache #load-sample-lazy x11-bell /usr/share/sounds/gtk-events/activate.wav #load-sample-lazy pulse-hotplug /usr/share/sounds/startup3.wav #load-sample-lazy pulse-coldplug /usr/share/sounds/startup3.wav #load-sample-lazy pulse-access /usr/share/sounds/generic.wav .fail ### Load audio drivers statically load-module module-alsa-sink device=intelHDA sink_name=Spkr rate=192000 load-module module-alsa-sink device=iMic sink_name=HeadPh rate=48000 ### Load several protocols #load-module module-esound-protocol-unix load-module module-native-protocol-unix ### Automatically restore the volume of playback streams #load-module module-volume-restore ### Automatically restore the default sink/source when changed by the user during runtime #load-module module-default-device-restore ### Automatically move streams to the default sink if the sink they are ### connected to dies, similar for sources load-module module-rescue-streams ### Automatically suspend sinks/sources that become idle for too long load-module module-suspend-on-idle ### Make some devices default set-default-sink Spkr #set-default-source input
To make alsa applications work directly with pulseaudio we just need to set the default pcm and ctl to the pulse alsa plugin (configuration shown later). The pulse plugin creates a new audio device called pulseaudio and maps its audio I/O to the default pulse sink which can be changed at runtime. The pulseaudio device also has two mixer controls; a “Master” for playback and a “Capture” for recording.
The problem with the above is that pulseaudio starts looking for mixer controls “Master” for every configured sink hardware device (with a fallback to “PCM”). The default alsa configuration doesn’t provide a “Master” control for either the intelHDA card or the iMic card. The “PCM” on iMic controls the hardware mixer directly and that for intelHDA controls a software volume for alsa’s default dmix configuration. Thus, the pulseaudio fallback to “PCM” works correctly for iMic (changing the pulseaudio “Master” control changes the volume) but not for intelHDA (changing pulseaudio “Master” control has no change on volume, but changing “Front” directly on the hardware using alsamixer -c does work). To work around this I configured two virtual softvol (software volume) devices for my two cards naming the softvol control “Master”. The configuration is shown below.
.asoundrc
pcm.!default {
type pulse
}
ctl.!default {
type pulse
}
# Create softvol devices for intelHDA and iMic.
# For intelHDA, its "PCM" control controls its default (not used) softvol.
# For iMic, its "PCM" control controls its hardware directly.
pcm.intelHDA {
type softvol
slave.pcm "hw:0,0"
control.name "Master"
control.card 0
}
pcm.iMic {
type softvol
slave.pcm "hw:1,0"
control.name "Master"
control.card 1
}
# It seems we require these dummies as pulseaudio tries to look up mixer devices.
ctl.intelHDA {
type hw
card 0
}
ctl.iMic {
type hw
card 1
}
# For UT2004 (which uses dsp0 through aoss), always go directly to headphone hardware.
pcm.dsp0 {
type plug
slave.pcm "hw:1,0"
}
ctl.dsp0 {
type hw
card 1
}
Note that the pcm names used (intelHDA and iMic) are used in /etc/pulse/default.pa as sinks. More information on the softvol alsa plugin can be found here. There is some nice documentation about the various alsa plugins here. There some good documentation about alsa is also present here, here and here.
To change the current default pulseaudio sink I rewrote the audio.sh from the previous post to the following:
audio.sh
#!/bin/bash
pulse_set_default_sink () {
pacmd << EOF
set-default-sink $1
EOF
}
h=`cat $HOME/.dwm/status_audio`;
if [ "x$1" == "x" ]; then
if [ "x$h" == "x[ Spkr ] " ]; then
echo -n "[ HeadPh ] " > $HOME/.dwm/status_audio ;
pulse_set_default_sink HeadPh ;
else
echo -n "[ Spkr ] " > $HOME/.dwm/status_audio ;
pulse_set_default_sink Spkr ;
fi
elif [ $1 == "up" ]; then
amixer set Master 2%+ ;
elif [ $1 == "down" ]; then
amixer set Master 5%- ;
elif [ $1 == "toggle" ]; then
amixer set Master toggle ;
else
echo "$0: Unknown command $1";
fi
v=`amixer get Master | grep "Front Left:" | egrep -o "[0-9]+%"`
m=`amixer get Master | grep "Front Left:" | egrep -o "off"`
if [ "x$m" == "x" ]; then
echo -n "vol:$v "
else
echo -n "vol:(M) "
fi > $HOME/.dwm/status_volume
Note that now environment based device settings are gone as the current default pulseaudio sink automatically maps to the global alsa default pcm device. Once an application connects to pulseaudio, it retains its sink mapping even after the default sink is changed. (Update: It seems that module-volume-restore remembers the volume and sink of a client and restores both when it sees the client again. This behavior is definitely useful but we need to disable module-volume-restore if we want our current default sink logic to work). Pulseaudio also support hot swapping an application’s audio from one sink to another. I am still thinking of a way to toggle the sink device of the currently focussed application using dwm shortcuts… that would be some nifty configuration
.
ALSA configuration
I recently configured the sound setup on my home computer. The problem was as follows: I have two sound cards 1) intel HDA (inbuilt) 2) usb based iMic. (I needed two because I wanted to have both my headphones and audio system hooked up and ready to play audio without manually (un)plugging cables.) I wanted to be able to switch between the cards on a per application basis. Basically enough capability to be able to launch applications each with a playback device determined at launch time.
Also, both the soundcards are pretty cheap and hence (probably) lack good re-sampling engines on the card itself. Most of my music is in 44.1KHz and iMic probably re-samples them to 48KHz during playback. intelHDA supports sample rates as high as 192KHz and I think does a naive re-sampling to that rate too before playback. So besides simple device switching I also desired to use a decent resampler to convert to 48KHz or 192KHz before the signal is fed to the device.
And last (but definitely not the least) I needed some way to mix multiple streams without latency issues.
Pulseaudio fits the above requirements very well. It also supports per application volume controls and dynamically switching applications to different input/output devices. It packages good resampling algorithms and sports a lot of features through modules. However, it doesn’t support 32 bit integer audio (which intel HDA does). Once pulseaudio supports 32bit integer devices natively I plan to switch. Given the recent interest in pulseaudio by Ubuntu and Fedora projects, this should happen fast.
So I took the alsa route. The environment variables ALSA_CARD (or ALSA_PCM_CARD) can be set to the card number to switch the card being used. This gives us an easy mechanism to launch different applications with different audio devices.
Also, alsa by default configures a ‘dmix’ plugin to mix audio streams before sending it to the hardware. However, the default configuration (buried in /usr/share/alsa) puts dmix before the hardware device selection. dmix has to operate on data at a fixed sampling rate which by default is set to 48KHz. Moreover, to avoid lots of CPU usage, the re-sampling algorithm used is poor. I wanted to setup separate dmix plugins for each of my devices operating at their native frequencies and use good re-samplers for audio sample rate conversions. Fortunately, alsa has a set of plugins (package alsa-plugins in gentoo) which include good re-samplers. Note that with two dmix plugins setup, using ALSA_CARD to switch the hardware device will not (and should not) work. We need a mechanism to switch to the given dmix plugin instance using environment variables.
Without further ado, here is my ~/.asoundrc and audio.sh (which I use for launching audio applications / switching devices / manipulating volume).
~/.asoundrc
defaults.pcm.rate_converter "speexrate"
defaults.pcm.card_name "intelHD"
defaults.pcm.card 0
pcm.!default {
type plug
slave.pcm {
@func getenv
vars [
ALSA_CARD_NAME
]
default {
@func refer
name defaults.pcm.card_name
}
}
}
ctl.!default {
type hw
card {
@func getenv
vars [
ALSA_CARD
]
default {
@func refer
name defaults.pcm.card
}
}
}
pcm.dsp {
type plug
slave.pcm "intelHD"
}
ctl.dsp {
type hw
card 0
}
pcm.intelHD {
type dmix
ipc_key 1024
slave {
pcm "hw:0,0"
format S32_LE
rate 192000
}
bindings {
0 0
1 1
}
}
ctl.intelHD {
type hw
card 0
}
pcm.iMic {
type dmix
ipc_key 1025
slave {
pcm "hw:1,0"
format S16_LE
rate 48000
}
bindings {
0 0
1 1
}
}
ctl.iMic {
type hw
card 1
}
and audio.sh
#!/bin/bash
h=`cat $HOME/.dwm/status_audio`;
if [ "x$h" == "x[ Spkr ] " ]; then
export ALSA_CARD_NAME=intelHD ;
export ALSA_CARD=0 ;
master=Front ;
else
export ALSA_CARD_NAME=iMic ;
export ALSA_CARD=1 ;
master=PCM ;
fi
if [ "x$1" == "x" ]; then
if [ "x$h" == "x[ Spkr ] " ]; then
echo -n "[ HeadPh ] " > $HOME/.dwm/status_audio ;
export ALSA_CARD_NAME=iMic ;
export ALSA_CARD=1 ;
master=PCM ;
else
echo -n "[ Spkr ] " > $HOME/.dwm/status_audio ;
export ALSA_CARD_NAME=intelHD ;
export ALSA_CARD=0 ;
master=Front ;
fi
elif [ $1 == "up" ]; then
amixer set $master 5%+ ;
elif [ $1 == "down" ]; then
amixer set $master 5%- ;
elif [ $1 == "toggle" ]; then
amixer set $master toggle ;
else
exec $1 ;
fi
v=`amixer get $master | grep "Front Left:" | egrep -o "[0-9]+%"`
m=`amixer get $master | grep "Front Left:" | egrep -o "off"`
if [ "x$m" == "x" ]; then
echo -n "vol:$v "
else
echo -n "vol:(M) "
fi > $HOME/.dwm/status_volume
Let’s go over .asoundrc first. BTW, just for the record, the alsa configuration format is one of the weirdest formats I have seen. It is not user friendly and it also lacks a good deal of flexibility. Anyways, alsa configuration is all about defining pcm (virtual devices for audio I/O) and ctl (mixer interfaces) virtual devices. A number of pcm virtual device plugins along with some details on setting them up is documented at alsa-project. I use the ‘hw’, ‘dmix’ and ‘plug’ plugins in the above configuration. The pcm.intelHD, ctl.intelHD, pcm.iMic and ctl.imic sections outline dmix configurations for each device. The ‘type dmix’ creates dmix plugin instances named ‘intelHD’ and ‘iMic’. Each requires unique (arbitrarily chosen) ipc_keys. The slave configuration is pretty much the hardware device at its highest possible capabilities in format and sample-rate (pcm “hw:n,m” uses the hw plugin to talk directly to the kernel device; BTW, we could have used any pcm virtual device here). I don’t know what bindings are, but I am guessing it binds channels between the slave pcm device and the pcm being configured. I use two channels and the above seems to work.
Note that the above creates dmix virtual pcm device instances with the same format and sample rates as the slave pcm. So intelHD dmix can take signed integer 32bit data at 192KHz and the iMic dmix can take signed integer 16bit data at 48KHz. My devices don’t support float 32bit data (which pulseaudio supports :/). If we directly use these pcm devices for audio playback our audio application will either need to do format conversion/resampling itself or fail with format/samplerate incompability kind of errors. Fortunately, alsa provides a ‘plug’ virtual pcm device (very weird name if you ask me) to do the format conversion and resampling automatically. It can also do all kinds of channel routing magic too but I didn’t use any such capabilities. I basically created the ‘default’ pcm device (used by all alsa applications in case no pcm device is explicitly stated) using plug. This frees applications to match my dmix (and hardware device ) format/samplerates. Moreover, the default pcm ‘plug’ virtual device uses the ’speexrate’ re-sampler for all resampling. The documentation at the url above says that plug supports a rate_converter argument for specifying the re-sampling engine to use. However, that didn’t work on my system. Fortunately changing the default resamler works. The speexrate resampler takes a little less than 20% CPU on a single core on my 2.4GHz Core2Duo. The CPU usage is reported as part of the audio application using the audio device. It would have been nicer on the CPU to be able to be able to create separate dmix instances for each sample rate in use by applications and then resample each of them to the hardware sample rate. But I guess that’s necessary only when one has a lot of simultaneous audio applications running and a lot of them at the same sample rate. Moreover, it will be a nightmare to configure that using the alsa configuration format :/.
The default pcm device looks up an environment variable ALSA_CARD_NAME to form its slave pcm device. I can give any pcm name here but the intent is to configure it to either “intelHD” or “iMic” to use the dmix pcms. Note the really weird syntax. I took me a few trials and inspiration from /usr/share/alsa/alsa.conf to get this right. I had to use two different environment variables for the defaut mixer (ctl) and default pcm. This is because I couldn’t figure how to use a slave with ctl.!default. (The !mark is for overriding a previous configured pcm).
This completes alsa configuration. Now let’s come to audio.sh. It looks up the status_audio file to check which audio device should be selected for the to be performed operation. If status_audio contains “[ Spkr ]” then intelHD is used, otherwise iMic is used. Its usage is as follows:
audio.sh <command>
runs the command with the selected audio device as the default pcm device. Basically, it sets up the the environment variables ALSA_CARD_NAME and ALSA_CARD and starts the command.
audio.sh up
Turns up volume by 2%. Note the usage of $master. The volume control that’s effective on the two devices are different. $master lets amixer use the appropriate control for each device.
audio.sh down
Turns down volume by 5%. (I use different values for up and down so that I can turn down very loud music really fast).
audio.sh
Selects the other device than the current. It writes to the status_audio file to preserve the setting.
audio.sh also writes the volume of the device being configured to status_volume. I use status_audio and status_volume for displaying audio status in dwm (which is a fantastic window manager, if you like a minimalistic and highly productive windowing environment).


2 comments