Exemple #1
0
    def __init__(self, user, log_level=6):
        ## Load config file
        self._config = ConfigParser.ConfigParser()
        self._config.read('./config.cfg')

        ## Initialize logger
        dispsip._user = user
        self._user = user
        self._user_code = user.user_code
        self.logger = logging.getLogger(self._user_code + '.dispsip')
        self.logger.info('Initializing SIP device for user: %s',
                         self._user_code)

        ## Initializing SIP device
        if not pj.Lib.instance():
            lib = pj.Lib()
        else:
            lib = pj.Lib.instance()

        my_ua_cfg = pj.UAConfig()
        my_media_cfg = pj.MediaConfig()

        try:
            self.logger.debug('Initializing PJSUA library')
            lib.init(log_cfg=pj.LogConfig(level=log_level, callback=log_cb),
                     ua_cfg=my_ua_cfg,
                     media_cfg=my_media_cfg)
            self.logger.debug('Setting null sound device in PJSUA library')
            lib.set_null_snd_dev()

        except pj.Error, e:
            self.logger.error('Lib Initialization error: %s', e)
Exemple #2
0
    def run(self, domain, user, password):
        try:
            mediaconfig = pj.MediaConfig()
            mediaconfig.quality = 10
            self.lib.init(log_cfg=pj.LogConfig(level=4, callback=self.log_cb),
                          media_cfg=mediaconfig)
            transport = self.lib.create_transport(pj.TransportType.UDP,
                                                  pj.TransportConfig())
            self.lib.start()

            # Put your sIP client credentials here
            acc = self.lib.create_account(
                pj.AccountConfig(domain=domain,
                                 username=user,
                                 password=password))

            acc_cb = MyAccountCallback(app=self, account=acc)
            acc.set_callback(acc_cb)
            acc_cb.wait()

            print "\n"
            print "Registration complete, status=", acc.info().reg_status, \
                "(" + acc.info().reg_reason + ")"

            if len(sys.argv) > 1:
                lck = self.lib.auto_lock()

            my_sip_uri = "sip:" + transport.info().host + \
                         ":" + str(transport.info().port)

            # Menu loop
            while True:
                print "My SIP URI is", my_sip_uri
                print "Menu: h=hangup call, q=quit"

                input = sys.stdin.readline().rstrip("\r\n")

                if input == "h":
                    if not self.current_call:
                        print "There is no call"
                        continue
                    self.current_call.hangup()
                    self.reset_all()

                elif input == "q":
                    break

            # shutdown the library
            transport = None

            self.lib.destroy()
            self.lib = None

        except pj.Error, e:
            print "Exception: " + str(e)
            self.lib.destroy()
            lib = None
    def start(self):
        ua = pj.UAConfig()
        ua.nameserver = ['8.8.8.8', '8.8.4.4']
        ua.user_agent = "PJSIP Python EasyPhone"

        media = pj.MediaConfig()
        media.enable_ice = True

        logger = pj.LogConfig(level=self.verbose, callback=logger_callback)

        self.pjsip.init(ua_cfg=ua, media_cfg=media, log_cfg=logger)
        self.pjsip.create_transport(pj.TransportType.TCP, pj.TransportConfig())
        self.pjsip.set_null_snd_dev()
        self.pjsip.start()
        self.pjsip.handle_events()
Exemple #4
0
 def init(self):
     self.status = States.init
     self.lib = pj.Lib()
     self.cfg_ua = pj.UAConfig()
     self.cfg_md = pj.MediaConfig()
     self.cfg_ua.max_calls, self.cfg_ua.user_agent = 32, "TrashTalker/1.0"
     self.cfg_md.no_vad, self.cfg_md.enable_ice = True, False
     self.cfg_lg = pj.LogConfig(level=self.LOG_LEVEL, callback=PJLog)
     self.lib.init(ua_cfg=cfg_ua, media_cfg=cfg_md, log_cfg=cfg_lg)
     self.lib.set_null_snd_dev()
     self.lib.start(with_thread=True)
     self.transport = self.lib.create_transport(
         pj.TransportType.UDP, pj.TransportConfig(self.port))
     self.account = self.lib.create_account_for_transport(self.transport,
                                                          cb=AccountCb())
     self.uri = "sip:%s:%s" % (self.transport.info().host,
                               self.transport.info().port)
     self.status &= States.done
