hello.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #!/usr/bin/env python3
  2. # encoding:utf-8
  3. import time
  4. import json
  5. import wave
  6. import traceback
  7. import pjsua2 as pj
  8. from asr import TestSt
  9. calls = {}
  10. recording_file = '/code/pjsip-apps/src/swig/python/incoming_call.wav'
  11. player_file = '/code/pjsip-apps/src/swig/python/test111.wav'
  12. # Subclass to extend the Account and get notifications etc.
  13. class Account(pj.Account):
  14. def __init__(self):
  15. pj.Account.__init__(self)
  16. def onRegState(self, prm):
  17. print("***OnRegState: " + prm.reason)
  18. def onIncomingCall(self, prm):
  19. print("***onIncomingCall: ", prm.callId)
  20. call = MyCall(self, prm.callId)
  21. call_op_param = pj.CallOpParam(True)
  22. call_op_param.statusCode = pj.PJSIP_SC_OK
  23. call.answer(call_op_param)
  24. calls[prm.callId] = call
  25. class MyAudioMediaPort(pj.AudioMediaPort):
  26. def __init__(self, asr=None):
  27. pj.AudioMediaPort.__init__(self)
  28. # 打开一个 .pcm 文件来保存音频流(可选:保存为 .wav)
  29. self.wav = wave.open(f"{recording_file}", "wb")
  30. self.wav.setnchannels(1)
  31. self.wav.setsampwidth(2) # 假设每个样本是 16 位(2 字节)
  32. self.wav.setframerate(16000)
  33. self.asr = asr
  34. # def onFrameRequested(self, frame):
  35. # print("Request audio frame:", frame)
  36. def onFrameReceived(self, frame):
  37. self.wav.writeframes(bytes(frame.buf))
  38. # print("Received audio frame:", frame.buf, frame.size)
  39. if self.asr: # 如果ASR实例存在,则发送音频数据
  40. self.asr.send_audio(frame.buf)
  41. class MyCall(pj.Call):
  42. def __init__(self, acc, call_id):
  43. pj.Call.__init__(self, acc, call_id)
  44. self.call_id = call_id
  45. self.audio_port = None
  46. self.aud_med = None
  47. self.recorder = None
  48. self.player = None # 用于播放录音的媒体播放器
  49. self.asr = TestSt(call_id) # 创建ASR实例
  50. self.asr.start() # 启动ASR线程
  51. def onDtmfDigit(self, prm):
  52. digit = prm.digit
  53. print(f"Received DTMF digit: {digit}")
  54. def onCallState(self, prm):
  55. call_info = self.getInfo()
  56. print("Call state: ", call_info.stateText, dir(call_info))
  57. # if call_info.state == pj.PJSIP_INV_STATE_CONFIRMED:
  58. # # 当呼叫状态为已确认(即接通)
  59. # audio_media = self.getAudioMedia() # 获取音频媒体对象
  60. # audio_media.startTransmit(audio_media) # 这里可以对音频流进行处理
  61. # print ('11111111111')
  62. if call_info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
  63. print("通话结束")
  64. self.delete()
  65. def onCallMediaState(self, prm):
  66. call_info = self.getInfo()
  67. print("Call Media state: ", call_info.stateText)
  68. for media in call_info.media:
  69. if media.type == pj.PJMEDIA_TYPE_AUDIO and \
  70. (media.status == pj.PJSUA_CALL_MEDIA_ACTIVE):
  71. self.aud_med = self.getAudioMedia(media.index)
  72. try:
  73. self.audio_port = MyAudioMediaPort(asr=self.asr) # 将ASR实例传入端口
  74. self.audio_port.createPort("Incoming Call Port", self.build_audio_format())
  75. self.aud_med.startTransmit(self.audio_port) # 将音频流传输到 ASR
  76. self.audio_port.startTransmit(self.aud_med) # 将 ASR 的输出传回通话
  77. # 录制来电声音
  78. # self.recorder = pj.AudioMediaRecorder()
  79. # self.recorder.createRecorder(recording_file)
  80. # self.aud_med.startTransmit(self.recorder)
  81. # self.send_audio_to_asr()
  82. # 播放其它录音文件
  83. self.player = pj.AudioMediaPlayer()
  84. self.player.createPlayer(player_file)
  85. self.player.startTransmit(self.aud_med)
  86. # 显示播放进度
  87. # self.display_playback_progress()
  88. except Exception as e:
  89. traceback.print_exc()
  90. def build_audio_format(self):
  91. fmt = pj.MediaFormatAudio()
  92. fmt.type = pj.PJMEDIA_TYPE_AUDIO
  93. fmt.id = pj.PJMEDIA_FORMAT_PCM
  94. fmt.clockRate = 16000 # 采样率
  95. fmt.channelCount = 1 # 通道数
  96. fmt.frameTimeUsec = 20000 # 每帧的时间(20 毫秒)
  97. fmt.bitsPerSample = 16 # 每个采样的位数
  98. return fmt
  99. def display_playback_progress(self):
  100. while self.player:
  101. # 获取当前播放位置和总时长
  102. current_pos = self.player.getPos()
  103. player_info = self.player.getInfo()
  104. print (current_pos, player_info.sizeBytes, player_info.sizeSamples)
  105. total_duration = player_info.sizeBytes
  106. if total_duration > 0:
  107. progress = (current_pos / total_duration) * 100
  108. print(f"播放进度: {progress:.2f}%")
  109. time.sleep(1) # 每隔1秒更新一次进度
  110. def stopMedia(self):
  111. pass
  112. # if self.player:
  113. # self.player.stopTransmit(self.aud_med)
  114. # self.player = None
  115. # if self.recorder:
  116. # self.recorder.stopTransmit(self.aud_med)
  117. # self.recorder = None
  118. def delete(self):
  119. self.stopMedia()
  120. # pjsua2 test function
  121. def pjsua2_test():
  122. # Create and initialize the library
  123. ep = pj.Endpoint()
  124. ep_cfg = pj.EpConfig()
  125. try:
  126. ep.libCreate()
  127. ep.libInit(ep_cfg)
  128. aud_dev_mgr = ep.audDevManager()
  129. aud_dev_mgr.setNullDev() # 使用虚拟音频设备(如果没有实际设备)
  130. # Create SIP transport. Error handling sample is shown
  131. sipTpConfig = pj.TransportConfig()
  132. sipTpConfig.port = 30506
  133. ep.transportCreate(pj.PJSIP_TRANSPORT_UDP, sipTpConfig)
  134. # Start the library
  135. ep.libStart()
  136. acfg = pj.AccountConfig()
  137. acfg.idUri = "sip:1001@pbx.fuxicarbon.com"
  138. acfg.regConfig.registrarUri = "sip:pbx.fuxicarbon.com"
  139. cred = pj.AuthCredInfo("digest", "*", "1001", 0, "slibra@#123456")
  140. # acfg.idUri = "sip:1013@test-bot.shuiditech.com:30506"
  141. # acfg.regConfig.registrarUri = "sip:test-bot.shuiditech.com:30506"
  142. # cred = pj.AuthCredInfo("digest", "*", "1013", 0, "000000")
  143. acfg.sipConfig.authCreds.append(cred)
  144. # Create the account
  145. acc = Account()
  146. acc.create(acfg)
  147. try:
  148. while True:
  149. ep.libHandleEvents(100)
  150. except KeyboardInterrupt:
  151. print('Existing...')
  152. # while True:
  153. # # Here we don't have anything else to do..
  154. # time.sleep(10);
  155. finally:
  156. # Destroy the library
  157. ep.libDestroy()
  158. #
  159. # main()
  160. #
  161. if __name__ == "__main__":
  162. pjsua2_test()