SIP решения на основе библиотеки PJSIP

Материал из M-200 WIKI
(Различия между версиями)
Перейти к: навигация, поиск
 
(не показана 1 промежуточная версия 1 участника)
Строка 10: Строка 10:
 
Пример сделан из примера к самой библиотеке.
 
Пример сделан из примера к самой библиотеке.
  
<code>
+
<tt>
#coding=utf8
+
#coding=utf8
# $Id: call.py 2171 2008-07-24 09:01:33Z bennylp $
+
# $Id: call.py 2171 2008-07-24 09:01:33Z bennylp $
#
+
#
# SIP call sample.
+
# SIP call sample.
#
+
#
# Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+
# Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
#
+
#
# This program is free software; you can redistribute it and/or modify
+
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
+
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
+
# (at your option) any later version.
#
+
#
# This program is distributed in the hope that it will be useful,
+
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
+
# GNU General Public License for more details.
#
+
#
# You should have received a copy of the GNU General Public License
+
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
+
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
#
+
#
import sys
+
import sys
import pjsua as pj
+
import pjsua as pj
import threading
+
import threading
 
+
LOG_LEVEL=0
+
LOG_LEVEL=0
current_call = None
+
current_call = None
 
+
# Logging callback
+
# Logging callback
def log_cb(level, str, len):
+
def log_cb(level, str, len):
 
     print str,
 
     print str,
 
+
 
 
+
# Callback to receive events from account
+
# Callback to receive events from account
class MyAccountCallback(pj.AccountCallback):
+
class MyAccountCallback(pj.AccountCallback):
 
+
 
     def __init__(self, account=None):
 
     def __init__(self, account=None):
 
         pj.AccountCallback.__init__(self, account)
 
         pj.AccountCallback.__init__(self, account)
 
+
 
     # уведомление о входящем вызове
 
     # уведомление о входящем вызове
 
     def on_incoming_call(self, call):
 
     def on_incoming_call(self, call):
Строка 59: Строка 59:
 
         print "Incoming call from ", call.info().remote_uri
 
         print "Incoming call from ", call.info().remote_uri
 
         print "Press 'a' to answer"
 
         print "Press 'a' to answer"
 
+
 
         current_call = call
 
         current_call = call
 
+
 
         call_cb = callCallbackIn(current_call)
 
         call_cb = callCallbackIn(current_call)
 
         current_call.set_callback(call_cb)
 
         current_call.set_callback(call_cb)
 
+
 
         # отвечаем call progressом
 
         # отвечаем call progressом
 
         current_call.answer(183)
 
         current_call.answer(183)
 
+
 
     def wait(self):
 
     def wait(self):
 
         self.sem = threading.Semaphore(0)
 
         self.sem = threading.Semaphore(0)
 
         self.sem.acquire()
 
         self.sem.acquire()
 
+
 
     def on_reg_state(self):
 
     def on_reg_state(self):
 
         if self.sem:
 
         if self.sem:
 
             if self.account.info().reg_status >= 200:
 
             if self.account.info().reg_status >= 200:
 
                 self.sem.release()
 
                 self.sem.release()
 
+
 
          
 
          
# Сообщение от входящего вызова
+
# Сообщение от входящего вызова
class callCallbackIn(pj.CallCallback):
+
class callCallbackIn(pj.CallCallback):
 
+
 
     def __init__(self, call=None):
 
     def __init__(self, call=None):
 
         pj.CallCallback.__init__(self, call)
 
         pj.CallCallback.__init__(self, call)
 
+
 
     # уведомление об изменении состояния
 
     # уведомление об изменении состояния
 
     def on_state(self):
 
     def on_state(self):
Строка 91: Строка 91:
 
         print "last code =", self.call.info().last_code,  
 
         print "last code =", self.call.info().last_code,  
 
         print "(" + self.call.info().last_reason + ")"
 
         print "(" + self.call.info().last_reason + ")"
 
+
 
         # в предответном проключаем одну мелодию
 
         # в предответном проключаем одну мелодию
 
         if self.call.info().state == pj.CallState.EARLY:
 
         if self.call.info().state == pj.CallState.EARLY:
Строка 100: Строка 100:
 
             # проключаем канал плеера на разговор
 
             # проключаем канал плеера на разговор
 
             pj.Lib.instance().conf_connect(self.wav_slot, call_slot)
 
             pj.Lib.instance().conf_connect(self.wav_slot, call_slot)
 
+
 
         # в разговорном подаем другую
 
         # в разговорном подаем другую
 
         if self.call.info().state == pj.CallState.CONFIRMED:
 
         if self.call.info().state == pj.CallState.CONFIRMED:
Строка 117: Строка 117:
 
             current_call = None
 
             current_call = None
 
             print 'Current call is', current_call
 
             print 'Current call is', current_call
 
+
 
     # уведомление об изменении состояния системы коммутации
 
     # уведомление об изменении состояния системы коммутации
 
     def on_media_state(self):           
 
     def on_media_state(self):           
Строка 124: Строка 124:
 
         else:
 
         else:
 
             print "Media is inactive"
 
             print "Media is inactive"
 
+
# Сообщение от исходящего вызова
+
# Сообщение от исходящего вызова
class callCallbackOut(pj.CallCallback):
+
class callCallbackOut(pj.CallCallback):
 
+
 
     def __init__(self, call=None):
 
     def __init__(self, call=None):
 
         pj.CallCallback.__init__(self, call)
 
         pj.CallCallback.__init__(self, call)
 
+
 
     # уведомление об изменении состояния
 
     # уведомление об изменении состояния
 
     def on_state(self):
 
     def on_state(self):
Строка 138: Строка 138:
 
         print "last code =", self.call.info().last_code,  
 
         print "last code =", self.call.info().last_code,  
 
         print "(" + self.call.info().last_reason + ")"
 
         print "(" + self.call.info().last_reason + ")"
 
+
 
         # в разговорном подаем другую
 
         # в разговорном подаем другую
 
         if self.call.info().state == pj.CallState.CONFIRMED:
 
         if self.call.info().state == pj.CallState.CONFIRMED:
Строка 148: Строка 148:
 
             pj.Lib.instance().conf_connect(self.wav_slot, call_slot)
 
             pj.Lib.instance().conf_connect(self.wav_slot, call_slot)
 
            
 
            
 
+
 
         if self.call.info().state == pj.CallState.DISCONNECTED:
 
         if self.call.info().state == pj.CallState.DISCONNECTED:
 
             current_call = None
 
             current_call = None
 
             print 'Current call is', current_call
 
             print 'Current call is', current_call
 
+
 
     # уведомление об изменении состояния системы коммутации
 
     # уведомление об изменении состояния системы коммутации
 
     def on_media_state(self):           
 
     def on_media_state(self):           
Строка 159: Строка 159:
 
         else:
 
         else:
 
             print "Media is inactive"
 
             print "Media is inactive"
 
+
 
+
 
+
# Function to make call
+
# Function to make call
def make_call(uri):
+
def make_call(uri):
 
     try:
 
     try:
 
         print "Making call to", uri
 
         print "Making call to", uri
Строка 171: Строка 171:
 
         return None
 
         return None
 
          
 
          
 
+
# Create library instance
+
# Create library instance
lib = pj.Lib()
+
lib = pj.Lib()
 
+
try:
+
try:
 
     my_media_cfg = pj.MediaConfig()
 
     my_media_cfg = pj.MediaConfig()
 
     my_media_cfg.clock_rate = 8000
 
     my_media_cfg.clock_rate = 8000
Строка 183: Строка 183:
 
     my_media_cfg.ptime = 0
 
     my_media_cfg.ptime = 0
 
     my_media_cfg.max_media_ports = 4
 
     my_media_cfg.max_media_ports = 4
 