Exemple #5
0
def create_MediaConfig():
    logger.debug("create_MediaConfig")
    # Doc: http://www.pjsip.org/python/pjsua.htm#MediaConfig
    MediaConfig = pj.MediaConfig()
    MediaConfig.audio_frame_ptime = conf.get_int(SIPPHONE_SECTION,
                                                 'media.audio_frame_ptime', 20)
    MediaConfig.channel_count = conf.get_int(SIPPHONE_SECTION,
                                             'media.channel_count', 1)
    MediaConfig.clock_rate = conf.get_int(SIPPHONE_SECTION, 'media.clock_rate',
                                          8000)
    MediaConfig.ec_options = conf.get_int(SIPPHONE_SECTION, 'media.ec_options',
                                          0)
    MediaConfig.ec_tail_len = conf.get_int(SIPPHONE_SECTION,
                                           'media.ec_tail_len', 1024)
    MediaConfig.enable_ice = conf.get_bool(SIPPHONE_SECTION,
                                           'media.enable_ice', True)
    MediaConfig.enable_turn = conf.get_bool(SIPPHONE_SECTION,
                                            'media.enable_turn', False)
    MediaConfig.ilbc_mode = conf.get_int(SIPPHONE_SECTION, 'media.ilbc_mode',
                                         30)
    MediaConfig.jb_max = conf.get_int(SIPPHONE_SECTION, 'media.jb_max', -1)
    MediaConfig.jb_min = conf.get_int(SIPPHONE_SECTION, 'media.jb_min', -1)
    MediaConfig.max_media_ports = conf.get_int(SIPPHONE_SECTION,
                                               'media.max_media_ports', 32)
    MediaConfig.no_vad = conf.get_bool(SIPPHONE_SECTION, 'media.no_vad', False)
    MediaConfig.ptime = conf.get_int(SIPPHONE_SECTION, 'media.ptime', 0)
    MediaConfig.quality = conf.get_int(SIPPHONE_SECTION, 'media.quality', 10)
    MediaConfig.rx_drop_pct = conf.get_int(SIPPHONE_SECTION,
                                           'media.rx_drop_pct', 0)
    MediaConfig.snd_auto_close_time = conf.get_int(
        SIPPHONE_SECTION, 'media.snd_auto_close_time', 5)
    MediaConfig.snd_clock_rate = conf.get_int(SIPPHONE_SECTION,
                                              'media.snd_clock_rate', 0)
    MediaConfig.turn_conn_type = conf.get_int(SIPPHONE_SECTION,
                                              'media.turn_conn_type', 17)
    #TODO: string to http://www.pjsip.org/python/pjsua.htm#AuthCred
    MediaConfig.turn_cred = None
    MediaConfig.turn_server = conf.get(SIPPHONE_SECTION, 'media.turn_server',
                                       '')
    MediaConfig.tx_drop_pct = conf.get_int(SIPPHONE_SECTION,
                                           'media.tx_drop_pct', 0)
    return MediaConfig
Exemple #6
0
        return acc.make_call(uri, cb=MyCallCallback())
    except pj.Error, e:
        log("Exception: " + str(e))
        return None


lib = pj.Lib()

try:
    ua_cfg = pj.UAConfig()

    loging_cfg = pj.LogConfig()
    loging_cfg.level = log_level
    loging_cfg.callback = log_cb

    media_cfg = pj.MediaConfig()
    if snd_clock_rate != -1:
        media_cfg.clock_rate = snd_clock_rate
    if ptime != -1:
        media_cfg.ptime = ptime
    if echo_cancel_type != -1:
        media_cfg.ec_options = echo_cancel_type
    if echo_cancel_tail != -1:
        media_cfg.ec_tail_len = echo_cancel_tail
    if quality != -1:
        media_cfg.quality = quality
    if channel_count != -1:
        media_cfg.channel_count = channel_count

    media_cfg.no_vad = no_vad
