Archive for January, 2010

New AMI commands for Asterisk

Our mobile-phone operator has given us access to live status information about all the phones in our subscription. What this means is that when one of our phones are being called to, or turned of, or even roaming to another country; they automagically notifies us instantly via a private API.

What this means, is that we can make this information available to our existing phone system. Since we are using Asterisk, I was going to connect to AMI and update the device state of the mobile phone in question, when we received a status update via the API. The problem is. Asterisk didn’t have any AMI commands for updating Custom device states, only inside the dialplan. Luckily, it’s easy to add new commands to the AMI interface, and it was done in a jiffy.

If anyone is interested, the patch is up at https://issues.asterisk.org/view.php?id=16732.

Now, my Aastra 57i phone correctly lights up a red led, and shows a “un-hooked” icon in front of my extension on the expansion module on phone(or on the phone itself), when my mobile phone is in use.

New penalty function for Asterisk Queue

This patch was developed because Asterisk was missing a ACD feature that our customer has on their previous IVR system. The feature is that if a person(read: agent) goes away from his/her phone, and forgets to log out from the queue, the agent gets ‘paused’ for a specific amount of ‘penalty’-time, where the agent won’t receive any more call attempts. This is almost like the “autopause” function, already present in Asterisk. Except that this one will unpause the user again after a given amount of time.

Lets say we have 3 agents in a queue.. The two first agents have priority 1, and the last one has priority 2. This means that as long as one of the first two agents are off their phones, the queue system will try to call those phones. It will not go to priority 2 unless both agents are busy on their phones, because, they’re free, right? With my patch, the two first agents are temporarily removed from the queue after they don’t answer before the timeout specified for the queue. Now the queue system will try agents in priority 2 automatically. This way, people who wait in line for an agent doesn’t have to wait for ages because one agent forgot to log off.

To accomplish this, I note the time when a member fails to answer his phone in time, and then neglects to call him anymore until (current time – no-answer time) is more than X seconds.

The amount of seconds to wait is defined in queues.conf with the new notpresent-penalty option, or in a realtime database, by a integer field with the name notpresent_penalty.

You can find the patch at Asterisks issue tracker

Programming in Akelos

For some while I have been using the Akelos library for MVC development within PHP. The reason I like this library over other well-known libraries like Zend Framework, CakePHP etc, is that this library is very much coded with “Convension over configuration” which means that you don’t have to over-configure everything. And it’s easy to learn new people how to use it. (more…)

Simple Perl based Icecast clone

This is acctually a mini project I did a while ago, but I thought I could write a small post about it here, and give out the source code.

The reason I did this, was because I used icecast, and had 5 streams up with a lot of users, but sometimes you would get sound from other streams on the same server, or old sound in the middle of the stream. I tried googling after other people with the same problems as me. But found nothing. So I thought; it’s quite simple software, how hard can it be to make a stable myself?

So first I made a proof-of-concept perl script to receive data, and send out to several listeners. Worked great at first try. Only a minior problems. If I paused the stream on one client, the whole server started waiting for that one listener, before sending any more data to all the other listeners. (more about this later) The other problem was that I didn’t have any in-stream “title” support.

The reason the stream stopped when one of the clients stopped listening for data (and blocked further data), is that I was sending data with a blocking socket. Now I tried googling about how to _send_ nonblocking, but coulnd’t find anything. So I made my own little workaround. (someone please give me a better solution)

Instead of:

$sock->syswrite($data)

I wrote a new send subroutine using IO::Select to check if the client is ready for data:

sub send {
	my $self = shift;
	my $sock = $self->{'sock'};
	my $data = shift;
 
	my $select = IO::Select->new;
	$select->add($sock);
	if ($select->can_write(0)) {
		return $sock->syswrite($data);
	} else {
		return 0;
	}
}

This finally did the work for me. The “send()” subroutine now returns how many bytes it sent to the client, and if it couldn’t send any, then it returns zero of course.

Then over to the problem of sending title updates inside the stream. I googled this and found a nice informative page about Shoutcast MetaData.  To bring it into a short explanation; if the client supports shoutcast metadata, it sends the following request header “Icy-MetaData:1” to inform the server that it knows about metadata. Then the server, my script, sends “icy-metaint: 123” back in the response header, where “123” is the amount of mp3 bytes before a metadata string should arrive. After exactly 123 (or whatever the server decides) bytes, the server sends a byte containing information about how long the metadata block is, and then the metadata right after. The “length byte” must be multiplied by 16 to get the real length of the metadata string. So the largest metadata string possible would be 4096 bytes long. Just after the metadata, the mp3 data continues as usual. Usually you won’t send the title data each time the metaint-counter goes around. You’re probably good by sending zero length metadata (just sending a ‘\0’ byte as metadata-length) all the time, until the title actually changes.

So at this time I rewrote the script, and mode it more module based, and added support for several streams, and yaml configuration file for access control, and some status pages, using TemplateToolkit.

So anyways, the script is still in early beta stage, but it should work fluently. It did however seem that the title-data got out of sync after about a day of listening to a stream, until you reconnected. Can’t seem to understand how it would get out of sync, unless a malformed tcp packet would arrive. So either I was testing it with a really crappy internet connection that time, or there is a bug berried deep in the simple code. You are free to have fun with the script, and tell me whats wrong. I also think it’s still full of debug printing. But I have already warned you, this is still in the proof of concept “whack-some-shit-together” stage. I’ts just one of those projects that ends up collecting dust.

If you fire the script up, and go to http://127.0.0.1:8001/ it should give you a list of the current connected streams. Also http://127.0.0.1:8001/xml should give you xml output of current streams. I’ve been using oddcast to send icecast stream to it.

Here’s the full script: perlcast.tar