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, "org.freedesktop.Telepathy.Connection") 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) iface.connect_to_signal("StreamAdded", on_stream_added)
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: return iface = dbus.Interface(conn, "org.freedesktop.Telepathy.Connection") contact_data = iface.InspectHandles(1, [contact_handle]) uri = filter(lambda d: d.startswith("sip"), contact_data[0].split(";"))[0] 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 :)