Exemple #7
0
    def __init__(self):
        super( Example,self ).__init__()
         
        self.initUI()
        lib = pj.Lib()

        current_call = None

        my_ua_cfg = pj.UAConfig()
        my_ua_cfg.nameserver = ['8.8.8.8', '8.8.4.4']
        my_ua_cfg.user_agent = "hanxiaotian_bupt"
        # http://www.pjsip.org/python/pjsua.htm#MediaConfig
        my_media_cfg = pj.MediaConfig()
        my_media_cfg.enable_ice = True
    
        #
        # Procedure: Initialize > Create Transpot > Start > Handle calls > Shutdown
        #

        # https://trac.pjsip.org/repos/wiki/Python_SIP/Settings#StartupandShutdown
        # Initialize the Library
        lib.init(ua_cfg=my_ua_cfg, media_cfg=my_media_cfg, log_cfg = pj.LogConfig(level=3, callback=log_cb))
    
        # Create One or More Transports
        transport = lib.create_transport(pj.TransportType.TCP, pj.TransportConfig())
        #transport = lib.create_transport(pj.TransportType.UDP, pj.TransportConfig(0))
        #transport = lib.create_transport(pj.TransportType.TLS, pj.TransportConfig(port=5060)) # SSL
        lib.set_null_snd_dev()

        # Starting the Library
        lib.start()
        lib.handle_events()

        #
        # Registration
        #
        acc_cfg = pj.AccountConfig()
        succeed = 0
        while (succeed == 0):
            print "---------------------------------------------------------------------"
            acc_cfg.id = "sip:[email protected]"
            # 
            acc_cfg.reg_uri  = "sip:10.103.241.142;transport=tcp"
            #
            acc_cfg.proxy = [] 
       
            server = "10.103.241.142"
            acc_cfg.proxy = [ "sip:10.103.241.142;transport=tcp;lr" ]
            #
            realm = "han"
            #
            username = "******"
            #
            passwd = "101"
            print "---------------------------------------------------------------------"
    
            acc_cfg.auth_cred = [pj.AuthCred(realm, username ,passwd)]
            
            self.acc_cb = MyAccountCallback()
            self.acc = lib.create_account(acc_cfg, cb=self.acc_cb)
            self.acc_cb.wait()
    
            # Conditions are not correct, because when "IP address change detected for account", all other accounts is Forbidden
            if ((str(self.acc.info().reg_status) == "200") or (str(self.acc.info().reg_status) == "403")):
                succeed = 1
            else:
                print ""
                print "Registration failed, status=", self.acc.info().reg_status, \
                  "(" + self.acc.info().reg_reason + ")"
                print ""
                print "Please try again !"
Exemple #8
0
def resetAll():
    global current_call
    global recorderid
    global playerid
    global call_slot
    current_call = None
    recorderid = None
    playerid = None
    call_slot = None


lib = pj.Lib()

try:
    mediaconfig = pj.MediaConfig()
    mediaconfig.quality = 10
    lib.init(log_cfg=pj.LogConfig(
        level=4, callback=log_cb), media_cfg=mediaconfig)
    transport = lib.create_transport(
        pj.TransportType.UDP, pj.TransportConfig())
    lib.start()

    # Put your sIP client credentials here
    acc = lib.create_account(pj.AccountConfig(
        "10.208.209.59", "1000", "1000"))

    acc_cb = MyAccountCallback(acc)
    acc.set_callback(acc_cb)
    acc_cb.wait()
Exemple #9
0
def main(argv):
    global broker
    global pj
    global lib
    global args

    app_name = "SIP2MQTT"

    parser = argparse.ArgumentParser(
        description=
        'A SIP monitoring tool that publishes incoming calls with CallerID to an MQTT channel'
    )
    requiredNamed = parser.add_argument_group('required named arguments')

    requiredNamed.add_argument("-a",
                               "--mqtt_domain",
                               type=str,
                               required=True,
                               help="the MQTT broker domain string",
                               default=os.environ.get('MQTT_DOMAIN', None))
    requiredNamed.add_argument("-t",
                               "--mqtt_port",
                               type=int,
                               required=True,
                               help="the MQTT broker port number",
                               default=os.environ.get('MQTT_PORT', None))
    parser.add_argument("--mqtt_keepalive",
                        type=int,
                        required=False,
                        help="the MQTT broker keep alive in seconds",
                        default=60)
    parser.add_argument("--mqtt_protocol",
                        type=str,
                        required=False,
                        help="the MQTT broker protocol",
                        default="MQTTv311",
                        choices=['MQTTv31', 'MQTTv311'])
    requiredNamed.add_argument("-u",
                               "--mqtt_username",
                               type=str,
                               required=True,
                               help="the MQTT broker username",
                               default=os.environ.get('MQTT_USERNAME', None))
    requiredNamed.add_argument("-p",
                               "--mqtt_password",
                               type=str,
                               required=False,
                               help="the MQTT broker password",
                               default=os.environ.get('MQTT_PASSWORD', None))
    parser.add_argument("--mqtt_topic",
                        type=str,
                        required=False,
                        help="the MQTT broker topic",
                        default=os.environ.get('MQTT_TOPIC', "home/sip"))

    requiredNamed.add_argument("-d",
                               "--sip_domain",
                               type=str,
                               required=True,
                               help="the SIP domain",
                               default=os.environ.get('SIP_DOMAIN', None))
    parser.add_argument("--sip_port",
                        type=int,
                        required=False,
                        help="the SIP transport port number",
                        default=os.environ.get('SIP_PORT', 5060))
    requiredNamed.add_argument("-n",
                               "--sip_username",
                               type=str,
                               required=True,
                               help="the SIP username",
                               default=os.environ.get('SIP_USERNAME', None))
    requiredNamed.add_argument("-s",
                               "--sip_password",
                               type=str,
                               required=False,
                               help="the SIP password",
                               default=os.environ.get('SIP_PASSWORD', None))
    parser.add_argument("--sip_display",
                        type=str,
                        required=False,
                        help="the SIP user display name",
                        default=app_name)

    parser.add_argument("--log_level",
                        type=int,
                        required=False,
                        help="the application log level",
                        default=3,
                        choices=[0, 1, 2, 3])
    parser.add_argument("-v",
                        "--verbosity",
                        action="count",
                        help="increase output verbosity",
                        default=3)

    args = parser.parse_args()

    log_level = logging.INFO  #Deault logging level
    if args.verbosity == 1:
        log_level = logging.ERROR
    elif args.verbosity == 2:
        log_level = logging.WARN
    elif args.verbosity == 3:
        log_level = logging.INFO
    elif args.verbosity >= 4:
        log_level = logging.DEBUG

    # Configure logging
    # logging.basicConfig(filename="sip2mqtt.log", format="%(asctime)s - %(levelname)s - %(message)s",
    #                     datefmt="%m/%d/%Y %I:%M:%S %p", level=log_level)
    root = logging.getLogger()
    root.setLevel(log_level)

    #    ch = logging.StreamHandler(sys.stdout)
    #    ch.setLevel(log_level)
    #    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    #    ch.setFormatter(formatter)
    #    root.addHandler(ch)
    # A more docker-friendly approach is to output to stdout
    logging.basicConfig(stream=sys.stdout,
                        format="%(asctime)s - %(levelname)s - %(message)s",
                        datefmt="%m/%d/%Y %I:%M:%S %p",
                        level=log_level)

    # Log startup messages and our configuration parameters
    logging.info("------------------------")
    logging.info("Starting up...")
    logging.info("--- MQTT Broker Configuration ---")
    logging.info("Domain: " + args.mqtt_domain)
    logging.info("Port: " + str(args.mqtt_port))
    logging.info("Protocol: " + args.mqtt_protocol)
    logging.info("Username: "******"Keepalive Interval: " + str(args.mqtt_keepalive))
    logging.info("Status Topic: " + args.mqtt_topic)
    logging.info("--- SIP Configuration ---")
    logging.info("Domain: " + args.sip_domain)
    logging.info("Username: "******"DisplayName: " + args.sip_display)

    try:
        # Handle mqtt connection and callbacks
        broker = mqtt.Client(client_id="",
                             clean_session=True,
                             userdata=None,
                             protocol=eval("mqtt." + args.mqtt_protocol))
        broker.username_pw_set(args.mqtt_username, password=args.mqtt_password)
        broker.on_connect = mqtt_connect
        #broker.on_message = mqtt_message #don't need this callback for now
        broker.connect(args.mqtt_domain, args.mqtt_port, args.mqtt_keepalive)

        # Create library instance of Lib class
        lib = pj.Lib()

        ua = pj.UAConfig()
        ua.user_agent = app_name

        mc = pj.MediaConfig()
        mc.clock_rate = 8000

        lib.init(ua_cfg=ua,
                 log_cfg=pj.LogConfig(level=args.verbosity, callback=None),
                 media_cfg=mc)
        lib.create_transport(pj.TransportType.UDP,
                             pj.TransportConfig(args.sip_port))
        lib.set_null_snd_dev()
        lib.start()

        acc_cfg = pj.AccountConfig()
        acc_cfg.id = "sip:" + args.sip_username + "@" + args.sip_domain
        acc_cfg.reg_uri = "sip:" + args.sip_domain
        acc_cfg.auth_cred = [
            pj.AuthCred(args.sip_domain, args.sip_username, args.sip_password)
        ]
        acc_cfg.allow_contact_rewrite = False

        acc = lib.create_account(acc_cfg)
        acc_cb = SMAccountCallback(acc)
        acc.set_callback(acc_cb)

        logging.info("-- Registration Complete --")
        logging.info('SIP: Status = ' + str(acc.info().reg_status) + ' (' +
                     acc.info().reg_reason + ')')

    except pj.Error, e:
        logging.critical(("Exception: " + str(e)))
        lib.destroy()
        sys.exit(1)
            if self.record == True:
                self.recorder_id = lib.create_recorder(
                    name_sound_file_for_call)
                print "Recorder id: " + str(self.recorder_id)
                self.recorder_slot_Id = lib.recorder_get_slot(self.recorder_id)
                lib.conf_connect(call_slot, self.recorder_slot_Id)
                print "Recording Call..."


try:
    print "Inside record-samples.py script"
    # Create library instance
    lib = pj.Lib()

    # Init library with default config
    med_conf = pj.MediaConfig()
    med_conf.clock_rate = CALL_SAMPLING_RATE
    med_conf.ec_options = 0
    med_conf.jb_max = 0
    med_conf.jb_min = 0
    med_conf.max_media_ports = 1020

    ua_config = pj.UAConfig()
    ua_config.max_calls = 1000

    lib.init(ua_cfg=ua_config,
             log_cfg=pj.LogConfig(level=7, callback=log_cb),
             media_cfg=med_conf)
    # Remedy the non availibility of sound device
    lib.set_null_snd_dev()
Exemple #11
0
class SIPCallRecordVerify:
    ua_cfg = pj.UAConfig()
    ua_cfg.max_calls = 10
    ua_cfg.nameserver = ["8.8.8.8"]
    ua_cfg.user_agent = "SIPCallRecordVerify"

    media_cfg = pj.MediaConfig()
    media_cfg.channel_count = 8
    media_cfg.max_media_ports = 8

    def __init__(self, caller, calling, log_level=3):
        self.verify = Verify()
        if not self.verify.setup():
            sys.exit(1)
        self.lib = pj.Lib()
        self.lib.init(
            ua_cfg=self.ua_cfg,
            log_cfg=pj.LogConfig(
                level=7,
                callback=lambda level, str, len: logging.debug(str.strip())),
            media_cfg=self.media_cfg)
        self.lib.start(with_thread=True)
        self.caller_ddi, self.caller_account, self.caller_cb, self.caller_cfg = self.register(
            caller, default=True)
        self.calling_ddi, self.calling_account, self.calling_cb, self.calling_cfg = self.register(
            calling)

    def register(self, config, default=False):
        for k, v in config.iteritems():
            config[k] = str(v)
        ddi = config['ddi']
        logging.info("Creating transport for %s" % (config['uri']))
        transport = self.lib.create_transport(pj.TransportType.UDP)
        logging.info(
            "Listening on %s:%d for %s" %
            (transport.info().host, transport.info().port, config['uri']))
        logging.info("Attempting registration for %s" % config['uri'])
        account_cfg = pj.AccountConfig(domain=config['domain'],
                                       username=config['username'],
                                       password=config['password'],
                                       proxy=config['proxy'])
        account_cfg.id = config['uri']
        account = self.lib.create_account(acc_config=account_cfg,
                                          set_default=default)
        account.set_transport(transport)
        account_cb = AccountHandler(account)
        account.set_callback(account_cb)
        account_cb.wait()
        logging.info("%s registered, status: %s (%s)" %
                     (config['uri'], account.info().reg_status,
                      account.info().reg_reason))
        return (ddi, account, account_cb, account_cfg)

    def start_caller(self, audiotest, interval=300):
        try:
            call = None
            end = time.time() + interval
            while True:
                if call:
                    while call.is_valid():
                        logging.info("Call in progress")
                        sleep(1)
                        continue
                remaining = end - time.time()
                logging.info("Seconds until next call: %d" % remaining)
                if time.time() <= end:
                    sleep(1)
                    continue
                end = time.time() + interval
                logging.info("Making call")
                call, callhandler = self.caller_cb.new_call(
                    "%s@%s" %
                    (self.calling_ddi, self.caller_cfg.proxy[0][4:-3]))
                if call:
                    while call.info().state != pj.CallState.CONFIRMED:
                        logging.info("Looping call state check with %s" %
                                     call.info().state)
                        sleep(1)
                        continue
                    sleep(1)
                    callhandler.play_file(audiotest['filename'], True)
                    # TODO: Fetch recording, convert to text, validate.
                    sleep(1)
                    call.hangup()
                sleep(1)
        except pj.Error, e:
            logging.error("Exception: " + str(e))
