Example #1
0
 def speak(self, speech):
     if not self.call_established:
         LOG.error("Speaking without an active call!")
     else:
         LOG.info("Sending TTS for " + speech)
         self.send_audio(self.tts.get_mp3(speech))
         sleep(0.5)
Example #2
0
 def do_command(self, action):
     if self.ready:
         action = str(action)
         self.baresip.sendline(action)
     else:
         LOG.warning(action + " not executed!")
         LOG.error("NOT READY! please wait")
Example #3
0
 def hang(self):
     if self.current_call:
         LOG.info("Hanging: " + self.current_call)
         self.do_command("/hangup")
         self.current_call = None
         self._call_status = None
     else:
         LOG.error("No active call to hang")
Example #4
0
 def send_dtmf(self, number):
     number = str(number)
     for n in number:
         if n not in "0123456789":
             LOG.error("invalid dtmf tone")
             return
     LOG.info("Sending dtmf tones for " + number)
     dtmf = join(tempfile.gettempdir(), number + ".wav")
     ToneGenerator().dtmf_to_wave(number, dtmf)
     self.send_audio(dtmf)
Example #5
0
 def quit(self):
     LOG.info("Exiting")
     if self.running:
         if self.current_call:
             self.hang()
         self.baresip.sendline("/quit")
     self.running = False
     self.current_call = None
     self._call_status = None
     self.abort = True
Example #6
0
 def send_audio(self, wav_file):
     if not self.call_established:
         LOG.error("Can't send audio without an active call!")
         return
     wav_file, duration = self.convert_audio(wav_file)
     # send audio stream
     LOG.info("transmitting audio")
     self.do_command("/ausrc aufile," + wav_file)
     # wait till playback ends
     sleep(duration - 0.5)
     # avoid baresip exiting
     self.do_command("/ausrc alsa,default")
Example #7
0
 def quit(self):
     if self.updated_config:
         LOG.info("restoring original config")
         with open(join(self.config_path, "config"), "w") as f:
             f.write(self._original_config)
     LOG.info("Exiting")
     if self.running:
         if self.current_call:
             self.hang()
         self.baresip.sendline("/quit")
     self.running = False
     self.current_call = None
     self._call_status = None
     self.abort = True
     self.baresip.close()
     self.baresip.kill(signal.SIGKILL)
Example #8
0
 def mute_mic(self):
     if not self.call_established:
         LOG.error("Can not mute microphone while not in a call")
         return
     if not self.mic_muted:
         LOG.info("Muting mic")
         self.do_command("/mute")
     else:
         LOG.info("Mic already muted")
Example #9
0
 def handle_incoming_call(self, number):
     LOG.info("Incoming call: " + number)
     if self.call_established:
         LOG.info("already in a call, rejecting")
         sleep(0.1)
         self.do_command("b")
     else:
         LOG.info("default behaviour, rejecting call")
         sleep(0.1)
         self.do_command("b")
Example #10
0
 def handle_error(self, error):
     LOG.error(error)
     if error == "failed to set audio-source (No such device)":
         self.handle_audio_stream_failure()
Example #11
0
    def run(self):
        self.running = True
        while self.running:
            try:
                out = self.baresip.readline().decode("utf-8")

                if out != self._prev_output:
                    out = out.strip()
                    if self.debug:
                        LOG.debug(out)
                    if "baresip is ready." in out:
                        self.handle_ready()
                    elif "account: No SIP accounts found" in out:
                        self._handle_no_accounts()
                    elif "All 1 useragent registered successfully!" in out:
                        self.ready = True
                        self.handle_login_success()
                    elif "ua: SIP register failed:" in out or\
                            "401 Unauthorized" in out or \
                            "Register: Destination address required" in out or\
                            "Register: Connection timed out" in out:
                        self.handle_error(out)
                        self.handle_login_failure()
                    elif "Incoming call from: " in out:
                        num = out.split("Incoming call from: ")[1].split(
                            " - (press 'a' to accept)")[0].strip()
                        self.current_call = num
                        self._call_status = "INCOMING"
                        self.handle_incoming_call(num)
                    elif "call: rejecting incoming call from " in out:
                        num = out.split("rejecting incoming call from "
                                        )[1].split(" ")[0].strip()
                        self.handle_call_rejected(num)
                    elif "call: SIP Progress: 180 Ringing" in out:
                        self.handle_call_ringing()
                        status = "RINGING"
                        self.handle_call_status(status)
                        self._call_status = status
                    elif "call: connecting to " in out:
                        n = out.split("call: connecting to '")[1].split("'")[0]
                        self.current_call = n
                        self.handle_call_start()
                        status = "OUTGOING"
                        self.handle_call_status(status)
                        self._call_status = status
                    elif "Call established:" in out:

                        status = "ESTABLISHED"
                        self.handle_call_status(status)
                        self._call_status = status
                        sleep(0.5)
                        self.handle_call_established()
                    elif "call: hold " in out:
                        n = out.split("call: hold ")[1]
                        status = "ON HOLD"
                        self.handle_call_status(status)
                        self._call_status = status
                    elif "Call with " in out and \
                            "terminated (duration: " in out:
                        status = "DISCONNECTED"
                        duration = out.split("terminated (duration: ")[1][:-1]
                        self.handle_call_status(status)
                        self._call_status = status
                        self.handle_call_timestamp(duration)
                        self.mic_muted = False
                    elif "call muted" in out:
                        self.mic_muted = True
                        self.handle_mic_muted()
                    elif "call un-muted" in out:
                        self.mic_muted = False
                        self.handle_mic_unmuted()
                    elif "session closed:" in out:
                        reason = out.split("session closed:")[1].strip()
                        status = "DISCONNECTED"
                        self.handle_call_status(status)
                        self._call_status = status
                        self.handle_call_ended(reason)
                        self.mic_muted = False
                    elif "(no active calls)" in out:
                        status = "DISCONNECTED"
                        self.handle_call_status(status)
                        self._call_status = status
                    elif "===== Call debug " in out:
                        status = out.split("(")[1].split(")")[0]
                        self.handle_call_status(status)
                        self._call_status = status
                    elif "--- List of active calls (1): ---" in \
                            self._prev_output:
                        if "ESTABLISHED" in out and self.current_call in out:
                            ts = out.split("ESTABLISHED")[0].split(
                                "[line 1]")[1].strip()
                            if ts != self._ts:
                                self._ts = ts
                                self.handle_call_timestamp(ts)
                    elif "failed to set audio-source (No such device)" in out:
                        error = "failed to set audio-source (No such device)"
                        self.handle_error(error)

                    self._prev_output = out
            except pexpect.exceptions.EOF:
                # baresip exited
                self.quit()
            except pexpect.exceptions.TIMEOUT:
                # nothing happened for a while
                pass
