@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
import linphone
import time
import threading
import subprocess
from pylinphone . pylinphone import LinphoneCommunicationSocket
class PhoneProxyConfiguration ( object ) :
@ -40,27 +40,46 @@ class PhoneEvent(object):
@@ -40,27 +40,46 @@ class PhoneEvent(object):
@classmethod
def string ( cls , val ) :
for k , v in vars ( cls ) . items ( ) :
for k , v in vars ( cls ) . iterite ms ( ) :
if v == val :
return k
class PhoneInterface ( object ) :
def __init__ ( self , config ) :
cbs = {
' global_state_changed ' : self . __global_state_changed ,
' registration_state_changed ' : self . __registration_state_changed ,
' call_state_changed ' : self . __call_state_changed
}
self . __event_cbs = [ ]
self . __config = config
self . __core = LinphoneCommunicationSocket ( " /var/tmp/debian-sid/tmp/linphone " )
self . __core . onLinphoneCallIncomingReceived = self . on_LinphoneCallIncomingReceived
self . __core . onLinphoneCallOutgoingRinging = self . on_LinphoneCallOutgoingRinging
self . __core . onLinphoneCallConnected = self . on_LinphoneCallConnected
self . __core . onLinphoneCallEnd = self . on_LinphoneCallEnd
self . __core . onLinphoneCallError = self . on_LinphoneCallError
self . __core = linphone . Core . new ( cbs , None , config . linphone_config )
# Create and add all proxy configs
for p in config . proxies :
aid = self . __core . register ( p . identity , p . proxy , p . password , p . username ) # sip:XXXX@hg.eventphone.de, hg.eventphone.de, MySecretPassword, XXXX
ainfo = self . __core . create_auth_info ( p . username , p . username ,
p . password , None , p . realm ,
None )
self . __core . add_auth_info ( ainfo )
pconf = self . __core . create_proxy_config ( )
pconf . edit ( )
if self . __core . version < ' 3.9.0 ' :
pconf . identity = p . identity
else :
pconf . identity_address = pconf . normalize_sip_uri ( p . identity )
pconf . publish_enabled = False
pconf . realm = p . realm
pconf . register_enabled = True
pconf . server_addr = p . proxy
self . __core . add_proxy_config ( pconf )
pconf . done ( )
if p . name == config . default_proxy :
self . __core . default_proxy_config = pconf
self . __audioproc = None
aplay = subprocess . Popen ( [ ' aplay ' , ' -qD %s ' % config . sound_device ] ,
@ -70,44 +89,68 @@ class PhoneInterface(object):
@@ -70,44 +89,68 @@ class PhoneInterface(object):
stdout = aplay . stdin )
# Set default parameters overriding the ones from the given config file
# TODO: figure out how to set at least some of these settings through the unix socket
#self.__core.set_user_agent('FeTAp 615', '0.1')
#self.__core.stun_server = config.stun_server
#self.__core.ringback = ''
#self.__core.max_calls = 1
#self.__core.inc_timeout = config.incoming_timeout
#self.__core.set_call_error_tone(linphone.Reason.Busy, '')
#self.__core.disable_chat(linphone.Reason.None)
#self.__core.echo_cancellation_enabled = False
#self.__core.video_capture_enabled = False
#self.__core.video_display_enabled = False
def run_callbacks ( self , evt ) :
print ( PhoneEvent . string ( evt ) )
self . __core . set_user_agent ( ' FeTAp 615 ' , ' 0.1 ' )
self . __core . stun_server = config . stun_server
self . __core . ringback = ' '
self . __core . max_calls = 1
self . __core . inc_timeout = config . incoming_timeout
self . __core . set_call_error_tone ( linphone . Reason . Busy , ' ' )
self . __core . disable_chat ( linphone . Reason . None )
self . __core . echo_cancellation_enabled = False
self . __core . video_capture_enabled = False
self . __core . video_display_enabled = False
def __global_state_changed ( self , core , state , msg ) :
print ' Global state changed: ' , state , msg
# TODO: Do we need events emitted here?
pass
def __registration_state_changed ( self , core , proxyconf , state , msg ) :
print ' Registration state changed: ' , proxyconf , state , msg
evt = None
if state == linphone . RegistrationState . Progress :
evt = PhoneEvent . RegInProgress
elif state == linphone . RegistrationState . Ok :
evt = PhoneEvent . RegSuccessfull
elif state == linphone . RegistrationState . None :
evt = PhoneEvent . RegLost
if evt is not None :
for cb in self . __event_cbs :
cb ( evt )
def on_LinphoneCallIncomingReceived ( self , event ) :
self . run_callbacks ( PhoneEvent . CallIncoming )
def on_LinphoneCallOutgoingRinging ( self , event ) :
self . run_callbacks ( PhoneEvent . CallRinging )
def on_LinphoneCallConnected ( self , event ) :
self . run_callbacks ( PhoneEvent . CallAccepted )
def on_LinphoneCallEnd ( self , event ) :
self . run_callbacks ( PhoneEvent . CallEnded )
def on_LinphoneCallError ( self , event ) :
# TODO: Distinguish between different errors
self . run_callbacks ( PhoneEvent . CallBusy )
else :
print ' Unhandled registration state: ' , linphone . RegistrationState . string ( state )
def __call_state_changed ( self , core , call , state , msg ) :
print ' Call state changed: ' , call , state , msg
evt = None
if state == linphone . CallState . IncomingReceived :
evt = PhoneEvent . CallIncoming
elif state == linphone . CallState . OutgoingRinging :
evt = PhoneEvent . CallRinging
elif state == linphone . CallState . Connected :
evt = PhoneEvent . CallAccepted
elif state == linphone . CallState . End :
evt = PhoneEvent . CallEnded
elif state == linphone . CallState . Error :
error = call . error_info . reason
if error == linphone . Reason . Busy :
evt = PhoneEvent . CallBusy
elif error == linphone . Reason . NotFound :
evt = PhoneEvent . CallInvalidNumber
else :
evt = PhoneEvent . CallEnded
if evt is not None :
for cb in self . __event_cbs :
cb ( evt )
else :
print ' Unhandled call state: ' , linphone . CallState . string ( state )
def __pollthread ( self ) :
while self . __running :
self . __core . process_event ( )
time . sleep ( 0.2 ) # Value for good measure
self . __core . iterate ( )
time . sleep ( 0.0 2 ) # Value from example cod e
def start ( self ) :
self . __running = True
@ -124,32 +167,23 @@ class PhoneInterface(object):
@@ -124,32 +167,23 @@ class PhoneInterface(object):
self . __event_cbs . append ( cb )
def call ( self , number ) :
if ' @ ' not in number :
proxy = None
default_name = self . __config . default_proxy
for p in self . __config . proxies :
if p . name == default_name :
proxy = p
break
if proxy is None :
if ' @ ' not in number and self . __core . default_proxy_config is None :
# Try to resolve prefix
for p in self . __config . proxies :
if number . startswith ( p . prefix ) :
number = number [ len ( p . prefix ) : ]
proxy = p
number + = ' @ ' + p . realm
break
if proxy is not None :
number + = ' @ ' + proxy . realm
self . __core . call ( number )
self . __core . invite ( number )
def accept_call ( self ) :
self . __core . answer ( )
self . __core . accept_call ( self . __core . current_call )
def decline_call ( self ) :
self . __core . decline_call ( self . __core . current_call )
self . __core . decline_call ( self . __core . current_call , linphone . Reason . Busy )
def end_call ( self ) :
self . __core . terminate ( )
self . __core . terminate_call ( self . __core . current_call )
def play_dial_tone ( self ) :
self . stop_playing ( )
@ -179,17 +213,15 @@ class PhoneInterface(object):
@@ -179,17 +213,15 @@ class PhoneInterface(object):
self . __audioproc . terminate ( )
def read_text ( self , text ) :
self . __ttsproc . stdin . write ( text . encode ( ' utf8 ' ) + b ' \n ' )
self . __ttsproc . stdin . write ( text + ' \n ' )
self . __ttsproc . stdin . flush ( )
def get_remote_number ( self ) :
# FIXME
#return self.__core.current_call_remote_address.username
return ' 0000 '
return self . __core . current_call_remote_address . username
if __name__ == ' __main__ ' :
def event_cb ( evt ) :
print ( ' Got event: ' , PhoneEvent . string ( evt ) )
print ' Got event: ' , PhoneEvent . string ( evt )
try :
phone = PhoneInterface ( ' .linphonerc-foo ' , ' .linphonerc ' )