You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
import pjsua2 as pj
import time
import threading
import sys
import os # For handling file paths
Logging callback
def log_cb(level, str, len):
print(str.strip())
Subclass to extend the Account class
class MyAccount(pj.Account):
def init(self, sip_phone):
pj.Account.init(self)
self.sip_phone = sip_phone
def onRegState(self, prm):
print("Registration state changed:")
print(f" Status code: {prm.code}")
print(f" Status text: {prm.reason}")
print(f" Expiration: {prm.expiration}")
if prm.code != 200:
print(f" Registration failed. Please check your credentials and connection.")
def onCallState(self, prm):
ci = self.getInfo()
print(f"Call state changed to {ci.stateText}")
print(f"Call duration: {ci.totalDuration.sec} seconds")
if ci.state == pj.PJSIP_INV_STATE_DISCONNECTED:
print(f"Call disconnected. Last status: {ci.lastStatusCode}")
self.connected = False
if self.keep_alive_timer:
self.keep_alive_timer.cancel()
# Stop recording when the call is disconnected
if self.recorder:
print("Stopping the recording.")
try:
if self.getMedia(0): # Ensure media still exists before stopping transmission
am = pj.AudioMedia.typecastFromMedia(self.getMedia(0)) # Assume media index 0
self.recorder.stopTransmit(am) # Pass the remote media (am) to stopTransmit
self.recorder = None
except pj.Error as e:
print(f"Error stopping the recording: {e}")
except ValueError as e:
print(f"Invalid media reference: {e}")
elif ci.state == pj.PJSIP_INV_STATE_CONFIRMED:
print("Call is now connected.")
self.connected = True
self.start_keep_alive()
def onCallMediaState(self, prm):
ci = self.getInfo()
print("Call media state changed.")
for mi in ci.media:
if mi.type == pj.PJMEDIA_TYPE_AUDIO and mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE:
m = self.getMedia(mi.index)
am = pj.AudioMedia.typecastFromMedia(m)
# Check if this is the remote media (customer's voice)
if mi.dir == pj.PJMEDIA_DIR_DECODING or mi.dir == pj.PJMEDIA_DIR_ENCODING_DECODING:
print("Remote media detected, recording customer's voice.")
# Record only the customer's voice (remote media)
if not self.recorder: # Avoid multiple recorders for the same call
self.recorder = pj.AudioMediaRecorder()
filename = f"customer_voice_{ci.id}_{time.strftime('%Y%m%d-%H%M%S')}.wav"
try:
# Ensure the directory exists
if not os.path.exists('recordings'):
os.makedirs('recordings')
filepath = os.path.join('recordings', filename)
self.recorder.createRecorder(filepath)
am.startTransmit(self.recorder) # Start transmitting only remote media to recorder
print(f"Recording customer's voice to file: {filepath}")
except pj.Error as e:
print(f"Error setting up recorder: {e}")
else:
print("Skipping local media.")
def start_keep_alive(self):
def send_keep_alive():
pj.Endpoint.instance().libRegisterThread('keep_alive_thread')
if self.connected:
try:
# Send a re-INVITE
self.reinvite(pj.CallOpParam())
print("Sent keep-alive (re-INVITE) to Asterisk")
except pj.Error as e:
print(f"Error sending keep-alive: {e}")
# Schedule the next re-INVITE after 20 seconds
self.keep_alive_timer = threading.Timer(20, send_keep_alive)
self.keep_alive_timer.start()
# Schedule the first re-INVITE after 20 seconds
print("Starting keep-alive process (sending re-INVITE every 20 seconds)...")
self.keep_alive_timer = threading.Timer(20, send_keep_alive)
self.keep_alive_timer.start()
def hang_up(self):
if self.current_call:
try:
self.current_call.hangup(pj.CallOpParam())
except pj.Error as e:
print(f"Error hanging up call: {e}")
self.current_call = None
def run(self):
print("SIP Phone is running. Waiting for incoming calls...")
try:
while True:
self.ep.libHandleEvents(10)
except KeyboardInterrupt:
print("Exiting...")
finally:
self.hang_up()
if self.acc:
try:
self.acc.shutdown() # Use shutdown instead of delete
except pj.Error as e:
print(f"Error shutting down account: {e}")
The text was updated successfully, but these errors were encountered:
import pjsua2 as pj
import time
import threading
import sys
import os # For handling file paths
Logging callback
def log_cb(level, str, len):
print(str.strip())
Subclass to extend the Account class
class MyAccount(pj.Account):
def init(self, sip_phone):
pj.Account.init(self)
self.sip_phone = sip_phone
def onRegState(self, prm):
print("Registration state changed:")
print(f" Status code: {prm.code}")
print(f" Status text: {prm.reason}")
print(f" Expiration: {prm.expiration}")
if prm.code != 200:
print(f" Registration failed. Please check your credentials and connection.")
def onIncomingCall(self, prm):
call = MyCall(self, prm.callId)
call_info = call.getInfo()
print(f"Incoming call from: {call_info.remoteUri}")
self.sip_phone.current_call = call
Subclass to extend the Call class
class MyCall(pj.Call):
def init(self, acc, call_id=pj.PJSUA_INVALID_ID):
pj.Call.init(self, acc, call_id)
self.connected = False
self.keep_alive_timer = None
self.recorder = None # AudioMediaRecorder for customer voice
def onCallState(self, prm):
ci = self.getInfo()
print(f"Call state changed to {ci.stateText}")
print(f"Call duration: {ci.totalDuration.sec} seconds")
if ci.state == pj.PJSIP_INV_STATE_DISCONNECTED:
print(f"Call disconnected. Last status: {ci.lastStatusCode}")
self.connected = False
if self.keep_alive_timer:
self.keep_alive_timer.cancel()
def onCallMediaState(self, prm):
ci = self.getInfo()
print("Call media state changed.")
for mi in ci.media:
if mi.type == pj.PJMEDIA_TYPE_AUDIO and mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE:
m = self.getMedia(mi.index)
am = pj.AudioMedia.typecastFromMedia(m)
def start_keep_alive(self):
def send_keep_alive():
pj.Endpoint.instance().libRegisterThread('keep_alive_thread')
if self.connected:
try:
# Send a re-INVITE
self.reinvite(pj.CallOpParam())
print("Sent keep-alive (re-INVITE) to Asterisk")
except pj.Error as e:
print(f"Error sending keep-alive: {e}")
# Schedule the next re-INVITE after 20 seconds
self.keep_alive_timer = threading.Timer(20, send_keep_alive)
self.keep_alive_timer.start()
class SipPhone:
def init(self):
self.ep = None
self.acc = None
self.current_call = None
def init_lib(self):
self.ep = pj.Endpoint()
self.ep.libCreate()
def create_account(self, username, password, domain):
acc_cfg = pj.AccountConfig()
acc_cfg.idUri = f"sip:{username}@{domain}"
acc_cfg.regConfig.registrarUri = f"sip:{domain}"
cred = pj.AuthCredInfo("digest", "*", username, 0, password)
acc_cfg.sipConfig.authCreds.append(cred)
def hang_up(self):
if self.current_call:
try:
self.current_call.hangup(pj.CallOpParam())
except pj.Error as e:
print(f"Error hanging up call: {e}")
self.current_call = None
def run(self):
print("SIP Phone is running. Waiting for incoming calls...")
try:
while True:
self.ep.libHandleEvents(10)
except KeyboardInterrupt:
print("Exiting...")
finally:
self.hang_up()
if self.acc:
try:
self.acc.shutdown() # Use shutdown instead of delete
except pj.Error as e:
print(f"Error shutting down account: {e}")
The text was updated successfully, but these errors were encountered: