123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #!/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,
|