Beispiel #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)
Beispiel #2
0
    def init(self):
        """Initialize global pjsip library.
        General codec and device configuration should be done here.
        """
        try:
            # Get log level from command line
            log_level = Settings().verbose
            nameserver = Settings().nameserver
            if nameserver:
                ua_cfg = pjsua.UAConfig()
                ua_cfg.nameserver = Settings().nameserver
            else:
                ua_cfg = None

            # Initializa PJSUA
            self.lib = pjsua.Lib()
            self.lib.init(log_cfg=pjsua.LogConfig(level=log_level, callback=self.pjlog_cb), ua_cfg=ua_cfg)

            if Settings().transport == 'tcp':
                self.transport_tcp = self.lib.create_transport(pjsua.TransportType.TCP)
            elif Settings().transport == 'tls':
                self.transport_tls = self.lib.create_transport(pjsua.TransportType.TLS)
            else:
                self.transport_udp = self.lib.create_transport(pjsua.TransportType.UDP)

            self.lib.set_null_snd_dev()
            self.lib.start()
        except pjsua.Error, e:
            self.lib.destroy()
            print "Exception: " + str(e)
Beispiel #3
0
    def initLib(self):
        try:
            self.lib = pj.Lib()
        except:
            raise UnrecoverableFailure

        uaconfig = pj.UAConfig()
        #uaconfig.stun_host = STUN_SERVER
        if self.account:
            if self.account.has_key('useragent'):
                uaconfig.user_agent = self.account['useragent']

        def log_cb(lvl, str, len):
            pass
            print str

        try:
            self.lib.init(ua_cfg=uaconfig,
                          log_cfg=pj.LogConfig(level=5, callback=log_cb))
            self.lib.create_transport(pj.TransportType.TCP)
            self.lib.start()
        except:
            raise UnrecoverableFailure

        self.broadcastStatus(CONNECTING)
        self.accountResolver = AccountResolver(self.callback_accountsRetrieved,
                                               clientid=None)
Beispiel #4
0
    def __ami_connect(self, ami):
        """
        Handler for when AMI has started.

        We use AMI connection as the signal to start creating PJSUA accounts
        and starting PJLIB.
        """
        self.ami_connected += 1
        if (self.ami_connected < len(self.test_object.ami)):
            LOGGER.info("{0} ami connected. Waiting for "
                        "{1}".format(self.ami_connected,
                                     len(self.test_object.ami)))
            return

        ua_cfg = pj.UAConfig()
        ua_cfg.max_calls = self.max_calls
        self.lib = pj.Lib()
        try:
            self.lib.init(ua_cfg=ua_cfg)
            self.__create_transports()
            self.lib.set_null_snd_dev()
            self.__create_accounts()
            self.lib.start()
        except pj.Error, exception:
            LOGGER.error("Exception: " + str(exception))
            self.lib.destroy()
            self.lib = None
            self.test_object.stop_reactor()
Beispiel #5
0
def create_UAConfig():
    logger.debug("create_UAConfig")
    # Doc: http://www.pjsip.org/python/pjsua.htm#UAConfig
    UAConfig = pj.UAConfig()
    UAConfig.max_calls = conf.get_int(SIPPHONE_SECTION, 'ua.max_calls', 1)
    UAConfig.nameserver = conf.get_list(SIPPHONE_SECTION, 'ua.nameserver', [])
    UAConfig.stun_domain = conf.get(SIPPHONE_SECTION, 'ua.stun_domain', '')
    UAConfig.stun_host = conf.get(SIPPHONE_SECTION, 'ua.stun_host', '')
    UAConfig.user_agent = 'DoorPi'
    return UAConfig
    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()
Beispiel #7
0
 def __init__(self,lib=None):
     if lib:
         self.lib=lib
     elif pj.Lib.instance():
         self.lib=pj.Lib.instance()
     else:
         self.lib = pj.Lib()
         ua=pj.UAConfig()
         ua.max_calls=40
         self.lib.init(log_cfg = pj.LogConfig(level=2,callback=log_cb),ua_cfg=ua)  
         self._transport=self.lib.create_transport(pj.TransportType.UDP, pj.TransportConfig(0))
         self.lib.start()  
     devs=self.lib.enum_snd_dev()
     if not len(devs):
         self.lib.set_null_snd_dev()
     self.player=Player()
     self.created={}
