import linphone import time import threading DIAL_TONE_FILE = 'freizeichen.wav' DIAL_TONE_LEN = 5 BUSY_TONE_FILE = 'besetztzeichen.wav' BUSY_TONE_LEN = 0.96 RINGBACK_TONE = 'weckzeichen.wav' class PhoneEvent(object): RegInProgress,\ RegSuccessfull,\ CallIncoming,\ CallRinging,\ CallAccepted,\ CallEnded,\ CallBusy,\ CallInvalidNumber = range(8) @classmethod def string(cls, val): for k, v in vars(cls).iteritems(): if v == val: return k class PhoneInterface(object): def __init__(self, config, roconfig): 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.__core = linphone.Core.new(cbs, config, roconfig) # Set default parameters overriding the ones from the given config file self.__core.set_user_agent('FeTAp 615', '0.1') self.__core.ringback = RINGBACK_TONE self.__core.max_calls = 1 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 if evt is not None: for cb in self.__event_cbs: cb(evt) 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.iterate() time.sleep(0.02) # Value from example code def start(self): self.__running = True t = threading.Thread(target=self.__pollthread) t.start() def stop(self): self.__running = False def add_event_cb(self, cb): self.__event_cbs.append(cb) def call(self, number): self.__core.invite(number) def accept_call(self): self.__core.accept_call(self.__core.current_call) def end_call(self): self.__core.terminate_call(self.__core.current_call) def __play_loop_thread(self, filename, length, continous): self.__core.play_local(filename) # Start replay of file 500ms before the old playing will end # to get more or less continous play i = 50 if continous else 0 while self.__playing and self.__running: # TODO: Schoener? if i == length * 100: self.__core.play_local(filename) i = 0 time.sleep(0.01) i += 1 self.__core.stop_ringing() def __play_file(self, filename, length, continous=False): print 'Playing file:', filename self.__playing = True t = threading.Thread(target=self.__play_loop_thread, args=(filename, length, continous)) t.start() def play_dial_tone(self): self.__play_file(DIAL_TONE_FILE, DIAL_TONE_LEN, True) def play_busy_tone(self): self.__play_file(BUSY_TONE_FILE, BUSY_TONE_LEN) def stop_playing(self): self.__playing = False if __name__ == '__main__': def event_cb(evt): print 'Got event:', PhoneEvent.string(evt) try: phone = PhoneInterface('.linphonerc-foo', '.linphonerc') phone.add_event_cb(event_cb) phone.start() i = 0 while True: time.sleep(1) i += 1 if i == 5: phone.call('3474') #phone.play_busy_tone() pass except KeyboardInterrupt: phone.stop()