From 97f6dcc6bd59b94e9657532f6a5314a895d4bb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?W=C3=BCstengecko?= <1579756+Wuestengecko@users.noreply.github.com> Date: Fri, 8 Mar 2019 21:07:56 +0100 Subject: [PATCH] Remove linphone support With the linphone project being abandoned, there being no functional python3 bindings, and the python2 bindings already causing problems all over the place (see for example #182 and #184), there is no reason to keep the linphone support code. --- doorpi/sipphone/from_linphone.py | 354 ------------------ doorpi/sipphone/linphone_lib/CallBacks.py | 242 ------------ doorpi/sipphone/linphone_lib/Player.py | 56 --- doorpi/sipphone/linphone_lib/Recorder.py | 79 ---- doorpi/sipphone/linphone_lib/__init__.py | 2 - .../status/requirements_lib/req_sipphone.py | 75 +--- 6 files changed, 5 insertions(+), 803 deletions(-) delete mode 100644 doorpi/sipphone/from_linphone.py delete mode 100644 doorpi/sipphone/linphone_lib/CallBacks.py delete mode 100644 doorpi/sipphone/linphone_lib/Player.py delete mode 100644 doorpi/sipphone/linphone_lib/Recorder.py delete mode 100644 doorpi/sipphone/linphone_lib/__init__.py diff --git a/doorpi/sipphone/from_linphone.py b/doorpi/sipphone/from_linphone.py deleted file mode 100644 index cdb1f5f2..00000000 --- a/doorpi/sipphone/from_linphone.py +++ /dev/null @@ -1,354 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import logging -logger = logging.getLogger(__name__) -logger.debug("%s loaded", __name__) - -import datetime - -from .AbstractBaseClass import SipphoneAbstractBaseClass, SIPPHONE_SECTION -import linphone as lin - -from doorpi import DoorPi -from doorpi.sipphone.linphone_lib.CallBacks import LinphoneCallbacks -from doorpi.sipphone.linphone_lib.Player import LinphonePlayer -from doorpi.sipphone.linphone_lib.Recorder import LinphoneRecorder -from doorpi.media.CreateDialTone import generate_dial_tone - -conf = DoorPi().config - -def log_handler(level, msg): - if "pylinphone_Core_instance_method_iterate" in msg: return - if "pylinphone_Core_get_current_call" in msg: return - if "pylinphone_Call_from_native_ptr" in msg: return - if ": keep alive sent to [" in msg: return - method = getattr(logger, level) - method(msg) - -if logger.getEffectiveLevel() <= 5: lin.set_log_handler(log_handler) - -def get(*args, **kwargs): return LinPhone(*args, **kwargs) -class LinPhone(SipphoneAbstractBaseClass): - - @property - def name(self): return 'linphone wrapper' - - @property - def lib(self): return self.__Lib - @property - def core(self): return self.__Lib - - @property - def recorder(self): return self.__recorder - __recorder = None - - @property - def player(self): return self.__player - __player = None - - @property - def current_call(self): return self.core.current_call - - @property - def video_devices(self): - try: - all_devices = [] - for video_device in self.core.video_devices: - all_devices.append({ - 'name': video_device - }) - return all_devices - except Exception: - return [] - - @property - def sound_devices(self): - try: - all_devices = [] - for sound_device in self.core.sound_devices: - all_devices.append({ - 'name': sound_device, - 'capture': self.core.sound_device_can_capture(sound_device), - 'record': self.core.sound_device_can_playback(sound_device) - }) - return all_devices - except Exception as exp: - logger.exception(exp) - return [] - - def _create_payload_enum(self, payloads): - - try: - all_codecs = [] - for codec in payloads: - all_codecs.append({ - 'name': codec.mime_type, - 'channels': codec.channels, - 'bitrate': codec.normal_bitrate, - 'enable': self.core.payload_type_enabled(codec) - }) - return all_codecs - except Exception as exp: - logger.exception(exp) - return [] - - @property - def video_codecs(self): - return self._create_payload_enum(self.core.video_codecs) - - @property - def sound_codecs(self): - return self._create_payload_enum(self.core.audio_codecs) - - @property - def current_call_duration(self): - if not self.current_call: return 0 - diff_start_and_now = datetime.datetime.utcnow() - self.__current_call_start_datetime - return diff_start_and_now.total_seconds() - - @property - def current_call_dump(self): - try: - return { - 'direction': 'incoming' if self.current_call.dir == 0 else 'outgoing', - 'remote_uri': self.current_call.remote_address_as_string, - 'total_time': self.current_call_duration, - 'level_incoming': self.current_call.record_volume, - 'level_outgoing': self.current_call.play_volume, - 'camera': self.current_call.camera_enabled - } - except Exception: - return {} - - #TODO: Datetime from linphone CallLog.start_date is more then 30 sec different to python datetime.utcnow()? - __current_call_start_datetime = datetime.datetime.utcnow() - - @property - def base_config(self): - params = self.core.create_call_params(None) - params.record_file = self.recorder.reset_last_record_filename() - params.video_enabled = True - return params - - def reset_call_start_datetime(self): - self.__current_call_start_datetime = datetime.datetime.utcnow() - logger.debug('reset current call start datetime to %s', self.__current_call_start_datetime) - return self.__current_call_start_datetime - - def __init__(self, whitelist = list(), *args, **kwargs): - logger.debug("__init__") - - DoorPi().event_handler.register_action('OnShutdown', self.destroy) - - DoorPi().event_handler.register_event('OnSipPhoneCreate', __name__) - DoorPi().event_handler.register_event('OnSipPhoneStart', __name__) - DoorPi().event_handler.register_event('OnSipPhoneDestroy', __name__) - - DoorPi().event_handler.register_event('OnSipPhoneRecorderCreate', __name__) - DoorPi().event_handler.register_event('OnSipPhoneRecorderDestroy', __name__) - - DoorPi().event_handler.register_event('BeforeSipPhoneMakeCall', __name__) - DoorPi().event_handler.register_event('OnSipPhoneMakeCall', __name__) - DoorPi().event_handler.register_event('OnSipPhoneMakeCallFailed', __name__) - DoorPi().event_handler.register_event('AfterSipPhoneMakeCall', __name__) - - DoorPi().event_handler.register_event('OnSipPhoneCallTimeoutNoResponse', __name__) - DoorPi().event_handler.register_event('OnSipPhoneCallTimeoutMaxCalltime', __name__) - - DoorPi().event_handler.register_event('OnPlayerCreated', __name__) - - #http://pythonhosted.org/linphone/api_reference.html#linphone.Core.new - self.callback = LinphoneCallbacks() - config_path = None - factory_config_path = None - self.__Lib = lin.Core.new( - self.callback.used_callbacks, - config_path, - factory_config_path - ) - self.core.primary_contact = '%s '%conf.get(SIPPHONE_SECTION, "identity", 'DoorPi') - - def start(self): - DoorPi().event_handler('OnSipPhoneCreate', __name__) - self.core.max_calls = conf.get_int(SIPPHONE_SECTION, 'ua.max_calls', 2) - self.core.echo_cancellation_enabled = conf.get_bool(SIPPHONE_SECTION, 'echo_cancellation_enabled', False) - - # set local listen ports, default: random - self.core.sip_transports = lin.SipTransports(conf.get_int(SIPPHONE_SECTION, 'local_port', 5060), conf.get_int(SIPPHONE_SECTION, 'local_port', 5060), -1, -1) - - self.core.video_display_enabled = conf.get_bool(SIPPHONE_SECTION, 'video_display_enabled', False) - self.core.stun_server = conf.get(SIPPHONE_SECTION, 'stun_server', '') - firewall_policy = conf.get(SIPPHONE_SECTION, 'FirewallPolicy', 'PolicyNoFirewall') - if firewall_policy == "PolicyNoFirewall": self.core.firewall_policy = lin.FirewallPolicy.PolicyNoFirewall - elif firewall_policy == "PolicyUseNatAddress": self.core.firewall_policy = lin.FirewallPolicy.PolicyUseNatAddress - elif firewall_policy == "PolicyUseStun": self.core.firewall_policy = lin.FirewallPolicy.PolicyUseStun - elif firewall_policy == "PolicyUseIce": self.core.firewall_policy = lin.FirewallPolicy.PolicyUseIce - elif firewall_policy == "PolicyUseUpnp": self.core.firewall_policy = lin.FirewallPolicy.PolicyUseUpnp - else: self.core.firewall_policy = lin.FirewallPolicy.PolicyNoFirewall - - #http://pythonhosted.org/linphone/api_reference.html#linphone.Core.in_call_timeout - #After this timeout period, the call is automatically hangup. - self.core.in_call_timeout = conf.get_int(SIPPHONE_SECTION, 'max_call_time', 120) - #http://pythonhosted.org/linphone/api_reference.html#linphone.Core.inc_timeout - #If an incoming call isn’t answered for this timeout period, it is automatically declined. - self.core.inc_timeout = conf.get_int(SIPPHONE_SECTION, 'call_timeout', 15) - - self.__player = LinphonePlayer() - self.core.ringback = self.player.player_filename - self.__recorder = LinphoneRecorder() - - if len(self.core.sound_devices) == 0: - logger.warning('no audio devices available') - else: - self.core.capture_device = conf.get(SIPPHONE_SECTION, 'capture_device', self.core.capture_device) - self.core.playback_device = conf.get(SIPPHONE_SECTION, 'playback_device', self.core.playback_device) - self.core.mic_gain_db = conf.get_float(SIPPHONE_SECTION, 'mic_gain_db', 0) - logger.info("found %s possible sounddevices:", len(self.core.sound_devices)) - logger.debug("|rec|play| name") - logger.debug("------------------------------------") - for sound_device in self.core.sound_devices: - logger.debug("| %s | %s | %s", - 'X' if self.core.sound_device_can_capture(sound_device) else 'O', - 'X' if self.core.sound_device_can_playback(sound_device) else 'O', - sound_device - ) - logger.debug("------------------------------------") - logger.debug("using capture_device: %s", self.core.capture_device) - logger.debug("using playback_device: %s", self.core.playback_device) - logger.debug("mic_gain_db: %s", self.core.mic_gain_db) - - # Only enable PCMU and PCMA audio codecs by default - config_audio_codecs = conf.get_list(SIPPHONE_SECTION, 'audio_codecs', 'PCMA,PCMU') - for codec in self.core.audio_codecs: - if codec.mime_type in config_audio_codecs: - logger.debug('enable audio codec %s', codec.mime_type) - self.core.enable_payload_type(codec, True) - else: - logger.debug('disable audio codec %s', codec.mime_type) - self.core.enable_payload_type(codec, False) - - - if len(self.core.video_devices) == 0: - self.core.video_capture_enabled = False - logger.warning('no video devices available') - else: - logger.info("found %s possible videodevices:", len(self.core.video_devices)) - logger.debug("| name") - logger.debug("------------------------------------") - for video_device in self.core.video_devices: - logger.debug("| %s ", video_device) - logger.debug("------------------------------------") - config_camera = conf.get(SIPPHONE_SECTION, 'video_device', self.core.video_devices[0]) - if config_camera not in self.core.video_devices: - logger.warning('camera "%s" from config does not exist in possible video devices.', config_camera) - logger.debug('switching to first possible video device "%s"', self.core.video_devices[0]) - config_camera = self.core.video_devices[0] - - self.core.video_capture_enabled = True - self.core.video_device = config_camera - self.core.preferred_video_size_by_name = conf.get(SIPPHONE_SECTION, 'video_size', 'vga') - logger.debug("using video_device: %s", self.core.video_device) - - # Only enable VP8 video codec - config_video_codecs = conf.get_list(SIPPHONE_SECTION, 'video_codecs', 'VP8') - for codec in self.core.video_codecs: - if codec.mime_type in config_video_codecs and self.core.video_capture_enabled: - logger.debug('enable video codec %s', codec.mime_type) - self.core.enable_payload_type(codec, True) - else: - logger.debug('disable video codec %s', codec.mime_type) - self.core.enable_payload_type(codec, False) - - # Configure the SIP account - server = conf.get(SIPPHONE_SECTION, "sipserver_server") - username = conf.get(SIPPHONE_SECTION, "sipserver_username") - password = conf.get(SIPPHONE_SECTION, "sipserver_password", username) - realm = conf.get(SIPPHONE_SECTION, "sipserver_realm", server) - if server and username and password: - logger.info('using DoorPi with SIP-Server') - proxy_cfg = self.core.create_proxy_config() - proxy_cfg.identity_address = lin.Address.new("%s " % ( - conf.get(SIPPHONE_SECTION, "identity", 'DoorPi'), username, server) - ) - proxy_cfg.server_addr = "sip:%s"%server - proxy_cfg.register_enabled = True - self.core.add_proxy_config(proxy_cfg) - self.core.default_proxy_config = proxy_cfg - auth_info = self.core.create_auth_info(username, None, password, None, None, realm) - self.core.add_auth_info(auth_info) - else: - logger.info('using DoorPi without SIP-Server? Okay...') - proxy_cfg = self.core.create_proxy_config() - proxy_cfg.register_enabled = False - self.core.add_proxy_config(proxy_cfg) - self.core.default_proxy_config = proxy_cfg - logger.debug('%s',self.core.proxy_config_list) - - logger.debug("start successfully") - - def destroy(self): - logger.debug("destroy") - self.core.terminate_all_calls() - DoorPi().event_handler.fire_event_synchron('OnSipPhoneDestroy', __name__) - DoorPi().event_handler.unregister_source(__name__, True) - return - - def self_check(self, *args, **kwargs): - if not self.core: return - - self.core.iterate() - - if not self.current_call: return - - if self.current_call.state < lin.CallState.Connected: - if self.current_call_duration > self.core.inc_timeout - 0.5: - logger.info("call timeout - hangup current call after %s seconds (max. %s)", self.current_call_duration, self.core.inc_timeout) - self.core.terminate_all_calls() - DoorPi().event_handler('OnSipPhoneCallTimeoutNoResponse', __name__) - else: - if int(self.current_call_duration) > self.core.in_call_timeout - 0.5: - logger.info("max call time reached - hangup current call after %s seconds (max. %s)", self.current_call_duration, self.core.in_call_timeout) - self.core.terminate_all_calls() - DoorPi().event_handler('OnSipPhoneCallTimeoutMaxCalltime', __name__) - - def call(self, number): - DoorPi().event_handler('BeforeSipPhoneMakeCall', __name__, {'number':number}) - logger.debug("call (%s)",str(number)) - if not self.current_call: - logger.debug('no current call -> start new call') - self.reset_call_start_datetime() - if self.core.invite_with_params(number, self.base_config) is None: - if DoorPi().event_handler.db.get_event_log_entries_count('OnSipPhoneMakeCallFailed') > 5: - logger.error('failed to execute call five times') - else: - DoorPi().event_handler('OnSipPhoneMakeCallFailed', __name__, {'number':number}) - return None - DoorPi().event_handler('OnSipPhoneMakeCall', __name__, {'number':number}) - elif number in self.current_call.remote_address.as_string_uri_only(): - if self.current_call_duration <= 2: - logger.debug("same call %s again while call is running since %s seconds? -> skip", - self.core.current_call.remote_address.as_string_uri_only(), - self.current_call_duration - ) - else: - logger.debug("press twice with call duration > 1 second? Want to hangup current call? OK...") - self.core.terminate_all_calls() - else: - logger.debug("new call needed? hangup old first...") - self.core.terminate_all_calls() - self.call(number) - - DoorPi().event_handler('AfterSipPhoneMakeCall', __name__, {'number':number}) - return self.current_call - - def is_admin_number(self, remote_uri): - return self.callback.is_admin_number(remote_uri) - - def hangup(self): - if self.current_call: - logger.debug("Received hangup request, cancelling current call") - self.core.terminate_call(self.current_call) - else: - logger.debug("Ignoring hangup request as there is no ongoing call") - diff --git a/doorpi/sipphone/linphone_lib/CallBacks.py b/doorpi/sipphone/linphone_lib/CallBacks.py deleted file mode 100644 index 7aeba004..00000000 --- a/doorpi/sipphone/linphone_lib/CallBacks.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import logging -logger = logging.getLogger(__name__) -logger.debug("%s loaded", __name__) - -from time import sleep -import linphone -from doorpi import DoorPi - -class LinphoneCallbacks: - - @property - def used_callbacks(self): return { - #http://www.linphone.org/docs/liblinphone/struct__LinphoneCoreVTable.html - #'global_state_changed': self.global_state_changed, #Notifies global state changes - #'registration_state_changed': self.registration_state_changed, #Notifies registration state changes - 'call_state_changed': self.call_state_changed, #Notifies call state changes - #'notify_presence_received': self.notify_presence_received, #Notify received presence events - #'new_subscription_requested': self.new_subscription_requested, #Notify about pending presence subscription request - #'auth_info_requested': self.auth_info_requested, #Ask the application some authentication information - #'call_log_updated': self.call_log_updated, #Notifies that call log list has been updated - #'message_received': self.message_received, #a message is received, can be text or external body - #'is_composing_received': self.is_composing_received, #An is-composing notification has been received - 'dtmf_received': self.dtmf_received, #A dtmf has been received received - #'refer_received': self.refer_received, #An out of call refer was received - #'call_encryption_changed': self.call_encryption_changed, #Notifies on change in the encryption of call streams - #'transfer_state_changed': self.transfer_state_changed, #Notifies when a transfer is in progress - #'buddy_info_updated': self.buddy_info_updated, #a LinphoneFriend's BuddyInfo has changed - #'call_stats_updated': self.call_stats_updated, #Notifies on refreshing of call's statistics. - #'info_received': self.info_received, #Notifies an incoming informational message received. - #'subscription_state_changed': self.subscription_state_changed, #Notifies subscription state change - #'notify_received': self.notify_received, #Notifies a an event notification, see linphone_core_subscribe() - #'configuring_status': self.configuring_status, #Notifies publish state change (only from LinphoneEvent api) - #'network_reachable': self.network_reachable, #Callback to report IP network status (I.E up/down ) - #'log_collection_upload_state_changed': self.log_collection_upload_state_changed, #Callback to upload collected logs - #'log_collection_upload_progress_indication': self.log_collection_upload_progress_indication #Callback to indicate log collection upload progress - } - - @property - def whitelist(self): return DoorPi().config.get_keys('AdminNumbers') - - def is_admin_number(self, remote_uri): - logger.debug("is_admin_number (%s)",remote_uri) - for admin_number in self.whitelist: - if admin_number == "*": - logger.info("admin numbers are deactivated by using '*' as single number") - return True - if "sip:"+admin_number+"@" in remote_uri: - logger.debug("%s is adminnumber %s", remote_uri, admin_number) - return True - if "sip:"+admin_number is remote_uri: - logger.debug("%s is adminnumber %s", remote_uri, admin_number) - return True - logger.debug("%s is not an adminnumber", remote_uri) - return False - - __DTMF = '' - __possible_DTMF = [] - - def __init__(self): - logger.debug("__init__") - - self._last_number_of_calls = 0 - - DoorPi().event_handler.register_action('OnSipPhoneDestroy', self.destroy) - - DoorPi().event_handler.register_event('OnCallMediaStateChange', __name__) - DoorPi().event_handler.register_event('OnMediaRequired', __name__) - DoorPi().event_handler.register_event('OnMediaNotRequired', __name__) - - DoorPi().event_handler.register_event('OnCallStateChange', __name__) - DoorPi().event_handler.register_event('OnCallStateConnect', __name__) - DoorPi().event_handler.register_event('AfterCallStateConnect', __name__) - DoorPi().event_handler.register_event('OnCallStateDisconnect', __name__) - DoorPi().event_handler.register_event('AfterCallStateDisconnect', __name__) - DoorPi().event_handler.register_event('OnCallStateDismissed', __name__) - DoorPi().event_handler.register_event('OnCallStateReject', __name__) - DoorPi().event_handler.register_event('OnCallStart', __name__) - DoorPi().event_handler.register_event('OnDTMF', __name__) - - self.__possible_DTMF = DoorPi().config.get_keys('DTMF') - for DTMF in self.__possible_DTMF: - DoorPi().event_handler.register_event('OnDTMF_'+DTMF, __name__) - - DoorPi().event_handler.register_event('OnCallStart', __name__) - DoorPi().event_handler.register_event('BeforeCallIncoming', __name__) - DoorPi().event_handler.register_event('OnCallReconnect', __name__) - DoorPi().event_handler.register_event('AfterCallReconnect', __name__) - DoorPi().event_handler.register_event('OnCallBusy', __name__) - DoorPi().event_handler.register_event('AfterCallBusy', __name__) - DoorPi().event_handler.register_event('OnCallIncoming', __name__) - DoorPi().event_handler.register_event('AfterCallIncoming', __name__) - DoorPi().event_handler.register_event('OnCallReject', __name__) - DoorPi().event_handler.register_event('AfterCallReject', __name__) - #DoorPi().event_handler.register_event('AfterAccountRegState', __name__) - - DoorPi().event_handler('OnCallStart', __name__) - - def destroy(self): - logger.debug("destroy") - DoorPi().event_handler.unregister_source(__name__, True) - - def global_state_changed(self, core, global_state, message): pass - def registration_state_changed(self, core, linphone_proxy_config, state, message): pass - def call_state_changed(self, core, call, call_state, message): - self.call_state_changed_handle(core, call, call_state, message) - - if core.calls_nb > 0 and self._last_number_of_calls == 0: - DoorPi().event_handler('OnMediaRequired', __name__) - elif self._last_number_of_calls is not core.calls_nb: - DoorPi().event_handler('OnMediaNotRequired', __name__) - self._last_number_of_calls = core.calls_nb - - def call_state_changed_handle(self, core, call, call_state, message): - logger.debug("call_state_changed (%s - %s)", call_state, message) - - remote_uri = call.remote_address.as_string_uri_only() - - DoorPi().event_handler('OnCallStateChange', __name__, { - 'remote_uri': remote_uri, - 'call_state': call_state, - 'state': message - }) - - if call_state == linphone.CallState.Idle: - pass - elif call_state == linphone.CallState.IncomingReceived: - DoorPi().event_handler('BeforeCallIncoming', __name__, {'remote_uri': remote_uri}) - if core.current_call and core.current_call.state > linphone.CallState.IncomingReceived: - logger.debug("Incoming call while another call is active") - logger.debug("- incoming.remote_uri: %s", call) - logger.debug("- current.remote_uri : %s", core.current_call) - - if core.current_call.remote_address.as_string_uri_only() == remote_uri: - logger.info("Current call is incoming call - quitting current and connecting to incoming. Maybe connection reset?") - DoorPi().event_handler('OnCallReconnect', __name__, {'remote_uri': remote_uri}) - core.terminate_call(core.current_call) - DoorPi().sipphone.reset_call_start_datetime() - core.accept_call_with_params(call, DoorPi().sipphone.base_config) - DoorPi().event_handler('AfterCallReconnect', __name__) - return - else: - if self.is_admin_number(remote_uri): - logger.info("Incoming and current call are different - incoming is AdminNumber, so hanging up current call") - DoorPi().event_handler('OnCallIncoming', __name__, {'remote_uri': remote_uri}) - core.terminate_call(core.current_call) - DoorPi().sipphone.reset_call_start_datetime() - core.accept_call_with_params(call, DoorPi().sipphone.base_config) - DoorPi().event_handler('AfterCallIncoming', __name__, {'remote_uri': remote_uri}) - return - else: - logger.info("Incoming and current call are different - sending busy signal to incoming call") - DoorPi().event_handler('OnCallBusy', __name__, {'remote_uri': remote_uri}) - core.decline_call(call, linphone.Reason.Busy) - DoorPi().event_handler('AfterCallBusy', __name__) - return - if self.is_admin_number(remote_uri): - DoorPi().event_handler('OnCallIncoming', __name__, {'remote_uri': remote_uri}) - DoorPi().sipphone.reset_call_start_datetime() - core.accept_call_with_params(call, DoorPi().sipphone.base_config) - DoorPi().event_handler('AfterCallIncoming', __name__, {'remote_uri': remote_uri}) - return - else: - DoorPi().event_handler('OnCallReject', __name__) - core.decline_call(call, linphone.Reason.Forbidden) #Declined - DoorPi().event_handler('AfterCallReject', __name__) - return - elif call_state == linphone.CallState.OutgoingInit: - pass - elif call_state == linphone.CallState.OutgoingProgress: - pass - elif call_state == linphone.CallState.OutgoingRinging: - pass - elif call_state == linphone.CallState.OutgoingEarlyMedia: - DoorPi().event_handler('OnCallMediaStateChange', __name__) - elif call_state == linphone.CallState.Connected: - DoorPi().event_handler('OnCallStateConnect', __name__) - elif call_state == linphone.CallState.StreamsRunning: - DoorPi().event_handler('AfterCallStateConnect', __name__) - DoorPi().event_handler('OnCallMediaStateChange', __name__) - elif call_state == linphone.CallState.Pausing: - pass - elif call_state == linphone.CallState.Paused: - DoorPi().event_handler('OnCallMediaStateChange', __name__) - elif call_state == linphone.CallState.Resuming: - DoorPi().event_handler('OnCallStateConnect', __name__) - DoorPi().event_handler('OnCallMediaStateChange', __name__) - elif call_state == linphone.CallState.Refered: - pass - elif call_state == linphone.CallState.Error: - if message == "Busy here": DoorPi().event_handler('OnCallStateDismissed', __name__) - elif call_state == linphone.CallState.End: - if message == "Call declined.": DoorPi().event_handler('OnCallStateReject', __name__) - DoorPi().event_handler('OnCallStateDisconnect', __name__) - elif call_state == linphone.CallState.PausedByRemote: - pass - elif call_state == linphone.CallState.UpdatedByRemote: - pass - elif call_state == linphone.CallState.IncomingEarlyMedia: - DoorPi().event_handler('OnCallMediaStateChange', __name__) - elif call_state == linphone.CallState.Updating: - DoorPi().event_handler('OnCallStateConnect', __name__) - DoorPi().event_handler('OnCallMediaStateChange', __name__) - elif call_state == linphone.CallState.Released: - pass - elif call_state == linphone.CallState.EarlyUpdatedByRemote: - pass - elif call_state == linphone.CallState.EarlyUpdating: - pass - def notify_presence_received(self, core, linphone_friend): pass - def new_subscription_requested(self, core, linphone_friend, url): pass - def auth_info_requested(self, core, realm, username): pass - def call_log_updated(self, core, new_call_log_entry): pass - def message_received(self, core, linphone_chat_room, message): pass - def is_composing_received(self, core, linphone_chat_room): pass - def dtmf_received(self, core, call, digits): - logger.debug("on_dtmf_digit (%s)", str(digits)) - digits = chr(digits) - DoorPi().event_handler('OnDTMF', __name__, {'digits':digits}) - self.__DTMF += str(digits) - for DTMF in self.__possible_DTMF: - if self.__DTMF.endswith(DTMF[1:-1]): - DoorPi().event_handler('OnDTMF_'+DTMF+'', __name__, { - 'remote_uri': str(call.remote_address.as_string_uri_only()), - 'DTMF': str(self.__DTMF) - }) - def refer_received(self, core, refer_to): pass - def call_encryption_changed(self, core, call, on, authentication_token): pass - def transfer_state_changed(self, core, call, transfer_state): pass - def buddy_info_updated(self, core, linphone_friend): pass - def call_stats_updated(self, core, call, stats): pass - def info_received(self, core, call, message): pass - def subscription_state_changed(self, core, linphone_event, linphone_subscription_state): pass - def notify_received(self, core, linphone_event, linphone_subscription_state, linphone_body): pass - def configuring_status(self, core, linphone_configuring_state, message): pass - def network_reachable(self, core, reachable): pass - def log_collection_upload_state_changed(self, core, linphone_core_log_collection_upload_state, info): pass - def log_collection_upload_progress_indication(self, core, offset, total): pass - - __del__ = destroy \ No newline at end of file diff --git a/doorpi/sipphone/linphone_lib/Player.py b/doorpi/sipphone/linphone_lib/Player.py deleted file mode 100644 index 64cd306c..00000000 --- a/doorpi/sipphone/linphone_lib/Player.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import logging -logger = logging.getLogger(__name__) -logger.debug("%s loaded", __name__) - -import os - -import doorpi -from doorpi.media.CreateDialTone import generate_dial_tone -from doorpi.sipphone.AbstractBaseClass import PlayerAbstractBaseClass, SIPPHONE_SECTION - -class LinphonePlayer(PlayerAbstractBaseClass): - - __player_id = None - __slot_id = None - - __player_filename = '' - - @property - def player_filename(self): return self.__player_filename - - def __init__(self): - self.__player_filename = doorpi.DoorPi().config.get_string_parsed(SIPPHONE_SECTION, 'dialtone', - '!BASEPATH!/media/ShortDialTone.wav') - if self.__player_filename is '': - logger.debug('no player found in config at section DoorPi and key dialtone') - return - - doorpi.DoorPi().event_handler.register_action('OnSipPhoneDestroy', self.destroy) - - self.__player_filename = doorpi.DoorPi().parse_string(self.__player_filename) - if not os.path.exists(os.path.dirname(self.__player_filename)): - logger.info('Path %s does not exist - creating it now', os.path.dirname(self.__player_filename)) - os.makedirs(os.path.dirname(self.__player_filename)) - dialtone_renew_every_start = doorpi.DoorPi().config.get_bool(SIPPHONE_SECTION, 'dialtone_renew_every_start', False) - if not os.path.isfile(self.__player_filename) or dialtone_renew_every_start: - logger.info('DialTone %s does not exist - creating it now', self.__player_filename) - dialtone_volume = doorpi.DoorPi().config.get_int(SIPPHONE_SECTION, 'dialtone_volume', 35) - generate_dial_tone(self.__player_filename, dialtone_volume) - doorpi.DoorPi().event_handler.register_event('OnPlayerStarted', __name__) - doorpi.DoorPi().event_handler.register_event('OnPlayerStopped', __name__) - doorpi.DoorPi().event_handler.register_event('OnPlayerCreated', __name__) - - doorpi.DoorPi().event_handler.register_action('OnSipPhoneMakeCall', self.start) - doorpi.DoorPi().event_handler.register_action('OnCallStateConnect', self.stop) - doorpi.DoorPi().event_handler.register_action('OnCallStateDisconnect', self.stop) - - doorpi.DoorPi().event_handler('OnPlayerCreated', __name__) - - def start(self): doorpi.DoorPi().event_handler('OnPlayerStarted', __name__) - def stop(self): doorpi.DoorPi().event_handler('OnPlayerStopped', __name__) - def destroy(self): - self.stop() - doorpi.DoorPi().event_handler.unregister_source(__name__, True) diff --git a/doorpi/sipphone/linphone_lib/Recorder.py b/doorpi/sipphone/linphone_lib/Recorder.py deleted file mode 100644 index df89bd42..00000000 --- a/doorpi/sipphone/linphone_lib/Recorder.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import logging -logger = logging.getLogger(__name__) -logger.debug("%s loaded", __name__) - -import os - -from doorpi import DoorPi -from doorpi.sipphone.AbstractBaseClass import RecorderAbstractBaseClass, SIPPHONE_SECTION - -class LinphoneRecorder(RecorderAbstractBaseClass): - - __record_filename = '' - __last_record_filename = '' - - @property - def record_filename(self): return self.__record_filename - - @property - def parsed_record_filename(self): return DoorPi().parse_string(self.__record_filename) - - @property - def last_record_filename(self): return self.__last_record_filename - - def reset_last_record_filename(self): - self.__last_record_filename = self.parsed_record_filename - return self.__last_record_filename - - def __init__(self): - self.__record_filename = DoorPi().config.get(SIPPHONE_SECTION, 'records', - '!BASEPATH!/records/%Y-%m-%d_%H-%M-%S.wav') - if self.__record_filename is '': - logger.debug('no recorder found in config at section DoorPi and key records') - return - - DoorPi().event_handler.register_action('OnSipPhoneDestroy', self.destroy) - - DoorPi().event_handler.register_event('OnRecorderStarted', __name__) - DoorPi().event_handler.register_event('OnRecorderStopped', __name__) - DoorPi().event_handler.register_event('OnRecorderCreated', __name__) - - if DoorPi().config.get_bool(SIPPHONE_SECTION, 'record_while_dialing', 'False') is True: - DoorPi().event_handler.register_action('OnSipPhoneMakeCall', self.start) - else: - DoorPi().event_handler.register_action('OnCallStateConnect', self.start) - - DoorPi().event_handler.register_action('OnCallStateDisconnect', self.stop) - - DoorPi().event_handler('OnRecorderCreated', __name__) - - def start(self): - if self.__record_filename is '': - return - - if self.__record_filename is not '': - if not os.path.exists(os.path.dirname(self.__last_record_filename)): - logger.info('Path %s does not exist - creating it now', os.path.dirname(self.__last_record_filename)) - os.makedirs(os.path.dirname(self.__last_record_filename)) - - logger.debug('starting recording to %s', self.__last_record_filename) - DoorPi().sipphone.current_call.start_recording() - DoorPi().event_handler('OnRecorderStarted', __name__, { - 'last_record_filename': self.__last_record_filename - }) - - def stop(self): - if not DoorPi().sipphone.current_call: return - logger.debug('stopping recording to %s', self.__last_record_filename) - DoorPi().sipphone.current_call.stop_recording() - DoorPi().event_handler('OnRecorderStopped', __name__, { - 'last_record_filename': self.__last_record_filename - }) - - def destroy(self): - try: self.stop() - except: pass - DoorPi().event_handler.unregister_source(__name__, True) diff --git a/doorpi/sipphone/linphone_lib/__init__.py b/doorpi/sipphone/linphone_lib/__init__.py deleted file mode 100644 index 9c000e15..00000000 --- a/doorpi/sipphone/linphone_lib/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -"""provide intercomstation to the doorstation by VoIP""" diff --git a/doorpi/status/requirements_lib/req_sipphone.py b/doorpi/status/requirements_lib/req_sipphone.py index 42ad218d..77f79083 100644 --- a/doorpi/status/requirements_lib/req_sipphone.py +++ b/doorpi/status/requirements_lib/req_sipphone.py @@ -50,7 +50,7 @@ dict( name = 'OnRecorderCreated', description = 'Es wurde eine Recorder erstellt wurde und bereit ist Anrufe aufzuzeichnen.') ], configuration = [ - dict( section = SIPPHONE_SECTION, key = 'sipphonetyp', type = 'string', default = '', mandatory = False, description = 'Auswahl welches SIP-Phone benutzt werden soll ("linphone" oder "pjsua")'), + dict( section = SIPPHONE_SECTION, key = 'sipphonetyp', type = 'string', default = '', mandatory = False, description = 'Auswahl welches SIP-Phone benutzt werden soll. Derzeit wird nur "pjsua2" unterstützt.'), dict( section = SIPPHONE_SECTION, key = 'sipphone_server', type = 'string', default = '', mandatory = False, description = 'Wenn eine SIP-Phone Server verwendet werden soll muss dazu der Server, der Benutzername, das Passwort und der Realm angegeben werden.'), dict( section = SIPPHONE_SECTION, key = 'sipphone_username', type = 'string', default = '', mandatory = False, description = 'Benutzer zur Anmeldung am SIP-Phone Server'), dict( section = SIPPHONE_SECTION, key = 'sipphone_password', type = 'string', default = '', mandatory = False, description = 'Passwort zur Anmeldung am SIP-Phone Server'), @@ -69,74 +69,10 @@ dict( section = SIPPHONE_SECTION, key = 'number_of_snapshots', type = 'integer', default = '10', mandatory = False, description = 'Anzahl der Bilder die gespeichert werden.') ], libraries = dict( - linphone = dict( - text_description = ''' -Linphone ist eine freie Software für die IP-Telefonie (VoIP), die unter der Lizenz GNU GPLv2 verfügbar ist. Es ist ein einfaches und zuverlässiges VoIP-Programm mit Videoübertragung. Wegen der recht guten Videoqualität eignet es sich zum Beispiel auch für Unterhaltungen in Gebärdensprache. - -Das Programm ist in einer Linux-, Windows- und OS-X-Version erhältlich, für unixähnliche Betriebssysteme wie FreeBSD kann der frei zugängliche Quelltext genutzt werden. Zudem existieren Clients für Android, iOS, Blackberry und Windows Phone. Neben der GTK+-basierenden grafischen Oberfläche existieren auch zwei Konsolen-Programme. - -Das Programm hat folgende Funktionalitäten: - -* Internettelefonie – basierend auf dem SIP-Standard -* Bildtelefonie oder Videokonferenz -* Präsenz (man kann feststellen, ob ein Gesprächspartner gerade erreichbar ist) -* Instant Messaging -* Verschlüsselung der Audio- und Video-Übertragung - -Für die Sprachübertragung stehen folgende Codecs zur Verfügung: - -* G.711a bzw. G.711u -* GSM -* Speex -* LPC10-15 -* G.722 -* Opus - -Videoübertragungen können mit folgenden Codecs durchgeführt werden: - -* H.263 bzw. H.263+ -* MPEG4 Part 2 -* Theora -* H.264 (mit Plug-in basierend auf x264) - -Verschlüsselung kann mit folgenden Protokollen durchgeführt werden: - -* SRTP -* ZRTP - -Für den Betrieb hinter einem NAT-Router steht das STUN-Protokoll zur Verfügung.''', - text_warning = 'Es gibt derzeit keine funktionierende Python3-Version von Linphone.', - auto_install = False, - text_test = 'Es kann jederzeit der Status manuell gestestet werden, indem im Python-Interpreter ``import linphone`` eingeben wird.', - text_configuration = 'Für die Konfiguration von Linphone stehen eine Vielzahl an Parametern zur Verfügung, die im Abschnitt Konfiguration eingesehen werden können.', - configuration = [ - dict( section = SIPPHONE_SECTION, key = 'echo_cancellation_enabled', type = 'boolean', default = 'False', mandatory = False, description = 'Softwareseitige Echo-Unterdrückung - Achtung: sehr hohe Systemauslastung und nicht empfehlenswert'), - dict( section = SIPPHONE_SECTION, key = 'video_display_enabled', type = 'boolean', default = 'False', mandatory = False, description = 'Soll auf der Außenstelle ein Bild auf dem Display angezeigt werden? - Achtung: sehr hohe Systemauslastung und nicht empfehlenswert'), - dict( section = SIPPHONE_SECTION, key = 'stun_server', type = 'string', default = '', mandatory = False, description = 'STUN Server der genutzt werden soll'), - dict( section = SIPPHONE_SECTION, key = 'FirewallPolicy', type = 'string', default = 'PolicyNoFirewall', mandatory = False, description = 'möglich Werte: PolicyNoFirewall, PolicyUseStun, PolicyUseIce und PolicyUseUpnp.'), - dict( section = SIPPHONE_SECTION, key = 'video_device', type = 'string', default = '', mandatory = False, description = 'Kamera, die für die Aufnahme genutzt wird - wenn nichts angegeben wird, dann wird die erst Beste genutzt. Bitte dazu in der LOG-Datei nach "possible videodevices:" suchen'), - dict( section = SIPPHONE_SECTION, key = 'video_size', type = 'string', default = '', mandatory = False, description = 'möglich Werte: [fehlt noch]'), - dict( section = SIPPHONE_SECTION, key = 'video_codecs', type = 'array', default = 'VP8', mandatory = False, description = 'Video-Codecs die aktiviert und genutzt werden können.'), - dict( section = SIPPHONE_SECTION, key = 'capture_device', type = 'string', default = '', mandatory = False, description = 'Audiogerät, das für die Aufnahme genutzt wird - wenn nichts angegeben wird, dann wird das erst Beste genutzt. Bitte dazu in der LOG-Datei nach "possible sounddevices:" suchen'), - dict( section = SIPPHONE_SECTION, key = 'mic_gain_db', type = 'float', default = '0', mandatory = False, description = 'Zusätzliche Software-Verstärkung der Aufnahme, falls der Pegel vom Mikro auch bei maximaler Mixer-Einstellung zu schwach ist.'), - dict( section = SIPPHONE_SECTION, key = 'playback_device', type = 'string', default = '', mandatory = False, description = 'Audiogerät, das für die Aufnahme genutzt wird - wenn nichts angegeben wird, dann wird das erst Beste genutzt. Bitte dazu in der LOG-Datei nach "possible sounddevices:" suchen'), - dict( section = SIPPHONE_SECTION, key = 'audio_codecs', type = 'array', default = 'PCMA,PCMU', mandatory = False, description = 'Audio-Codecs die aktiviert und genutzt werden können.'), - ], - text_links = { - 'linphone.org': { - 'Übersicht Liblinphone': 'http://www.linphone.org/technical-corner/liblinphone/overview', - 'Installationsanleitung im Wiki': 'https://wiki.linphone.org/wiki/index.php/Raspberrypi:start', - 'News Linphone für Raspberry': 'http://www.linphone.org/news/32/26/Linphone-Python-for-Raspberry-Pi-3-8.html' - }, - 'Linphone for Python documentation': 'http://pythonhosted.org/linphone/', - 'linphone auf wikipedia.de': 'https://de.wikipedia.org/wiki/Linphone' - } - ), - pjsua = dict( - text_warning = 'Das SIP-Phone pjsua wird aktuell nicht in DoorPi unterstützt.', - #text_description = '', - #text_installation = '', - #text_test = '', + pjsua2 = dict( + text_description = 'PJSIP ist eine quelloffene Bibliothek, die Standardprotokolle wie SIP, SDP, RTP, STUN, TURN und ICE implementiert. DoorPi nutzt das zugehörige Python-Modul pjsua2, um VoIP-Verbindungen zwischen der Gegensprechanlage an der Tür und den Innenstationen bzw. Telefonen herzustellen.', + text_installation = 'Das Modul ist im Paket ``python-pjproject`` (Arch Linux ARM) enthalten. Für Raspbian existiert derzeit kein offizielles Paket.', + text_test = 'Der Status kann gestestet werden, indem im Python-Interpreter ``import pjsua2`` eingeben wird.', #text_configuration = '', #configuration = [], text_links = { @@ -146,4 +82,3 @@ ) ) ) -