LinphoneCallbacks.call_state_changed_handle()   F
last analyzed

Complexity

Conditions 29

Size

Total Lines 96

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
dl 0
loc 96
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like LinphoneCallbacks.call_state_changed_handle() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
import logging
5
logger = logging.getLogger(__name__)
6
logger.debug("%s loaded", __name__)
7
8
from time import sleep
0 ignored issues
show
Unused Code introduced by Thomas
Unused sleep imported from time
Loading history...
9
import linphone
10
from doorpi import DoorPi
11
12
class LinphoneCallbacks:
13
14
    @property
15
    def used_callbacks(self): return {
16
        #http://www.linphone.org/docs/liblinphone/struct__LinphoneCoreVTable.html
17
        #'global_state_changed': self.global_state_changed, #Notifies global state changes
18
        #'registration_state_changed': self.registration_state_changed, #Notifies registration state changes
19
        'call_state_changed': self.call_state_changed, #Notifies call state changes
20
        #'notify_presence_received': self.notify_presence_received, #Notify received presence events
21
        #'new_subscription_requested': self.new_subscription_requested, #Notify about pending presence subscription request
22
        #'auth_info_requested': self.auth_info_requested, #Ask the application some authentication information
23
        #'call_log_updated': self.call_log_updated, #Notifies that call log list has been updated
24
        #'message_received': self.message_received, #a message is received, can be text or external body
25
        #'is_composing_received': self.is_composing_received, #An is-composing notification has been received
26
        'dtmf_received': self.dtmf_received, #A dtmf has been received received
27
        #'refer_received': self.refer_received, #An out of call refer was received
28
        #'call_encryption_changed': self.call_encryption_changed, #Notifies on change in the encryption of call streams
29
        #'transfer_state_changed': self.transfer_state_changed, #Notifies when a transfer is in progress
30
        #'buddy_info_updated': self.buddy_info_updated, #a LinphoneFriend's BuddyInfo has changed
31
        #'call_stats_updated': self.call_stats_updated, #Notifies on refreshing of call's statistics.
32
        #'info_received': self.info_received, #Notifies an incoming informational message received.
33
        #'subscription_state_changed': self.subscription_state_changed, #Notifies subscription state change
34
        #'notify_received': self.notify_received, #Notifies a an event notification, see linphone_core_subscribe()
35
        #'configuring_status': self.configuring_status, #Notifies publish state change (only from LinphoneEvent api)
36
        #'network_reachable': self.network_reachable, #Callback to report IP network status (I.E up/down )
37
        #'log_collection_upload_state_changed': self.log_collection_upload_state_changed, #Callback to upload collected logs
38
        #'log_collection_upload_progress_indication': self.log_collection_upload_progress_indication #Callback to indicate log collection upload progress
39
    }
40
41
    @property
42
    def whitelist(self): return DoorPi().config.get_keys('AdminNumbers')
43
44
    def is_admin_number(self, remote_uri):
45
        logger.debug("is_admin_number (%s)",remote_uri)
46
        for admin_number in self.whitelist:
47
            if admin_number == "*":
48
                logger.info("admin numbers are deactivated by using '*' as single number")
49
                return True
50
            if "sip:"+admin_number+"@" in remote_uri:
51
                logger.debug("%s is adminnumber %s", remote_uri, admin_number)
52
                return True
53
            if "sip:"+admin_number is remote_uri:
54
                logger.debug("%s is adminnumber %s", remote_uri, admin_number)
55
                return True
56
        logger.debug("%s is not an adminnumber", remote_uri)
57
        return False
58
59
    __DTMF = ''
60
    __possible_DTMF = []
61
62
    def __init__(self):
63
        logger.debug("__init__")
64
65
        self._last_number_of_calls = 0
66
67
        DoorPi().event_handler.register_action('OnSipPhoneDestroy', self.destroy)
68
69
        DoorPi().event_handler.register_event('OnCallMediaStateChange', __name__)
70
        DoorPi().event_handler.register_event('OnMediaRequired', __name__)
71
        DoorPi().event_handler.register_event('OnMediaNotRequired', __name__)
72
73
        DoorPi().event_handler.register_event('OnCallStateChange', __name__)
74
        DoorPi().event_handler.register_event('OnCallStateConnect', __name__)
75
        DoorPi().event_handler.register_event('AfterCallStateConnect', __name__)
76
        DoorPi().event_handler.register_event('OnCallStateDisconnect', __name__)
77
        DoorPi().event_handler.register_event('AfterCallStateDisconnect', __name__)
78
        DoorPi().event_handler.register_event('OnCallStateDismissed', __name__)
79
        DoorPi().event_handler.register_event('OnCallStateReject', __name__)
80
        DoorPi().event_handler.register_event('OnCallStart', __name__)
