Files
appointment_tool/gsmmodem/models/Call.py
T

81 lines
3.2 KiB
Python

import weakref
from gsmmodem.exceptions import CmeError, InterruptedException, InvalidStateException
class Call(object):
""" A voice call """
DTMF_COMMAND_BASE = '+VTS='
dtmfSupport = False # Indicates whether or not DTMF tones can be sent in calls
def __init__(self, gsmModem, callId, callType, number, callStatusUpdateCallbackFunc=None):
"""
:param gsmModem: GsmModem instance that created this object
:param number: The number that is being called
"""
self._gsmModem = weakref.proxy(gsmModem)
self._callStatusUpdateCallbackFunc = callStatusUpdateCallbackFunc
# Unique ID of this call
self.id = callId
# Call type (VOICE == 0, etc)
self.type = callType
# The remote number of this call (destination or origin)
self.number = number
# Flag indicating whether the call has been answered or not (backing field for "answered" property)
self._answered = False
# Flag indicating whether or not the call is active
# (meaning it may be ringing or answered, but not ended because of a hangup event)
self.active = True
@property
def answered(self):
return self._answered
@answered.setter
def answered(self, answered):
self._answered = answered
if self._callStatusUpdateCallbackFunc:
self._callStatusUpdateCallbackFunc(self)
def sendDtmfTone(self, tones):
""" Send one or more DTMF tones to the remote party (only allowed for an answered call)
Note: this is highly device-dependent, and might not work
:param digits: A str containining one or more DTMF tones to play, e.g. "3" or "\*123#"
:raise CommandError: if the command failed/is not supported
:raise InvalidStateException: if the call has not been answered, or is ended while the command is still executing
"""
if self.answered:
dtmfCommandBase = self.DTMF_COMMAND_BASE.format(cid=self.id)
toneLen = len(tones)
for tone in list(tones):
try:
self._gsmModem.write('AT{0}{1}'.format(dtmfCommandBase, tone), timeout=(5 + toneLen))
except CmeError as e:
if e.code == 30:
# No network service - can happen if call is ended during DTMF transmission (but also if DTMF is sent immediately after call is answered)
raise InterruptedException('No network service', e)
elif e.code == 3:
# Operation not allowed - can happen if call is ended during DTMF transmission
raise InterruptedException('Operation not allowed', e)
else:
raise e
else:
raise InvalidStateException('Call is not active (it has not yet been answered, or it has ended).')
def hangup(self):
""" End the phone call.
Does nothing if the call is already inactive.
"""
if self.active:
self._gsmModem.write('ATH')
self.answered = False
self.active = False
if self.id in self._gsmModem.activeCalls:
del self._gsmModem.activeCalls[self.id]