Beispiel #8
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
Beispiel #9
0
 def start_pjsip(self):
     self.domain = None
     self.account = None
     self.lib = pj.Lib()
     ua_cfg = pj.UAConfig()
     ua_cfg.max_calls = 3000
     ua_cfg.user_agent = 'WebAutoDialer'
     self.lib.init(ua_cfg=ua_cfg,
                   log_cfg=pj.LogConfig(level=5, callback=self._log_cb))
     self.lib.start()
     log.info('Started PJSIP library with maximum calls number ' +
              str(ua_cfg.max_calls))
     codecs = self.lib.enum_codecs()
     for codec in codecs:
         #adjust codecs priorities
         codec_priority = codec.priority
         if 'G729' in codec.name or 'PCMA' in codec.name:
             codec_priority = 255
             self.lib.set_codec_priority(codec.name, codec_priority)
         log.info('Codec name ' + codec.name + ', priority ' +
                  str(codec_priority))
Beispiel #10
0
            log("Media are closed...")


def make_call(uri):
    try:
        log("Making call to:" + uri)
        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:
Beispiel #11
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 !"
Beispiel #12
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)

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()

    # Create UDP transport which listens to any available port
    transport = lib.create_transport(pj.TransportType.UDP,
                                     pj.TransportConfig(VOIP_SERVER_PORT))

    RECORDING = True
    lib.start()
Beispiel #14
0
            player_slot = lib.player_get_slot(self._player)
            #lib.conf_connect(call_slot, 0)
            #lib.conf_connect(0, call_slot)
            lib.conf_connect(player_slot, call_slot)
            #lib.conf_connect(call_slot, player_slot)
            lib.conf_connect(player_slot, 0)
            print "Hello world, I can talk!"


# Check command line argument
if len(sys.argv) != 4:
    print "Usage: call.py <dst-URI> <ext> <pass>"
    sys.exit(1)

try:
    uc = pj.UAConfig()
    #uc.max_calls = 20
    # Create library instance
    lib = pj.Lib()

    # Init library with default config
    log_config = pj.LogConfig(level=5, callback=log_cb)
    log_config.msg_logging = False
    lib.init(ua_cfg=uc, log_cfg=log_config)

    # Create UDP transport which listens to any available port
    transport = lib.create_transport(pj.TransportType.UDP)

    # Start the library
    lib.start()
Beispiel #15
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))
Beispiel #16
0
    # Notification when call's media state has changed.
    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:
    # Create library instance
    lib = pj.Lib()

    # Create a user agent
    ua = pj.UAConfig()
    ua.max_calls = 100
    ua.user_agent = sys.argv[0]

    # Init library with default config
    lib.init(ua)

    # Create UDP transport which listens to any available port
    transport = lib.create_transport(pj.TransportType.UDP)

    # Start the library
    lib.start()

    # Create local/user-less account
    acc = lib.create_account(pj.AccountConfig(
        config.get("account", "domain"),
Beispiel #17
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.")
Beispiel #18
0
        lib = None
        print('Destroyed')
    else:
        print('Already destroyed')


atexit.register(pjLibDestroy)

print('Making configuration...')
logingConfiguration = pj.LogConfig()
logingConfiguration.console_level = 6
logingConfiguration.level = 6
logingConfiguration.filename = '/tmp/pj.log'
#logingConfiguration.callback=log_cb

pjUAconfig = pj.UAConfig()
pjUAconfig.max_calls = 20
pjUAconfig.user_agent = 'Yealink SIP-T29G 46.80.0.125'
#pjUAconfig.user_agent = 'Tadiran SIP-T328P 2.72.19.4 00:15:65:50:81:1b'
#listenAddr = str(os.environ.get('TC_EXT_TRUNK_IP'))
listenAddr = config.testConfigJson['SystemVars'][0]['%%IP%%']
#listenAddr = '192.168.118.12'

print('Init lib pj...')
try:
    lib.init(ua_cfg=pjUAconfig, log_cfg=logingConfiguration)
except pj.Error as e:
    print('Lib pjsua init exception: ' + str(e))
    #pjLibDestroy()
    sys.exit(1)