81
        DoorPi().event_handler.register_event('OnDTMF', __name__)
82
83
        self.__possible_DTMF = DoorPi().config.get_keys('DTMF')
84
        for DTMF in self.__possible_DTMF:
85
            DoorPi().event_handler.register_event('OnDTMF_'+DTMF, __name__)
86
87
        DoorPi().event_handler.register_event('OnCallStart', __name__)
88
        DoorPi().event_handler.register_event('BeforeCallIncoming', __name__)
89
        DoorPi().event_handler.register_event('OnCallReconnect', __name__)
90
        DoorPi().event_handler.register_event('AfterCallReconnect', __name__)
91
        DoorPi().event_handler.register_event('OnCallBusy', __name__)
92
        DoorPi().event_handler.register_event('AfterCallBusy', __name__)
93
        DoorPi().event_handler.register_event('OnCallIncoming', __name__)
94
        DoorPi().event_handler.register_event('AfterCallIncoming', __name__)
95
        DoorPi().event_handler.register_event('OnCallReject', __name__)
96
        DoorPi().event_handler.register_event('AfterCallReject', __name__)
97
        #DoorPi().event_handler.register_event('AfterAccountRegState', __name__)
98
99
        DoorPi().event_handler('OnCallStart', __name__)
100
101
    def destroy(self):
102
        logger.debug("destroy")
103
        DoorPi().event_handler.unregister_source(__name__, True)
104
105
    def global_state_changed(self, core, global_state, message): pass
106
    def registration_state_changed(self, core, linphone_proxy_config, state, message): pass
107
    def call_state_changed(self, core, call, call_state, message):
108
        self.call_state_changed_handle(core, call, call_state, message)
109
110
        if core.calls_nb > 0 and self._last_number_of_calls == 0:
111
            DoorPi().event_handler('OnMediaRequired', __name__)
112
        elif self._last_number_of_calls is not core.calls_nb:
113
            DoorPi().event_handler('OnMediaNotRequired', __name__)
114
        self._last_number_of_calls = core.calls_nb
115
116
    def call_state_changed_handle(self, core, call, call_state, message):
117
        logger.debug("call_state_changed (%s - %s)", call_state, message)
118
119
        remote_uri = call.remote_address.as_string_uri_only()
120
121
        DoorPi().event_handler('OnCallStateChange', __name__, {
122
            'remote_uri': remote_uri,
123
            'call_state': call_state,
124
            'state': message
125
        })
126
127
        if call_state == linphone.CallState.Idle:
128
            pass
129
        elif call_state == linphone.CallState.IncomingReceived:
130
            DoorPi().event_handler('BeforeCallIncoming', __name__, {'remote_uri': remote_uri})
131
            if core.current_call and core.current_call.state > linphone.CallState.IncomingReceived:
132
                logger.debug("Incoming call while another call is active")
133
                logger.debug("- incoming.remote_uri: %s", call)
134
                logger.debug("- current.remote_uri : %s", core.current_call)
135
136
                if core.current_call.remote_address.as_string_uri_only() == remote_uri:
137
                    logger.info("Current call is incoming call - quitting current and connecting to incoming. Maybe connection reset?")
138
                    DoorPi().event_handler('OnCallReconnect', __name__, {'remote_uri': remote_uri})
139
                    core.terminate_call(core.current_call)
140
                    DoorPi().sipphone.reset_call_start_datetime()
141
                    core.accept_call_with_params(call, DoorPi().sipphone.base_config)
142
                    DoorPi().event_handler('AfterCallReconnect', __name__)
143
                    return
144
                else:
145
                    if self.is_admin_number(remote_uri):
146
                        logger.info("Incoming and current call are different - incoming is AdminNumber, so hanging up current call")
147
                        DoorPi().event_handler('OnCallIncoming', __name__, {'remote_uri': remote_uri})
148
                        core.terminate_call(core.current_call)
149
                        DoorPi().sipphone.reset_call_start_datetime()
150
                        core.accept_call_with_params(call, DoorPi().sipphone.base_config)
151
                        DoorPi().event_handler('AfterCallIncoming', __name__, {'remote_uri': remote_uri})
152
                        return
153
                    else:
154
                        logger.info("Incoming and current call are different - sending busy signal to incoming call")
155
                        DoorPi().event_handler('OnCallBusy', __name__, {'remote_uri': remote_uri})
156
                        core.decline_call(call, linphone.Reason.Busy)
157
                        DoorPi().event_handler('AfterCallBusy', __name__)
158
                        return
159
            if self.is_admin_number(remote_uri):
160
                DoorPi().event_handler('OnCallIncoming', __name__, {'remote_uri': remote_uri})
161
                DoorPi().sipphone.reset_call_start_datetime()
162
                core.accept_call_with_params(call, DoorPi().sipphone.base_config)