+
 
      
 
      
 
     # Init library with default config and some customized
 
     # Init library with default config and some customized
 
     # logging config.
 
     # logging config.
 
     lib.init(log_cfg = pj.LogConfig(level=LOG_LEVEL, callback=log_cb), media_cfg = my_media_cfg)
 
     lib.init(log_cfg = pj.LogConfig(level=LOG_LEVEL, callback=log_cb), media_cfg = my_media_cfg)
 
+
 
+
 
+
 
     # Create UDP transport which listens to any available port
 
     # Create UDP transport which listens to any available port
 
     transport = lib.create_transport(pj.TransportType.UDP, pj.TransportConfig(5060))
 
     transport = lib.create_transport(pj.TransportType.UDP, pj.TransportConfig(5060))
Строка 198: Строка 198:
 
     # Start the library
 
     # Start the library
 
     lib.start()
 
     lib.start()
 
+
 
     # Create local account
 
     # Create local account
 
     acc = lib.create_account(pj.AccountConfig("192.168.5.48", "7000", "7000"))
 
     acc = lib.create_account(pj.AccountConfig("192.168.5.48", "7000", "7000"))
 
+
 
     acc_cb = MyAccountCallback(acc)
 
     acc_cb = MyAccountCallback(acc)
 
     acc.set_callback(acc_cb)
 
     acc.set_callback(acc_cb)
 
     acc_cb.wait()
 
     acc_cb.wait()
 
+
 
     print "\n"
 
     print "\n"
 
     print "Registration complete, status=", acc.info().reg_status, \
 
     print "Registration complete, status=", acc.info().reg_status, \
 
           "(" + acc.info().reg_reason + ")"
 
           "(" + acc.info().reg_reason + ")"
 
+
 
+
 
     my_sip_uri = "sip:" + transport.info().host + \
 
     my_sip_uri = "sip:" + transport.info().host + \
 
                 ":" + str(transport.info().port)
 
                 ":" + str(transport.info().port)
 
+
 
     # Menu loop
 
     # Menu loop
 
     while True:
 
     while True:
 
         print "My SIP URI is", my_sip_uri
 
         print "My SIP URI is", my_sip_uri
 
         print "Menu:  m=make call, h=hangup call, a=answer call, c=call 407, q=quit"
 
         print "Menu:  m=make call, h=hangup call, a=answer call, c=call 407, q=quit"
 
+
 
         input = sys.stdin.readline().rstrip("\r\n")
 
         input = sys.stdin.readline().rstrip("\r\n")
 
         if input == "m":
 
         if input == "m":
Строка 231: Строка 231:
 
             current_call = make_call(input)
 
             current_call = make_call(input)
 
             del lck
 
             del lck
 
+
 
         elif input == "h":
 
         elif input == "h":
 
             if not current_call:
 
             if not current_call:
Строка 237: Строка 237:
 
                 continue
 
                 continue
 
             current_call.hangup()
 
             current_call.hangup()
 
+
 
         elif input == "a":
 
         elif input == "a":
 
             if not current_call:
 
             if not current_call:
Строка 243: Строка 243:
 
                 continue
 
                 continue
 
             current_call.answer(200)
 
             current_call.answer(200)
 
+
 
         elif input == "c":
 
         elif input == "c":
 
             lck = lib.auto_lock()
 
             lck = lib.auto_lock()
 
             current_call = make_call("sip:100@192.168.5.48")
 
             current_call = make_call("sip:100@192.168.5.48")
 
             del lck
 
             del lck
 
+
 
         elif input == "q":
 
         elif input == "q":
 
             break
 
             break
 
+
 
     # Shutdown the library
 
     # Shutdown the library
 
     transport = None
 
     transport = None
Строка 258: Строка 258:
 
     lib.destroy()
 
     lib.destroy()
 
     lib = None
 
     lib = None
 
+
except pj.Error, e:
+
except pj.Error, e:
 
     print "Exception: " + str(e)
 
     print "Exception: " + str(e)
 
     lib.destroy()
 
     lib.destroy()
 
     lib = None
 
     lib = None
 
