|
@@ -4,15 +4,15 @@
|
|
import time
|
|
import time
|
|
import json
|
|
import json
|
|
import wave
|
|
import wave
|
|
|
|
+import queue
|
|
import threading
|
|
import threading
|
|
import traceback
|
|
import traceback
|
|
import pjsua2 as pj
|
|
import pjsua2 as pj
|
|
from enum import Enum
|
|
from enum import Enum
|
|
-from src.core.voip.asr import TestSt
|
|
|
|
|
|
|
|
calls = {}
|
|
calls = {}
|
|
-recording_file = '/code/voip/incoming_call.wav'
|
|
|
|
-player_file = '/code/voip/test111.wav'
|
|
|
|
|
|
+recording_file = '/code/src/core/voip/incoming_call.wav'
|
|
|
|
+player_file = '/code/src/core/voip/test111.wav'
|
|
|
|
|
|
|
|
|
|
class BotStatus(Enum):
|
|
class BotStatus(Enum):
|
|
@@ -37,8 +37,9 @@ class UserStatus(Enum):
|
|
|
|
|
|
# Subclass to extend the Account and get notifications etc.
|
|
# Subclass to extend the Account and get notifications etc.
|
|
class Account(pj.Account):
|
|
class Account(pj.Account):
|
|
- def __init__(self):
|
|
|
|
|
|
+ def __init__(self, user_agent):
|
|
pj.Account.__init__(self)
|
|
pj.Account.__init__(self)
|
|
|
|
+ self.user_agent = user_agent
|
|
|
|
|
|
def onRegState(self, prm):
|
|
def onRegState(self, prm):
|
|
print("***OnRegState: " + prm.reason)
|
|
print("***OnRegState: " + prm.reason)
|
|
@@ -50,7 +51,7 @@ class Account(pj.Account):
|
|
call_op_param = pj.CallOpParam(True)
|
|
call_op_param = pj.CallOpParam(True)
|
|
call_op_param.statusCode = pj.PJSIP_SC_OK
|
|
call_op_param.statusCode = pj.PJSIP_SC_OK
|
|
call.answer(call_op_param)
|
|
call.answer(call_op_param)
|
|
- calls[prm.callId] = call
|
|
|
|
|
|
+ self.user_agent.calls[prm.callId] = call
|
|
|
|
|
|
|
|
|
|
class MyAudioMediaPort(pj.AudioMediaPort):
|
|
class MyAudioMediaPort(pj.AudioMediaPort):
|
|
@@ -83,6 +84,7 @@ class MyAudioMediaPlayer(pj.AudioMediaPlayer):
|
|
print('player complete')
|
|
print('player complete')
|
|
self.stopTransmit(self.sink)
|
|
self.stopTransmit(self.sink)
|
|
|
|
|
|
|
|
+
|
|
class MyCall(pj.Call):
|
|
class MyCall(pj.Call):
|
|
|
|
|
|
def __init__(self, acc, call_id):
|
|
def __init__(self, acc, call_id):
|
|
@@ -92,6 +94,7 @@ class MyCall(pj.Call):
|
|
self.aud_med = None
|
|
self.aud_med = None
|
|
self.recorder = None
|
|
self.recorder = None
|
|
self.player = None # 用于播放录音的媒体播放器
|
|
self.player = None # 用于播放录音的媒体播放器
|
|
|
|
+ from src.core.voip.asr import TestSt
|
|
self.asr = TestSt(call_id) # 创建ASR实例
|
|
self.asr = TestSt(call_id) # 创建ASR实例
|
|
self.asr.start() # 启动ASR线程
|
|
self.asr.start() # 启动ASR线程
|
|
|
|
|
|
@@ -102,6 +105,15 @@ class MyCall(pj.Call):
|
|
def onCallState(self, prm):
|
|
def onCallState(self, prm):
|
|
call_info = self.getInfo()
|
|
call_info = self.getInfo()
|
|
print("Call state: ", call_info.stateText)
|
|
print("Call state: ", call_info.stateText)
|
|
|
|
+
|
|
|
|
+ # pj.PJSIP_INV_STATE_NULL
|
|
|
|
+ # pj.PJSIP_INV_STATE_CALLING
|
|
|
|
+ # pj.PJSIP_INV_STATE_INCOMING
|
|
|
|
+ # pj.PJSIP_INV_STATE_EARLY
|
|
|
|
+ # pj.PJSIP_INV_STATE_CONNECTING
|
|
|
|
+ # pj.PJSIP_INV_STATE_CONFIRMED
|
|
|
|
+ # pj.PJSIP_INV_STATE_DISCONNECTED
|
|
|
|
+
|
|
# if call_info.state == pj.PJSIP_INV_STATE_CONFIRMED:
|
|
# if call_info.state == pj.PJSIP_INV_STATE_CONFIRMED:
|
|
# # 当呼叫状态为已确认(即接通)
|
|
# # 当呼叫状态为已确认(即接通)
|
|
# audio_media = self.getAudioMedia() # 获取音频媒体对象
|
|
# audio_media = self.getAudioMedia() # 获取音频媒体对象
|
|
@@ -109,7 +121,6 @@ class MyCall(pj.Call):
|
|
# print ('11111111111')
|
|
# print ('11111111111')
|
|
if call_info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
|
|
if call_info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
|
|
print("通话结束")
|
|
print("通话结束")
|
|
- self.delete()
|
|
|
|
|
|
|
|
def onCallMediaState(self, prm):
|
|
def onCallMediaState(self, prm):
|
|
call_info = self.getInfo()
|
|
call_info = self.getInfo()
|
|
@@ -169,66 +180,98 @@ class MyCall(pj.Call):
|
|
|
|
|
|
# time.sleep(0.1) # 每隔1秒更新一次进度
|
|
# time.sleep(0.1) # 每隔1秒更新一次进度
|
|
|
|
|
|
- def stopMedia(self):
|
|
|
|
- pass
|
|
|
|
- # if self.player:
|
|
|
|
- # self.player.stopTransmit(self.aud_med)
|
|
|
|
- # self.player = None
|
|
|
|
- # if self.recorder:
|
|
|
|
- # self.recorder.stopTransmit(self.aud_med)
|
|
|
|
- # self.recorder = None
|
|
|
|
-
|
|
|
|
- def delete(self):
|
|
|
|
- self.stopMedia()
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-# pjsua2 test function
|
|
|
|
-def pjsua2_test():
|
|
|
|
- # Create and initialize the library
|
|
|
|
- ep = pj.Endpoint()
|
|
|
|
- ep_cfg = pj.EpConfig()
|
|
|
|
- try:
|
|
|
|
- ep.libCreate()
|
|
|
|
- ep.libInit(ep_cfg)
|
|
|
|
-
|
|
|
|
- aud_dev_mgr = ep.audDevManager()
|
|
|
|
- aud_dev_mgr.setNullDev() # 使用虚拟音频设备(如果没有实际设备)
|
|
|
|
|
|
|
|
|
|
+class UserAgent:
|
|
|
|
+ def __init__(self, user_part, host="192.168.124.6", port="5060", password="slibra@#123456"):
|
|
|
|
+ self.user_part, self.host, self.port, self.password = user_part, host, port, password
|
|
|
|
+ self.calls = {}
|
|
|
|
+ self.ep = pj.Endpoint()
|
|
|
|
+ self.acc = Account(self)
|
|
|
|
+ self.is_stopping = False
|
|
|
|
+
|
|
|
|
+ def start(self):
|
|
|
|
+ threading.Thread(target=self.create_pjsua2, args=()).start()
|
|
|
|
+
|
|
|
|
+ # pjsua2 test function
|
|
|
|
+ def create_pjsua2(self):
|
|
|
|
+ # Create and initialize the library
|
|
|
|
+ ep_cfg = pj.EpConfig()
|
|
|
|
+ self.ep.libCreate()
|
|
|
|
+ self.ep.libInit(ep_cfg)
|
|
|
|
+
|
|
|
|
+ aud_dev_mgr = self.ep.audDevManager()
|
|
|
|
+ aud_dev_mgr.setNullDev() # 使用虚拟音频设备(如果没有实际设备)
|
|
|
|
|
|
# Create SIP transport. Error handling sample is shown
|
|
# Create SIP transport. Error handling sample is shown
|
|
sipTpConfig = pj.TransportConfig()
|
|
sipTpConfig = pj.TransportConfig()
|
|
sipTpConfig.port = 30506
|
|
sipTpConfig.port = 30506
|
|
- ep.transportCreate(pj.PJSIP_TRANSPORT_UDP, sipTpConfig)
|
|
|
|
- # Start the library
|
|
|
|
- ep.libStart()
|
|
|
|
|
|
+ self.ep.transportCreate(pj.PJSIP_TRANSPORT_UDP, sipTpConfig)
|
|
|
|
|
|
|
|
+ # Start the library
|
|
|
|
+ self.ep.libStart()
|
|
acfg = pj.AccountConfig()
|
|
acfg = pj.AccountConfig()
|
|
- acfg.idUri = "sip:1001@192.168.124.6:5060"
|
|
|
|
- acfg.regConfig.registrarUri = "sip:192.168.124.6:5060"
|
|
|
|
- cred = pj.AuthCredInfo("digest", "*", "1001", 0, "slibra@#123456")
|
|
|
|
- # acfg.idUri = "sip:1013@test-bot.shuiditech.com:30506"
|
|
|
|
- # acfg.regConfig.registrarUri = "sip:test-bot.shuiditech.com:30506"
|
|
|
|
- # cred = pj.AuthCredInfo("digest", "*", "1013", 0, "000000")
|
|
|
|
|
|
+ acfg.idUri = f"sip:{self.user_part}@{self.host}:{self.port}"
|
|
|
|
+ acfg.regConfig.registrarUri = f"sip:{self.host}:{self.port}"
|
|
|
|
+ cred = pj.AuthCredInfo("digest", "*", f"{self.user_part}", 0, self.password)
|
|
acfg.sipConfig.authCreds.append(cred)
|
|
acfg.sipConfig.authCreds.append(cred)
|
|
# Create the account
|
|
# Create the account
|
|
- acc = Account()
|
|
|
|
- acc.create(acfg)
|
|
|
|
-
|
|
|
|
- try:
|
|
|
|
- while True:
|
|
|
|
- ep.libHandleEvents(100)
|
|
|
|
- except KeyboardInterrupt:
|
|
|
|
- print('Existing...')
|
|
|
|
- # while True:
|
|
|
|
- # # Here we don't have anything else to do..
|
|
|
|
- # time.sleep(10);
|
|
|
|
- finally:
|
|
|
|
|
|
+ self.acc.create(acfg)
|
|
|
|
+
|
|
|
|
+ while not self.is_stopping:
|
|
|
|
+ self.ep.libHandleEvents(100)
|
|
|
|
+
|
|
|
|
+ def hangup(self, reason="NORMAL_CLEARING", **sip_headers):
|
|
|
|
+ call_op_param = pj.CallOpParam(True)
|
|
|
|
+ call_op_param.statusCode = pj.PJSIP_SC_OK
|
|
|
|
+ call_op_param.reason = reason
|
|
|
|
+ for k, v in sip_headers:
|
|
|
|
+ call_op_param.headers.append(pj.SipHeader(f"sip_h_{k}", v))
|
|
|
|
+ for k, v in self.calls.items():
|
|
|
|
+ v.hangup(call_op_param)
|
|
|
|
+
|
|
|
|
+ def register(self, renew=False):
|
|
|
|
+ self.acc.setRegistration(renew=renew)
|
|
|
|
+
|
|
|
|
+ def destroy(self):
|
|
|
|
+ self.is_stopping = True
|
|
# Destroy the library
|
|
# Destroy the library
|
|
- ep.libDestroy()
|
|
|
|
|
|
+ self.ep.libDestroy()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class UserAgentPool:
|
|
|
|
+ def __init__(self, pool_size, user_part_range=range(1000, 1019)):
|
|
|
|
+ self.pool_size = pool_size
|
|
|
|
+ self.pool = queue.Queue(maxsize=pool_size)
|
|
|
|
+
|
|
|
|
+ # 初始化连接池
|
|
|
|
+ for i in range(pool_size):
|
|
|
|
+ conn = self.create(user_part_range[i])
|
|
|
|
+ self.pool.put(conn)
|
|
|
|
+
|
|
|
|
+ def create(self, user_part, host='192.168.124.6', port='6379', password="slibra@#123456"):
|
|
|
|
+ return UserAgent(user_part, host=host, port=port, password=password)
|
|
|
|
+
|
|
|
|
+ def get(self):
|
|
|
|
+ return self.pool.get()
|
|
|
|
+
|
|
|
|
+ def release(self, conn):
|
|
|
|
+ self.pool.put(conn)
|
|
|
|
+
|
|
|
|
+ def destroy(self):
|
|
|
|
+ while not self.pool.empty():
|
|
|
|
+ agent = self.pool.get()
|
|
|
|
+ agent.destroy()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class Voip:
|
|
|
|
+
|
|
|
|
+ def __init__(self, logger):
|
|
|
|
+ self.logger = logger
|
|
|
|
+ # self.pool = UserAgentPool(pool_size=2)
|
|
|
|
+ agent = UserAgent('1001')
|
|
|
|
+ agent.start()
|
|
|
|
|
|
|
|
|
|
-#
|
|
|
|
-# main()
|
|
|
|
-#
|
|
|
|
-if __name__ == "__main__":
|
|
|
|
- pjsua2_test()
|
|
|
|
|
|
+# if __name__ == "__main__":
|
|
|
|
+# voip = Voip()
|
|
|
|
+# voip.create_pjsua2()
|