Exemple #12
0
            current_call = None

    # Notification when call's media state change
    def on_media_state(self):
        global lib
        if self.call.info().media_state == pj.MediaState.ACTIVE:
            # Connect the call to sound device
            call_slot = self.call.info().conf_slot
            lib.conf_connect(call_slot, 0)
            lib.conf_connect(0, call_slot)


try:
    sipcfg = config.get_sipcfg()  # Get PBX/SIP auth credentials
    speedial = config.get_speedial()  # Get Speed Dial Extensions
    media = pj.MediaConfig()  # Media Config
    media.ec_options = 0  # pjsua default 0
    media.ec_tail_len = 256  # pjsua default 256
    media.no_vad = False  # disable Voice Activity Detector
    media.enable_ice = True  # Enable (ICE) Interactive Connectivity Establishment
    lib = pj.Lib()  # Create pjsua library instance
    # Init pjsua with default config
    lib.init(log_cfg=pj.LogConfig(level=LOG_LEVEL, callback=log_cb))
    # Set sound device TODO in vc.py
    # lib.set_snd_dev(0,0)
    # Create UDP transport which listens to any available port
    transport = lib.create_transport(pj.TransportType.UDP)
    # Start the library
    lib.start()
    if sipcfg is None:
        # Create local/user-less account
