{"id":17195891,"url":"https://github.com/jchavanton/voip_patrol","last_synced_at":"2025-04-04T22:04:46.162Z","repository":{"id":23868392,"uuid":"67028785","full_name":"jchavanton/voip_patrol","owner":"jchavanton","description":"VoIP signaling and media test automation","archived":false,"fork":false,"pushed_at":"2025-03-19T22:07:50.000Z","size":2781,"stargazers_count":119,"open_issues_count":12,"forks_count":34,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-28T21:06:36.663Z","etag":null,"topics":["c","sip","speech-quality","test-automation","voip"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jchavanton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-31T10:42:48.000Z","updated_at":"2025-03-19T22:07:17.000Z","dependencies_parsed_at":"2023-01-13T23:59:52.348Z","dependency_job_id":"4f04082c-6a85-4e97-9e77-827c89a65eb8","html_url":"https://github.com/jchavanton/voip_patrol","commit_stats":{"total_commits":333,"total_committers":14,"mean_commits":"23.785714285714285","dds":"0.18018018018018023","last_synced_commit":"3bf1b63bdf7bd502e6a006fed26aec5a346f579b"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchavanton%2Fvoip_patrol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchavanton%2Fvoip_patrol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchavanton%2Fvoip_patrol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchavanton%2Fvoip_patrol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jchavanton","download_url":"https://codeload.github.com/jchavanton/voip_patrol/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247256110,"owners_count":20909240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","sip","speech-quality","test-automation","voip"],"created_at":"2024-10-15T01:51:49.200Z","updated_at":"2025-04-04T22:04:46.125Z","avatar_url":"https://github.com/jchavanton.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Docker Pulls](https://img.shields.io/docker/pulls/jchavanton/voip_patrol.svg)](https://hub.docker.com/r/jchavanton/voip_patrol/)\n\n# VoIP Patrol\n![GitHub Logo](VP_Logo_1200px-11th_Airborne_Division.patch_small2.jpg)\n\n## VoIP signaling and media test automaton\nDesigned to automate end2end and or integration tests.\n\nVoIP patrol will follow a scenario in XML format and will output results in JSON.\n\nEach line in the output file is a separate JSON structure, note that the entire file is not a valid JSON file,\nthis is because VoIP patrol will output results as they become available.\n\nIt is possible to test many scenarios that are not easy to test manually like a re-invite with a new codec.\n\n### Docker quick start\n[quick start with docker](QUICK_START.md)\n\n\n### Linux Debian building from sources\n[see commands in Dockerfile](docker/Dockerfile)\n\n### Load test example\n[load test example](load_test/LOAD_TEST.md)\n\n### run\n```\n./voip_patrol --help\n```\n\n### Example: making a test call\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"call\" label=\"us-east-va\"\n            transport=\"tls\"\n            expected_cause_code=\"200\"\n            caller=\"15147371787@noreply.com\"\n            callee=\"12012665228@target.com\"\n            to_uri=\"+12012665228@target.com\"\n            max_duration=\"20\" hangup=\"16\"\n            username=\"VP_ENV_USERNAME\"\n            password=\"VP_ENV_PASSWORD\"\n            rtp_stats=\"true\"\n    \u003e\n        \u003cx-header name=\"X-Foo\" value=\"Bar\"/\u003e\n    \u003c/action\u003e\n    \u003c!-- note: param value starting with VP_ENV_ will be replaced by environment variables --\u003e\n    \u003c!-- note: rtp_stats will include RTP transmission statistics --\u003e\n    \u003c!-- note: x-header tag inside an action will append an header --\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n### Sample JSON output\n```json\n{\n  \"2\": {\n    \"label\": \"us-east-va\",\n    \"start\": \"17-07-2018 00:00:05\",\n    \"end\": \"17-07-2018 00:00:24\",\n    \"action\": \"call\",\n    \"from\": \"15147371787\",\n    \"to\": \"12012665228\",\n    \"result\": \"PASS\",\n    \"expected_cause_code\": 200,\n    \"cause_code\": 200,\n    \"reason\": \"Normal call clearing\",\n    \"callid\": \"7iYDFukJr-9BOLOmWg.7fZyHZeZUAwao\",\n    \"transport\": \"TLS\",\n    \"peer_socket\": \"34.226.136.32:5061\",\n    \"duration\": 16,\n    \"expected_duration\": 0,\n    \"max_duration\": 20,\n    \"hangup_duration\": 16,\n    \"rtp_stats_0\": {\n      \"rtt\": 0,\n      \"remote_rtp_socket\": \"10.250.7.88:4028\",\n      \"codec_name\": \"PCMU\",\n      \"clock_rate\": \"8000\",\n      \"Tx\": {\n        \"jitter_avg\": 0,\n        \"jitter_max\": 0,\n        \"pkt\": 816,\n        \"kbytes\": 127,\n        \"loss\": 0,\n        \"discard\": 0,\n        \"mos_lq\": 4.5\n      },\n      \"Rx\": {\n        \"jitter_avg\": 0,\n        \"jitter_max\": 0,\n        \"pkt\": 813,\n        \"kbytes\": 127,\n        \"loss\": 0,\n        \"discard\": 0,\n        \"mos_lq\": 4.5\n      }\n    }\n  }\n}\n```\n\n### Example: starting a TLS server\n```bash\n./voip_patrol \\\n   --port 5060 \\ # TLS port 5061 +1\n   --conf \"xml/tls_server.xml\" \\\n   --tls-calist \"tls/ca_list.pem\" \\\n   --tls-privkey \"tls/key.pem\" \\\n   --tls-cert \"tls/certificate.pem\" \\\n   --tls-verify-server \\\n```\n\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n     \u003c!-- note: default is the \"catch all\" account,\n          else account as to match called number --\u003e\n    \u003caction type=\"accept\"\n            account=\"default\"\n            hangup=\"5\"\n            play_dtmf=\"0123456789#*\"\n            play=\"voice_ref_files/f.wav\"\n            code=\"200\" reason=\"YES\"\n            ring_duration=\"5\"\n    /\u003e\n    \u003c!-- DTMF will be sent using RFC2833 --\u003e\n    \u003c!-- note: wait for new incoming calls\n               forever and generate test results --\u003e\n    \u003caction type=\"wait\" ms=\"-1\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### Example: accepting calls and checking for specific header\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"accept\"\n            account=\"default\"\n            hangup=\"5\"\n            code=\"200\" reason=\"OK\"\n    \u003e\n        \u003ccheck-header name=\"Min-SE\"/\u003e\n        \u003ccheck-header name=\"X-Foo\" value=\"Bar\"/\u003e\n    \u003c/action\u003e\n    \u003caction type=\"wait\" ms=\"-1\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### Example: accepting calls and checking for specific header with exact match or regular expression and no match on other\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"accept\"\n            match_account=\"default\"\n            hangup=\"5\"\n            code=\"200\" reason=\"OK\"\n    \u003e\n        \u003ccheck-header name=\"Min-SE\"/\u003e\n        \u003c!-- Chech that a header exists --\u003e\n        \u003ccheck-header name=\"X-Foo\" value=\"Bar\"/\u003e\n        \u003c!-- Chech that a header exists and have a specific value --\u003e\n        \u003ccheck-header name=\"From\" regex=\"^.*sip:\\+1234@example\\.com\"/\u003e\n        \u003c!-- Chech that a header exists and matches a specific regex --\u003e\n        \u003ccheck-header name=\"To\" regex=\"^.*sip:\\+5678@example\\.com\" fail_on_match=\"true\"/\u003e\n        \u003c!-- Chech that a header exists and NOT matches a specific regex --\u003e\n        \u003ccheck-header name=\"RURI\" regex=\"^INVITE\\ sip:\\d{5}@(\\d{1,3}\\.){3}\\d{1,3}:\\d{1,5};.*transport=[a-zA-Z]{3};.*\"/\u003e\n        \u003c!-- Not really a header, but allows to check the Request URI on an incoming INVITE--\u003e\n    \u003c/action\u003e\n    \u003caction type=\"wait\" ms=\"-1\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### Example: accepting calls and searching the message with a regular expression\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"accept\"\n            account=\"default\"\n            hangup=\"5\"\n            code=\"200\" reason=\"OK\"\n    \u003e\n        \u003ccheck-message method=\"INVITE\" regex=\"m=audio(.*)RTP/AVP 0 8.*\"/\u003e\n        \u003c!-- searching for pcmu pcma in the SDP --\u003e\n    \u003c/action\u003e\n    \u003caction type=\"wait\" ms=\"-1\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### Example: making tests calls with wait_until\nScenario execution is sequential and non-blocking.\nWe can use “wait” command with previously set “wait_until” params\nto control parallel execution.\n\n```\nCall States\nNULL : Before INVITE is sent or received\nCALLING : After INVITE is sent\nINCOMING : After INVITE is received.\nEARLY : After response with To tag.\nCONNECTING : After 2xx is sent/received.\nCONFIRMED : After ACK is sent/received.\nDISCONNECTED\n```\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"call\" label=\"call#1\"\n            transport=\"udp\"\n            wait_until=\"CONFIRMED\"\n            expected_cause_code=\"200\"\n            caller=\"15148888888@noreply.com\"\n            callee=\"12011111111@target.com\"\n    /\u003e\n    \u003c!-- note: will wait until all tests pass wait_until state --\u003e\n    \u003caction type=\"wait\"/\u003e\n    \u003caction type=\"call\" label=\"call#2\"\n            transport=\"udp\"\n            wait_until=\"CONFIRMED\"\n            expected_cause_code=\"200\"\n            caller=\"15147777777@noreply.com\"\n            callee=\"12012222222@target.com\"\n    /\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### Example: testing registration\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003c!-- note: proxy param to send to a proxy --\u003e\n    \u003caction type=\"register\" label=\"register target.com\"\n            transport=\"udp\"\n            account=\"VP_ENV_USERNAME\"\n            username=\"VP_ENV_USERNAME\"\n            password=\"VP_ENV_PASSWORD\"\n            proxy=\"172.16.7.1\"\n            registrar=\"target.com\"\n            expected_cause_code=\"200\"\n    /\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### Example: re-invite with new codec\n```xml\n\u003cconfig\u003e\n    \u003caction\u003e\n        \u003caction type=\"codec\" disable=\"all\"/\u003e\n        \u003caction type=\"codec\" enable=\"pcma\" priority=\"250\"/\u003e\n        \u003caction type=\"codec\" enable=\"pcmu\" priority=\"248\"/\u003e\n\n        \u003c!-- call that will last 12 seconds and re-invite every 2 seconds --\u003e\n        \u003caction type=\"call\"\n            wait_until=\"CONFIRMED\"\n            expected_cause_code=\"200\"\n            caller=\"16364990640@125.22.198.115\"\n            callee=\"12349099229@sip.mydomain.com\"\n            max_duration=\"55\" hangup=\"12\"\n            username=\"65454659288\" password=\"adaadzWidD7T\"\n            re_invite_interval=\"2\"\n            rtp_stats=\"true\"\n        /\u003e\n        \u003caction type=\"wait\"/\u003e \u003c!-- this will wait until the call is confirmed --\u003e\n        \u003caction type=\"codec\" disable=\"pcma\"/\u003e\n        \u003c!-- re-invite will now use pcmu forcing a new session --\u003e\n        \u003caction type=\"wait\" ms=\"3000\"/\u003e \u003c!-- this will wait 3 seconds --\u003e\n        \u003caction type=\"codec\" enable=\"pcma\" priority=\"250\"/\u003e\n        \u003c!-- re-invite will now use pcma forcing a new session --\u003e\n\n        \u003caction type=\"wait\" complete=\"true\"\u003e \u003c!-- Wait until the calls are disconnected --\u003e\n    \u003cactions/\u003e\n\u003cconfig/\u003e\n```\n\n### Example: Overwriting local contact header\n```xml\n\u003cconfig\u003e\u003cactions\u003e\n    \u003caction type=\"codec\" disable=\"all\"/\u003e\n    \u003caction type=\"codec\" enable=\"pcma\" priority=\"250\"/\u003e\n    \u003caction type=\"codec\" enable=\"gsm\" priority=\"249\"/\u003e\n    \u003caction type=\"codec\" enable=\"pcmu\" priority=\"248\"/\u003e\n\n    \u003caction type=\"call\"\n        transport=\"udp\"\n        caller=\"+15147371787@fakecustomer.xyz\"\n        callee=\"+911@edgeproxy1\"\n        transport=\"udp\"\n        username=\"20255655\"\n        password=\"qntzhpbl\"\n        rtp_stats=\"true\"\n        late_start=\"false\"\n        force_contact=\"sip:+15147371787@10.10.2.5:5777\"\n        play=\"/git/voip_patrol/voice_ref_files/reference_8000_12s.wav\"\n        hangup=\"5\"\u003e\n\n    \u003cx-header name=\"Foo\" value=\"Bar\"/\u003e\n    \u003c/action\u003e\n    \u003caction type=\"wait\" complete=\"true\" /\u003e\n\u003c/actions\u003e\u003c/config\u003e\n```\n\n### Example: WAIT action\n#### wait forever:\n```xml\n\u003caction type=\"wait\" ms=\"-1\"/\u003e\n```\n#### wait until you receive a certain amount of calls\n```xml\n\u003caction type=\"accept\" call_count=\"x\" ... /\u003e\n\u003caction type=\"wait\" complete=\"true\"/\u003e\n```\n#### wait 5 seconds or one call\n```xml\n\u003caction type=\"accept\" call_count=\"1\" ... /\u003e\n\u003caction type=\"wait\" ms=\"5000\"/\u003e\n```\n\n### Sample JSON output RTP stats report with multiples sessions\n#### one block is generated everytime a session is created\n```json\n{\n \"rtp_stats_0\": {\n      \"rtt\": 0,\n      \"remote_rtp_socket\": \"10.250.7.88:4028\",\n      \"codec_name\": \"PCMA\",\n      \"clock_rate\": \"8000\",\n      \"Tx\": {\n        \"jitter_avg\": 0,\n        \"jitter_max\": 0,\n        \"pkt\": 105,\n        \"kbytes\": 16,\n        \"loss\": 0,\n        \"discard\": 0,\n        \"mos_lq\": 4.5\n      },\n      \"Rx\": {\n        \"jitter_avg\": 0,\n        \"jitter_max\": 0,\n        \"pkt\": 104,\n        \"kbytes\": 16,\n        \"loss\": 0,\n        \"discard\": 0,\n        \"mos_lq\": 4.5\n      }\n    },\n    \"rtp_stats_1\": {\n      \"rtt\": 0,\n      \"remote_rtp_socket\": \"10.250.7.89:40230\",\n      \"codec_name\": \"PCMU\",\n      \"clock_rate\": \"8000\",\n      \"Tx\": {\n        \"jitter_avg\": 0,\n        \"jitter_max\": 0,\n        \"pkt\": 501,\n        \"kbytes\": 78,\n        \"loss\": 0,\n        \"discard\": 0,\n        \"mos_lq\": 4.5\n      },\n      \"Rx\": {\n        \"jitter_avg\": 0,\n        \"jitter_max\": 0,\n        \"pkt\": 501,\n        \"kbytes\": 78,\n        \"loss\": 0,\n        \"discard\": 0,\n        \"mos_lq\": 4.5\n      }\n    }\n}\n```\n### Example: email reporting\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"alert\"\n     email=\"jchavanton+vp@gmail.com\"\n     email_from=\"test@voip-patrol.org\"\n     smtp_host=\"smtp://gmail-smtp-in.l.google.com:25\"\n    /\u003e\n    \u003c!-- add more test actions here ...  --\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### accept command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| ring_duration | int | ringing duration in seconds |\n| early_media | bool | if \"true\" 183 with SDP and early media is used |\n| timer | string | control SIP session timers, possible values are : inactive, optional, required or always |\n| code | int | SIP cause code to return must be \u003e100 and \u003c700 |\n| account | string | Account will be used if it matches the user part of an incoming call RURI or \"default\" will catch all |\n| response_delay | int | ms delay before reponse is sent, useful to test timeouts and race conditions |\n| call_count | int | The amount of calls to receive to consider the command completed, default -1 (considered completed) |\n| transport | string | Force a specific transport for all messages on accepted calls, default to all transport available |\n| re_invite_interval | int | Interval in seconds at which a re-invite with SDP will be sent |\n| rtp_stats | bool | if \"true\" the json report will include a report on RTP transmission |\n| srtp | string | Comma-separated values of the following \"sdes\" - add SDES support, \"dtls\" - add DTLS-SRTP support, \"force\" - make SRTP mandatory |\n| hangup | int | call duration in second before hangup |\n| label | string | test description or label |\n| record | bool | if \"true\" the call will be recorded once connected in /voice_files |\n| record_early | bool | if \"true\" the call will be recorded when early media starts in /voice_files. If call is answered after, recording will continue in the same file |\n\n### call command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| timer | string | control SIP session timers, possible values are : inactive, optional, required or always |\n| proxy | string | ip/hostname of a proxy where to send the call |\n| caller | string | From header user@host, only used if from it not specified |\n| display_name | string | From and Contact header display name, example: \"Alice\" |\n| callee | string | request URI user@host (also used in the To header unless to_uri is specified) |\n| to_uri | string | used@host part of the URI in the To header |\n| transport | string | force a specific transport \u003ctcp,udp,tls,sips\u003e |\n| re_invite_interval | int | Interval in seconds at which a re-invite with SDP will be sent |\n| rtp_stats | bool | if \"true\" the json report will include a report on RTP transmission |\n| srtp | string | Comma-separated values of the following \"sdes\" - add SDES support, \"dtls\" - add DTLS-SRTP support, \"force\" - make SRTP mandatory. Note, if you don't specify \"force\", call would be made with plain RTP. If you specify both \"sdes\" and \"dtls\", DTLS-SRTP would be used regardless of order. |\n| late_start | bool | if \"true\" no SDP will be included in the INVITE and will result in a late offer in 200 OK/ACK |\n| record | bool | if \"true\" the call will be recorded once connected in /voice_files |\n| record_early | bool | if \"true\" the call will be recorded when early media starts in /voice_files. If call is answered after, recording will continue in the same file |\n| force_contact | string | local contact header will be overwritten by the given string |\n| max_ringing_duration | int | max ringing duration in seconds before cancel, default 60 |\n| hangup | int | call duration in second before hangup |\n| repeat | int | do this call multiple times |\n| username | string | authentication username, account name, From/To/Contact header user part |\n| password | string | authentication password |\n| label | string | test description or label |\n\n### register command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| proxy | string | ip/hostname of a proxy where to send the register |\n| username | string | authentication username, account name, From/To/Contact header user part |\n| password | string | authentication password |\n| account | string | if not specified username is used, this is the the account name and From/To/Contact header user part |\n| registrar | string | SIP UAS handling registration where the messages will be sent |\n| transport | string | force a specific transport \u003ctcp,udp,tls,sips\u003e |\n| unregister | bool | unregister the account \u003cusename@registrar;transport=x\u003e |\n| reg_id | int | if present outbound and other related parameters will be added see RFC5626 |\n| instance_id | int | same as reg_id, if not present, it will be generated automatically |\n| rewrite_contact | bool | default true, detect public IP when registering and rewrite the contact header |\n| srtp | string | Comma-separated values of the following \"sdes\" - add SDES support, \"dtls\" - add DTLS-SRTP support, \"force\" - make SRTP mandatory. Used for incoming calls to this account |\n| account | string | if not specified username is used, this is the the account name and From/To/Contact header user part |\n| registrar | string | SIP UAS handling registration where the messages will be sent |\n| transport | string | force a specific transport \u003ctcp,udp,tls,sips\u003e |\n| unregister | bool | unregister the account \u003cusename@registrar;transport=x\u003e |\n| reg_id | int | if present outbound and other related parameters will be added see RFC5626 |\n| instance_id | int | same as reg_id, if not present, it will be generated automatically |\n| rewrite_contact | bool | default true, detect public IP when registering and rewrite the contact header |\n| srtp | string | Comma-separated values of the following \"sdes\" - add SDES support, \"dtls\" - add DTLS-SRTP support, \"force\" - make SRTP mandatory. Used for incoming calls to this account |\n\n### message command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| from | string | From header complete \"\\\u0026quot;Display Name\\\u0026quot; \u003csip:test at 127.0.0.1\u003e\"  |\n| to_uri | string | used@host part of the URI in the To header |\n| transport | string | force a specific transport \u003ctcp,udp,tls,sips\u003e |\n| username | string | authentication username, account name, From/To/Contact header user part |\n| password | string | authentication password |\n| label | string | test description or label |\n\n### Example: sending a message\n```xml\n\u003c?xml version=\"1.0\"?\u003e\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"message\" label=\"testing SIP message\" transport=\"udp\"\n      expected_cause_code=\"202\"\n      text=\"Message in a bottle.\"\n      from=\"123456@in.the.ocean\"\n      to_uri=\"15876580542@in.the.ocean\"\n      username=\"123456\"\n      password=\"pass\"\n     /\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### accept_message command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| account | string | Account will be used if it matches the user part of an incoming message RURI or \"default\" will catch all |\n| message_count | int | The amount of messages to receive to consider the command completed, default -1 (considered completed) |\n| transport | string | Force a specific transport for all messages on accepted messages, default to all transport available |\n| label | string | test description or label |\n\n### Example: receiving a message\n```xml\n\u003c?xml version=\"1.0\"?\u003e\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"register\" label=\"register\" transport=\"udp\"\n      expected_cause_code=\"200\"\n      username=\"123456\"\n      password=\"password\"\n      registrar=\"pbx.somewhere.time\"\n     /\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n    \u003caction type=\"accept_message\" \n      account=\"123456\"\n      message_count=\"1\"\n     /\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### wait command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| complete | bool | if \"true\" wait for all the test to complete (or reach their wait_until state) before executing next action or disconnecting calls and exiting, needed in most cases |\n| ms | int | the amount of milliseconds to wait before executing next action or disconnecting calls and exiting, if -1 wait forever |\n\n### Example: codec configuration\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"codec\" disable=\"all\"/\u003e\n    \u003caction type=\"codec\" enable=\"pcmu\" priority=\"250\"/\u003e\n    \u003c!-- more actions ... --\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### codec command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| priority | int | 0-255, where zero means to disable the codec |\n| enable | string | Codec payload type ID, ex. \"g722\", \"pcma\", \"opus\" or \"all\" |\n| disable | string | Codec payload type ID, ex. \"g722\", \"pcma\", \"opus\" or \"all\" |\n\n### Example: TURN configuration\n```xml\n\u003cconfig\u003e\n  \u003cactions\u003e\n    \u003caction type=\"turn\" enabled=\"true\" server=\"x.x.x.x:3478\" username=\"foo\" password=\"bar\"/\u003e\n    \u003c!-- more actions ... --\u003e\n    \u003caction type=\"wait\" complete=\"true\"/\u003e\n  \u003c/actions\u003e\n\u003c/config\u003e\n```\n\n### turn command parameters\n\n| Name | Type | Description |\n| ---- | ---- | ----------- |\n| enabled | bool | if \"true\" turn server usage will be enabled |\n| server | string | turn server URI or IP:port |\n| username | string | turn server username |\n| password | string | turn server password |\n| password_hashed | bool | if \"true\" us hashed password, default plain password |\n| sip_stun_use | bool | if \"true\" SIP reflective IP is use with signaling |\n| media_stun_use | bool | if \"true\" STUN reflective IP is use with media/SDP |\n| stun_only | bool | if \"true\" TURN and ICE are disabled and only STUN is use |\n\n### using multiple accounts\nWhen using multiple accounts, accounts can be created and selected with the following parameters.\n\n|command | account parameter |\n| ------ | ----------------- |\n| accept | account |\n| register | account |\n| call | caller |\n|accept_message| account |\n| message | from |\n\n### using env variable in scenario actions parameters\nAny value starting with `VP_ENV` will be replaced by the envrironment variable of the same name.\nExample : `username=\"VP_ENV_USERNAME\"`\n```bash\nexport VP_ENV_PASSWORD=????????\nexport VP_ENV_USERNAME=username\n```\n\n### Docker\n```bash\nvoip_patrol/docker$ tree\n.\n├── build.sh        # docker build command example\n├── Dockerfile      # docker build file for Linux Alpine\n└── voip_patrol.sh  # docker run example starting\n```\n\n## Dependencies\n\n#### PJSUA2\nPJSUA2 : A C++ High Level Softphone API : built on top of PJSIP and PJMEDIA\nhttp://www.pjsip.org\nhttp://www.pjsip.org/docs/book-latest/PJSUA2Doc.pdf\n\n## External tool to test audio quality\n\n#### PESQ\nP.862 : Perceptual evaluation of speech quality (PESQ): An objective method for end-to-end speech quality assessment of narrow-band telephone networks and speech codecs\nhttp://www.itu.int/rec/T-REC-P.862\n```\n./run_pesq +16000 voice_files/reference.wav voice_files/recording.wav\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchavanton%2Fvoip_patrol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjchavanton%2Fvoip_patrol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchavanton%2Fvoip_patrol/lists"}