21 Mar 2008 henrique   » (Observer)

Telepathy rocks, and it rocks a lot! First, let me explain our problem: we need a way to watch outgoing voip calls on maemo and since maemo is, fortunately, using telepathy for its communication software subsystem (named rtcomm), we finish having to use telepathy to do this job.

In the begining, things were obscure, we didn't know the way to follow, but the folks on the telepathy IRC channel (#telepathy @ irc.freenode.net) were very cool... and so, we got the problem fixed before the expected, this motivated to write about the solution here.

The first step was to watch for new connections made to a connection manager, it is quite simple, we just need to connect a callback to the "NewConnection" event, the initial block of code follows:

import dbus
bus = dbus.SessionBus()

cm = bus.get_object( "org.freedesktop.Telepathy.ConnectionManager.sofiasip", "/org/freedesktop/Telepathy/ConnectionManager/sofiasip") iface = dbus.Interface(cm, "org.freedesktop.Telepathy.ConnectionManager.sofiasip") iface.connect_to_signal("NewConnection", on_new_connection)

When a connection is created, we need to watch for new channels being created (which can be read as "a communication channel with some of the contacts was created"), this way:

def on_new_connection(bus_name, object_path, protocol):
    conn = bus.get_object(bus_name, object_path)
    iface = dbus.Interface(conn,
    iface.connect_to_signal("NewChannel", on_new_channel)

So when a channel is created, you got the channel type, if it is a text conversation, the channel_type parameter would be something like "org.freedesktop.Telepathy.Channel.Type.Text". For our case, we need to filter "streamed-media" conversation, so channel_type must be "org.freedesktop.Telepathy.Channel.Type.StreamedMedia". If it is satisfied, we need then attach a new callback for the "StreamAdded" event -- this callback will be fired when a voice or video data transfer has began.

def on_new_channel(object_path, channel_type, handle_type,
                   handle, supress_handler):
    if channel_type.split(".")[-1] == "StreamedMedia":
        channel = bus.get_object(conn.bus_name, object_path)
        iface = dbus.Interface(channel, channel_type)

Finally, on on_stream_added callback, we filter out voice channels, and get the person the user is trying to speak with:

def on_stream_added(stream_id, contact_handle, stream_type):
    # discard video channels
    if stream_type == 1:
    iface = dbus.Interface(conn,
    contact_data = iface.InspectHandles(1, [contact_handle])
    uri = filter(lambda d: d.startswith("sip"),
    print "new call: %s" % uri

Shazam! It works! There is two things to note, though. If you just copy-and-paste the code, it'll not work -- as you can have noticed, some callbacks needs the connection object... you have two choices here: to use lambdas to proxy the real handler passing the connection object among all the handlers until on_stream_added or you can encapsulate all these handlers in a class and define the connection object as an attribute of it, it is up to you.

The other thing is that it can seem not too simple as watch_for_voip_connections(), but you must to note that telepathy doesn't have something specific to do what we needed here, but even in this case the framework seems to be so well designed that it gives to you the power needed to do your work.

I loved telepathy since the moment I start working with it, and I expect to contribute with the project as soon as possible. Hope you like it too :)

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!