summaryrefslogtreecommitdiff
path: root/telepathy-farstream/examples/python/callui.py
diff options
context:
space:
mode:
Diffstat (limited to 'telepathy-farstream/examples/python/callui.py')
-rw-r--r--telepathy-farstream/examples/python/callui.py285
1 files changed, 285 insertions, 0 deletions
diff --git a/telepathy-farstream/examples/python/callui.py b/telepathy-farstream/examples/python/callui.py
new file mode 100644
index 000000000..9e7558f6c
--- /dev/null
+++ b/telepathy-farstream/examples/python/callui.py
@@ -0,0 +1,285 @@
+#!/usr/bin/env python
+#
+# callui.py
+# Copyright (C) 2008-2010 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gobject
+gobject.threads_init()
+
+import pygtk
+import gtk
+
+gtk.gdk.threads_init()
+
+import dbus
+from dbus.mainloop.glib import DBusGMainLoop
+DBusGMainLoop(set_as_default=True)
+
+import sys
+import time
+
+from telepathy.interfaces import *
+from telepathy.constants import *
+
+from constants import *
+
+class CallChannelRequest:
+ def __init__ (self, bus, account_path, contact,
+ preferred_handler = "", audio = True, video = False,
+ calltype = HANDLE_TYPE_CONTACT):
+ self.bus = bus
+ self.cd = bus.get_object (CHANNEL_DISPATCHER,
+ '/' + CHANNEL_DISPATCHER.replace('.', '/'))
+
+ props = {
+ CHANNEL_INTERFACE + ".ChannelType": CHANNEL_TYPE_CALL,
+ CHANNEL_INTERFACE + ".TargetHandleType": calltype,
+ CHANNEL_INTERFACE + ".TargetID": contact,
+ }
+
+ if audio:
+ props[CHANNEL_TYPE_CALL + ".InitialAudio"] = True
+ if video:
+ props[CHANNEL_TYPE_CALL + ".InitialVideo"] = True
+
+ self.request_path = req_path = self.cd.CreateChannel(account_path,
+ props,
+ 0,
+ preferred_handler,
+ dbus_interface = CHANNEL_DISPATCHER)
+
+ self.req = self.bus.get_object (CHANNEL_DISPATCHER, req_path)
+ self.req.connect_to_signal("Failed", self.req_failed)
+ self.req.connect_to_signal("Succeeded", self.req_succeeded)
+ self.req.Proceed(dbus_interface = CHANNEL_REQUEST)
+
+ def req_failed(self, error, message):
+ print "FAILURE: %s (%s)"% (error, message)
+
+ def req_succeeded(self):
+ pass
+
+class Account:
+ CALL_CLASS = {
+ CHANNEL_INTERFACE + '.ChannelType': CHANNEL_TYPE_CALL,
+ CHANNEL_INTERFACE + '.TargetHandleType': HANDLE_TYPE_CONTACT
+ }
+
+ def __init__(self, bus, path):
+ self.bus = bus
+ self.path = path
+ self.obj = bus.get_object (ACCOUNT_MANAGER, path)
+ self.properties = self.obj.GetAll (ACCOUNT,
+ dbus_interface=dbus.PROPERTIES_IFACE)
+
+ def get_path(self):
+ return self.path
+
+ def name(self):
+ return self.properties["DisplayName"]
+
+ def has_connection(self):
+ return self.properties["Connection"] != "/"
+
+ def get_contacts(self):
+ path = self.properties["Connection"]
+ if path == "/":
+ return []
+
+ conn = self.bus.get_object (path[1:].replace("/","."), path)
+ yours, channel, properties = conn.EnsureChannel (
+ { CHANNEL_INTERFACE + ".ChannelType": CHANNEL_TYPE_CONTACT_LIST,
+ CHANNEL_INTERFACE + ".TargetHandleType": HANDLE_TYPE_LIST,
+ CHANNEL_INTERFACE + ".TargetID": "subscribe"
+ },
+ dbus_interface = CONNECTION_INTERFACE_REQUESTS
+ )
+
+ subscribe = self.bus.get_object (conn.bus_name, channel)
+ members = subscribe.Get(CHANNEL_INTERFACE_GROUP, "Members",
+ dbus_interface = dbus.PROPERTIES_IFACE)
+
+ caps = conn.GetContactCapabilities (members,
+ dbus_interface = CONNECTION_INTERFACE_CONTACT_CAPABILITIES)
+ members = caps.keys()
+
+ for k, v in caps.iteritems():
+ for c in v:
+ if c[0][CHANNEL_TYPE] == CHANNEL_TYPE_CALL:
+ break
+ else:
+ members.remove (k)
+
+ attributes = conn.GetContactAttributes (
+ dbus.Array(members, signature="u"),
+ dbus.Array([], signature="s"),
+ True)
+
+ return map (lambda v: v[CONNECTION + "/contact-id"],
+ attributes.itervalues())
+
+ def supports_calls(self):
+ path = self.properties["Connection"]
+ if path == "/":
+ return False
+
+ conn = self.bus.get_object (path[1:].replace("/","."), path)
+ classes = conn.Get (CONNECTION_INTERFACE_REQUESTS,
+ 'RequestableChannelClasses', dbus_interface=dbus.PROPERTIES_IFACE)
+
+ return len ([c for c in classes if c[0] == self.CALL_CLASS]) > 0
+
+class UI(gtk.Window):
+ WIDTH=240
+ HEIGHT=-1
+ def __init__ (self, bus):
+ gtk.Window.__init__(self)
+ self.connect('destroy', lambda x: gtk.main_quit())
+ self.set_resizable(False)
+ self.set_size_request(self.WIDTH, self.HEIGHT)
+
+ vbox = gtk.VBox(False, 3)
+ self.add(vbox)
+
+ # call type combo box
+ self.type_store = gtk.ListStore (
+ gobject.TYPE_STRING,
+ gobject.TYPE_UINT)
+
+ self.type_store.append (("1-to-1", CONNECTION_HANDLE_TYPE_CONTACT))
+ self.type_store.append (("Conference",
+ CONNECTION_HANDLE_TYPE_ROOM))
+
+ self.type_combo = combobox = gtk.ComboBox (self.type_store)
+ vbox.pack_start(combobox, False)
+
+ renderer = gtk.CellRendererText()
+ combobox.pack_start(renderer, True)
+ combobox.set_attributes(renderer, text=0)
+ combobox.set_active (0)
+
+ # account combo box
+ self.store = gtk.ListStore (gobject.TYPE_STRING,
+ gobject.TYPE_BOOLEAN,
+ gobject.TYPE_PYOBJECT)
+ self.store.set_sort_func(0,
+ (lambda m, i0, i1:
+ { True: -1, False: 1}[m.get(i0, 0) < m.get(i1, 0)] ))
+ self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
+
+ f = self.store.filter_new()
+ f.set_visible_func(self.filter_visible)
+ self.account_combo = combobox = gtk.ComboBox(f)
+ vbox.pack_start(combobox, False)
+
+ renderer = gtk.CellRendererText()
+ combobox.pack_start(renderer, True)
+ combobox.set_attributes(renderer, text=0)
+ combobox.connect('changed', self.account_selected)
+
+ # contact entry box
+ self.contact_store = gtk.ListStore(gobject.TYPE_STRING)
+
+ completion = gtk.EntryCompletion ()
+ completion.set_model(self.contact_store)
+ completion.set_text_column(0)
+
+ self.contact_store.set_sort_func(0, self.contact_sort)
+ self.contact_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
+
+ self.contact_combo = combobox = gtk.ComboBoxEntry(self.contact_store)
+ combobox.get_child().set_completion(completion)
+
+ vbox.pack_start(combobox, False)
+
+ bbox = gtk.HButtonBox()
+ bbox.set_layout(gtk.BUTTONBOX_END)
+ vbox.pack_start(bbox, True, False, 3)
+
+ call = gtk.Button("Audio call")
+ call.connect("clicked", self.start_call)
+ bbox.add(call)
+
+ call = gtk.Button("Video call")
+ call.connect("clicked",
+ lambda button: self.start_call(button, video=True))
+ bbox.add(call)
+
+ self.show_all()
+
+ self.bus = bus
+ self.account_mgr = bus.get_object (ACCOUNT_MANAGER,
+ '/' + ACCOUNT_MANAGER.replace('.', '/'))
+ self.get_accounts()
+
+ def start_call(self, button, audio=True, video=False):
+ i = self.type_combo.get_active_iter()
+ (calltype, ) = self.type_combo.get_model().get(i, 1)
+
+ i = self.account_combo.get_active_iter()
+ (account, ) = self.account_combo.get_model().get(i, 2)
+
+ contact = self.contact_combo.get_active_text().strip()
+
+ print "* starting %s call" % ('video' if video else 'audio')
+ CallChannelRequest (self.bus, account.path, contact,
+ audio=audio, video=video, calltype=calltype)
+
+ def contact_sort (self, model, i0, i1):
+ if model.get(i0, 0)[0] < model.get(i1, 0)[0]:
+ return -1
+ else:
+ return 0
+
+ def filter_visible(self, model, titer):
+ return model.get(titer, 1)[0]
+
+ def account_selected (self, combobox):
+ iter = combobox.get_active_iter()
+ if iter == None:
+ return None
+
+ (account,) = combobox.get_model().get(iter, 2)
+
+ self.contact_store.clear()
+
+ map(lambda x: self.contact_store.insert (0, (x,)),
+ account.get_contacts())
+
+ def bail (self, *args):
+ print "BAILING"
+ print args
+ gtk.main_quit()
+
+ def got_accounts(self, accounts):
+ for x in accounts:
+ a = Account(self.bus, x)
+ if a.supports_calls():
+ self.store.insert(0, (a.name(), a.has_connection(), a))
+ self.account_combo.set_active(0)
+
+ def get_accounts (self):
+ self.account_mgr.Get(ACCOUNT_MANAGER, "ValidAccounts",
+ dbus_interface = dbus.PROPERTIES_IFACE,
+ reply_handler = self.got_accounts,
+ error_handler = self.bail)
+
+if __name__ == '__main__':
+ bus = dbus.SessionBus()
+
+ UI(bus)
+ gtk.main()