diff --git a/docs/Globals.rst b/docs/Globals.rst index 4a7752d..40b507d 100644 --- a/docs/Globals.rst +++ b/docs/Globals.rst @@ -1,10 +1,13 @@ +Globals +####### + Global Variables -######## +**************** There are a few global variables that may assist you if you're having problems with the library. pyVoIP.\ **DEBUG** = False - If set to true, pyVoIP will print debug messages that may be useful if you need to open a GitHub issue. Otherwise, does nothing. + If set to true, pyVoIP will print debug messages that may be useful if you need to troubleshoot or open a GitHub issue. pyVoIP.\ **TRANSMIT_DELAY_REDUCTION** = 0.0 The higher this variable is, the more often RTP packets are sent. This *should* only ever need to be 0.0. However, when testing on Windows, there has sometimes been jittering, setting this to 0.75 fixed this in testing, but you may need to tinker with this number on a per-system basis. @@ -26,18 +29,20 @@ pyVoIP.\ **ALLOW_TLS_FALLBACK** = False pyVoIP.\ **TLS_CHECK_HOSTNAME** = True Is used to create SSLContexts. See `Python's documentation `_ on this feature. - You should use the set_tls_security to change this variable. + You should use the :ref:`set_tls_security ` function to change this variable. pyVoIP.\ **TLS_VERIFY_MODE** = True Is used to create SSLContexts. See `Python's documentation `_ on this feature. - You should use the set_tls_security to change this variable. + You should use the :ref:`set_tls_security ` function to change this variable. -pyVoIP.\ **SIP_STATE_EB_LOCATION** = ":memory:" +pyVoIP.\ **SIP_STATE_DB_LOCATION** = ":memory:" This variable allows you to save the SIP message state database to a file instead of storing it in memory which is the default. This is useful for debugging, however pyVoIP does not delete the database afterwards which will cause an Exception upon restarting pyVoIP. For this reason, we recommend you do not change this variable in production. Global Functions -######## +**************** + +.. _set_tls_security: -pyVoIP.\ **set_tls_security**\ (verify_mode: `ssl.VerifyMode `) -> None +pyVoIP.\ **set_tls_security**\ (verify_mode: `ssl.VerifyMode `_) -> None This method ensures that TLS_CHECK_HOSTNAME and TLS_VERIFY_MODE are set correctly depending on the TLS certificate verification settings you want to use. diff --git a/docs/VoIP.rst b/docs/VoIP.rst index 7dec461..6d464a6 100644 --- a/docs/VoIP.rst +++ b/docs/VoIP.rst @@ -1,60 +1,68 @@ VoIP - The Bridge Between SIP and RTP ##################################### -The VoIP module coordinates between the SIP and RTP modules in order to create an effective Voice over Internet Protocol system. The VoIP system is made for your convenience, and if you have a particularly intricate situation, you can use the SIP and RTP modules independently and create your own version of the VoIP module. If you choose to use the VoIP module, this section will explain how. +The VoIP module coordinates between the SIP and RTP modules in order to create an effective Voice over Internet Protocol system. The VoIP system is made for your convenience, and if you have a particularly intricate situation, you can override the SIP module on initialization to fit your use case. Errors ******** -There are two errors under ``pyVoIP.VoIP``. +There are three errors under ``pyVoIP.VoIP.error``. .. _invalidstateerror: -*exception* VoIP.\ **InvalidStateError** - This is thrown by :ref:`VoIPCall` when you try to perform an action that cannot be performed during the current :ref:`CallState`. For example denying a call that has already been answered, hanging up a call that hasn't been answered yet, or has already been ended. +*exception* pyVoIP.VoIP.error.\ **InvalidStateError** + This is thrown by :ref:`VoIPCall` when you try to perform an action that cannot be performed during the current :ref:`CallState`. For example denying a call that has already been answered, hanging up a call that hasn't been answered yet, or has already ended. -*exception* VoIP.\ **InvalidRangeError** - This is thrown by :ref:`VoIPPhone` when you define the rtpPort ranges as rtpPortLow > rtpPortHigh. However, this is not checked by :ref:`VoIPCall`, so if you are using your own class instead of VoIPPhone, make sure these ranges are correct. +*exception* pyVoIP.VoIP.error.\ **InvalidRangeError** + This is thrown by :ref:`VoIPPhone` when you define the RTP port ranges as rtp_port_low > rtp_port_high. However, this is not checked by :ref:`VoIPCall`, so if you are using your own class instead of VoIPPhone, make sure these ranges are correct. -*exception* VoIP.\ **NoPortsAvailableError** - This is thrown when a call is attempting to be initiated but no ports are available. +*exception* pyVoIP.VoIP.error.\ **NoPortsAvailableError** + This is thrown when a call is attempting to be initiated but no RTP ports are available. Enums *********** .. _callstate: -VoIP.\ **CallState** - CallState is an Enum with four attributes. - +*enum* pyVoIP.VoIP.\ **CallState** + CallState is an Enum with six attributes. + CallState.\ **DIALING** This CallState is used to describe when a :term:`user` has originated a call to a :term:`client`, but it has yet to be answered. - + + In this state, you can use ``VoIPCall.cancel()``. + CallState.\ **RINGING** This CallState is used to describe when a :term:`client` is calling, but the call has yet to be answered. - + In this state, you can use ``VoIPCall.answer()`` or ``VoIPCall.deny()``. - + + CallState.\ **PROGRESS** + This CallState is used when a 183 Session Progress response is received on a call that is dialing. + + In this state, you can use ``VoIPCall.answer()``, ``VoIPCall.deny()``, or ``VoIPCall.cancel()``. + CallState.\ **ANSWRED** This CallState is used to describe when a call has been answered and is active. - + In this state, you can use ``VoIPCall.hangup()``. - + + CallState.\ **CANCELING** + This CallState is used when a dialing call is canceled with ``VoIPCall.cancel()``. + CallState.\ **ENDED** This CallState is used to describe when a call has been terminated. - - In this state, you can not use any functions. -.. _phonestatus +.. _PhoneStatus: -VoIP.\ **PhoneStatus** +*enum* pyVoIP.VoIP.\ **PhoneStatus** PhoneStatus is an Enum with five attributes. PhoneStatus.\ **INACTIVE** This PhoneStatus is used when ``VoIPPhone.start()`` has not been called, or after the phone has fully stopped after calling ``VoIPPhone.stop()``. PhoneStatus.\ **REGISTERING** - This PhoneStatus is used when ``VoIPPhone.start()`` has been called, but has not finished starting. + This PhoneStatus is used when ``VoIPPhone.start()`` has been called, but has not finished starting, or when the phone is re-registering. PhoneStatus.\ **REGISTERED** This PhoneStatus is used when ``VoIPPhone`` has finished starting successfully, and is ready for use. @@ -73,114 +81,115 @@ Classes VoIPCall ========= -The VoIPCall class is used to represent a single VoIP Session, which may be to multiple :term:`clients`. +The VoIPCall class is used to represent a single VoIP session, which may be to multiple :term:`clients`. -*class* VoIP.\ **VoIPCall**\ (phone: :ref:`VoIPPhone`, request: :ref:`SIPMessage`, session_id: int, myIP: str, rtpPortLow: int, rtpPortHigh: int) +*class* pyVoIP.VoIP.\ **VoIPCall**\ (phone: :ref:`VoIPPhone`, callstate: :ref:`CallState `, request: :ref:`SIPMessage`, session_id: int, bind_ip: str, conn: :ref:`VoIPConnection`, ms: Optional[Dict[int, RTP.PayloadType]] = None, sendmode="sendonly") The *phone* argument is the initating instance of :ref:`VoIPPhone`. - + The *callstate* arguement is the initiating :ref:`CallState`. - + The *request* argument is the :ref:`SIPMessage` representation of the SIP INVITE request from the VoIP server. - + The *session_id* argument is a unique code used to identify the session with `SDP `_ when answering the call. - - The *myIP* argument is the IP address it will pass to :ref:`RTPClient`'s to bind to. - - The *ms* arguement is a dictionary with int as the key and a :ref:`PayloadType` as the value. This is only used when originating the call. - - - **dtmf_callback**\ (code: str) -> None - This method is called by :ref:`RTPClient`'s when a telephone-event DTMF message is received. The *code* argument is a string. It should be an Event in complinace with `RFC 4733 Section 3.2 `_. - + + The *bind_ip* argument is the IP address it will pass to :ref:`RTPClient`'s to bind to. + + The *ms* arguement is a dictionary with int as the key and a :ref:`PayloadType` as the value. This is only used when originating the call. + + **get_dtmf**\ (length=1) -> str - This method can be called get the next pressed DTMF key. DTMF's are stored in an ``io.StringIO`` and act as a stack. Meaning if the :term:`client` presses the numbers 1-9-5 you'll have the following output: - + This method can be called get the next pressed DTMF key. DTMF's are stored in an `io.StringIO `_ which is a buffer. Calling this method when there a key has not been pressed returns an empty string. To return the entire contents of the buffer set length to a negative number or None. If the :term:`client` presses the numbers 1-9-5 you'll have the following output: + .. code-block:: python - - VoIPCall.get_dtmf() + + self.get_dtmf() >>> '1' - VoIPCall.get_dtmf(length=2) + self.get_dtmf(length=2) >>> '95' - VoIPCall.get_dtmf() + self.get_dtmf() >>> '' - - As you can see, calling this method when there a key has not been pressed returns an empty string. - + + **answer**\ () -> None Answers the call if the phone's state is CallState.RINGING. - - **answered**\ (request: :ref:`SIPMessage`) -> None - This function is called by :ref:`SIPClient` when a call originated by the :term:`user` has been answered by the :term:`client`. - + + **transfer**\ (user: Optional[str] = None, uri: Optional[str] = None, blind=True) -> bool + Sends a REFER request to transfer the call. If blind is true (default), the call will immediately end after received a 200 or 202 response. Otherwise, it will wait for the Transferee to report a successful transfer. Or, if the transfer is unsuccessful, the call will continue. This function returns true if the transfer is blind or successful, and returns false if it is unsuccessful. + + If using a URI to transfer, you must use a complete URI to include <> brackets as necessary. + + **ringing**\ (request: :ref:`SIPMessage`) -> None + This function is what is called when receiving a new call. Custom VoIPCall classes should override this function to answer the call. + **deny**\ () -> None Denies the call if the phone's state is CallState.RINGING. - + **hangup**\ () -> None Ends the call if the phone's state is CallState.ANSWRED. - - **bye**\ () -> None - Ends the call but does not send a SIP BYE message to the SIP server. This function is used to end the call on the server side when the client ended the call. **THE** :term:`USER` **SHOUND NOT CALL THIS FUNCTION OR THE** :term:`CLIENT` **WILL BE LEFT ON THE LINE WITH NO RESPONSE. CALL HANGUP() INSTEAD.** - + + **cancel**\ () -> None + Cancels a dialing call. + **write_audio**\ (data: bytes) -> None - Writes linear/raw audio data to the transmit buffer before being encoded and sent. The *data* argument MUST be bytes. **This audio must be linear/not encoded,** :ref:`RTPClient` **will encode it before transmitting.** - + Writes linear/raw audio data to the transmit buffer before being encoded and sent. The *data* argument MUST be bytes. **This audio must be linear/not encoded.** :ref:`RTPClient` **will encode it before transmitting.** + **read_audio**\ (length=160, blocking=True) -> bytes - Reads linear/raw audio data from the received buffer. Returns *length* amount of bytes. Default length is 160 as that is the amount of bytes sent per PCMU/PCMA packet. When *blocking* is set to true, this function will not return until data is available. When *blocking* is set to false and data is not available, this function will return ``b"\x80" * length``. + Reads linear/raw audio data from the received buffer. Returns *length* amount of bytes. Default length is 160 as that is the amount of bytes sent per PCMU/PCMA packet. When *blocking* is set to true, this function will not return until data is available. When *blocking* is set to false and data is not available, this function will return ``b"\x80" * length``. .. _VoIPPhoneParameter: VoIPPhoneParameter -========= - -*class* VoIP.\ **VoIPPhone**\ (server: str, port: int, username: str, password: str, callCallback: Optional[Callable] = None, bind_ip="0.0.0.0", bind_port=5060, transport_mode=SIP.TransportMode.UDP, rtp_port_low=10000, rtp_port_high=20000, callClass: Type[VoIPCall] = None, sipClass: Type[SIP.SIPClient] = None) +================== +*class* pyVoIP.VoIP.\ **VoIPPhoneParameter**\ (server: str, port: int, credentials_manager: Optional[:ref:`CredentialsManager`], bind_ip="0.0.0.0", bind_port=5060, bind_network="0.0.0.0/0", hostname: Optional[str] = None, remote_hostname: Optional[str] = None, transport_mode=\ :ref:`TransportMode`.UDP, cert_file: Optional[str] = None, key_file: Optional[str] = None, key_password: Optional[str] = None, rtp_port_low=10000, rtp_port_high=20000, call_class: Type[VoIPCall] = None, sip_class: Type[SIP.SIPClient] = None) The *server* argument is your PBX/VoIP server's IP, represented as a string. The *port* argument is your PBX/VoIP server's port, represented as an integer. - The *username* argument is your SIP account username on the PBX/VoIP server, represented as a string. + The *credentials_manager* argument is a :ref:`CredentialsManager` instance that stores all usernames and passwords your phone may need. + + The *bind_ip* argument is used to bind SIP and RTP ports to receive incoming calls. Default is to bind to 0.0.0.0, however, this is not recommended. + + The *bind_port* argument is the port SIP will bind to to receive SIP requests. The default for this protocol is port 5060, but any port can be used. - The *password* argument is your SIP account password on the PBX/VoIP server, represented as a string. + The *bind_network* argument is used to configure pyVoIP's NAT. pyVoIP uses this to know whether to use the *hostname* or *remote_hostname* when generating SIP requests to in-network and out-of-network devices respectively. Value must be a string with IPv4 CIDR notation. - The *bind_ip* argument is used to bind SIP and RTP ports to receive incoming calls. If left as None, the VoIPPhone will bind to 0.0.0.0. + The *hostname* argument is used to generate SIP requests and responses with devices within pyVoIP's *bind_network*. If left as None, the *bind_ip* will be used instead. - The *bind_port* argument is the port SIP will bind to to receive SIP requests. The default for this protocol is port 5060, but any port can be used. + The *remote_hostname* argument is used to generate SIP requests and responses with devices outside of pyVoIP's *bind_network*. If left as None, pyVoIP will throw a :ref:`NATError` if a request is sent outside of pyVoIP's *bind_network*. - The *transport_mode* argument is SIP.TransportMode.UDP or SIP.TransportMode.TCP. + The *transport_mode* argument determines whether pyVoIP will use UDP, TCP, or TLS. Value should be a :ref:`TransportMode`. - The *rtp_port_low* and *rtp_port_high* arguments are used to generate random ports to use for audio transfer. Per RFC 4566 Sections `5.7 `_ and `5.14 `_, it can take multiple ports to fully communicate with other :term:`clients`, as such a large range is recommended. If an invalid range is given, a :ref:`InvalidStateError` will be thrown. + The *cert_file*, *key_file*, and *key_password* arguments are used to load certificates in pyVoIP's server context if using TLS for the transport mode. See `Python's documentation on load_cert_chain `_ for more details. - The *callClass* argument allows to override the used :ref:`VoIPCall` class (must be a child class of :ref:`VoIPCall`). + The *rtp_port_low* and *rtp_port_high* arguments are used to generate random ports to use for audio transfer. Per RFC 4566 Sections `5.7 `_ and `5.14 `_, it can take multiple ports to fully communicate with other :term:`clients`, as such a large range is recommended. If an invalid range is given, a :ref:`InvalidStateError` will be thrown. - The *sipClass* argument allows to override the used :ref:`SIPClient` class (must be a child class of :ref:`SIPClient`). + The *call_class* argument allows to override the used :ref:`VoIPCall` class (must be a child class of :ref:`VoIPCall`). + + The *sip_class* argument allows to override the used :ref:`SIPClient` class (must be a child class of :ref:`SIPClient`). .. _VoIPPhone: VoIPPhone ========= -The VoIPPhone class is used to manage the :ref:`SIPClient` class and create :ref:`VoIPCall`'s when there is an incoming call. It then uses the VoIPCall class to handle the call states. - -*class* VoIP.\ **VoIPPhone**\ (voip_phone_parameter: VoIPPhoneParameter) +The VoIPPhone class is used to manage the :ref:`SIPClient` class and create :ref:`VoIPCall`'s when there is an incoming call or a :term:`user` makes a call. It then uses the VoIPCall class to handle the call's states. - **callback**\ (request: :ref:`SIPMessage`) -> None - This method is called by the :ref:`SIPClient` when an INVITE or BYE request is received. This function then creates a :ref:`VoIPCall` or terminates it respectively. When a VoIPCall is created, it will then pass it to the *callCallback* function as an argument. If *callCallback* is set to None, this function replies as BUSY. **This function should not be called by the** :term:`user`. - - **get_status**\ () -> PhoneStatus - This method returns the :ref:`PhoneStatus`. - - **request_port**\ (blocking=True) -> int - This method is called when a new port is needed to use in a :ref:`VoIPCall`. If blocking is set to True, this will wait until a port is available. Otherwise, it will raise NoPortsAvailableError. - - **release_ports**\ (call: Optional[VoIPCall] = None) -> None - This method is called when a call ends. If call is provided, it will only release the ports used by that :ref:`VoIPCall`. Otherwise, it will iterate through all active calls, and release all ports that are no longer in use. +*class* pyVoIP.VoIP.\ **VoIPPhone**\ (voip_phone_parameter: :ref:`VoIPPhoneParameter`) + **get_status**\ () -> :ref:`PhoneStatus ` + This method returns the phone's current status. **start**\ () -> None - This method starts the :ref:`SIPClient` class. On failure, this will automatically call stop(). + This method starts the :ref:`SIPClient` class. On failure, this will automatically call stop(). **stop**\ () -> None - This method ends all currently ongoing calls, then stops the :ref:`SIPClient` class + This method ends all ongoing calls, then stops the :ref:`SIPClient` class - **call**\ (number: str) -> :ref:`VoIPCall` - Originates a call using PCMU and telephone-event. The *number* argument must be a string, and it returns a :ref:`VoIPCall` class in CallState.DIALING. You should use a while loop to wait until the CallState is ANSWRED. + **call**\ (number: str, payload_types: Optional[List[:ref:`PayloadType`]] = None) -> :ref:`VoIPCall` + Originates a call using the specified *payload_types*, or PCMU and telephone-event by default. The *number* argument must be a string. + + Returns a :ref:`VoIPCall` class in CallState.DIALING. + + **message**\ (number: str, body: str, ctype = "text/plain") -> bool + Sends a MESSAGE request to the *number* with the text of *body*, and the Content-Type header is set to the value of *ctype*.