Example #12
0
 def handle_call_timestamp(self, timestr):
     LOG.info("Call time: " + timestr)
Example #13
0
 def handle_audio_stream_failure(self):
     LOG.debug("Aborting call, maybe we reached voicemail?")
     self.hang()
Example #14
0
 def say(self, speech):
     if not self.call_established:
         LOG.warning("Speaking without an active call!")
     self.tts.say(speech, blocking=True)
Example #15
0
 def resume(self):
     if self.current_call:
         LOG.info("Resuming " + self.current_call)
         self.do_command("/resume")
     else:
         LOG.error("No active call to resume")
Example #16
0
    def __init__(self, user, pwd, gateway, tts=None, debug=False,
                 block=True, config_path=None, sounds_path=None):
        config_path = config_path or join("~", ".baresipy")
        self.config_path = expanduser(config_path)
        if not isdir(self.config_path):
            makedirs(self.config_path)
        if isfile(join(self.config_path, "config")):
            with open(join(self.config_path, "config"), "r") as f:
                self.config = f.read()
            LOG.info("config loaded from " + self.config_path + "/config")
            self.updated_config = False
        else:
            self.config = baresipy.config.DEFAULT
            self.updated_config = True

        self._original_config = str(self.config)

        if sounds_path is not None and "#audio_path" in self.config:
            self.updated_config = True
            if sounds_path is False:
                # sounds disabled
                self.config = self.config.replace(
                    "#audio_path		/usr/share/baresip",
                    "audio_path		/dont/load")
            elif isdir(sounds_path):
                self.config = self.config.replace(
                    "#audio_path		/usr/share/baresip",
                    "audio_path		" + sounds_path)

        if self.updated_config:
            with open(join(self.config_path, "config.bak"), "w") as f:
                f.write(self._original_config)

            LOG.info("saving config")
            with open(join(self.config_path, "config"), "w") as f:
                f.write(self.config)

        self.debug = debug
        self.user = user
        self.pwd = pwd
        self.gateway = gateway
        if tts:
            self.tts = tts
        else:
            self.tts = ResponsiveVoice(gender=ResponsiveVoice.MALE)
        self._login = "******".format(u=self.user, p=self.pwd,
                                               g=self.gateway)
        self._prev_output = ""
        self.running = False
        self.ready = False
        self.mic_muted = False
        self.abort = False
        self.current_call = None
        self._call_status = None
        self.audio = None
        self._ts = None
        self.baresip = pexpect.spawn('baresip -f ' + self.config_path)
        super().__init__()
        self.start()
        if block:
            self.wait_until_ready()
Example #17
0
 def handle_login_success(self):
     LOG.info("Logged in!")
Example #18
0
 def handle_call_established(self):
     LOG.info("Call established")
Example #19
0
 def handle_call_ended(self, reason):
     LOG.info("Call ended")
     LOG.debug("Reason: " + reason)
Example #20
0
 def handle_call_ringing(self):
     number = self.current_call
     LOG.info(number + " is Ringing")
Example #21
0
 def handle_call_start(self):
     number = self.current_call
     LOG.info("Calling: " + number)
Example #22
0
 def handle_call_status(self, status):
     if status != self._call_status:
         LOG.debug("Call Status: " + status)
Example #23
0
 def login(self):
     LOG.info("Adding account: " + self.user)
     self.baresip.sendline("/uanew " + self._login)
Example #24
0
 def handle_login_failure(self):
     LOG.error("Log in failed!")
     self.quit()
Example #25
0
 def call(self, number):
     LOG.info("Dialling: " + number)
     self.do_command("/dial " + number)
Example #26
0
 def handle_ready(self):
     LOG.info("Ready for instructions")
Example #27
0
 def hold(self):
     if self.current_call:
         LOG.info("Holding: " + self.current_call)
         self.do_command("/hold")
     else:
         LOG.error("No active call to hold")
Example #28
0
 def handle_mic_unmuted(self):
     LOG.info("Microphone unmuted")
Example #29
0
 def _handle_no_accounts(self):
     LOG.debug("No accounts setup")
     self.login()
Example #30
0
 def handle_call_rejected(self, number):
     LOG.info("Rejected incoming call: " + number)