e9232081691d637425cee82260b28549c6451391
[theonering] / src / channel / call.py
1 import logging
2
3 import dbus
4 import gobject
5 import telepathy
6
7 import tp
8 import gtk_toolbox
9
10
11 _moduleLogger = logging.getLogger("channel.call")
12
13
14 class CallChannel(
15                 tp.ChannelTypeStreamedMedia,
16                 tp.ChannelInterfaceCallState,
17                 tp.ChannelInterfaceGroup,
18         ):
19         # @bug On Maemo 5 this is having some kind of "General" error, possibly due to an issue with "GetAll" DBusProperties stuff
20
21         def __init__(self, connection, manager, props, contactHandle):
22                 self.__manager = manager
23                 self.__props = props
24                 self.__cancelId = None
25
26                 if telepathy.interfaces.CHANNEL_INTERFACE + '.InitiatorHandle' in props:
27                         self._initiator = connection.get_handle_by_id(
28                                 telepathy.HANDLE_TYPE_CONTACT,
29                                 props[telepathy.interfaces.CHANNEL_INTERFACE + '.InitiatorHandle'],
30                         )
31                 elif telepathy.interfaces.CHANNEL_INTERFACE + '.InitiatorID' in props:
32                         self._initiator = connection.get_handle_by_name(
33                                 telepathy.HANDLE_TYPE_CONTACT,
34                                 props[telepathy.interfaces.CHANNEL_INTERFACE + '.InitiatorHandle'],
35                         )
36                 else:
37                         # Maemo 5 seems to require InitiatorHandle/InitiatorID to be set
38                         # even though I can't find them in the dbus spec.  I think its
39                         # generally safe to assume that its locally initiated if not
40                         # specified.  Specially for The One Ring, its always locally
41                         # initiated
42                         _moduleLogger.warning('InitiatorID or InitiatorHandle not set on new channel, assuming locally initiated')
43                         self._initiator = connection.GetSelfHandle()
44
45                 tp.ChannelTypeStreamedMedia.__init__(self, connection, manager, props)
46                 tp.ChannelInterfaceCallState.__init__(self)
47                 tp.ChannelInterfaceGroup.__init__(self)
48                 self.__contactHandle = contactHandle
49                 self._implement_property_get(
50                         telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA,
51                         {
52                                 "InitialAudio": self.initial_audio,
53                                 "InitialVideo": self.initial_video,
54                         },
55                 )
56                 self._implement_property_get(
57                         telepathy.interfaces.CHANNEL_INTERFACE,
58                         {
59                                 'InitiatorHandle': lambda: dbus.UInt32(self._initiator.id),
60                                 'InitiatorID': lambda: self._initiator.name,
61                         },
62                 )
63
64                 self.GroupFlagsChanged(0, 0)
65                 self.MembersChanged(
66                         '', [self._conn.GetSelfHandle()], [], [], [contactHandle],
67                         0, telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE
68                 )
69
70         def initial_audio(self):
71                 return False
72
73         def initial_video(self):
74                 return False
75
76         @gtk_toolbox.log_exception(_moduleLogger)
77         def Close(self):
78                 self.close()
79
80         def close(self):
81                 _moduleLogger.debug("Closing call")
82                 tp.ChannelTypeStreamedMedia.Close(self)
83                 self.remove_from_connection()
84                 if self.__cancelId is not None:
85                         gobject.source_remove(self.__cancelId)
86                         self.__cancelId = None
87
88         @gtk_toolbox.log_exception(_moduleLogger)
89         def GetLocalPendingMembersWithInfo(self):
90                 return []
91
92         @gtk_toolbox.log_exception(_moduleLogger)
93         def ListStreams(self):
94                 """
95                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
96                 """
97                 return ()
98
99         @gtk_toolbox.log_exception(_moduleLogger)
100         def RemoveStreams(self, streams):
101                 """
102                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
103                 """
104                 raise telepathy.errors.NotImplemented("Cannot remove a stream")
105
106         @gtk_toolbox.log_exception(_moduleLogger)
107         def RequestStreamDirection(self, stream, streamDirection):
108                 """
109                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
110
111                 @note Since streams are short lived, not bothering to implement this
112                 """
113                 _moduleLogger.info("A request was made to change the stream direction")
114                 raise telepathy.errors.NotImplemented("Cannot change directions")
115
116         @gtk_toolbox.log_exception(_moduleLogger)
117         def RequestStreams(self, contactId, streamTypes):
118                 """
119                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
120
121                 @returns [(Stream ID, contact, stream type, stream state, stream direction, pending send flags)]
122                 """
123                 contact = self._conn.get_handle_by_id(telepathy.constants.HANDLE_TYPE_CONTACT, contactId)
124                 assert self.__contactHandle == contact, "%r != %r" % (self.__contactHandle, contact)
125                 contactNumber = contact.phoneNumber
126
127                 self.CallStateChanged(self.__contactHandle, telepathy.constants.CHANNEL_CALL_STATE_RINGING)
128                 self.__cancelId = gobject.idle_add(self._on_cancel)
129                 self._conn.session.backend.call(contactNumber)
130
131                 streamId = 0
132                 streamState = telepathy.constants.MEDIA_STREAM_STATE_DISCONNECTED
133                 streamDirection = telepathy.constants.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL
134                 pendingSendFlags = telepathy.constants.MEDIA_STREAM_PENDING_REMOTE_SEND
135                 return [(streamId, contact, streamTypes[0], streamState, streamDirection, pendingSendFlags)]
136
137         @gtk_toolbox.log_exception(_moduleLogger)
138         def GetCallStates(self):
139                 """
140                 For org.freedesktop.Telepathy.Channel.Interface.CallState
141
142                 Get the current call states for all contacts involved in this call. 
143                 @returns {Contact: telepathy.constants.CHANNEL_CALL_STATE_*}
144                 """
145                 return {self.__contactHandle: telepathy.constants.CHANNEL_CALL_STATE_FORWARDED}
146
147         @gtk_toolbox.log_exception(_moduleLogger)
148         def _on_cancel(self, *args):
149                 self.CallStateChanged(self.__contactHandle, telepathy.constants.CHANNEL_CALL_STATE_FORWARDED)
150                 self.close()
151                 self.__cancelId = None
152                 return False