[ N O C T E R N I T Y ] Contributing to the general pollution of the internet

27Mar/130

Playing with Asterisk (4/?) – Voice mail

Even in the context of a home set-up, voice mail is a "must-have" feature. My idea is to have a set of voicemail boxes - one per person, and a global "family" mailbox. Ideally, local phones / softphones should be able to access the corresponding mailboxes (the mailbox of the phone's owner and the family mailbox) without having to type a password, but other mailboxes should still be available with an identifier and passwords on all internal phones.

Basic set-up

Before trying to do that, I created a simple set-up that only worked for one of the test lines, and always required credentials to access. The first thing to configure is the voice mail application itself. I had to re-enable the app_voicemail.so module, and write a configuration file for the application (aptly named voicemail.conf). I also wanted email notifications with the message attached. Finally, I noticed the options of having the system force setting greeting messages and password when initially logging in, and that seemed interesting. Here is the resulting configuration file.

[general]
format=wav49|gsm|wav

serveremail=phones@nocternity.net
fromstring=Téléphonie
attach=yes
emaildateformat=%A, %d %B %Y at %H:%M:%S
sendvoicemail=yes
charset=UTF-8

maxmsg=100
maxsecs=180
minsecs=3 
maxgreet=90
maxsilence=2 
silencethreshold=128

moveheard=yes
review=yes
forcename=yes
forcegreetings=yes

maxlogins=3
minpassword=4 

[zonemessages]
; Empty

[default]
1 => 1,Emmanuel Benoît,tseeker@nocternity.net

I left the zonemessages section empty, because I really don't care about that feature; as for the password, it is set to "1" on my user in order to cause the voice mail application to force me to set it when I connect to it.

The next thing to configure was the dial plan. I had to modify one of the extensions for the internal phones in order to have it fall back on the voice mail when necessary. I initially used the following configuration:

exten => 100,1,Dial(${DIAL_TEST1},10,tT)
	exten => 100,n,Voicemail(1@default)
	exten => 100,n,Hangup()

The new argument to Dial() simply indicates the maximal ringing time before falling back to the voice mail. In this case, "ring for 10 seconds and fall back to the voice mail if there is no response".

I also had to add an extension that would give users (namely, me) access to their voice mail:

exten => 666,1,VoiceMailMain()
	exten => 666,n,Hangup()

Finally, I modified the voice mail fall-back  in order to play either the "busy" greeting or the "unavailable" greeting, depending on the Dial() application's result. This took me a while to figure out due to the somewhat twisted syntax.

exten => 100,1,Dial(${DIAL_TEST1},10,tT)
		exten => 100,n,Voicemail(1@default,${IF($["${DIALSTATUS}" = "BUSY"]?b:u)})
		exten => 100,n,Hangup()

Note about voice mail notifications

I tried setting up voice mail notifications for the SIP clients, by adding the following to their section in the sip.conf file:

mailbox=1@default

However, linphone does not appear to support this (it causes a warning on Asterisk's side), and the other free (not as in beer) softphones I tried had a tendency to blow up in my face.

General set-up

I needed to make quite a few changes in order to implement the idea I mentioned in this post's introduction.

Voice mail fall-backs for all phones

First, having a voice mail fall-back for all phones. In order to do that without the configuration becoming a copy-pasted mess, I had to learn about macros, which are basically dial plan sections which can be invoked from other areas of the dial plan. Here's the macro I used for the voice mail fall-back:

[macro-internal-call]

exten => s,1,Dial(${ARG1},10,tT)
	exten => s,n,Voicemail(${ARG2}@default,${IF($["${DIALSTATUS}" = "BUSY"]?b:u)})
	exten => s,n,Hangup()

This macro takes two arguments: the phone(s) to dial, and the voice mail box to fall back to. It then needs to be used in place of the internal phones' extensions:

exten => 100,1,Macro(internal-call,${DIAL_TEST1},1)
exten => 101,1,Macro(internal-call,${DIAL_TEST2},1)
exten => 102,1,Macro(internal-call,${DIAL_TEST3},2)

(I'd added box #2 and #9 in the meantime.) I also had to "emulate" that family voice mail box. I simply added the following extension:

exten => 999,1,Macro(internal-call,${DIAL_TEST1}&${DIAL_TEST2}&${DIAL_TEST3},9)

... which will cause all phones to ring when dialed, and fall back on mailbox #9.

Password-less access to voice mail

The next step was to allow clients to access their own voice mail, as well as the global one, without password. I started by changing the contexts for SIP clients to something that corresponds to their owners in sip.conf:

; ...

[test1](test-template)
        context=phones-tseeker
        ;...

[test2](test-template)
        context=phones-tseeker
        ;...

[test3](test-template)
        context=phones-ju
        ;...

Of course, I then needed to define these contexts in the dial plan. However, I wanted to avoid having to copy/paste common configuration; this is where the include thing comes in. It allows the extensions listed in another section to be considered. The modified extensions.conf looked somewhat like this:

[phones-tseeker]

        include => tests
        include => phones

[phones-ju]

        include => tests
        include => phones

[tests]

        ; Various 8378-prefixed tests here

[phones]

exten => 100,1,Macro(internal-call,${DIAL_TEST1},1)
; etc...

exten => 666,1,VoiceMailMain()
        exten => 666,n,Hangup()

Finally, I added the lines allowing direct access to the voice mail to each "owner-specific" section:

[phones-tseeker]

        include => tests
        include => phones

exten => 700,1,VoiceMailMain(1@default,s)
        exten => 700,n,Hangup()
exten => 701,1,VoiceMailMain(9@default,s)
        exten => 701,n,Hangup()

[phones-ju]

        include => tests
        include => phones

exten => 700,1,VoiceMailMain(2@default,s)
        exten => 700,n,Hangup()
exten => 701,1,VoiceMailMain(9@default,s)
        exten => 701,n,Hangup()

Some thoughts for later

I think it would be best if all internal numbers were prefixed with something that is not associated with outgoing calls at all. The "star" key seems like a decent prefix. In addition, it would be a good idea to make the various extensions and voice mail box numbers a little more rational and consistent.

Related Images:

Gallery not found. Please check your settings.
26Mar/130

Playing with Asterisk (3/?) – A menu (sort of)

I wanted to try adding something that sort of feels like a menu to the dial plan. I am not sure that I will actually use one in the final setup, but it wasn't that much effort anyway.

A menu (or something with similar functionality) can be implemented using either Background() or WaitExten(). Or both, actually. Since I don't have anything to play as a prompt, I chose to do with the latter only. After all, this is only a test.

First, I replaced the previous test with the following:

[test]

exten => 8378,1,Answer()
        exten => 8378,n,Set(TESTCOUNT=0)
        exten => 8378,n,Goto(numbers,0,1)

This will cause Asterisk to answer calls to 8378 ("test"), set a channel-specific variable called TESTCOUNT to zero, and jump to extension 0 of the numbers section in the dial plan. The idea is to accumulate the digits typed by the user, and then to have Asterisk say that number. So, for each possible digit, the section will contain something like this:

[numbers]

exten => 0,1,Set(TESTCOUNT=$[ ${TESTCOUNT} * 10 ])
        exten => 0,n,WaitExten()
exten => 1,1,Set(TESTCOUNT=$[ ${TESTCOUNT} * 10 + 1 ])
        exten => 1,n,WaitExten()
; ... Same thing for 2 - 9 here ...

Finally, pressing the star key will cause the system to say the number (using SayNumber()) that was typed and to hangup.

    exten => *,1,SayNumber(${TESTCOUNT})
	    exten => *,n,Hangup()

Related Images:

Gallery not found. Please check your settings.
21Mar/130

Playing with Asterisk (2/?)

Last time I managed to get a very basic Asterisk setup to work. Since then, I haven't had the time to really work on it, but I've made a few improvements here and there.

Dial plan improvements

In quite a few documents I read, dial plans always include a Hangup() line for all extensions, whatever they contain. I'm not 100% sure it's actually useful, but I added it anyway:

exten => 100,1,Dial(SIP/test1)
        exten => 100,2,Hangup()

exten => 101,1,Dial(SIP/test2)
        exten => 101,2,Hangup()

One of the things that was a little scary about the dial plan in general was the fact that I would have needed to renumber all lines for an extension if I wanted to insert stuff in one of its parts. That would have been rather annoying. As it turns out, Asterisk supports using "n" as the priority field in the dial plan's extension definitions. Using it causes Asterisk to handle the "line numbering" automatically (with the exception of the first line that still needs to be 1):

exten => 8378,1,Answer()
        exten => 8378,n,Playback(hello-world)
        exten => 8378,n,Hangup

exten => 100,1,Dial(SIP/test1)
        exten => 100,n,Hangup()

exten => 101,1,Dial(SIP/test2)
        exten => 101,n,Hangup()

Finally, I started using global variables to define the dialing targets, which would make it much easier to change if I needed to:

[globals]
        DIAL_TEST1=SIP/test1
        DIAL_TEST2=SIP/test2

[test]

; ...

exten => 100,1,Dial(${DIAL_TEST1})
        exten => 100,n,Hangup()

; ...

Granted, it is "a little" pointless in this context, but it will come in handy later.

Caller IDs for SIP clients

I also added caller IDs for SIP clients. It is extremely simple to do that by simply adding a line that looks like this...

        callerid="TSeeker's mobile" <101>

...to a SIP client's configuration.

Transferring calls

One other thing I added is the ability to transfer calls. First, I started by creating a features.conf file in order to define the DTMF sequences to use. Here's what it contains:

[general]
        ; Empty

[featuremap]
        blindxfer => #1
        atxfer => #2

[applicationmap]
        ; Empty

This is not strictly necessary, as the defaults can be used. Anyway - the next step is to enable the functionality when calls are being made. This is done from the dial plan:

; ...
exten => 100,1,Dial(${DIAL_TEST1},,tT)
; ...

In this specific case, I want to allow both sides to transfer the calls, as these are internal phones anyway (I added a third client on Ju's also-microphone-less PC to run tests).

Miscellaneous changes

Amongst other minor changes, I also re-configured logging using the following configuration in logger.conf:

[general]
        ; Empty

[logfiles]
        console => notice,warning,error,debug
        messages => notice,warning,error

No need for Asterisk-based log file rotation as the Debian package handles that using logrotate.

I also modified modules.conf to remove more currently useless modules (it's just a bunch of noload's for stuff I know I'm not gonna need so I'm not pasting this here).

Finally, I did not add IPv6 support yet, as I need to upgrade to 1.8 for that and I figured IPv4 would be fine for testing purposes; I don't expect many things to change because of IPv6 support anyway (although I may be wrong).

Related Images:

Gallery not found. Please check your settings.
19Mar/130

Playing with Asterisk (1/?)

The long term "plan" here at home is to switch over to VoIP for all phone calls. This includes getting rid of our old POTS phones, using softphones on the PCs, possibly buying hardware VoIP phones or, if I ever get the time to finish playing with the STM32 board, making our own; it also implies subscribing to a pair of SIP lines and using a board to connect our POTS line to the network.

There's a catch, tho: I've never used Asterisk (or any other kind of VoIP software), and it seems to be rather complex. So before we do anything, I'm going to be exploring its configuration a little when I have some time and nothing more important to do.

Since I'm basically a complete newbie when it comes to it, I'll try and post about it as it might be useful to someone in a similar situation.

System

Before I go on, it should be noted that I am working with a Debian Squeeze system, running inside a Xen VM. That VM is on a network that has both IPv4 and IPv6 stacks. The idea is to have everything local going through IPv6, with support for IPv4 through NAT (which means the Linux routers here need to have nf_conntrack_sip and nf_nat_sip loaded; the VM itself only has nf_conntrack_sip). While I've read that NAT is terrible when it comes to SIP (and for everything else), I'm afraid I don't have much choice on the matter.

For now I won't be doing anything that requires specific hardware, as it is a bit pointless to buy a €700 board if you're not even remotely sure you can do what you need to with it.

I have ordered a pair of webcams that include microphones, and they should arrive in a few days. At the moment, however, the PCs here have no way to record sound, so my ability to test with them is limited. I figured I could use my mobile phone for testing, though. I installed Linphone on both my PC and my smartphone.

Installing Asterisk

This is a Debian system so  it's rather easy to install Asterisk and its various dependencies:

apt-get install asterisk

Ok, I actually removed some recommended dependencies I won't be needing (either "for now" or "permanently").

The Debian package comes with a metric ton of sample configuration files under /etc/asterisk; while these are rather handy to have around as they are very well commented, I moved them out of the way as I prefer writing my own configuration from scratch.

First steps

So, the first thing I want to do is set up the server so it is possible to connect to it. That's the definition of "minimal configuration", but one has to start somewhere.

I left both asterisk.conf and modules.conf mostly untouched (with the exception of comments being removed), although I'll probably have to remove some modules when I have a better idea of what I'm doing. Most of the action here takes place in sip.conf:

[general]
        context=default
        allowoverlap=no
        udpbindaddr=0.0.0.0
        tcpenable=no
        srvlookup=yes

[test1]
        type=friend
        host=dynamic
        canreinvite=no
        nat=yes
        context=default
        dtmfmode=rfc2833
        allow=all
        username=test1
        secret=...

The general section is basically the default, followed by a test user which I can use to try and connect to the server. I also included an empty dial plan (while I'm not sure it was necessary, I figured it wouldn't hurt):

[general]
static=yes
writeprotect=no
clearglobalvars=no

[globals]
; No variables

[default]
; Empty context

After some tinkering with the Linphone configuration (I needed to add a proxy account, using sip:test1@server-ip as the identity and sip:server-ip as the proxy address), I was able to get it to connect to the server.

A basic dial plan

The next logical step was to try and have the client dialing, with the server responding with something. Fortunately, Asterisk comes with a lovely hello-world.gsm file.

First I modified my test user so that its default context would be something other than default. I called that new context test. For some reason.  Then I created a simple dial plan that would cause the server to answer, play the "hello world" sound, and hangup, when the client dials "1".

[test]
exten => 1,1,Answer()
exten => 1,2,Playback(hello-world)
exten => 1,3,Hangup

And "1" was dialed, and "Hello world" was heard, and it was good.

Two accounts

Having done that, I decided to try implementing calls between SIP clients. Of course, since only one of the two SIP clients has a microphone, my ability to test is limited.

So, I wanted to add a second SIP client. Since its configuration would end up being mostly the same as the one I already had, I decided to use a template for the clients. Here's the resulting sip.conf:

[test-template](!)
        type=friend
        host=dynamic
        canreinvite=no
        nat=yes
        context=test
        dtmfmode=rfc2833
        allow=all

[test1](test-template)
        username=test1
        secret=...

[test2](test-template)
        username=test2
        secret=...

Then I had to add a few lines to the dial plan in order to allow dialing between one client and the other. It only takes two new lines in the dial plan:

exten => 100,1,Dial(SIP/test1)
exten => 101,1,Dial(SIP/test2)

Because I don't have WiFi here, I had to whitelist the phone carrier's IP range on the firewall to let it connect to the server. The configuration of Linphone uses the server's internal IPv4 address (i.e. its address on the LAN here) as the domain, and the IPv4 address of the DSL connection as the proxy. With this configuration, I was able to call the phone from the PC and vice-versa.

Related Images:

Gallery not found. Please check your settings.
13Nov/120

Stuck on the CS43L22

I have not been making much progress lately. I am trying to get the board to produce sound through its CS23L22 chip. So far, I've managed to:

  • make it accept commands through I2C (which I know succeeded because, well, the commands do not timeout),
  • enable and configure the I2S bus.

I've been sending data on it (basically a simple 440Hz sine wave), but there is no output. I know the bus' clock is configured correctly, because I've been pumping the data onto it directly through SPI3's data register, and toggling a LED every 22100 samples, which works just right (the LED blinks with a period of 2s). I also know that the chip works (because it does produce sound when I run the board's original firmware).

I'm quite sure it's something extremely silly I'm forgetting to do, or doing in the wrong order somewhere... but I have no clue where and what it is.

Related Images:

Gallery not found. Please check your settings.
7Nov/120

RS232 != TTL

Ok, I've said it before, but repeating it one more time won't hurt: when it comes to electronics or hardware, I am completely ignorant. So, yesterday morning, I spent the best part of 3 hours trying to plug the STM32's UART ports on a PC DE9 interface, trying to get the code to work and fiddling with Minicom's settings.

Then I looked it up. As it turns out, signals from the microcontroller are encoded using TTL (where a voltage close to 0V indicates a zero, while a voltage close to the chip's power supply voltage indicates a one), while RS232 relies on a negative voltage to indicate a zero.

*cough* I felt really silly.

So I looked up how to interface both. There are many schematics and explanation on the web; this explanation is quite good, and I ended up using their schematics and some parts I already had to build one (well, I didn't add the LEDs because I didn't see much point in these).

Here's the result:

And, if that can help, here are the schematics for the board itself (not exactly the one shown above, as I'd made a bit of a mistake):

And the list of parts:

Parts
R1 R2 R3 R4 R5 10kΩ
C1 10µF, 50V
D1 1N914
Q1 2N3906
Q2 2N3904

Related Images:

Gallery not found. Please check your settings.
4Nov/120

A little progress

I managed to get the TFT screen working this afternoon. For now I'm using bit-banging both to initialise the board and access the framebuffer, the idea being to try and use it with the STM32F4's FSMC later. I'm a little disappointed that the backlight is hardwired to the module's power supply (which means the SSD1963's backlight control can't be used) and that the tearing output pin is not connected at all. Ah well.

This one actually moves:

Related Images:

Gallery not found. Please check your settings.
3Nov/120

Toys

Just bought a few interesting toys:

The ITDB02-4.3 module includes a 480x272 LCD screen controlled by an SSD1963 chip, a resistive touch screen controlled by an XPT2046, and a SD card slot. For now, I only managed to get the touchscreen working (I've never programmed for an MCU before, so I'm a bit slow). My screwing around with the board and module can be found on GitHub.

Related Images:

Gallery not found. Please check your settings.
25Oct/110

Mass destruction

The first stage of the repairs in the house wasn't quite in the "repair" category. Indeed, most of the work implied getting raw plaster on the walls and ceilings, removing carpet from the floor, and so on.  This task kept us busy from July to October 2009. Since it would be boring to present that kind of activities everywhere in the house, I'll present a few emblematic spots.

The hall is a good example of what we had to face in most rooms on the ground floor.

The wallpaper is quite easy to get rid of, but there's something much, much worse : polystyrene tiles glued on all ceilings. Not only they are  quite difficult to remove because of the position you have to be in in order to remove them, but you usually leave pieces of skin on the ceiling and end up bleeding after a few hours. Last but not least, it is impossible to remove the glue without removing pieces of plaster from the ceiling. In the end, we have ceilings which look like fields of round holes.

We ended up with:

  • on the one hand somewhat "correct" walls and ceiling, if you ignore the holes which will have to be filled
  • plenty of junk which we had to bring to the waste collection centre on a regular basis. We were going there so often that the employees were almost on a first name basis with us !

Another rather interesting place was the living and dining rooms. If you remember the pictures from the origins, these rooms not only had the wonderful polystyrene tiles on the ceiling but also panelling on the walls. Manu had great fun removing them and... the glue...The work in progress provides a wonderful idea of the extent of the issue.

In the end, this allowed us to reach that kind of stage:

Last but not least, the "situation" on the first floor... We had:

  • The ever-present polystyrene tiles on the ceilings, of course, which were impossible to unglue without removing part of the paper of the drywalls,
  • Moquette on the floors. These went off easily, even if part of them were hidden under a floating floor.
  • Moquette on the walls. That was the real pain because some kind of paper layer remained glued on the drywalls and it was awful to unglue it.

For instance, we went through that kind of stage regarding the corridor on the first floor:

... or in one of the bedrooms:

And with much effort, we managed to reach these almost final conditions:

  • In the corridor

  • In the bedroom:

To be honest it was quite a depressing activity: indeed we were destroying what was somewhat decent in order to reach the raw skeleton of the house. However things would soon improve, which I will explain in a later post.

Related Images:

Gallery not found. Please check your settings.
20Oct/110

Criminal incompetence

I have a lot of work to do, and many posts I'd like to write, but that will have to wait. I need to vent some frustration right now.

I am currently on a systems administration mission where I need to inspect and fix (if necessary... lol!) a few virtual servers.

Let's start with the documentation. Oh wait, I can't really start from there. There's nothing. A bunch of IP addresses, a few very weak passwords. A list of a few shell commands, out of the blue. A list of stuff that's been done, or at least I suppose that's what it's supposed to be (the list contains entries such as "Access phpmyadmin", followed by "Change init level"). Nothing to see here, let's move on.

The server's list of virtual hosts includes a SSH gateway, from which you're supposed to connect to the server's other VMs. Well, that sounded fine to me, as it may have meant I wouldn't need to go there and could simply log on through that gateway. Of course, since the "existing" documentation doesn't really list the VM's IP addresses, it's a bit messy. Especially since most ICMP packets seem to be blocked, somewhere, somehow. Oh, and some of the VMs do not listen on port 22. Has it been changed to some other port? Is it being blocked by iptables rules? No fucking clue. In addition, it was possible to log in as root (using a password that wasn't much better than "test") on the gateway.

For now, I've been able to find 3 out of the 11 VMs I'm supposed to take a look at,  including the aforementioned gateway. Each host includes the full Gnome desktop, as well as a random assortment of useless stuff (laptop-detect? Dude, it's a VM!). Of course, since the... person... who did this decided to use Ubuntu Server, it's not even possible to remove dbus, because upstart depends on it. Still, I was able to remove a few gigabytes of crap on the servers I could access.

I expect more bad surprises as I keep on working on that. In the meantime, my opinion is that whoever committed this in the first place should seriously think about giving up on systems administration and looking for a career in, oh, I don't know, floor wiping. Or something like that.

Related Images:

Gallery not found. Please check your settings.