+
</code>
+
</tt>
  
 
[[Категория:SIP]]
 
[[Категория:SIP]]
 
[[Категория:М-200. Разработка]]
 
[[Категория:М-200. Разработка]]

Текущая версия на 11:38, 24 декабря 2014

Иногда имеется необходимость реализовать какой нибудь дополнительный функционал для клиентов АТС М-200.С появлением IP телефонии стало возможно доставлять голосовую информацию как от пользователя, так и к пользователю.

Так как М-200 поддерживает протокол SIP есть интересная библиотека реализации SIP стека и Media интерфейса http://www.pjsip.org/. По мимо реализации библиотеки на классическом С, есть обертка для языка Python. PJSIP может работать по Linux, MAC, Linux платформами. Библиотека распространяется под лицензией GPLv2.

На сколько это просто, покажет следующий пример. Данный пример регистрируется на станции 192.168.5.48, под номером 7000 с паролем 7000. При входящем на себя вызове проигрывает мелодию из файла /ATS/SOUND/music0.wav, в предответном состоянии в разговорном играется мелодия из файла /ATS/SOUND/music1.wav. При исходящем вызове при ответе играет мелодию из файла /ATS/SOUND/music4.wav

Клавиша a - ответ, с - звонок на номер 100, h - положить трубку.

Пример сделан из примера к самой библиотеке.

#coding=utf8
# $Id: call.py 2171 2008-07-24 09:01:33Z bennylp $
#
# SIP call sample.
#
# Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
#
import sys
import pjsua as pj
import threading

LOG_LEVEL=0
current_call = None

# Logging callback
def log_cb(level, str, len):
   print str,
 

# Callback to receive events from account
class MyAccountCallback(pj.AccountCallback):

   def __init__(self, account=None):
       pj.AccountCallback.__init__(self, account)

   # уведомление о входящем вызове
   def on_incoming_call(self, call):
       global current_call 
       if current_call:
           call.answer(486, "Busy")
           return
           
       print "Incoming call from ", call.info().remote_uri
       print "Press 'a' to answer"

       current_call = call

       call_cb = callCallbackIn(current_call)
       current_call.set_callback(call_cb)

       # отвечаем call progressом
       current_call.answer(183)

   def wait(self):
       self.sem = threading.Semaphore(0)
       self.sem.acquire()

   def on_reg_state(self):
       if self.sem:
           if self.account.info().reg_status >= 200:
               self.sem.release()

       
# Сообщение от входящего вызова
class callCallbackIn(pj.CallCallback):

   def __init__(self, call=None):
       pj.CallCallback.__init__(self, call)

   # уведомление об изменении состояния
   def on_state(self):
       global current_call
       print "Call with", self.call.info().remote_uri,
       print "is", self.call.info().state_text,
       print "last code =", self.call.info().last_code, 
       print "(" + self.call.info().last_reason + ")"

       # в предответном проключаем одну мелодию
       if self.call.info().state == pj.CallState.EARLY:
           call_slot = self.call.info().conf_slot
           # создаем плеер wav файла
           self.wav_player_id = pj.Lib.instance().create_player('/ATS/SOUND/music0.wav', loop=False)
           self.wav_slot = pj.Lib.instance().player_get_slot(self.wav_player_id)
           # проключаем канал плеера на разговор
           pj.Lib.instance().conf_connect(self.wav_slot, call_slot)

       # в разговорном подаем другую
       if self.call.info().state == pj.CallState.CONFIRMED:
           call_slot = self.call.info().conf_slot
           # отключаем от музыки
           pj.Lib.instance().conf_disconnect(self.wav_slot, call_slot)
           # удаляем плеер
           pj.Lib.instance().player_destroy(self.wav_player_id)
           # создаем новый
           self.wav_player_id = pj.Lib.instance().create_player('/ATS/SOUND/music1.wav', loop=False)
           self.wav_slot = pj.Lib.instance().player_get_slot(self.wav_player_id)
           # проключаем канал плеера на разговор
           pj.Lib.instance().conf_connect(self.wav_slot, call_slot)
           
       if self.call.info().state == pj.CallState.DISCONNECTED:
           current_call = None
           print 'Current call is', current_call

   # уведомление об изменении состояния системы коммутации
   def on_media_state(self):           
       if self.call.info().media_state == pj.MediaState.ACTIVE:
           print "Media is now active"
       else:
           print "Media is inactive"

