From 1f1f870c1ae7ca40119e2fc8973e6314d3615aca Mon Sep 17 00:00:00 2001 From: Ajay Raj Date: Mon, 15 Jul 2024 14:10:33 -0700 Subject: [PATCH 1/2] adds # and * support and also ability to press multiple buttons in a row --- vocode/streaming/utils/dtmf_utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vocode/streaming/utils/dtmf_utils.py b/vocode/streaming/utils/dtmf_utils.py index 34732dbce..fbf80eed4 100644 --- a/vocode/streaming/utils/dtmf_utils.py +++ b/vocode/streaming/utils/dtmf_utils.py @@ -8,6 +8,7 @@ from vocode.streaming.utils.singleton import Singleton DEFAULT_DTMF_TONE_LENGTH_SECONDS = 0.3 +DEFAULT_DTMF_TONE_SILENCE_SECONDS = 0.1 MAX_INT = 32767 @@ -22,6 +23,8 @@ class KeypadEntry(str, Enum): EIGHT = "8" NINE = "9" ZERO = "0" + POUND = "#" + STAR = "*" DTMF_FREQUENCIES = { @@ -35,6 +38,8 @@ class KeypadEntry(str, Enum): KeypadEntry.EIGHT: (852, 1336), KeypadEntry.NINE: (852, 1477), KeypadEntry.ZERO: (941, 1336), + KeypadEntry.STAR: (941, 1209), + KeypadEntry.POUND: (941, 1477), } @@ -49,6 +54,7 @@ def generate( sampling_rate: int, audio_encoding: AudioEncoding, duration_seconds: float = DEFAULT_DTMF_TONE_LENGTH_SECONDS, + silence_seconds: float = DEFAULT_DTMF_TONE_SILENCE_SECONDS, ) -> bytes: if (keypad_entry, sampling_rate, audio_encoding) in self.tone_cache: return self.tone_cache[(keypad_entry, sampling_rate, audio_encoding)] @@ -57,6 +63,7 @@ def generate( tone = np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t) tone = tone / np.max(np.abs(tone)) # Normalize to [-1, 1] pcm = (tone * MAX_INT).astype(np.int16).tobytes() + pcm += b"\0" * int(silence_seconds * sampling_rate * 2) if audio_encoding == AudioEncoding.MULAW: output = audioop.lin2ulaw(pcm, 2) else: From d670bd032186b97986beec6cc5bb206ae994b4bf Mon Sep 17 00:00:00 2001 From: Ajay Raj Date: Mon, 15 Jul 2024 17:12:57 -0700 Subject: [PATCH 2/2] fix tests --- tests/streaming/action/test_dtmf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/streaming/action/test_dtmf.py b/tests/streaming/action/test_dtmf.py index e65f46cf5..6466aeb8b 100644 --- a/tests/streaming/action/test_dtmf.py +++ b/tests/streaming/action/test_dtmf.py @@ -32,7 +32,7 @@ async def test_vonage_dtmf_press_digits(mocker, mock_env): action = VonageDTMF(action_config=DTMFVocodeActionConfig()) vonage_uuid = generate_uuid() - digits = "1234" + digits = "1234*#" vonage_phone_conversation_mock = mocker.MagicMock() vonage_config = VonageConfig( @@ -92,7 +92,7 @@ async def test_twilio_dtmf_press_digits( mocker, mock_env, mock_twilio_phone_conversation, mock_twilio_output_device: TwilioOutputDevice ): action = TwilioDTMF(action_config=DTMFVocodeActionConfig()) - digits = "1234" + digits = "1234*#" twilio_sid = "twilio_sid" action.attach_conversation_state_manager( @@ -136,7 +136,7 @@ async def test_twilio_dtmf_failure( mocker, mock_env, mock_twilio_phone_conversation, mock_twilio_output_device: TwilioOutputDevice ): action = TwilioDTMF(action_config=DTMFVocodeActionConfig()) - digits = "****" + digits = "%%%%" twilio_sid = "twilio_sid" action.attach_conversation_state_manager(