163
                DoorPi().event_handler('AfterCallIncoming', __name__, {'remote_uri': remote_uri})
164
                return
165
            else:
166
                DoorPi().event_handler('OnCallReject', __name__)
167
                core.decline_call(call, linphone.Reason.Forbidden) #Declined
168
                DoorPi().event_handler('AfterCallReject', __name__)
169
                return
170
        elif call_state == linphone.CallState.OutgoingInit:
171
            pass
172
        elif call_state == linphone.CallState.OutgoingProgress:
173
            pass
174
        elif call_state == linphone.CallState.OutgoingRinging:
175
            pass
176
        elif call_state == linphone.CallState.OutgoingEarlyMedia:
177
            DoorPi().event_handler('OnCallMediaStateChange', __name__)
178
        elif call_state == linphone.CallState.Connected:
179
            DoorPi().event_handler('OnCallStateConnect', __name__)
180
        elif call_state == linphone.CallState.StreamsRunning:
181
            DoorPi().event_handler('AfterCallStateConnect', __name__)
182
            DoorPi().event_handler('OnCallMediaStateChange', __name__)
183
        elif call_state == linphone.CallState.Pausing:
184
            pass
185
        elif call_state == linphone.CallState.Paused:
186
            DoorPi().event_handler('OnCallMediaStateChange', __name__)
187
        elif call_state == linphone.CallState.Resuming:
188
            DoorPi().event_handler('OnCallStateConnect', __name__)
189
            DoorPi().event_handler('OnCallMediaStateChange', __name__)
190
        elif call_state == linphone.CallState.Refered:
191
            pass
192
        elif call_state == linphone.CallState.Error:
193
            if message == "Busy here": DoorPi().event_handler('OnCallStateDismissed', __name__)
194
        elif call_state == linphone.CallState.End:
195
            if message == "Call declined.": DoorPi().event_handler('OnCallStateReject', __name__)
196
            DoorPi().event_handler('OnCallStateDisconnect', __name__)
197
        elif call_state == linphone.CallState.PausedByRemote:
198
            pass
199
        elif call_state == linphone.CallState.UpdatedByRemote:
200
            pass
201
        elif call_state == linphone.CallState.IncomingEarlyMedia:
202
            DoorPi().event_handler('OnCallMediaStateChange', __name__)
203
        elif call_state == linphone.CallState.Updating:
204
            DoorPi().event_handler('OnCallStateConnect', __name__)
205
            DoorPi().event_handler('OnCallMediaStateChange', __name__)
206
        elif call_state == linphone.CallState.Released:
207
            pass
208
        elif call_state == linphone.CallState.EarlyUpdatedByRemote:
209
            pass
210
        elif call_state == linphone.CallState.EarlyUpdating:
211
            pass
212
    def notify_presence_received(self, core, linphone_friend): pass
213
    def new_subscription_requested(self, core, linphone_friend, url): pass
214
    def auth_info_requested(self, core, realm, username): pass
215
    def call_log_updated(self, core, new_call_log_entry): pass
216
    def message_received(self, core, linphone_chat_room, message): pass
217
    def is_composing_received(self, core, linphone_chat_room): pass
218
    def dtmf_received(self, core, call, digits):
0 ignored issues
show
Unused Code introduced by Thomas
The argument core seems to be unused.
Loading history...
219
        logger.debug("on_dtmf_digit (%s)", str(digits))
220
        digits = chr(digits)
221
        DoorPi().event_handler('OnDTMF', __name__, {'digits':digits})
222
        self.__DTMF += str(digits)
223
        for DTMF in self.__possible_DTMF:
224
            if self.__DTMF.endswith(DTMF[1:-1]):
225
                DoorPi().event_handler('OnDTMF_'+DTMF+'', __name__, {
226
                    'remote_uri': str(call.remote_address.as_string_uri_only()),
227
                    'DTMF': str(self.__DTMF)
228
                })
229
    def refer_received(self, core, refer_to): pass
230
    def call_encryption_changed(self, core, call, on, authentication_token): pass
231
    def transfer_state_changed(self, core, call, transfer_state): pass
232
    def buddy_info_updated(self, core, linphone_friend): pass
233
    def call_stats_updated(self, core, call, stats): pass
234
    def info_received(self, core, call, message): pass
235
    def subscription_state_changed(self, core, linphone_event, linphone_subscription_state): pass
236
    def notify_received(self, core, linphone_event, linphone_subscription_state, linphone_body): pass
237
    def configuring_status(self, core, linphone_configuring_state, message): pass
238
    def network_reachable(self, core, reachable): pass
239
    def log_collection_upload_state_changed(self, core, linphone_core_log_collection_upload_state, info): pass
240
    def log_collection_upload_progress_indication(self, core, offset, total): pass
241
242
    __del__ = destroy