# Сообщение от исходящего вызова
class callCallbackOut(pj.CallCallback):

   def __init__(self, call=None):
       pj.CallCallback.__init__(self, call)

   # уведомление об изменении состояния
   def on_state(self):
       global current_call
       print "Call with", self.call.info().remote_uri,
       print "is", self.call.info().state_text,
       print "last code =", self.call.info().last_code, 
       print "(" + self.call.info().last_reason + ")"

       # в разговорном подаем другую
       if self.call.info().state == pj.CallState.CONFIRMED:
           call_slot = self.call.info().conf_slot
           # создаем новый
           self.wav_player_id = pj.Lib.instance().create_player('/ATS/SOUND/music4.wav', loop=False)
           self.wav_slot = pj.Lib.instance().player_get_slot(self.wav_player_id)
           # проключаем канал плеера на разговор
           pj.Lib.instance().conf_connect(self.wav_slot, call_slot)
          

       if self.call.info().state == pj.CallState.DISCONNECTED:
           current_call = None
           print 'Current call is', current_call

   # уведомление об изменении состояния системы коммутации
   def on_media_state(self):           
       if self.call.info().media_state == pj.MediaState.ACTIVE:
           print "Media is now active"
       else:
           print "Media is inactive"



# Function to make call
def make_call(uri):
   try:
       print "Making call to", uri
       return acc.make_call(uri, cb=callCallbackOut())
   except pj.Error, e:
       print "Exception: " + str(e)
       return None
       

# Create library instance
lib = pj.Lib()

try:
   my_media_cfg = pj.MediaConfig()
   my_media_cfg.clock_rate = 8000
   my_media_cfg.snd_clock_rate = 44100
   my_media_cfg.no_vad = True
   my_media_cfg.quality = 10
   my_media_cfg.ptime = 0
   my_media_cfg.max_media_ports = 4

   
   # Init library with default config and some customized
   # logging config.
   lib.init(log_cfg = pj.LogConfig(level=LOG_LEVEL, callback=log_cb), media_cfg = my_media_cfg)



   # Create UDP transport which listens to any available port
   transport = lib.create_transport(pj.TransportType.UDP, pj.TransportConfig(5060))
   print "\nListening on", transport.info().host, 
   print "port", transport.info().port, "\n"
   
   # Start the library
   lib.start()

   # Create local account
   acc = lib.create_account(pj.AccountConfig("192.168.5.48", "7000", "7000"))

   acc_cb = MyAccountCallback(acc)
   acc.set_callback(acc_cb)
   acc_cb.wait()

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


   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:  m=make call, h=hangup call, a=answer call, c=call 407, q=quit"

       input = sys.stdin.readline().rstrip("\r\n")
       if input == "m":
           if current_call:
               print "Already have another call"
               continue
           print "Enter destination URI to call: ", 
           input = sys.stdin.readline().rstrip("\r\n")
           if input == "":
               continue
           lck = lib.auto_lock()
           current_call = make_call(input)
           del lck

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

       elif input == "a":
           if not current_call:
               print "There is no call"
               continue
           current_call.answer(200)

       elif input == "c":
           lck = lib.auto_lock()
           current_call = make_call("sip:100@192.168.5.48")
           del lck

       elif input == "q":
           break

   # Shutdown the library
   transport = None
   acc.delete()
   acc = None
   lib.destroy()
   lib = None

except pj.Error, e:
   print "Exception: " + str(e)
   lib.destroy()
   lib = None

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты