#!/usr/bin/env python2 # -*- coding: utf-8 -*- import audioop import contextlib import glob import io import os import subprocess import syslog import threading import time import wave from datetime import datetime import linphone from enum import Enum import threading VOLUME_THRESHOLD = 100 class ConversationStatus(Enum): READY_TO_TALK = 0 IMTALKING = 1 WAITFORANSWER = 2 class Conversation(object): def __init__(self): self._status = ConversationStatus.READY_TO_TALK @property def status(self): return self._status @status.setter def status(self, value): if value != self._status: print(" New status : " + str(value)) self._status = value current_dir = os.path.dirname(os.path.realpath(__file__)) replies_seq = glob.glob(current_dir + "/replies/sequence/*.wav") replies_seq.sort() replies_generic = glob.glob(current_dir + "/replies/generic/*.wav") replies_generic.sort() incoming_stream_file = "/tmp/lenny" conversation = Conversation() replies_pos = 0 THREADS_MUST_QUIT = False def log(msg): syslog.syslog(msg) print(msg) def get_wav_duration(fname): with contextlib.closing(wave.open(fname, 'r')) as f: frames = f.getnframes() rate = f.getframerate() return frames / float(rate) def sleep(duration): dummy_event = threading.Event() dummy_event.wait(timeout=duration) def say(core): global conversation global replies_pos if conversation.status is not ConversationStatus.IMTALKING: conversation.status = ConversationStatus.IMTALKING # On joue les repliques en sequence, puis quand # on arrive au bout, on en joue une au hasard # du groupe 'generic' voice_filename = replies_seq[replies_pos] replies_pos = (replies_pos + 1) % len(replies_seq) if replies_pos == 0: # On ne rejoue jamais la première réplique "allo" replies_pos = 1 duration = get_wav_duration(voice_filename) print("Saying : " + voice_filename + "(duration : " + str(duration) + ")") core.play_file = voice_filename sleep(duration) core.play_file = "" # On laisse l'autre l'occassion de reparler conversation.status = ConversationStatus.WAITFORANSWER def call_state_changed(core, call, state, message): global conversation global replies_pos log("state changed : " + message) if state == linphone.CallState.Released: # Let's convert wav to mp3 log("Converting output from wav to mp3") subprocess.call('lame --quiet --preset insane %s' % call.current_params.record_file, shell=True) os.remove(call.current_params.record_file) if state == linphone.CallState.IncomingReceived: log("Incoming call : {}".format(call.remote_address.username)) replies_pos = 0 if call.remote_address.username == "**620" or call.remote_address.username == "0765757624": print(" ... " + call.remote_address.username) #if call.remote_address.username == "0227570500": # print(" .. from Bernard !") call_params = core.create_call_params(call) call_params.record_file = current_dir + "/out/call_" + datetime.now().strftime( '%Y-%m-%d_%Hh%Mmn%Ss') + ".wav" # Let ring some time sleep(5) core.accept_call_with_params(call, call_params) call.start_recording() sleep(2) t = threading.Thread(target=incoming_stream_worker, args=[core, call]) t.start() say(core) def global_state_changed(*args, **kwargs): log("global_state_changed: %r %r" % (args, kwargs)) def registration_state_changed(core, call, state, message): log("registration_state_changed: " + str(state) + ", " + message) def incoming_stream_worker(core, call): global conversation print("Worker is starting") f = open(incoming_stream_file, "rb") f.seek(0, io.SEEK_END) p = f.tell() buf = '' previous_status = conversation.status while call.state is not linphone.CallState.End and not THREADS_MUST_QUIT: if conversation.status is ConversationStatus.IMTALKING: f.seek(0, io.SEEK_END) p = f.tell() else: if previous_status != conversation.status: f.seek(0, io.SEEK_END) p = f.tell() f.seek(p) buf += f.read(4096) p = f.tell() if len(buf) >= 20000: volume = audioop.rms(buf, 2) print("Detected volume : " + str(volume)) #print("State : " + str(conversation.status)) buf = '' if volume < VOLUME_THRESHOLD: if conversation.status is ConversationStatus.READY_TO_TALK: threading.Thread(target=say, args=[core]).start() else: conversation.status = ConversationStatus.READY_TO_TALK # We must sleep a bit to avoid cpu hog sleep(0.01) previous_status = conversation.status print("Worker is quitting") def main(): log("lenny is starting ...") callbacks = { 'call_state_changed': call_state_changed, 'registration_state_changed': registration_state_changed, 'global_state_changed': global_state_changed, } username = "621" password = "toto" port = "5060" domain = "192.168.1.1" core = linphone.Core.new(callbacks, None, None) # On fait le setup pour la capture et analyse du stream entrant os.system("rm -rf " + incoming_stream_file) os.system("touch " + incoming_stream_file) core.use_files = True core.record_file = incoming_stream_file proxy_cfg = core.create_proxy_config() proxy_cfg.identity_address = core.create_address('sip:' + username + '@' + domain + ':' + port) proxy_cfg.server_addr = 'sip:' + domain + ':' + port proxy_cfg.register_enabled = True core.add_proxy_config(proxy_cfg) auth_info = core.create_auth_info(username, None, password, None, None, domain) core.add_auth_info(auth_info) while True: sleep(0.03) core.iterate() log("callblocker quitting.") if __name__ == "__main__": try: main() except KeyboardInterrupt: THREADS_MUST_QUIT = True print "Bye" # - Hi its lenny # - Hmmm, sorry, I can barely here you there # - Yes, yes, yes # - Oh good, yes, yes, yes # - Hmm, mais il me semble que quelqu'un a appelé pour ça la semaine passée ... c'était vous ? # - Yeah, pouvez-vous me rappeler votre nom ? # - Ca tombe bien que vous m'appeliez, car justement ma nièce me parlait de la même chose l'autre jour. # j'écoute d'ailleurs toujours attentivement son avis, car vous savez, c'est la première de la famille # qui est allé à l'Université. Et elle l'a terminé avec mention, nous en sommes très fière. # et du coup elle m'a dit que je devrais jeter un oeil à ce dont vous me parlez. # - Hmm, désolé, j'ai pas tout à fait compris, vous pouvez répéter ? # - Heu, oui, vous pouvez me rappeler de la part de quelle entreprise vous appelez # - Oui, en fait y'a une chose ... heuu, car j'avais eu un appel comme le votre, j'ai eu pas mal # de problème avec le personnel ici, qui m'on fait la morale, car je me suis retrouvé avec des affaires # dont je n'avais pas besoin, et ma nièce justement m'a fait la morale également ... vous savez ce que c'est # la famille .... # - Could you say that again please ? # Idées : # - En tout cas vous me semblez une personne fort sympathique, c'est toujours agréable de discute # des personnes sympathique, quand on est une personne seule comme moi ... heuu, en fait on parlait # de quoi déjà ? # - Bon,