diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eee0445..db0d8e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,7 +84,7 @@ The following table shows all the change types we use. All like change types sho | Fixed something that was broken | FIX | | Removed code, file, etc. | REMOVE | -Each line of your commit message should not excede 79 characters. PEP8 limits code to 79 characters long because `Limiting the required editor window width makes it possible to have several files open side by side, and works well when using code review tools that present the two versions in adjacent columns`. This will ensure readability when running `git log`. +Each line of your commit message should not exceed 79 characters. PEP8 limits code to 79 characters long because `Limiting the required editor window width makes it possible to have several files open side by side, and works well when using code review tools that present the two versions in adjacent columns`. This will ensure readability when running `git log`. For multilined descriptions, the following line should start inline with the first letter after the change type. diff --git a/README.md b/README.md index 8d81ab3..e275226 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This basic code will simple make a phone that will automatically answer then han from pyVoIP.credentials import CredentialsManager from pyVoIP.VoIP.call import VoIPCall from pyVoIP.VoIP.error import InvalidStateError -from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParamter +from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParameter class Call(VoIPCall): @@ -35,7 +35,7 @@ class Call(VoIPCall): if __name__ == "__main__": cm = CredentialsManager() cm.add(, ) - params = VoIPPhoneParamter(, , , cm, bind_ip=, call_class=Call) + params = VoIPPhoneParameter(, , , cm, bind_ip=, call_class=Call) phone = VoIPPhone(params) phone.start() input('Press enter to disable the phone') diff --git a/docs/Credentials.rst b/docs/Credentials.rst index f63a657..50071f3 100644 --- a/docs/Credentials.rst +++ b/docs/Credentials.rst @@ -3,7 +3,7 @@ Credentials Since SIP requests can traverse multiple servers and can receive multiple challenges, the Credentials Manager was made to store multiple passwords and pyVoIP will use the appropriate password upon request. -Per `RFC 3261 Section 22.1 `_, SIP uses authentication similar to HTTP authentication (:RFC:`2617`), with the main difference being ``The realm string alone defines the protection domain.``. However, some services always use the same domain. For example, if you need to authenticate with two seperate Asterisk servers, the realm will almost certainly be ``asterisk`` for both, despite being otherwise unrelated servers. For that reason, the Credentials Manager also supports server filtering. +Per `RFC 3261 Section 22.1 `_, SIP uses authentication similar to HTTP authentication (:RFC:`2617`), with the main difference being ``The realm string alone defines the protection domain.``. However, some services always use the same domain. For example, if you need to authenticate with two separate Asterisk servers, the realm will almost certainly be ``asterisk`` for both, despite being otherwise unrelated servers. For that reason, the Credentials Manager also supports server filtering. .. _CredentialsManager: @@ -19,10 +19,10 @@ CredentialsManager The *password* argument is the password that will be used in the Authentication header digest calculation. The *server* argument is used to determine the correct credentials when challenged for authentication. If *server* is left as ``None``, the credentials may be selected with any server. - + The *realm* argument is used to determine the correct credentials when challenged for authentication. If *realm* is left as ``None``, the credentials may be selected with any realm. - + The *user* argument is used to determine the correct credentials when challenged for authentication. If *user* is left as ``None``, the credentials may be selected with any user. The *user* argument is the user in the SIP URI, **not** the username used in authentication. - + **get**\ (server: str, realm: str, user: str) -> Dict[str, str] Looks for credentials that match the server, realm, and user in that order. If no matchng credentials are found, this will return anonymous credentials as a server MAY accept them per `RFC 3261 Section 22.1 `_. diff --git a/docs/Examples.rst b/docs/Examples.rst index e4d42cc..91af9e6 100644 --- a/docs/Examples.rst +++ b/docs/Examples.rst @@ -8,16 +8,16 @@ Setup PyVoIP uses a :ref:`VoIPPhone` class to receive and initiate phone calls. The settings for our phone are passed via the :ref:`VoIPPhoneParameter` dataclass. When a call is received, a new instance of a :ref:`VoIPCall` is initialized. You can overwrite this class in initialization of VoIPPhone. -In this example, we are importing :ref:`CredentialsManager`, :ref:`VoIPPhone`, :ref:`VoIPPhoneParameter`, :ref:`VoIPCall`, and :ref:`InvalidStateError`. :ref:`CredentialsManager` stores and retreives passwords for authentication with registrars. :ref:`VoIPPhone` is the main class for our `softphone `_. :ref:`VoIPPhoneParameter` is the settings for our :ref:`VoIPPhone`. :ref:`VoIPCall` will be used to create our custom answering class. An :ref:`InvalidStateError` is thrown when you try to perform an impossible command. For example, denying the call when the phone is already answered, answering when it's already answered, etc. +In this example, we are importing :ref:`CredentialsManager`, :ref:`VoIPPhone`, :ref:`VoIPPhoneParameter`, :ref:`VoIPCall`, and :ref:`InvalidStateError`. :ref:`CredentialsManager` stores and retrieves passwords for authentication with registrars. :ref:`VoIPPhone` is the main class for our `softphone `_. :ref:`VoIPPhoneParameter` is the settings for our :ref:`VoIPPhone`. :ref:`VoIPCall` will be used to create our custom answering class. An :ref:`InvalidStateError` is thrown when you try to perform an impossible command. For example, denying the call when the phone is already answered, answering when it's already answered, etc. The following will create a phone that answers and automatically hangs up: .. code-block:: python - + from pyVoIP.credentials import CredentialsManager from pyVoIP.VoIP.call import VoIPCall from pyVoIP.VoIP.error import InvalidStateError - from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParamter + from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParameter class Call(VoIPCall): @@ -31,12 +31,12 @@ The following will create a phone that answers and automatically hangs up: if __name__ == "__main__": cm = CredentialsManager() cm.add(, ) - params = VoIPPhoneParamter(, , , cm, bind_ip=, call_class=Call) + params = VoIPPhoneParameter(, , , cm, bind_ip=, call_class=Call) phone = VoIPPhone(params) phone.start() input('Press enter to disable the phone') phone.stop() - + Announcement Board ****************** @@ -47,7 +47,7 @@ Let's say you want to make a phone that when you call it, it plays an announceme from pyVoIP.credentials import CredentialsManager from pyVoIP.VoIP.call import VoIPCall from pyVoIP.VoIP.error import InvalidStateError - from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParamter + from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParameter import time import wave @@ -55,16 +55,16 @@ Let's say you want to make a phone that when you call it, it plays an announceme def ringing(self, invite_request): try: - f = wave.open('announcment.wav', 'rb') + f = wave.open('announcement.wav', 'rb') frames = f.getnframes() data = f.readframes(frames) f.close() - + call.answer() call.write_audio(data) # This writes the audio data to the transmit buffer, this must be bytes. - + stop = time.time() + (frames / 8000) # frames/8000 is the length of the audio in seconds. 8000 is the hertz of PCMU. - + while time.time() <= stop and call.state == CallState.ANSWERED: time.sleep(0.1) call.hangup() @@ -76,7 +76,7 @@ Let's say you want to make a phone that when you call it, it plays an announceme if __name__ == "__main__": cm = CredentialsManager() cm.add(, ) - params = VoIPPhoneParamter(, , , cm, bind_ip=, call_class=Call) + params = VoIPPhoneParameter(, , , cm, bind_ip=, call_class=Call) phone = VoIPPhone(params) phone.start() input('Press enter to disable the phone') @@ -87,7 +87,7 @@ Something important to note is our wait function. We are currently using: .. code-block:: python stop = time.time() + (frames / 8000) # The number of frames/8000 is the length of the audio in seconds. - + while time.time() <= stop and call.state == CallState.ANSWERED: time.sleep(0.1) @@ -105,10 +105,10 @@ We can use the following code to create `IVR Menus , ) - params = VoIPPhoneParamter(, , , cm, bind_ip=, call_class=Call) + params = VoIPPhoneParameter(, , , cm, bind_ip=, call_class=Call) phone = VoIPPhone(params) phone.start() input('Press enter to disable the phone') @@ -156,7 +156,7 @@ We can use the following code to handle various states for calls: from pyVoIP.credentials import CredentialsManager from pyVoIP.VoIP.call import VoIPCall from pyVoIP.VoIP.error import InvalidStateError - from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParamter + from pyVoIP.VoIP.phone import VoIPPhone, VoIPPhoneParameter import time import wave @@ -181,7 +181,7 @@ We can use the following code to handle various states for calls: if __name__ == '__main__': cm = CredentialsManager() cm.add(, ) - params = VoIPPhoneParamter(, , , cm, bind_ip=, call_class=Call) + params = VoIPPhoneParameter(, , , cm, bind_ip=, call_class=Call) phone = VoIPPhone(params) phone.start() phone.call() diff --git a/docs/Networking.rst b/docs/Networking.rst index 3142a74..a4d56cc 100644 --- a/docs/Networking.rst +++ b/docs/Networking.rst @@ -20,7 +20,7 @@ pyVoIP.networking.nat.\ **AddressType** Used for determining remote or local tags in SIP messages. AddressType.\ **REMOTE** - + AddressType.\ **LOCAL** .. _TransportMode: @@ -30,21 +30,21 @@ pyVoIP.networking.transport.\ **TransportMode** TransportMode.\ **value** This is the string value of the TransportMode. For example, ``UDP`` or ``TLS``. - + TransportMode.\ **socket_type** This is the `SocketKind `_ associated with the TransportMode. - + TransportMode.\ **tls_mode** This is either `PROTOCOL_TLS `_ when using TLS or None otherwise. - + Here is a list of current supported transport modes: TransportMode.\ **UDP** "UDP", `SOCK_DGRAM `_, None - + TransportMode.\ **TCP** "TCP", `SOCK_STREAM `_, None - + TransportMode.\ **TLS** "TLS", `SOCK_STREAM `_, `PROTOCOL_TLS `_ @@ -69,7 +69,7 @@ The NAT class is used automatically understand and translate IPs and hostnames f **get_host**\ (host: str) -> str This method return the hostname another :term:`client` needs to connect to us. - + **check_host**\ (host: str) -> :ref:`AddressType` This method determine if a host is a remote computer or not. @@ -102,14 +102,14 @@ The VoIPSocket class is the phone's main SIP socket. It receives and processes a VoIPConnection ============== -The VoIPConnecion class is a wrapper for Python's sockets. Since UDP, TCP, and TLS sockets all have different quarks in Python, this class consolidates everything into one interface. For UDP, VoIPConnection will pull messages from :ref:`VoIPSocket`'s database. +The VoIPConnection class is a wrapper for Python's sockets. Since UDP, TCP, and TLS sockets all have different quarks in Python, this class consolidates everything into one interface. For UDP, VoIPConnection will pull messages from :ref:`VoIPSocket`'s database. *class* pyVoIP.networking.sock.\ **VoIPConnection**\ (voip_sock: :ref:`VoIPSocket`, conn: Optional[:ref:`SOCKETS`, message: :ref:`SIPMessage`) - The *voiop_socket* argument is a :ref:`VoIPSocket` instance reference. + The *voip_socket* argument is a :ref:`VoIPSocket` instance reference. The *conn* argument is the underlying Python socket. - The *message* argument is the :ref:`SIPMessage` used to initate the dialog. + The *message* argument is the :ref:`SIPMessage` used to initiate the dialog. **send**\ (data: Union[bytes, str]) -> None Sends *data* to the :term:`client`. If *data* is a string, it will be UTF8 encoded first. diff --git a/docs/RTP.rst b/docs/RTP.rst index a22e82f..f56b656 100644 --- a/docs/RTP.rst +++ b/docs/RTP.rst @@ -1,7 +1,7 @@ RTP - Real-time Transport Protocol ################################### -The RTP module recives and transmits sound and phone-event data for a particular phone call. +The RTP module receives and transmits sound and phone-event data for a particular phone call. Functions ********* @@ -10,16 +10,16 @@ The RTP module has two functions that are used by various classes for packet par pyVoIP.RTP.\ **byte_to_bits**\ (byte: bytes) -> str This method converts a single byte into an eight character string of ones and zeros. The *byte* argument must be a single byte. - + pyVoIP.RTP.\ **add_bytes**\ (bytes: bytes) -> int This method takes multiple bytes and adds them together into an integer. - + Errors ******* *exception* pyVoIP.RTP.\ **DynamicPayloadType** This may be thrown when you try to int cast a dynamic PayloadType. Most PayloadTypes have a number assigned in `RFC 3551 Section 6 `_. However, some are considered to be 'dynamic' meaning the PBX/VoIP server will pick an available number, and define it. - + *exception* pyVoIP.RTP.\ **RTPParseError** This is thrown by :ref:`RTPMessage` when unable to parse a RTP message. It may also be thrown by `RTPClient` when it's unable to encode or decode the RTP packet payload. @@ -28,71 +28,71 @@ Enums pyVoIP.RTP.\ **RTPProtocol** RTPProtocol is an Enum with three attributes. It defines the method that packets are to be sent with. Currently, only AVP is supported. - + RTPProtocol.\ **UDP** This means the audio should be sent with pure UDP. Returns ``'udp'`` when string casted. - + RTPProtocol.\ **AVP** This means the audio should be sent with RTP Audio/Video Protocol described in :RFC:`3551`. Returns ``'RTP/AVP'`` when string casted. - + RTPProtocol.\ **SAVP** This means the audio should be sent with RTP Secure Audio/Video Protocol described in :RFC:`3711`. Returns ``'RTP/SAVP'`` when string casted. - + .. _transmittype: - + pyVoIP.RTP.\ **TransmitType** TransmitType is an Enum with four attributes. It describes how the :ref:`RTPClient` should act. - + TransmitType.\ **RECVONLY** - This means the RTPClient should only recive audio, not transmit it. Returns ``'recvonly'`` when string casted. - + This means the RTPClient should only receive audio, not transmit it. Returns ``'recvonly'`` when string casted. + TransmitType.\ **SENDRECV** This means the RTPClient should send and receive audio. Returns ``'sendrecv'`` when string casted. - + TransmitType.\ **SENDONLY** This means the RTPClient should only send audio, not receive it. Returns ``'sendonly'`` when string casted. - + TransmitType.\ **INACTIVE** This means the RTP client should not send or receive audio, and instead wait to be activated. Returns ``'inactive'`` when string casted. .. _payload-type: pyVoIP.RTP.\ **PayloadType** - PayloadType is an Enum with multiple attributes. It described the list of attributes in `RFC 3551 Section 6 `_. Currently, only one dynamic event is assigned: telephone-event. Telephone-event is used for sending and recieving DTMF codes. There are a few conflicing names in the RFC as they're the same codec with varrying options so we will go over the conflicts here. PayloadType has the following attributes: - + PayloadType is an Enum with multiple attributes. It described the list of attributes in `RFC 3551 Section 6 `_. Currently, only one dynamic event is assigned: telephone-event. Telephone-event is used for sending and receiving DTMF codes. There are a few conflicting names in the RFC as they're the same codec with varrying options so we will go over the conflicts here. PayloadType has the following attributes: + type.\ **value** This is either the number assigned as PT in the `RFC 3551 Section 6 chart `_, or it is the encoding name if it is dynamic. Int casting the PayloadType will return this number, or raise a DynamicPayloadType error if the protocol is dynamic. - + type.\ **rate** This will return the clock rate of the codec. - + type.\ **channel** This will return the number of channels the used in the codec, or for Non-codecs like telephone-event, it will return zero. - + type.\ **description** This will return the encoding name of the payload. String casting the PayloadType will return this value. - + PayloadType.\ **DVI4_8000** This variation of the DVI4 Codec has the attributes: value 5, rate 8000, channel 1, description "DVI4" - + PayloadType.\ **DVI4_16000** This variation of the DVI4 Codec has the attributes: value 6, rate 16000, channel 1, description "DVI4" - + PayloadType.\ **DVI4_11025** This variation of the DVI4 Codec has the attributes: value 16, rate 11025, channel 1, description "DVI4" - + PayloadType.\ **DVI4_22050** This variation of the DVI4 Codec has the attributes: value 17, rate 22050, channel 1, description "DVI4" - + PayloadType.\ **L16** This variation of the L16 Codec has the attributes: value 11, rate 44100, channel 1, description "L16" - + PayloadType.\ **L16_2** This variation of the L16 Codec has the attributes: value 11, rate 44100, channel 2, description "L16" - + PayloadType.\ **EVENT** This is the dynamic non-codec 'telephone-event'. Telephone-event is used for sending and receiving DTMF codes. - + Classes ********* @@ -104,13 +104,13 @@ RTPPacketManager The RTPPacketManager class utilizes an ``io.ByteIO`` that stores either received payloads, or raw audio data waiting to be transmitted. pyVoIP.RTP.\ **RTPPacketManager**\ () - + **read**\ (length=160) -> bytes Reads *length* bytes from the ByteIO. This will always return the length requested, and will append ``b'\x80'``'s onto the end of the available bytes to achieve this length. - + **rebuild**\ (reset: bool, offset=0, data=b'') -> None This rebuilds the ByteIO if packets are sent out of order. Setting the argument *reset* to ``True`` will wipe all data in the ByteIO and insert in the data in the argument *data* at the position in the argument *offset*. - + **write**\ (offset: int, data: bytes) -> None Writes the data in the argument *data* to the ByteIO at the position in the argument *offset*. RTP data comes with a timestamp that is passed as the offset in this case. This makes it so a hole left by delayed packets can be filled later. If a packet with a timestamp sooner than any other timestamp received, it will rebuild the ByteIO with the new data. If this new position is over 100,000 bytes before the earliest byte, the ByteIO is completely wiped and starts over. This is to prevent Overflow errors. @@ -122,49 +122,49 @@ RTPMessage The RTPMessage class is used to parse RTP packets and makes them easily processed by the :ref:`RTPClient`. pyVoIP.RTP.\ **RTPMessage**\ (data: bytes, assoc: dict[int, :ref:`PayloadType`]) - + The *data* argument is the received RTP packet in bytes. - + The *assoc* argument is a dictionary, using the payload number as a key and a :ref:`PayloadType` as the value. This way RTPMessage can determine what number a dynamic payload is. This association dictionary is generated by :ref:`VoIPCall`. - + RTPMessage has attributes that come from `RFC 3550 Section 5.1 `_. RTPMessage has the following attributes: - + RTPMessage.\ **version** This attribute is the RTP packet version, represented as an integer. - + RTPMessage.\ **padding** If this attribute is set to True the payload has padding. - + RTPMessage.\ **extension** If this attribute is set to True the packet has a header extension. - + RTPMessage.\ **CC** This attribute is the CSRC Count, represented as an integer. - + RTPMessage.\ **marker** This attribute is set to True if the marker bit is set. - + RTPMessage.\ **payload_type** This attribute is set to the :ref:`PayloadType` that corresponds to the payload codec. - + RTPMessage.\ **sequence** This attribute is set to the sequence number of the RTP packet, represented as an integer. - + RTPMessage.\ **timestamp** This attribute is set to the timestamp of the RTP packet, represented as an integer. - + RTPMessage.\ **SSRC** This attribute is set to the synchronization source of the RTP packet, represented as an integer. - + RTPMessage.\ **payload** This attribute is the payload data of the RTP packet, represented as bytes. - + RTPMessage.\ **raw** This attribute is the unparsed version of the *data* argument, in bytes. - + **summary**\ () -> str This method returns a string representation of the RTP packet excluding the payload. - + **parse**\ (data: bytes) -> None This method is called by the initialization of the class. It determines the RTP version, whether the packet has padding, has a header extension, and other information about the backet. @@ -176,57 +176,57 @@ RTPClient The RTPClient is used to send and receive RTP packets and encode/decode the audio codecs. *class* pyVoIP.RTP.\ **RTPClient**\ (assoc: dict[int, :ref:`PayloadType`], inIP: str, inPort: int, outIP: str, outPort: int, sendrecv: :ref:`TransmitType`, dtmf: Optional[Callable[[str], None] = None): - + The *assoc* argument is a dictionary, using the payload number as a key and a :ref:`PayloadType` as the value. This way, RTPMessage can determine what a number a dynamic payload is. This association dictionary is generated by :ref:`VoIPCall`. - + The *inIP* argument is used to receive incoming RTP message. - + The *inPort* argument is the port RTPClient will bind to, to receive incoming RTP packets. - + The *outIP* argument is used to transmit RTP packets. - + The *outPort* argument is used to transmit RTP packets. - + The *sendrecv* argument describes how the RTPClient should act. Please reference :ref:`TransmitType` for more details. - + The *dtmf* argument is set to the callback :ref:`VoIPCall`.dtmfCallback(). - + **start**\ () -> None This method is called by :ref:`VoIPCall`.answer(). It starts the recv() and trans() threads. It is also what initiates the bound port. **This should not be called by the** :term:`user`. - + **stop**\ () -> None This method is called by :ref:`VoIPCall`.hangup() and :ref:`VoIPCall`.bye(). It stops the recv() and trans() threads. It will also close the bound port. **This should not be called by the** :term:`user`. - + **read**\ (length=160, blocking=True) -> bytes This method is called by :ref:`VoIPCall`.readAudio(). It 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 bytes(length). - + **write**\ (data: bytes) -> None This method is called by :ref:`VoIPCall`.writeAudio(). It queues the data written to be sent to the :term:`client`. - + **recv**\ () -> None This method is called by RTPClient.start() and is responsible for receiving and parsing through RTP packets. **This should not be called by the** :term:`user`. - + **trans**\ () -> None This method is called by RTPClient.start() and is responsible for transmitting RTP packets. **This should not be called by the** :term:`user`. - + **parse_packet**\ (packet: bytes) -> None This method is called by the recv() thread. It converts the argument *packet* into a :ref:`RTPMessage`, then sends it to the proper parse function depending on the :ref:`PayloadType`. - + **encode_packet**\ (payload: bytes) -> bytes - This method is called by the trans() thread. It encoded the argument *payload* into the prefered codec. Currently, PCMU is the hardcoded prefered codec. The trans() thread will use the payload to create the RTP packet before transmitting. - + This method is called by the trans() thread. It encoded the argument *payload* into the preferred codec. Currently, PCMU is the hardcoded preferred codec. The trans() thread will use the payload to create the RTP packet before transmitting. + **parse_pcmu**\ (packet: :ref:`RTPMessage`) -> None This method is called by parse_packet(). It will decode the *packet*'s payload from PCMU to linear/raw audio and write it to the incoming :ref:`RTPPacketManager`. - + **encode_pcmu**\ (packet: bytes) -> bytes This method is called by encode_packet(). It will encode the *payload* into the PCMU audio codec. - + **parse_pcma**\ (packet: :ref:`RTPMessage`) -> None This method is called by parse_packet(). It will decode the *packet*'s payload from PCMA to linear/raw audio and write it to the incoming :ref:`RTPPacketManager`. - + **encode_pcma**\ (payload: bytes) -> bytes This method is called by encode_packet(). It will encode the *payload* into the PCMA audio codec. - + **parse_telephone_event**\ (packet: :ref:`RTPMessage`) -> None This method is called by parse_packet(). It will decode the *packet*'s payload from the telephone-event non-codec to the string representation of the event. It will then call :ref:`VoIPCall`.dtmf_callback(). - + diff --git a/docs/VoIP.rst b/docs/VoIP.rst index 9374adf..6d567b6 100644 --- a/docs/VoIP.rst +++ b/docs/VoIP.rst @@ -12,10 +12,10 @@ There are three errors under ``pyVoIP.VoIP.error``. *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* 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* pyVoIP.VoIP.error.\ **NoPortsAvailableError** This is thrown when a call is attempting to be initiated but no RTP ports are available. @@ -84,9 +84,9 @@ VoIPCall The VoIPCall class is used to represent a single VoIP session, which may be to multiple :term:`clients`. *class* pyVoIP.VoIP.call.\ **VoIPCall**\ (phone: :ref:`VoIPPhone`, callstate: :ref:`CallState `, request: :ref:`SIPMessage`, session_id: int, bind_ip: str, conn: :ref:`VoIPConnection`, ms: Optional[Dict[int, :ref:`PayloadType`]] = None, sendmode="sendonly") - The *phone* argument is the initating instance of :ref:`VoIPPhone`. + The *phone* argument is the initiating instance of :ref:`VoIPPhone`. - The *callstate* arguement is the initiating :ref:`CallState`. + The *callstate* argument is the initiating :ref:`CallState`. The *request* argument is the :ref:`SIPMessage` representation of the SIP INVITE request from the VoIP server. @@ -94,14 +94,14 @@ The VoIPCall class is used to represent a single VoIP session, which may be to m The *bind_ip* argument is the IP address that pyVoIP will bind its sockets 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. + The *ms* argument 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 `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 - + self.get_dtmf() >>> '1' self.get_dtmf(length=2) @@ -120,22 +120,22 @@ The VoIPCall class is used to represent a single VoIP session, which may be to m **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. - + **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.** - + **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``. - + .. _VoIPPhoneParameter: VoIPPhoneParameter @@ -180,18 +180,18 @@ The VoIPPhone class is used to manage the :ref:`SIPClient` class and create :ref *class* pyVoIP.VoIP.phone.\ **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(). - + **stop**\ () -> None This method ends all ongoing calls, then stops the :ref:`SIPClient` class - + **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. + 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*. - + diff --git a/pyVoIP/RTP.py b/pyVoIP/RTP.py index b646aa5..49bf209 100644 --- a/pyVoIP/RTP.py +++ b/pyVoIP/RTP.py @@ -205,7 +205,7 @@ def write(self, offset: int, data: bytes) -> None: self.bufferLock.release() """ Rebuilds the buffer if something before the earliest - timestamp comes in, this will stop overwritting. + timestamp comes in, this will stop overwriting. """ self.rebuild(reset, offset, data) return @@ -415,7 +415,7 @@ def trans(self) -> None: self.outSequence += 1 self.outTimestamp += len(payload) # Calculate how long it took to generate this packet. - # Then how long we should wait to send the next, then devide by 2. + # Then how long we should wait to send the next, then divide by 2. delay = (1 / self.preference.rate) * 160 sleep_time = max( 0, delay - ((time.monotonic_ns() - last_sent) / 1000000000) diff --git a/pyVoIP/SIP/client.py b/pyVoIP/SIP/client.py index d7bf526..38be3a6 100644 --- a/pyVoIP/SIP/client.py +++ b/pyVoIP/SIP/client.py @@ -36,7 +36,7 @@ debug = pyVoIP.debug -UNAUTORIZED_RESPONSE_CODES = [ +UNAUTHORIZED_RESPONSE_CODES = [ ResponseCode.UNAUTHORIZED, ResponseCode.PROXY_AUTHENTICATION_REQUIRED, ] @@ -183,12 +183,12 @@ def parse_message(self, message: SIPMessage) -> None: response = self.gen_ok(message) try: # BYE comes from client cause server only acts as mediator - (_sender_adress, _sender_port) = message.headers["Via"][0][ + (_sender_address, _sender_port) = message.headers["Via"][0][ "address" ] self.sendto( response, - (_sender_adress, int(_sender_port)), + (_sender_address, int(_sender_port)), ) except Exception: debug("BYE Answer failed falling back to server as target") @@ -288,7 +288,7 @@ def __gen_from_to( password: Optional[str] = None, port=5060, uri_params: Optional[str] = None, - header_parms: Optional[str] = None, + header_params: Optional[str] = None, ) -> str: header_type = header_type.capitalize() @@ -299,8 +299,8 @@ def __gen_from_to( uri = self.__gen_uri(method, user, host, password, port, uri_params) display_name = f'"{display_name}" ' if display_name else "" - header_parms = f"{header_parms}" if header_parms else "" - return f"{header_type}: {display_name}<{uri}>{header_parms}\r\n" + header_params = f"{header_params}" if header_params else "" + return f"{header_type}: {display_name}<{uri}>{header_params}\r\n" def __gen_uri( self, @@ -559,7 +559,7 @@ def gen_first_request(self, deregister=False) -> str: self.server, method=method, port=self.port, - header_parms=f";tag={tag}", + header_params=f";tag={tag}", ) regRequest += self.__gen_from_to( "To", self.user, self.server, method=method, port=self.port @@ -599,7 +599,7 @@ def gen_subscribe(self, response: SIPMessage) -> str: self.nat.get_host(self.server), method=method, port=self.bind_port, - header_parms=f";tag={self.gen_tag()}", + header_params=f";tag={self.gen_tag()}", ) subRequest += self.__gen_from_to( "To", @@ -641,7 +641,7 @@ def gen_register(self, request: SIPMessage, deregister=False) -> str: self.server, method=method, port=self.port, - header_parms=f";tag={self.tagLibrary['register']}", + header_params=f";tag={self.tagLibrary['register']}", ) regRequest += self.__gen_from_to( "To", @@ -856,7 +856,7 @@ def gen_invite( self.user, self.nat.get_host(self.server), port=self.bind_port, - header_parms=f";tag={tag}", + header_params=f";tag={tag}", ) invRequest += f"Call-ID: {call_id}\r\n" invRequest += f"CSeq: {self.inviteCounter.next()} INVITE\r\n" @@ -904,7 +904,7 @@ def __gen_refer_new_dialog( self.user, self.nat.get_host(self.bind_ip), method, - header_parms=f";tag={tag}", + header_params=f";tag={tag}", ) # Determine if To or From is local to decide who the refer is to @@ -1122,7 +1122,7 @@ def invite( type(response) is SIPResponse and ( response.status - not in UNAUTORIZED_RESPONSE_CODES + INVITE_OK_RESPONSE_CODES + not in UNAUTHORIZED_RESPONSE_CODES + INVITE_OK_RESPONSE_CODES ) or response.headers["Call-ID"] != call_id ): @@ -1173,7 +1173,7 @@ def gen_message( self.nat.get_host(self.server), method=method, port=self.bind_port, - header_parms=f";tag={self.gen_tag()}", + header_params=f";tag={self.gen_tag()}", ) msg += self.__gen_from_to( "To", @@ -1339,7 +1339,7 @@ def register(self) -> bool: try: registered = self.__register() if not registered: - debug("REGISTERATION FAILED") + debug("REGISTRATION FAILED") self.register_failures += 1 else: self.phone._status = PhoneStatus.REGISTERED @@ -1354,7 +1354,7 @@ def register(self) -> bool: return registered except BaseException as e: - debug(f"REGISTERATION ERROR: {e}") + debug(f"REGISTRATION ERROR: {e}") self.register_failures += 1 if self.register_failures >= pyVoIP.REGISTER_FAILURE_THRESHOLD: self.stop() diff --git a/pyVoIP/SIP/message/parse.py b/pyVoIP/SIP/message/parse.py index 6173e10..cb5d7c4 100644 --- a/pyVoIP/SIP/message/parse.py +++ b/pyVoIP/SIP/message/parse.py @@ -22,7 +22,7 @@ def parse_raw_headers(raw_headers: List[bytes]) -> Dict[str, Any]: headers: Dict[str, Any] = {"Via": []} - # Only use first occurance of VIA header field; + # Only use first occurrence of VIA header field; # got second VIA from Kamailio running in DOCKER # According to RFC 3261 these messages should be # discarded in a response @@ -299,7 +299,7 @@ def parse_sdp_tag(parsed_body: Dict[str, Any], field: str, data: str) -> Any: # b=: # A bwtype of CT means Conference Total between all medias # and all devices in the conference. - # A bwtype of AS means Applicaton Specific total for this + # A bwtype of AS means Application Specific total for this # media and this device. # The bandwidth is given in kilobits per second. # As this was written in 2006, this could be Kibibits. @@ -344,7 +344,7 @@ def parse_sdp_tag(parsed_body: Dict[str, Any], field: str, data: str) -> Any: # SDP 5.14 Media Descriptions # m= / ... # should be even, and +1 should be the RTCP port. - # should coinside with number of + # should coincide with number of # addresses in SDP 5.7 c= if "m" not in parsed_body: parsed_body["m"] = [] diff --git a/pyVoIP/SIP/message/response_codes.py b/pyVoIP/SIP/message/response_codes.py index 7f42387..a72de1d 100644 --- a/pyVoIP/SIP/message/response_codes.py +++ b/pyVoIP/SIP/message/response_codes.py @@ -163,9 +163,9 @@ def description(self, value: str) -> None: "Unsupported URI Scheme", "Cannot satisfy request", ) - UNKOWN_RESOURCE_PRIORITY = ( + UNKNOWN_RESOURCE_PRIORITY = ( 417, - "Unkown Resource-Priority", + "Unknown Resource-Priority", "There was a resource-priority option tag, " + "but no Resource-Priority header", ) @@ -181,7 +181,7 @@ def description(self, value: str) -> None: + "listed in the Supported header.", ) SESSION_INTERVAL_TOO_SMALL = 422, "Session Interval Too Small" - SESSION_INTERVAL_TOO_BRIEF = 423, "Session Interval Too Breif" + SESSION_INTERVAL_TOO_BRIEF = 423, "Session Interval Too Brief" BAD_LOCATION_INFORMATION = 424, "Bad Location Information" USE_IDENTITY_HEADER = ( 428, diff --git a/pyVoIP/VoIP/phone.py b/pyVoIP/VoIP/phone.py index 56b82a5..2b8fb8a 100644 --- a/pyVoIP/VoIP/phone.py +++ b/pyVoIP/VoIP/phone.py @@ -166,14 +166,14 @@ def _callback_MSG_Invite( raise def _callback_MSG_Bye(self, request: SIPMessage) -> None: - debug("BYE recieved") + debug("BYE received") call_id = request.headers["Call-ID"] if call_id not in self.calls: return self.calls[call_id].bye() def _callback_MSG_Options(self, request: SIPMessage) -> str: - debug("Options recieved") + debug("Options received") response = self.sip.gen_busy(request) if self.call_class: response = response.replace("486 Busy Here", "200 OK") @@ -240,7 +240,7 @@ def _callback_RESP_Terminated(self, request: SIPMessage) -> None: self.sip.sendto(ack) def _callback_RESP_NotFound(self, request: SIPMessage) -> None: - debug("Not Found recieved, invalid number called?") + debug("Not Found received, invalid number called?") call_id = request.headers["Call-ID"] if call_id not in self.calls: debug("Unknown/No call") @@ -254,7 +254,7 @@ def _callback_RESP_NotFound(self, request: SIPMessage) -> None: self.sip.sendto(ack) def _callback_RESP_Unavailable(self, request: SIPMessage) -> None: - debug("Service Unavailable recieved") + debug("Service Unavailable received") call_id = request.headers["Call-ID"] if call_id not in self.calls: debug("Unknown call") diff --git a/pyVoIP/credentials.py b/pyVoIP/credentials.py index 21fcc06..65ab01b 100644 --- a/pyVoIP/credentials.py +++ b/pyVoIP/credentials.py @@ -17,7 +17,7 @@ def add( """ Add a username and password for a server, realm, and/or user. - If you want to set a default ommit the option. For examle, if you want + If you want to set a default omit the option. For example, if you want to use the same username and password for the realm asterisk regardless of the server or user you would do: diff --git a/setup.py b/setup.py index a8d046c..41caf29 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ url="https://github.com/tayler6000/pyVoIP", project_urls={ "Bug Tracker": "https://github.com/tayler6000/pyVoIP/issues", - "Documentaiton": "https://pyvoip.readthedocs.io/", + "Documentation": "https://pyvoip.readthedocs.io/", }, classifiers=[ "Programming Language :: Python :: 3",