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
The roadmap calls for a voicemail system, and the current voice stack already has most low-level primitives: CallSession.play(), CallSession.record(), WAV format validation, DTMF collection, and an auto-answer example in server.py. What is missing is a small, reusable voicemail helper that turns those primitives into a safe PBX building block: play a greeting, record caller audio, store metadata, and make tests deterministic without hardware.
This should be a one-PR slice focused on local voicemail capture, not a full dashboard or remote mailbox product.
User journey
An operator configures a voicemail directory and greeting WAV.
Their call handler delegates unanswered/after-hours calls to a voicemail box.
Callstack plays the greeting, records up to a bounded duration, optionally stops on DTMF, and hangs up cleanly.
A VoicemailMessage metadata record is returned so the app can show, upload, or notify about the saved message.
File names and logs avoid embedding raw phone numbers.
Optional later integration with pre-answer routing can send only rejected/after-hours calls to voicemail, but this first slice can work with the existing on_call flow.
Technical approach
Add a new callstack/voice/voicemail.py module with:
Motivation
The roadmap calls for a voicemail system, and the current voice stack already has most low-level primitives:
CallSession.play(),CallSession.record(), WAV format validation, DTMF collection, and an auto-answer example inserver.py. What is missing is a small, reusable voicemail helper that turns those primitives into a safe PBX building block: play a greeting, record caller audio, store metadata, and make tests deterministic without hardware.This should be a one-PR slice focused on local voicemail capture, not a full dashboard or remote mailbox product.
User journey
VoicemailMessagemetadata record is returned so the app can show, upload, or notify about the saved message.API / UX sketch
Optional later integration with pre-answer routing can send only rejected/after-hours calls to voicemail, but this first slice can work with the existing
on_callflow.Technical approach
callstack/voice/voicemail.pymodule with:VoicemailBoxconfiguration: directory, greeting path, max duration, stop-on-DTMF, optional goodbye prompt.VoicemailMessagedataclass: id, audio path, caller label/ID, started/ended timestamps, duration seconds, byte size, termination reason.CallSession.play()andCallSession.record()instead of duplicating audio transport code.CallSession/AudioPipelineorMockTransportso no real modem/audio hardware is needed.Affected modules and tests
Likely files:
callstack/voice/voicemail.py—VoicemailBox,VoicemailMessage, metadata helpers.callstack/voice/__init__.pyand/orcallstack/__init__.py— public exports if consistent with existing API style.tests/test_voicemail.py— greeting playback, recording path generation, JSON metadata, DTMF stop option, hangup behavior, error cases.server.pyonly if replacing the demo greet-and-hangup with a tiny commented example; keep docs/examples minimal to avoid scope creep.Existing context:
CallSession.record(output_path, max_duration, stop_on_dtmf)already records 8 kHz, 16-bit mono WAV viaAudioPipeline.record().AudioPlayer.validate()already rejects incompatible greeting WAV files.server.pycurrently auto-answers and playsaudio/greet.wav, then hangs up.Hardware / modem caveats
AudioPipeline; voicemail should not introduce new modem-specific commands.DTMFEventbehavior; if Normalize quoted DTMF URC digits before IVR dispatch #37 is unresolved, tests should use normalized public events rather than raw URCs.Acceptance criteria
VoicemailBox.record(session)plays the configured greeting before recording.max_durationis enforced andstop_on_dtmf=Trueis passed through to the existing recording path.Exact verification gates
Non-goals