Making sure we close the stream after the call
[theonering] / src / channel / call.py
1 import logging
2
3 import gobject
4 import telepathy
5
6 import gtk_toolbox
7 import handle
8
9
10 _moduleLogger = logging.getLogger("channel.call")
11
12
13 class CallChannel(
14                 telepathy.server.ChannelTypeStreamedMedia,
15                 telepathy.server.ChannelInterfaceCallState,
16                 telepathy.server.ChannelInterfaceGroup,
17         ):
18
19         def __init__(self, connection, manager, props, contactHandle):
20                 self.__manager = manager
21                 self.__props = props
22                 self.__cancelId = None
23
24                 try:
25                         # HACK Older python-telepathy way
26                         telepathy.server.ChannelTypeStreamedMedia.__init__(self, connection, contactHandle)
27                         self._requested = props[telepathy.interfaces.CHANNEL_INTERFACE + '.Requested']
28                         self._implement_property_get(
29                                 telepathy.interfaces.CHANNEL_INTERFACE,
30                                 {"Requested": lambda: self._requested}
31                         )
32                 except TypeError:
33                         # HACK Newer python-telepathy way
34                         telepathy.server.ChannelTypeStreamedMedia.__init__(self, connection, manager, props)
35                 telepathy.server.ChannelInterfaceCallState.__init__(self)
36                 telepathy.server.ChannelInterfaceGroup.__init__(self)
37                 self.__contactHandle = contactHandle
38                 self._implement_property_get(
39                         telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA,
40                         {
41                                 "InitialAudio": self.initial_audio,
42                                 "InitialVideo": self.initial_video,
43                         },
44                 )
45
46                 # HACK Older python-telepathy doesn't provide this
47                 self._immutable_properties = {
48                         'ChannelType': telepathy.server.interfaces.CHANNEL_INTERFACE,
49                         'TargetHandle': telepathy.server.interfaces.CHANNEL_INTERFACE,
50                         'Interfaces': telepathy.server.interfaces.CHANNEL_INTERFACE,
51                         'TargetHandleType': telepathy.server.interfaces.CHANNEL_INTERFACE,
52                         'TargetID': telepathy.server.interfaces.CHANNEL_INTERFACE,
53                         'Requested': telepathy.server.interfaces.CHANNEL_INTERFACE
54                 }
55
56                 self.GroupFlagsChanged(0, 0)
57                 self.MembersChanged(
58                         '', [self._conn.GetSelfHandle()], [], [], [contactHandle],
59                         0, telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE
60                 )
61
62         def initial_audio(self):
63                 return False
64
65         def initial_video(self):
66                 return False
67
68         def get_props(self):
69                 # HACK Older python-telepathy doesn't provide this
70                 props = dict()
71                 for prop, iface in self._immutable_properties.items():
72                         props[iface + '.' + prop] = \
73                                 self._prop_getters[iface][prop]()
74                 return props
75
76         @gtk_toolbox.log_exception(_moduleLogger)
77         def Close(self):
78                 self.close()
79
80         def close(self):
81                 telepathy.server.ChannelTypeStreamedMedia.Close(self)
82                 if self.__manager.channel_exists(self.__props):
83                         # HACK Older python-telepathy requires doing this manually
84                         self.__manager.remove_channel(self)
85                 self.remove_from_connection()
86                 if self.__cancelId is not None:
87                         gobject.source_remove(self.__cancelId)
88                         self.__cancelId = None
89
90         @gtk_toolbox.log_exception(_moduleLogger)
91         def ListStreams(self):
92                 """
93                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
94                 """
95                 return ()
96
97         @gtk_toolbox.log_exception(_moduleLogger)
98         def RemoveStreams(self, streams):
99                 """
100                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
101                 """
102                 raise telepathy.errors.NotImplemented("Cannot remove a stream")
103
104         @gtk_toolbox.log_exception(_moduleLogger)
105         def RequestStreamDirection(self, stream, streamDirection):
106                 """
107                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
108
109                 @note Since streams are short lived, not bothering to implement this
110                 """
111                 _moduleLogger.info("A request was made to change the stream direction")
112                 raise telepathy.errors.NotImplemented("Cannot change directions")
113
114         @gtk_toolbox.log_exception(_moduleLogger)
115         def RequestStreams(self, contactId, streamTypes):
116                 """
117                 For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
118
119                 @returns [(Stream ID, contact, stream type, stream state, stream direction, pending send flags)]
120                 """
121                 contact = self._conn.handle(telepathy.constants.HANDLE_TYPE_CONTACT, contactId)
122                 assert self.__contactHandle == contact, "%r != %r" % (self.__contactHandle, contact)
123                 contactId, contactNumber = handle.ContactHandle.from_handle_name(contact.name)
124
125                 self.CallStateChanged(self.__contactHandle, telepathy.constants.CHANNEL_CALL_STATE_RINGING)
126                 self.__cancelId = gobject.idle_add(self._on_cancel)
127                 self._conn.session.backend.call(contactNumber)
128
129                 streamId = 0
130                 streamState = telepathy.constants.MEDIA_STREAM_STATE_DISCONNECTED
131                 streamDirection = telepathy.constants.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL
132                 pendingSendFlags = telepathy.constants.MEDIA_STREAM_PENDING_REMOTE_SEND
133                 return [(streamId, contact, streamTypes[0], streamState, streamDirection, pendingSendFlags)]
134
135         @gtk_toolbox.log_exception(_moduleLogger)
136         def GetCallStates(self):
137                 """
138                 For org.freedesktop.Telepathy.Channel.Interface.CallState
139
140                 Get the current call states for all contacts involved in this call. 
141                 @returns {Contact: telepathy.constants.CHANNEL_CALL_STATE_*}
142                 """
143                 return {self.__contactHandle: telepathy.constants.CHANNEL_CALL_STATE_FORWARDED}
144
145         @gtk_toolbox.log_exception(_moduleLogger)
146         def _on_cancel(self, *args):
147                 self.CallStateChanged(self.__contactHandle, telepathy.constants.CHANNEL_CALL_STATE_FORWARDED)
148                 self.close()
149                 self.__cancelId = None
150                 return False