Exemple #13
0
class Softphone:

    ua_cfg = pj.UAConfig()
    log_cfg = pj.LogConfig()
    log_cfg.callback = lambda level, str, len: logger.info(str.strip())
    media_cfg = pj.MediaConfig(
    )  # look at the options it takes: https://www.pjsip.org/python/pjsua.htm#MediaConfig

    def __init__(
            self,
            max_calls=1,  # TODO: Add support for multiple simultaneous calls.
            nameserver=['1.1.1.1'],
            user_agent='Python Softphone',
            log_level=5,
            sample_rate=48000,
            duration_ms=20,
            channel_count=2,
            max_media_ports=8,
            thread=True):
        """
        :param max_calls: Integer - Maximum simultaneous calls.
        :param nameserver: List - A list of DNS server(s) to use.
        :param user_agent: String - User-agent.
        :param log_level: Integer - Level to use for the logger.
        :sample_rate: Integer - Sample rate (hz) to capture and playback audio.
        :duration_ms: Integer - Milliseconds per audio frame.
        :channel_count: Integer - Number of channels to use. 1 for Mono, 2 for Stereo.
        :max_media_ports: Integer - PJSIP maximum media ports.
        :thread: Boolean - Use a threaded instance of softphone.
        """

        self.pid = os.getpid()

        # Media config
        self.media_cfg.clock_rate = sample_rate
        self.media_cfg.channel_count = channel_count

        #self.media_cfg.snd_clock_rate = sample_rate# Clock rate to be applied when opening the sound device. If value is zero, conference bridge clock rate will be used.
        self.media_cfg.audio_frame_ptime = duration_ms  # Default: 20 ms audio data
        #self.media_cfg.no_vad = True # disable voice activation detection
        #self.media_cfg.enable_ice = False
        self.media_cfg.max_media_ports = max_media_ports

        # User-agent config
        self.ua_cfg.max_calls = max_calls
        self.ua_cfg.nameserver = nameserver
        self.ua_cfg.user_agent = user_agent

        # Log config
        self.log_cfg.level = log_level

        # Lib settings (put this in run() instead when using multiprocessing.Process)
        self.lib = pj.Lib()  # Singleton instance
        self.lib.init(ua_cfg=self.ua_cfg,
                      log_cfg=self.log_cfg,
                      media_cfg=self.media_cfg)
        self.lib.start(with_thread=thread)

        # Playback / Recording varaibles
        self.player = None
        self.recorder = None

        # Stream callback id and slot
        self.audio_cb_id = None
        self.audio_cb_slot = None

        # Call variables
        self.call_handler = True
        self.current_call = None

        logger.info(f"Object created.")

    def __del__(self):
        self.lib.destroy()
        logger.info(f"Object destroyed.")

    def register(self,
                 server,
                 port,
                 username,
                 password,
                 default_account=False,
                 proxy=None,
                 protocol='UDP',
                 bind_address='127.0.0.1',
                 bind_port=0):
        """ Register an account at i.e. Asterisk PBX, and set network transport options.
            Returns: Account registered, account callback handler.
        """
        if protocol == 'UDP': protocol = pj.TransportType.UDP
        elif protocol == 'TCP': protocol = pj.TransportType.TCP
        elif protocol == 'TLS': protocol = pj.TransportType.TLS
        else: logger.info(f"Error: Invalid protocol type.")

        logger.info("Creating transport and generating SIP URI.")
        transport = self.lib.create_transport(
            protocol,
            pj.TransportConfig(
                0
            )  # TransportConfig(host=bind_address, port=bind_port) # TODO: Add bind_address and bind_port here.
        )

        public_sip_uri = f"sip:{username}@{str(transport.info().host)}:{str(transport.info().port)}"
        logger.info(
            f"Listening on {transport.info().host}:{transport.info().port} for {public_sip_uri}."
        )
        logger.info(
            f"Attempting registration for {public_sip_uri} at {server}:{port}."
        )

        account_cfg = pj.AccountConfig(domain=server + ":" + port,
                                       username=username,
                                       password=password)

        account_cfg.id = public_sip_uri

        account = self.lib.create_account(acc_config=account_cfg,
                                          set_default=default_account)
        account.set_transport(transport)

        account_handler = AccountHandler(lib=self.lib, account=account)
        account.set_callback(account_handler)

        logger.info(f"Waiting for registration...")
        account_handler.wait()
        logger.info(
            f"Successfully registered {public_sip_uri}, status: {account.info().reg_status} ({account.info().reg_reason})."
        )

        return account

    def unregister(self, account):
        """ Unregister a registered account.
        """
        logger.info(
            f"Attempting to unregister account by deletion: {account}.")
        account.delete()
        logger.info(f"Successfully unregistered and deleted account.")

    def call(self, account, sip_uri):
        """ Make a new outgoing call to sip_uri from SIP account.
        """
        try:
            if self.current_call:
                logger.info(f"Already have a call.")
                return

            if self.lib.verify_sip_url(sip_uri) != 0:
                logger.info(f"Invalid SIP URI.")
                return

            logger.info(f"Attempting new call to {sip_uri}")
            lck = self.lib.auto_lock()  # To prevent deadlocks

            call_handler = CallHandler(lib=self.lib,
                                       audio_cb_slot=self.audio_cb_slot)
            self.current_call = account.make_call(sip_uri, cb=call_handler)
            logger.info(f"Current call is {self.current_call}.")
            del lck

        except pj.Error as e:
            logger.info(f"Error: {e}")
            self.current_call = None
            self.lib.destroy()

    def end_call(self):
        """ Hang up an ongoing call for SIP account.
        """
        try:
            if not self.current_call:
                logger.info("There is no call.")
                return

            if not self.current_call.is_valid(
            ):  # Is this needed? Used by g-farrow, but might be handled already.
                logger.info("Call has already ended.")
                return

            self.current_call.hangup()
            self.current_call = None
            logger.info(f"Call ended.")

        except pj.Error as e:
            logger.info(f"Error: {e}")

    def wait_for_active_audio(self):
        """ Wait until call audio is activated.
        """
        while self.current_call.info().media_state != pj.MediaState.ACTIVE:
            time.sleep(0.5)

    def wait_for_confirmed_call(self):
        """ Wait until call has been confirmed.
        """
        while self.current_call.info().state != pj.CallState.CONFIRMED:
            time.sleep(0.5)

    def get_call_length(self):
        """ Get the length of the current call in seconds. 
        :return call_length, total_length: Tuple (Call Connection length (seconds), Total Length (seconds))
        """
        if not self.current_call:
            raise PhoneCallNotInProgress("The call does not exist")

        call_length = self.current_call.info().call_time
        total_length = self.current_call.info().total_time
        logger.info(
            "Call duration information: connection '{call_length}' second(s), total '{total_length}' second(s)."
        )

        return call_length, total_length

    def send_dtmf_key_tones(self, digits):
        """ Send DTMF keypad tones to the call.
        :param digits: String - Digits to send over the call
        """
        logger.debug("Sending DTMF key tones: '{digits}'")
        self.current_call.dial_dtmf(digits)
        logger.debug("DTMF tones sent")

    def get_sound_devices(self):
        """ Get a detailed list of available sound devices.
            Returns a list of available sound devices.
        """
        sounddevices = []

        snd_devs = self.lib.enum_snd_dev()

        i = 0
        for snd_dev in snd_devs:
            dev = {}
            dev['index'] = i
            dev['name'] = snd_dev.name
            dev['input_channels'] = snd_dev.input_channels
            dev['output_channels'] = snd_dev.output_channels
            dev['sample_rate'] = snd_dev.default_clock_rate
            sounddevices.append(dev)
            i += 1

        return sounddevices

    def set_null_sound_device(self):
        """ Set NULL sound device / Do not use system audio device.
        """
        self.lib.set_null_snd_dev()
        logger.info(f"Using NULL sound device.")

    def get_capture_device(self):
        """ Get capture device ID currently in use.
        """
        capture_id, playback_id = self.lib.get_snd_dev()
        return capture_id

    def set_capture_device(self, capture_id):
        """ Set capture device ID to be used.
        """
        _, playback_id = self.lib.get_snd_dev()
        self.lib.set_snd_dev(capture_id, playback_id)
        logger.info(f"Capture device set to: {capture_id}")

    def get_playback_device(self):
        """ Get playback device ID currently in use.
        """
        capture_id, playback_id = self.lib.get_snd_dev()
        return playback_id

    def set_playback_device(self, playback_id):
        """ Set playback device ID to be used.
        """
        capture_id, _ = self.lib.get_snd_dev()
        self.lib.set_snd_dev(capture_id, playback_id)
        logger.info(f"Playback device set to: {playback_id}")

    def capture(self, file_name):
        """ Save call audio to WAV file.
        """
        if os.path.exists(file_name):
            raise FileExistsError(
                "A file with this name already exists: {file_name}")

        self.recorder = self.lib.create_recorder(file_name)
        recorder_slot = self.lib.recorder_get_slot(self.recorder)
        #self.lib.conf_connect(recorder_slot, self.current_call.info().conf_slot) # not needed? or?
        self.lib.conf_connect(self.current_call.info().conf_slot,
                              recorder_slot)
        logger.info(f"Started audio capture.")

    def stop_capturing(self):
        """ Stop capturing call audio to file
        """
        recorder_slot = self.lib.recorder_get_slot(self.recorder)
        self.lib.conf_disconnect(self.current_call.info().conf_slot,
                                 recorder_slot)
        self.lib.recorder_destroy(self.recorder)
        self.recorder = None
        logger.info(f"Stopped audio capture.")

    def playback(self, file_name):
        """ Playback a WAV file into call.
        :param file_path: String - path to the audio (WAV) file to be played to the call.
        """
        if not os.path.exists(file_name):
            raise FileNotFoundError("Cannot find audio file: {file_name}")

        if not os.path.isfile(file_name):
            raise FileNotFoundError(
                "The audio file is not a file: {file_path}")

        self.player = self.lib.create_player(file_name)
        player_slot = self.lib.player_get_slot(self.player)
        self.lib.conf_connect(player_slot, self.current_call.info().conf_slot)
        logger.info(f"Started audio playback.")

    def stop_playback(self):
        """ Stop playing audio file to call
        """
        player_slot = self.lib.player_get_slot(self.player)
        self.lib.conf_disconnect(player_slot,
                                 self.current_call.info().conf_slot)
        self.lib.player_destroy(self.player)
        self.player = None
        logger.info(f"Stopped audio playback.")

    def create_audio_stream(self, audio_callback):
        self.audio_cb_id = self.lib.create_audio_cb(audio_callback)
        self.audio_cb_slot = self.lib.audio_cb_get_slot(self.audio_cb_id)
        logger.info(f"Created audio callback.")

    def destroy_audio_stream(self):
        self.lib.audio_cb_destroy(self.audio_cb_id)
        self.audio_cb_id = None
        self.audio_cb_slot = None
        logger.info(f"Destroyed audio callback.")
Exemple #14
0
    auth_login = sys.argv[6]
    if len(sys.argv) > 7:
        auth_pass = sys.argv[7]
    else:
        auth_pass = ""
else:
    auth = False

try:
    global current_account
    global current_call
    global player
    global result

    # library 
    mc  = pj.MediaConfig()
    mc.clock_rate = 16000
    lib = pj.Lib()
    lib.init(log_cfg = pj.LogConfig(level=0, callback=log_cb),media_cfg=mc)
    # no sound device 
    lib.set_null_snd_dev()
    lib.set_codec_priority('G722/16000/1', 0 )
    lib.set_codec_priority('iLBC/8000/1', 0 )
    lib.set_codec_priority('PCMA/8000/1', 190 )
    lib.set_codec_priority('PCMU/8000/1', 180 )

    # no account active
    current_account = None
    # no call active
    current_call = None
    # nothing to play
Exemple #15
0
        def __init__(self):
            self.media = pj.MediaConfig()
            #self._load_config(self.media, "media")

            self.buddies = []