The claim Noise reduction is a switch, not a setting. In SWML, the denoise verb starts it and stop_denoise stops it; the bundled schema gives both an empty object and describes denoise as “Start noise reduction. You can stop it at any time using stop_denoise”. Over REST, the vendored spec has the same pair as call commands, calling.denoise and calling.denoise.stop, addressed to a live call by id with empty params. The SDK wraps those as client.calling.denoise and client.calling.denoise_stop.
How it works - answer: {}
- denoise: {}
- play: { url: "say:Leave your message after the tone." }
- record: { beep: true, max_length: 60, terminators: "#" }
- stop_denoise: {}
- play: { url: "say:Thanks. Goodbye." }
- hangup: {} Noise reduction is on while the caller records and off for the goodbye. The Python surface builds the same document with SWMLService, and adds two helpers for the REST side:
def quiet(call_id):
return client.calling.denoise(call_id)
def loud(call_id):
return client.calling.denoise_stop(call_id) What the platform receives from quiet:
{"command": "calling.denoise", "id": "6d3f4a0e-2b1c-4e7a-9f0d-1c2b3a4d5e6f", "params": {}} params is empty because the spec’s variant has no properties; id is the call’s id.
Limitations The verifier proves the documents and the requests. What noise reduction does to the audio is the platform’s processing on a live call.
What to change first Move stop_denoise above record in both surfaces and run the verifier. The order assertion fails, which is the point: the switch is on exactly between the two verbs, and the recording sat between them.
Markup Python
swml/agent.yaml python/app.py Copy
# Reduce background noise on a call. `denoise` switches noise reduction on for
# this leg and `stop_denoise` switches it off again; both take no parameters.
# Here it is on while the caller records a message and off for the goodbye.
version : "1.0.0"
sections :
main :
- answer : {}
- denoise : {}
- play : { url : "say:Leave your message after the tone." }
- record :
beep : true
max_length : 60
terminators : "#"
- stop_denoise : {}
- play : { url : "say:Thanks. Goodbye." }
- hangup : {} """Reduce background noise on a call.
Two ways to switch noise reduction on and off for one leg. In SWML, `denoise`
starts it and
`stop_denoise` stops it; both take no parameters. Over REST, the same pair are
the call commands `calling.denoise` and `calling.denoise.stop`, addressed to a
live call by id, so your backend can toggle it mid-call.
Written against signalwire-sdk 3.0.1 (SWMLService, RestClient.calling).
"""
import os
from dotenv import load_dotenv
from signalwire import SWMLService
from signalwire.rest import RestClient
# the SDK does not read .env for you
load_dotenv ()
# RestClient() reads SIGNALWIRE_PROJECT_ID / SIGNALWIRE_API_TOKEN /
# SIGNALWIRE_SPACE from the environment (signalwire/rest/client.py).
client = RestClient ()
def build ( service = None ):
"""The document: noise reduction on while the caller records, off after."""
service = service or SWMLService ( name = "denoise" , route = "/denoise" )
service . reset_document ()
service . add_verb ( "answer" , {})
service . add_verb ( "denoise" , {})
service . add_verb ( "play" , { "url" : "say:Leave your message after the tone." })
service . add_verb ( "record" , { "beep" : True , "max_length" : 60 , "terminators" : "#" })
service . add_verb ( "stop_denoise" , {})
service . add_verb ( "play" , { "url" : "say:Thanks. Goodbye." })
service . add_verb ( "hangup" , {})
return service
def quiet ( call_id ):
"""Switch noise reduction on for a live call, from your backend."""
return client . calling . denoise ( call_id )
def loud ( call_id ):
"""Switch it off again."""
return client . calling . denoise_stop ( call_id )
if __name__ == "__main__" :
build () . serve ( port = int ( os . getenv ( "PORT" , "8080" ))) Run it cd python
pip install -r requirements.txt
cp ../.env.example .env # then edit .env: credentials, and the basic-auth pair
python app.py The webhook needs a public HTTPS URL. For a local run, expose port 8080 with a tunnel such as ngrok and use that hostname. Point a number’s SWML webhook at https://<user>:<password>@<your-host>/denoise/. To toggle mid-call from your backend instead, call quiet(call_id) and loud(call_id) from a Python shell with a live call’s id.
Verify it No network, no account.
cd .. # back to the recipe folder
python verify.py It validates both surfaces, swaps the SDK’s HTTP layer for a recorder, and asserts the following.
both surfaces run answer, denoise, play, record, stop_denoise, play, hangup, in that order, and render the same document denoise and stop_denoise each carry an empty object, and the bundled schema gives both no parametersquiet and loud each make exactly one POST to the documented calling path, measured with a fresh recorder per helpereach body is exactly the command, the call id at the top level, and empty params the spec’s variants for both commands require command, id and params and define no param properties